feat: finist chromium download douyin media
This commit is contained in:
parent
38dc501f4f
commit
075ed9296d
74
bun.lock
74
bun.lock
@ -4,8 +4,12 @@
|
|||||||
"": {
|
"": {
|
||||||
"name": "qq-bot",
|
"name": "qq-bot",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@types/cors": "^2.8.19",
|
||||||
|
"@types/multer": "^2.0.0",
|
||||||
|
"cors": "^2.8.5",
|
||||||
"dotenv": "^17.0.0",
|
"dotenv": "^17.0.0",
|
||||||
"express": "^5.1.0",
|
"express": "^5.1.0",
|
||||||
|
"multer": "^2.0.2",
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/bun": "latest",
|
"@types/bun": "latest",
|
||||||
@ -24,6 +28,8 @@
|
|||||||
|
|
||||||
"@types/connect": ["@types/connect@3.4.38", "", { "dependencies": { "@types/node": "*" } }, "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug=="],
|
"@types/connect": ["@types/connect@3.4.38", "", { "dependencies": { "@types/node": "*" } }, "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug=="],
|
||||||
|
|
||||||
|
"@types/cors": ["@types/cors@2.8.19", "https://registry.npmmirror.com/@types/cors/-/cors-2.8.19.tgz", { "dependencies": { "@types/node": "*" } }, "sha512-mFNylyeyqN93lfe/9CSxOGREz8cpzAhH+E93xJ4xWQf62V8sQ/24reV2nyzUWM6H6Xji+GGHpkbLe7pVoUEskg=="],
|
||||||
|
|
||||||
"@types/express": ["@types/express@5.0.3", "", { "dependencies": { "@types/body-parser": "*", "@types/express-serve-static-core": "^5.0.0", "@types/serve-static": "*" } }, "sha512-wGA0NX93b19/dZC1J18tKWVIYWyyF2ZjT9vin/NRu0qzzvfVzWjs04iq2rQ3H65vCTQYlRqs3YHfY7zjdV+9Kw=="],
|
"@types/express": ["@types/express@5.0.3", "", { "dependencies": { "@types/body-parser": "*", "@types/express-serve-static-core": "^5.0.0", "@types/serve-static": "*" } }, "sha512-wGA0NX93b19/dZC1J18tKWVIYWyyF2ZjT9vin/NRu0qzzvfVzWjs04iq2rQ3H65vCTQYlRqs3YHfY7zjdV+9Kw=="],
|
||||||
|
|
||||||
"@types/express-serve-static-core": ["@types/express-serve-static-core@5.0.6", "", { "dependencies": { "@types/node": "*", "@types/qs": "*", "@types/range-parser": "*", "@types/send": "*" } }, "sha512-3xhRnjJPkULekpSzgtoNYYcTWgEZkp4myc+Saevii5JPnHNvHMRlBSHDbs7Bh1iPPoVTERHEZXyhyLbMEsExsA=="],
|
"@types/express-serve-static-core": ["@types/express-serve-static-core@5.0.6", "", { "dependencies": { "@types/node": "*", "@types/qs": "*", "@types/range-parser": "*", "@types/send": "*" } }, "sha512-3xhRnjJPkULekpSzgtoNYYcTWgEZkp4myc+Saevii5JPnHNvHMRlBSHDbs7Bh1iPPoVTERHEZXyhyLbMEsExsA=="],
|
||||||
@ -32,7 +38,9 @@
|
|||||||
|
|
||||||
"@types/mime": ["@types/mime@1.3.5", "", {}, "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w=="],
|
"@types/mime": ["@types/mime@1.3.5", "", {}, "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w=="],
|
||||||
|
|
||||||
"@types/node": ["@types/node@24.0.4", "", { "dependencies": { "undici-types": "~7.8.0" } }, "sha512-ulyqAkrhnuNq9pB76DRBTkcS6YsmDALy6Ua63V8OhrOBgbcYt6IOdzpw5P1+dyRIyMerzLkeYWBeOXPpA9GMAA=="],
|
"@types/multer": ["@types/multer@2.0.0", "https://registry.npmmirror.com/@types/multer/-/multer-2.0.0.tgz", { "dependencies": { "@types/express": "*" } }, "sha512-C3Z9v9Evij2yST3RSBktxP9STm6OdMc5uR1xF1SGr98uv8dUlAL2hqwrZ3GVB3uyMyiegnscEK6PGtYvNrjTjw=="],
|
||||||
|
|
||||||
|
"@types/node": ["@types/node@24.3.0", "https://registry.npmmirror.com/@types/node/-/node-24.3.0.tgz", { "dependencies": { "undici-types": "~7.10.0" } }, "sha512-aPTXCrfwnDLj4VvXrm+UUCQjNEvJgNA8s5F1cvwQU+3KNltTOkBm1j30uNLyqqPNe7gE3KFzImYoZEfLhp4Yow=="],
|
||||||
|
|
||||||
"@types/qs": ["@types/qs@6.14.0", "", {}, "sha512-eOunJqu0K1923aExK6y8p6fsihYEn/BYuQ4g0CxAAgFc4b/ZLN4CrsRZ55srTdqoiLzU2B2evC+apEIxprEzkQ=="],
|
"@types/qs": ["@types/qs@6.14.0", "", {}, "sha512-eOunJqu0K1923aExK6y8p6fsihYEn/BYuQ4g0CxAAgFc4b/ZLN4CrsRZ55srTdqoiLzU2B2evC+apEIxprEzkQ=="],
|
||||||
|
|
||||||
@ -44,16 +52,24 @@
|
|||||||
|
|
||||||
"accepts": ["accepts@2.0.0", "", { "dependencies": { "mime-types": "^3.0.0", "negotiator": "^1.0.0" } }, "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng=="],
|
"accepts": ["accepts@2.0.0", "", { "dependencies": { "mime-types": "^3.0.0", "negotiator": "^1.0.0" } }, "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng=="],
|
||||||
|
|
||||||
|
"append-field": ["append-field@1.0.0", "https://registry.npmmirror.com/append-field/-/append-field-1.0.0.tgz", {}, "sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw=="],
|
||||||
|
|
||||||
"body-parser": ["body-parser@2.2.0", "", { "dependencies": { "bytes": "^3.1.2", "content-type": "^1.0.5", "debug": "^4.4.0", "http-errors": "^2.0.0", "iconv-lite": "^0.6.3", "on-finished": "^2.4.1", "qs": "^6.14.0", "raw-body": "^3.0.0", "type-is": "^2.0.0" } }, "sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg=="],
|
"body-parser": ["body-parser@2.2.0", "", { "dependencies": { "bytes": "^3.1.2", "content-type": "^1.0.5", "debug": "^4.4.0", "http-errors": "^2.0.0", "iconv-lite": "^0.6.3", "on-finished": "^2.4.1", "qs": "^6.14.0", "raw-body": "^3.0.0", "type-is": "^2.0.0" } }, "sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg=="],
|
||||||
|
|
||||||
|
"buffer-from": ["buffer-from@1.1.2", "https://registry.npmmirror.com/buffer-from/-/buffer-from-1.1.2.tgz", {}, "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ=="],
|
||||||
|
|
||||||
"bun-types": ["bun-types@1.2.17", "", { "dependencies": { "@types/node": "*" } }, "sha512-ElC7ItwT3SCQwYZDYoAH+q6KT4Fxjl8DtZ6qDulUFBmXA8YB4xo+l54J9ZJN+k2pphfn9vk7kfubeSd5QfTVJQ=="],
|
"bun-types": ["bun-types@1.2.17", "", { "dependencies": { "@types/node": "*" } }, "sha512-ElC7ItwT3SCQwYZDYoAH+q6KT4Fxjl8DtZ6qDulUFBmXA8YB4xo+l54J9ZJN+k2pphfn9vk7kfubeSd5QfTVJQ=="],
|
||||||
|
|
||||||
|
"busboy": ["busboy@1.6.0", "https://registry.npmmirror.com/busboy/-/busboy-1.6.0.tgz", { "dependencies": { "streamsearch": "^1.1.0" } }, "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA=="],
|
||||||
|
|
||||||
"bytes": ["bytes@3.1.2", "", {}, "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg=="],
|
"bytes": ["bytes@3.1.2", "", {}, "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg=="],
|
||||||
|
|
||||||
"call-bind-apply-helpers": ["call-bind-apply-helpers@1.0.2", "", { "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2" } }, "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ=="],
|
"call-bind-apply-helpers": ["call-bind-apply-helpers@1.0.2", "", { "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2" } }, "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ=="],
|
||||||
|
|
||||||
"call-bound": ["call-bound@1.0.4", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "get-intrinsic": "^1.3.0" } }, "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg=="],
|
"call-bound": ["call-bound@1.0.4", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "get-intrinsic": "^1.3.0" } }, "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg=="],
|
||||||
|
|
||||||
|
"concat-stream": ["concat-stream@2.0.0", "https://registry.npmmirror.com/concat-stream/-/concat-stream-2.0.0.tgz", { "dependencies": { "buffer-from": "^1.0.0", "inherits": "^2.0.3", "readable-stream": "^3.0.2", "typedarray": "^0.0.6" } }, "sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A=="],
|
||||||
|
|
||||||
"content-disposition": ["content-disposition@1.0.0", "", { "dependencies": { "safe-buffer": "5.2.1" } }, "sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg=="],
|
"content-disposition": ["content-disposition@1.0.0", "", { "dependencies": { "safe-buffer": "5.2.1" } }, "sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg=="],
|
||||||
|
|
||||||
"content-type": ["content-type@1.0.5", "", {}, "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA=="],
|
"content-type": ["content-type@1.0.5", "", {}, "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA=="],
|
||||||
@ -62,6 +78,8 @@
|
|||||||
|
|
||||||
"cookie-signature": ["cookie-signature@1.2.2", "", {}, "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg=="],
|
"cookie-signature": ["cookie-signature@1.2.2", "", {}, "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg=="],
|
||||||
|
|
||||||
|
"cors": ["cors@2.8.5", "https://registry.npmmirror.com/cors/-/cors-2.8.5.tgz", { "dependencies": { "object-assign": "^4", "vary": "^1" } }, "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g=="],
|
||||||
|
|
||||||
"debug": ["debug@4.4.1", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ=="],
|
"debug": ["debug@4.4.1", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ=="],
|
||||||
|
|
||||||
"depd": ["depd@2.0.0", "", {}, "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw=="],
|
"depd": ["depd@2.0.0", "", {}, "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw=="],
|
||||||
@ -126,10 +144,18 @@
|
|||||||
|
|
||||||
"mime-types": ["mime-types@3.0.1", "", { "dependencies": { "mime-db": "^1.54.0" } }, "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA=="],
|
"mime-types": ["mime-types@3.0.1", "", { "dependencies": { "mime-db": "^1.54.0" } }, "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA=="],
|
||||||
|
|
||||||
|
"minimist": ["minimist@1.2.8", "https://registry.npmmirror.com/minimist/-/minimist-1.2.8.tgz", {}, "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA=="],
|
||||||
|
|
||||||
|
"mkdirp": ["mkdirp@0.5.6", "https://registry.npmmirror.com/mkdirp/-/mkdirp-0.5.6.tgz", { "dependencies": { "minimist": "^1.2.6" }, "bin": { "mkdirp": "bin/cmd.js" } }, "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw=="],
|
||||||
|
|
||||||
"ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
|
"ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
|
||||||
|
|
||||||
|
"multer": ["multer@2.0.2", "https://registry.npmmirror.com/multer/-/multer-2.0.2.tgz", { "dependencies": { "append-field": "^1.0.0", "busboy": "^1.6.0", "concat-stream": "^2.0.0", "mkdirp": "^0.5.6", "object-assign": "^4.1.1", "type-is": "^1.6.18", "xtend": "^4.0.2" } }, "sha512-u7f2xaZ/UG8oLXHvtF/oWTRvT44p9ecwBBqTwgJVq0+4BW1g8OW01TyMEGWBHbyMOYVHXslaut7qEQ1meATXgw=="],
|
||||||
|
|
||||||
"negotiator": ["negotiator@1.0.0", "", {}, "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg=="],
|
"negotiator": ["negotiator@1.0.0", "", {}, "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg=="],
|
||||||
|
|
||||||
|
"object-assign": ["object-assign@4.1.1", "https://registry.npmmirror.com/object-assign/-/object-assign-4.1.1.tgz", {}, "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg=="],
|
||||||
|
|
||||||
"object-inspect": ["object-inspect@1.13.4", "", {}, "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew=="],
|
"object-inspect": ["object-inspect@1.13.4", "", {}, "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew=="],
|
||||||
|
|
||||||
"on-finished": ["on-finished@2.4.1", "", { "dependencies": { "ee-first": "1.1.1" } }, "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg=="],
|
"on-finished": ["on-finished@2.4.1", "", { "dependencies": { "ee-first": "1.1.1" } }, "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg=="],
|
||||||
@ -152,6 +178,8 @@
|
|||||||
|
|
||||||
"raw-body": ["raw-body@3.0.0", "", { "dependencies": { "bytes": "3.1.2", "http-errors": "2.0.0", "iconv-lite": "0.6.3", "unpipe": "1.0.0" } }, "sha512-RmkhL8CAyCRPXCE28MMH0z2PNWQBNk2Q09ZdxM9IOOXwxwZbN+qbWaatPkdkWIKL2ZVDImrN/pK5HTRz2PcS4g=="],
|
"raw-body": ["raw-body@3.0.0", "", { "dependencies": { "bytes": "3.1.2", "http-errors": "2.0.0", "iconv-lite": "0.6.3", "unpipe": "1.0.0" } }, "sha512-RmkhL8CAyCRPXCE28MMH0z2PNWQBNk2Q09ZdxM9IOOXwxwZbN+qbWaatPkdkWIKL2ZVDImrN/pK5HTRz2PcS4g=="],
|
||||||
|
|
||||||
|
"readable-stream": ["readable-stream@3.6.2", "https://registry.npmmirror.com/readable-stream/-/readable-stream-3.6.2.tgz", { "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", "util-deprecate": "^1.0.1" } }, "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA=="],
|
||||||
|
|
||||||
"router": ["router@2.2.0", "", { "dependencies": { "debug": "^4.4.0", "depd": "^2.0.0", "is-promise": "^4.0.0", "parseurl": "^1.3.3", "path-to-regexp": "^8.0.0" } }, "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ=="],
|
"router": ["router@2.2.0", "", { "dependencies": { "debug": "^4.4.0", "depd": "^2.0.0", "is-promise": "^4.0.0", "parseurl": "^1.3.3", "path-to-regexp": "^8.0.0" } }, "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ=="],
|
||||||
|
|
||||||
"safe-buffer": ["safe-buffer@5.2.1", "", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="],
|
"safe-buffer": ["safe-buffer@5.2.1", "", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="],
|
||||||
@ -174,20 +202,62 @@
|
|||||||
|
|
||||||
"statuses": ["statuses@2.0.2", "", {}, "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw=="],
|
"statuses": ["statuses@2.0.2", "", {}, "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw=="],
|
||||||
|
|
||||||
|
"streamsearch": ["streamsearch@1.1.0", "https://registry.npmmirror.com/streamsearch/-/streamsearch-1.1.0.tgz", {}, "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg=="],
|
||||||
|
|
||||||
|
"string_decoder": ["string_decoder@1.3.0", "https://registry.npmmirror.com/string_decoder/-/string_decoder-1.3.0.tgz", { "dependencies": { "safe-buffer": "~5.2.0" } }, "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA=="],
|
||||||
|
|
||||||
"toidentifier": ["toidentifier@1.0.1", "", {}, "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA=="],
|
"toidentifier": ["toidentifier@1.0.1", "", {}, "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA=="],
|
||||||
|
|
||||||
"type-is": ["type-is@2.0.1", "", { "dependencies": { "content-type": "^1.0.5", "media-typer": "^1.1.0", "mime-types": "^3.0.0" } }, "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw=="],
|
"type-is": ["type-is@2.0.1", "", { "dependencies": { "content-type": "^1.0.5", "media-typer": "^1.1.0", "mime-types": "^3.0.0" } }, "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw=="],
|
||||||
|
|
||||||
|
"typedarray": ["typedarray@0.0.6", "https://registry.npmmirror.com/typedarray/-/typedarray-0.0.6.tgz", {}, "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA=="],
|
||||||
|
|
||||||
"typescript": ["typescript@5.8.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ=="],
|
"typescript": ["typescript@5.8.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ=="],
|
||||||
|
|
||||||
"undici-types": ["undici-types@7.8.0", "", {}, "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw=="],
|
"undici-types": ["undici-types@7.10.0", "https://registry.npmmirror.com/undici-types/-/undici-types-7.10.0.tgz", {}, "sha512-t5Fy/nfn+14LuOc2KNYg75vZqClpAiqscVvMygNnlsHBFpSXdJaYtXMcdNLpl/Qvc3P2cB3s6lOV51nqsFq4ag=="],
|
||||||
|
|
||||||
"unpipe": ["unpipe@1.0.0", "", {}, "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ=="],
|
"unpipe": ["unpipe@1.0.0", "", {}, "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ=="],
|
||||||
|
|
||||||
|
"util-deprecate": ["util-deprecate@1.0.2", "https://registry.npmmirror.com/util-deprecate/-/util-deprecate-1.0.2.tgz", {}, "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="],
|
||||||
|
|
||||||
"vary": ["vary@1.1.2", "", {}, "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg=="],
|
"vary": ["vary@1.1.2", "", {}, "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg=="],
|
||||||
|
|
||||||
"wrappy": ["wrappy@1.0.2", "", {}, "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="],
|
"wrappy": ["wrappy@1.0.2", "", {}, "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="],
|
||||||
|
|
||||||
|
"xtend": ["xtend@4.0.2", "https://registry.npmmirror.com/xtend/-/xtend-4.0.2.tgz", {}, "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ=="],
|
||||||
|
|
||||||
|
"@types/body-parser/@types/node": ["@types/node@24.0.4", "", { "dependencies": { "undici-types": "~7.8.0" } }, "sha512-ulyqAkrhnuNq9pB76DRBTkcS6YsmDALy6Ua63V8OhrOBgbcYt6IOdzpw5P1+dyRIyMerzLkeYWBeOXPpA9GMAA=="],
|
||||||
|
|
||||||
|
"@types/connect/@types/node": ["@types/node@24.0.4", "", { "dependencies": { "undici-types": "~7.8.0" } }, "sha512-ulyqAkrhnuNq9pB76DRBTkcS6YsmDALy6Ua63V8OhrOBgbcYt6IOdzpw5P1+dyRIyMerzLkeYWBeOXPpA9GMAA=="],
|
||||||
|
|
||||||
|
"@types/express-serve-static-core/@types/node": ["@types/node@24.0.4", "", { "dependencies": { "undici-types": "~7.8.0" } }, "sha512-ulyqAkrhnuNq9pB76DRBTkcS6YsmDALy6Ua63V8OhrOBgbcYt6IOdzpw5P1+dyRIyMerzLkeYWBeOXPpA9GMAA=="],
|
||||||
|
|
||||||
|
"@types/send/@types/node": ["@types/node@24.0.4", "", { "dependencies": { "undici-types": "~7.8.0" } }, "sha512-ulyqAkrhnuNq9pB76DRBTkcS6YsmDALy6Ua63V8OhrOBgbcYt6IOdzpw5P1+dyRIyMerzLkeYWBeOXPpA9GMAA=="],
|
||||||
|
|
||||||
|
"@types/serve-static/@types/node": ["@types/node@24.0.4", "", { "dependencies": { "undici-types": "~7.8.0" } }, "sha512-ulyqAkrhnuNq9pB76DRBTkcS6YsmDALy6Ua63V8OhrOBgbcYt6IOdzpw5P1+dyRIyMerzLkeYWBeOXPpA9GMAA=="],
|
||||||
|
|
||||||
|
"bun-types/@types/node": ["@types/node@24.0.4", "", { "dependencies": { "undici-types": "~7.8.0" } }, "sha512-ulyqAkrhnuNq9pB76DRBTkcS6YsmDALy6Ua63V8OhrOBgbcYt6IOdzpw5P1+dyRIyMerzLkeYWBeOXPpA9GMAA=="],
|
||||||
|
|
||||||
"http-errors/statuses": ["statuses@2.0.1", "", {}, "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ=="],
|
"http-errors/statuses": ["statuses@2.0.1", "", {}, "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ=="],
|
||||||
|
|
||||||
|
"multer/type-is": ["type-is@1.6.18", "https://registry.npmmirror.com/type-is/-/type-is-1.6.18.tgz", { "dependencies": { "media-typer": "0.3.0", "mime-types": "~2.1.24" } }, "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g=="],
|
||||||
|
|
||||||
|
"@types/body-parser/@types/node/undici-types": ["undici-types@7.8.0", "", {}, "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw=="],
|
||||||
|
|
||||||
|
"@types/connect/@types/node/undici-types": ["undici-types@7.8.0", "", {}, "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw=="],
|
||||||
|
|
||||||
|
"@types/express-serve-static-core/@types/node/undici-types": ["undici-types@7.8.0", "", {}, "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw=="],
|
||||||
|
|
||||||
|
"@types/send/@types/node/undici-types": ["undici-types@7.8.0", "", {}, "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw=="],
|
||||||
|
|
||||||
|
"@types/serve-static/@types/node/undici-types": ["undici-types@7.8.0", "", {}, "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw=="],
|
||||||
|
|
||||||
|
"bun-types/@types/node/undici-types": ["undici-types@7.8.0", "", {}, "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw=="],
|
||||||
|
|
||||||
|
"multer/type-is/media-typer": ["media-typer@0.3.0", "https://registry.npmmirror.com/media-typer/-/media-typer-0.3.0.tgz", {}, "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ=="],
|
||||||
|
|
||||||
|
"multer/type-is/mime-types": ["mime-types@2.1.35", "https://registry.npmmirror.com/mime-types/-/mime-types-2.1.35.tgz", { "dependencies": { "mime-db": "1.52.0" } }, "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw=="],
|
||||||
|
|
||||||
|
"multer/type-is/mime-types/mime-db": ["mime-db@1.52.0", "https://registry.npmmirror.com/mime-db/-/mime-db-1.52.0.tgz", {}, "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,26 +1,83 @@
|
|||||||
// node run.js https://example.com/dashboard
|
import path from 'path';
|
||||||
import { chromium } from 'playwright';
|
import { chromium } from 'playwright';
|
||||||
|
|
||||||
const userDataDir = './profiles/site1';
|
const __dirname = path.dirname(new URL(import.meta.url).pathname);
|
||||||
const targetUrl = process.argv[2] || 'https://baidu.com/';
|
|
||||||
|
|
||||||
const context = await chromium.launchPersistentContext(userDataDir, {
|
export async function downloadDouyinMedia(targetUrl: string, target_id?: string) {
|
||||||
headless: true, // 无头
|
const USER_DATA_DIR = path.join(__dirname, 'profiles/site1');
|
||||||
});
|
const TARGET_URL = targetUrl;
|
||||||
await context.addInitScript({ path: './userscripts/my-script.js' });
|
const HEADLESS = true;
|
||||||
|
const TIMEOUT = 10000;
|
||||||
|
|
||||||
const page = context.pages()[0] || await context.newPage();
|
const context = await chromium.launchPersistentContext(USER_DATA_DIR, {
|
||||||
await page.goto(targetUrl, { waitUntil: 'networkidle' });
|
headless: HEADLESS,
|
||||||
|
});
|
||||||
|
|
||||||
// === 你的自动化逻辑(示例)===
|
try {
|
||||||
await page.click('text=开始任务', { timeout: 10_000 }).catch(()=>{});
|
const page = context.pages()[0] || (await context.newPage());
|
||||||
await page.waitForTimeout(1000);
|
await page.goto(TARGET_URL, { waitUntil: 'load' });
|
||||||
|
|
||||||
// @ts-ignore
|
await page.waitForSelector('.xgplayer', { timeout: TIMEOUT }).catch(() => {
|
||||||
console.log('当前用户:', await page.evaluate(() => document.title));
|
});
|
||||||
|
|
||||||
// 示例:截图/导出结果
|
if (target_id) {
|
||||||
await page.screenshot({ path: './out.png', fullPage: true });
|
await page.evaluate(`window.f_down_target_id = "${target_id}"; window.f_down_server_port = ${process.env.PORT || 6100}`)
|
||||||
|
}
|
||||||
|
|
||||||
await context.close();
|
await page.evaluate(async () => {
|
||||||
console.log('Done.');
|
const d = (globalThis as any).document;
|
||||||
|
const vEle = d.querySelector('.xgplayer video source')
|
||||||
|
const isVideo = !!vEle && !vEle.src.includes('.mp3');
|
||||||
|
|
||||||
|
const urls: string[] = isVideo ? [d.querySelector(".xgplayer video source").src] : [
|
||||||
|
...new Set(
|
||||||
|
Array.from(d.querySelectorAll('.xgplayer img'))
|
||||||
|
// @ts-ignore
|
||||||
|
.map(img => img?.src)
|
||||||
|
.filter(Boolean)
|
||||||
|
),
|
||||||
|
];
|
||||||
|
|
||||||
|
async function urlToBlob(url: string) {
|
||||||
|
const res = await fetch(url, { credentials: "omit" });
|
||||||
|
if (!res.ok) throw new Error(`fetch image failed: ${res.status}`);
|
||||||
|
return await res.blob(); // 保持原 MIME
|
||||||
|
}
|
||||||
|
|
||||||
|
const fd = new FormData();
|
||||||
|
// 附带标题作为一个普通字段
|
||||||
|
fd.append("title", d.title || "");
|
||||||
|
|
||||||
|
let idx = 1;
|
||||||
|
for (const src of urls) {
|
||||||
|
const blob = await urlToBlob(src); // ✅ 直接用字符串
|
||||||
|
const ext = (blob.type && blob.type.split("/")[1]) || "bin";
|
||||||
|
// @ts-ignore
|
||||||
|
fd.append(`file_${idx}`, blob, `media_${idx}.${ext}`);
|
||||||
|
idx++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
|
const url = new URL(`http://127.0.0.1:${window.f_down_server_port}/upload`);
|
||||||
|
url.searchParams.set("title", d.title || "");
|
||||||
|
url.searchParams.set("type", isVideo ? "video" : "image");
|
||||||
|
// @ts-ignore
|
||||||
|
url.searchParams.set("target_id", window.f_down_target_id || "");
|
||||||
|
|
||||||
|
const r = await fetch(url.toString(), {
|
||||||
|
method: "POST",
|
||||||
|
body: fd,
|
||||||
|
});
|
||||||
|
|
||||||
|
// 为了在 evaluate 内确保完成整个请求-响应流程,读取下响应
|
||||||
|
const json = await r.json().catch(() => ({}));
|
||||||
|
|
||||||
|
return json;
|
||||||
|
});
|
||||||
|
await page.waitForTimeout(1000)
|
||||||
|
|
||||||
|
} finally {
|
||||||
|
await context.close();
|
||||||
|
console.log('Done.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -5,21 +5,17 @@ const userDataDir = './profiles/site1';
|
|||||||
const startUrl = process.argv[2] || 'https://douyin.com';
|
const startUrl = process.argv[2] || 'https://douyin.com';
|
||||||
|
|
||||||
const context = await chromium.launchPersistentContext(userDataDir, {
|
const context = await chromium.launchPersistentContext(userDataDir, {
|
||||||
headless: false, // 首次建议“有头”,方便手工/2FA
|
headless: false,
|
||||||
args: ['--disable-blink-features=AutomationControlled'],
|
args: ['--disable-blink-features=AutomationControlled'],
|
||||||
});
|
});
|
||||||
await context.addInitScript({ path: './userscripts/my-script.js' });
|
|
||||||
|
|
||||||
const page = context.pages()[0] || await context.newPage();
|
const page = context.pages()[0] || await context.newPage();
|
||||||
await page.goto(startUrl, { waitUntil: 'domcontentloaded' });
|
await page.goto(startUrl, { waitUntil: 'domcontentloaded' });
|
||||||
|
|
||||||
// 在这一步完成你的登录(手输或自动化都可)
|
|
||||||
console.log('>>> 请在打开的浏览器里完成登录,完成后回到终端按回车...');
|
console.log('>>> 请在打开的浏览器里完成登录,完成后回到终端按回车...');
|
||||||
process.stdin.resume();
|
process.stdin.resume();
|
||||||
await new Promise(r => process.stdin.once('data', r));
|
await new Promise(r => process.stdin.once('data', r));
|
||||||
|
|
||||||
// 可选:导出 storageState 做备份(即使不用它,持久化目录也保存了)
|
|
||||||
await context.storageState({ path: `${userDataDir}/storageState.json` });
|
|
||||||
await context.close();
|
await context.close();
|
||||||
|
|
||||||
console.log('>>> 登录态已写入 profiles/site1/,后续可无头复用。');
|
console.log('>>> 登录态已写入 profiles/site1/,后续可无头复用。');
|
||||||
|
|||||||
173
index.ts
173
index.ts
@ -2,48 +2,20 @@ import express from 'express';
|
|||||||
import type { Request, Response, NextFunction } from 'express';
|
import type { Request, Response, NextFunction } from 'express';
|
||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
|
import cors from "cors";
|
||||||
|
import multer from "multer";
|
||||||
|
import * as douyin from './douyin'
|
||||||
|
|
||||||
const app = express();
|
const app = express();
|
||||||
const PORT = process.env.PORT || 6100;
|
const PORT = process.env.PORT || 6100;
|
||||||
|
|
||||||
// 中间件:解析 JSON 请求体
|
const __dirname = path.dirname(new URL(import.meta.url).pathname);
|
||||||
app.use(express.json({ limit: '10mb' }));
|
|
||||||
|
|
||||||
// 中间件:解析 URL 编码的请求体
|
app.use(cors());
|
||||||
app.use(express.urlencoded({ extended: true, limit: '10mb' }));
|
|
||||||
|
|
||||||
// 中间件:解析原始请求体
|
// 仅解析明确类型;不要用 '*/*'
|
||||||
app.use(express.raw({ type: '*/*', limit: '10mb' }));
|
app.use(express.json({ limit: '10mb', type: ['application/json'] }));
|
||||||
|
app.use(express.urlencoded({ extended: true, limit: '10mb', type: ['application/x-www-form-urlencoded'] }));
|
||||||
// 自定义中间件:打印所有请求的详细信息
|
|
||||||
/* app.use((req: Request, res: Response, next: NextFunction) => {
|
|
||||||
const timestamp = new Date().toISOString();
|
|
||||||
|
|
||||||
console.log('\n' + '='.repeat(80));
|
|
||||||
console.log(`[${timestamp}] 收到请求:`);
|
|
||||||
console.log(`方法: ${req.method}`);
|
|
||||||
console.log(`路径: ${req.path}`);
|
|
||||||
console.log(`完整URL: ${req.originalUrl}`);
|
|
||||||
console.log(`查询参数:`, req.query);
|
|
||||||
console.log(`请求头:`, req.headers);
|
|
||||||
|
|
||||||
// 打印请求体(如果存在)
|
|
||||||
if (req.body) {
|
|
||||||
if (Buffer.isBuffer(req.body)) {
|
|
||||||
console.log(`请求体 (原始):`, req.body.toString());
|
|
||||||
} else if (typeof req.body === 'object' && Object.keys(req.body).length > 0) {
|
|
||||||
console.log(`请求体 (JSON):`, req.body);
|
|
||||||
} else if (req.body) {
|
|
||||||
console.log(`请求体:`, req.body);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log(`客户端IP: ${req.ip}`);
|
|
||||||
console.log(`User-Agent: ${req.get('User-Agent')}`);
|
|
||||||
console.log('='.repeat(80));
|
|
||||||
|
|
||||||
next();
|
|
||||||
}); */
|
|
||||||
|
|
||||||
// QQ机器人回显功能
|
// QQ机器人回显功能
|
||||||
app.post('/', async (req: Request, res: Response) => {
|
app.post('/', async (req: Request, res: Response) => {
|
||||||
@ -65,62 +37,9 @@ app.post('/', async (req: Request, res: Response) => {
|
|||||||
if (douyinMatch) {
|
if (douyinMatch) {
|
||||||
const douyinUrl = douyinMatch[0];
|
const douyinUrl = douyinMatch[0];
|
||||||
console.log(`[抖音链接检测] 发现抖音链接: ${douyinUrl}`);
|
console.log(`[抖音链接检测] 发现抖音链接: ${douyinUrl}`);
|
||||||
|
sendMsg(`[抖音链接检测] 发现抖音链接: ${douyinUrl},启动 Chromium 中...`, target_id);
|
||||||
|
|
||||||
// 调用抖音视频解析API
|
douyin.downloadDouyinMedia(douyinUrl, target_id);
|
||||||
const apiUrl = `http://localhost:6101/api/hybrid/video_data?url=${encodeURIComponent(douyinUrl)}`;
|
|
||||||
console.log(`[抖音解析] 调用API: ${apiUrl}`);
|
|
||||||
|
|
||||||
const apiResponse = await fetch(apiUrl, {
|
|
||||||
method: 'GET',
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!apiResponse.ok)
|
|
||||||
throw new Error(`抖音API调用失败: ${apiResponse.status} ${apiResponse.statusText}`);
|
|
||||||
|
|
||||||
let vD: any = await apiResponse.json();
|
|
||||||
|
|
||||||
if (!vD.data)
|
|
||||||
throw new Error('抖音API返回数据格式错误');
|
|
||||||
|
|
||||||
vD = vD.data;
|
|
||||||
|
|
||||||
// 发送视频信息
|
|
||||||
sendMsg(`[抖音下载] ${vD.author.nickname}: ${vD.caption}\n`, target_id);
|
|
||||||
|
|
||||||
// 下载视频
|
|
||||||
const downloadUrl = `http://localhost:6101/api/download?url=${encodeURIComponent(douyinUrl)}&prefix=true&with_watermark=false`;
|
|
||||||
console.log(`[抖音下载] 调用下载API: ${downloadUrl}`);
|
|
||||||
|
|
||||||
const downloadResponse = await fetch(downloadUrl);
|
|
||||||
if (!downloadResponse.ok) {
|
|
||||||
throw new Error(`视频下载失败: ${downloadResponse.status} ${downloadResponse.statusText}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 创建下载目录
|
|
||||||
const downloadDir = process.env.DOWNLOAD_DIR || path.join(__dirname, 'downloads');
|
|
||||||
if (!fs.existsSync(downloadDir)) {
|
|
||||||
fs.mkdirSync(downloadDir, { recursive: true });
|
|
||||||
}
|
|
||||||
|
|
||||||
// 生成文件名
|
|
||||||
const timestamp = Date.now();
|
|
||||||
// 清理文件名中的非法字符
|
|
||||||
const cleanCaption = vD.caption.replace(/[<>:"/\\|?*]/g, '_').substring(0, 50);
|
|
||||||
const fileName = `${cleanCaption}_${timestamp}.mp4`;
|
|
||||||
const filePath = path.join(downloadDir, fileName);
|
|
||||||
|
|
||||||
// 保存视频文件
|
|
||||||
console.log(`[抖音下载] 保存视频到: ${filePath}`);
|
|
||||||
const buffer = await downloadResponse.arrayBuffer();
|
|
||||||
fs.writeFileSync(filePath, Buffer.from(buffer));
|
|
||||||
|
|
||||||
// 发送视频消息
|
|
||||||
console.log(`[抖音发送] 发送视频文件`);
|
|
||||||
await sendVideoMsg(filePath, target_id);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(`[错误] 处理消息时发生错误:`, error);
|
console.error(`[错误] 处理消息时发生错误:`, error);
|
||||||
@ -130,6 +49,66 @@ app.post('/', async (req: Request, res: Response) => {
|
|||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function sanitizeDirname(input: string) {
|
||||||
|
// 基础清洗:去除路径分隔符、控制字符,并截断长度(防止奇怪标题)
|
||||||
|
const s = (input || "default")
|
||||||
|
.trim()
|
||||||
|
.replace(/[\\/]+/g, "_")
|
||||||
|
.replace(/[<>:"|?*\u0000-\u001F]/g, "_")
|
||||||
|
.slice(0, 128) || "default";
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
const storage = multer.diskStorage({
|
||||||
|
destination: (req, _file, cb) => {
|
||||||
|
const title = sanitizeDirname(req.query.title as string);
|
||||||
|
const baseDir = process.env.DOWNLOAD_DIR || path.join(__dirname, "downloads");
|
||||||
|
const dest = req.query.type == 'image' ? path.join(baseDir, title) : baseDir;
|
||||||
|
|
||||||
|
fs.mkdir(dest, { recursive: true }, (err) => cb(err, dest));
|
||||||
|
}, filename: (req, file, cb) => {
|
||||||
|
const ext = path.extname(file.originalname || "");
|
||||||
|
const title = sanitizeDirname(req.query.title as string);
|
||||||
|
|
||||||
|
cb(null, `${title}_${Date.now()}_${Math.random().toString(36).slice(2)}${ext}`);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const upload = multer({
|
||||||
|
storage,
|
||||||
|
// 限制:单文件最大 1GB、最多 50 个字段(可按需调整)
|
||||||
|
limits: { fileSize: 1024 * 1024 * 1024, fields: 50, files: 50 },
|
||||||
|
fileFilter: (_req, file, cb) => {
|
||||||
|
// 只接受字段名以 file_ 开头的文件,其他拒绝
|
||||||
|
if (/^file_\d+$/i.test(file.fieldname)) cb(null, true);
|
||||||
|
else cb(new Error(`Unexpected file field: ${file.fieldname}`));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
app.post("/upload", upload.any(), (req, res) => {
|
||||||
|
// 1) 取出文件:multer.any() 把所有文件放在 req.files
|
||||||
|
const files = (req.files as Express.Multer.File[]) || [];
|
||||||
|
// 只保留我们关心的 file_*
|
||||||
|
const accepted = files.filter(f => /^file_\d+$/i.test(f.fieldname));
|
||||||
|
|
||||||
|
let meta = {
|
||||||
|
title: req.body.title,
|
||||||
|
type: req.query.type as 'video' | 'image',
|
||||||
|
target_id: req.query.target_id
|
||||||
|
};
|
||||||
|
|
||||||
|
console.log(meta);
|
||||||
|
console.log(`收到上传: ${accepted.length} 个文件`, files.map(f => f.path));
|
||||||
|
|
||||||
|
if (meta.target_id) {
|
||||||
|
const totalSize = accepted.reduce((sum, f) => sum + f.size, 0);
|
||||||
|
sendMsg(`[抖音下载] ${meta.title},已下载 ${accepted.length} 个文件,类型 ${meta.type},共 ${(totalSize/1024/1024).toFixed(2)} MB,上传中...`, meta.target_id as string);
|
||||||
|
accepted.forEach(f => {
|
||||||
|
sendMediaMsg(f.path, meta.target_id as string, meta.type);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
res.json({ ok: true, files: accepted.length, meta });
|
||||||
|
});
|
||||||
|
|
||||||
function sendMsg(msg: string, target_id: string) {
|
function sendMsg(msg: string, target_id: string) {
|
||||||
const replyMessage = {
|
const replyMessage = {
|
||||||
user_id: String(target_id),
|
user_id: String(target_id),
|
||||||
@ -145,6 +124,8 @@ function sendMsg(msg: string, target_id: string) {
|
|||||||
|
|
||||||
const replyUrl = `http://localhost:30000/send_private_msg`;
|
const replyUrl = `http://localhost:30000/send_private_msg`;
|
||||||
|
|
||||||
|
console.log(`[发送消息] ${msg} -> ${target_id}`);
|
||||||
|
|
||||||
return fetch(replyUrl, {
|
return fetch(replyUrl, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
@ -154,12 +135,12 @@ function sendMsg(msg: string, target_id: string) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function sendVideoMsg(filePath: string, target_id: string) {
|
function sendMediaMsg(filePath: string, target_id: string, type: 'video' | 'image') {
|
||||||
const videoMessage = {
|
const mediaMessage = {
|
||||||
user_id: String(target_id),
|
user_id: String(target_id),
|
||||||
message: [
|
message: [
|
||||||
{
|
{
|
||||||
type: "video",
|
type: type,
|
||||||
data: {
|
data: {
|
||||||
file: `file://${filePath}`
|
file: `file://${filePath}`
|
||||||
}
|
}
|
||||||
@ -169,12 +150,14 @@ function sendVideoMsg(filePath: string, target_id: string) {
|
|||||||
|
|
||||||
const replyUrl = `http://localhost:30000/send_private_msg`;
|
const replyUrl = `http://localhost:30000/send_private_msg`;
|
||||||
|
|
||||||
|
console.log(`[发送媒体消息] ${type} - ${filePath} -> ${target_id}`);
|
||||||
|
|
||||||
return fetch(replyUrl, {
|
return fetch(replyUrl, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
},
|
},
|
||||||
body: JSON.stringify(videoMessage)
|
body: JSON.stringify(mediaMessage)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -16,7 +16,11 @@
|
|||||||
"typescript": "^5"
|
"typescript": "^5"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@types/cors": "^2.8.19",
|
||||||
|
"@types/multer": "^2.0.0",
|
||||||
|
"cors": "^2.8.5",
|
||||||
"dotenv": "^17.0.0",
|
"dotenv": "^17.0.0",
|
||||||
"express": "^5.1.0"
|
"express": "^5.1.0",
|
||||||
|
"multer": "^2.0.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user