diff --git a/.gitignore b/.gitignore index ae8a628..502028e 100644 --- a/.gitignore +++ b/.gitignore @@ -2,7 +2,8 @@ node_modules/ /src/utils/fetchVideoStreams.js *.py -DiscordRPC.js + +test.js # Logs logs @@ -13,6 +14,8 @@ yarn-error.log* lerna-debug.log* .pnpm-debug.log* +mal.js + # Diagnostic reports (https://nodejs.org/api/report.html) report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json diff --git a/README.md b/README.md index 3fe05bc..f894ea1 100644 --- a/README.md +++ b/README.md @@ -12,8 +12,7 @@ I built NekoNode using Node.js, and I used the following libraries: - [Axios](https://www.npmjs.com/package/axios) for making HTTP requests. - [Chalk](https://www.npmjs.com/package/chalk) for styling the terminal output. - [Ora](https://www.npmjs.com/package/ora) for displaying loading spinners. -- [Figlet](https://www.npmjs.com/package/figlet) for creating ASCII art from text. -- [Consumet](https://github.com/consumet/api.consumet.org) I used this for fetching the streaming links for the anime. (Hosted on a secure server.) +- [NekoNode-API](https://github.com/DeveloperJosh/nekonode-api) I used this for fetching the streaming links for the anime. (Hosted on a secure server.) ## Supported Platforms @@ -44,8 +43,6 @@ I built NekoNode using Node.js, and I used the following libraries: - [MPV](https://mpv.io/) - - ## Found a Bug? If you find a bug or have a feature request, please open an issue on the [NekoNode GitHub repository](https://github.com/DeveloperJosh/anime-cli/issues) make sure it has the `bug` Label. \ No newline at end of file diff --git a/bun.lockb b/bun.lockb new file mode 100644 index 0000000..69cd9f1 Binary files /dev/null and b/bun.lockb differ diff --git a/package-lock.json b/package-lock.json index 397094d..115a9dd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,23 +1,28 @@ { "name": "nekonode", - "version": "1.1.3", + "version": "1.1.7", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "nekonode", - "version": "1.1.3", + "version": "1.1.7", "license": "MIT", "dependencies": { "axios": "^1.7.2", + "chalk": "^5.3.0", "cheerio": "^1.0.0-rc.12", "cli-table3": "^0.6.5", "commander": "^8.0.0", + "crypto": "^1.0.1", "discord-rpc": "^4.0.1", + "dotenv": "^16.4.5", + "express": "^4.19.2", "figlet": "^1.7.0", "fluent-ffmpeg": "^2.1.3", - "inquirer": "^9.2.23", + "inquirer": "^9.3.6", "js-yaml": "^4.1.0", + "open": "^10.1.0", "ora": "^5.4.1", "uuid": "^10.0.0" }, @@ -42,15 +47,16 @@ "node": ">=18" } }, - "node_modules/@ljharb/through": { - "version": "2.3.13", - "resolved": "https://registry.npmjs.org/@ljharb/through/-/through-2.3.13.tgz", - "integrity": "sha512-/gKJun8NNiWGZJkGzI/Ragc53cOdcLNdzjLaIa+GEjguQs0ulsurx8WN0jijdK9yPqDvziX995sMRLyLt1uZMQ==", + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", "dependencies": { - "call-bind": "^1.0.7" + "mime-types": "~2.1.34", + "negotiator": "0.6.3" }, "engines": { - "node": ">= 0.4" + "node": ">= 0.6" } }, "node_modules/ansi-escapes": { @@ -94,6 +100,11 @@ "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" }, + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" + }, "node_modules/async": { "version": "0.2.10", "resolved": "https://registry.npmjs.org/async/-/async-0.2.10.tgz", @@ -152,6 +163,29 @@ "readable-stream": "^3.4.0" } }, + "node_modules/body-parser": { + "version": "1.20.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", + "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.5", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.11.0", + "raw-body": "2.5.2", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, "node_modules/boolbase": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", @@ -180,6 +214,28 @@ "ieee754": "^1.1.13" } }, + "node_modules/bundle-name": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-4.1.0.tgz", + "integrity": "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==", + "dependencies": { + "run-applescript": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/call-bind": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", @@ -199,15 +255,11 @@ } }, "node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", "engines": { - "node": ">=10" + "node": "^12.17.0 || ^14.13 || >=16.0.0" }, "funding": { "url": "https://github.com/chalk/chalk?sponsor=1" @@ -341,6 +393,44 @@ "node": ">= 12" } }, + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" + }, + "node_modules/crypto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/crypto/-/crypto-1.0.1.tgz", + "integrity": "sha512-VxBKmeNcqQdiUQUW2Tzq0t377b54N2bMtXO/qiLa+6eRRmmC4qT3D4OnTGoT/U6O9aklQ/jTwbOtRMTTY8G0Ig==", + "deprecated": "This package is no longer supported. It's now a built-in Node module. If you've depended on crypto, you should switch to the one that's built-in." + }, "node_modules/css-select": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz", @@ -367,6 +457,40 @@ "url": "https://github.com/sponsors/fb55" } }, + "node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/default-browser": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-5.2.1.tgz", + "integrity": "sha512-WY/3TUME0x3KPYdRRxEJJvXRHV4PyPoUsxtZa78lwItwRQRHhd2U9xOscaT/YTf8uCXIAjeJOFBVEh/7FtD8Xg==", + "dependencies": { + "bundle-name": "^4.1.0", + "default-browser-id": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/default-browser-id": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-5.0.0.tgz", + "integrity": "sha512-A6p/pu/6fyBcA1TRz/GqWYPViplrftcW2gZC9q79ngNCKAeR/X3gcEdXQHl4KNXV+3wgIJ1CPkJQ3IHM6lcsyA==", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/defaults": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", @@ -394,6 +518,17 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/define-lazy-prop": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz", + "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", @@ -402,6 +537,23 @@ "node": ">=0.4.0" } }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, "node_modules/discord-rpc": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/discord-rpc/-/discord-rpc-4.0.1.tgz", @@ -465,11 +617,35 @@ "url": "https://github.com/fb55/domutils?sponsor=1" } }, + "node_modules/dotenv": { + "version": "16.4.5", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.5.tgz", + "integrity": "sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" + }, "node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" }, + "node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/entities": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", @@ -500,6 +676,60 @@ "node": ">= 0.4" } }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/express": { + "version": "4.19.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz", + "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==", + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.2", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.6.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.2.0", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.7", + "qs": "6.11.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.18.0", + "serve-static": "1.15.0", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + } + }, "node_modules/external-editor": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", @@ -530,6 +760,23 @@ "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", "optional": true }, + "node_modules/finalhandler": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", + "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/fluent-ffmpeg": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/fluent-ffmpeg/-/fluent-ffmpeg-2.1.3.tgz", @@ -574,6 +821,22 @@ "node": ">= 6" } }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/function-bind": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", @@ -681,6 +944,21 @@ "entities": "^4.4.0" } }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/iconv-lite": { "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", @@ -717,39 +995,47 @@ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, "node_modules/inquirer": { - "version": "9.2.23", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-9.2.23.tgz", - "integrity": "sha512-kod5s+FBPIDM2xiy9fu+6wdU/SkK5le5GS9lh4FEBjBHqiMgD9lLFbCbuqFNAjNL2ZOy9Wd9F694IOzN9pZHBA==", + "version": "9.3.6", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-9.3.6.tgz", + "integrity": "sha512-riK/iQB2ctwkpWYgjjWIRv3MBLt2gzb2Sj0JNQNbyTXgyXsLWcDPJ5WS5ZDTCx7BRFnJsARtYh+58fjP5M2Y0Q==", "dependencies": { "@inquirer/figures": "^1.0.3", - "@ljharb/through": "^2.3.13", "ansi-escapes": "^4.3.2", - "chalk": "^5.3.0", - "cli-cursor": "^3.1.0", "cli-width": "^4.1.0", "external-editor": "^3.1.0", - "lodash": "^4.17.21", "mute-stream": "1.0.0", "ora": "^5.4.1", "run-async": "^3.0.0", "rxjs": "^7.8.1", "string-width": "^4.2.3", "strip-ansi": "^6.0.1", - "wrap-ansi": "^6.2.0" + "wrap-ansi": "^6.2.0", + "yoctocolors-cjs": "^2.1.2" }, "engines": { "node": ">=18" } }, - "node_modules/inquirer/node_modules/chalk": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", - "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", "engines": { - "node": "^12.17.0 || ^14.13 || >=16.0.0" + "node": ">= 0.10" + } + }, + "node_modules/is-docker": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", + "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" }, "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/is-fullwidth-code-point": { @@ -760,6 +1046,23 @@ "node": ">=8" } }, + "node_modules/is-inside-container": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz", + "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", + "dependencies": { + "is-docker": "^3.0.0" + }, + "bin": { + "is-inside-container": "cli.js" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-interactive": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", @@ -779,6 +1082,20 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/is-wsl": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.0.tgz", + "integrity": "sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw==", + "dependencies": { + "is-inside-container": "^1.0.0" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", @@ -795,11 +1112,6 @@ "js-yaml": "bin/js-yaml.js" } }, - "node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" - }, "node_modules/log-symbols": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", @@ -815,6 +1127,53 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/log-symbols/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/mime-db": { "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", @@ -842,6 +1201,11 @@ "node": ">=6" } }, + "node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, "node_modules/mute-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-1.0.0.tgz", @@ -850,6 +1214,14 @@ "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/node-addon-api": { "version": "1.7.2", "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-1.7.2.tgz", @@ -886,6 +1258,28 @@ "url": "https://github.com/fb55/nth-check?sponsor=1" } }, + "node_modules/object-inspect": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz", + "integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/onetime": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", @@ -900,6 +1294,23 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/open": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/open/-/open-10.1.0.tgz", + "integrity": "sha512-mnkeQ1qP5Ue2wd+aivTD3NHd/lZ96Lu0jgf0pwktLPtx6cTZiH7tyeGRRHs0zX0rbrahXPnXlUnbeXyaBBuIaw==", + "dependencies": { + "default-browser": "^5.2.1", + "define-lazy-prop": "^3.0.0", + "is-inside-container": "^1.0.0", + "is-wsl": "^3.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/ora": { "version": "5.4.1", "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", @@ -922,6 +1333,21 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/ora/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, "node_modules/os-tmpdir": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", @@ -953,11 +1379,72 @@ "url": "https://github.com/inikulin/parse5?sponsor=1" } }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, "node_modules/proxy-from-env": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" }, + "node_modules/qs": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "dependencies": { + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/readable-stream": { "version": "3.6.2", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", @@ -994,6 +1481,17 @@ "node": ">=8" } }, + "node_modules/run-applescript": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-7.0.0.tgz", + "integrity": "sha512-9by4Ij99JUr/MCFBUkDKLWK3G9HVXmabKz9U5MlIAIuvuzkiOicRYs8XJLxX+xahD+mLiiCYDqF9dKAgtzKP1A==", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/run-async": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/run-async/-/run-async-3.0.0.tgz", @@ -1034,6 +1532,48 @@ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, + "node_modules/send": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "node_modules/serve-static": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "dependencies": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.18.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, "node_modules/set-function-length": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", @@ -1050,11 +1590,41 @@ "node": ">= 0.4" } }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" + }, + "node_modules/side-channel": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", + "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", + "dependencies": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "object-inspect": "^1.13.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/signal-exit": { "version": "3.0.7", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" }, + "node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/string_decoder": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", @@ -1109,6 +1679,14 @@ "node": ">=0.6.0" } }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "engines": { + "node": ">=0.6" + } + }, "node_modules/tr46": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", @@ -1130,11 +1708,39 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "engines": { + "node": ">= 0.4.0" + } + }, "node_modules/uuid": { "version": "10.0.0", "resolved": "https://registry.npmjs.org/uuid/-/uuid-10.0.0.tgz", @@ -1147,6 +1753,14 @@ "uuid": "dist/bin/uuid" } }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/wcwidth": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", @@ -1212,6 +1826,17 @@ "optional": true } } + }, + "node_modules/yoctocolors-cjs": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yoctocolors-cjs/-/yoctocolors-cjs-2.1.2.tgz", + "integrity": "sha512-cYVsTjKl8b+FrnidjibDWskAv7UKOfcwaVZdp/it9n1s9fU3IkgDbhdIRKCW4JDsAlECJY0ytoVPT3sK6kideA==", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } } } } diff --git a/package.json b/package.json index 9d252f8..556da9e 100644 --- a/package.json +++ b/package.json @@ -1,12 +1,16 @@ { "name": "nekonode", - "version": "1.1.5-dev", + "version": "1.1.8", "description": "nekonode is a CLI tool to search and watch anime", "type": "module", "main": "src/main.js", "repository": "https://github.com/DeveloperJosh/anime-cli", "homepage": "https://github.com/DeveloperJosh/anime-cli#readme", "license": "MIT", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1", + "start": "node src/main.js" + }, "bin": { "nekonode": "src/main.js" }, @@ -17,14 +21,19 @@ ], "dependencies": { "axios": "^1.7.2", + "chalk": "^5.3.0", "cheerio": "^1.0.0-rc.12", "cli-table3": "^0.6.5", "commander": "^8.0.0", + "crypto": "^1.0.1", "discord-rpc": "^4.0.1", + "dotenv": "^16.4.5", + "express": "^4.19.2", "figlet": "^1.7.0", "fluent-ffmpeg": "^2.1.3", - "inquirer": "^9.2.23", + "inquirer": "^9.3.6", "js-yaml": "^4.1.0", + "open": "^10.1.0", "ora": "^5.4.1", "uuid": "^10.0.0" } diff --git a/src/commands/list.js b/src/commands/list.js index 07bd27b..61a57f1 100644 --- a/src/commands/list.js +++ b/src/commands/list.js @@ -1,6 +1,6 @@ import AnimeList from '../utils/animelist.js'; -import inquirer from 'inquirer'; // Correctly import inquirer -import chalk from 'chalk'; // Correctly import chalk +import inquirer from 'inquirer'; +import chalk from 'chalk'; import ora from 'ora'; import configLoader from '../utils/configLoader.js'; @@ -19,20 +19,20 @@ async function listAnime() { type: 'list', name: 'animeListName', message: 'Select an option:', - choices: ['Get', 'Add', 'Remove', 'Exit'] + choices: ['View list', 'Add to list', 'Remove from list', 'Exit'] }); switch (animeListName) { case 'Exit': console.log('Exiting...'); process.exit(0); - case 'Get': + case 'View list': await handleGetAnime(animeListNames); break; - case 'Add': + case 'Add to list': await handleAddAnime(); break; - case 'Remove': + case 'Remove from list': await handleRemoveAnime(animeListNames); break; } diff --git a/src/commands/new.js b/src/commands/new.js index 376c72c..b5abfa1 100644 --- a/src/commands/new.js +++ b/src/commands/new.js @@ -1,5 +1,4 @@ import axios from 'axios'; -import { load } from 'cheerio'; import loadConfig from '../utils/configLoader.js'; import ora from 'ora'; import Table from 'cli-table3'; @@ -7,41 +6,33 @@ import chalk from 'chalk'; import inquirer from 'inquirer'; import watchAnime from './watch.js'; -// Load configuration using the configLoader utility const config = loadConfig(); async function fetchNewestAnime() { console.clear(); const spinner = ora('Fetching newest anime...').start(); - const newAnimeUrl = `${config.baseUrl}/`; + const newAnimeUrl = `${config.api}/api/latest`; try { - // Make a GET request to fetch the latest anime data const response = await axios.get(newAnimeUrl); - const $ = load(response.data); - const animeList = []; + const animeList = response.data; - // Parse the HTML to extract anime information - $('.last_episodes .items li').each((_, element) => { - const animeElement = $(element); - const animeName = animeElement.find('.name a').attr('title').trim(); - const episodeUrl = animeElement.find('.name a').attr('href'); - const episodeNumber = animeElement.find('.episode').text().trim(); - const imgUrl = animeElement.find('.img a img').attr('src'); - - animeList.push({ - name: animeName, - episode: episodeNumber, - url: `${config.baseUrl}${episodeUrl}`, - // img: imgUrl - }); - }); - - // Stop the spinner once the data is fetched and processed - spinner.stop(); + console.clear(); + /* + how the data is structured: + [ + { + name: 'title', + encodedName: 'encodedTitle', + lang: 'sub', + image: 'imageLink', + url: 'animeLink' + } + ] + */ console.info(chalk.cyanBright.bold('\nNewest Anime Releases:\n')); - + // Determine the maximum length of anime names const maxNameLength = Math.max(...animeList.map(anime => anime.name.length), 10); @@ -57,21 +48,20 @@ async function fetchNewestAnime() { }); animeList.forEach(anime => { + let url = anime.url; + // Extract the episode number from the URL + let episodeMatch = url.match(/(?:episode-)(\d+)/i); + let episodeNumber = episodeMatch ? episodeMatch[1] : 'N/A'; table.push([ chalk.blueBright(anime.name), - chalk.yellowBright(anime.episode) + chalk.yellowBright(episodeNumber) ]); }); console.log(table.toString()); - - // Display anime URLs with color - // animeList.forEach(anime => { - // console.log(`${chalk.magenta('Watch here:')} ${chalk.underline.cyan(anime.url)}`); - // }); + + spinner.stop(); - // Exit the process successfully - // back to the main menu await inquirer.prompt([ { type: 'input', @@ -80,7 +70,7 @@ async function fetchNewestAnime() { } ]); console.clear(); - console.log(chalk.bgBlueBright('Welcome to NekoNode Watcher!')); + //console.log(chalk.bgBlueBright('Welcome to NekoNode Watcher!')); await watchAnime(); } catch (error) { // Handle errors and stop the spinner if an error occurs diff --git a/src/commands/watch.js b/src/commands/watch.js index 9a930dd..ae81e5b 100644 --- a/src/commands/watch.js +++ b/src/commands/watch.js @@ -1,25 +1,12 @@ -const originalEmitWarning = process.emitWarning; - -process.emitWarning = (warning, ...args) => { - if (typeof warning === 'string' && warning.startsWith('DeprecationWarning')) { - // Suppress specific deprecation warnings - return; - } - originalEmitWarning(warning, ...args); -}; - - import inquirer from 'inquirer'; -// color console output import chalk from 'chalk'; -import readline from 'node:readline'; +import ora from 'ora'; import axios from 'axios'; import Table from 'cli-table3'; import { exec } from 'child_process'; import { homedir } from 'node:os'; import { join } from 'node:path'; import { existsSync, mkdirSync } from 'node:fs'; - import fetchAnime from '../utils/fetchAnime.js'; import fetchEpisodes from '../utils/fetchEpisodes.js'; import History from '../utils/history.js'; @@ -40,10 +27,8 @@ let currentEpisode = null; async function watchAnime() { console.clear(); - // add a background color to the console console.log(chalk.bgBlueBright('Welcome to NekoNode Watcher!')); - // Check config for player and then check if it is installed exec(`${config.player} --version`, (error, stdout, stderr) => { if (error) { console.error(`Error: ${config.player} is not installed. Please install ${config.player} and try again.`); @@ -63,36 +48,48 @@ async function displayMenu() { choices: ['Search', 'Help', 'View History', 'List Manager', 'New Anime', 'Exit'] }); - if (action === 'Search') { - await selectAnime(); - } else if (action === 'Help') { - console.clear(); - console.log(chalk.bgBlueBright('Help Menu:')); - console.log('Search: Search for an anime to watch'); - console.log('Help: Display this help menu'); - console.log('View History: View the history of watched episodes'); - console.log('List Manager: Manage your anime list (This is separate from the history and this menu)'); - console.log('New Anime: Fetch the newest anime releases'); - console.log('Exit: Exit the program'); - await promptReturnToMenu(); - } else if (action === 'New Anime') { - await fetchNewestAnime(); - } else if (action === 'List Manager') { - await listAnime(); - } else if (action === 'View History') { - await viewHistory(); - } else if (action === 'Exit') { - console.log('Exiting...'); - process.exit(0); + switch (action) { + case 'Search': + await selectAnime(); + break; + case 'Help': + displayHelpMenu(); + await promptReturnToMenu(); + break; + case 'New Anime': + await fetchNewestAnime(); + await promptReturnToMenu(); + break; + case 'List Manager': + await listAnime(); + await promptReturnToMenu(); + break; + case 'View History': + await viewHistory(); + await promptReturnToMenu(); + break; + case 'Exit': + console.log('Exiting...'); + process.exit(0); } } } +function displayHelpMenu() { + console.clear(); + console.log(chalk.bgBlueBright('Help Menu:')); + console.log('Search: Search for an anime to watch'); + console.log('Help: Display this help menu'); + console.log('View History: View the history of watched episodes'); + console.log('List Manager: Manage your anime list'); + console.log('New Anime: Fetch the newest anime releases'); + console.log('Exit: Exit the program'); +} + async function viewHistory() { const historyList = history.getHistory(); if (historyList.length === 0) { console.log('No history found.'); - await promptReturnToMenu(); return; } @@ -109,8 +106,6 @@ async function viewHistory() { console.log(table.toString()); console.info('\nEnd of History\n'); - - await promptReturnToMenu(); } async function selectAnime() { @@ -124,7 +119,6 @@ async function selectAnime() { const animeResults = await fetchAnime(animeName); if (animeResults.length === 0) { console.log('No anime found.'); - await promptReturnToMenu(); return; } @@ -147,7 +141,6 @@ async function selectEpisode() { const episodeData = await fetchEpisodes(currentAnime.url); if (!episodeData || episodeData.episodes.length === 0) { console.log('No episodes found.'); - await promptReturnToMenu(); return; } @@ -159,19 +152,25 @@ async function selectEpisode() { }); const episodeId = episodeChoice.url.split('/').pop(); - const response = await axios.get(`${config.api}/anime/gogoanime/watch/${episodeId}`, { - params: { server: 'gogocdn' } - }); - - const videoUrl = findVideoUrl(response.data.sources); + // const response = await axios.get(`${config.api}/anime/gogoanime/watch/${episodeId}`, { + // params: { server: 'gogocdn' } + // }); + //fs.writeFileSync('test.json', JSON.stringify(`${config.api}/api/watch/${episodeId}`)); + const response = await axios.get(`${config.api}/api/watch/${episodeId}`); + + //fs.writeFileSync('test.json', JSON.stringify(response.data)); + const videoUrl = findVideoUrl(response.data); + //fs.writeFileSync('url.json', JSON.stringify(response.data)); if (!videoUrl) { console.log('No video URL found for the selected episode.'); - await promptReturnToMenu(); return; } history.save(currentAnime.name, episodeChoice.title, episodeChoice.url, videoUrl); + + const spinner = ora('Loading video...').start(); playVideo(videoUrl, currentAnime.name, episodeChoice.title); + spinner.stop(); currentEpisode = episodeChoice; setRichPresence( @@ -191,86 +190,68 @@ async function selectEpisode() { } function findVideoUrl(sources) { - let videoUrl = sources.find(source => source.quality === '1080p')?.url; - if (!videoUrl) { - videoUrl = sources.find(source => source.quality === 'backup')?.url; - } - return videoUrl; + // Find 1080p quality video URL + const highestQuality = sources.find(source => source.quality === '1080p'); + + // Find backup quality video URL + const backupQuality = sources.find(source => source.quality === 'backup'); + + // Return 1080p URL if available, otherwise return backup URL + return highestQuality ? highestQuality.source : backupQuality ? backupQuality.source : null; } async function episodeMenu(currentEpisodeId) { - console.clear(); - //console.log(`Current Anime: ${currentAnime.name}`); - console.log(chalk.bgBlueBright(`Current Episode: ${currentAnime.name}`)); - if (!currentEpisodeId) { - console.log('Error: No episode ID provided.'); - return; - } + while (true) { + console.clear(); + console.log(chalk.bgBlueBright(`Current Episode: ${currentAnime.name} - ${currentEpisode.title}`)); + if (!currentEpisodeId) { + console.log('Error: No episode ID provided.'); + return; + } - const { action } = await inquirer.prompt({ - type: 'list', - name: 'action', - message: 'Select an option:', - choices: [ - 'Next Episode', - 'Previous Episode', - 'Reply Episode', - 'Anime Info', - 'Download', - 'Save To List', - 'Return to main menu' - ] - }); + const { action } = await inquirer.prompt({ + type: 'list', + name: 'action', + message: 'Select an option:', + choices: [ + 'Next Episode', + 'Previous Episode', + /// 'Replay Episode', + 'Choose Episode', + 'Anime Info', + 'Download', + 'Save To List', + 'Return to main menu' + ] + }); - switch (action) { - case 'Next Episode': - await navigateEpisode(currentEpisodeId, 1); - currentEpisodeId += 1; - break; - case 'Reply Episode': - await navigateEpisode(currentEpisodeId, 0); - break; - case 'Previous Episode': - await navigateEpisode(currentEpisodeId, -1); - currentEpisodeId -= 1; - break; - case 'Download': - await downloadEpisode(currentEpisodeId); - break; - case 'Save To List': - let episodeNumber = parseInt(currentEpisodeId.split('-').pop()); - episodeNumber = episodeNumber.toString(); - //update currentEpisode.url to have the episode number - currentEpisode.url = `${config.baseUrl}/${currentAnime.name.replace(/\s/g, '-').toLowerCase()}-episode-${episodeNumber}`; - animeList.save(currentAnime.name, episodeNumber, currentEpisode.url); - console.log('Episode saved to anime list.'); - await promptReturnToMenu(); - await episodeMenu(currentEpisodeId); - break; - case 'Anime Info': - console.clear(); - let name = currentAnime.name; - let animeNameSlug = name.toLowerCase().replace(/\s/g, '-'); - if (animeNameSlug.includes(':')) { - animeNameSlug = animeNameSlug.replace(':', ''); - } - if (animeNameSlug.includes('-(dub)')) { - animeNameSlug = animeNameSlug.replace('-(dub)', ''); - } - const infoUrl = `${config.api}/anime/gogoanime/info/${animeNameSlug}`; - const infoResponse = await axios.get(infoUrl); - let animeInfo = infoResponse.data; - let text = `Title: ${animeInfo.title}\nTotal Episodes: ${animeInfo.totalEpisodes}\nGenres: ${animeInfo.genres.join(', ')}\nStatus: ${animeInfo.status}\nRelease Date: ${animeInfo.releaseDate}\nType: ${animeInfo.type}\nDescription: ${animeInfo.description}`; - console.log(text); - await promptReturnToMenu(); - await episodeMenu(currentEpisodeId); - break; - case 'Return to main menu': - await displayMenu(); - break; + switch (action) { + case 'Next Episode': + currentEpisodeId = await navigateEpisode(currentEpisodeId, 1); + break; + // case 'Replay Episode': + // await navigateEpisode(currentEpisodeId, 0); + // break; + case 'Previous Episode': + currentEpisodeId = await navigateEpisode(currentEpisodeId, -1); + break; + case 'Choose Episode': + await selectEpisode(); + return; // Exit the episode menu loop + case 'Download': + await downloadEpisode(currentEpisodeId); + break; + case 'Save To List': + saveEpisodeToList(currentEpisodeId); + await promptReturnToMenu(); + break; + case 'Anime Info': + await showAnimeInfo(currentAnime.name); + break; + case 'Return to main menu': + return; // Exit the episode menu loop + } } - - await episodeMenu(currentEpisodeId); } async function navigateEpisode(currentEpisodeId, direction) { @@ -279,19 +260,21 @@ async function navigateEpisode(currentEpisodeId, direction) { let episodeNumber = parseInt(currentEpisodeId.split('-').pop()) + direction; const nextEpisodeId = `${basePart}${episodeNumber}`; - const response = await axios.get(`${config.api}/anime/gogoanime/watch/${nextEpisodeId}`, { - params: { server: 'gogocdn' } - }); + // const response = await axios.get(`${config.api}/anime/gogoanime/watch/${nextEpisodeId}`, { + // params: { server: 'gogocdn' } + // }); + + const response = await axios.get(`${config.api}/api/watch/${nextEpisodeId}`); - const videoUrl = findVideoUrl(response.data.sources); + const videoUrl = findVideoUrl(response.data); if (!videoUrl) { console.log('No more episodes found.'); - await promptReturnToMenu(); - return; + return currentEpisodeId; // Stay on current episode } const link = `${config.baseUrl}/${currentAnime.name.replace(/\s/g, '-').toLowerCase()}-episode-${episodeNumber}`; history.save(currentAnime.name, `EP ${episodeNumber}`, link, videoUrl); + currentEpisode = { title: `EP ${episodeNumber}`, url: link }; playVideo(videoUrl, currentAnime.name, `Episode ${episodeNumber}`); setRichPresence( `Watching ${currentAnime.name} - Episode ${episodeNumber}`, @@ -303,26 +286,24 @@ async function navigateEpisode(currentEpisodeId, direction) { 'Active' ); - await episodeMenu(nextEpisodeId); + return nextEpisodeId; } catch (error) { console.error('Error navigating episodes:', error.message); + return currentEpisodeId; // Stay on current episode } } -const sanitizeFileName = (name) => { - return name.replace(/[:<>?"|*\/\\]/g, '_'); -}; - async function downloadEpisode(currentEpisodeId) { try { - const response = await axios.get(`${config.api}/anime/gogoanime/watch/${currentEpisodeId}`, { - params: { server: 'gogocdn' } - }); + //const response = await axios.get(`${config.api}/anime/gogoanime/watch/${currentEpisodeId}`, { + // params: { server: 'gogocdn' } + // }); + //console.log(currentEpisodeId); + const response = await axios.get(`${config.api}/api/watch/${currentEpisodeId}`); - const videoUrl = findVideoUrl(response.data.sources); + const videoUrl = findVideoUrl(response.data); if (!videoUrl) { console.log('No video found.'); - await promptReturnToMenu(); return; } @@ -334,12 +315,12 @@ async function downloadEpisode(currentEpisodeId) { if (!confirmDownload) { console.log('Download cancelled.'); - await promptReturnToMenu(); return; } console.clear(); const sanitizedAnimeName = sanitizeFileName(currentAnime.name); + //console.log(`Downloading episode "${currentEpisode.title}" of anime "${currentAnime.name}"...`); const videosPath = join(homedir(), 'Videos'); const animePath = join(videosPath, sanitizedAnimeName); @@ -354,26 +335,85 @@ async function downloadEpisode(currentEpisodeId) { console.log(`Created directory: ${animePath}`); } await convertUrlToMp4(videoUrl, outputFilePath); - - console.log(`Episode saved to: ${outputFilePath}`); + console.log('File:', outputFilePath); await promptReturnToMenu(); - await episodeMenu(currentEpisodeId); - } catch (error) { console.error('Error encountered:', error.message); - console.error('Full error details:', error); } } +function saveEpisodeToList(currentEpisodeId) { + console.log('Saving episode to list...'); + console.log('Current Episode ID:', currentEpisodeId); + + // Check if currentEpisodeId is valid + if (!currentEpisodeId) { + console.error('Invalid episode ID.'); + return; + } + + let episodeNumber = parseInt(currentEpisodeId.split('-').pop()); + console.log('Parsed Episode Number:', episodeNumber); + + // Check if currentAnime and currentEpisode are set + if (!currentAnime || !currentAnime.name) { + console.error('No current anime selected.'); + return; + } + + if (!currentEpisode || !currentEpisode.title) { + console.error('No current episode selected.'); + return; + } + + ///const episodeUrl = `${config.baseUrl}/${currentAnime.name.replace(/\s/g, '-').toLowerCase()}-episode-${episodeNumber}`; + const episodeUrl = `https://nekonode.net/anime/${currentAnime.name.replace(/\s/g, '-').toLowerCase()}?ep=${episodeNumber}`; + console.log('Constructed Episode URL:', episodeUrl); + + // Update the current episode's URL + currentEpisode.url = episodeUrl; + + try { + animeList.save(currentAnime.name, episodeNumber.toString(),episodeUrl); + console.log(`Episode "${currentEpisode.title}" of anime "${currentAnime.name}" saved to anime list.`); + } catch (error) { + console.error('Error saving to anime list:', error.message); + } +} + +async function showAnimeInfo(animeName) { + console.clear(); + // tensei-kizoku,-kantei-skill-de-nariagaru + // remove , and - from anime name + let animeNameSlug = animeName.toLowerCase() + .replace(/\s/g, '-') + .replace(/:/g, '') + .replace(/\(dub\)/g, 'dub') + .replace(/, /g, '-') + .replace(/,/g, '') + .replace(/-+$/, ''); + + const infoUrl = `${config.api}/api/info/${animeNameSlug}`; + //fs.writeFileSync('test.json', JSON.stringify(infoUrl)); + const infoResponse = await axios.get(infoUrl); + let animeInfo = infoResponse.data; + let text = `Title: ${animeInfo.title}\nTotal Episodes: ${animeInfo.totalEpisodes}\nGenres: ${animeInfo.genres.join(', ')}\nStatus: ${animeInfo.status}\nRelease Date: ${animeInfo.released}\nDescription: ${animeInfo.description}`; + console.log(text); + await promptReturnToMenu(); +} + async function promptReturnToMenu() { await inquirer.prompt({ type: 'input', name: 'back', message: 'Hit enter to go back' }); - console.clear(); console.log(chalk.bgBlueBright('Welcome to NekoNode Watcher!')); } +const sanitizeFileName = (name) => { + return name.replace(/[:<>?"|*\/\\]/g, '_'); +}; + export default watchAnime; diff --git a/src/main.js b/src/main.js index 8462d65..eb40394 100644 --- a/src/main.js +++ b/src/main.js @@ -1,16 +1,5 @@ #!/usr/bin/env node -// Suppress deprecation warnings -const originalEmitWarning = process.emitWarning; - -process.emitWarning = (warning, ...args) => { - if (typeof warning === 'string' && warning.startsWith('DeprecationWarning')) { - // Suppress specific deprecation warnings - return; - } - originalEmitWarning(warning, ...args); -}; - import { Command } from 'commander'; import watchAnime from './commands/watch.js'; import listAnime from './commands/list.js'; @@ -18,12 +7,14 @@ import fetchNewestAnime from './commands/new.js'; import History from './utils/history.js'; import Table from 'cli-table3'; import chalk from 'chalk'; +import { join } from 'path'; +import { homedir } from 'os'; const history = new History(); const program = new Command(); program .name('NekoNode') - .version('1.1.5-dev') + .version('1.1.8') .description('The newest anime steaming CLI'); program @@ -45,7 +36,13 @@ program .command('config') .description('This will give you the path to the config file.') .action(() => { - console.log(`${process.env.APPDATA}/anime-cli/config.yml`); + // linux support + const isWindows = process.platform === 'win32'; + const configDir = isWindows + ? join(process.env.APPDATA, 'anime-cli') + : join(homedir(), '.anime-cli'); + console.log(`Config file path: ${configDir}`); + process.exit(0); }); program diff --git a/src/utils/configLoader.js b/src/utils/configLoader.js index fe75ebc..4eb0cab 100644 --- a/src/utils/configLoader.js +++ b/src/utils/configLoader.js @@ -11,21 +11,32 @@ function loadConfig() { : join(homedir(), '.anime-cli'); const configFile = join(configDir, 'config.yml'); - try { - const configFileContent = readFileSync(configFile, 'utf8'); - config = load(configFileContent); - } catch (e) { - console.error('Failed to load config file:', e.message); - console.log('Creating a default config file...\nRun the command again\n'); - + // Default configuration + const defaultConfigContent = `player: mpv # We suggest to use mpv as vlc sometimes doesn't work\nbaseUrl: https://gogoanime3.co\napi: https://api.nekonode.net # DO NOT EDIT\nLang: NA # Set to SUB/DUB if you want to only watch SUB/DUB, Set back to NA for all\nproxy: https://node-proxy.5yg3y1.easypanel.host`; + + if (!existsSync(configFile)) { + console.log('Config file not found, creating a default config file...'); + if (!existsSync(configDir)) { mkdirSync(configDir, { recursive: true }); } - - // Create a default config file - writeFileSync(configFile, `player: mpv # We suggest to use mpv as vlc sometimes doesn't work\nbaseUrl: https://gogoanime3.co\napi: https://api.nekonode.net # DO NOT EDIT\nLang: NA # Set to SUB/DUB if you want to only watch SUB/DUB, Set back to NA for all\n`); - process.exit(1); + + writeFileSync(configFile, defaultConfigContent); + + console.log('Default config file created at', configFile); + config = load(defaultConfigContent); + } else { + try { + const configFileContent = readFileSync(configFile, 'utf8'); + config = load(configFileContent); + } catch (e) { + console.error('Failed to load config file:', e.message); + console.log('Using default configuration settings.'); + + config = load(defaultConfigContent); + } } + return config; } diff --git a/src/utils/discord.js b/src/utils/discord.js index 4e5cbcd..7d91f02 100644 --- a/src/utils/discord.js +++ b/src/utils/discord.js @@ -52,7 +52,11 @@ function handleError(error) { // if erorr message - Could not connect then ingore it if (error.message === 'Could not connect') { return; - } else { + } // if time out then try again + else if (error.message === 'RPC_CONNECTION_TIMEOUT') { + rpc.login({ clientId }).catch(handleError); + } + else { console.error(`An error occurred: ${error.message}`); // Optionally, you can perform additional error handling here, such as retrying or logging to a file. } diff --git a/src/utils/downloader.js b/src/utils/downloader.js index 2b86b8f..ab3aeb0 100644 --- a/src/utils/downloader.js +++ b/src/utils/downloader.js @@ -26,12 +26,12 @@ function convertUrlToMp4(m3u8Url, outputPath) { if (progress.percent !== undefined) { spinner.text = `Downloading... ${progress.percent.toFixed(2)}% done`; } else { - console.log('Processing: progress information not available'); + console.log('Processing: progress information not available, Trying to download...'); } }) .on('end', () => { spinner.succeed('Download and conversion complete.'); - console.log('Conversion complete.'); + //console.log('Conversion complete.'); resolve(); }) .on('error', (err) => { diff --git a/src/utils/player.js b/src/utils/player.js index c89503d..865394e 100644 --- a/src/utils/player.js +++ b/src/utils/player.js @@ -5,6 +5,7 @@ const config = loadConfig(); // Function to play video using MPV or VLC based on config function playEpisode(episodeUrl, player, animeName, episode) { + const proxy_url = `${config.proxy}/fetch/m3u8?url=${episodeUrl}`; const playerOptions = { mpv: [ @@ -16,14 +17,14 @@ function playEpisode(episodeUrl, player, animeName, episode) { '--hwdec=auto', '--vf=scale=1920:1080', '--video-sync=display-resample', - episodeUrl + proxy_url ], vlc: [ '--quiet', '--video-filter=scale', '--scale=1', '--height=1080', - episodeUrl + proxy_url ] };