diff --git a/Dockerfile b/Dockerfile index a052374..7b1cc31 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM node:16-alpine +FROM node:18-alpine #Dependencies RUN apk add --virtual .build-deps python3 make g++ gcc git diff --git a/SECURITY.md b/SECURITY.md index eaabe9a..1ff3d4f 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -4,6 +4,7 @@ | Version | Supported | | ------- | ------------------ | +| 0.5.x | :white_check_mark: | | 0.4.x | :white_check_mark: | | 0.3.x | :x: | | 0.2.x | :x: | diff --git a/package-lock.json b/package-lock.json index cbd5109..e1097b7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "eximiabots-radiox", - "version": "0.4.4", - "lockfileVersion": 2, + "version": "0.5.0", + "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "eximiabots-radiox", - "version": "0.4.4", + "version": "0.5.0", "license": "MIT", "dependencies": { "@discordjs/builders": "^1.6.3", @@ -17,7 +17,6 @@ "discord.js": "^14.11.0", "dotenv": "^16.1.4", "libsodium-wrappers": "^0.7.11", - "node-fetch": "^3.3.1", "path": "^0.12.7" }, "devDependencies": { @@ -35,8 +34,8 @@ "typescript": "^5.1.3" }, "engines": { - "node": ">=16.9.1", - "npm": ">=7.0.0" + "node": ">=18.16.0", + "npm": ">=8.0.0" } }, "node_modules/@cspotcode/source-map-support": { @@ -125,25 +124,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/@discordjs/node-pre-gyp/node_modules/node-fetch": { - "version": "2.6.11", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.11.tgz", - "integrity": "sha512-4I6pdBY1EthSqDmJkiNk3JIT8cswwR9nfeW/cPdUagJYEQG7R95WRH74wpz7ma8Gh/9dI9FP+OU+0E4FvtA55w==", - "dependencies": { - "whatwg-url": "^5.0.0" - }, - "engines": { - "node": "4.x || >=6.0.0" - }, - "peerDependencies": { - "encoding": "^0.1.0" - }, - "peerDependenciesMeta": { - "encoding": { - "optional": true - } - } - }, "node_modules/@discordjs/node-pre-gyp/node_modules/rimraf": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", @@ -467,9 +447,9 @@ } }, "node_modules/@sapphire/shapeshift": { - "version": "3.9.1", - "resolved": "https://registry.npmjs.org/@sapphire/shapeshift/-/shapeshift-3.9.1.tgz", - "integrity": "sha512-zZb+VCDAoqxN+Kc1ICFaNvkLo6VaZPBxQPIPHcxHLIk7AEQWzkRjRYOSxPv9CQbvBR6CAO2EEB2jiAOiCDbyzA==", + "version": "3.9.2", + "resolved": "https://registry.npmjs.org/@sapphire/shapeshift/-/shapeshift-3.9.2.tgz", + "integrity": "sha512-YRbCXWy969oGIdqR/wha62eX8GNHsvyYi0Rfd4rNW6tSVVa8p0ELiMEuOH/k8rgtvRoM+EMV7Csqz77YdwiDpA==", "dependencies": { "fast-deep-equal": "^3.1.3", "lodash": "^4.17.21" @@ -988,14 +968,6 @@ "node": ">= 8" } }, - "node_modules/data-uri-to-buffer": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", - "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==", - "engines": { - "node": ">= 12" - } - }, "node_modules/debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", @@ -1424,28 +1396,6 @@ "reusify": "^1.0.4" } }, - "node_modules/fetch-blob": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", - "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/jimmywarting" - }, - { - "type": "paypal", - "url": "https://paypal.me/jimmywarting" - } - ], - "dependencies": { - "node-domexception": "^1.0.0", - "web-streams-polyfill": "^3.0.3" - }, - "engines": { - "node": "^12.20 || >= 14.13" - } - }, "node_modules/file-entry-cache": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", @@ -1459,9 +1409,9 @@ } }, "node_modules/file-type": { - "version": "18.4.0", - "resolved": "https://registry.npmjs.org/file-type/-/file-type-18.4.0.tgz", - "integrity": "sha512-o6MQrZKTAK6WpvmQk3jqTVUmqxYBxW5bloUfrdH1ZnRFDvvAPNr+l+rgOxM3nkqWT+3khaj3FRMDydWe0xhu+w==", + "version": "18.5.0", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-18.5.0.tgz", + "integrity": "sha512-yvpl5U868+V6PqXHMmsESpg6unQ5GfnPssl4dxdJudBrr9qy7Fddt7EVX1VLlddFfe8Gj9N7goCZH22FXuSQXQ==", "dependencies": { "readable-web-to-node-stream": "^3.0.2", "strtok3": "^7.0.0", @@ -1584,17 +1534,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/formdata-polyfill": { - "version": "4.0.10", - "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", - "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", - "dependencies": { - "fetch-blob": "^3.1.2" - }, - "engines": { - "node": ">=12.20.0" - } - }, "node_modules/from": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/from/-/from-0.1.7.tgz", @@ -1648,9 +1587,9 @@ } }, "node_modules/glob": { - "version": "10.2.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.2.6.tgz", - "integrity": "sha512-U/rnDpXJGF414QQQZv5uVsabTVxMSwzS5CH0p3DRCIV6ownl4f7PzGnkGmvlum2wB+9RlJWJZ6ACU1INnBqiPA==", + "version": "10.2.7", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.2.7.tgz", + "integrity": "sha512-jTKehsravOJo8IJxUGfZILnkvVJM/MOfHRs8QcXolVef2zNI9Tqyy5+SeuOAZd3upViEZQLyFpQhYiHLrMUNmA==", "dev": true, "dependencies": { "foreground-child": "^3.1.0", @@ -2144,39 +2083,23 @@ "integrity": "sha512-qN8v/s2PAJwGUtr1/hYTpNKlD6Y9rc4p8KSmJXyGdYGZsDGKXrGThikLFP9OCHFeLeEpQzPwiAtdIvBLqm//Hw==", "dev": true }, - "node_modules/node-domexception": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", - "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/jimmywarting" - }, - { - "type": "github", - "url": "https://paypal.me/jimmywarting" - } - ], - "engines": { - "node": ">=10.5.0" - } - }, "node_modules/node-fetch": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.1.tgz", - "integrity": "sha512-cRVc/kyto/7E5shrWca1Wsea4y6tL9iYJE5FBCius3JQfb/4P4I295PfhgbJQBLTx6lATE4z+wK0rPM4VS2uow==", + "version": "2.6.11", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.11.tgz", + "integrity": "sha512-4I6pdBY1EthSqDmJkiNk3JIT8cswwR9nfeW/cPdUagJYEQG7R95WRH74wpz7ma8Gh/9dI9FP+OU+0E4FvtA55w==", "dependencies": { - "data-uri-to-buffer": "^4.0.0", - "fetch-blob": "^3.1.4", - "formdata-polyfill": "^4.0.10" + "whatwg-url": "^5.0.0" }, "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + "node": "4.x || >=6.0.0" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/node-fetch" + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } } }, "node_modules/nopt": { @@ -3040,14 +2963,6 @@ "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", "dev": true }, - "node_modules/web-streams-polyfill": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz", - "integrity": "sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==", - "engines": { - "node": ">= 8" - } - }, "node_modules/webidl-conversions": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", @@ -3242,2253 +3157,5 @@ "url": "https://github.com/sponsors/sindresorhus" } } - }, - "dependencies": { - "@cspotcode/source-map-support": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", - "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", - "dev": true, - "requires": { - "@jridgewell/trace-mapping": "0.3.9" - } - }, - "@discordjs/builders": { - "version": "1.6.3", - "resolved": "https://registry.npmjs.org/@discordjs/builders/-/builders-1.6.3.tgz", - "integrity": "sha512-CTCh8NqED3iecTNuiz49mwSsrc2iQb4d0MjMdmS/8pb69Y4IlzJ/DIy/p5GFlgOrFbNO2WzMHkWKQSiJ3VNXaw==", - "requires": { - "@discordjs/formatters": "^0.3.1", - "@discordjs/util": "^0.3.1", - "@sapphire/shapeshift": "^3.8.2", - "discord-api-types": "^0.37.41", - "fast-deep-equal": "^3.1.3", - "ts-mixer": "^6.0.3", - "tslib": "^2.5.0" - } - }, - "@discordjs/collection": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-1.5.1.tgz", - "integrity": "sha512-aWEc9DCf3TMDe9iaJoOnO2+JVAjeRNuRxPZQA6GVvBf+Z3gqUuWYBy2NWh4+5CLYq5uoc3MOvUQ5H5m8CJBqOA==" - }, - "@discordjs/formatters": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/@discordjs/formatters/-/formatters-0.3.1.tgz", - "integrity": "sha512-M7X4IGiSeh4znwcRGcs+49B5tBkNDn4k5bmhxJDAUhRxRHTiFAOTVUNQ6yAKySu5jZTnCbSvTYHW3w0rAzV1MA==", - "requires": { - "discord-api-types": "^0.37.41" - } - }, - "@discordjs/node-pre-gyp": { - "version": "0.4.5", - "resolved": "https://registry.npmjs.org/@discordjs/node-pre-gyp/-/node-pre-gyp-0.4.5.tgz", - "integrity": "sha512-YJOVVZ545x24mHzANfYoy0BJX5PDyeZlpiJjDkUBM/V/Ao7TFX9lcUvCN4nr0tbr5ubeaXxtEBILUrHtTphVeQ==", - "requires": { - "detect-libc": "^2.0.0", - "https-proxy-agent": "^5.0.0", - "make-dir": "^3.1.0", - "node-fetch": "^2.6.7", - "nopt": "^5.0.0", - "npmlog": "^5.0.1", - "rimraf": "^3.0.2", - "semver": "^7.3.5", - "tar": "^6.1.11" - }, - "dependencies": { - "glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "node-fetch": { - "version": "2.6.11", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.11.tgz", - "integrity": "sha512-4I6pdBY1EthSqDmJkiNk3JIT8cswwR9nfeW/cPdUagJYEQG7R95WRH74wpz7ma8Gh/9dI9FP+OU+0E4FvtA55w==", - "requires": { - "whatwg-url": "^5.0.0" - } - }, - "rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "requires": { - "glob": "^7.1.3" - } - } - } - }, - "@discordjs/opus": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/@discordjs/opus/-/opus-0.9.0.tgz", - "integrity": "sha512-NEE76A96FtQ5YuoAVlOlB3ryMPrkXbUCTQICHGKb8ShtjXyubGicjRMouHtP1RpuDdm16cDa+oI3aAMo1zQRUQ==", - "requires": { - "@discordjs/node-pre-gyp": "^0.4.5", - "node-addon-api": "^5.0.0" - } - }, - "@discordjs/rest": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/@discordjs/rest/-/rest-1.7.1.tgz", - "integrity": "sha512-Ofa9UqT0U45G/eX86cURQnX7gzOJLG2oC28VhIk/G6IliYgQF7jFByBJEykPSHE4MxPhqCleYvmsrtfKh1nYmQ==", - "requires": { - "@discordjs/collection": "^1.5.1", - "@discordjs/util": "^0.3.0", - "@sapphire/async-queue": "^1.5.0", - "@sapphire/snowflake": "^3.4.2", - "discord-api-types": "^0.37.41", - "file-type": "^18.3.0", - "tslib": "^2.5.0", - "undici": "^5.22.0" - } - }, - "@discordjs/util": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/@discordjs/util/-/util-0.3.1.tgz", - "integrity": "sha512-HxXKYKg7vohx2/OupUN/4Sd02Ev3PBJ5q0gtjdcvXb0ErCva8jNHWfe/v5sU3UKjIB/uxOhc+TDOnhqffj9pRA==" - }, - "@discordjs/voice": { - "version": "0.16.0", - "resolved": "https://registry.npmjs.org/@discordjs/voice/-/voice-0.16.0.tgz", - "integrity": "sha512-ToGCvHD1cBscuW3p+C7zOF5+L7MJmU4GjdOARfNk9mkHyFFZq4grK+Sxr3QXKbp27DtfDBc9uqD4GUOYgxngfA==", - "requires": { - "@types/ws": "^8.5.4", - "discord-api-types": "^0.37.37", - "prism-media": "^1.3.5", - "tslib": "^2.5.0", - "ws": "^8.13.0" - } - }, - "@discordjs/ws": { - "version": "0.8.3", - "resolved": "https://registry.npmjs.org/@discordjs/ws/-/ws-0.8.3.tgz", - "integrity": "sha512-hcYtppanjHecbdNyCKQNH2I4RP9UrphDgmRgLYrATEQF1oo4sYSve7ZmGsBEXSzH72MO2tBPdWSThunbxUVk0g==", - "requires": { - "@discordjs/collection": "^1.5.1", - "@discordjs/rest": "^1.7.1", - "@discordjs/util": "^0.3.1", - "@sapphire/async-queue": "^1.5.0", - "@types/ws": "^8.5.4", - "@vladfrangu/async_event_emitter": "^2.2.1", - "discord-api-types": "^0.37.41", - "tslib": "^2.5.0", - "ws": "^8.13.0" - } - }, - "@eslint-community/eslint-utils": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", - "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", - "dev": true, - "requires": { - "eslint-visitor-keys": "^3.3.0" - } - }, - "@eslint-community/regexpp": { - "version": "4.5.1", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.5.1.tgz", - "integrity": "sha512-Z5ba73P98O1KUYCCJTUeVpja9RcGoMdncZ6T49FCUl2lN38JtCJ+3WgIDBv0AuY4WChU5PmtJmOCTlN6FZTFKQ==", - "dev": true - }, - "@eslint/eslintrc": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.0.3.tgz", - "integrity": "sha512-+5gy6OQfk+xx3q0d6jGZZC3f3KzAkXc/IanVxd1is/VIIziRqqt3ongQz0FiTUXqTk0c7aDB3OaFuKnuSoJicQ==", - "dev": true, - "requires": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^9.5.2", - "globals": "^13.19.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" - } - }, - "@eslint/js": { - "version": "8.42.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.42.0.tgz", - "integrity": "sha512-6SWlXpWU5AvId8Ac7zjzmIOqMOba/JWY8XZ4A7q7Gn1Vlfg/SFFIlrtHXt9nPn4op9ZPAkl91Jao+QQv3r/ukw==", - "dev": true - }, - "@humanwhocodes/config-array": { - "version": "0.11.10", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.10.tgz", - "integrity": "sha512-KVVjQmNUepDVGXNuoRRdmmEjruj0KfiGSbS8LVc12LMsWDQzRXJ0qdhN8L8uUigKpfEHRhlaQFY0ib1tnUbNeQ==", - "dev": true, - "requires": { - "@humanwhocodes/object-schema": "^1.2.1", - "debug": "^4.1.1", - "minimatch": "^3.0.5" - } - }, - "@humanwhocodes/module-importer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", - "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", - "dev": true - }, - "@humanwhocodes/object-schema": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", - "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", - "dev": true - }, - "@isaacs/cliui": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", - "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", - "dev": true, - "requires": { - "string-width": "^5.1.2", - "string-width-cjs": "npm:string-width@^4.2.0", - "strip-ansi": "^7.0.1", - "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", - "wrap-ansi": "^8.1.0", - "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", - "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", - "dev": true - }, - "emoji-regex": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "dev": true - }, - "string-width": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", - "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", - "dev": true, - "requires": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" - } - }, - "strip-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", - "dev": true, - "requires": { - "ansi-regex": "^6.0.1" - } - } - } - }, - "@jridgewell/resolve-uri": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", - "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", - "dev": true - }, - "@jridgewell/sourcemap-codec": { - "version": "1.4.15", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", - "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", - "dev": true - }, - "@jridgewell/trace-mapping": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", - "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", - "dev": true, - "requires": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" - } - }, - "@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "requires": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - } - }, - "@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true - }, - "@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, - "requires": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - } - }, - "@pkgjs/parseargs": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", - "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", - "dev": true, - "optional": true - }, - "@sapphire/async-queue": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@sapphire/async-queue/-/async-queue-1.5.0.tgz", - "integrity": "sha512-JkLdIsP8fPAdh9ZZjrbHWR/+mZj0wvKS5ICibcLrRI1j84UmLMshx5n9QmL8b95d4onJ2xxiyugTgSAX7AalmA==" - }, - "@sapphire/shapeshift": { - "version": "3.9.1", - "resolved": "https://registry.npmjs.org/@sapphire/shapeshift/-/shapeshift-3.9.1.tgz", - "integrity": "sha512-zZb+VCDAoqxN+Kc1ICFaNvkLo6VaZPBxQPIPHcxHLIk7AEQWzkRjRYOSxPv9CQbvBR6CAO2EEB2jiAOiCDbyzA==", - "requires": { - "fast-deep-equal": "^3.1.3", - "lodash": "^4.17.21" - } - }, - "@sapphire/snowflake": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/@sapphire/snowflake/-/snowflake-3.5.1.tgz", - "integrity": "sha512-BxcYGzgEsdlG0dKAyOm0ehLGm2CafIrfQTZGWgkfKYbj+pNNsorZ7EotuZukc2MT70E0UbppVbtpBrqpzVzjNA==" - }, - "@tokenizer/token": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/@tokenizer/token/-/token-0.3.0.tgz", - "integrity": "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==" - }, - "@tsconfig/node10": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", - "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", - "dev": true - }, - "@tsconfig/node12": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", - "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", - "dev": true - }, - "@tsconfig/node14": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", - "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", - "dev": true - }, - "@tsconfig/node16": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", - "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", - "dev": true - }, - "@types/json-schema": { - "version": "7.0.12", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.12.tgz", - "integrity": "sha512-Hr5Jfhc9eYOQNPYO5WLDq/n4jqijdHNlDXjuAQkkt+mWdQR+XJToOHrsD4cPaMXpn6KO7y2+wM8AZEs8VpBLVA==", - "dev": true - }, - "@types/node": { - "version": "20.2.5", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.2.5.tgz", - "integrity": "sha512-JJulVEQXmiY9Px5axXHeYGLSjhkZEnD+MDPDGbCbIAbMslkKwmygtZFy1X6s/075Yo94sf8GuSlFfPzysQrWZQ==" - }, - "@types/semver": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.0.tgz", - "integrity": "sha512-G8hZ6XJiHnuhQKR7ZmysCeJWE08o8T0AXtk5darsCaTVsYZhhgUrq53jizaR2FvsoeCwJhlmwTjkXBY5Pn/ZHw==", - "dev": true - }, - "@types/ws": { - "version": "8.5.4", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.4.tgz", - "integrity": "sha512-zdQDHKUgcX/zBc4GrwsE/7dVdAD8JR4EuiAXiiUhhfyIJXXb2+PrGshFyeXWQPMmmZ2XxgaqclgpIC7eTXc1mg==", - "requires": { - "@types/node": "*" - } - }, - "@typescript-eslint/eslint-plugin": { - "version": "5.59.9", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.59.9.tgz", - "integrity": "sha512-4uQIBq1ffXd2YvF7MAvehWKW3zVv/w+mSfRAu+8cKbfj3nwzyqJLNcZJpQ/WZ1HLbJDiowwmQ6NO+63nCA+fqA==", - "dev": true, - "requires": { - "@eslint-community/regexpp": "^4.4.0", - "@typescript-eslint/scope-manager": "5.59.9", - "@typescript-eslint/type-utils": "5.59.9", - "@typescript-eslint/utils": "5.59.9", - "debug": "^4.3.4", - "grapheme-splitter": "^1.0.4", - "ignore": "^5.2.0", - "natural-compare-lite": "^1.4.0", - "semver": "^7.3.7", - "tsutils": "^3.21.0" - } - }, - "@typescript-eslint/parser": { - "version": "5.59.9", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.59.9.tgz", - "integrity": "sha512-FsPkRvBtcLQ/eVK1ivDiNYBjn3TGJdXy2fhXX+rc7czWl4ARwnpArwbihSOHI2Peg9WbtGHrbThfBUkZZGTtvQ==", - "dev": true, - "requires": { - "@typescript-eslint/scope-manager": "5.59.9", - "@typescript-eslint/types": "5.59.9", - "@typescript-eslint/typescript-estree": "5.59.9", - "debug": "^4.3.4" - } - }, - "@typescript-eslint/scope-manager": { - "version": "5.59.9", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.59.9.tgz", - "integrity": "sha512-8RA+E+w78z1+2dzvK/tGZ2cpGigBZ58VMEHDZtpE1v+LLjzrYGc8mMaTONSxKyEkz3IuXFM0IqYiGHlCsmlZxQ==", - "dev": true, - "requires": { - "@typescript-eslint/types": "5.59.9", - "@typescript-eslint/visitor-keys": "5.59.9" - } - }, - "@typescript-eslint/type-utils": { - "version": "5.59.9", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.59.9.tgz", - "integrity": "sha512-ksEsT0/mEHg9e3qZu98AlSrONAQtrSTljL3ow9CGej8eRo7pe+yaC/mvTjptp23Xo/xIf2mLZKC6KPv4Sji26Q==", - "dev": true, - "requires": { - "@typescript-eslint/typescript-estree": "5.59.9", - "@typescript-eslint/utils": "5.59.9", - "debug": "^4.3.4", - "tsutils": "^3.21.0" - } - }, - "@typescript-eslint/types": { - "version": "5.59.9", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.59.9.tgz", - "integrity": "sha512-uW8H5NRgTVneSVTfiCVffBb8AbwWSKg7qcA4Ot3JI3MPCJGsB4Db4BhvAODIIYE5mNj7Q+VJkK7JxmRhk2Lyjw==", - "dev": true - }, - "@typescript-eslint/typescript-estree": { - "version": "5.59.9", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.59.9.tgz", - "integrity": "sha512-pmM0/VQ7kUhd1QyIxgS+aRvMgw+ZljB3eDb+jYyp6d2bC0mQWLzUDF+DLwCTkQ3tlNyVsvZRXjFyV0LkU/aXjA==", - "dev": true, - "requires": { - "@typescript-eslint/types": "5.59.9", - "@typescript-eslint/visitor-keys": "5.59.9", - "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "semver": "^7.3.7", - "tsutils": "^3.21.0" - } - }, - "@typescript-eslint/utils": { - "version": "5.59.9", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.59.9.tgz", - "integrity": "sha512-1PuMYsju/38I5Ggblaeb98TOoUvjhRvLpLa1DoTOFaLWqaXl/1iQ1eGurTXgBY58NUdtfTXKP5xBq7q9NDaLKg==", - "dev": true, - "requires": { - "@eslint-community/eslint-utils": "^4.2.0", - "@types/json-schema": "^7.0.9", - "@types/semver": "^7.3.12", - "@typescript-eslint/scope-manager": "5.59.9", - "@typescript-eslint/types": "5.59.9", - "@typescript-eslint/typescript-estree": "5.59.9", - "eslint-scope": "^5.1.1", - "semver": "^7.3.7" - } - }, - "@typescript-eslint/visitor-keys": { - "version": "5.59.9", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.59.9.tgz", - "integrity": "sha512-bT7s0td97KMaLwpEBckbzj/YohnvXtqbe2XgqNvTl6RJVakY5mvENOTPvw5u66nljfZxthESpDozs86U+oLY8Q==", - "dev": true, - "requires": { - "@typescript-eslint/types": "5.59.9", - "eslint-visitor-keys": "^3.3.0" - } - }, - "@vladfrangu/async_event_emitter": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/@vladfrangu/async_event_emitter/-/async_event_emitter-2.2.2.tgz", - "integrity": "sha512-HIzRG7sy88UZjBJamssEczH5q7t5+axva19UbZLO6u0ySbYPrwzWiXBcC0WuHyhKKoeCyneH+FvYzKQq/zTtkQ==" - }, - "abbrev": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", - "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" - }, - "acorn": { - "version": "8.8.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", - "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==", - "dev": true - }, - "acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "requires": {} - }, - "acorn-walk": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", - "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", - "dev": true - }, - "agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "requires": { - "debug": "4" - } - }, - "ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - } - }, - "ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" - }, - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "aproba": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", - "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==" - }, - "are-we-there-yet": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz", - "integrity": "sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==", - "requires": { - "delegates": "^1.0.0", - "readable-stream": "^3.6.0" - } - }, - "arg": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", - "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "dev": true - }, - "argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "dev": true - }, - "balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" - }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "requires": { - "fill-range": "^7.0.1" - } - }, - "busboy": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", - "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", - "requires": { - "streamsearch": "^1.1.0" - } - }, - "callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "chownr": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", - "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==" - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "color-support": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", - "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==" - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" - }, - "console-control-strings": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", - "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==" - }, - "create-require": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", - "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", - "dev": true - }, - "cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "requires": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - } - }, - "data-uri-to-buffer": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", - "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==" - }, - "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "requires": { - "ms": "2.1.2" - } - }, - "deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true - }, - "delegates": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", - "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==" - }, - "detect-libc": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.1.tgz", - "integrity": "sha512-463v3ZeIrcWtdgIg6vI6XUncguvr2TnGl4SzDXinkt9mSLpBJKXT3mW6xT3VQdDN11+WVs29pgvivTc4Lp8v+w==" - }, - "diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "dev": true - }, - "dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "dev": true, - "requires": { - "path-type": "^4.0.0" - } - }, - "discord-api-types": { - "version": "0.37.43", - "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.37.43.tgz", - "integrity": "sha512-bBhDWU3TF9KADxR/mHp1K4Bvu/LRtFQdGyBjADu4e66F3ZnD4kp12W/SJCttIaCcMXzPV3sfty6eDGRNRph51Q==" - }, - "discord.js": { - "version": "14.11.0", - "resolved": "https://registry.npmjs.org/discord.js/-/discord.js-14.11.0.tgz", - "integrity": "sha512-CkueWYFQ28U38YPR8HgsBR/QT35oPpMbEsTNM30Fs8loBIhnA4s70AwQEoy6JvLcpWWJO7GY0y2BUzZmuBMepQ==", - "requires": { - "@discordjs/builders": "^1.6.3", - "@discordjs/collection": "^1.5.1", - "@discordjs/formatters": "^0.3.1", - "@discordjs/rest": "^1.7.1", - "@discordjs/util": "^0.3.1", - "@discordjs/ws": "^0.8.3", - "@sapphire/snowflake": "^3.4.2", - "@types/ws": "^8.5.4", - "discord-api-types": "^0.37.41", - "fast-deep-equal": "^3.1.3", - "lodash.snakecase": "^4.1.1", - "tslib": "^2.5.0", - "undici": "^5.22.0", - "ws": "^8.13.0" - } - }, - "doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "requires": { - "esutils": "^2.0.2" - } - }, - "dotenv": { - "version": "16.1.4", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.1.4.tgz", - "integrity": "sha512-m55RtE8AsPeJBpOIFKihEmqUcoVncQIwo7x9U8ZwLEZw9ZpXboz2c+rvog+jUaJvVrZ5kBOeYQBX5+8Aa/OZQw==" - }, - "duplexer": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", - "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==", - "dev": true - }, - "eastasianwidth": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", - "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", - "dev": true - }, - "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==" - }, - "escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true - }, - "eslint": { - "version": "8.42.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.42.0.tgz", - "integrity": "sha512-ulg9Ms6E1WPf67PHaEY4/6E2tEn5/f7FXGzr3t9cBMugOmf1INYvuUwwh1aXQN4MfJ6a5K2iNwP3w4AColvI9A==", - "dev": true, - "requires": { - "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.4.0", - "@eslint/eslintrc": "^2.0.3", - "@eslint/js": "8.42.0", - "@humanwhocodes/config-array": "^0.11.10", - "@humanwhocodes/module-importer": "^1.0.1", - "@nodelib/fs.walk": "^1.2.8", - "ajv": "^6.10.0", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.3.2", - "doctrine": "^3.0.0", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.2.0", - "eslint-visitor-keys": "^3.4.1", - "espree": "^9.5.2", - "esquery": "^1.4.2", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", - "find-up": "^5.0.0", - "glob-parent": "^6.0.2", - "globals": "^13.19.0", - "graphemer": "^1.4.0", - "ignore": "^5.2.0", - "import-fresh": "^3.0.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "is-path-inside": "^3.0.3", - "js-yaml": "^4.1.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", - "natural-compare": "^1.4.0", - "optionator": "^0.9.1", - "strip-ansi": "^6.0.1", - "strip-json-comments": "^3.1.0", - "text-table": "^0.2.0" - }, - "dependencies": { - "eslint-scope": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.0.tgz", - "integrity": "sha512-DYj5deGlHBfMt15J7rdtyKNq/Nqlv5KfU4iodrQ019XESsRnwXH9KAE0y3cwtUHDo2ob7CypAnCqefh6vioWRw==", - "dev": true, - "requires": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - } - }, - "estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true - } - } - }, - "eslint-config-prettier": { - "version": "8.8.0", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.8.0.tgz", - "integrity": "sha512-wLbQiFre3tdGgpDv67NQKnJuTlcUVYHas3k+DZCc2U2BadthoEY4B7hLPvAxaqdyOGCzuLfii2fqGph10va7oA==", - "dev": true, - "requires": {} - }, - "eslint-plugin-prettier": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-4.2.1.tgz", - "integrity": "sha512-f/0rXLXUt0oFYs8ra4w49wYZBG5GKZpAYsJSm6rnYL5uVDjd+zowwMwVZHnAjf4edNrKpCDYfXDgmRE/Ak7QyQ==", - "dev": true, - "requires": { - "prettier-linter-helpers": "^1.0.0" - } - }, - "eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "dev": true, - "requires": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - } - }, - "eslint-visitor-keys": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.1.tgz", - "integrity": "sha512-pZnmmLwYzf+kWaM/Qgrvpen51upAktaaiI01nsJD/Yr3lMOdNtq0cxkrrg16w64VtisN6okbs7Q8AfGqj4c9fA==", - "dev": true - }, - "espree": { - "version": "9.5.2", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.5.2.tgz", - "integrity": "sha512-7OASN1Wma5fum5SrNhFMAMJxOUAbhyfQ8dQ//PJaJbNw0URTPWqIghHWt1MmAANKhHZIYOHruW4Kw4ruUWOdGw==", - "dev": true, - "requires": { - "acorn": "^8.8.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.1" - } - }, - "esquery": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", - "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", - "dev": true, - "requires": { - "estraverse": "^5.1.0" - }, - "dependencies": { - "estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true - } - } - }, - "esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "requires": { - "estraverse": "^5.2.0" - }, - "dependencies": { - "estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true - } - } - }, - "estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true - }, - "esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true - }, - "event-stream": { - "version": "3.3.4", - "resolved": "https://registry.npmjs.org/event-stream/-/event-stream-3.3.4.tgz", - "integrity": "sha512-QHpkERcGsR0T7Qm3HNJSyXKEEj8AHNxkY3PK8TS2KJvQ7NiSHe3DDpwVKKtoYprL/AreyzFBeIkBIWChAqn60g==", - "dev": true, - "requires": { - "duplexer": "~0.1.1", - "from": "~0", - "map-stream": "~0.1.0", - "pause-stream": "0.0.11", - "split": "0.3", - "stream-combiner": "~0.0.4", - "through": "~2.3.1" - } - }, - "fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" - }, - "fast-diff": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz", - "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", - "dev": true - }, - "fast-glob": { - "version": "3.2.12", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", - "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", - "dev": true, - "requires": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" - }, - "dependencies": { - "glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "requires": { - "is-glob": "^4.0.1" - } - } - } - }, - "fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true - }, - "fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true - }, - "fastq": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", - "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", - "dev": true, - "requires": { - "reusify": "^1.0.4" - } - }, - "fetch-blob": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", - "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", - "requires": { - "node-domexception": "^1.0.0", - "web-streams-polyfill": "^3.0.3" - } - }, - "file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", - "dev": true, - "requires": { - "flat-cache": "^3.0.4" - } - }, - "file-type": { - "version": "18.4.0", - "resolved": "https://registry.npmjs.org/file-type/-/file-type-18.4.0.tgz", - "integrity": "sha512-o6MQrZKTAK6WpvmQk3jqTVUmqxYBxW5bloUfrdH1ZnRFDvvAPNr+l+rgOxM3nkqWT+3khaj3FRMDydWe0xhu+w==", - "requires": { - "readable-web-to-node-stream": "^3.0.2", - "strtok3": "^7.0.0", - "token-types": "^5.0.1" - } - }, - "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "requires": { - "to-regex-range": "^5.0.1" - } - }, - "find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "requires": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - } - }, - "flat-cache": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", - "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", - "dev": true, - "requires": { - "flatted": "^3.1.0", - "rimraf": "^3.0.2" - }, - "dependencies": { - "glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "requires": { - "glob": "^7.1.3" - } - } - } - }, - "flatted": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", - "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", - "dev": true - }, - "foreground-child": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", - "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==", - "dev": true, - "requires": { - "cross-spawn": "^7.0.0", - "signal-exit": "^4.0.1" - }, - "dependencies": { - "signal-exit": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.0.2.tgz", - "integrity": "sha512-MY2/qGx4enyjprQnFaZsHib3Yadh3IXyV2C321GY0pjGfVBu4un0uDJkwgdxqO+Rdx8JMT8IfJIRwbYVz3Ob3Q==", - "dev": true - } - } - }, - "formdata-polyfill": { - "version": "4.0.10", - "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", - "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", - "requires": { - "fetch-blob": "^3.1.2" - } - }, - "from": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/from/-/from-0.1.7.tgz", - "integrity": "sha512-twe20eF1OxVxp/ML/kq2p1uc6KvFK/+vs8WjEbeKmV2He22MKm7YF2ANIt+EOqhJ5L3K/SuuPhk0hWQDjOM23g==", - "dev": true - }, - "fs-minipass": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", - "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", - "requires": { - "minipass": "^3.0.0" - }, - "dependencies": { - "minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "requires": { - "yallist": "^4.0.0" - } - } - } - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" - }, - "gauge": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz", - "integrity": "sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==", - "requires": { - "aproba": "^1.0.3 || ^2.0.0", - "color-support": "^1.1.2", - "console-control-strings": "^1.0.0", - "has-unicode": "^2.0.1", - "object-assign": "^4.1.1", - "signal-exit": "^3.0.0", - "string-width": "^4.2.3", - "strip-ansi": "^6.0.1", - "wide-align": "^1.1.2" - } - }, - "glob": { - "version": "10.2.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.2.6.tgz", - "integrity": "sha512-U/rnDpXJGF414QQQZv5uVsabTVxMSwzS5CH0p3DRCIV6ownl4f7PzGnkGmvlum2wB+9RlJWJZ6ACU1INnBqiPA==", - "dev": true, - "requires": { - "foreground-child": "^3.1.0", - "jackspeak": "^2.0.3", - "minimatch": "^9.0.1", - "minipass": "^5.0.0 || ^6.0.2", - "path-scurry": "^1.7.0" - }, - "dependencies": { - "brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "requires": { - "balanced-match": "^1.0.0" - } - }, - "minimatch": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.1.tgz", - "integrity": "sha512-0jWhJpD/MdhPXwPuiRkCbfYfSKp2qnn2eOc279qI7f+osl/l+prKSrvhg157zSYvx/1nmgn2NqdT6k2Z7zSH9w==", - "dev": true, - "requires": { - "brace-expansion": "^2.0.1" - } - } - } - }, - "glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, - "requires": { - "is-glob": "^4.0.3" - } - }, - "globals": { - "version": "13.20.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", - "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==", - "dev": true, - "requires": { - "type-fest": "^0.20.2" - } - }, - "globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", - "dev": true, - "requires": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" - } - }, - "grapheme-splitter": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", - "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", - "dev": true - }, - "graphemer": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", - "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "has-unicode": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", - "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==" - }, - "https-proxy-agent": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", - "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", - "requires": { - "agent-base": "6", - "debug": "4" - } - }, - "ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" - }, - "ignore": { - "version": "5.2.4", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", - "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", - "dev": true - }, - "import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, - "requires": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - } - }, - "imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "dev": true - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" - }, - "is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "requires": { - "is-extglob": "^2.1.1" - } - }, - "is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true - }, - "is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", - "dev": true - }, - "isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true - }, - "jackspeak": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.2.1.tgz", - "integrity": "sha512-MXbxovZ/Pm42f6cDIDkl3xpwv1AGwObKwfmjs2nQePiy85tP3fatofl3FC1aBsOtP/6fq5SbtgHwWcMsLP+bDw==", - "dev": true, - "requires": { - "@isaacs/cliui": "^8.0.2", - "@pkgjs/parseargs": "^0.11.0" - } - }, - "js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "requires": { - "argparse": "^2.0.1" - } - }, - "json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true - }, - "levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, - "requires": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - } - }, - "libsodium": { - "version": "0.7.11", - "resolved": "https://registry.npmjs.org/libsodium/-/libsodium-0.7.11.tgz", - "integrity": "sha512-WPfJ7sS53I2s4iM58QxY3Inb83/6mjlYgcmZs7DJsvDlnmVUwNinBCi5vBT43P6bHRy01O4zsMU2CoVR6xJ40A==" - }, - "libsodium-wrappers": { - "version": "0.7.11", - "resolved": "https://registry.npmjs.org/libsodium-wrappers/-/libsodium-wrappers-0.7.11.tgz", - "integrity": "sha512-SrcLtXj7BM19vUKtQuyQKiQCRJPgbpauzl3s0rSwD+60wtHqSUuqcoawlMDheCJga85nKOQwxNYQxf/CKAvs6Q==", - "requires": { - "libsodium": "^0.7.11" - } - }, - "locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "requires": { - "p-locate": "^5.0.0" - } - }, - "lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" - }, - "lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true - }, - "lodash.snakecase": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/lodash.snakecase/-/lodash.snakecase-4.1.1.tgz", - "integrity": "sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw==" - }, - "lru-cache": { - "version": "9.1.2", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-9.1.2.tgz", - "integrity": "sha512-ERJq3FOzJTxBbFjZ7iDs+NiK4VI9Wz+RdrrAB8dio1oV+YvdPzUEE4QNiT2VD51DkIbCYRUUzCRkssXCHqSnKQ==", - "dev": true - }, - "make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "requires": { - "semver": "^6.0.0" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" - } - } - }, - "make-error": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", - "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "dev": true - }, - "map-stream": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/map-stream/-/map-stream-0.1.0.tgz", - "integrity": "sha512-CkYQrPYZfWnu/DAmVCpTSX/xHpKZ80eKh2lAkyA6AJTef6bW+6JpbQZN5rofum7da+SyN1bi5ctTm+lTfcCW3g==", - "dev": true - }, - "merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true - }, - "micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", - "dev": true, - "requires": { - "braces": "^3.0.2", - "picomatch": "^2.3.1" - } - }, - "minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minipass": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-6.0.2.tgz", - "integrity": "sha512-MzWSV5nYVT7mVyWCwn2o7JH13w2TBRmmSqSRCKzTw+lmft9X4z+3wjvs06Tzijo5z4W/kahUCDpRXTF+ZrmF/w==", - "dev": true - }, - "minizlib": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", - "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", - "requires": { - "minipass": "^3.0.0", - "yallist": "^4.0.0" - }, - "dependencies": { - "minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "requires": { - "yallist": "^4.0.0" - } - } - } - }, - "mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==" - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, - "natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true - }, - "natural-compare-lite": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz", - "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==", - "dev": true - }, - "node-addon-api": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-5.1.0.tgz", - "integrity": "sha512-eh0GgfEkpnoWDq+VY8OyvYhFEzBk6jIYbRKdIlyTiAXIVJ8PyBaKb0rp7oDtoddbdoHWhq8wwr+XZ81F1rpNdA==" - }, - "node-cleanup": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/node-cleanup/-/node-cleanup-2.1.2.tgz", - "integrity": "sha512-qN8v/s2PAJwGUtr1/hYTpNKlD6Y9rc4p8KSmJXyGdYGZsDGKXrGThikLFP9OCHFeLeEpQzPwiAtdIvBLqm//Hw==", - "dev": true - }, - "node-domexception": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", - "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==" - }, - "node-fetch": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.1.tgz", - "integrity": "sha512-cRVc/kyto/7E5shrWca1Wsea4y6tL9iYJE5FBCius3JQfb/4P4I295PfhgbJQBLTx6lATE4z+wK0rPM4VS2uow==", - "requires": { - "data-uri-to-buffer": "^4.0.0", - "fetch-blob": "^3.1.4", - "formdata-polyfill": "^4.0.10" - } - }, - "nopt": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", - "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", - "requires": { - "abbrev": "1" - } - }, - "npmlog": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-5.0.1.tgz", - "integrity": "sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==", - "requires": { - "are-we-there-yet": "^2.0.0", - "console-control-strings": "^1.1.0", - "gauge": "^3.0.0", - "set-blocking": "^2.0.0" - } - }, - "object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==" - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "requires": { - "wrappy": "1" - } - }, - "optionator": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", - "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", - "dev": true, - "requires": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.3" - } - }, - "p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "requires": { - "yocto-queue": "^0.1.0" - } - }, - "p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "requires": { - "p-limit": "^3.0.2" - } - }, - "parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, - "requires": { - "callsites": "^3.0.0" - } - }, - "path": { - "version": "0.12.7", - "resolved": "https://registry.npmjs.org/path/-/path-0.12.7.tgz", - "integrity": "sha512-aXXC6s+1w7otVF9UletFkFcDsJeO7lSZBPUQhtb5O0xJe8LtYhj/GxldoL09bBj9+ZmE2hNoHqQSFMN5fikh4Q==", - "requires": { - "process": "^0.11.1", - "util": "^0.10.3" - } - }, - "path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true - }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==" - }, - "path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true - }, - "path-scurry": { - "version": "1.9.2", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.9.2.tgz", - "integrity": "sha512-qSDLy2aGFPm8i4rsbHd4MNyTcrzHFsLQykrtbuGRknZZCBBVXSv2tSCDN2Cg6Rt/GFRw8GoW9y9Ecw5rIPG1sg==", - "dev": true, - "requires": { - "lru-cache": "^9.1.1", - "minipass": "^5.0.0 || ^6.0.2" - } - }, - "path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true - }, - "pause-stream": { - "version": "0.0.11", - "resolved": "https://registry.npmjs.org/pause-stream/-/pause-stream-0.0.11.tgz", - "integrity": "sha512-e3FBlXLmN/D1S+zHzanP4E/4Z60oFAa3O051qt1pxa7DEJWKAyil6upYVXCWadEnuoqa4Pkc9oUx9zsxYeRv8A==", - "dev": true, - "requires": { - "through": "~2.3" - } - }, - "peek-readable": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/peek-readable/-/peek-readable-5.0.0.tgz", - "integrity": "sha512-YtCKvLUOvwtMGmrniQPdO7MwPjgkFBtFIrmfSbYmYuq3tKDV/mcfAhBth1+C3ru7uXIZasc/pHnb+YDYNkkj4A==" - }, - "picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true - }, - "prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true - }, - "prettier": { - "version": "2.8.8", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", - "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", - "dev": true - }, - "prettier-linter-helpers": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", - "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", - "dev": true, - "requires": { - "fast-diff": "^1.1.2" - } - }, - "prism-media": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/prism-media/-/prism-media-1.3.5.tgz", - "integrity": "sha512-IQdl0Q01m4LrkN1EGIE9lphov5Hy7WWlH6ulf5QdGePLlPas9p2mhgddTEHrlaXYjjFToM1/rWuwF37VF4taaA==", - "requires": {} - }, - "process": { - "version": "0.11.10", - "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", - "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==" - }, - "ps-tree": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/ps-tree/-/ps-tree-1.2.0.tgz", - "integrity": "sha512-0VnamPPYHl4uaU/nSFeZZpR21QAWRz+sRv4iW9+v/GS/J5U5iZB5BNN6J0RMoOvdx2gWM2+ZFMIm58q24e4UYA==", - "dev": true, - "requires": { - "event-stream": "=3.3.4" - } - }, - "punycode": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", - "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", - "dev": true - }, - "queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true - }, - "readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - }, - "readable-web-to-node-stream": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/readable-web-to-node-stream/-/readable-web-to-node-stream-3.0.2.tgz", - "integrity": "sha512-ePeK6cc1EcKLEhJFt/AebMCLL+GgSKhuygrZ/GLaKZYEecIgIECf4UaUuaByiGtzckwR4ain9VzUh95T1exYGw==", - "requires": { - "readable-stream": "^3.6.0" - } - }, - "resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true - }, - "reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true - }, - "rimraf": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.1.tgz", - "integrity": "sha512-OfFZdwtd3lZ+XZzYP/6gTACubwFcHdLRqS9UX3UwpU2dnGQYkPFISRwvM3w9IiB2w7bW5qGo/uAwE4SmXXSKvg==", - "dev": true, - "requires": { - "glob": "^10.2.5" - } - }, - "run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, - "requires": { - "queue-microtask": "^1.2.2" - } - }, - "safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" - }, - "semver": { - "version": "7.5.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.1.tgz", - "integrity": "sha512-Wvss5ivl8TMRZXXESstBA4uR5iXgEN/VC5/sOcuXdVLzcdkz4HWetIoRfG5gb5X+ij/G9rw9YoGn3QoQ8OCSpw==", - "requires": { - "lru-cache": "^6.0.0" - }, - "dependencies": { - "lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "requires": { - "yallist": "^4.0.0" - } - } - } - }, - "set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==" - }, - "shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "requires": { - "shebang-regex": "^3.0.0" - } - }, - "shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true - }, - "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==" - }, - "slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true - }, - "split": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/split/-/split-0.3.3.tgz", - "integrity": "sha512-wD2AeVmxXRBoX44wAycgjVpMhvbwdI2aZjCkvfNcH1YqHQvJVa1duWc73OyVGJUc05fhFaTZeQ/PYsrmyH0JVA==", - "dev": true, - "requires": { - "through": "2" - } - }, - "stream-combiner": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/stream-combiner/-/stream-combiner-0.0.4.tgz", - "integrity": "sha512-rT00SPnTVyRsaSz5zgSPma/aHSOic5U1prhYdRy5HS2kTZviFpmDgzilbtsJsxiroqACmayynDN/9VzIbX5DOw==", - "dev": true, - "requires": { - "duplexer": "~0.1.1" - } - }, - "streamsearch": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", - "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==" - }, - "string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "requires": { - "safe-buffer": "~5.2.0" - } - }, - "string-argv": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.2.tgz", - "integrity": "sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==", - "dev": true - }, - "string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - } - }, - "string-width-cjs": { - "version": "npm:string-width@4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - } - }, - "strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "requires": { - "ansi-regex": "^5.0.1" - } - }, - "strip-ansi-cjs": { - "version": "npm:strip-ansi@6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "requires": { - "ansi-regex": "^5.0.1" - } - }, - "strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true - }, - "strtok3": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/strtok3/-/strtok3-7.0.0.tgz", - "integrity": "sha512-pQ+V+nYQdC5H3Q7qBZAz/MO6lwGhoC2gOAjuouGf/VO0m7vQRh8QNMl2Uf6SwAtzZ9bOw3UIeBukEGNJl5dtXQ==", - "requires": { - "@tokenizer/token": "^0.3.0", - "peek-readable": "^5.0.0" - } - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - }, - "tar": { - "version": "6.1.15", - "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.15.tgz", - "integrity": "sha512-/zKt9UyngnxIT/EAGYuxaMYgOIJiP81ab9ZfkILq4oNLPFX50qyYmu7jRj9qeXoxmJHjGlbH0+cm2uy1WCs10A==", - "requires": { - "chownr": "^2.0.0", - "fs-minipass": "^2.0.0", - "minipass": "^5.0.0", - "minizlib": "^2.1.1", - "mkdirp": "^1.0.3", - "yallist": "^4.0.0" - }, - "dependencies": { - "minipass": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", - "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==" - } - } - }, - "text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "dev": true - }, - "through": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", - "dev": true - }, - "to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "requires": { - "is-number": "^7.0.0" - } - }, - "token-types": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/token-types/-/token-types-5.0.1.tgz", - "integrity": "sha512-Y2fmSnZjQdDb9W4w4r1tswlMHylzWIeOKpx0aZH9BgGtACHhrk3OkT52AzwcuqTRBZtvvnTjDBh8eynMulu8Vg==", - "requires": { - "@tokenizer/token": "^0.3.0", - "ieee754": "^1.2.1" - } - }, - "tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" - }, - "ts-mixer": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/ts-mixer/-/ts-mixer-6.0.3.tgz", - "integrity": "sha512-k43M7uCG1AkTyxgnmI5MPwKoUvS/bRvLvUb7+Pgpdlmok8AoqmUaZxUUw8zKM5B1lqZrt41GjYgnvAi0fppqgQ==" - }, - "ts-node": { - "version": "10.9.1", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", - "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", - "dev": true, - "requires": { - "@cspotcode/source-map-support": "^0.8.0", - "@tsconfig/node10": "^1.0.7", - "@tsconfig/node12": "^1.0.7", - "@tsconfig/node14": "^1.0.0", - "@tsconfig/node16": "^1.0.2", - "acorn": "^8.4.1", - "acorn-walk": "^8.1.1", - "arg": "^4.1.0", - "create-require": "^1.1.0", - "diff": "^4.0.1", - "make-error": "^1.1.1", - "v8-compile-cache-lib": "^3.0.1", - "yn": "3.1.1" - } - }, - "tsc-watch": { - "version": "6.0.4", - "resolved": "https://registry.npmjs.org/tsc-watch/-/tsc-watch-6.0.4.tgz", - "integrity": "sha512-cHvbvhjO86w2aGlaHgSCeQRl+Aqw6X6XN4sQMPZKF88GoP30O+oTuh5lRIJr5pgFWrRpF1AgXnJJ2DoFEIPHyg==", - "dev": true, - "requires": { - "cross-spawn": "^7.0.3", - "node-cleanup": "^2.1.2", - "ps-tree": "^1.2.0", - "string-argv": "^0.3.1" - } - }, - "tslib": { - "version": "2.5.3", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.3.tgz", - "integrity": "sha512-mSxlJJwl3BMEQCUNnxXBU9jP4JBktcEGhURcPR6VQVlnP0FdDEsIaz0C35dXNGLyRfrATNofF0F5p2KPxQgB+w==" - }, - "tsutils": { - "version": "3.21.0", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", - "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", - "dev": true, - "requires": { - "tslib": "^1.8.1" - }, - "dependencies": { - "tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true - } - } - }, - "type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, - "requires": { - "prelude-ls": "^1.2.1" - } - }, - "type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true - }, - "typescript": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.1.3.tgz", - "integrity": "sha512-XH627E9vkeqhlZFQuL+UsyAXEnibT0kWR2FWONlr4sTjvxyJYnyefgrkyECLzM5NenmKzRAy2rR/OlYLA1HkZw==", - "dev": true - }, - "undici": { - "version": "5.22.1", - "resolved": "https://registry.npmjs.org/undici/-/undici-5.22.1.tgz", - "integrity": "sha512-Ji2IJhFXZY0x/0tVBXeQwgPlLWw13GVzpsWPQ3rV50IFMMof2I55PZZxtm4P6iNq+L5znYN9nSTAq0ZyE6lSJw==", - "requires": { - "busboy": "^1.6.0" - } - }, - "uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, - "requires": { - "punycode": "^2.1.0" - } - }, - "util": { - "version": "0.10.4", - "resolved": "https://registry.npmjs.org/util/-/util-0.10.4.tgz", - "integrity": "sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A==", - "requires": { - "inherits": "2.0.3" - }, - "dependencies": { - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==" - } - } - }, - "util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" - }, - "v8-compile-cache-lib": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", - "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", - "dev": true - }, - "web-streams-polyfill": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz", - "integrity": "sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==" - }, - "webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" - }, - "whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", - "requires": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } - }, - "which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - }, - "wide-align": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", - "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", - "requires": { - "string-width": "^1.0.2 || 2 || 3 || 4" - } - }, - "word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", - "dev": true - }, - "wrap-ansi": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", - "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", - "dev": true, - "requires": { - "ansi-styles": "^6.1.0", - "string-width": "^5.0.1", - "strip-ansi": "^7.0.1" - }, - "dependencies": { - "ansi-regex": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", - "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", - "dev": true - }, - "ansi-styles": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", - "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", - "dev": true - }, - "emoji-regex": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "dev": true - }, - "string-width": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", - "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", - "dev": true, - "requires": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" - } - }, - "strip-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", - "dev": true, - "requires": { - "ansi-regex": "^6.0.1" - } - } - } - }, - "wrap-ansi-cjs": { - "version": "npm:wrap-ansi@7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "requires": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - } - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" - }, - "ws": { - "version": "8.13.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz", - "integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==", - "requires": {} - }, - "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - }, - "yn": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", - "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", - "dev": true - }, - "yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true - } } } diff --git a/package.json b/package.json index 095b0c9..9d3209d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "eximiabots-radiox", - "version": "0.4.4", + "version": "0.5.0", "description": "Internet Radio to your Discord guild", "main": "index.js", "scripts": { @@ -26,7 +26,6 @@ "discord.js": "^14.11.0", "dotenv": "^16.1.4", "libsodium-wrappers": "^0.7.11", - "node-fetch": "^3.3.1", "path": "^0.12.7" }, "devDependencies": { @@ -44,7 +43,7 @@ "typescript": "^5.1.3" }, "engines": { - "node": ">=16.9.1", - "npm": ">=7.0.0" + "node": ">=18.16.0", + "npm": ">=8.0.0" } } diff --git a/src/Client.ts b/src/Client.ts index 18a83b5..336bf33 100644 --- a/src/Client.ts +++ b/src/Client.ts @@ -1,16 +1,15 @@ import { Client, Collection, IntentsBitField } from "discord.js"; -import Datastore from "./client/classes/Datastore.js"; -import Radio from "./client/classes/Radio.js"; -import Stations from "./client/classes/Stations.js"; -import Streamer from "./client/classes/Streamer.js"; -import Statistics from "./client/classes/Statistics.js"; -import fs from "fs"; -import { command, radio } from "./client/utils/typings.js"; -import config from "./config.js"; -import messages from "./client/messages.js"; -import path from "path"; +import Datastore from "./client/classes/Datastore"; +import Radio from "./client/classes/Radio"; +import Stations from "./client/classes/Stations"; +import Streamer from "./client/classes/Streamer"; +import Statistics from "./client/classes/Statistics"; +import { command } from "./client/commands"; +import config from "./config"; +import events from "./client/events" +import { funcs } from "./client/funcs"; +import { messages } from "./client/messages"; -const events = "./client/events/"; const GatewayIntents = new IntentsBitField(); GatewayIntents.add( @@ -19,9 +18,9 @@ GatewayIntents.add( 1 << 9 // GUILD_MESSAGES ); -class RadioClient extends Client { +export default class RadioClient extends Client { readonly commands: Collection; - public funcs: any; + readonly funcs = funcs; readonly config = config; readonly messages = messages; public datastore: Datastore | null; @@ -29,6 +28,7 @@ class RadioClient extends Client { public streamer: Streamer | null; public statistics: Statistics | null; public radio: Radio | null; + constructor() { super({ intents: GatewayIntents @@ -40,16 +40,6 @@ class RadioClient extends Client { this.statistics = null; this.radio = null; - this.funcs = {}; - this.funcs.check = require("./client/funcs/check.js"); - this.funcs.isDev = require("./client/funcs/isDev.js"); - this.funcs.logger = require("./client/funcs/logger.js"); - this.funcs.msToTime = require("./client/funcs/msToTime.js"); - this.funcs.saveState = require("./client/funcs/saveState.js"); - this.funcs.loadState = require("./client/funcs/loadState.js"); - this.funcs.play = require("./client/funcs/play.js"); - this.funcs.listStations = require("./client/funcs/listStations.js"); - console.log('RadioX ' + this.config.version); console.log('Internet Radio to your Discord guild'); console.log('(c)2020-2022 EximiaBots by Warén Group'); @@ -60,58 +50,12 @@ class RadioClient extends Client { this.funcs.logger("Maintenance Mode", "Enabled"); this.config.maintenanceMode = true; - this.on("ready", () => { - require(`${events}ready`).execute(this); - }); - - this.on("messageCreate", msg => { - require(`${events}messageCreate`).execute(this, msg); - }); - - this.on("messageDelete", msg => { - require(`${events}messageDelete`).execute(this, msg); - }); - - this.on("interactionCreate", interaction => { - require(`${events}interactionCreate`).execute(this, interaction); - }); - - this.on("voiceStateUpdate", (oldState, newState) => { - require(`${events}voiceStateUpdate`).execute(this, oldState, newState); - }); - - this.on("error", error => { - this.funcs.logger("Discord Client / Error"); - console.error(error); - console.log(''); - }); - - process.on('SIGINT', () => { - require(`${events}SIGINT`).execute(this); - }); - - process.on('SIGTERM', () => { - require(`${events}SIGTERM`).execute(this); - }); - - process.on('uncaughtException', (error) => { - require(`${events}uncaughtException`).execute(this, error); - }); - - process.on('exit', () => { - this.funcs.logger("Bot", "Stopping"); - }); - - process.on('warning', (warning) => { - require(`${events}warning`).execute(this, warning); - }); + events(this); this.login(this.config.token).catch((err) => { - this.funcs.logger("Discord Client / Error"); + this.funcs.logger("Discord Client", "Login Error"); console.log(err); console.log(''); }); } } - -export default RadioClient diff --git a/src/client/classes/Datastore.js b/src/client/classes/Datastore.ts similarity index 63% rename from src/client/classes/Datastore.js rename to src/client/classes/Datastore.ts index bf0ce66..9f4f1fe 100644 --- a/src/client/classes/Datastore.js +++ b/src/client/classes/Datastore.ts @@ -1,7 +1,21 @@ -const fs = require('fs'); -const path = require('path'); +import { Guild } from 'discord.js'; +import fs from 'fs'; +import path from 'path'; +import { state } from './Radio'; +import { statistics } from './Statistics'; -module.exports = class { +export interface datastore { + guild: { + id: string, + name?: string + }, + statistics: statistics, + state: state | null, + updated?: string +} + +export default class Datastore { + map: Map; constructor() { this.map = new Map(); this.loadData(); @@ -13,7 +27,7 @@ module.exports = class { fs.mkdirSync(dir); } //console.log(""); - const dataFiles = fs.readdirSync(path.join(path.dirname(__dirname), '../../datastore')).filter(f => f.endsWith('.json')); + const dataFiles = fs.readdirSync(path.join(path.dirname(__dirname), '../../datastore')).filter((f: string) => f.endsWith('.json')); for (const file of dataFiles) { try { const json = require(`../../../datastore/${file}`); @@ -27,7 +41,8 @@ module.exports = class { //console.log(""); } - checkEntry(id){ + checkEntry(id: string | undefined){ + if(!id) return; this.loadEntry(id); if(!this.map.has(id)){ this.createEntry(id); @@ -37,17 +52,19 @@ module.exports = class { } } - createEntry(id){ - let newData = {}; - newData.guild = {}; - newData.guild.id = id; - newData.statistics = {}; - newData.state = {}; + createEntry(id: string){ + let newData: datastore = { + guild: { + id: id, + }, + statistics: {}, + state: null + }; this.map.set(id, newData); this.saveEntry(id, newData); } - loadEntry(id){ + loadEntry(id: string){ try { const json = require(`../../../datastore/` + id + '.json'); this.map.set(id, json); @@ -55,11 +72,11 @@ module.exports = class { } } - getEntry(id){ + getEntry(id: string){ return this.map.get(id); } - updateEntry(guild, newData) { + updateEntry(guild: Guild | { id: string, name: string }, newData: datastore) { newData.guild.name = guild.name; let date = new Date(); @@ -70,36 +87,14 @@ module.exports = class { //this.showEntry(this.getEntry(guild.id)); } - showEntry(data){ + showEntry(data : datastore){ console.log(data); } - createTestFile () { - let newData = { - "guild": { - "id": "test", - "name": "Test" - }, - "statistics": { - "test": { - "time": 0, - "used": 0 - } - }, - "state": { - - } - } - - this.updateEntry(newData.guild, newData); - } - - saveEntry(file, data) { - data = JSON.stringify(data, null, 4); - - fs.writeFile(path.join(path.dirname(__dirname), '../../datastore') + "/" + file + ".json", data, 'utf8', function(err) { + saveEntry(file: string, data: datastore) { + fs.writeFile(path.join(path.dirname(__dirname), '../../datastore') + "/" + file + ".json", JSON.stringify(data, null, 4), 'utf8', function(err: NodeJS.ErrnoException | null) { if (err) { - //console.log(err); + } }); } diff --git a/src/client/classes/Radio.js b/src/client/classes/Radio.js deleted file mode 100644 index 7990782..0000000 --- a/src/client/classes/Radio.js +++ /dev/null @@ -1,78 +0,0 @@ -const { - getVoiceConnection, - joinVoiceChannel -} = require("@discordjs/voice"); - -module.exports = class Radio extends Map { - constructor() { - super(); - } - - save(client) { - let currentRadios = this.keys(); - let radio = currentRadios.next(); - - while (!radio.done) { - let currentRadio = this.get(radio.value); - - if (currentRadio) { - currentRadio.guild = client.datastore.getEntry(radio.value).guild; - - client.statistics.update(client, currentRadio.guild, currentRadio); - client.funcs.saveState(client, currentRadio.guild, currentRadio); - currentRadio.connection?.destroy(); - currentRadio.message?.delete(); - this.delete(radio.value); - } - - radio = currentRadios.next(); - } - } - - restore(client, guilds) { - if(!client.stations) return; - - guilds.forEach(async guild => { - let state = client.funcs.loadState(client, guild); - if(!state) return; - if(!state.station || !state.channels.voice || !state.channels.text) return; - let voiceChannel = client.channels.cache.get(state.channels.voice); - if(!voiceChannel) return; - if(voiceChannel.members.filter(member => !member.user.bot).size === 0) return; - - - const sstation = await client.stations.search(state.station.name, "direct"); - let station = sstation; - - if(!station) return; - - const construct = { - textChannel: client.channels.cache.get(state.channels.text), - voiceChannel: client.channels.cache.get(state.channels.voice), - connection: null, - message: null, - station: station - }; - this.set(guild.id, construct); - - try { - const connection = - getVoiceConnection(guild.id) ?? - joinVoiceChannel({ - channelId: voiceChannel.id, - guildId: voiceChannel.guild.id, - adapterCreator: voiceChannel.guild.voiceAdapterCreator - }); - - construct.connection = connection; - let date = new Date(); - construct.startTime = date.getTime(); - client.datastore.checkEntry(guild.id); - client.funcs.play(client, null, guild, station); - } catch (error) { - console.log(error); - } - }); - } - -}; diff --git a/src/client/classes/Radio.ts b/src/client/classes/Radio.ts new file mode 100644 index 0000000..357c120 --- /dev/null +++ b/src/client/classes/Radio.ts @@ -0,0 +1,108 @@ +import { Channel, Collection, GuildMember, OAuth2Guild, TextBasedChannel, VoiceBasedChannel, VoiceChannel } from "discord.js"; +import { getVoiceConnection, joinVoiceChannel, VoiceConnection } from "@discordjs/voice"; +import RadioClient from "../../Client"; +import { station } from "./Stations"; +import { datastore } from "./Datastore"; + +export interface radio { + textChannel: Channel | TextBasedChannel | undefined | null, + voiceChannel: Channel | VoiceBasedChannel | undefined, + connection: VoiceConnection | null, + message: null, + station: station, + datastore?: datastore, + currentTime?: number, + startTime: number, + playTime?: number, +} + +export interface state { + channels: { + "text": string | undefined, + "voice": string | undefined + }, + date: string, + station: { + name: string, + owner: string + } +} + +export default class Radio extends Map { + + constructor() { + super(); + } + + save(client: RadioClient): void { + let currentRadios = this.keys(); + let radio = currentRadios.next(); + + while (!radio.done) { + let currentRadio = this.get(radio.value); + + if (currentRadio) { + currentRadio.guild = client.datastore?.getEntry(radio.value)?.guild; + + client.statistics?.update(client, currentRadio.guild, currentRadio); + client.funcs.saveState(client, currentRadio.guild, currentRadio); + currentRadio.connection?.destroy(); + currentRadio.message?.delete(); + this.delete(radio.value); + } + + radio = currentRadios.next(); + } + } + + restore(client: RadioClient, guilds: Collection): void { + if(!client.stations) return; + + guilds.forEach(async (guild: OAuth2Guild) => { + let state = client.funcs.loadState(client, guild); + + if(!state) return; + if(state.channels?.text === undefined || state.channels?.voice === undefined) return; + + let voiceChannel = client.channels.cache.get(state.channels.voice); + if(!voiceChannel || !(voiceChannel instanceof VoiceChannel)) return; + if(voiceChannel.members.filter((member: GuildMember) => !member.user.bot).size === 0) return; + + const sstation = client.stations?.search(state.station.name, "direct"); + let station = sstation; + + if(!station) return; + + let date = new Date(); + const construct: radio = { + textChannel: client.channels.cache.get(state.channels.text), + voiceChannel: client.channels.cache.get(state.channels.voice), + connection: null, + message: null, + station: station, + startTime: date.getTime() + }; + this.set(guild.id, construct); + + try { + const connection = + getVoiceConnection(guild.id) ?? + joinVoiceChannel({ + channelId: voiceChannel.id, + guildId: voiceChannel.guild.id, + adapterCreator: voiceChannel.guild.voiceAdapterCreator + }); + + construct.connection = connection; + let date = new Date(); + construct.startTime = date.getTime(); + client.datastore?.checkEntry(guild.id); + + client.funcs.play(client, null, guild, station); + } catch (error) { + console.log(error); + } + }); + } + +}; diff --git a/src/client/classes/Stations.js b/src/client/classes/Stations.ts similarity index 55% rename from src/client/classes/Stations.js rename to src/client/classes/Stations.ts index 67d67c5..c8319af 100644 --- a/src/client/classes/Stations.js +++ b/src/client/classes/Stations.ts @@ -1,80 +1,59 @@ -const _importDynamic = new Function('modulePath', 'return import(modulePath)'); -const fetch = (...args) => _importDynamic('node-fetch').then(({default: fetch}) => fetch(...args)); +import logger from "../funcs/logger"; + +export interface station { + name: string, + owner: string, + logo: string, + stream: { + [key: string]: string + } +} + +export default class Stations extends Array { -module.exports = class Stations extends Array { constructor() { super(); - this.logger = require("../funcs/logger.js"); } - async fetch(options){ + async fetch(options: { url: string, show?: boolean}){ try { - this.logger('Stations', 'Started fetching list – ' + options.url); - let list = await fetch(options.url) + logger('Stations', 'Started fetching list - ' + options.url); + let stations: station[] = await fetch(options.url) .then(this.checkFetchStatus) - .then(response => response.json()); + .then((response: Response) => response.json()); - if(list){ - this.length = 0; - list.forEach(station => { - try { - this.push(station); - } catch (error) { - - } - }); - - if(options.show){ - list.forEach(station => { - this.logger('Stations', station.name); - }); - } - - list.forEach(async station => { - try { - let stationTest = await fetch(station.stream[station.stream.default]); - if(stationTest.ok === true) return; - this.splice(this.indexOf(station),1); - } catch (error) { - this.splice(this.indexOf(station),1); - } - }); + for(const station of stations){ + this.push(station); + if(options.show) logger('Stations', station.name); } - this.logger('Stations', 'Successfully fetched list'); + logger('Stations', 'Successfully fetched list'); } catch (error) { - this.logger('Stations', 'Fetching list failed'); + logger('Stations', 'Fetching list failed'); console.error(error + "\n"); - if(this.length == 0) this.fetch(options); + if(this.length == 0) setTimeout( () => { + this.fetch(options) + }, 150 ); } } - checkFetchStatus(response) { - if (response.ok) { // res.status >= 200 && res.status < 300 + checkFetchStatus(response: Response) { + if (response.ok) { return response; } else { throw new Error(response.status + " " + response.statusText); } } - search(key, type) { - if (this === null) return false; - if (!key) return false; - if (!type) return false; + search(key: string, type: string) { + if (this === null || !key || !type) return null; if(type == "direct"){ - let foundStation; - this.forEach(station => { - if(station.name != key) return false; - foundStation = station; - }); - - return foundStation; + return this.find(station => station.name === key); } else { - - let foundStations = []; - if (key == "radio") return false; + let foundStations : { station: string, name: string, probability: number }[] = []; + if (key == "radio") return null; this .filter( @@ -95,7 +74,7 @@ module.exports = class Stations extends Array { foundStations.push({ station: x, name: x.name, probability: probabilityIncrement }) ); } - if (foundStations.length === 0) return false; + if (foundStations.length === 0) return null; for (let i = 0; i < foundStations.length; i++) { for (let j = 0; j < foundStations.length; j++) { if (foundStations[i] === foundStations[j] && i !== j) foundStations.splice(i, 1); @@ -116,7 +95,9 @@ module.exports = class Stations extends Array { } } } - let highestProbabilityStation; + let highestProbabilityStation : { station: string, name: string, probability: number } | undefined; + let stationName = ""; + for (let i = 0; i < foundStations.length; i++) { if ( !highestProbabilityStation || @@ -127,10 +108,10 @@ module.exports = class Stations extends Array { highestProbabilityStation && highestProbabilityStation.probability === foundStations[i].probability ) { - highestProbabilityStation = foundStations[i].station; + stationName = foundStations[i].station; } } - return highestProbabilityStation; + return stationName; } } }; diff --git a/src/client/classes/Statistics.js b/src/client/classes/Statistics.js deleted file mode 100644 index 78bfac5..0000000 --- a/src/client/classes/Statistics.js +++ /dev/null @@ -1,70 +0,0 @@ -module.exports = class { - constructor() { - this.map = new Map(); - } - - update(client, guild, radio) { - - client.datastore.checkEntry(guild.id); - - radio.datastore = client.datastore.getEntry(guild.id); - - if(!radio.datastore.statistics[radio.station.name]){ - radio.datastore.statistics[radio.station.name] = {}; - radio.datastore.statistics[radio.station.name].time = 0; - radio.datastore.statistics[radio.station.name].used = 0; - client.datastore.updateEntry(guild, radio.datastore); - } - - let date = new Date(); - radio.currentTime = date.getTime(); - radio.playTime = parseInt(radio.currentTime)-parseInt(radio.startTime); - radio.datastore.statistics[radio.station.name].time = parseInt(radio.datastore.statistics[radio.station.name].time)+parseInt(radio.playTime); - - radio.datastore.statistics[radio.station.name].used = parseInt(radio.datastore.statistics[radio.station.name].used)+1; - client.datastore.updateEntry(guild, radio.datastore); - this.calculateGlobal(client); - } - - calculateGlobal(client){ - if(!client.stations) return; - if(!client.datastore.map) return; - - let guilds = client.datastore.map.keys(); - let stations = client.stations; - let statistics = {}; - - if(!client.stations) return; - - let calculation = guilds.next(); - - while (!calculation.done) { - let currentGuild = client.datastore.getEntry(calculation.value); - if(calculation.value != 'global'){ - if(stations){ - Object.keys(stations).forEach(function(station) { - if(currentGuild.statistics[stations[station].name] && currentGuild.statistics[stations[station].name].time && parseInt(currentGuild.statistics[stations[station].name].time) != 0 && currentGuild.statistics[stations[station].name].used && parseInt(currentGuild.statistics[stations[station].name].used) != 0){ - if(!statistics[stations[station].name]){ - statistics[stations[station].name] = {}; - statistics[stations[station].name].time = 0; - statistics[stations[station].name].used = 0; - } - - statistics[stations[station].name].time = parseInt(statistics[stations[station].name].time)+parseInt(currentGuild.statistics[stations[station].name].time); - statistics[stations[station].name].used = parseInt(statistics[stations[station].name].used)+parseInt(currentGuild.statistics[stations[station].name].used); - } - }); - } - } - calculation = guilds.next(); - } - - let newData = {}; - newData.guild = {}; - newData.guild.id = "global"; - newData.guild.name = "global"; - newData.statistics = statistics; - client.datastore.updateEntry(newData.guild, newData); - } - -}; diff --git a/src/client/classes/Statistics.ts b/src/client/classes/Statistics.ts new file mode 100644 index 0000000..78ea997 --- /dev/null +++ b/src/client/classes/Statistics.ts @@ -0,0 +1,95 @@ +import { Guild } from "discord.js"; +import RadioClient from "../../Client"; +import { radio } from "./Radio"; + +export interface statistics { + [key: string]: statistic +} + +interface statistic { + "time": number, + "used": number +} + +export default class Statistics { + map: Map; + + constructor() { + this.map = new Map(); + } + + update(client: RadioClient, guild: Guild | null, radio: radio) { + if(!guild) return; + + client.datastore?.checkEntry(guild.id); + + radio.datastore = client.datastore?.getEntry(guild.id); + + if(radio.datastore === undefined) return; + + if(!radio.datastore.statistics[radio.station.name]){ + radio.datastore.statistics[radio.station.name] = { + time: 0, + used: 0 + }; + client.datastore?.updateEntry(guild, radio.datastore); + } + + let date = new Date(); + radio.currentTime = date.getTime(); + radio.playTime = radio.currentTime - radio.startTime; + radio.datastore.statistics[radio.station.name] = { + time: radio.datastore.statistics[radio.station.name].time + radio.playTime, + used: radio.datastore.statistics[radio.station.name].used + 1 + } + client.datastore?.updateEntry(guild, radio.datastore); + this.calculateGlobal(client); + } + + calculateGlobal(client: RadioClient){ + if(!client.datastore?.map) return; + + let guilds = client.datastore.map.keys(); + let statistics : statistics = {}; + + if(!client.stations) return; + + let calculation = guilds.next(); + + while (!calculation.done) { + let currentGuild = client.datastore.getEntry(calculation.value); + if(calculation.value != 'global'){ + if(client.stations){ + for(const station of client.stations) { + if(!currentGuild) return; + if(currentGuild.statistics[station.name] && currentGuild.statistics[station.name]?.time && currentGuild.statistics[station.name].time != 0 && currentGuild.statistics[station.name].used && currentGuild.statistics[station.name].used != 0){ + if(!statistics[station.name]){ + statistics[station.name] = { + time: 0, + used: 0 + }; + } + + statistics[station.name] = { + time: statistics[station.name].time + currentGuild.statistics[station.name].time, + used: statistics[station.name].used + currentGuild.statistics[station.name].used + } + } + } + } + } + calculation = guilds.next(); + } + + let newData = { + guild: { + id: "global", + name: "global" + }, + statistics: statistics, + state: null + }; + client.datastore.updateEntry(newData.guild, newData); + } + +}; diff --git a/src/client/classes/Streamer.js b/src/client/classes/Streamer.js deleted file mode 100644 index 3ed27de..0000000 --- a/src/client/classes/Streamer.js +++ /dev/null @@ -1,120 +0,0 @@ -const { - createAudioPlayer, - createAudioResource, - AudioPlayerStatus, - NoSubscriberBehavior -} = require("@discordjs/voice"); - -module.exports = class { - constructor() { - this.map = new Map(); - this.mode = null; - this.logger = require("../funcs/logger.js"); - } - - init(client){ - if(!client.config.streamerMode) return; - - switch(client.config.streamerMode){ - case "manual": - this.mode = "manual"; - break; - case "auto": - this.mode = "auto"; - break; - default: - this.mode = "manual"; - } - - if(this.mode == "auto"){ - if(!client.stations) return; - - client.stations.forEach(station => { - this.play(station); - }); - } - } - - refresh(client){ - this.init(client); - - let streamers = this.map.keys(); - streamers.forEach(streamer => { - if(client.stations.findIndex(station => station.name == streamer) == -1){ - this.stop(streamer); - } - }); - } - - play(station) { - let audioPlayer = this.map.get(station.name); - if(!audioPlayer) { - if(this.mode == "auto"){ - audioPlayer = createAudioPlayer({ - behaviors: { - noSubscriber: NoSubscriberBehavior.Play, - maxMissedFrames: Math.round(5000 / 20), - }, - }); - } - if(this.mode == "manual"){ - audioPlayer = createAudioPlayer({ - behaviors: { - noSubscriber: NoSubscriberBehavior.Stop, - maxMissedFrames: Math.round(5000 / 20), - }, - }); - } - this.map.set(station.name, audioPlayer); - } - const url = station.stream[station.stream.default]; - const resource = createAudioResource(url); - audioPlayer.play(resource); - audioPlayer - .on('playing', () => { - this.logger('Streamer', station.name + " / " + "Playing"); - }) - .on('idle', () => { - this.logger('Streamer', station.name + " / " + "Idle"); - audioPlayer.removeAllListeners(); - if(this.mode == "manual" && audioPlayer.subscribers.length == 0) return; - this.play(station); - }) - .on('paused', () => { - this.logger('Streamer', station.name + " / " + "Paused"); - }) - .on('buffering', () => { - this.logger('Streamer', station.name + " / " + "Buffering"); - }) - .on('autopaused', () => { - this.logger('Streamer', station.name + " / " + "AutoPaused"); - }) - .on('error', error => { - this.logger('Streamer', station.name + " / " + "Error" + "\n" + error); - }); - return audioPlayer; - } - - stop(station){ - let audioPlayer = this.map.get(station.name); - if(audioPlayer){ - this.logger('Streamer', station.name + " / " + "Stop"); - audioPlayer.removeAllListeners(); - audioPlayer.stop(); - } - this.map.delete(station.name); - } - - listen(station) { - let audioPlayer = this.map.get(station.name); - if(!audioPlayer || this.mode == "manual" && audioPlayer.subscribers.length == 0) audioPlayer = this.play(station); - return audioPlayer; - } - - leave(client) { - if(!client.stations) return; - client.stations.forEach(station => { - this.stop(station); - }); - } -}; diff --git a/src/client/classes/Streamer.ts b/src/client/classes/Streamer.ts new file mode 100644 index 0000000..9e583e2 --- /dev/null +++ b/src/client/classes/Streamer.ts @@ -0,0 +1,116 @@ +import logger from "../funcs/logger"; +import { AudioPlayer, AudioPlayerStatus, createAudioPlayer, createAudioResource, NoSubscriberBehavior } from "@discordjs/voice"; +import RadioClient from "../../Client"; +import { station } from "./Stations"; + +export default class Streamer { + map: Map; + mode: "auto" | "manual"; + + constructor() { + this.map = new Map(); + this.mode = "manual"; + } + + init(client: RadioClient){ + if(!client.config.streamerMode) return; + + switch(client.config.streamerMode){ + case "manual": + this.mode = "manual"; + break; + case "auto": + this.mode = "auto"; + break; + default: + this.mode = "manual"; + } + + if(this.mode == "auto"){ + if(!client.stations) return; + + for(const station of client.stations){ + this.play(station); + } + } + } + + refresh(client: RadioClient){ + this.init(client); + + for (const streamer of this.map.keys()){ + if(client.stations?.findIndex((station: station) => station.name == streamer) == -1){ + this.stop(streamer); + } + } + } + + play(station: station) { + let audioPlayer = this.map.get(station.name); + if(!audioPlayer) { + if(this.mode == "auto"){ + audioPlayer = createAudioPlayer({ + behaviors: { + noSubscriber: NoSubscriberBehavior.Play, + maxMissedFrames: Math.round(5000 / 20), + } + }); + } else { + audioPlayer = createAudioPlayer({ + behaviors: { + noSubscriber: NoSubscriberBehavior.Stop, + maxMissedFrames: Math.round(5000 / 20), + } + }); + } + + audioPlayer + .on(AudioPlayerStatus.Playing, () => { + logger('Streamer', station.name + " / " + "Playing"); + }) + .on(AudioPlayerStatus.Idle, () => { + logger('Streamer', station.name + " / " + "Idle"); + }) + .on(AudioPlayerStatus.Paused, () => { + logger('Streamer', station.name + " / " + "Paused"); + }) + .on(AudioPlayerStatus.Buffering, () => { + logger('Streamer', station.name + " / " + "Buffering"); + }) + .on(AudioPlayerStatus.AutoPaused, () => { + logger('Streamer', station.name + " / " + "AutoPaused"); + }) + + this.map.set(station.name, audioPlayer); + } + + const url = station.stream[station.stream.default]; + const resource = createAudioResource(url); + audioPlayer.play(resource); + + return audioPlayer; + } + + stop(streamer: string){ + let audioPlayer = this.map.get(streamer); + if(audioPlayer){ + logger('Streamer', streamer + " / " + "Stop"); + audioPlayer.removeAllListeners(); + audioPlayer.stop(); + } + this.map.delete(streamer); + } + + listen(station: station) { + let audioPlayer = this.map.get(station.name); + if(!audioPlayer) audioPlayer = this.play(station); + return audioPlayer; + } + + leave(client: RadioClient) { + if(!client.stations) return; + for(const station of client.stations){ + this.stop(station.name); + } + } +}; diff --git a/src/client/commands.js b/src/client/commands.js deleted file mode 100644 index 4eb46d9..0000000 --- a/src/client/commands.js +++ /dev/null @@ -1,83 +0,0 @@ -const { SlashCommandBuilder } = require('@discordjs/builders'); -const { REST } = require('@discordjs/rest'); -const { Routes } = require('discord-api-types/v9'); -const fs = require('fs'); -const path = require ('path'); - -module.exports = { - async execute(client) { - - const commands = []; - const commandFiles = fs.readdirSync(path.join("./src/client/commands")).filter(f => f.endsWith(".js")); - - for (const file of commandFiles) { - const command = require(`./commands/${file}`); - client.commands.set(command.name, command); - - command.data = new SlashCommandBuilder() - .setName(command.name) - .setDescription(command.description); - - command.data = command.data.toJSON(); - if(command.options) { - command.options.forEach(function(option) { - if(option.type == "STRING") option.type = 3; - if(option.type == "NUMBER") option.type = 10; - command.data.options.push(option); - }); - } - - commands.push(command.data); - } - - const rest = new REST({ version: '9' }).setToken(client.config.token); - - (async () => { - try { - client.funcs.logger('Slash Commands', 'Started refreshing application (/) commands.'); - - if(client.config.devMode){ - await rest.put( - Routes.applicationCommands(client.user.id), - { body: [] }, - ); - - let guilds = await client.guilds.fetch(); - guilds.forEach(async guild => { - try { - await rest.put( - Routes.applicationGuildCommands(client.user.id, guild.id), - { body: commands } - ); - client.funcs.logger('Slash Commands', 'Guild Applications – Successful' + "\n" + guild.id + " / " + guild.name); - } catch (DiscordAPIError) { - client.funcs.logger('Slash Commands', 'Guild Applications – Failed' + "\n" + guild.id + " / " + guild.name); - if(DiscordAPIError.name != "DiscordAPIError[50001]") console.error(DiscordAPIError.message + "\n\n"); - } - }); - } else { - await rest.put( - Routes.applicationCommands(client.user.id), - { body: commands } - ); - - let guilds = await client.guilds.fetch(); - guilds.forEach(async guild => { - try { - await rest.put( - Routes.applicationGuildCommands(client.user.id, guild.id), - { body: [] } - ); - } catch (DiscordAPIError) { - } - }); - } - - client.funcs.logger('Slash Commands', 'Successfully reloaded application (/) commands.' + "\n"); - } catch (error) { - client.funcs.logger('Slash Commands', 'Reloading application (/) commands failed.' + "\n"); - console.error(error); - } - })(); - } -} diff --git a/src/client/commands.ts b/src/client/commands.ts new file mode 100644 index 0000000..5874489 --- /dev/null +++ b/src/client/commands.ts @@ -0,0 +1,72 @@ +import { Snowflake } from "discord.js"; +import RadioClient from "../Client"; +import bug from "./commands/bug"; +import help from "./commands/help"; +import invite from "./commands/invite"; +import list from "./commands/list"; +import maintenance from "./commands/maintenance"; +import next from "./commands/next"; +import nowplaying from "./commands/nowplaying"; +import play from "./commands/play"; +import prev from "./commands/prev"; +import statistics from "./commands/statistics"; +import status from "./commands/status"; +import stop from "./commands/stop"; + +export interface command { + name: string, + description: string, + category: string, + options?: [], + execute: Function +} + +export default async function commands(client: RadioClient) { + const commands : command[] = [ bug, help, invite, list, maintenance, next, nowplaying, play, prev, statistics, status, stop ]; + + for(const command of commands){ + client.commands.set(command.name, command); + } + + if(!client.application) return; + client.funcs.logger('Application Commands', 'Started refreshing application (/) commands.'); + if(client.config.devMode){ + client.application.commands.set([]); + for(const command of commands){ + let guilds = await client.guilds.fetch(); + guilds.forEach(async (guild: { id: Snowflake; name: string; }) => { + try { + if(!client.application) return; + await client.application.commands.create({ + name: command.name, + description: command.description, + options: command.options || [] + }, guild.id); + client.funcs.logger('Application Commands', 'Guild: ' + guild.id + " (" + guild.name + ") \n" + 'Command: ' + command.name); + } catch(DiscordAPIError) { + client.funcs.logger('Application Commands', 'Guild: ' + guild.id + " (" + guild.name + ") [FAILED] \n" + 'Command: ' + command.name); + } + }); + } + } else { + for(const command of commands){ + await client.application.commands.create({ + name: command.name, + description: command.description, + options: command.options || [] + }); + + client.funcs.logger('Application Commands', 'Command: ' + command.name); + } + + let guilds = await client.guilds.fetch(); + guilds.forEach(async (guild: { id: Snowflake; }) => { + try { + if(!client.application) return; + await client.application.commands.set([], guild.id); + } catch (DiscordAPIError){ + } + }); + } + client.funcs.logger('Application Commands', 'Successfully reloaded application (/) commands.' + "\n"); +} diff --git a/src/client/commands/bug.js b/src/client/commands/bug.js deleted file mode 100644 index 87bac4a..0000000 --- a/src/client/commands/bug.js +++ /dev/null @@ -1,29 +0,0 @@ -import { EmbedBuilder } from "discord.js"; - -module.exports = { - name: 'bug', - description: 'Report a bug', - category: 'info', - async execute(interaction, client) { - let message = {}; - - message.bugTitle = client.messages.bugTitle.replace("%client.user.username%", client.user.username); - message.bugDescription = client.messages.bugDescription.replace("%client.config.supportGuild%", client.config.supportGuild); - - const embed = new EmbedBuilder() - .setTitle(message.bugTitle) - .setThumbnail("https://cdn.discordapp.com/emojis/" + client.messageEmojis["logo"].replace(/[^0-9]+/g, '')) - .setColor(client.config.embedColor) - .setDescription(message.bugDescription) - .setImage('https://waren.io/berriabot-temp-sa7a36a9xm6837br/images/empty-3.png') - .setFooter({ - text: client.messages.footerText, - iconURL: "https://cdn.discordapp.com/emojis/" + client.messageEmojis["eximiabots"].replace(/[^0-9]+/g, '') - }); - - interaction.reply({ - embeds: [embed], - ephemeral: true - }); - } -}; diff --git a/src/client/commands/bug.ts b/src/client/commands/bug.ts new file mode 100644 index 0000000..5fb9e57 --- /dev/null +++ b/src/client/commands/bug.ts @@ -0,0 +1,34 @@ +import { ChatInputCommandInteraction, EmbedBuilder } from "discord.js"; +import RadioClient from "../../Client"; + +export default { + name: 'bug', + description: 'Report a bug', + category: 'info', + async execute(interaction: ChatInputCommandInteraction, client: RadioClient) { + if(!client.user) return interaction.reply({ + content: client.messages.emojis["error"] + client.messages.maintenance, + ephemeral: true + }); + + const embed = new EmbedBuilder() + .setTitle(client.messages.replace(client.messages.bugTitle, { + "%client.user.username%": client.user.username + })) + .setThumbnail("https://cdn.discordapp.com/emojis/" + client.messages.emojis["logo"].replace(/[^0-9]+/g, '')) + .setColor(client.config.embedColor) + .setDescription(client.messages.replace(client.messages.bugDescription, { + "%client.config.supportGuild%": client.config.supportGuild + })) + .setImage('https://waren.io/berriabot-temp-sa7a36a9xm6837br/images/empty-3.png') + .setFooter({ + text: client.messages.footerText, + iconURL: "https://cdn.discordapp.com/emojis/" + client.messages.emojis["eximiabots"].replace(/[^0-9]+/g, '') + }); + + interaction.reply({ + embeds: [embed], + ephemeral: true + }); + } +}; diff --git a/src/client/commands/help.js b/src/client/commands/help.js deleted file mode 100644 index 8c96388..0000000 --- a/src/client/commands/help.js +++ /dev/null @@ -1,38 +0,0 @@ -import { EmbedBuilder } from "discord.js"; - -module.exports = { - name: 'help', - description: 'Get help using bot', - category: 'info', - execute(interaction, client) { - let message = {}; - - const categories = []; - for (let i = 0; i < client.commands.size; i++) { - if (!categories.includes([...client.commands.values()][i].category)) categories.push([...client.commands.values()][i].category); - } - let commands = ''; - for (let i = 0; i < categories.length; i++) { - commands += `**» ${categories[i].toUpperCase()}**\n${client.commands.filter(x => x.category === categories[i] && !x.omitFromHelp).map(x => `\`${x.name}\``).join(', ')}\n`; - } - - message.helpTitle = client.messages.helpTitle.replace("%client.user.username%", client.user.username); - message.helpDescription = client.messages.helpDescription.replace("%commands%", commands); - - const embed = new EmbedBuilder() - .setTitle(message.helpTitle) - .setThumbnail("https://cdn.discordapp.com/emojis/" + client.messageEmojis["logo"].replace(/[^0-9]+/g, '')) - .setColor(client.config.embedColor) - .setDescription(message.helpDescription) - .setImage('https://waren.io/berriabot-temp-sa7a36a9xm6837br/images/empty-3.png') - .setFooter({ - text: client.messages.footerText, - iconURL: "https://cdn.discordapp.com/emojis/" + client.messageEmojis["eximiabots"].replace(/[^0-9]+/g, '') - }); - - interaction.reply({ - embeds: [embed], - ephemeral: true - }); - } -}; diff --git a/src/client/commands/help.ts b/src/client/commands/help.ts new file mode 100644 index 0000000..b81ba1b --- /dev/null +++ b/src/client/commands/help.ts @@ -0,0 +1,45 @@ +import { ChatInputCommandInteraction, EmbedBuilder } from "discord.js"; +import RadioClient from "../../Client"; +import { command } from "../commands"; + +export default { + name: 'help', + description: 'Get help using bot', + category: 'info', + execute(interaction: ChatInputCommandInteraction, client: RadioClient) { + + if(!client.user) return interaction.reply({ + content: client.messages.emojis["error"] + client.messages.maintenance, + ephemeral: true + }); + + const categories: string[] = []; + for (let i = 0; i < client.commands.size; i++) { + if (!categories.includes([...client.commands.values()][i].category)) categories.push([...client.commands.values()][i].category); + } + let commands = ''; + for (let i = 0; i < categories.length; i++) { + commands += `**» ${categories[i].toUpperCase()}**\n${client.commands.filter(x => x.category === categories[i]).map((x: command) => `\`${x.name}\``).join(', ')}\n`; + } + + const embed = new EmbedBuilder() + .setTitle(client.messages.replace(client.messages.helpTitle, { + "%client.user.username%": client.user.username + })) + .setThumbnail("https://cdn.discordapp.com/emojis/" + client.messages.emojis["logo"].replace(/[^0-9]+/g, '')) + .setColor(client.config.embedColor) + .setDescription(client.messages.replace(client.messages.helpDescription, { + "%commands%": commands + })) + .setImage('https://waren.io/berriabot-temp-sa7a36a9xm6837br/images/empty-3.png') + .setFooter({ + text: client.messages.footerText, + iconURL: "https://cdn.discordapp.com/emojis/" + client.messages.emojis["eximiabots"].replace(/[^0-9]+/g, '') + }); + + interaction.reply({ + embeds: [embed], + ephemeral: true + }); + } +}; diff --git a/src/client/commands/invite.js b/src/client/commands/invite.ts similarity index 56% rename from src/client/commands/invite.js rename to src/client/commands/invite.ts index d1bc453..a45d52c 100644 --- a/src/client/commands/invite.js +++ b/src/client/commands/invite.ts @@ -1,20 +1,27 @@ -import { EmbedBuilder } from "discord.js"; +import { ChatInputCommandInteraction, EmbedBuilder } from "discord.js"; +import RadioClient from "../../Client"; -module.exports = { +export default { name: 'invite', description: 'Invite Bot', category: 'info', - execute(interaction, client) { - let message = {}; - message.inviteTitle = client.messages.inviteTitle.replace("%client.user.username%", client.user.username); + execute(interaction: ChatInputCommandInteraction, client: RadioClient) { + + if(!client.user) return interaction.reply({ + content: client.messages.emojis["error"] + client.messages.maintenance, + ephemeral: true + }); + const embed = new EmbedBuilder() - .setTitle(message.inviteTitle) + .setTitle(client.messages.replace(client.messages.inviteTitle, { + "%client.user.username%": client.user.username + })) .setColor(client.config.embedColor) .setURL("https://discord.com/api/oauth2/authorize?client_id=" + client.user.id + "&permissions=2184465408&scope=applications.commands%20bot") //View Channels, Send Messages, Embed Links, Use External Emojis, Use Slash Commands, Connect, Speak, Use Voice Activity .setImage('https://waren.io/berriabot-temp-sa7a36a9xm6837br/images/empty-3.png') .setFooter({ text: client.messages.footerText, - iconURL: "https://cdn.discordapp.com/emojis/" + client.messageEmojis["eximiabots"].replace(/[^0-9]+/g, '') + iconURL: "https://cdn.discordapp.com/emojis/" + client.messages.emojis["eximiabots"].replace(/[^0-9]+/g, '') }); interaction.reply({ diff --git a/src/client/commands/list.js b/src/client/commands/list.ts similarity index 52% rename from src/client/commands/list.js rename to src/client/commands/list.ts index 50378c1..563d418 100644 --- a/src/client/commands/list.js +++ b/src/client/commands/list.ts @@ -1,26 +1,35 @@ -import { EmbedBuilder } from "discord.js"; +import { ButtonInteraction, ChatInputCommandInteraction, EmbedBuilder, StringSelectMenuInteraction } from "discord.js"; +import RadioClient from "../../Client"; +import { station } from "../classes/Stations"; -module.exports = { +export default { name: 'list', description: 'List radio stations', category: 'radio', - execute(interaction, client) { - let message = {}; + execute(interaction: ButtonInteraction | ChatInputCommandInteraction | StringSelectMenuInteraction, client: RadioClient) { - if(!client.stations) { - message.errorToGetPlaylist = client.messages.errorToGetPlaylist.replace("%client.config.supportGuild%", client.config.supportGuild); + if(client.config.maintenanceMode){ return interaction.reply({ - content: client.messageEmojis["error"] + message.errorToGetPlaylist, + content: client.messages.emojis["error"] + client.messages.maintenance, ephemeral: true }); } - const radio = client.radio.get(interaction.guild.id); + if(!client.stations) { + return interaction.reply({ + content: client.messages.emojis["error"] + client.messages.replace(client.messages.errorToGetPlaylist, { + "%client.config.supportGuild%": client.config.supportGuild + }), + ephemeral: true + }); + } + + const radio = client.radio?.get(interaction.guild?.id); if(radio && !client.config.maintenanceMode){ client.funcs.listStations(client, interaction); } else { - let stations = `${client.stations.map(s => `**#** ${s.name}`).join('\n')}` + let stations = `${client.stations.map((s: station) => `**#** ${s.name}`).join('\n')}` const hashs = stations.split('**#**').length; for (let i = 0; i < hashs; i++) { stations = stations.replace('**#**', `**${i + 1}.**`); @@ -28,13 +37,13 @@ module.exports = { let embed = new EmbedBuilder() .setTitle(client.messages.listTitle) - .setThumbnail("https://cdn.discordapp.com/emojis/" + client.messageEmojis["list"].replace(/[^0-9]+/g, '')) + .setThumbnail("https://cdn.discordapp.com/emojis/" + client.messages.emojis["list"].replace(/[^0-9]+/g, '')) .setColor(client.config.embedColor) .setDescription(stations) .setImage('https://waren.io/berriabot-temp-sa7a36a9xm6837br/images/empty-3.png') .setFooter({ text: client.messages.footerText, - iconURL: "https://cdn.discordapp.com/emojis/" + client.messageEmojis["eximiabots"].replace(/[^0-9]+/g, '') + iconURL: "https://cdn.discordapp.com/emojis/" + client.messages.emojis["eximiabots"].replace(/[^0-9]+/g, '') }); interaction.reply({ diff --git a/src/client/commands/maintenance.js b/src/client/commands/maintenance.js deleted file mode 100644 index 3098cc0..0000000 --- a/src/client/commands/maintenance.js +++ /dev/null @@ -1,200 +0,0 @@ -import { ActionRowBuilder, EmbedBuilder, StringSelectMenuBuilder } from "discord.js"; -import Streamer from "../classes/Streamer.js"; -const _importDynamic = new Function('modulePath', 'return import(modulePath)'); -const fetch = (...args) => _importDynamic('node-fetch').then(({default: fetch}) => fetch(...args)); - -module.exports = { - name: 'maintenance', - description: 'Bot Maintenance', - category: 'info', - async execute(interaction, client) { - let message = {}; - - if(!client.funcs.isDev(client.config.devId, interaction.user.id)) return interaction.reply({ - content: client.messageEmojis["error"] + client.messages.notAllowed, - ephemeral: true - }); - let action = interaction.options?.getNumber("action") ?? interaction.values?.[0]; - const options = new Array( - { - emoji: "🌀", - label: "Restart Bot", - value: "0" - }, - { - emoji: "<:RadioXStop:688541155377414168>", - label: "Save Radios", - value: "4" - }, - { - emoji: "<:RadioXPlay:688541155712827458>", - label: "Restore Radios", - value: "5" - }, - { - emoji: "#️⃣", - label: "Reload Commands", - value: "6" - }, - { - emoji: "<:RadioXList:688541155519889482>", - label: "Reload Stations", - value: "7" - }, - { - emoji: "<:dnd:746069698139127831>", - label: "Enable Maintenance Mode", - value: "8" - }, - { - emoji: "<:online:746069731836035098>", - label: "Disable Maintenance Mode", - value: "9" - }, - { - emoji: "💤", - label: "Streamer Mode – Manual", - value: "10" - }, - { - emoji: "📡", - label: "Streamer Mode – Auto", - value: "11" - } - ); - - const menu = new ActionRowBuilder() - .addComponents( - new StringSelectMenuBuilder() - .setCustomId('maintenance') - .setPlaceholder('Select action') - .addOptions(options) - ); - - if(!action){ - return interaction.reply({ - content: "**" + client.messages.maintenanceTitle + "**", - components: [menu], - ephemeral: true - }); - } - - client.funcs.logger('Maintenance', options.find(option => option.value == action).label); - - const embed = new EmbedBuilder() - .setTitle(client.messages.maintenanceTitle) - .setColor(client.config.embedColor) - .setDescription(options.find(option => option.value == action).label) - .setFooter({ - text: client.messages.footerText, - iconURL: "https://cdn.discordapp.com/emojis/" + client.messageEmojis["eximiabots"].replace(/[^0-9]+/g, '') - }); - - interaction.reply({ - embeds: [embed], - ephemeral: true - }); - - let guilds = await client.guilds.fetch(); - - switch(action){ - case "0": - client.config.maintenanceMode = true; - process.emit('SIGINT'); - break; - case "4": - client.config.maintenanceMode = true; - client.user.setStatus('idle'); - client.radio.save(client); - client.user.setStatus('online'); - client.config.maintenanceMode = false; - break; - case "5": - client.config.maintenanceMode = true; - client.user.setStatus('idle'); - client.radio.restore(client, guilds); - client.user.setStatus('online'); - client.config.maintenanceMode = false; - break; - case "6": - client.config.maintenanceMode = true; - client.user.setStatus('idle'); - require(`../commands.js`).execute(client); - client.user.setStatus('online'); - client.config.maintenanceMode = false; - break; - case "7": - try { - client.stations.fetch({ - url: client.config.stationslistUrl - }); - client.streamer.refresh(client); - - } catch (error) { - - } - break; - case "8": - client.user.setStatus('dnd'); - client.funcs.logger("Maintenance Mode", "Enabled"); - client.config.maintenanceMode = true; - break; - case "9": - client.user.setStatus('online'); - client.funcs.logger("Maintenance Mode", "Disabled"); - client.config.maintenanceMode = false; - break; - case "10": - client.config.streamerMode = "manual"; - client.config.maintenanceMode = true; - - client.user.setStatus('idle'); - client.radio.save(client); - - setInterval(() => { - if(client.radio.size == 0 && client.config.streamerMode == "manual" && client.config.maintenanceMode){ - client.streamer.leave(client); - client.streamer = new Streamer(); - client.streamer.init(client); - - client.radio.restore(client, guilds); - client.user.setStatus('online'); - client.config.maintenanceMode = false; - } - - if(!client.config.maintenanceMode){ - clearInterval(); - } - }, 500); - - break; - case "11": - client.config.streamerMode = "auto"; - client.config.maintenanceMode = true; - - client.user.setStatus('idle'); - client.radio.save(client); - - setInterval(() => { - if(client.radio.size == 0 && client.config.streamerMode == "auto" && client.config.maintenanceMode){ - client.streamer.leave(client); - client.streamer = new Streamer(); - client.streamer.init(client); - - client.radio.restore(client, guilds); - client.user.setStatus('online'); - client.config.maintenanceMode = false; - } - - if(!client.config.maintenanceMode){ - clearInterval(); - } - }, 500); - - break; - default: - - } - - } -}; diff --git a/src/client/commands/maintenance.ts b/src/client/commands/maintenance.ts new file mode 100644 index 0000000..e255915 --- /dev/null +++ b/src/client/commands/maintenance.ts @@ -0,0 +1,232 @@ +import { ActionRowBuilder, APISelectMenuOption, ButtonInteraction, ChatInputCommandInteraction, EmbedBuilder, StringSelectMenuBuilder, StringSelectMenuInteraction } from "discord.js"; +import RadioClient from "../../Client"; +import Streamer from "../classes/Streamer"; +import commands from "../commands"; + +export default { + name: 'maintenance', + description: 'Bot Maintenance', + category: 'info', + async execute(interaction: ButtonInteraction | ChatInputCommandInteraction | StringSelectMenuInteraction, client: RadioClient) { + + if(!client.funcs.isDev(client.config.devIDs, interaction.user.id)) return interaction.reply({ + content: client.messages.emojis["error"] + client.messages.notAllowed, + ephemeral: true + }); + + let action : number | string | null = null; + + if(interaction.isChatInputCommand()){ + action = interaction.options?.getNumber("action"); + } + + if(interaction.isStringSelectMenu()){ + action = interaction.values?.[0]; + } + + const options: APISelectMenuOption[] = new Array( + { + emoji: { + "name": "🌀", + }, + label: "Restart Bot", + value: "0" + }, + { + emoji: { + id: "688541155377414168", + name: "RadioXStop", + }, + label: "Save Radios", + value: "4" + }, + { + emoji: { + id: "688541155712827458", + name: "RadioXPlay", + }, + label: "Restore Radios", + value: "5" + }, + { + emoji: { + name: "#️⃣", + }, + label: "Reload Commands", + value: "6" + }, + { + emoji: { + id: "688541155519889482", + name: "RadioXList", + }, + label: "Reload Stations", + value: "7" + }, + { + emoji: { + id: "746069698139127831", + name: "dnd", + }, + label: "Enable Maintenance Mode", + value: "8" + }, + { + emoji: { + id: "746069731836035098", + name: "online", + }, + label: "Disable Maintenance Mode", + value: "9" + }, + { + emoji: { + name: "💤", + }, + label: "Streamer Mode - Manual", + value: "10" + }, + { + emoji: { + name: "📡", + }, + label: "Streamer Mode - Auto", + value: "11" + } + ); + + const menu = new ActionRowBuilder() + .addComponents( + new StringSelectMenuBuilder() + .setCustomId('maintenance') + .setPlaceholder('Select action') + .addOptions(options) + ); + + if(!action){ + return interaction.reply({ + content: "**" + client.messages.maintenanceTitle + "**", + components: [menu], + ephemeral: true + }); + } + + client.funcs.logger('Maintenance', options.find((option: APISelectMenuOption) => option.value == action)?.label); + + const embed = new EmbedBuilder() + .setTitle(client.messages.maintenanceTitle) + .setColor(client.config.embedColor) + .setDescription(options.find((option: APISelectMenuOption) => option.value == action)?.label || "-") + .setFooter({ + text: client.messages.footerText, + iconURL: "https://cdn.discordapp.com/emojis/" + client.messages.emojis["eximiabots"].replace(/[^0-9]+/g, '') + }); + + interaction.reply({ + embeds: [embed], + ephemeral: true + }); + + let guilds = await client.guilds.fetch(); + + switch(action){ + case "0": + client.config.maintenanceMode = true; + process.emit('SIGINT'); + break; + case "4": + client.config.maintenanceMode = true; + client.user?.setStatus('idle'); + client.radio?.save(client); + client.user?.setStatus('online'); + client.config.maintenanceMode = false; + break; + case "5": + client.config.maintenanceMode = true; + client.user?.setStatus('idle'); + client.radio?.restore(client, guilds); + client.user?.setStatus('online'); + client.config.maintenanceMode = false; + break; + case "6": + client.config.maintenanceMode = true; + client.user?.setStatus('idle'); + commands(client); + client.user?.setStatus('online'); + client.config.maintenanceMode = false; + break; + case "7": + try { + client.stations?.fetch({ + url: client.config.stationslistUrl + }); + client.streamer?.refresh(client); + + } catch (error) { + + } + break; + case "8": + client.user?.setStatus('dnd'); + client.funcs.logger("Maintenance Mode", "Enabled"); + client.config.maintenanceMode = true; + break; + case "9": + client.user?.setStatus('online'); + client.funcs.logger("Maintenance Mode", "Disabled"); + client.config.maintenanceMode = false; + break; + case "10": + client.config.streamerMode = "manual"; + client.config.maintenanceMode = true; + + client.user?.setStatus('idle'); + client.radio?.save(client); + + setInterval(() => { + if(client.radio?.size == 0 && client.config.streamerMode == "manual" && client.config.maintenanceMode){ + client.streamer?.leave(client); + client.streamer = new Streamer(); + client.streamer.init(client); + + client.radio?.restore(client, guilds); + client.user?.setStatus('online'); + client.config.maintenanceMode = false; + } + + if(!client.config.maintenanceMode){ + clearInterval(undefined); + } + }, 500); + + break; + case "11": + client.config.streamerMode = "auto"; + client.config.maintenanceMode = true; + + client.user?.setStatus('idle'); + client.radio?.save(client); + + setInterval(() => { + if(client.radio?.size == 0 && client.config.streamerMode == "auto" && client.config.maintenanceMode){ + client.streamer?.leave(client); + client.streamer = new Streamer(); + client.streamer.init(client); + + client.radio.restore(client, guilds); + client.user?.setStatus('online'); + client.config.maintenanceMode = false; + } + + if(!client.config.maintenanceMode){ + clearInterval(undefined); + } + }, 500); + + break; + default: + + } + + } +}; diff --git a/src/client/commands/next.js b/src/client/commands/next.js deleted file mode 100644 index 268752a..0000000 --- a/src/client/commands/next.js +++ /dev/null @@ -1,35 +0,0 @@ -module.exports = { - name: 'next', - description: 'Next Station', - category: 'radio', - async execute(interaction, client, command) { - if (client.funcs.check(client, interaction, command)) { - const radio = client.radio.get(interaction.guild.id); - - let index = client.stations.findIndex(station => station.name == radio.station.name) + 1; - if(index == client.stations.length) index = 0; - - let station = client.stations[index]; - - if(!station) return interaction.reply({ - content: client.messageEmojis["error"] + client.messages.noSearchResults, - ephemeral: true - }); - - client.statistics.update(client, interaction.guild, radio); - - let date = new Date(); - radio.station = station; - radio.textChannel = interaction.channel; - radio.startTime = date.getTime(); - - if(interaction.isChatInputCommand()) { - client.funcs.play(client, interaction, interaction.guild, station); - } - if(interaction.isButton()) { - interaction.deferUpdate(); - client.funcs.play(client, null, interaction.guild, station); - } - } - } -} diff --git a/src/client/commands/next.ts b/src/client/commands/next.ts new file mode 100644 index 0000000..60dfd46 --- /dev/null +++ b/src/client/commands/next.ts @@ -0,0 +1,56 @@ +import { ButtonInteraction, ChatInputCommandInteraction, StringSelectMenuInteraction } from "discord.js"; +import RadioClient from "../../Client"; +import { station } from "../classes/Stations" +import { command } from "../commands"; + +export default { + name: 'next', + description: 'Next Station', + category: 'radio', + async execute(interaction: ButtonInteraction | ChatInputCommandInteraction | StringSelectMenuInteraction, client: RadioClient, command: command) { + if (client.funcs.check(client, interaction, command)) { + const radio = client.radio?.get(interaction.guild?.id); + + if(client.config.maintenanceMode){ + return interaction.reply({ + content: client.messages.emojis["error"] + client.messages.maintenance, + ephemeral: true + }); + } + + if(!client.stations) { + return interaction.reply({ + content: client.messages.emojis["error"] + client.messages.replace(client.messages.errorToGetPlaylist, { + "%client.config.supportGuild%": client.config.supportGuild + }), + ephemeral: true + }); + } + + let index: number = client.stations.findIndex((station: station) => station.name == radio.station.name) + 1; + if(index == client.stations?.length) index = 0; + + let station = client.stations[index]; + + if(!station) return interaction.reply({ + content: client.messages.emojis["error"] + client.messages.noSearchResults, + ephemeral: true + }); + + client.statistics?.update(client, interaction.guild, radio); + + let date = new Date(); + radio.station = station; + radio.textChannel = interaction.channel; + radio.startTime = date.getTime(); + + if(interaction.isChatInputCommand()) { + client.funcs.play(client, interaction, interaction.guild, station); + } + if(interaction.isButton()) { + interaction.deferUpdate(); + client.funcs.play(client, null, interaction.guild, station); + } + } + } +} diff --git a/src/client/commands/nowplaying.js b/src/client/commands/nowplaying.js deleted file mode 100644 index 3b7b830..0000000 --- a/src/client/commands/nowplaying.js +++ /dev/null @@ -1,38 +0,0 @@ -import { EmbedBuilder } from "discord.js"; - -module.exports = { - name: 'nowplaying', - description: 'Current Radio Station', - category: 'radio', - async execute(interaction, client, command) { - if (client.funcs.check(client, interaction, command)) { - let message = {}; - const radio = client.radio.get(interaction.guild.id); - - let date = new Date(); - radio.currentTime = date.getTime(); - radio.playTime = parseInt(radio.currentTime)-parseInt(radio.startTime); - const completed = (radio.playTime); - - message.nowplayingDescription = client.messages.nowplayingDescription.replace("%radio.station.name%", radio.station.name); - message.nowplayingDescription = message.nowplayingDescription.replace("%radio.station.owner%" + "\n", radio.station.name != radio.station.owner ? radio.station.owner + "\n" : ""); - message.nowplayingDescription = message.nowplayingDescription.replace("%client.funcs.msToTime(completed)%", client.funcs.msToTime(completed)); - - const embed = new EmbedBuilder() - .setTitle(client.messages.nowplayingTitle) - .setThumbnail((radio.station.logo || "https://cdn.discordapp.com/emojis/" + client.messageEmojis["play"].replace(/[^0-9]+/g, ''))) - .setColor(client.config.embedColor) - .setDescription(message.nowplayingDescription) - .setImage('https://waren.io/berriabot-temp-sa7a36a9xm6837br/images/empty-3.png') - .setFooter({ - text: client.messages.footerText, - iconURL: "https://cdn.discordapp.com/emojis/" + client.messageEmojis["eximiabots"].replace(/[^0-9]+/g, '') - }); - - interaction.reply({ - embeds: [embed], - ephemeral: true - }); - } - } -}; diff --git a/src/client/commands/nowplaying.ts b/src/client/commands/nowplaying.ts new file mode 100644 index 0000000..20ed34e --- /dev/null +++ b/src/client/commands/nowplaying.ts @@ -0,0 +1,40 @@ +import { ButtonInteraction, ChatInputCommandInteraction, EmbedBuilder, StringSelectMenuInteraction } from "discord.js"; +import RadioClient from "../../Client"; +import { command } from "../commands"; + +export default { + name: 'nowplaying', + description: 'Current Radio Station', + category: 'radio', + async execute(interaction: ButtonInteraction | ChatInputCommandInteraction | StringSelectMenuInteraction, client: RadioClient, command: command) { + if(client.funcs.check(client, interaction, command)) { + + const radio = client.radio?.get(interaction.guild?.id); + + let date = new Date(); + radio.currentTime = date.getTime(); + radio.playTime = parseInt(radio.currentTime)-parseInt(radio.startTime); + const completed = (radio.playTime); + + const embed = new EmbedBuilder() + .setTitle(client.messages.nowplayingTitle) + .setThumbnail((radio.station.logo || "https://cdn.discordapp.com/emojis/" + client.messages.emojis["play"].replace(/[^0-9]+/g, ''))) + .setColor(client.config.embedColor) + .setDescription(client.messages.replace(client.messages.nowplayingDescription, { + "%radio.station.name%": radio.station.name, + "%radio.station.owner%\n": radio.station.name != radio.station.owner ? radio.station.owner + "\n" : "", + "%client.funcs.msToTime(completed)%": client.funcs.msToTime(completed) + })) + .setImage('https://waren.io/berriabot-temp-sa7a36a9xm6837br/images/empty-3.png') + .setFooter({ + text: client.messages.footerText, + iconURL: "https://cdn.discordapp.com/emojis/" + client.messages.emojis["eximiabots"].replace(/[^0-9]+/g, '') + }); + + interaction.reply({ + embeds: [embed], + ephemeral: true + }); + } + } +}; diff --git a/src/client/commands/play.js b/src/client/commands/play.js deleted file mode 100644 index b1e816b..0000000 --- a/src/client/commands/play.js +++ /dev/null @@ -1,148 +0,0 @@ -import { PermissionFlagsBits } from "discord.js"; -const { - getVoiceConnection, - joinVoiceChannel -} = require("@discordjs/voice"); - -module.exports = { - name: "play", - usage: "", - description: "Play radio", - options: [ - { type: "STRING", name: "query", description: "Select station", required: false} - ], - category: "radio", - async execute(interaction, client) { - let message = {}; - - if(client.config.maintenanceMode){ - return interaction.reply({ - content: client.messageEmojis["error"] + client.messages.maintenance, - ephemeral: true - }); - } - - if(!client.stations) { - message.errorToGetPlaylist = client.messages.errorToGetPlaylist.replace("%client.config.supportGuild%", client.config.supportGuild); - return interaction.reply({ - content: client.messageEmojis["error"] + message.errorToGetPlaylist, - ephemeral: true - }); - } - - let query = interaction.options?.getString("query") ?? interaction.values?.[0]; - if(!query){ - return client.funcs.listStations(client, interaction); - } - let url = query ? query.replace(/<(.+)>/g, "$1") : ""; - const radio = client.radio.get(interaction.guild.id); - const voiceChannel = interaction.member.voice.channel; - if (!voiceChannel) return interaction.reply({ - content: client.messageEmojis["error"] + client.messages.noVoiceChannel, - ephemeral: true - }); - if (radio) { - if (voiceChannel !== radio.voiceChannel) return interaction.reply({ - content: client.messageEmojis["error"] + client.messages.wrongVoiceChannel, - ephemeral: true - }); - } - if (!query) return interaction.reply({ - content: client.messages.noQuery, - ephemeral: true - }); - const permissions = voiceChannel.permissionsFor(interaction.client.user); - if (!permissions.has(PermissionFlagsBits.Connect)) { - return interaction.reply({ - content: client.messageEmojis["error"] + client.messages.noPermsConnect, - ephemeral: true - }); - } - if (!permissions.has(PermissionFlagsBits.Speak)) { - return interaction.reply({ - content: client.messageEmojis["error"] + client.messages.noPermsSpeak, - ephemeral: true - }); - } - let station; - const number = parseInt(query - 1); - if (url.startsWith("http")) { - return interaction.reply({ - content: client.messageEmojis["error"] + client.messages.errorStationURL, - ephemeral: true - }); - } else if (!isNaN(number)) { - if (number > client.stations.length - 1) { - return interaction.reply({ - content: client.messageEmojis["error"] + client.messages.wrongStationNumber, - ephemeral: true - }); - } else { - station = client.stations[number]; - } - } else { - if (query.length < 3) return interaction.reply({ - content: client.messageEmojis["error"] + client.messages.tooShortSearch, - ephemeral: true - }); - - let type = ""; - - if(interaction.values?.[0]){ - type = "direct"; - } else { - type = "text"; - } - - const sstation = await client.stations.search(query, type); - if (!sstation) return interaction.reply({ - content: client.messageEmojis["error"] + client.messages.noSearchResults, - ephemeral: true - }); - station = sstation; - } - - if (radio) { - client.statistics.update(client, interaction.guild, radio); - - let date = new Date(); - radio.station = station; - radio.textChannel = interaction.channel; - radio.startTime = date.getTime(); - client.funcs.play(client, interaction, interaction.guild, station); - - return; - } - - const construct = { - textChannel: interaction.channel, - voiceChannel: voiceChannel, - connection: null, - message: null, - station: station - }; - client.radio.set(interaction.guild.id, construct); - - try { - const connection = - getVoiceConnection(voiceChannel.guild.id) ?? - joinVoiceChannel({ - channelId: voiceChannel.id, - guildId: voiceChannel.guild.id, - adapterCreator: voiceChannel.guild.voiceAdapterCreator - }); - construct.connection = connection; - let date = new Date(); - construct.startTime = date.getTime(); - client.datastore.checkEntry(interaction.guild.id); - client.funcs.play(client, interaction, interaction.guild, station); - } catch (error) { - console.log(error); - client.radio.delete(interaction.guild.id); - return interaction.reply({ - content: client.messageEmojis["error"] + `An error occured: ${error}`, - ephemeral: true - }); - } - } -}; diff --git a/src/client/commands/play.ts b/src/client/commands/play.ts new file mode 100644 index 0000000..e9bb0cc --- /dev/null +++ b/src/client/commands/play.ts @@ -0,0 +1,159 @@ +import { ApplicationCommandOptionType, ChatInputCommandInteraction, GuildMember, PermissionFlagsBits, StringSelectMenuInteraction } from "discord.js"; +import { getVoiceConnection, joinVoiceChannel } from "@discordjs/voice"; +import RadioClient from "../../Client"; +import { radio } from "../classes/Radio" + +export default { + name: "play", + usage: "", + description: "Play radio", + options: [ + { type: ApplicationCommandOptionType.String, name: "query", description: "Select station", required: false} + ], + category: "radio", + async execute(interaction: ChatInputCommandInteraction | StringSelectMenuInteraction, client: RadioClient) { + + if(client.config.maintenanceMode){ + return interaction.reply({ + content: client.messages.emojis["error"] + client.messages.maintenance, + ephemeral: true + }); + } + + if(!client.stations) { + return interaction.reply({ + content: client.messages.emojis["error"] + client.messages.replace(client.messages.errorToGetPlaylist, { + "%client.config.supportGuild%": client.config.supportGuild + }), + ephemeral: true + }); + } + + let query: string | null = null; + + if(interaction.isChatInputCommand()){ + query = interaction.options?.getString("query"); + } + + if(interaction.isStringSelectMenu()){ + query = interaction.values?.[0]; + } + + if(!query){ + return client.funcs.listStations(client, interaction); + } + + const radio = client.radio?.get(interaction.guild?.id); + + if(!(interaction.member instanceof GuildMember)) return; + const voiceChannel = interaction.member?.voice.channel; + + if (!voiceChannel) return interaction.reply({ + content: client.messages.emojis["error"] + client.messages.noVoiceChannel, + ephemeral: true + }); + + if (radio) { + if (voiceChannel !== radio.voiceChannel) return interaction.reply({ + content: client.messages.emojis["error"] + client.messages.wrongVoiceChannel, + ephemeral: true + }); + } + + if (!query) return interaction.reply({ + content: client.messages.noQuery, + ephemeral: true + }); + + const permissions = voiceChannel.permissionsFor(interaction.client.user); + if (!permissions?.has(PermissionFlagsBits.Connect)) { + return interaction.reply({ + content: client.messages.emojis["error"] + client.messages.noPermsConnect, + ephemeral: true + }); + } + if (!permissions?.has(PermissionFlagsBits.Speak)) { + return interaction.reply({ + content: client.messages.emojis["error"] + client.messages.noPermsSpeak, + ephemeral: true + }); + } + let station; + + if(!isNaN(parseInt(query) - 1)){ + let number = parseInt(query) - 1; + if(number > client.stations.length - 1) { + return interaction.reply({ + content: client.messages.emojis["error"] + client.messages.wrongStationNumber, + ephemeral: true + }); + } else { + station = client.stations[number]; + } + } else { + + if(query.length < 3) return interaction.reply({ + content: client.messages.emojis["error"] + client.messages.tooShortSearch, + ephemeral: true + }); + + let type = "text"; + + if(interaction.isStringSelectMenu() && interaction.values?.[0]){ + type = "direct"; + } + + const sstation = client.stations.search(query, type); + if (!sstation) return interaction.reply({ + content: client.messages.emojis["error"] + client.messages.noSearchResults, + ephemeral: true + }); + station = sstation; + } + + if (radio) { + client.statistics?.update(client, interaction.guild, radio); + + let date = new Date(); + radio.station = station; + radio.textChannel = interaction.channel; + radio.startTime = date.getTime(); + client.funcs.play(client, interaction, interaction.guild, station); + + return; + } + + let date = new Date(); + const construct: radio = { + textChannel: interaction.channel, + voiceChannel: voiceChannel, + connection: null, + message: null, + station: station, + startTime: date.getTime() + }; + client.radio?.set(interaction.guild?.id, construct); + + try { + const connection = + getVoiceConnection(voiceChannel.guild.id) ?? + joinVoiceChannel({ + channelId: voiceChannel.id, + guildId: voiceChannel.guild.id, + adapterCreator: voiceChannel.guild.voiceAdapterCreator + }); + construct.connection = connection; + let date = new Date(); + construct.startTime = date.getTime(); + client.datastore?.checkEntry(interaction.guild?.id); + client.funcs.play(client, interaction, interaction.guild, station); + } catch (error) { + console.log(error); + client.radio?.delete(interaction.guild?.id); + return interaction.reply({ + content: client.messages.emojis["error"] + `An error occured: ${error}`, + ephemeral: true + }); + } + } +}; diff --git a/src/client/commands/prev.js b/src/client/commands/prev.js deleted file mode 100644 index d73093f..0000000 --- a/src/client/commands/prev.js +++ /dev/null @@ -1,36 +0,0 @@ -module.exports = { - name: 'prev', - description: 'Previous Station', - category: 'radio', - async execute(interaction, client, command) { - if (client.funcs.check(client, interaction, command)) { - const radio = client.radio.get(interaction.guild.id); - - let index = client.stations.findIndex(station => station.name == radio.station.name) - 1; - if(index == -1) index = client.stations.length - 1; - - let station = client.stations[index]; - - if(!station) return interaction.reply({ - content: client.messageEmojis["error"] + client.messages.noSearchResults, - ephemeral: true - }); - - client.statistics.update(client, interaction.guild, radio); - - let date = new Date(); - radio.station = station; - radio.textChannel = interaction.channel; - radio.startTime = date.getTime(); - - if(interaction.isChatInputCommand()) { - client.funcs.play(client, interaction, interaction.guild, station); - } - if(interaction.isButton()) { - interaction.deferUpdate(); - client.funcs.play(client, null, interaction.guild, station); - } - - } - } -} diff --git a/src/client/commands/prev.ts b/src/client/commands/prev.ts new file mode 100644 index 0000000..fa8e39c --- /dev/null +++ b/src/client/commands/prev.ts @@ -0,0 +1,57 @@ +import { ButtonInteraction, ChatInputCommandInteraction, StringSelectMenuInteraction } from "discord.js"; +import RadioClient from "../../Client"; +import { command } from "../commands"; +import { station } from "../classes/Stations" + +export default { + name: 'prev', + description: 'Previous Station', + category: 'radio', + async execute(interaction: ButtonInteraction | ChatInputCommandInteraction | StringSelectMenuInteraction, client: RadioClient, command: command) { + if (client.funcs.check(client, interaction, command)) { + const radio = client.radio?.get(interaction.guild?.id); + + if(client.config.maintenanceMode){ + return interaction.reply({ + content: client.messages.emojis["error"] + client.messages.maintenance, + ephemeral: true + }); + } + + if(!client.stations) { + return interaction.reply({ + content: client.messages.emojis["error"] + client.messages.replace(client.messages.errorToGetPlaylist, { + "%client.config.supportGuild%": client.config.supportGuild + }), + ephemeral: true + }); + } + + let index = client.stations.findIndex((station: station) => station.name == radio.station.name) - 1; + if(index == -1) index = client.stations.length - 1; + + let station = client.stations[index]; + + if(!station) return interaction.reply({ + content: client.messages.emojis["error"] + client.messages.noSearchResults, + ephemeral: true + }); + + client.statistics?.update(client, interaction.guild, radio); + + let date = new Date(); + radio.station = station; + radio.textChannel = interaction.channel; + radio.startTime = date.getTime(); + + if(interaction.isChatInputCommand()) { + client.funcs.play(client, interaction, interaction.guild, station); + } + if(interaction.isButton()) { + interaction.deferUpdate(); + client.funcs.play(client, null, interaction.guild, station); + } + + } + } +} diff --git a/src/client/commands/statistics.js b/src/client/commands/statistics.ts similarity index 57% rename from src/client/commands/statistics.js rename to src/client/commands/statistics.ts index 00d3876..636be21 100644 --- a/src/client/commands/statistics.js +++ b/src/client/commands/statistics.ts @@ -1,21 +1,27 @@ -import { EmbedBuilder } from "discord.js"; +import { ButtonInteraction, ChatInputCommandInteraction, EmbedBuilder, StringSelectMenuInteraction } from "discord.js"; +import RadioClient from "../../Client"; -module.exports = { +export default { name: 'statistics', description: 'Show statistics', category: 'info', - execute(interaction, client) { - let message = {}; - let stations = client.stations; - let currentGuild = client.datastore.getEntry(interaction.guild.id); - let global = client.datastore.getEntry("global"); + execute(interaction: ButtonInteraction | ChatInputCommandInteraction | StringSelectMenuInteraction, client: RadioClient) { + + if(!interaction.guild) return interaction.reply({ + content: client.messages.emojis["error"] + client.messages.maintenance, + ephemeral: true + }); + + let currentGuild = client.datastore?.getEntry(interaction.guild.id); + let global = client.datastore?.getEntry("global"); let statistics = ""; if(!client.stations) { - message.errorToGetPlaylist = client.messages.errorToGetPlaylist.replace("%client.config.supportGuild%", client.config.supportGuild); return interaction.reply({ - content: client.messageEmojis["error"] + message.errorToGetPlaylist, + content: client.messages.emojis["error"] + client.messages.replace(client.messages.errorToGetPlaylist, { + "%client.config.supportGuild%": client.config.supportGuild + }), ephemeral: true }); } @@ -28,13 +34,13 @@ module.exports = { const embed = new EmbedBuilder() .setTitle(client.messages.statisticsTitle) - .setThumbnail("https://cdn.discordapp.com/emojis/" + client.messageEmojis["statistics"].replace(/[^0-9]+/g, '')) + .setThumbnail("https://cdn.discordapp.com/emojis/" + client.messages.emojis["statistics"].replace(/[^0-9]+/g, '')) .setColor(client.config.embedColor) .setDescription(statistics) .setImage('https://waren.io/berriabot-temp-sa7a36a9xm6837br/images/empty-3.png') .setFooter({ text: client.messages.footerText, - iconURL: "https://cdn.discordapp.com/emojis/" + client.messageEmojis["eximiabots"].replace(/[^0-9]+/g, '') + iconURL: "https://cdn.discordapp.com/emojis/" + client.messages.emojis["eximiabots"].replace(/[^0-9]+/g, '') }); interaction.reply({ diff --git a/src/client/commands/status.js b/src/client/commands/status.ts similarity index 57% rename from src/client/commands/status.js rename to src/client/commands/status.ts index 67e0ac6..ebc23c9 100644 --- a/src/client/commands/status.js +++ b/src/client/commands/status.ts @@ -1,30 +1,36 @@ -import { EmbedBuilder } from "discord.js"; +import { ChatInputCommandInteraction, EmbedBuilder } from "discord.js"; +import RadioClient from "../../Client"; -module.exports = { +export default { name: 'status', description: 'Bot Status', category: 'info', - async execute(interaction, client) { - let message = {}; + async execute(interaction: ChatInputCommandInteraction, client: RadioClient) { - message.statusTitle = client.messages.statusTitle.replace("%client.user.username%", client.user.username); - let uptime = client.funcs.msToTime(client.uptime); + if(!client.user) return interaction.reply({ + content: client.messages.emojis["error"] + client.messages.maintenance, + ephemeral: true + }); + + let uptime = client.funcs.msToTime(client.uptime || 0); const embed = new EmbedBuilder() - .setTitle(message.statusTitle) - .setThumbnail("https://cdn.discordapp.com/emojis/" + client.messageEmojis["logo"].replace(/[^0-9]+/g, '')) + .setTitle(client.messages.replace(client.messages.statusTitle, { + "%client.user.username%": client.user.username + })) + .setThumbnail("https://cdn.discordapp.com/emojis/" + client.messages.emojis["logo"].replace(/[^0-9]+/g, '')) .setColor(client.config.embedColor) - .addFields( + .addFields([ { name: client.messages.statusField1, value: uptime }, { name: client.messages.statusField2, value: client.config.version }, { name: client.messages.statusField3, value: Date.now() - interaction.createdTimestamp + "ms" }, { name: client.messages.statusField4, value: client.ws.ping.toString() }, { name: client.messages.statusField5, value: client.config.hostedBy } - ) + ]) .setImage('https://waren.io/berriabot-temp-sa7a36a9xm6837br/images/empty-3.png') .setFooter({ text: client.messages.footerText, - iconURL: "https://cdn.discordapp.com/emojis/" + client.messageEmojis["eximiabots"].replace(/[^0-9]+/g, '') + iconURL: "https://cdn.discordapp.com/emojis/" + client.messages.emojis["eximiabots"].replace(/[^0-9]+/g, '') }); interaction.reply({ diff --git a/src/client/commands/stop.js b/src/client/commands/stop.ts similarity index 59% rename from src/client/commands/stop.js rename to src/client/commands/stop.ts index 83516f0..aa15563 100644 --- a/src/client/commands/stop.js +++ b/src/client/commands/stop.ts @@ -1,19 +1,21 @@ -import { EmbedBuilder } from "discord.js"; +import { ButtonInteraction, ChatInputCommandInteraction, EmbedBuilder, StringSelectMenuInteraction } from "discord.js"; +import RadioClient from "../../Client"; +import { command } from "../commands"; -module.exports = { +export default { name: 'stop', description: 'Stop radio', category: 'radio', - async execute(interaction, client, command) { + async execute(interaction: ButtonInteraction | ChatInputCommandInteraction | StringSelectMenuInteraction, client: RadioClient, command: command) { if (client.funcs.check(client, interaction, command)) { - const radio = client.radio.get(interaction.guild.id); - client.statistics.update(client, interaction.guild, radio); + const radio = client.radio?.get(interaction.guild?.id); + client.statistics?.update(client, interaction.guild, radio); radio.connection?.destroy(); - client.funcs.logger('Radio', interaction.guild.id + " / " + 'Stop'); + client.funcs.logger('Radio', interaction.guild?.id + " / " + 'Stop'); const embed = new EmbedBuilder() - .setTitle(client.user.username) - .setThumbnail("https://cdn.discordapp.com/emojis/" + client.messageEmojis["stop"].replace(/[^0-9]+/g, '')) + .setTitle(client.user?.username || "-") + .setThumbnail("https://cdn.discordapp.com/emojis/" + client.messages.emojis["stop"].replace(/[^0-9]+/g, '')) .setColor(client.config.embedColor) .addFields({ name: client.messages.nowplayingTitle, @@ -22,7 +24,7 @@ module.exports = { .setImage('https://waren.io/berriabot-temp-sa7a36a9xm6837br/images/empty-3.png') .setFooter({ text: client.messages.footerText, - iconURL: "https://cdn.discordapp.com/emojis/" + client.messageEmojis["eximiabots"].replace(/[^0-9]+/g, '') + iconURL: "https://cdn.discordapp.com/emojis/" + client.messages.emojis["eximiabots"].replace(/[^0-9]+/g, '') }); if(!radio.message){ @@ -39,10 +41,10 @@ module.exports = { await radio.message?.delete(); }, 5000); - client.radio.delete(interaction.guild.id); + client.radio?.delete(interaction.guild?.id); interaction.reply({ - content: client.messageEmojis["stop"] + client.messages.stop, + content: client.messages.emojis["stop"] + client.messages.stop, ephemeral: true }); } diff --git a/src/client/emojis.js b/src/client/emojis.js deleted file mode 100644 index 61af51a..0000000 --- a/src/client/emojis.js +++ /dev/null @@ -1,42 +0,0 @@ -module.exports = { - name: 'emojis', - async execute(client) { - let customEmojis = { - logo: "<:RadioX:688765708808487072>", - eximiabots: "<:EximiaBots:693277919929303132>", - list: "<:RadioXList:688541155519889482>", - play: "<:RadioXPlay:688541155712827458>", - stop: "<:RadioXStop:688541155377414168>", - statistics: "<:RadioXStatistics:694954485507686421>", - maintenance: "<:RadioXMaintenance:695043843057254493>", - error: "<:RadioXError:688541155792781320>", - prev: "<:RadioXPrev:882153637370023957>", - next: "<:RadioXNext:882153637474893834>" - }; - - let fallbackEmojis = { - logo: "RadioX", - eximiabots: "EximiaBots", - list: "📜", - play: "▶️", - stop: "⏹️", - statistics: "📊", - maintenance: "🛠️", - error: "❌", - prev: "⏪", - next: "⏩" - }; - - client.messageEmojis = {}; - - for (const customEmojiName in customEmojis) { - const customEmojiID = customEmojis[customEmojiName].replace(/[^0-9]+/g, ''); - const customEmoji = client.emojis.cache.get(customEmojiID); - if (customEmoji) { - client.messageEmojis[customEmojiName] = customEmojis[customEmojiName]; - } else { - client.messageEmojis[customEmojiName] = fallbackEmojis[customEmojiName]; - } - } - } -} diff --git a/src/client/events.ts b/src/client/events.ts new file mode 100644 index 0000000..9da068b --- /dev/null +++ b/src/client/events.ts @@ -0,0 +1,53 @@ +import RadioClient from "../Client" +import interactionCreate from "./events/interactionCreate" +import messageDelete from "./events/messageDelete" +import ready from "./events/ready" +import SIGINT from "./events/SIGINT" +import SIGTERM from "./events/SIGTERM" +import uncaughtException from "./events/uncaughtException" +import voiceStateUpdate from "./events/voiceStateUpdate" +import warning from "./events/warning" + +export default function events(client: RadioClient) { + client.on("ready", () => { + ready(client); + }); + + client.on("messageDelete", msg => { + messageDelete(client, msg); + }); + + client.on("interactionCreate", interaction => { + interactionCreate(client, interaction); + }); + + client.on("voiceStateUpdate", (oldState, newState) => { + voiceStateUpdate(client, oldState, newState); + }); + + client.on("error", error => { + client.funcs.logger("Discord Client", "Error"); + console.error(error); + console.log(''); + }); + + process.on('SIGINT', () => { + SIGINT(client); + }); + + process.on('SIGTERM', () => { + SIGTERM(client); + }); + + process.on('uncaughtException', (error) => { + uncaughtException(client, error); + }); + + process.on('exit', () => { + client.funcs.logger("Bot", "Stopping"); + }); + + process.on('warning', (error) => { + warning(client, error); + }); +} diff --git a/src/client/events/SIGINT.js b/src/client/events/SIGINT.js deleted file mode 100644 index b7f11f1..0000000 --- a/src/client/events/SIGINT.js +++ /dev/null @@ -1,15 +0,0 @@ -module.exports = { - name: 'SIGINT', - execute(client) { - client.user.setStatus('dnd'); - - client.streamer.leave(client); - client.radio.save(client); - - setInterval(() => { - if(client.radio.size == 0){ - process.exit(); - } - }, 500); - } -} diff --git a/src/client/events/SIGINT.ts b/src/client/events/SIGINT.ts new file mode 100644 index 0000000..307ce12 --- /dev/null +++ b/src/client/events/SIGINT.ts @@ -0,0 +1,14 @@ +import RadioClient from "../../Client"; + +export default function SIGINT(client: RadioClient) { + client.user?.setStatus('dnd'); + + client.streamer?.leave(client); + client.radio?.save(client); + + setInterval(() => { + if(client.radio?.size == 0){ + process.exit(); + } + }, 500); +} diff --git a/src/client/events/SIGTERM.js b/src/client/events/SIGTERM.js deleted file mode 100644 index 62c4830..0000000 --- a/src/client/events/SIGTERM.js +++ /dev/null @@ -1,6 +0,0 @@ -module.exports = { - name: 'SIGTERM', - execute(client) { - process.emit('SIGINT'); - } -} diff --git a/src/client/events/SIGTERM.ts b/src/client/events/SIGTERM.ts new file mode 100644 index 0000000..c0e492d --- /dev/null +++ b/src/client/events/SIGTERM.ts @@ -0,0 +1,5 @@ +import RadioClient from "../../Client"; + +export default function SIGTERM(client: RadioClient) { + process.emit('SIGINT'); +} diff --git a/src/client/events/interactionCreate.js b/src/client/events/interactionCreate.js deleted file mode 100644 index b368e5f..0000000 --- a/src/client/events/interactionCreate.js +++ /dev/null @@ -1,45 +0,0 @@ -import { PermissionFlagsBits } from "discord.js"; - -module.exports = { - name: 'interactionCreate', - async execute(client, interaction) { - - const permissions = interaction.channel.permissionsFor(interaction.client.user); - if (!permissions.has(PermissionFlagsBits.ViewChannel)) return; - - if (!permissions.has(PermissionFlagsBits.EmbedLinks)) return interaction.reply({ - content: client.messageEmojis["error"] + client.messages.noPermsEmbed, - ephemeral: true - }); - - if(interaction.isChatInputCommand()){ - const commandName = interaction.commandName; - const command = client.commands.get(commandName); - if (!command) return; - - try { - command.execute(interaction, client); - } catch (error) { - interaction.reply({ - content: client.messageEmojis["error"] + client.messages.runningCommandFailed, - ephemeral: true - }); - console.error(error); - } - } else if (interaction.isStringSelectMenu() || interaction.isButton()){ - const commandName = interaction.customId; - const command = client.commands.get(commandName); - if (!command) return; - - try { - command.execute(interaction, client, command); - } catch (error) { - interaction.reply({ - content: client.messageEmojis["error"] + client.messages.runningCommandFailed, - ephemeral: true - }); - console.error(error); - } - } - } -} diff --git a/src/client/events/interactionCreate.ts b/src/client/events/interactionCreate.ts new file mode 100644 index 0000000..8a5986d --- /dev/null +++ b/src/client/events/interactionCreate.ts @@ -0,0 +1,46 @@ +import { ChannelType, Interaction, PermissionFlagsBits } from "discord.js"; +import RadioClient from "../../Client"; + +export default function interactionCreate(client: RadioClient, interaction: Interaction) { + if(!(interaction.isButton()) && !(interaction.isChatInputCommand()) && !(interaction.isStringSelectMenu())) return; + + if(interaction.channel?.type != ChannelType.DM){ + const permissions = interaction.channel?.permissionsFor(interaction.client.user); + if (!permissions?.has(PermissionFlagsBits.ViewChannel)) return; + + if (!permissions?.has(PermissionFlagsBits.EmbedLinks)) return interaction.reply({ + content: client.messages.emojis["error"] + client.messages.noPermsEmbed, + ephemeral: true + }); + } + + if(interaction.isChatInputCommand()){ + const commandName = interaction.commandName; + const command = client.commands.get(commandName); + if (!command) return; + + try { + command.execute(interaction, client); + } catch (error) { + interaction.reply({ + content: client.messages.emojis["error"] + client.messages.runningCommandFailed, + ephemeral: true + }); + console.error(error); + } + } else if (interaction.isStringSelectMenu() || interaction.isButton()){ + const commandName = interaction.customId; + const command = client.commands.get(commandName); + if (!command) return; + + try { + command.execute(interaction, client, command); + } catch (error) { + interaction.reply({ + content: client.messages.emojis["error"] + client.messages.runningCommandFailed, + ephemeral: true + }); + console.error(error); + } + } +} diff --git a/src/client/events/messageCreate.js b/src/client/events/messageCreate.js deleted file mode 100644 index 54459e4..0000000 --- a/src/client/events/messageCreate.js +++ /dev/null @@ -1,62 +0,0 @@ -import { EmbedBuilder, PermissionFlagsBits } from "discord.js"; - -module.exports = { - name: 'messageCreate', - async execute(client, message) { - - if (message.author.bot || !message.guild) return; - let prefix = "rx$"; - if(client.user.username == "RadioX"){ - prefix = "rx>"; - } else if (client.user.username == "RadioX Beta"){ - prefix = "rx-"; - } else if (client.user.username == "RadioX Dev"){ - prefix = "rx$"; - } else if(message.mentions.members.first() && message.mentions.members.first().user.id === client.user.id){ - prefix = "<@!" + client.user.id + "> "; - } else { - return; - } - - const args = message.content.slice(prefix.length).split(' '); - if (!message.content.startsWith(prefix)) return; - if (!args[0]) return; - const commandName = args[0].toLowerCase(); - if (commandName === 'none') return; - const command = client.commands.get(commandName) || client.commands.find(cmd => cmd.aliases && cmd.aliases.includes(commandName)); - if (!command && message.content !== `${prefix}`) return; - const permissions = message.channel.permissionsFor(message.client.user); - if (!permissions.has(PermissionFlagsBits.EmbedLinks)) return message.channel.send(client.messages.noPermsEmbed); - try { - let newMessage = {}; - - newMessage.messageCommandsDeprecatedTitle = client.messages.messageCommandsDeprecatedTitle.replace("%client.user.username%", client.user.username); - - const embed = new EmbedBuilder() - .setTitle(newMessage.messageCommandsDeprecatedTitle) - .setThumbnail("https://cdn.discordapp.com/emojis/" + client.messageEmojis["logo"].replace(/[^0-9]+/g, '')) - .setColor(client.config.embedColor) - .setDescription(client.messages.messageCommandsDeprecatedDescription) - .setImage('https://waren.io/berriabot-temp-sa7a36a9xm6837br/images/empty-3.png') - .setFooter({ - text: client.messages.footerText, - iconURL: "https://cdn.discordapp.com/emojis/" + client.messageEmojis["eximiabots"].replace(/[^0-9]+/g, '') - }); - - let msg = await message.channel.send({ embeds: [embed] }); - - setTimeout(async function() { - try { - await msg.delete(); - } catch (DiscordAPIError) { - } - }, 30000); - } catch (error) { - message.reply({ - content: client.messages.runningCommandFailed, - ephemeral: true - }); - console.error(error); - } - } -} diff --git a/src/client/events/messageDelete.js b/src/client/events/messageDelete.js deleted file mode 100644 index 01d3431..0000000 --- a/src/client/events/messageDelete.js +++ /dev/null @@ -1,11 +0,0 @@ -module.exports = { - name: 'messageDelete', - async execute(client, msg) { - if(!msg.author.bot || !msg.guild) return; - const radio = client.radio.get(msg.guild.id); - if(!radio) return; - if(!radio.message) return; - if(msg.id != radio.message.id) return; - radio.message = null; - } -} diff --git a/src/client/events/messageDelete.ts b/src/client/events/messageDelete.ts new file mode 100644 index 0000000..3efbbfd --- /dev/null +++ b/src/client/events/messageDelete.ts @@ -0,0 +1,11 @@ +import { Message, PartialMessage } from "discord.js"; +import RadioClient from "../../Client"; + +export default function messageDelete(client: RadioClient, msg: Message | PartialMessage){ + if(!msg.author?.bot || !msg.guild) return; + const radio = client.radio?.get(msg.guild.id); + if(!radio) return; + if(!radio.message) return; + if(msg.id != radio.message.id) return; + radio.message = null; +} diff --git a/src/client/events/ready.js b/src/client/events/ready.js deleted file mode 100644 index 1b58d91..0000000 --- a/src/client/events/ready.js +++ /dev/null @@ -1,95 +0,0 @@ -import Datastore from "../classes/Datastore.js"; -import Radio from "../classes/Radio.js"; -import Stations from "../classes/Stations.js"; -import Streamer from "../classes/Streamer.js"; -import Statistics from "../classes/Statistics.js"; - -module.exports = { - name: 'ready', - async execute(client) { - - client.funcs.logger("Bot", "Ready"); - - /*DATASTORE*/ - client.funcs.logger('Datastore', 'Initialize'); - client.datastore = new Datastore(); - - client.datastore.map.forEach(datastore => { - client.funcs.logger('Datastore', datastore.guild.id + " / " + datastore.guild.name); - }); - - client.funcs.logger('Datastore', 'Ready'); - - /*DEVELOPERS*/ - client.developers = ""; - let user = ""; - for (let i = 0; i < client.config.devId.length; i++) { - user = await client.users.fetch(client.config.devId[i]); - client.funcs.logger('Developers', user.tag); - if (i == client.config.devId.length - 1) { - client.developers += user.tag; - } else { - client.developers += user.tag + " & "; - } - } - - /*STATIONS*/ - client.stations = new Stations(); - - await client.stations.fetch({ - url: client.config.stationslistUrl, - show: true - }); - - /*setInterval(async () => { - await client.stations.fetch({ - url: client.config.stationslistUrl, - show: false - }); - }, 3600000);*/ - - client.streamer = new Streamer(); - client.streamer.init(client); - - if(!client.stations) { - client.user.setStatus('dnd'); - } - - /*GUILDS*/ - client.funcs.logger('Guilds', 'Started fetching list'); - - let guilds = await client.guilds.fetch(); - guilds.forEach(guild => { - client.funcs.logger('Guilds', guild.id + " / " + guild.name); - }); - - client.funcs.logger('Guilds', 'Successfully fetched list'); - - /*STATISTICS*/ - client.statistics = new Statistics(); - client.statistics.calculateGlobal(client); - - /*EMOJIS*/ - require(`../emojis.js`).execute(client); - - /*COMMANDS*/ - require(`../commands.js`).execute(client); - - /*RADIO*/ - client.radio = new Radio(); - - setTimeout(function () { - /*RESTORE RADIOS*/ - client.radio.restore(client, guilds); - }, 5000); - - setTimeout(function () { - if(client.stations) { - /*MAINTENANCE MODE*/ - client.funcs.logger("Maintenance Mode", "Disabled"); - client.config.maintenanceMode = false; - } - }, 10000); - - } -} diff --git a/src/client/events/ready.ts b/src/client/events/ready.ts new file mode 100644 index 0000000..3defdb1 --- /dev/null +++ b/src/client/events/ready.ts @@ -0,0 +1,77 @@ +import RadioClient from "../../Client"; +import Datastore, { datastore } from "../classes/Datastore"; +import Radio from "../classes/Radio"; +import Stations from "../classes/Stations"; +import Streamer from "../classes/Streamer"; +import Statistics from "../classes/Statistics"; +import commands from "../commands"; +import { OAuth2Guild } from "discord.js"; + +export default async function ready(client: RadioClient) { + client.funcs.logger("Bot", "Ready"); + + /*DATASTORE*/ + client.funcs.logger('Datastore', 'Initialize'); + client.datastore = new Datastore(); + + client.datastore.map.forEach((datastore: datastore) => { + client.funcs.logger('Datastore', datastore.guild.id + " / " + datastore.guild.name); + }); + + client.funcs.logger('Datastore', 'Ready'); + + /*DEVELOPERS*/ + let developers : string[] = []; + for(let devID of client.config.devIDs){ + developers.push((await client.users.fetch(devID)).tag); + } + client.funcs.logger('Developers', developers.join(" & ")); + + /*STATIONS*/ + client.stations = new Stations(); + + await client.stations.fetch({ + url: client.config.stationslistUrl, + show: true + }); + + client.streamer = new Streamer(); + client.streamer.init(client); + + if(!client.stations) { + client.user?.setStatus('dnd'); + } + + /*GUILDS*/ + client.funcs.logger('Guilds', 'Started fetching list'); + + let guilds = await client.guilds.fetch(); + guilds.forEach((guild: OAuth2Guild) => { + client.funcs.logger('Guilds', guild.id + " / " + guild.name); + }); + + client.funcs.logger('Guilds', 'Successfully fetched list'); + + /*STATISTICS*/ + client.statistics = new Statistics(); + client.statistics.calculateGlobal(client); + + /*COMMANDS*/ + commands(client); + + /*RADIO*/ + client.radio = new Radio(); + + setTimeout(function () { + /*RESTORE RADIOS*/ + client.radio?.restore(client, guilds); + }, 5000); + + setTimeout(function () { + if(client.stations) { + /*MAINTENANCE MODE*/ + client.funcs.logger("Maintenance Mode", "Disabled"); + client.config.maintenanceMode = false; + } + }, 10000); +} diff --git a/src/client/events/uncaughtException.js b/src/client/events/uncaughtException.js deleted file mode 100644 index e3c27e2..0000000 --- a/src/client/events/uncaughtException.js +++ /dev/null @@ -1,11 +0,0 @@ -module.exports = { - name: 'uncaughtException', - execute(client, error) { - client.funcs.logger("Error"); - console.log(error.stack); - console.log(''); - - if(error.name == "DiscordAPIError" && error.message == "Unknown interaction") return; - process.emit('SIGINT'); - } -} diff --git a/src/client/events/uncaughtException.ts b/src/client/events/uncaughtException.ts new file mode 100644 index 0000000..b0d8536 --- /dev/null +++ b/src/client/events/uncaughtException.ts @@ -0,0 +1,10 @@ +import RadioClient from "../../Client"; + +export default function uncaughtException(client: RadioClient, error: Error) { + client.funcs.logger("Error"); + console.log(error.stack); + console.log(''); + + if(error.name == "DiscordAPIError" && error.message == "Unknown interaction") return; + process.emit('SIGINT'); +} diff --git a/src/client/events/voiceStateUpdate.js b/src/client/events/voiceStateUpdate.js deleted file mode 100644 index 09d7dc4..0000000 --- a/src/client/events/voiceStateUpdate.js +++ /dev/null @@ -1,68 +0,0 @@ -import { PermissionFlagsBits } from "discord.js"; -const { - getVoiceConnection, - joinVoiceChannel -} = require("@discordjs/voice"); - -module.exports = { - name: "voiceStateUpdate", - async execute(client, oldState, newState) { - if (oldState.channel === null) return; - let change = false; - const radio = client.radio?.get(newState.guild.id); - if (!radio) return; - - if (newState.member.id === client.user.id && oldState.member.id === client.user.id) { - - if (newState.channel === null) { - client.statistics.update(client, newState.guild, radio); - radio.connection?.destroy(); - radio.message?.delete(); - client.funcs.logger('Radio', newState.guild.id + " / " + 'Stop'); - return client.radio.delete(newState.guild.id); - } - - const newPermissions = newState.channel.permissionsFor(newState.client.user); - if (!newPermissions.has(PermissionFlagsBits.Connect) || !newPermissions.has(PermissionFlagsBits.Speak) || !newPermissions.has(PermissionFlagsBits.ViewChannel)) { - try { - setTimeout( - async () => ( - radio.connection = joinVoiceChannel({ - channelId: oldState.channel.id, - guildId: oldState.channel.guild.id, - adapterCreator: oldState.channel.guild.voiceAdapterCreator - }) - //radio.connection = await oldState.channel.join() - ), - 1000 - ); - } catch (error) { - client.statistics.update(client, newState.guild, radio); - radio.connection?.destroy(); - radio.message?.delete(); - client.funcs.logger('Radio', newState.guild.id + " / " + 'Stop'); - client.radio.delete(oldState.guild.id); - } - return; - } - if (newState.channel !== radio.voiceChannel) { - change = true; - radio.voiceChannel = newState.channel; - radio.connection = getVoiceConnection(newState.channel.guild.id); - //radio.connection = await newState.channel.join(); - } - } - if ((oldState.channel.members.filter(member => !member.user.bot).size === 0 && oldState.channel === radio.voiceChannel) || change) { - setTimeout(() => { - if (!radio || !radio.connection || !radio.connection === null) return; - if (radio.voiceChannel.members.filter(member => !member.user.bot).size === 0) { - client.statistics.update(client, newState.guild, radio); - radio.connection?.destroy(); - radio.message?.delete(); - client.funcs.logger('Radio', newState.guild.id + " / " + 'Stop'); - client.radio.delete(newState.guild.id); - } - }, 5000); - } - }, -}; diff --git a/src/client/events/voiceStateUpdate.ts b/src/client/events/voiceStateUpdate.ts new file mode 100644 index 0000000..8caad08 --- /dev/null +++ b/src/client/events/voiceStateUpdate.ts @@ -0,0 +1,65 @@ +import { GuildMember, PermissionFlagsBits, VoiceState } from "discord.js"; +import RadioClient from "../../Client"; +const { + getVoiceConnection, + joinVoiceChannel +} = require("@discordjs/voice"); + +export default async function voiceStateUpdate(client: RadioClient, oldState: VoiceState, newState: VoiceState) { + if (oldState.channel === null) return; + let change = false; + const radio = client.radio?.get(newState.guild.id); + if (!radio) return; + + if (newState.member?.id === client.user?.id && oldState.member?.id === client.user?.id) { + + if (newState.channel === null) { + client.statistics?.update(client, newState.guild, radio); + radio.connection?.destroy(); + radio.message?.delete(); + client.funcs.logger('Radio', newState.guild.id + " / " + 'Stop'); + return client.radio?.delete(newState.guild.id); + } + + const newPermissions = newState.channel.permissionsFor(newState.client.user); + if (!newPermissions?.has(PermissionFlagsBits.Connect) || !newPermissions?.has(PermissionFlagsBits.Speak) || !newPermissions?.has(PermissionFlagsBits.ViewChannel)) { + try { + setTimeout( + async () => ( + radio.connection = joinVoiceChannel({ + channelId: oldState.channel?.id, + guildId: oldState.channel?.guild.id, + adapterCreator: oldState.channel?.guild.voiceAdapterCreator + }) + ), + 1000 + ); + } catch (error) { + client.statistics?.update(client, newState.guild, radio); + radio.connection?.destroy(); + radio.message?.delete(); + client.funcs.logger('Radio', newState.guild.id + " / " + 'Stop'); + client.radio?.delete(oldState.guild.id); + } + return; + } + if (newState.channel !== radio.voiceChannel) { + change = true; + radio.voiceChannel = newState.channel; + radio.connection = getVoiceConnection(newState.channel.guild.id); + + } + } + if ((oldState.channel.members.filter(member => !member.user.bot).size === 0 && oldState.channel === radio.voiceChannel) || change) { + setTimeout(() => { + if (!radio || !radio.connection || !radio.connection === null) return; + if (radio.voiceChannel.members.filter((member: GuildMember) => !member.user.bot).size === 0) { + client.statistics?.update(client, newState.guild, radio); + radio.connection?.destroy(); + radio.message?.delete(); + client.funcs.logger('Radio', newState.guild.id + " / " + 'Stop'); + client.radio?.delete(newState.guild.id); + } + }, 5000); + } +}; diff --git a/src/client/events/warning.js b/src/client/events/warning.js deleted file mode 100644 index 537c089..0000000 --- a/src/client/events/warning.js +++ /dev/null @@ -1,12 +0,0 @@ -module.exports = { - name: 'warning', - execute(client, warning) { - if(warning.name == "ExperimentalWarning" && warning.message.startsWith("stream/web")) return; - - client.funcs.logger("Warning"); - console.warn(warning.name); - console.warn(warning.message); - console.warn(warning.stack); - console.log(''); - } -} diff --git a/src/client/events/warning.ts b/src/client/events/warning.ts new file mode 100644 index 0000000..431cf03 --- /dev/null +++ b/src/client/events/warning.ts @@ -0,0 +1,11 @@ +import RadioClient from "../../Client"; + +export default function warning(client: RadioClient, warning: Error) { + if(warning.name == "ExperimentalWarning" && warning.message.startsWith("stream/web")) return; + + client.funcs.logger("Warning"); + console.warn(warning.name); + console.warn(warning.message); + console.warn(warning.stack); + console.log(''); +} diff --git a/src/client/funcs.ts b/src/client/funcs.ts new file mode 100644 index 0000000..259d2bc --- /dev/null +++ b/src/client/funcs.ts @@ -0,0 +1,12 @@ +import check from "./funcs/check"; +import isDev from "./funcs/isDev"; +import listStations from "./funcs/listStations"; +import loadState from "./funcs/loadState"; +import logger from "./funcs/logger"; +import msToTime from "./funcs/msToTime"; +import play from "./funcs/play"; +import saveState from "./funcs/saveState"; + +export const funcs = { + check, isDev, listStations, loadState, logger, msToTime, play, saveState +} diff --git a/src/client/funcs/check.js b/src/client/funcs/check.js deleted file mode 100644 index 8a7c153..0000000 --- a/src/client/funcs/check.js +++ /dev/null @@ -1,35 +0,0 @@ -module.exports = function check(client, interaction, command) { - let message = {}; - const radio = client.radio.get(interaction.guild.id); - if(client.config.maintenanceMode){ - interaction.reply({ - content: client.messageEmojis["error"] + client.messages.maintenance, - ephemeral: true - }); - return false; - } - if(!client.stations) { - message.errorToGetPlaylist = client.messages.errorToGetPlaylist.replace("%client.config.supportGuild%", client.config.supportGuild); - interaction.reply({ - content: client.messageEmojis["error"] + message.errorToGetPlaylist, - ephemeral: true - }); - return false; - } - if (!radio) { - interaction.reply({ - content: client.messageEmojis["error"] + client.messages.notPlaying, - ephemeral: true - }); - return false; - } - if (interaction.member.voice.channel !== radio.voiceChannel) { - interaction.reply({ - content: client.messageEmojis["error"] + client.messages.wrongVoiceChannel, - ephemeral: true - }); - return false; - } - - return true; -}; diff --git a/src/client/funcs/check.ts b/src/client/funcs/check.ts new file mode 100644 index 0000000..63b6252 --- /dev/null +++ b/src/client/funcs/check.ts @@ -0,0 +1,34 @@ +import { ButtonInteraction, ChatInputCommandInteraction, GuildMember, StringSelectMenuInteraction } from "discord.js"; +import RadioClient from "../../Client"; +import { command } from "../commands"; + +export default function check(client: RadioClient, interaction: ButtonInteraction | ChatInputCommandInteraction | StringSelectMenuInteraction, command: command) { + + const radio = client.radio?.get(interaction.guild?.id); + if(!client.stations) { + interaction.reply({ + content: client.messages.emojis["error"] + client.messages.replace(client.messages.errorToGetPlaylist, { + "%client.config.supportGuild%": client.config.supportGuild + }), + ephemeral: true + }); + return false; + } + if (!radio) { + interaction.reply({ + content: client.messages.emojis["error"] + client.messages.notPlaying, + ephemeral: true + }); + return false; + } + + if (interaction.member instanceof GuildMember && interaction.member?.voice.channel !== radio.voiceChannel) { + interaction.reply({ + content: client.messages.emojis["error"] + client.messages.wrongVoiceChannel, + ephemeral: true + }); + return false; + } + + return true; +}; diff --git a/src/client/funcs/isDev.js b/src/client/funcs/isDev.js deleted file mode 100644 index 8be3ac9..0000000 --- a/src/client/funcs/isDev.js +++ /dev/null @@ -1,10 +0,0 @@ -module.exports = function isDev(devList, authorID){ - let response = false; - Object.keys(devList).forEach(function(oneDev) { - let devID = devList[oneDev]; - if(authorID == devID){ - response = true; - } - }); - return response; -} diff --git a/src/client/funcs/isDev.ts b/src/client/funcs/isDev.ts new file mode 100644 index 0000000..b74e906 --- /dev/null +++ b/src/client/funcs/isDev.ts @@ -0,0 +1,9 @@ +import { Snowflake } from "discord.js"; + +export default function isDev(devIDs : string[], authorID : Snowflake){ + for (const devID of devIDs){ + if(authorID == devID){ + return true; + } + } +} diff --git a/src/client/funcs/listStations.js b/src/client/funcs/listStations.js deleted file mode 100644 index 94a5e94..0000000 --- a/src/client/funcs/listStations.js +++ /dev/null @@ -1,33 +0,0 @@ -import { ActionRowBuilder, StringSelectMenuBuilder } from "discord.js"; - -module.exports = function listStations(client, interaction){ - let stations = new Array(); - let options = new Array(); - - stations = client.stations.forEach(station => { - if(station.name == "GrooveFM") return; - station = { - label: station.name, - description: station.owner, - value: station.name - }; - options.push(station); - }); - - const menu = new ActionRowBuilder() - .addComponents( - new StringSelectMenuBuilder() - .setCustomId('play') - .setPlaceholder('Nothing selected') - .addOptions(options) - ); - - stations = null; - options = null; - - return interaction.reply({ - content: '**Select station:**', - components: [menu], - ephemeral: true - }); -} diff --git a/src/client/funcs/listStations.ts b/src/client/funcs/listStations.ts new file mode 100644 index 0000000..96349a6 --- /dev/null +++ b/src/client/funcs/listStations.ts @@ -0,0 +1,30 @@ +import { ActionRowBuilder, ButtonInteraction, ChatInputCommandInteraction, SelectMenuComponentOptionData, StringSelectMenuBuilder, StringSelectMenuInteraction } from "discord.js"; +import RadioClient from "../../Client"; + +export default function listStations(client: RadioClient, interaction: ButtonInteraction | ChatInputCommandInteraction | StringSelectMenuInteraction){ + if(!client.stations) return; + + let options : SelectMenuComponentOptionData[] = new Array(); + + for (const station of client.stations){ + options.push({ + label: station.name, + description: station.owner, + value: station.name + }); + } + + const menu = new ActionRowBuilder() + .addComponents( + new StringSelectMenuBuilder() + .setCustomId('play') + .setPlaceholder('Nothing selected') + .addOptions(options) + ); + + return interaction.reply({ + content: '**Select station:**', + components: [menu], + ephemeral: true + }); +} diff --git a/src/client/funcs/loadState.js b/src/client/funcs/loadState.js deleted file mode 100644 index d56c275..0000000 --- a/src/client/funcs/loadState.js +++ /dev/null @@ -1,12 +0,0 @@ -module.exports = function loadState(client, guild){ - let data = client.datastore.getEntry(guild.id); - if(!data) return; - let state; - - state = data.state; - if(!state) return; - - data.state = {}; - client.datastore.updateEntry(guild, data); - return state; -} diff --git a/src/client/funcs/loadState.ts b/src/client/funcs/loadState.ts new file mode 100644 index 0000000..67f4ffa --- /dev/null +++ b/src/client/funcs/loadState.ts @@ -0,0 +1,13 @@ +import { OAuth2Guild } from "discord.js"; +import RadioClient from "../../Client"; + +export default function loadState(client: RadioClient, guild: OAuth2Guild) { + if(!client.datastore) return; + let data = client.datastore.getEntry(guild.id); + if(!data) return; + let state = data.state; + if(!state) return; + data.state = null; + client.datastore.updateEntry(guild, data); + return state; +} diff --git a/src/client/funcs/logger.js b/src/client/funcs/logger.js deleted file mode 100644 index ec39d1a..0000000 --- a/src/client/funcs/logger.js +++ /dev/null @@ -1,5 +0,0 @@ -module.exports = function logger(area, text){ - let date = new Date(); - console.log('[' + area + '] – ' + date.toISOString()); - if(text) console.log(text + '\n'); -} diff --git a/src/client/funcs/logger.ts b/src/client/funcs/logger.ts new file mode 100644 index 0000000..5279de4 --- /dev/null +++ b/src/client/funcs/logger.ts @@ -0,0 +1,5 @@ +export default function logger(area: string, text?: string){ + let date = new Date(); + console.log('[' + area + '] - ' + date.toISOString()); + if(text) console.log(text + '\n'); +} diff --git a/src/client/funcs/msToTime.js b/src/client/funcs/msToTime.ts similarity index 92% rename from src/client/funcs/msToTime.js rename to src/client/funcs/msToTime.ts index 07fdb9a..fdb10b9 100644 --- a/src/client/funcs/msToTime.js +++ b/src/client/funcs/msToTime.ts @@ -1,4 +1,4 @@ -module.exports = function msToTime(duration) { +export default function msToTime(duration : number) { let seconds = Math.floor((duration / 1000) % 60), minutes = Math.floor((duration / (1000 * 60)) % 60), hours = Math.floor((duration / (1000 * 60 * 60)) % 24), diff --git a/src/client/funcs/play.js b/src/client/funcs/play.ts similarity index 52% rename from src/client/funcs/play.js rename to src/client/funcs/play.ts index 83fc28a..ca062d3 100644 --- a/src/client/funcs/play.js +++ b/src/client/funcs/play.ts @@ -1,61 +1,64 @@ -import { ActionRowBuilder, ButtonBuilder, ButtonStyle, EmbedBuilder } from "discord.js"; +import { ActionRowBuilder, ButtonBuilder, ButtonStyle, ChatInputCommandInteraction, EmbedBuilder, Guild, OAuth2Guild, StringSelectMenuInteraction } from "discord.js"; +import RadioClient from "../../Client"; +import { station } from "../classes/Stations"; -module.exports = async function play(client, interaction, guild, station) { - let message = {}; - const radio = client.radio.get(guild.id); - const audioPlayer = client.streamer.listen(station); +export default async function play(client: RadioClient, interaction: ChatInputCommandInteraction | StringSelectMenuInteraction | null, guild: OAuth2Guild | Guild | null, station: station) { + if(!guild) return; + + const radio = client.radio?.get(guild.id); + const audioPlayer = client.streamer?.listen(station); radio.connection.subscribe(audioPlayer); client.funcs.logger('Radio', guild.id + " / " + "Play" + " / " + radio.station.name); - message.nowplayingDescription = client.messages.nowplayingDescription.replace("%radio.station.name%", radio.station.name); - message.nowplayingDescription = message.nowplayingDescription.replace("%radio.station.owner%", radio.station.name != radio.station.owner ? radio.station.owner + "\n" : ""); - message.nowplayingDescription = message.nowplayingDescription.replace("%client.funcs.msToTime(completed)%", ""); - message.nowplayingDescription = message.nowplayingDescription.replace("**", ""); - message.nowplayingDescription = message.nowplayingDescription.replace("**", ""); - const embed = new EmbedBuilder() - .setTitle(client.user.username) - .setThumbnail((radio.station.logo || "https://cdn.discordapp.com/emojis/" + client.messageEmojis["play"].replace(/[^0-9]+/g, ''))) + .setTitle(client.user?.username || "-") + .setThumbnail((radio.station.logo || "https://cdn.discordapp.com/emojis/" + client.messages.emojis["play"].replace(/[^0-9]+/g, ''))) .setColor(client.config.embedColor) .addFields({ name: client.messages.nowplayingTitle, - value: message.nowplayingDescription + value: client.messages.replace(client.messages.nowplayingDescription, { + "%radio.station.name%": radio.station.name, + "%radio.station.owner%\n": radio.station.name != radio.station.owner ? radio.station.owner + "\n" : "", + "%client.funcs.msToTime(completed)%": "", + "**": "", + "**:2": "" + }) }) .setImage('https://waren.io/berriabot-temp-sa7a36a9xm6837br/images/empty-3.png') .setFooter({ text: client.messages.footerText, - iconURL: "https://cdn.discordapp.com/emojis/" + client.messageEmojis["eximiabots"].replace(/[^0-9]+/g, '') + iconURL: "https://cdn.discordapp.com/emojis/" + client.messages.emojis["eximiabots"].replace(/[^0-9]+/g, '') }); - const buttons = new ActionRowBuilder() + const buttons = new ActionRowBuilder() .addComponents( new ButtonBuilder() .setCustomId('list') - .setEmoji(client.messageEmojis["list"]) + .setEmoji(client.messages.emojis["list"]) .setStyle(ButtonStyle.Secondary) ) .addComponents( new ButtonBuilder() .setCustomId('prev') - .setEmoji(client.messageEmojis["prev"]) + .setEmoji(client.messages.emojis["prev"]) .setStyle(ButtonStyle.Secondary) ) .addComponents( new ButtonBuilder() .setCustomId('stop') - .setEmoji(client.messageEmojis["stop"]) + .setEmoji(client.messages.emojis["stop"]) .setStyle(ButtonStyle.Secondary) ) .addComponents( new ButtonBuilder() .setCustomId('next') - .setEmoji(client.messageEmojis["next"]) + .setEmoji(client.messages.emojis["next"]) .setStyle(ButtonStyle.Secondary) ) .addComponents( new ButtonBuilder() .setCustomId('statistics') - .setEmoji(client.messageEmojis["statistics"]) + .setEmoji(client.messages.emojis["statistics"]) .setStyle(ButtonStyle.Secondary) ); @@ -70,10 +73,10 @@ module.exports = async function play(client, interaction, guild, station) { } } - message.play = client.messages.play.replace("%radio.station.name%", radio.station.name); - interaction?.reply({ - content: client.messageEmojis["play"] + message.play, + content: client.messages.emojis["play"] + client.messages.replace(client.messages.play, { + "%radio.station.name%": radio.station.name + }), ephemeral: true }); diff --git a/src/client/funcs/saveState.js b/src/client/funcs/saveState.js deleted file mode 100644 index 6ef476a..0000000 --- a/src/client/funcs/saveState.js +++ /dev/null @@ -1,18 +0,0 @@ -module.exports = function saveState(client, guild, radio){ - client.datastore.checkEntry(guild.id); - - let date = new Date(); - - let data = client.datastore.getEntry(guild.id); - - data.state = {}; - data.state.channels = {}; - data.state.channels.text = radio.textChannel.id; - data.state.channels.voice = radio.voiceChannel.id; - data.state.date = date.toISOString(); - data.state.station = {}; - data.state.station.name = radio.station.name; - data.state.station.owner = radio.station.owner; - - client.datastore.updateEntry(guild, data); -} diff --git a/src/client/funcs/saveState.ts b/src/client/funcs/saveState.ts new file mode 100644 index 0000000..63a6dd5 --- /dev/null +++ b/src/client/funcs/saveState.ts @@ -0,0 +1,26 @@ +import { Guild } from "discord.js"; +import RadioClient from "../../Client"; +import { radio } from "../classes/Radio"; + +export default function saveState(client: RadioClient, guild: Guild, radio: radio){ + if(!client.datastore) return; + client.datastore.checkEntry(guild.id); + + let date = new Date(); + + let data = client.datastore.getEntry(guild.id); + if(!data) return; + data.state = { + channels: { + text: radio.textChannel?.id, + voice: radio.voiceChannel?.id + }, + date: date.toISOString(), + station: { + name: radio.station.name, + owner: radio.station.owner + } + }; + + client.datastore.updateEntry(guild, data); +} diff --git a/src/client/messages.js b/src/client/messages.ts similarity index 66% rename from src/client/messages.js rename to src/client/messages.ts index b50f160..be0d000 100644 --- a/src/client/messages.js +++ b/src/client/messages.ts @@ -1,4 +1,16 @@ -module.exports = { +export const messages = { + replace(message: string, variables: { [key: string]: string }){ + for(let variable in variables){ + if(variable.includes('%')){ + message = message.replace(variable, variables[variable]); + } else if(variable.includes(':')){ + message = message.replace(variable.split(':')[0], variables[variable]); + } else { + message = message.replace(variable, variables[variable]); + } + } + return message; + }, wrongVoiceChannel: "You need to be in the same voice channel as RadioX to use this command!", noPerms: "You need the %command.permission% permission to use this command!", notPlaying: "There is nothing playing!", @@ -35,7 +47,17 @@ module.exports = { statusField4: ":hourglass: Latency", statusField5: ":globe_with_meridians: Hosted by", errorStationURL: "Station can't be URL", - messageCommandsDeprecatedTitle: "%client.user.username%", - messageCommandsDeprecatedDescription: "We recommend you to reauthorize our bot by clicking the invite link down below, because Discord is planning to remove message content from verified bots [Read More](https://support-dev.discord.com/hc/en-us/articles/4404772028055)" + "\n\n" + "**Invite Bot**" + "\n" + "https://wgi.fi/radiox_invite" + "\n\n" + "This bot now supports slash commands, you should start using them instead. Type / into the message box and select the bot you wish to use. Remember to be careful as there are a few bugs here and there on Discord." + "\n\n" + "We will remove this deprecation message in March of 2022 when RadioX 1.0.0 is released.", - maintenance: "Shhhh... We are now sleeping and dreaming about new features to implement. Will be back soon." + maintenance: "Shhhh... We are now sleeping and dreaming about new features to implement. Will be back soon.", + emojis: { + logo: "<:RadioX:688765708808487072>", + eximiabots: "<:EximiaBots:693277919929303132>", + list: "<:RadioXList:688541155519889482>", + play: "<:RadioXPlay:688541155712827458>", + stop: "<:RadioXStop:688541155377414168>", + statistics: "<:RadioXStatistics:694954485507686421>", + maintenance: "<:RadioXMaintenance:695043843057254493>", + error: "<:RadioXError:688541155792781320>", + prev: "<:RadioXPrev:882153637370023957>", + next: "<:RadioXNext:882153637474893834>" + } }; diff --git a/src/client/utils/typings.ts b/src/client/utils/typings.ts deleted file mode 100644 index 1e5d860..0000000 --- a/src/client/utils/typings.ts +++ /dev/null @@ -1,3 +0,0 @@ -export interface command { } - -export interface radio {} diff --git a/src/config.js b/src/config.ts similarity index 70% rename from src/config.js rename to src/config.ts index 668ae51..59df496 100644 --- a/src/config.js +++ b/src/config.ts @@ -1,6 +1,6 @@ -require('dotenv/config'); +import { ColorResolvable } from "discord.js"; -module.exports = { +export default { //credentials token: process.env.DISCORD_TOKEN, @@ -10,17 +10,17 @@ module.exports = { //support supportGuild: "https://discord.gg/rRA65Mn", - devId: [ + devIDs: [ "493174343484833802", "360363051792203779" ], //misc - embedColor: "#88aa00", + embedColor: "#88aa00" as ColorResolvable, hostedBy: "[Warén Group](https://waren.io)", //Settings - version: process.env.DEV_MODE ? process.env.npm_package_version + "-dev" : process.env.npm_package_version, + version: process.env.DEV_MODE ? (process.env.npm_package_version ?? "0.0.0") + "-dev" : process.env.npm_package_version ?? "-", debug: process.env.DEBUG_MODE || false, devMode: process.env.DEV_MODE || false, maintenanceMode: false, diff --git a/src/index.js b/src/index.js deleted file mode 100644 index ef051ed..0000000 --- a/src/index.js +++ /dev/null @@ -1,3 +0,0 @@ -const { default: RadioClient } = require("./Client"); - -const client = new RadioClient(); diff --git a/src/index.ts b/src/index.ts new file mode 100644 index 0000000..87b8477 --- /dev/null +++ b/src/index.ts @@ -0,0 +1,3 @@ +import RadioClient from "./Client"; + +new RadioClient();