gablilli commited on
Commit ·
4f74731
1
Parent(s): 8a17e92
feat: change endpoints to retrieve books for sanoma
Browse files- .gitignore +2 -1
- package-lock.json +479 -6
- package.json +4 -0
- providers/bsmart.js +2 -2
- providers/sanoma.js +86 -57
- providers/src/{api.js → bsmart/api.js} +0 -0
- providers/src/{crypto.js → bsmart/crypto.js} +0 -0
- providers/src/{pdf.js → bsmart/pdf.js} +0 -0
- providers/src/sanoma/auth.js +464 -0
- server.js +1 -1
.gitignore
CHANGED
|
@@ -2,4 +2,5 @@ node_modules/
|
|
| 2 |
temp/
|
| 3 |
tmp/
|
| 4 |
*.pdf
|
| 5 |
-
*.epub
|
|
|
|
|
|
| 2 |
temp/
|
| 3 |
tmp/
|
| 4 |
*.pdf
|
| 5 |
+
*.epub
|
| 6 |
+
.DS_Store
|
package-lock.json
CHANGED
|
@@ -11,7 +11,10 @@
|
|
| 11 |
"dependencies": {
|
| 12 |
"adm-zip": "^0.5.12",
|
| 13 |
"aes-js": "^3.1.2",
|
|
|
|
|
|
|
| 14 |
"better-sqlite3": "^12.4.1",
|
|
|
|
| 15 |
"express": "^5.2.1",
|
| 16 |
"fs-extra": "^11.2.0",
|
| 17 |
"inquirer": "^8.2.7",
|
|
@@ -26,6 +29,7 @@
|
|
| 26 |
"sanitize-filename": "^1.6.3",
|
| 27 |
"svg-to-pdfkit": "^0.1.8",
|
| 28 |
"sync-request": "^6.1.0",
|
|
|
|
| 29 |
"ws": "^8.19.0",
|
| 30 |
"xml2js": "^0.6.2",
|
| 31 |
"yargs": "^17.5.1",
|
|
@@ -170,6 +174,15 @@
|
|
| 170 |
"integrity": "sha512-e5pEa2kBnBOgR4Y/p20pskXI74UEz7de8ZGVo58asOtvSVG5YAbJeELPZxOmt+Bnz3rX753YKhfIn4X4l1PPRQ==",
|
| 171 |
"license": "MIT"
|
| 172 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 173 |
"node_modules/ansi-escapes": {
|
| 174 |
"version": "4.3.2",
|
| 175 |
"resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz",
|
|
@@ -279,6 +292,52 @@
|
|
| 279 |
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
|
| 280 |
"license": "MIT"
|
| 281 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 282 |
"node_modules/balanced-match": {
|
| 283 |
"version": "4.0.4",
|
| 284 |
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz",
|
|
@@ -366,6 +425,12 @@
|
|
| 366 |
"url": "https://opencollective.com/express"
|
| 367 |
}
|
| 368 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 369 |
"node_modules/brace-expansion": {
|
| 370 |
"version": "5.0.4",
|
| 371 |
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.4.tgz",
|
|
@@ -501,6 +566,57 @@
|
|
| 501 |
"node": "*"
|
| 502 |
}
|
| 503 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 504 |
"node_modules/chownr": {
|
| 505 |
"version": "1.1.4",
|
| 506 |
"resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz",
|
|
@@ -864,6 +980,34 @@
|
|
| 864 |
"integrity": "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==",
|
| 865 |
"license": "MIT"
|
| 866 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 867 |
"node_modules/data-uri-to-buffer": {
|
| 868 |
"version": "4.0.1",
|
| 869 |
"resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz",
|
|
@@ -959,6 +1103,61 @@
|
|
| 959 |
"integrity": "sha512-ED3jP8saaweFTjeGX8HQPjeC1YYyZs98jGNZx6IiBvxW7JG5v492kamAQB3m2wop07CvU/RQmzcKr6bgcC5D/Q==",
|
| 960 |
"license": "MIT"
|
| 961 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 962 |
"node_modules/dunder-proto": {
|
| 963 |
"version": "1.0.1",
|
| 964 |
"resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
|
|
@@ -994,6 +1193,31 @@
|
|
| 994 |
"node": ">= 0.8"
|
| 995 |
}
|
| 996 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 997 |
"node_modules/end-of-stream": {
|
| 998 |
"version": "1.4.5",
|
| 999 |
"resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz",
|
|
@@ -1003,6 +1227,18 @@
|
|
| 1003 |
"once": "^1.4.0"
|
| 1004 |
}
|
| 1005 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1006 |
"node_modules/es-define-property": {
|
| 1007 |
"version": "1.0.1",
|
| 1008 |
"resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
|
|
@@ -1253,6 +1489,26 @@
|
|
| 1253 |
"url": "https://opencollective.com/express"
|
| 1254 |
}
|
| 1255 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1256 |
"node_modules/fontkit": {
|
| 1257 |
"version": "2.0.4",
|
| 1258 |
"resolved": "https://registry.npmjs.org/fontkit/-/fontkit-2.0.4.tgz",
|
|
@@ -1534,6 +1790,37 @@
|
|
| 1534 |
"node": ">= 0.4"
|
| 1535 |
}
|
| 1536 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1537 |
"node_modules/http-basic": {
|
| 1538 |
"version": "8.1.3",
|
| 1539 |
"resolved": "https://registry.npmjs.org/http-basic/-/http-basic-8.1.3.tgz",
|
|
@@ -1549,6 +1836,30 @@
|
|
| 1549 |
"node": ">=6.0.0"
|
| 1550 |
}
|
| 1551 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1552 |
"node_modules/http-errors": {
|
| 1553 |
"version": "2.0.1",
|
| 1554 |
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz",
|
|
@@ -2147,6 +2458,18 @@
|
|
| 2147 |
"node": ">=0.10.0"
|
| 2148 |
}
|
| 2149 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2150 |
"node_modules/object-inspect": {
|
| 2151 |
"version": "1.13.4",
|
| 2152 |
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz",
|
|
@@ -2271,6 +2594,55 @@
|
|
| 2271 |
"resolved": "https://registry.npmjs.org/parse-cache-control/-/parse-cache-control-1.0.1.tgz",
|
| 2272 |
"integrity": "sha512-60zvsJReQPX5/QP0Kzfd/VrpjScIQ7SHBW6bFCYfEP+fp0Eppr1SHhIO5nd1PjZtvclzSzES9D/p5nFJurwfWg=="
|
| 2273 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2274 |
"node_modules/parseurl": {
|
| 2275 |
"version": "1.3.3",
|
| 2276 |
"resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
|
|
@@ -2440,6 +2812,24 @@
|
|
| 2440 |
"node": ">= 0.10"
|
| 2441 |
}
|
| 2442 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2443 |
"node_modules/pump": {
|
| 2444 |
"version": "3.0.3",
|
| 2445 |
"resolved": "https://registry.npmjs.org/pump/-/pump-3.0.3.tgz",
|
|
@@ -2450,6 +2840,15 @@
|
|
| 2450 |
"once": "^1.3.1"
|
| 2451 |
}
|
| 2452 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2453 |
"node_modules/qs": {
|
| 2454 |
"version": "6.15.0",
|
| 2455 |
"resolved": "https://registry.npmjs.org/qs/-/qs-6.15.0.tgz",
|
|
@@ -2465,6 +2864,12 @@
|
|
| 2465 |
"url": "https://github.com/sponsors/ljharb"
|
| 2466 |
}
|
| 2467 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2468 |
"node_modules/range-parser": {
|
| 2469 |
"version": "1.2.1",
|
| 2470 |
"resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
|
|
@@ -2527,6 +2932,12 @@
|
|
| 2527 |
"node": ">=0.10.0"
|
| 2528 |
}
|
| 2529 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2530 |
"node_modules/restore-cursor": {
|
| 2531 |
"version": "3.1.0",
|
| 2532 |
"resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz",
|
|
@@ -3057,6 +3468,30 @@
|
|
| 3057 |
"node": ">=0.6"
|
| 3058 |
}
|
| 3059 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3060 |
"node_modules/truncate-utf8-bytes": {
|
| 3061 |
"version": "1.0.2",
|
| 3062 |
"resolved": "https://registry.npmjs.org/truncate-utf8-bytes/-/truncate-utf8-bytes-1.0.2.tgz",
|
|
@@ -3141,12 +3576,6 @@
|
|
| 3141 |
"integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==",
|
| 3142 |
"license": "MIT"
|
| 3143 |
},
|
| 3144 |
-
"node_modules/undici-types": {
|
| 3145 |
-
"version": "7.18.2",
|
| 3146 |
-
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.18.2.tgz",
|
| 3147 |
-
"integrity": "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==",
|
| 3148 |
-
"optional": true
|
| 3149 |
-
},
|
| 3150 |
"node_modules/unicode-properties": {
|
| 3151 |
"version": "1.4.1",
|
| 3152 |
"resolved": "https://registry.npmjs.org/unicode-properties/-/unicode-properties-1.4.1.tgz",
|
|
@@ -3191,6 +3620,16 @@
|
|
| 3191 |
"node": ">= 0.8"
|
| 3192 |
}
|
| 3193 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3194 |
"node_modules/utf8-byte-length": {
|
| 3195 |
"version": "1.0.5",
|
| 3196 |
"resolved": "https://registry.npmjs.org/utf8-byte-length/-/utf8-byte-length-1.0.5.tgz",
|
|
@@ -3230,6 +3669,40 @@
|
|
| 3230 |
"node": ">= 8"
|
| 3231 |
}
|
| 3232 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3233 |
"node_modules/which": {
|
| 3234 |
"version": "2.0.2",
|
| 3235 |
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
|
|
|
|
| 11 |
"dependencies": {
|
| 12 |
"adm-zip": "^0.5.12",
|
| 13 |
"aes-js": "^3.1.2",
|
| 14 |
+
"axios": "^1.13.6",
|
| 15 |
+
"axios-cookiejar-support": "^5.0.5",
|
| 16 |
"better-sqlite3": "^12.4.1",
|
| 17 |
+
"cheerio": "^1.2.0",
|
| 18 |
"express": "^5.2.1",
|
| 19 |
"fs-extra": "^11.2.0",
|
| 20 |
"inquirer": "^8.2.7",
|
|
|
|
| 29 |
"sanitize-filename": "^1.6.3",
|
| 30 |
"svg-to-pdfkit": "^0.1.8",
|
| 31 |
"sync-request": "^6.1.0",
|
| 32 |
+
"tough-cookie": "^4.1.4",
|
| 33 |
"ws": "^8.19.0",
|
| 34 |
"xml2js": "^0.6.2",
|
| 35 |
"yargs": "^17.5.1",
|
|
|
|
| 174 |
"integrity": "sha512-e5pEa2kBnBOgR4Y/p20pskXI74UEz7de8ZGVo58asOtvSVG5YAbJeELPZxOmt+Bnz3rX753YKhfIn4X4l1PPRQ==",
|
| 175 |
"license": "MIT"
|
| 176 |
},
|
| 177 |
+
"node_modules/agent-base": {
|
| 178 |
+
"version": "7.1.4",
|
| 179 |
+
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz",
|
| 180 |
+
"integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==",
|
| 181 |
+
"license": "MIT",
|
| 182 |
+
"engines": {
|
| 183 |
+
"node": ">= 14"
|
| 184 |
+
}
|
| 185 |
+
},
|
| 186 |
"node_modules/ansi-escapes": {
|
| 187 |
"version": "4.3.2",
|
| 188 |
"resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz",
|
|
|
|
| 292 |
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
|
| 293 |
"license": "MIT"
|
| 294 |
},
|
| 295 |
+
"node_modules/axios": {
|
| 296 |
+
"version": "1.13.6",
|
| 297 |
+
"resolved": "https://registry.npmjs.org/axios/-/axios-1.13.6.tgz",
|
| 298 |
+
"integrity": "sha512-ChTCHMouEe2kn713WHbQGcuYrr6fXTBiu460OTwWrWob16g1bXn4vtz07Ope7ewMozJAnEquLk5lWQWtBig9DQ==",
|
| 299 |
+
"license": "MIT",
|
| 300 |
+
"dependencies": {
|
| 301 |
+
"follow-redirects": "^1.15.11",
|
| 302 |
+
"form-data": "^4.0.5",
|
| 303 |
+
"proxy-from-env": "^1.1.0"
|
| 304 |
+
}
|
| 305 |
+
},
|
| 306 |
+
"node_modules/axios-cookiejar-support": {
|
| 307 |
+
"version": "5.0.5",
|
| 308 |
+
"resolved": "https://registry.npmjs.org/axios-cookiejar-support/-/axios-cookiejar-support-5.0.5.tgz",
|
| 309 |
+
"integrity": "sha512-jJG+p7JnOYxkVrYkCDKBrLqUmcpwHZTNQrEcIEKr5qe7YVTyPAD9nCsi1cO5LDmQpQApfS430czO+oceI3g/3g==",
|
| 310 |
+
"license": "MIT",
|
| 311 |
+
"dependencies": {
|
| 312 |
+
"http-cookie-agent": "^6.0.8"
|
| 313 |
+
},
|
| 314 |
+
"engines": {
|
| 315 |
+
"node": ">=18.0.0"
|
| 316 |
+
},
|
| 317 |
+
"funding": {
|
| 318 |
+
"url": "https://github.com/sponsors/3846masa"
|
| 319 |
+
},
|
| 320 |
+
"peerDependencies": {
|
| 321 |
+
"axios": ">=0.20.0",
|
| 322 |
+
"tough-cookie": ">=4.0.0"
|
| 323 |
+
}
|
| 324 |
+
},
|
| 325 |
+
"node_modules/axios/node_modules/form-data": {
|
| 326 |
+
"version": "4.0.5",
|
| 327 |
+
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz",
|
| 328 |
+
"integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==",
|
| 329 |
+
"license": "MIT",
|
| 330 |
+
"dependencies": {
|
| 331 |
+
"asynckit": "^0.4.0",
|
| 332 |
+
"combined-stream": "^1.0.8",
|
| 333 |
+
"es-set-tostringtag": "^2.1.0",
|
| 334 |
+
"hasown": "^2.0.2",
|
| 335 |
+
"mime-types": "^2.1.12"
|
| 336 |
+
},
|
| 337 |
+
"engines": {
|
| 338 |
+
"node": ">= 6"
|
| 339 |
+
}
|
| 340 |
+
},
|
| 341 |
"node_modules/balanced-match": {
|
| 342 |
"version": "4.0.4",
|
| 343 |
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz",
|
|
|
|
| 425 |
"url": "https://opencollective.com/express"
|
| 426 |
}
|
| 427 |
},
|
| 428 |
+
"node_modules/boolbase": {
|
| 429 |
+
"version": "1.0.0",
|
| 430 |
+
"resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
|
| 431 |
+
"integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==",
|
| 432 |
+
"license": "ISC"
|
| 433 |
+
},
|
| 434 |
"node_modules/brace-expansion": {
|
| 435 |
"version": "5.0.4",
|
| 436 |
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.4.tgz",
|
|
|
|
| 566 |
"node": "*"
|
| 567 |
}
|
| 568 |
},
|
| 569 |
+
"node_modules/cheerio": {
|
| 570 |
+
"version": "1.2.0",
|
| 571 |
+
"resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.2.0.tgz",
|
| 572 |
+
"integrity": "sha512-WDrybc/gKFpTYQutKIK6UvfcuxijIZfMfXaYm8NMsPQxSYvf+13fXUJ4rztGGbJcBQ/GF55gvrZ0Bc0bj/mqvg==",
|
| 573 |
+
"license": "MIT",
|
| 574 |
+
"dependencies": {
|
| 575 |
+
"cheerio-select": "^2.1.0",
|
| 576 |
+
"dom-serializer": "^2.0.0",
|
| 577 |
+
"domhandler": "^5.0.3",
|
| 578 |
+
"domutils": "^3.2.2",
|
| 579 |
+
"encoding-sniffer": "^0.2.1",
|
| 580 |
+
"htmlparser2": "^10.1.0",
|
| 581 |
+
"parse5": "^7.3.0",
|
| 582 |
+
"parse5-htmlparser2-tree-adapter": "^7.1.0",
|
| 583 |
+
"parse5-parser-stream": "^7.1.2",
|
| 584 |
+
"undici": "^7.19.0",
|
| 585 |
+
"whatwg-mimetype": "^4.0.0"
|
| 586 |
+
},
|
| 587 |
+
"engines": {
|
| 588 |
+
"node": ">=20.18.1"
|
| 589 |
+
},
|
| 590 |
+
"funding": {
|
| 591 |
+
"url": "https://github.com/cheeriojs/cheerio?sponsor=1"
|
| 592 |
+
}
|
| 593 |
+
},
|
| 594 |
+
"node_modules/cheerio-select": {
|
| 595 |
+
"version": "2.1.0",
|
| 596 |
+
"resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-2.1.0.tgz",
|
| 597 |
+
"integrity": "sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==",
|
| 598 |
+
"license": "BSD-2-Clause",
|
| 599 |
+
"dependencies": {
|
| 600 |
+
"boolbase": "^1.0.0",
|
| 601 |
+
"css-select": "^5.1.0",
|
| 602 |
+
"css-what": "^6.1.0",
|
| 603 |
+
"domelementtype": "^2.3.0",
|
| 604 |
+
"domhandler": "^5.0.3",
|
| 605 |
+
"domutils": "^3.0.1"
|
| 606 |
+
},
|
| 607 |
+
"funding": {
|
| 608 |
+
"url": "https://github.com/sponsors/fb55"
|
| 609 |
+
}
|
| 610 |
+
},
|
| 611 |
+
"node_modules/cheerio/node_modules/undici": {
|
| 612 |
+
"version": "7.24.4",
|
| 613 |
+
"resolved": "https://registry.npmjs.org/undici/-/undici-7.24.4.tgz",
|
| 614 |
+
"integrity": "sha512-BM/JzwwaRXxrLdElV2Uo6cTLEjhSb3WXboncJamZ15NgUURmvlXvxa6xkwIOILIjPNo9i8ku136ZvWV0Uly8+w==",
|
| 615 |
+
"license": "MIT",
|
| 616 |
+
"engines": {
|
| 617 |
+
"node": ">=20.18.1"
|
| 618 |
+
}
|
| 619 |
+
},
|
| 620 |
"node_modules/chownr": {
|
| 621 |
"version": "1.1.4",
|
| 622 |
"resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz",
|
|
|
|
| 980 |
"integrity": "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==",
|
| 981 |
"license": "MIT"
|
| 982 |
},
|
| 983 |
+
"node_modules/css-select": {
|
| 984 |
+
"version": "5.2.2",
|
| 985 |
+
"resolved": "https://registry.npmjs.org/css-select/-/css-select-5.2.2.tgz",
|
| 986 |
+
"integrity": "sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==",
|
| 987 |
+
"license": "BSD-2-Clause",
|
| 988 |
+
"dependencies": {
|
| 989 |
+
"boolbase": "^1.0.0",
|
| 990 |
+
"css-what": "^6.1.0",
|
| 991 |
+
"domhandler": "^5.0.2",
|
| 992 |
+
"domutils": "^3.0.1",
|
| 993 |
+
"nth-check": "^2.0.1"
|
| 994 |
+
},
|
| 995 |
+
"funding": {
|
| 996 |
+
"url": "https://github.com/sponsors/fb55"
|
| 997 |
+
}
|
| 998 |
+
},
|
| 999 |
+
"node_modules/css-what": {
|
| 1000 |
+
"version": "6.2.2",
|
| 1001 |
+
"resolved": "https://registry.npmjs.org/css-what/-/css-what-6.2.2.tgz",
|
| 1002 |
+
"integrity": "sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==",
|
| 1003 |
+
"license": "BSD-2-Clause",
|
| 1004 |
+
"engines": {
|
| 1005 |
+
"node": ">= 6"
|
| 1006 |
+
},
|
| 1007 |
+
"funding": {
|
| 1008 |
+
"url": "https://github.com/sponsors/fb55"
|
| 1009 |
+
}
|
| 1010 |
+
},
|
| 1011 |
"node_modules/data-uri-to-buffer": {
|
| 1012 |
"version": "4.0.1",
|
| 1013 |
"resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz",
|
|
|
|
| 1103 |
"integrity": "sha512-ED3jP8saaweFTjeGX8HQPjeC1YYyZs98jGNZx6IiBvxW7JG5v492kamAQB3m2wop07CvU/RQmzcKr6bgcC5D/Q==",
|
| 1104 |
"license": "MIT"
|
| 1105 |
},
|
| 1106 |
+
"node_modules/dom-serializer": {
|
| 1107 |
+
"version": "2.0.0",
|
| 1108 |
+
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz",
|
| 1109 |
+
"integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==",
|
| 1110 |
+
"license": "MIT",
|
| 1111 |
+
"dependencies": {
|
| 1112 |
+
"domelementtype": "^2.3.0",
|
| 1113 |
+
"domhandler": "^5.0.2",
|
| 1114 |
+
"entities": "^4.2.0"
|
| 1115 |
+
},
|
| 1116 |
+
"funding": {
|
| 1117 |
+
"url": "https://github.com/cheeriojs/dom-serializer?sponsor=1"
|
| 1118 |
+
}
|
| 1119 |
+
},
|
| 1120 |
+
"node_modules/domelementtype": {
|
| 1121 |
+
"version": "2.3.0",
|
| 1122 |
+
"resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz",
|
| 1123 |
+
"integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==",
|
| 1124 |
+
"funding": [
|
| 1125 |
+
{
|
| 1126 |
+
"type": "github",
|
| 1127 |
+
"url": "https://github.com/sponsors/fb55"
|
| 1128 |
+
}
|
| 1129 |
+
],
|
| 1130 |
+
"license": "BSD-2-Clause"
|
| 1131 |
+
},
|
| 1132 |
+
"node_modules/domhandler": {
|
| 1133 |
+
"version": "5.0.3",
|
| 1134 |
+
"resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz",
|
| 1135 |
+
"integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==",
|
| 1136 |
+
"license": "BSD-2-Clause",
|
| 1137 |
+
"dependencies": {
|
| 1138 |
+
"domelementtype": "^2.3.0"
|
| 1139 |
+
},
|
| 1140 |
+
"engines": {
|
| 1141 |
+
"node": ">= 4"
|
| 1142 |
+
},
|
| 1143 |
+
"funding": {
|
| 1144 |
+
"url": "https://github.com/fb55/domhandler?sponsor=1"
|
| 1145 |
+
}
|
| 1146 |
+
},
|
| 1147 |
+
"node_modules/domutils": {
|
| 1148 |
+
"version": "3.2.2",
|
| 1149 |
+
"resolved": "https://registry.npmjs.org/domutils/-/domutils-3.2.2.tgz",
|
| 1150 |
+
"integrity": "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==",
|
| 1151 |
+
"license": "BSD-2-Clause",
|
| 1152 |
+
"dependencies": {
|
| 1153 |
+
"dom-serializer": "^2.0.0",
|
| 1154 |
+
"domelementtype": "^2.3.0",
|
| 1155 |
+
"domhandler": "^5.0.3"
|
| 1156 |
+
},
|
| 1157 |
+
"funding": {
|
| 1158 |
+
"url": "https://github.com/fb55/domutils?sponsor=1"
|
| 1159 |
+
}
|
| 1160 |
+
},
|
| 1161 |
"node_modules/dunder-proto": {
|
| 1162 |
"version": "1.0.1",
|
| 1163 |
"resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
|
|
|
|
| 1193 |
"node": ">= 0.8"
|
| 1194 |
}
|
| 1195 |
},
|
| 1196 |
+
"node_modules/encoding-sniffer": {
|
| 1197 |
+
"version": "0.2.1",
|
| 1198 |
+
"resolved": "https://registry.npmjs.org/encoding-sniffer/-/encoding-sniffer-0.2.1.tgz",
|
| 1199 |
+
"integrity": "sha512-5gvq20T6vfpekVtqrYQsSCFZ1wEg5+wW0/QaZMWkFr6BqD3NfKs0rLCx4rrVlSWJeZb5NBJgVLswK/w2MWU+Gw==",
|
| 1200 |
+
"license": "MIT",
|
| 1201 |
+
"dependencies": {
|
| 1202 |
+
"iconv-lite": "^0.6.3",
|
| 1203 |
+
"whatwg-encoding": "^3.1.1"
|
| 1204 |
+
},
|
| 1205 |
+
"funding": {
|
| 1206 |
+
"url": "https://github.com/fb55/encoding-sniffer?sponsor=1"
|
| 1207 |
+
}
|
| 1208 |
+
},
|
| 1209 |
+
"node_modules/encoding-sniffer/node_modules/iconv-lite": {
|
| 1210 |
+
"version": "0.6.3",
|
| 1211 |
+
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
|
| 1212 |
+
"integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
|
| 1213 |
+
"license": "MIT",
|
| 1214 |
+
"dependencies": {
|
| 1215 |
+
"safer-buffer": ">= 2.1.2 < 3.0.0"
|
| 1216 |
+
},
|
| 1217 |
+
"engines": {
|
| 1218 |
+
"node": ">=0.10.0"
|
| 1219 |
+
}
|
| 1220 |
+
},
|
| 1221 |
"node_modules/end-of-stream": {
|
| 1222 |
"version": "1.4.5",
|
| 1223 |
"resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz",
|
|
|
|
| 1227 |
"once": "^1.4.0"
|
| 1228 |
}
|
| 1229 |
},
|
| 1230 |
+
"node_modules/entities": {
|
| 1231 |
+
"version": "4.5.0",
|
| 1232 |
+
"resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
|
| 1233 |
+
"integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==",
|
| 1234 |
+
"license": "BSD-2-Clause",
|
| 1235 |
+
"engines": {
|
| 1236 |
+
"node": ">=0.12"
|
| 1237 |
+
},
|
| 1238 |
+
"funding": {
|
| 1239 |
+
"url": "https://github.com/fb55/entities?sponsor=1"
|
| 1240 |
+
}
|
| 1241 |
+
},
|
| 1242 |
"node_modules/es-define-property": {
|
| 1243 |
"version": "1.0.1",
|
| 1244 |
"resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
|
|
|
|
| 1489 |
"url": "https://opencollective.com/express"
|
| 1490 |
}
|
| 1491 |
},
|
| 1492 |
+
"node_modules/follow-redirects": {
|
| 1493 |
+
"version": "1.15.11",
|
| 1494 |
+
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz",
|
| 1495 |
+
"integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==",
|
| 1496 |
+
"funding": [
|
| 1497 |
+
{
|
| 1498 |
+
"type": "individual",
|
| 1499 |
+
"url": "https://github.com/sponsors/RubenVerborgh"
|
| 1500 |
+
}
|
| 1501 |
+
],
|
| 1502 |
+
"license": "MIT",
|
| 1503 |
+
"engines": {
|
| 1504 |
+
"node": ">=4.0"
|
| 1505 |
+
},
|
| 1506 |
+
"peerDependenciesMeta": {
|
| 1507 |
+
"debug": {
|
| 1508 |
+
"optional": true
|
| 1509 |
+
}
|
| 1510 |
+
}
|
| 1511 |
+
},
|
| 1512 |
"node_modules/fontkit": {
|
| 1513 |
"version": "2.0.4",
|
| 1514 |
"resolved": "https://registry.npmjs.org/fontkit/-/fontkit-2.0.4.tgz",
|
|
|
|
| 1790 |
"node": ">= 0.4"
|
| 1791 |
}
|
| 1792 |
},
|
| 1793 |
+
"node_modules/htmlparser2": {
|
| 1794 |
+
"version": "10.1.0",
|
| 1795 |
+
"resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-10.1.0.tgz",
|
| 1796 |
+
"integrity": "sha512-VTZkM9GWRAtEpveh7MSF6SjjrpNVNNVJfFup7xTY3UpFtm67foy9HDVXneLtFVt4pMz5kZtgNcvCniNFb1hlEQ==",
|
| 1797 |
+
"funding": [
|
| 1798 |
+
"https://github.com/fb55/htmlparser2?sponsor=1",
|
| 1799 |
+
{
|
| 1800 |
+
"type": "github",
|
| 1801 |
+
"url": "https://github.com/sponsors/fb55"
|
| 1802 |
+
}
|
| 1803 |
+
],
|
| 1804 |
+
"license": "MIT",
|
| 1805 |
+
"dependencies": {
|
| 1806 |
+
"domelementtype": "^2.3.0",
|
| 1807 |
+
"domhandler": "^5.0.3",
|
| 1808 |
+
"domutils": "^3.2.2",
|
| 1809 |
+
"entities": "^7.0.1"
|
| 1810 |
+
}
|
| 1811 |
+
},
|
| 1812 |
+
"node_modules/htmlparser2/node_modules/entities": {
|
| 1813 |
+
"version": "7.0.1",
|
| 1814 |
+
"resolved": "https://registry.npmjs.org/entities/-/entities-7.0.1.tgz",
|
| 1815 |
+
"integrity": "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==",
|
| 1816 |
+
"license": "BSD-2-Clause",
|
| 1817 |
+
"engines": {
|
| 1818 |
+
"node": ">=0.12"
|
| 1819 |
+
},
|
| 1820 |
+
"funding": {
|
| 1821 |
+
"url": "https://github.com/fb55/entities?sponsor=1"
|
| 1822 |
+
}
|
| 1823 |
+
},
|
| 1824 |
"node_modules/http-basic": {
|
| 1825 |
"version": "8.1.3",
|
| 1826 |
"resolved": "https://registry.npmjs.org/http-basic/-/http-basic-8.1.3.tgz",
|
|
|
|
| 1836 |
"node": ">=6.0.0"
|
| 1837 |
}
|
| 1838 |
},
|
| 1839 |
+
"node_modules/http-cookie-agent": {
|
| 1840 |
+
"version": "6.0.8",
|
| 1841 |
+
"resolved": "https://registry.npmjs.org/http-cookie-agent/-/http-cookie-agent-6.0.8.tgz",
|
| 1842 |
+
"integrity": "sha512-qnYh3yLSr2jBsTYkw11elq+T361uKAJaZ2dR4cfYZChw1dt9uL5t3zSUwehoqqVb4oldk1BpkXKm2oat8zV+oA==",
|
| 1843 |
+
"license": "MIT",
|
| 1844 |
+
"dependencies": {
|
| 1845 |
+
"agent-base": "^7.1.3"
|
| 1846 |
+
},
|
| 1847 |
+
"engines": {
|
| 1848 |
+
"node": ">=18.0.0"
|
| 1849 |
+
},
|
| 1850 |
+
"funding": {
|
| 1851 |
+
"url": "https://github.com/sponsors/3846masa"
|
| 1852 |
+
},
|
| 1853 |
+
"peerDependencies": {
|
| 1854 |
+
"tough-cookie": "^4.0.0 || ^5.0.0",
|
| 1855 |
+
"undici": "^5.11.0 || ^6.0.0"
|
| 1856 |
+
},
|
| 1857 |
+
"peerDependenciesMeta": {
|
| 1858 |
+
"undici": {
|
| 1859 |
+
"optional": true
|
| 1860 |
+
}
|
| 1861 |
+
}
|
| 1862 |
+
},
|
| 1863 |
"node_modules/http-errors": {
|
| 1864 |
"version": "2.0.1",
|
| 1865 |
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz",
|
|
|
|
| 2458 |
"node": ">=0.10.0"
|
| 2459 |
}
|
| 2460 |
},
|
| 2461 |
+
"node_modules/nth-check": {
|
| 2462 |
+
"version": "2.1.1",
|
| 2463 |
+
"resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz",
|
| 2464 |
+
"integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==",
|
| 2465 |
+
"license": "BSD-2-Clause",
|
| 2466 |
+
"dependencies": {
|
| 2467 |
+
"boolbase": "^1.0.0"
|
| 2468 |
+
},
|
| 2469 |
+
"funding": {
|
| 2470 |
+
"url": "https://github.com/fb55/nth-check?sponsor=1"
|
| 2471 |
+
}
|
| 2472 |
+
},
|
| 2473 |
"node_modules/object-inspect": {
|
| 2474 |
"version": "1.13.4",
|
| 2475 |
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz",
|
|
|
|
| 2594 |
"resolved": "https://registry.npmjs.org/parse-cache-control/-/parse-cache-control-1.0.1.tgz",
|
| 2595 |
"integrity": "sha512-60zvsJReQPX5/QP0Kzfd/VrpjScIQ7SHBW6bFCYfEP+fp0Eppr1SHhIO5nd1PjZtvclzSzES9D/p5nFJurwfWg=="
|
| 2596 |
},
|
| 2597 |
+
"node_modules/parse5": {
|
| 2598 |
+
"version": "7.3.0",
|
| 2599 |
+
"resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz",
|
| 2600 |
+
"integrity": "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==",
|
| 2601 |
+
"license": "MIT",
|
| 2602 |
+
"dependencies": {
|
| 2603 |
+
"entities": "^6.0.0"
|
| 2604 |
+
},
|
| 2605 |
+
"funding": {
|
| 2606 |
+
"url": "https://github.com/inikulin/parse5?sponsor=1"
|
| 2607 |
+
}
|
| 2608 |
+
},
|
| 2609 |
+
"node_modules/parse5-htmlparser2-tree-adapter": {
|
| 2610 |
+
"version": "7.1.0",
|
| 2611 |
+
"resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-7.1.0.tgz",
|
| 2612 |
+
"integrity": "sha512-ruw5xyKs6lrpo9x9rCZqZZnIUntICjQAd0Wsmp396Ul9lN/h+ifgVV1x1gZHi8euej6wTfpqX8j+BFQxF0NS/g==",
|
| 2613 |
+
"license": "MIT",
|
| 2614 |
+
"dependencies": {
|
| 2615 |
+
"domhandler": "^5.0.3",
|
| 2616 |
+
"parse5": "^7.0.0"
|
| 2617 |
+
},
|
| 2618 |
+
"funding": {
|
| 2619 |
+
"url": "https://github.com/inikulin/parse5?sponsor=1"
|
| 2620 |
+
}
|
| 2621 |
+
},
|
| 2622 |
+
"node_modules/parse5-parser-stream": {
|
| 2623 |
+
"version": "7.1.2",
|
| 2624 |
+
"resolved": "https://registry.npmjs.org/parse5-parser-stream/-/parse5-parser-stream-7.1.2.tgz",
|
| 2625 |
+
"integrity": "sha512-JyeQc9iwFLn5TbvvqACIF/VXG6abODeB3Fwmv/TGdLk2LfbWkaySGY72at4+Ty7EkPZj854u4CrICqNk2qIbow==",
|
| 2626 |
+
"license": "MIT",
|
| 2627 |
+
"dependencies": {
|
| 2628 |
+
"parse5": "^7.0.0"
|
| 2629 |
+
},
|
| 2630 |
+
"funding": {
|
| 2631 |
+
"url": "https://github.com/inikulin/parse5?sponsor=1"
|
| 2632 |
+
}
|
| 2633 |
+
},
|
| 2634 |
+
"node_modules/parse5/node_modules/entities": {
|
| 2635 |
+
"version": "6.0.1",
|
| 2636 |
+
"resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz",
|
| 2637 |
+
"integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==",
|
| 2638 |
+
"license": "BSD-2-Clause",
|
| 2639 |
+
"engines": {
|
| 2640 |
+
"node": ">=0.12"
|
| 2641 |
+
},
|
| 2642 |
+
"funding": {
|
| 2643 |
+
"url": "https://github.com/fb55/entities?sponsor=1"
|
| 2644 |
+
}
|
| 2645 |
+
},
|
| 2646 |
"node_modules/parseurl": {
|
| 2647 |
"version": "1.3.3",
|
| 2648 |
"resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
|
|
|
|
| 2812 |
"node": ">= 0.10"
|
| 2813 |
}
|
| 2814 |
},
|
| 2815 |
+
"node_modules/proxy-from-env": {
|
| 2816 |
+
"version": "1.1.0",
|
| 2817 |
+
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
|
| 2818 |
+
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==",
|
| 2819 |
+
"license": "MIT"
|
| 2820 |
+
},
|
| 2821 |
+
"node_modules/psl": {
|
| 2822 |
+
"version": "1.15.0",
|
| 2823 |
+
"resolved": "https://registry.npmjs.org/psl/-/psl-1.15.0.tgz",
|
| 2824 |
+
"integrity": "sha512-JZd3gMVBAVQkSs6HdNZo9Sdo0LNcQeMNP3CozBJb3JYC/QUYZTnKxP+f8oWRX4rHP5EurWxqAHTSwUCjlNKa1w==",
|
| 2825 |
+
"license": "MIT",
|
| 2826 |
+
"dependencies": {
|
| 2827 |
+
"punycode": "^2.3.1"
|
| 2828 |
+
},
|
| 2829 |
+
"funding": {
|
| 2830 |
+
"url": "https://github.com/sponsors/lupomontero"
|
| 2831 |
+
}
|
| 2832 |
+
},
|
| 2833 |
"node_modules/pump": {
|
| 2834 |
"version": "3.0.3",
|
| 2835 |
"resolved": "https://registry.npmjs.org/pump/-/pump-3.0.3.tgz",
|
|
|
|
| 2840 |
"once": "^1.3.1"
|
| 2841 |
}
|
| 2842 |
},
|
| 2843 |
+
"node_modules/punycode": {
|
| 2844 |
+
"version": "2.3.1",
|
| 2845 |
+
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
|
| 2846 |
+
"integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==",
|
| 2847 |
+
"license": "MIT",
|
| 2848 |
+
"engines": {
|
| 2849 |
+
"node": ">=6"
|
| 2850 |
+
}
|
| 2851 |
+
},
|
| 2852 |
"node_modules/qs": {
|
| 2853 |
"version": "6.15.0",
|
| 2854 |
"resolved": "https://registry.npmjs.org/qs/-/qs-6.15.0.tgz",
|
|
|
|
| 2864 |
"url": "https://github.com/sponsors/ljharb"
|
| 2865 |
}
|
| 2866 |
},
|
| 2867 |
+
"node_modules/querystringify": {
|
| 2868 |
+
"version": "2.2.0",
|
| 2869 |
+
"resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz",
|
| 2870 |
+
"integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==",
|
| 2871 |
+
"license": "MIT"
|
| 2872 |
+
},
|
| 2873 |
"node_modules/range-parser": {
|
| 2874 |
"version": "1.2.1",
|
| 2875 |
"resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
|
|
|
|
| 2932 |
"node": ">=0.10.0"
|
| 2933 |
}
|
| 2934 |
},
|
| 2935 |
+
"node_modules/requires-port": {
|
| 2936 |
+
"version": "1.0.0",
|
| 2937 |
+
"resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
|
| 2938 |
+
"integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==",
|
| 2939 |
+
"license": "MIT"
|
| 2940 |
+
},
|
| 2941 |
"node_modules/restore-cursor": {
|
| 2942 |
"version": "3.1.0",
|
| 2943 |
"resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz",
|
|
|
|
| 3468 |
"node": ">=0.6"
|
| 3469 |
}
|
| 3470 |
},
|
| 3471 |
+
"node_modules/tough-cookie": {
|
| 3472 |
+
"version": "4.1.4",
|
| 3473 |
+
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.4.tgz",
|
| 3474 |
+
"integrity": "sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==",
|
| 3475 |
+
"license": "BSD-3-Clause",
|
| 3476 |
+
"dependencies": {
|
| 3477 |
+
"psl": "^1.1.33",
|
| 3478 |
+
"punycode": "^2.1.1",
|
| 3479 |
+
"universalify": "^0.2.0",
|
| 3480 |
+
"url-parse": "^1.5.3"
|
| 3481 |
+
},
|
| 3482 |
+
"engines": {
|
| 3483 |
+
"node": ">=6"
|
| 3484 |
+
}
|
| 3485 |
+
},
|
| 3486 |
+
"node_modules/tough-cookie/node_modules/universalify": {
|
| 3487 |
+
"version": "0.2.0",
|
| 3488 |
+
"resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz",
|
| 3489 |
+
"integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==",
|
| 3490 |
+
"license": "MIT",
|
| 3491 |
+
"engines": {
|
| 3492 |
+
"node": ">= 4.0.0"
|
| 3493 |
+
}
|
| 3494 |
+
},
|
| 3495 |
"node_modules/truncate-utf8-bytes": {
|
| 3496 |
"version": "1.0.2",
|
| 3497 |
"resolved": "https://registry.npmjs.org/truncate-utf8-bytes/-/truncate-utf8-bytes-1.0.2.tgz",
|
|
|
|
| 3576 |
"integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==",
|
| 3577 |
"license": "MIT"
|
| 3578 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3579 |
"node_modules/unicode-properties": {
|
| 3580 |
"version": "1.4.1",
|
| 3581 |
"resolved": "https://registry.npmjs.org/unicode-properties/-/unicode-properties-1.4.1.tgz",
|
|
|
|
| 3620 |
"node": ">= 0.8"
|
| 3621 |
}
|
| 3622 |
},
|
| 3623 |
+
"node_modules/url-parse": {
|
| 3624 |
+
"version": "1.5.10",
|
| 3625 |
+
"resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz",
|
| 3626 |
+
"integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==",
|
| 3627 |
+
"license": "MIT",
|
| 3628 |
+
"dependencies": {
|
| 3629 |
+
"querystringify": "^2.1.1",
|
| 3630 |
+
"requires-port": "^1.0.0"
|
| 3631 |
+
}
|
| 3632 |
+
},
|
| 3633 |
"node_modules/utf8-byte-length": {
|
| 3634 |
"version": "1.0.5",
|
| 3635 |
"resolved": "https://registry.npmjs.org/utf8-byte-length/-/utf8-byte-length-1.0.5.tgz",
|
|
|
|
| 3669 |
"node": ">= 8"
|
| 3670 |
}
|
| 3671 |
},
|
| 3672 |
+
"node_modules/whatwg-encoding": {
|
| 3673 |
+
"version": "3.1.1",
|
| 3674 |
+
"resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz",
|
| 3675 |
+
"integrity": "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==",
|
| 3676 |
+
"deprecated": "Use @exodus/bytes instead for a more spec-conformant and faster implementation",
|
| 3677 |
+
"license": "MIT",
|
| 3678 |
+
"dependencies": {
|
| 3679 |
+
"iconv-lite": "0.6.3"
|
| 3680 |
+
},
|
| 3681 |
+
"engines": {
|
| 3682 |
+
"node": ">=18"
|
| 3683 |
+
}
|
| 3684 |
+
},
|
| 3685 |
+
"node_modules/whatwg-encoding/node_modules/iconv-lite": {
|
| 3686 |
+
"version": "0.6.3",
|
| 3687 |
+
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
|
| 3688 |
+
"integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
|
| 3689 |
+
"license": "MIT",
|
| 3690 |
+
"dependencies": {
|
| 3691 |
+
"safer-buffer": ">= 2.1.2 < 3.0.0"
|
| 3692 |
+
},
|
| 3693 |
+
"engines": {
|
| 3694 |
+
"node": ">=0.10.0"
|
| 3695 |
+
}
|
| 3696 |
+
},
|
| 3697 |
+
"node_modules/whatwg-mimetype": {
|
| 3698 |
+
"version": "4.0.0",
|
| 3699 |
+
"resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz",
|
| 3700 |
+
"integrity": "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==",
|
| 3701 |
+
"license": "MIT",
|
| 3702 |
+
"engines": {
|
| 3703 |
+
"node": ">=18"
|
| 3704 |
+
}
|
| 3705 |
+
},
|
| 3706 |
"node_modules/which": {
|
| 3707 |
"version": "2.0.2",
|
| 3708 |
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
|
package.json
CHANGED
|
@@ -24,7 +24,10 @@
|
|
| 24 |
"dependencies": {
|
| 25 |
"adm-zip": "^0.5.12",
|
| 26 |
"aes-js": "^3.1.2",
|
|
|
|
|
|
|
| 27 |
"better-sqlite3": "^12.4.1",
|
|
|
|
| 28 |
"express": "^5.2.1",
|
| 29 |
"fs-extra": "^11.2.0",
|
| 30 |
"inquirer": "^8.2.7",
|
|
@@ -39,6 +42,7 @@
|
|
| 39 |
"sanitize-filename": "^1.6.3",
|
| 40 |
"svg-to-pdfkit": "^0.1.8",
|
| 41 |
"sync-request": "^6.1.0",
|
|
|
|
| 42 |
"ws": "^8.19.0",
|
| 43 |
"xml2js": "^0.6.2",
|
| 44 |
"yargs": "^17.5.1",
|
|
|
|
| 24 |
"dependencies": {
|
| 25 |
"adm-zip": "^0.5.12",
|
| 26 |
"aes-js": "^3.1.2",
|
| 27 |
+
"axios": "^1.13.6",
|
| 28 |
+
"axios-cookiejar-support": "^5.0.5",
|
| 29 |
"better-sqlite3": "^12.4.1",
|
| 30 |
+
"cheerio": "^1.2.0",
|
| 31 |
"express": "^5.2.1",
|
| 32 |
"fs-extra": "^11.2.0",
|
| 33 |
"inquirer": "^8.2.7",
|
|
|
|
| 42 |
"sanitize-filename": "^1.6.3",
|
| 43 |
"svg-to-pdfkit": "^0.1.8",
|
| 44 |
"sync-request": "^6.1.0",
|
| 45 |
+
"tough-cookie": "^4.1.4",
|
| 46 |
"ws": "^8.19.0",
|
| 47 |
"xml2js": "^0.6.2",
|
| 48 |
"yargs": "^17.5.1",
|
providers/bsmart.js
CHANGED
|
@@ -10,8 +10,8 @@ import { spawn } from 'child_process';
|
|
| 10 |
import path from 'path';
|
| 11 |
import pLimit from 'p-limit';
|
| 12 |
|
| 13 |
-
import { fetchEncryptionKey, decryptFile } from './src/crypto.js';
|
| 14 |
-
import { performBsmartLogin, getUserInfo, getBooks, getBookInfo, getBookResources, getResourceLinks } from './src/api.js';
|
| 15 |
|
| 16 |
const prompt = PromptSync({ sigint: true });
|
| 17 |
|
|
|
|
| 10 |
import path from 'path';
|
| 11 |
import pLimit from 'p-limit';
|
| 12 |
|
| 13 |
+
import { fetchEncryptionKey, decryptFile } from './src/bsmart/crypto.js';
|
| 14 |
+
import { performBsmartLogin, getUserInfo, getBooks, getBookInfo, getBookResources, getResourceLinks } from './src/bsmart/api.js';
|
| 15 |
|
| 16 |
const prompt = PromptSync({ sigint: true });
|
| 17 |
|
providers/sanoma.js
CHANGED
|
@@ -8,6 +8,7 @@ import fsExtra from 'fs-extra';
|
|
| 8 |
import path from 'path';
|
| 9 |
import { spawn } from 'child_process';
|
| 10 |
import { pipeline } from 'stream';
|
|
|
|
| 11 |
|
| 12 |
const prompt = PromptSync({ sigint: true });
|
| 13 |
const SANOMA_BASE_URLS = [
|
|
@@ -77,20 +78,17 @@ export async function run(options = {}) {
|
|
| 77 |
|
| 78 |
console.log("Avvio provider Sanoma...");
|
| 79 |
|
| 80 |
-
|
| 81 |
-
|
| 82 |
-
|
| 83 |
|
| 84 |
-
|
| 85 |
-
|
| 86 |
-
let userId = id || argv.id;
|
| 87 |
-
let userPassword = password || argv.password;
|
| 88 |
-
let bookGedi = gedi || argv.gedi;
|
| 89 |
|
| 90 |
-
|
| 91 |
-
|
|
|
|
| 92 |
|
| 93 |
-
|
| 94 |
return function (...args) {
|
| 95 |
return new Promise((resolve, reject) => {
|
| 96 |
api(...args, (err, response) => {
|
|
@@ -99,11 +97,11 @@ export async function run(options = {}) {
|
|
| 99 |
});
|
| 100 |
});
|
| 101 |
};
|
| 102 |
-
|
| 103 |
|
| 104 |
-
|
| 105 |
|
| 106 |
-
|
| 107 |
return new Promise((resolve, reject) => {
|
| 108 |
const ocr = spawn('ocrmypdf', [inputPdf, outputPdf], { stdio: 'inherit' });
|
| 109 |
|
|
@@ -120,9 +118,9 @@ export async function run(options = {}) {
|
|
| 120 |
else reject(new Error(`OCRmyPDF exited with code ${code}`));
|
| 121 |
});
|
| 122 |
});
|
| 123 |
-
|
| 124 |
|
| 125 |
-
|
| 126 |
let lastError = null;
|
| 127 |
|
| 128 |
for (const base of SANOMA_BASE_URLS) {
|
|
@@ -141,17 +139,17 @@ export async function run(options = {}) {
|
|
| 141 |
}
|
| 142 |
|
| 143 |
throw lastError || new Error('Richiesta Sanoma fallita');
|
| 144 |
-
|
| 145 |
|
| 146 |
-
|
| 147 |
return userAuth?.result?.data?.access_token
|
| 148 |
|| userAuth?.data?.access_token
|
| 149 |
|| userAuth?.access_token
|
| 150 |
|| userAuth?.token
|
| 151 |
|| null;
|
| 152 |
-
|
| 153 |
|
| 154 |
-
|
| 155 |
const data = payload?.result?.data || payload?.data || payload?.books || [];
|
| 156 |
const totalSize = payload?.result?.total_size ?? payload?.total_size ?? payload?.total ?? data.length;
|
| 157 |
const rawPageSize = payload?.result?.page_size ?? payload?.page_size ?? data.length;
|
|
@@ -160,20 +158,20 @@ export async function run(options = {}) {
|
|
| 160 |
data: Array.isArray(data) ? data : [],
|
| 161 |
pages: Math.max(1, Math.ceil(totalSize / pageSize)),
|
| 162 |
};
|
| 163 |
-
|
| 164 |
|
| 165 |
-
|
| 166 |
return book?.name || book?.title || `GEDI ${book?.gedi || ''}`.trim();
|
| 167 |
-
|
| 168 |
|
| 169 |
-
|
| 170 |
return book?.url_download || book?.urlDownload || book?.downloadUrl || book?.url || null;
|
| 171 |
-
|
| 172 |
|
| 173 |
-
|
| 174 |
await fsExtra.ensureDir(sessionTmp);
|
| 175 |
|
| 176 |
-
let
|
| 177 |
|
| 178 |
if (argv.download) {
|
| 179 |
let folder = await fs.promises.readdir(sessionTmp);
|
|
@@ -182,18 +180,43 @@ export async function run(options = {}) {
|
|
| 182 |
process.exit(1);
|
| 183 |
}
|
| 184 |
|
| 185 |
-
let
|
| 186 |
-
let
|
| 187 |
|
| 188 |
console.log('Warning: this script might log you out of other devices');
|
| 189 |
|
| 190 |
-
while (!
|
| 191 |
-
while (!
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 192 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 193 |
let userAuth = await fetchSanomaJson('/login', {
|
| 194 |
method: 'POST',
|
| 195 |
headers: { 'Content-Type': 'application/json', 'X-Timezone-Offset': '+0200' },
|
| 196 |
-
body: JSON.stringify({ id, password }),
|
| 197 |
}).catch((err) => { console.error('Failed to log in:', err.message); process.exit(1); });
|
| 198 |
|
| 199 |
if (!userAuth || (userAuth.code != null && userAuth.code !== 0)) {
|
|
@@ -207,8 +230,8 @@ export async function run(options = {}) {
|
|
| 207 |
process.exit(1);
|
| 208 |
}
|
| 209 |
|
| 210 |
-
console.log('
|
| 211 |
-
let
|
| 212 |
let pages = 1;
|
| 213 |
for (let i = 1; i <= pages; i++) {
|
| 214 |
const newBooks = await fetchSanomaJson(`/books?app=true&page=${i}`, {
|
|
@@ -219,35 +242,41 @@ export async function run(options = {}) {
|
|
| 219 |
pages = pageInfo.pages;
|
| 220 |
|
| 221 |
for (const item of pageInfo.data) {
|
| 222 |
-
if (
|
| 223 |
-
|
| 224 |
-
|
|
|
|
| 225 |
}
|
| 226 |
-
|
| 227 |
-
console.log('Books:');
|
| 228 |
-
console.table(Object.fromEntries(Object.entries(books).map(([bookId, book]) => [bookId, getBookName(book)])));
|
| 229 |
-
|
| 230 |
-
let gedi = bookGedi;
|
| 231 |
-
while (!gedi) gedi = prompt('Enter the book\'s gedi: ');
|
| 232 |
-
|
| 233 |
-
book = books[gedi];
|
| 234 |
-
if (!book) {
|
| 235 |
-
console.error(`GEDI non trovato: ${gedi}`);
|
| 236 |
-
process.exit(1);
|
| 237 |
}
|
| 238 |
|
| 239 |
-
const downloadUrl = getBookDownloadUrl(book);
|
| 240 |
if (!downloadUrl) {
|
| 241 |
-
console.error(
|
| 242 |
process.exit(1);
|
| 243 |
}
|
| 244 |
|
| 245 |
-
console.log('Downloading "' +
|
| 246 |
|
| 247 |
let zip = await fetch(downloadUrl);
|
| 248 |
if (!zip.ok) { console.error('Failed to download zip'); process.exit(1); }
|
| 249 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 250 |
await promisify(pipeline)(zip.body, fs.createWriteStream(sessionTmp + '/book.zip'));
|
|
|
|
| 251 |
} else {
|
| 252 |
console.log('Skipping download');
|
| 253 |
let stats = await fs.promises.stat(sessionTmp + '/book.zip');
|
|
@@ -290,7 +319,7 @@ export async function run(options = {}) {
|
|
| 290 |
}
|
| 291 |
|
| 292 |
let baseName = argv.output || options.output;
|
| 293 |
-
if (argv.download && !baseName) baseName =
|
| 294 |
else if (!baseName) baseName = 'output.pdf';
|
| 295 |
const outFilePath = path.join(outputDir, baseName);
|
| 296 |
|
|
@@ -319,22 +348,22 @@ export async function run(options = {}) {
|
|
| 319 |
console.log('Done. Output:', finalOutput);
|
| 320 |
console.log(`OURBOOKS_OUTPUT:${finalOutput}`);
|
| 321 |
});
|
| 322 |
-
|
| 323 |
|
| 324 |
-
|
| 325 |
try {
|
| 326 |
await convertPageWithInkscape(input, output);
|
| 327 |
} catch (err) {
|
| 328 |
console.error('Inkscape fallito:', err.message);
|
| 329 |
throw err;
|
| 330 |
}
|
| 331 |
-
|
| 332 |
|
| 333 |
-
|
| 334 |
return new Promise((resolve, reject) => {
|
| 335 |
const convert = spawn('inkscape', ['--export-filename=' + output, input]);
|
| 336 |
convert.on('error', reject);
|
| 337 |
convert.on('close', code => code === 0 ? resolve() : reject(new Error(`Inkscape exited with code ${code}`)));
|
| 338 |
});
|
| 339 |
-
|
| 340 |
}
|
|
|
|
| 8 |
import path from 'path';
|
| 9 |
import { spawn } from 'child_process';
|
| 10 |
import { pipeline } from 'stream';
|
| 11 |
+
import { loginSanoma, fetchBooks } from './src/sanoma/auth.js';
|
| 12 |
|
| 13 |
const prompt = PromptSync({ sigint: true });
|
| 14 |
const SANOMA_BASE_URLS = [
|
|
|
|
| 78 |
|
| 79 |
console.log("Avvio provider Sanoma...");
|
| 80 |
|
| 81 |
+
const sessionTmp = process.env.OURBOOKS_SESSION_TMP || 'tmp';
|
| 82 |
+
const outputDir = process.env.OURBOOKS_OUTPUT_DIR || '.';
|
| 83 |
+
const doOcr = (ocr || argv.ocr) === 'on';
|
| 84 |
|
| 85 |
+
await fsExtra.ensureDir(sessionTmp);
|
|
|
|
|
|
|
|
|
|
|
|
|
| 86 |
|
| 87 |
+
let userId = id || argv.id;
|
| 88 |
+
let userPassword = password || argv.password;
|
| 89 |
+
let bookGedi = gedi || argv.gedi;
|
| 90 |
|
| 91 |
+
function promisify(api) {
|
| 92 |
return function (...args) {
|
| 93 |
return new Promise((resolve, reject) => {
|
| 94 |
api(...args, (err, response) => {
|
|
|
|
| 97 |
});
|
| 98 |
});
|
| 99 |
};
|
| 100 |
+
}
|
| 101 |
|
| 102 |
+
const yauzlFromFile = promisify(yauzl.open);
|
| 103 |
|
| 104 |
+
function runOCR(inputPdf, outputPdf) {
|
| 105 |
return new Promise((resolve, reject) => {
|
| 106 |
const ocr = spawn('ocrmypdf', [inputPdf, outputPdf], { stdio: 'inherit' });
|
| 107 |
|
|
|
|
| 118 |
else reject(new Error(`OCRmyPDF exited with code ${code}`));
|
| 119 |
});
|
| 120 |
});
|
| 121 |
+
}
|
| 122 |
|
| 123 |
+
async function fetchSanomaJson(pathname, init = {}) {
|
| 124 |
let lastError = null;
|
| 125 |
|
| 126 |
for (const base of SANOMA_BASE_URLS) {
|
|
|
|
| 139 |
}
|
| 140 |
|
| 141 |
throw lastError || new Error('Richiesta Sanoma fallita');
|
| 142 |
+
}
|
| 143 |
|
| 144 |
+
function getAccessToken(userAuth) {
|
| 145 |
return userAuth?.result?.data?.access_token
|
| 146 |
|| userAuth?.data?.access_token
|
| 147 |
|| userAuth?.access_token
|
| 148 |
|| userAuth?.token
|
| 149 |
|| null;
|
| 150 |
+
}
|
| 151 |
|
| 152 |
+
function getBooksPage(payload) {
|
| 153 |
const data = payload?.result?.data || payload?.data || payload?.books || [];
|
| 154 |
const totalSize = payload?.result?.total_size ?? payload?.total_size ?? payload?.total ?? data.length;
|
| 155 |
const rawPageSize = payload?.result?.page_size ?? payload?.page_size ?? data.length;
|
|
|
|
| 158 |
data: Array.isArray(data) ? data : [],
|
| 159 |
pages: Math.max(1, Math.ceil(totalSize / pageSize)),
|
| 160 |
};
|
| 161 |
+
}
|
| 162 |
|
| 163 |
+
function getBookName(book) {
|
| 164 |
return book?.name || book?.title || `GEDI ${book?.gedi || ''}`.trim();
|
| 165 |
+
}
|
| 166 |
|
| 167 |
+
function getBookDownloadUrl(book) {
|
| 168 |
return book?.url_download || book?.urlDownload || book?.downloadUrl || book?.url || null;
|
| 169 |
+
}
|
| 170 |
|
| 171 |
+
(async () => {
|
| 172 |
await fsExtra.ensureDir(sessionTmp);
|
| 173 |
|
| 174 |
+
let targetBookName = "Sanoma Book";
|
| 175 |
|
| 176 |
if (argv.download) {
|
| 177 |
let folder = await fs.promises.readdir(sessionTmp);
|
|
|
|
| 180 |
process.exit(1);
|
| 181 |
}
|
| 182 |
|
| 183 |
+
let loginId = userId;
|
| 184 |
+
let loginPassword = userPassword;
|
| 185 |
|
| 186 |
console.log('Warning: this script might log you out of other devices');
|
| 187 |
|
| 188 |
+
while (!loginId) loginId = prompt('Enter account email: ');
|
| 189 |
+
while (!loginPassword) loginPassword = prompt('Enter account password: ', { echo: '*' });
|
| 190 |
+
|
| 191 |
+
console.log('Logging in to MyPlace to retrieve books...');
|
| 192 |
+
const skClient = await loginSanoma(loginId, loginPassword).catch(err => {
|
| 193 |
+
console.error('Failed to log in via MyPlace:', err.message);
|
| 194 |
+
process.exit(1);
|
| 195 |
+
});
|
| 196 |
+
|
| 197 |
+
console.log('Fetching book list...');
|
| 198 |
+
const skBooks = await fetchBooks(skClient);
|
| 199 |
|
| 200 |
+
let tableObj = {};
|
| 201 |
+
for (const b of skBooks) {
|
| 202 |
+
for (const p of b.products) {
|
| 203 |
+
tableObj[p.gedi] = p.name;
|
| 204 |
+
}
|
| 205 |
+
}
|
| 206 |
+
|
| 207 |
+
console.log('Books (MyPlace graph):');
|
| 208 |
+
console.table(tableObj);
|
| 209 |
+
|
| 210 |
+
let gedi = bookGedi;
|
| 211 |
+
while (!gedi) gedi = prompt('Enter the book\'s gedi: ');
|
| 212 |
+
|
| 213 |
+
targetBookName = tableObj[gedi] || `GEDI ${gedi}`;
|
| 214 |
+
|
| 215 |
+
console.log('Logging in to offline API to retrieve download URL...');
|
| 216 |
let userAuth = await fetchSanomaJson('/login', {
|
| 217 |
method: 'POST',
|
| 218 |
headers: { 'Content-Type': 'application/json', 'X-Timezone-Offset': '+0200' },
|
| 219 |
+
body: JSON.stringify({ id: loginId, password: loginPassword }),
|
| 220 |
}).catch((err) => { console.error('Failed to log in:', err.message); process.exit(1); });
|
| 221 |
|
| 222 |
if (!userAuth || (userAuth.code != null && userAuth.code !== 0)) {
|
|
|
|
| 230 |
process.exit(1);
|
| 231 |
}
|
| 232 |
|
| 233 |
+
console.log('Searching for download bundle...');
|
| 234 |
+
let downloadUrl = null;
|
| 235 |
let pages = 1;
|
| 236 |
for (let i = 1; i <= pages; i++) {
|
| 237 |
const newBooks = await fetchSanomaJson(`/books?app=true&page=${i}`, {
|
|
|
|
| 242 |
pages = pageInfo.pages;
|
| 243 |
|
| 244 |
for (const item of pageInfo.data) {
|
| 245 |
+
if (item?.gedi == gedi) {
|
| 246 |
+
downloadUrl = getBookDownloadUrl(item);
|
| 247 |
+
break;
|
| 248 |
+
}
|
| 249 |
}
|
| 250 |
+
if (downloadUrl) break;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 251 |
}
|
| 252 |
|
|
|
|
| 253 |
if (!downloadUrl) {
|
| 254 |
+
console.error(`URL download non trovato per questo GEDI (${gedi}) nella offline API. Errore bundle non disponibile.`);
|
| 255 |
process.exit(1);
|
| 256 |
}
|
| 257 |
|
| 258 |
+
console.log('Downloading "' + targetBookName + '"');
|
| 259 |
|
| 260 |
let zip = await fetch(downloadUrl);
|
| 261 |
if (!zip.ok) { console.error('Failed to download zip'); process.exit(1); }
|
| 262 |
|
| 263 |
+
const totalBytes = parseInt(zip.headers.get('content-length'), 10);
|
| 264 |
+
let downloadedBytes = 0;
|
| 265 |
+
let lastLoggedPercent = 0;
|
| 266 |
+
|
| 267 |
+
zip.body.on('data', (chunk) => {
|
| 268 |
+
downloadedBytes += chunk.length;
|
| 269 |
+
if (totalBytes) {
|
| 270 |
+
const percent = Math.floor((downloadedBytes / totalBytes) * 100);
|
| 271 |
+
if (percent >= lastLoggedPercent + 10) {
|
| 272 |
+
process.stdout.write(`...${percent}%`);
|
| 273 |
+
lastLoggedPercent = percent;
|
| 274 |
+
}
|
| 275 |
+
}
|
| 276 |
+
});
|
| 277 |
+
|
| 278 |
await promisify(pipeline)(zip.body, fs.createWriteStream(sessionTmp + '/book.zip'));
|
| 279 |
+
console.log('\nDownload completato!');
|
| 280 |
} else {
|
| 281 |
console.log('Skipping download');
|
| 282 |
let stats = await fs.promises.stat(sessionTmp + '/book.zip');
|
|
|
|
| 319 |
}
|
| 320 |
|
| 321 |
let baseName = argv.output || options.output;
|
| 322 |
+
if (argv.download && !baseName) baseName = targetBookName.replace(/[\\/:*?"<>|]/g, '') + '.pdf';
|
| 323 |
else if (!baseName) baseName = 'output.pdf';
|
| 324 |
const outFilePath = path.join(outputDir, baseName);
|
| 325 |
|
|
|
|
| 348 |
console.log('Done. Output:', finalOutput);
|
| 349 |
console.log(`OURBOOKS_OUTPUT:${finalOutput}`);
|
| 350 |
});
|
| 351 |
+
})();
|
| 352 |
|
| 353 |
+
async function convertPage(input, output) {
|
| 354 |
try {
|
| 355 |
await convertPageWithInkscape(input, output);
|
| 356 |
} catch (err) {
|
| 357 |
console.error('Inkscape fallito:', err.message);
|
| 358 |
throw err;
|
| 359 |
}
|
| 360 |
+
}
|
| 361 |
|
| 362 |
+
async function convertPageWithInkscape(input, output) {
|
| 363 |
return new Promise((resolve, reject) => {
|
| 364 |
const convert = spawn('inkscape', ['--export-filename=' + output, input]);
|
| 365 |
convert.on('error', reject);
|
| 366 |
convert.on('close', code => code === 0 ? resolve() : reject(new Error(`Inkscape exited with code ${code}`)));
|
| 367 |
});
|
| 368 |
+
}
|
| 369 |
}
|
providers/src/{api.js → bsmart/api.js}
RENAMED
|
File without changes
|
providers/src/{crypto.js → bsmart/crypto.js}
RENAMED
|
File without changes
|
providers/src/{pdf.js → bsmart/pdf.js}
RENAMED
|
File without changes
|
providers/src/sanoma/auth.js
ADDED
|
@@ -0,0 +1,464 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import axios from 'axios';
|
| 2 |
+
import { wrapper } from 'axios-cookiejar-support';
|
| 3 |
+
import { CookieJar } from 'tough-cookie';
|
| 4 |
+
import * as cheerio from 'cheerio';
|
| 5 |
+
import { URL } from 'url';
|
| 6 |
+
|
| 7 |
+
export async function loginSanoma(email, password) {
|
| 8 |
+
const jar = new CookieJar();
|
| 9 |
+
const client = wrapper(axios.create({
|
| 10 |
+
jar,
|
| 11 |
+
withCredentials: true,
|
| 12 |
+
maxRedirects: 0,
|
| 13 |
+
validateStatus: (status) => status >= 200 && status < 400,
|
| 14 |
+
headers: {
|
| 15 |
+
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
|
| 16 |
+
'Accept-Language': 'it-IT,it;q=0.9,en-US;q=0.8,en;q=0.7'
|
| 17 |
+
}
|
| 18 |
+
}));
|
| 19 |
+
|
| 20 |
+
const redirectUri = 'https://place.sanoma.it/';
|
| 21 |
+
let authUrl = null;
|
| 22 |
+
let clientId = null;
|
| 23 |
+
|
| 24 |
+
try {
|
| 25 |
+
// init session cookies
|
| 26 |
+
await client.get('https://place.sanoma.it/login', {
|
| 27 |
+
headers: {
|
| 28 |
+
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8'
|
| 29 |
+
}
|
| 30 |
+
});
|
| 31 |
+
|
| 32 |
+
const initParams = new URLSearchParams({
|
| 33 |
+
ref: 'https://place.sanoma.it/',
|
| 34 |
+
context: '',
|
| 35 |
+
text: email
|
| 36 |
+
});
|
| 37 |
+
|
| 38 |
+
const initRes = await client.post('https://place.sanoma.it/login?/status', initParams.toString(), {
|
| 39 |
+
headers: {
|
| 40 |
+
'Content-Type': 'application/x-www-form-urlencoded',
|
| 41 |
+
'Accept': 'application/json',
|
| 42 |
+
'Origin': 'https://place.sanoma.it',
|
| 43 |
+
'Referer': 'https://place.sanoma.it/login',
|
| 44 |
+
'x-sveltekit-action': 'true'
|
| 45 |
+
}
|
| 46 |
+
});
|
| 47 |
+
|
| 48 |
+
let data = initRes.data;
|
| 49 |
+
if (typeof data === 'string') {
|
| 50 |
+
try { data = JSON.parse(data); } catch (e) {}
|
| 51 |
+
}
|
| 52 |
+
|
| 53 |
+
if (data && data.type === 'redirect' && data.location) {
|
| 54 |
+
authUrl = data.location;
|
| 55 |
+
}
|
| 56 |
+
} catch (err) {
|
| 57 |
+
if (err.response && err.response.data && err.response.data.type === 'redirect' && err.response.data.location) {
|
| 58 |
+
authUrl = err.response.data.location;
|
| 59 |
+
} else if (err.response && err.response.headers && err.response.headers.location) {
|
| 60 |
+
authUrl = err.response.headers.location;
|
| 61 |
+
} else {
|
| 62 |
+
throw err;
|
| 63 |
+
}
|
| 64 |
+
}
|
| 65 |
+
|
| 66 |
+
if (!authUrl) {
|
| 67 |
+
throw new Error('Failed to get Auth0 redirect URL from /login?/status');
|
| 68 |
+
}
|
| 69 |
+
|
| 70 |
+
if (!authUrl.startsWith('http')) {
|
| 71 |
+
authUrl = 'https://login.sanoma.it' + (authUrl.startsWith('/') ? '' : '/') + authUrl;
|
| 72 |
+
}
|
| 73 |
+
|
| 74 |
+
const parsedInitUrl = new URL(authUrl);
|
| 75 |
+
clientId = parsedInitUrl.searchParams.get('client_id');
|
| 76 |
+
|
| 77 |
+
if (!clientId) {
|
| 78 |
+
throw new Error('Client ID missing from SvelteKit authorization URL');
|
| 79 |
+
}
|
| 80 |
+
|
| 81 |
+
let authPageRes = await client.get(authUrl, {
|
| 82 |
+
headers: {
|
| 83 |
+
'Referer': 'https://place.sanoma.it/',
|
| 84 |
+
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8'
|
| 85 |
+
}
|
| 86 |
+
});
|
| 87 |
+
|
| 88 |
+
while (authPageRes.status >= 300 && authPageRes.status < 400 && authPageRes.headers.location) {
|
| 89 |
+
let nextUrl = authPageRes.headers.location;
|
| 90 |
+
if (!nextUrl.startsWith('http')) {
|
| 91 |
+
nextUrl = 'https://login.sanoma.it' + nextUrl;
|
| 92 |
+
}
|
| 93 |
+
authUrl = nextUrl;
|
| 94 |
+
authPageRes = await client.get(authUrl, {
|
| 95 |
+
headers: {
|
| 96 |
+
'Referer': 'https://place.sanoma.it/',
|
| 97 |
+
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8'
|
| 98 |
+
}
|
| 99 |
+
});
|
| 100 |
+
}
|
| 101 |
+
|
| 102 |
+
const $ = cheerio.load(authPageRes.data);
|
| 103 |
+
|
| 104 |
+
const cookies = await jar.getCookies('https://login.sanoma.it');
|
| 105 |
+
const csrfCookie = cookies.find(c => c.key === '_csrf');
|
| 106 |
+
const csrfToken = $('input[name="_csrf"]').val() || (csrfCookie ? csrfCookie.value : '');
|
| 107 |
+
|
| 108 |
+
const parsedUrl = new URL(authUrl);
|
| 109 |
+
const state = parsedUrl.searchParams.get('state');
|
| 110 |
+
|
| 111 |
+
if (!state) {
|
| 112 |
+
throw new Error('State parameter not found in Auth0 URL');
|
| 113 |
+
}
|
| 114 |
+
|
| 115 |
+
const loginPayload = {
|
| 116 |
+
client_id: clientId,
|
| 117 |
+
redirect_uri: redirectUri,
|
| 118 |
+
tenant: "sanoma-italy",
|
| 119 |
+
response_type: "code",
|
| 120 |
+
scope: "openid profile email",
|
| 121 |
+
state: state,
|
| 122 |
+
connection: "Sanoma-Italy-Database",
|
| 123 |
+
username: email,
|
| 124 |
+
password: password,
|
| 125 |
+
popup_options: {},
|
| 126 |
+
sso: true,
|
| 127 |
+
protocol: "oauth2",
|
| 128 |
+
_csrf: csrfToken,
|
| 129 |
+
_intstate: "deprecated"
|
| 130 |
+
};
|
| 131 |
+
|
| 132 |
+
let loginRes;
|
| 133 |
+
try {
|
| 134 |
+
loginRes = await client.post('https://login.sanoma.it/usernamepassword/login', loginPayload, {
|
| 135 |
+
headers: {
|
| 136 |
+
'Content-Type': 'application/json',
|
| 137 |
+
'Origin': 'https://login.sanoma.it',
|
| 138 |
+
'Referer': authUrl,
|
| 139 |
+
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8'
|
| 140 |
+
}
|
| 141 |
+
});
|
| 142 |
+
} catch (err) {
|
| 143 |
+
throw new Error(`Login failed: ${err.response ? err.response.status : 'Unknown'} ${err.response ? err.response.statusText : ''}`);
|
| 144 |
+
}
|
| 145 |
+
|
| 146 |
+
const $login = cheerio.load(loginRes.data);
|
| 147 |
+
const wa = $login('input[name="wa"]').val();
|
| 148 |
+
const wresult = $login('input[name="wresult"]').val();
|
| 149 |
+
const wctx = $login('input[name="wctx"]').val();
|
| 150 |
+
|
| 151 |
+
if (!wa || !wresult || !wctx) {
|
| 152 |
+
console.error('Callback form fields not found');
|
| 153 |
+
throw new Error('Login failed: callback form not found (wrong credentials?)');
|
| 154 |
+
}
|
| 155 |
+
|
| 156 |
+
let finalCodeUrl = null;
|
| 157 |
+
|
| 158 |
+
try {
|
| 159 |
+
const callbackRes = await client.post('https://login.sanoma.it/login/callback',
|
| 160 |
+
`wa=${encodeURIComponent(wa)}&wresult=${encodeURIComponent(wresult)}&wctx=${encodeURIComponent(wctx)}`,
|
| 161 |
+
{
|
| 162 |
+
headers: {
|
| 163 |
+
'Content-Type': 'application/x-www-form-urlencoded',
|
| 164 |
+
'Origin': 'https://login.sanoma.it',
|
| 165 |
+
'Referer': 'https://login.sanoma.it/',
|
| 166 |
+
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8'
|
| 167 |
+
}
|
| 168 |
+
}
|
| 169 |
+
);
|
| 170 |
+
|
| 171 |
+
if (callbackRes.status >= 300 && callbackRes.status < 400) {
|
| 172 |
+
finalCodeUrl = callbackRes.headers.location;
|
| 173 |
+
}
|
| 174 |
+
} catch(err) {
|
| 175 |
+
if (err.response && err.response.status >= 300 && err.response.status < 400) {
|
| 176 |
+
finalCodeUrl = err.response.headers.location;
|
| 177 |
+
} else {
|
| 178 |
+
throw err;
|
| 179 |
+
}
|
| 180 |
+
}
|
| 181 |
+
|
| 182 |
+
if (!finalCodeUrl) {
|
| 183 |
+
throw new Error('Final redirect URL not found after callback');
|
| 184 |
+
}
|
| 185 |
+
|
| 186 |
+
if (!finalCodeUrl.startsWith('http')) {
|
| 187 |
+
if (finalCodeUrl.startsWith('/authorize')) {
|
| 188 |
+
finalCodeUrl = 'https://login.sanoma.it' + finalCodeUrl;
|
| 189 |
+
} else {
|
| 190 |
+
finalCodeUrl = 'https://place.sanoma.it' + (finalCodeUrl.startsWith('/') ? '' : '/') + finalCodeUrl;
|
| 191 |
+
}
|
| 192 |
+
}
|
| 193 |
+
|
| 194 |
+
let currentUrl = finalCodeUrl;
|
| 195 |
+
let redirectCount = 0;
|
| 196 |
+
const maxRedirects = 15;
|
| 197 |
+
|
| 198 |
+
while (redirectCount < maxRedirects) {
|
| 199 |
+
try {
|
| 200 |
+
const res = await client.get(currentUrl, {
|
| 201 |
+
headers: {
|
| 202 |
+
'Referer': redirectCount === 0 ? 'https://login.sanoma.it/' : currentUrl,
|
| 203 |
+
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8'
|
| 204 |
+
}
|
| 205 |
+
});
|
| 206 |
+
|
| 207 |
+
if (res.status >= 300 && res.status < 400 && res.headers.location) {
|
| 208 |
+
let nextUrl = res.headers.location;
|
| 209 |
+
|
| 210 |
+
if (!nextUrl.startsWith('http')) {
|
| 211 |
+
if (nextUrl.startsWith('/authorize')) {
|
| 212 |
+
nextUrl = 'https://login.sanoma.it' + nextUrl;
|
| 213 |
+
} else {
|
| 214 |
+
nextUrl = 'https://place.sanoma.it' + (nextUrl.startsWith('/') ? '' : '/') + nextUrl;
|
| 215 |
+
}
|
| 216 |
+
}
|
| 217 |
+
|
| 218 |
+
currentUrl = nextUrl;
|
| 219 |
+
redirectCount++;
|
| 220 |
+
} else {
|
| 221 |
+
break;
|
| 222 |
+
}
|
| 223 |
+
} catch (err) {
|
| 224 |
+
if (err.response && err.response.status >= 300 && err.response.status < 400) {
|
| 225 |
+
let nextUrl = err.response.headers.location;
|
| 226 |
+
|
| 227 |
+
if (!nextUrl.startsWith('http')) {
|
| 228 |
+
if (nextUrl.startsWith('/authorize')) {
|
| 229 |
+
nextUrl = 'https://login.sanoma.it' + nextUrl;
|
| 230 |
+
} else {
|
| 231 |
+
nextUrl = 'https://place.sanoma.it' + (nextUrl.startsWith('/') ? '' : '/') + nextUrl;
|
| 232 |
+
}
|
| 233 |
+
}
|
| 234 |
+
|
| 235 |
+
currentUrl = nextUrl;
|
| 236 |
+
redirectCount++;
|
| 237 |
+
} else {
|
| 238 |
+
break;
|
| 239 |
+
}
|
| 240 |
+
}
|
| 241 |
+
}
|
| 242 |
+
|
| 243 |
+
return client;
|
| 244 |
+
}
|
| 245 |
+
|
| 246 |
+
export async function fetchBooks(client) {
|
| 247 |
+
const response = await client.get('https://place.sanoma.it/prodotti_digitali/__data.json', {
|
| 248 |
+
headers: {
|
| 249 |
+
'Referer': 'https://place.sanoma.it/prodotti_digitali',
|
| 250 |
+
'Accept': 'application/json',
|
| 251 |
+
'X-Sveltekit-Invalidated': '01'
|
| 252 |
+
}
|
| 253 |
+
});
|
| 254 |
+
|
| 255 |
+
const lines = response.data.split('\n').filter(line => line.trim());
|
| 256 |
+
const jsonObjects = lines.map(line => JSON.parse(line));
|
| 257 |
+
|
| 258 |
+
let allData = [];
|
| 259 |
+
|
| 260 |
+
jsonObjects.forEach(obj => {
|
| 261 |
+
if (obj.data && Array.isArray(obj.data)) {
|
| 262 |
+
for (let i = 0; i < obj.data.length; i++) {
|
| 263 |
+
if (obj.data[i] !== undefined) {
|
| 264 |
+
allData[i] = obj.data[i];
|
| 265 |
+
}
|
| 266 |
+
}
|
| 267 |
+
}
|
| 268 |
+
if (obj.nodes) {
|
| 269 |
+
obj.nodes.forEach(node => {
|
| 270 |
+
if (node && Array.isArray(node.data)) {
|
| 271 |
+
for (let i = 0; i < node.data.length; i++) {
|
| 272 |
+
if (node.data[i] !== undefined) {
|
| 273 |
+
allData[i] = node.data[i];
|
| 274 |
+
}
|
| 275 |
+
}
|
| 276 |
+
}
|
| 277 |
+
});
|
| 278 |
+
}
|
| 279 |
+
});
|
| 280 |
+
|
| 281 |
+
jsonObjects.filter(obj => obj.type === 'chunk' && obj.data).forEach(chunk => {
|
| 282 |
+
let chunkData = chunk.data;
|
| 283 |
+
if (Array.isArray(chunkData[0])) chunkData = chunkData[0];
|
| 284 |
+
for (let i = 0; i < chunkData.length; i++) {
|
| 285 |
+
if (chunkData[i] !== undefined) {
|
| 286 |
+
allData[i] = chunkData[i];
|
| 287 |
+
}
|
| 288 |
+
}
|
| 289 |
+
});
|
| 290 |
+
|
| 291 |
+
const books = [];
|
| 292 |
+
const seenOperas = new Set();
|
| 293 |
+
|
| 294 |
+
// prevent ram out of limit (lol)
|
| 295 |
+
const resolved = new Map();
|
| 296 |
+
|
| 297 |
+
function decompressValue(val) {
|
| 298 |
+
if (typeof val === 'number') {
|
| 299 |
+
if (val < 0 || val >= allData.length || allData[val] === undefined) return val;
|
| 300 |
+
if (resolved.has(val)) return resolved.get(val);
|
| 301 |
+
|
| 302 |
+
const target = allData[val];
|
| 303 |
+
if (Array.isArray(target)) {
|
| 304 |
+
const newArr = [];
|
| 305 |
+
resolved.set(val, newArr); // register immediately before recurse
|
| 306 |
+
for (let j = 0; j < target.length; j++) {
|
| 307 |
+
newArr.push(decompressValue(target[j]));
|
| 308 |
+
}
|
| 309 |
+
return newArr;
|
| 310 |
+
} else if (target && typeof target === 'object') {
|
| 311 |
+
const newObj = {};
|
| 312 |
+
resolved.set(val, newObj); // register immediately before recurse
|
| 313 |
+
for (const key in target) {
|
| 314 |
+
newObj[key] = decompressValue(target[key]);
|
| 315 |
+
}
|
| 316 |
+
return newObj;
|
| 317 |
+
} else {
|
| 318 |
+
resolved.set(val, target);
|
| 319 |
+
return target;
|
| 320 |
+
}
|
| 321 |
+
}
|
| 322 |
+
return val;
|
| 323 |
+
}
|
| 324 |
+
|
| 325 |
+
for (let i = 0; i < allData.length; i++) {
|
| 326 |
+
const item = allData[i];
|
| 327 |
+
|
| 328 |
+
if (item && typeof item === 'object' && !Array.isArray(item) && 'opera_id' in item && 'display_name' in item) {
|
| 329 |
+
|
| 330 |
+
const fullyResolved = decompressValue(i);
|
| 331 |
+
|
| 332 |
+
if (!fullyResolved || !fullyResolved.opera_id || seenOperas.has(fullyResolved.opera_id)) {
|
| 333 |
+
continue;
|
| 334 |
+
}
|
| 335 |
+
|
| 336 |
+
seenOperas.add(fullyResolved.opera_id);
|
| 337 |
+
|
| 338 |
+
const productsMap = new Map();
|
| 339 |
+
const crawlVisited = new Set();
|
| 340 |
+
|
| 341 |
+
function extractProducts(node, namePath, inheritedIsbn) {
|
| 342 |
+
if (!node || typeof node !== 'object') return;
|
| 343 |
+
if (crawlVisited.has(node)) return;
|
| 344 |
+
crawlVisited.add(node);
|
| 345 |
+
|
| 346 |
+
let currentNames = [...namePath];
|
| 347 |
+
const potentialNames = [
|
| 348 |
+
node.display_name,
|
| 349 |
+
node.title,
|
| 350 |
+
node.name,
|
| 351 |
+
node.category_label,
|
| 352 |
+
node.category_name
|
| 353 |
+
];
|
| 354 |
+
|
| 355 |
+
for (const n of potentialNames) {
|
| 356 |
+
const str = String(n || '').trim();
|
| 357 |
+
if (str && str !== 'Prodotti' && str !== 'null' && str !== 'undefined' && str !== '[object Object]' && !/^\d+$/.test(str)) {
|
| 358 |
+
let isRedundant = false;
|
| 359 |
+
for (let j = 0; j < currentNames.length; j++) {
|
| 360 |
+
const existing = currentNames[j];
|
| 361 |
+
if (existing.toLowerCase() === str.toLowerCase()) {
|
| 362 |
+
isRedundant = true; break;
|
| 363 |
+
}
|
| 364 |
+
if (str.toLowerCase().includes(existing.toLowerCase()) && str.length > existing.length) {
|
| 365 |
+
currentNames[j] = str;
|
| 366 |
+
isRedundant = true; break;
|
| 367 |
+
}
|
| 368 |
+
if (existing.toLowerCase().includes(str.toLowerCase())) {
|
| 369 |
+
isRedundant = true; break;
|
| 370 |
+
}
|
| 371 |
+
}
|
| 372 |
+
if (!isRedundant) {
|
| 373 |
+
currentNames.push(str);
|
| 374 |
+
}
|
| 375 |
+
}
|
| 376 |
+
}
|
| 377 |
+
|
| 378 |
+
const currentIsbn = node.isbn || node.paper_isbn || inheritedIsbn;
|
| 379 |
+
|
| 380 |
+
// search a gedi
|
| 381 |
+
let gediCode = null;
|
| 382 |
+
if (node.external_id && /^\d{5,10}$/.test(String(node.external_id))) {
|
| 383 |
+
gediCode = String(node.external_id);
|
| 384 |
+
} else if (node.id && /^\d{5,10}$/.test(String(node.id))) {
|
| 385 |
+
gediCode = String(node.id);
|
| 386 |
+
}
|
| 387 |
+
|
| 388 |
+
if (gediCode) {
|
| 389 |
+
// clean names
|
| 390 |
+
let finalParts = [];
|
| 391 |
+
for (let j = 0; j < currentNames.length; j++) {
|
| 392 |
+
let isRedundant = false;
|
| 393 |
+
let currFirstWord = currentNames[j].trim().split(/[\s\-_]+/)[0].toLowerCase();
|
| 394 |
+
|
| 395 |
+
for (let k = j + 1; k < currentNames.length; k++) {
|
| 396 |
+
let nextFirstWord = currentNames[k].trim().split(/[\s\-_]+/)[0].toLowerCase();
|
| 397 |
+
|
| 398 |
+
// redudant names
|
| 399 |
+
if (currFirstWord && currFirstWord === nextFirstWord) {
|
| 400 |
+
isRedundant = true;
|
| 401 |
+
break;
|
| 402 |
+
}
|
| 403 |
+
}
|
| 404 |
+
if (!isRedundant) {
|
| 405 |
+
finalParts.push(currentNames[j]);
|
| 406 |
+
}
|
| 407 |
+
}
|
| 408 |
+
|
| 409 |
+
let finalName = finalParts.join(' - ');
|
| 410 |
+
if (!finalName) {
|
| 411 |
+
finalName = `Volume (${gediCode})`;
|
| 412 |
+
}
|
| 413 |
+
|
| 414 |
+
if (!productsMap.has(gediCode)) {
|
| 415 |
+
productsMap.set(gediCode, {
|
| 416 |
+
isbn: currentIsbn || '',
|
| 417 |
+
name: finalName,
|
| 418 |
+
gedi: gediCode,
|
| 419 |
+
resources: []
|
| 420 |
+
});
|
| 421 |
+
} else {
|
| 422 |
+
if (finalName.length > productsMap.get(gediCode).name.length) {
|
| 423 |
+
productsMap.get(gediCode).name = finalName;
|
| 424 |
+
}
|
| 425 |
+
}
|
| 426 |
+
|
| 427 |
+
productsMap.get(gediCode).resources.push({
|
| 428 |
+
type: node.category_name || '',
|
| 429 |
+
category_id: node.category_id || '',
|
| 430 |
+
external_id: node.external_id || '',
|
| 431 |
+
code: node.internal_code || '',
|
| 432 |
+
url: node.url || ''
|
| 433 |
+
});
|
| 434 |
+
}
|
| 435 |
+
|
| 436 |
+
if (Array.isArray(node)) {
|
| 437 |
+
for (let k = 0; k < node.length; k++) {
|
| 438 |
+
if (typeof node[k] === 'object') extractProducts(node[k], currentNames, currentIsbn);
|
| 439 |
+
}
|
| 440 |
+
} else {
|
| 441 |
+
for (const key in node) {
|
| 442 |
+
if (typeof node[key] === 'object') extractProducts(node[key], currentNames, currentIsbn);
|
| 443 |
+
}
|
| 444 |
+
}
|
| 445 |
+
}
|
| 446 |
+
|
| 447 |
+
let initialPath = [];
|
| 448 |
+
if (fullyResolved.display_name) initialPath.push(fullyResolved.display_name);
|
| 449 |
+
|
| 450 |
+
extractProducts(fullyResolved.included || fullyResolved, initialPath, '');
|
| 451 |
+
|
| 452 |
+
// independent names
|
| 453 |
+
for (const product of productsMap.values()) {
|
| 454 |
+
books.push({
|
| 455 |
+
name: product.name,
|
| 456 |
+
opera_id: fullyResolved.opera_id,
|
| 457 |
+
products: [product]
|
| 458 |
+
});
|
| 459 |
+
}
|
| 460 |
+
}
|
| 461 |
+
}
|
| 462 |
+
|
| 463 |
+
return books;
|
| 464 |
+
}
|
server.js
CHANGED
|
@@ -6,7 +6,7 @@ import path from 'path';
|
|
| 6 |
import { fileURLToPath } from 'url';
|
| 7 |
import { randomUUID } from 'crypto';
|
| 8 |
import fs from 'fs';
|
| 9 |
-
import { performBsmartLogin, getBooks, getUserInfo } from './providers/src/api.js';
|
| 10 |
|
| 11 |
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
| 12 |
|
|
|
|
| 6 |
import { fileURLToPath } from 'url';
|
| 7 |
import { randomUUID } from 'crypto';
|
| 8 |
import fs from 'fs';
|
| 9 |
+
import { performBsmartLogin, getBooks, getUserInfo } from './providers/src/bsmart/api.js';
|
| 10 |
|
| 11 |
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
| 12 |
|