Add music module and some fix and ToDos
This commit is contained in:
parent
9a7fbfa58f
commit
bf177e6548
18 changed files with 1244 additions and 17 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -107,7 +107,7 @@ dist
|
||||||
.idea
|
.idea
|
||||||
|
|
||||||
# TypeScript compiled sources
|
# TypeScript compiled sources
|
||||||
*.js
|
build/
|
||||||
|
|
||||||
# Configuration
|
# Configuration
|
||||||
config.json
|
config.json
|
||||||
|
|
579
package-lock.json
generated
579
package-lock.json
generated
|
@ -11,8 +11,12 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@discordjs/builders": "^0.6.0",
|
"@discordjs/builders": "^0.6.0",
|
||||||
"@discordjs/rest": "^0.1.0-canary.0",
|
"@discordjs/rest": "^0.1.0-canary.0",
|
||||||
|
"@discordjs/voice": "^0.7.5",
|
||||||
"discord-api-types": "^0.23.1",
|
"discord-api-types": "^0.23.1",
|
||||||
"discord.js": "^13.1.0"
|
"discord.js": "^13.1.0",
|
||||||
|
"libsodium-wrappers": "^0.7.9",
|
||||||
|
"youtube-dl-exec": "^2.0.0",
|
||||||
|
"ytdl-core": "^4.9.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"typescript": "^4.5.2"
|
"typescript": "^4.5.2"
|
||||||
|
@ -95,6 +99,59 @@
|
||||||
"node": ">=12"
|
"node": ">=12"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@discordjs/voice": {
|
||||||
|
"version": "0.7.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@discordjs/voice/-/voice-0.7.5.tgz",
|
||||||
|
"integrity": "sha512-lUk+CmIXNKslT6DkC9IF9rpsqhzlTiedauUCPBzepjd4XWxwBZiyVIzR6QpbAirxkAwCoAbbje+3Ho71PGLEAw==",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/ws": "^8.2.0",
|
||||||
|
"discord-api-types": "^0.24.0",
|
||||||
|
"prism-media": "^1.3.2",
|
||||||
|
"tiny-typed-emitter": "^2.1.0",
|
||||||
|
"tslib": "^2.3.1",
|
||||||
|
"ws": "^8.2.3"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=16.0.0",
|
||||||
|
"npm": ">=7.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@discordjs/voice/node_modules/@types/ws": {
|
||||||
|
"version": "8.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.2.0.tgz",
|
||||||
|
"integrity": "sha512-cyeefcUCgJlEk+hk2h3N+MqKKsPViQgF5boi9TTHSK+PoR9KWBb/C5ccPcDyAqgsbAYHTwulch725DV84+pSpg==",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/node": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@discordjs/voice/node_modules/discord-api-types": {
|
||||||
|
"version": "0.24.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.24.0.tgz",
|
||||||
|
"integrity": "sha512-X0uA2a92cRjowUEXpLZIHWl4jiX1NsUpDhcEOpa1/hpO1vkaokgZ8kkPtPih9hHth5UVQ3mHBu/PpB4qjyfJ4A==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@discordjs/voice/node_modules/ws": {
|
||||||
|
"version": "8.2.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/ws/-/ws-8.2.3.tgz",
|
||||||
|
"integrity": "sha512-wBuoj1BDpC6ZQ1B7DWQBYVLphPWkm8i9Y0/3YdHjHKHiohOJ1ws+3OccDWtH+PoC9DZD5WOTrJvNbWvjS6JWaA==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10.0.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"bufferutil": "^4.0.1",
|
||||||
|
"utf-8-validate": "^5.0.2"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"bufferutil": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"utf-8-validate": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@sapphire/async-queue": {
|
"node_modules/@sapphire/async-queue": {
|
||||||
"version": "1.1.4",
|
"version": "1.1.4",
|
||||||
"resolved": "https://registry.npmjs.org/@sapphire/async-queue/-/async-queue-1.1.4.tgz",
|
"resolved": "https://registry.npmjs.org/@sapphire/async-queue/-/async-queue-1.1.4.tgz",
|
||||||
|
@ -173,6 +230,27 @@
|
||||||
"node": ">= 0.8"
|
"node": ">= 0.8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/cross-spawn": {
|
||||||
|
"version": "7.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
|
||||||
|
"integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
|
||||||
|
"dependencies": {
|
||||||
|
"path-key": "^3.1.0",
|
||||||
|
"shebang-command": "^2.0.0",
|
||||||
|
"which": "^2.0.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/dargs": {
|
||||||
|
"version": "7.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/dargs/-/dargs-7.0.0.tgz",
|
||||||
|
"integrity": "sha512-2iy1EkLdlBzQGvbweYRFxmFath8+K7+AKB0TlhHWkNuH+TmovaMH/Wp7V7R4u7f4SnX3OgLsU9t1NI9ioDnUpg==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/delayed-stream": {
|
"node_modules/delayed-stream": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
|
||||||
|
@ -254,6 +332,28 @@
|
||||||
"node": ">=6"
|
"node": ">=6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/execa": {
|
||||||
|
"version": "5.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz",
|
||||||
|
"integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==",
|
||||||
|
"dependencies": {
|
||||||
|
"cross-spawn": "^7.0.3",
|
||||||
|
"get-stream": "^6.0.0",
|
||||||
|
"human-signals": "^2.1.0",
|
||||||
|
"is-stream": "^2.0.0",
|
||||||
|
"merge-stream": "^2.0.0",
|
||||||
|
"npm-run-path": "^4.0.1",
|
||||||
|
"onetime": "^5.1.2",
|
||||||
|
"signal-exit": "^3.0.3",
|
||||||
|
"strip-final-newline": "^2.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sindresorhus/execa?sponsor=1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/form-data": {
|
"node_modules/form-data": {
|
||||||
"version": "4.0.0",
|
"version": "4.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
|
||||||
|
@ -267,6 +367,25 @@
|
||||||
"node": ">= 6"
|
"node": ">= 6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/get-stream": {
|
||||||
|
"version": "6.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz",
|
||||||
|
"integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/human-signals": {
|
||||||
|
"version": "2.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz",
|
||||||
|
"integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10.17.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/is-obj": {
|
"node_modules/is-obj": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz",
|
||||||
|
@ -275,11 +394,65 @@
|
||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/is-stream": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz",
|
||||||
|
"integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/is-unix": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/is-unix/-/is-unix-2.0.1.tgz",
|
||||||
|
"integrity": "sha512-RyKp5JtlRnfOvnKtfBMPLw9ocqDe1NlPQ8Bt+geVzKGfMnLGj8z/Y2HOmk/aMf47P4EbrEt9dN6YGTT1fx4mZA==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/isexe": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
|
||||||
|
"integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA="
|
||||||
|
},
|
||||||
|
"node_modules/libsodium": {
|
||||||
|
"version": "0.7.9",
|
||||||
|
"resolved": "https://registry.npmjs.org/libsodium/-/libsodium-0.7.9.tgz",
|
||||||
|
"integrity": "sha512-gfeADtR4D/CM0oRUviKBViMGXZDgnFdMKMzHsvBdqLBHd9ySi6EtYnmuhHVDDYgYpAO8eU8hEY+F8vIUAPh08A=="
|
||||||
|
},
|
||||||
|
"node_modules/libsodium-wrappers": {
|
||||||
|
"version": "0.7.9",
|
||||||
|
"resolved": "https://registry.npmjs.org/libsodium-wrappers/-/libsodium-wrappers-0.7.9.tgz",
|
||||||
|
"integrity": "sha512-9HaAeBGk1nKTRFRHkt7nzxqCvnkWTjn1pdjKgcUnZxj0FyOP4CnhgFhMdrFfgNsukijBGyBLpP2m2uKT1vuWhQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"libsodium": "^0.7.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/lodash.isequal": {
|
"node_modules/lodash.isequal": {
|
||||||
"version": "4.5.0",
|
"version": "4.5.0",
|
||||||
"resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz",
|
"resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz",
|
||||||
"integrity": "sha1-QVxEePK8wwEgwizhDtMib30+GOA="
|
"integrity": "sha1-QVxEePK8wwEgwizhDtMib30+GOA="
|
||||||
},
|
},
|
||||||
|
"node_modules/m3u8stream": {
|
||||||
|
"version": "0.8.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/m3u8stream/-/m3u8stream-0.8.4.tgz",
|
||||||
|
"integrity": "sha512-sco80Db+30RvcaIOndenX6E6oQNgTiBKeJbFPc+yDXwPQIkryfboEbCvXPlBRq3mQTCVPQO93TDVlfRwqpD35w==",
|
||||||
|
"dependencies": {
|
||||||
|
"miniget": "^4.0.0",
|
||||||
|
"sax": "^1.2.4"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/merge-stream": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w=="
|
||||||
|
},
|
||||||
"node_modules/mime-db": {
|
"node_modules/mime-db": {
|
||||||
"version": "1.49.0",
|
"version": "1.49.0",
|
||||||
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.49.0.tgz",
|
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.49.0.tgz",
|
||||||
|
@ -299,10 +472,37 @@
|
||||||
"node": ">= 0.6"
|
"node": ">= 0.6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/mimic-fn": {
|
||||||
|
"version": "2.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz",
|
||||||
|
"integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/miniget": {
|
||||||
|
"version": "4.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/miniget/-/miniget-4.2.1.tgz",
|
||||||
|
"integrity": "sha512-O/DduzDR6f+oDtVype9S/Qu5hhnx73EDYGyZKwU/qN82lehFZdfhoa4DT51SpsO+8epYrB3gcRmws56ROfTIoQ==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/mkdirp": {
|
||||||
|
"version": "1.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
|
||||||
|
"integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==",
|
||||||
|
"bin": {
|
||||||
|
"mkdirp": "bin/cmd.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/node-fetch": {
|
"node_modules/node-fetch": {
|
||||||
"version": "2.6.4",
|
"version": "2.6.6",
|
||||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.4.tgz",
|
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.6.tgz",
|
||||||
"integrity": "sha512-aD1fO+xtLiSCc9vuD+sYMxpIuQyhHscGSkBEo2o5LTV/3bTEAYvdUii29n8LlO5uLCmWdGP7uVUVXFo5SRdkLA==",
|
"integrity": "sha512-Z8/6vRlTUChSdIgMa51jxQ4lrw/Jy5SOW10ObaA47/RElsAN2c5Pn8bTgFGWn/ibwzXTE8qwr1Yzx28vsecXEA==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"whatwg-url": "^5.0.0"
|
"whatwg-url": "^5.0.0"
|
||||||
},
|
},
|
||||||
|
@ -310,6 +510,31 @@
|
||||||
"node": "4.x || >=6.0.0"
|
"node": "4.x || >=6.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/npm-run-path": {
|
||||||
|
"version": "4.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz",
|
||||||
|
"integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==",
|
||||||
|
"dependencies": {
|
||||||
|
"path-key": "^3.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/onetime": {
|
||||||
|
"version": "5.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz",
|
||||||
|
"integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==",
|
||||||
|
"dependencies": {
|
||||||
|
"mimic-fn": "^2.1.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/ow": {
|
"node_modules/ow": {
|
||||||
"version": "0.27.0",
|
"version": "0.27.0",
|
||||||
"resolved": "https://registry.npmjs.org/ow/-/ow-0.27.0.tgz",
|
"resolved": "https://registry.npmjs.org/ow/-/ow-0.27.0.tgz",
|
||||||
|
@ -329,6 +554,81 @@
|
||||||
"url": "https://github.com/sponsors/sindresorhus"
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/path-key": {
|
||||||
|
"version": "3.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
|
||||||
|
"integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/prism-media": {
|
||||||
|
"version": "1.3.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/prism-media/-/prism-media-1.3.2.tgz",
|
||||||
|
"integrity": "sha512-L6UsGHcT6i4wrQhFF1aPK+MNYgjRqR2tUoIqEY+CG1NqVkMjPRKzS37j9f8GiYPlD6wG9ruBj+q5Ax+bH8Ik1g==",
|
||||||
|
"peerDependencies": {
|
||||||
|
"@discordjs/opus": "^0.5.0",
|
||||||
|
"ffmpeg-static": "^4.2.7 || ^3.0.0 || ^2.4.0",
|
||||||
|
"node-opus": "^0.3.3",
|
||||||
|
"opusscript": "^0.0.8"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@discordjs/opus": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"ffmpeg-static": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"node-opus": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"opusscript": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/sax": {
|
||||||
|
"version": "1.2.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
|
||||||
|
"integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw=="
|
||||||
|
},
|
||||||
|
"node_modules/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==",
|
||||||
|
"dependencies": {
|
||||||
|
"shebang-regex": "^3.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/shebang-regex": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/signal-exit": {
|
||||||
|
"version": "3.0.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.6.tgz",
|
||||||
|
"integrity": "sha512-sDl4qMFpijcGw22U5w63KmD3cZJfBuFlVNbVMKje2keoKML7X2UzWbc4XrmEbDwg0NXJc3yv4/ox7b+JWb57kQ=="
|
||||||
|
},
|
||||||
|
"node_modules/strip-final-newline": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/tiny-typed-emitter": {
|
||||||
|
"version": "2.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/tiny-typed-emitter/-/tiny-typed-emitter-2.1.0.tgz",
|
||||||
|
"integrity": "sha512-qVtvMxeXbVej0cQWKqVSSAHmKZEHAvxdF8HEUBFWts8h+xEo5m/lEiPakuyZ3BnCBjOD8i24kzNOiOLLgsSxhA=="
|
||||||
|
},
|
||||||
"node_modules/tr46": {
|
"node_modules/tr46": {
|
||||||
"version": "0.0.3",
|
"version": "0.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
|
||||||
|
@ -390,6 +690,20 @@
|
||||||
"webidl-conversions": "^3.0.0"
|
"webidl-conversions": "^3.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/which": {
|
||||||
|
"version": "2.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
|
||||||
|
"integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
|
||||||
|
"dependencies": {
|
||||||
|
"isexe": "^2.0.0"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"node-which": "bin/node-which"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 8"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/ws": {
|
"node_modules/ws": {
|
||||||
"version": "7.5.5",
|
"version": "7.5.5",
|
||||||
"resolved": "https://registry.npmjs.org/ws/-/ws-7.5.5.tgz",
|
"resolved": "https://registry.npmjs.org/ws/-/ws-7.5.5.tgz",
|
||||||
|
@ -409,6 +723,35 @@
|
||||||
"optional": true
|
"optional": true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"node_modules/youtube-dl-exec": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/youtube-dl-exec/-/youtube-dl-exec-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-wD5BSkxC1o3rzj+1ktXdWObvkorW3Zvl1E+l56JQqYFTek3d9SR7o1RbjLiQZYQpXpoCPw0zV16SNDXjhVksXQ==",
|
||||||
|
"hasInstallScript": true,
|
||||||
|
"dependencies": {
|
||||||
|
"dargs": "~7.0.0",
|
||||||
|
"execa": "~5.1.0",
|
||||||
|
"is-unix": "~2.0.1",
|
||||||
|
"mkdirp": "~1.0.4",
|
||||||
|
"node-fetch": "~2.6.5"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/ytdl-core": {
|
||||||
|
"version": "4.9.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/ytdl-core/-/ytdl-core-4.9.1.tgz",
|
||||||
|
"integrity": "sha512-6Jbp5RDhUEozlaJQAR+l8oV8AHsx3WUXxSyPxzE6wOIAaLql7Hjiy0ZM58wZoyj1YEenlEPjEqcJIjKYKxvHtQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"m3u8stream": "^0.8.3",
|
||||||
|
"miniget": "^4.0.0",
|
||||||
|
"sax": "^1.1.3"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
@ -473,6 +816,40 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"@discordjs/voice": {
|
||||||
|
"version": "0.7.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@discordjs/voice/-/voice-0.7.5.tgz",
|
||||||
|
"integrity": "sha512-lUk+CmIXNKslT6DkC9IF9rpsqhzlTiedauUCPBzepjd4XWxwBZiyVIzR6QpbAirxkAwCoAbbje+3Ho71PGLEAw==",
|
||||||
|
"requires": {
|
||||||
|
"@types/ws": "^8.2.0",
|
||||||
|
"discord-api-types": "^0.24.0",
|
||||||
|
"prism-media": "^1.3.2",
|
||||||
|
"tiny-typed-emitter": "^2.1.0",
|
||||||
|
"tslib": "^2.3.1",
|
||||||
|
"ws": "^8.2.3"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@types/ws": {
|
||||||
|
"version": "8.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.2.0.tgz",
|
||||||
|
"integrity": "sha512-cyeefcUCgJlEk+hk2h3N+MqKKsPViQgF5boi9TTHSK+PoR9KWBb/C5ccPcDyAqgsbAYHTwulch725DV84+pSpg==",
|
||||||
|
"requires": {
|
||||||
|
"@types/node": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"discord-api-types": {
|
||||||
|
"version": "0.24.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.24.0.tgz",
|
||||||
|
"integrity": "sha512-X0uA2a92cRjowUEXpLZIHWl4jiX1NsUpDhcEOpa1/hpO1vkaokgZ8kkPtPih9hHth5UVQ3mHBu/PpB4qjyfJ4A=="
|
||||||
|
},
|
||||||
|
"ws": {
|
||||||
|
"version": "8.2.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/ws/-/ws-8.2.3.tgz",
|
||||||
|
"integrity": "sha512-wBuoj1BDpC6ZQ1B7DWQBYVLphPWkm8i9Y0/3YdHjHKHiohOJ1ws+3OccDWtH+PoC9DZD5WOTrJvNbWvjS6JWaA==",
|
||||||
|
"requires": {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"@sapphire/async-queue": {
|
"@sapphire/async-queue": {
|
||||||
"version": "1.1.4",
|
"version": "1.1.4",
|
||||||
"resolved": "https://registry.npmjs.org/@sapphire/async-queue/-/async-queue-1.1.4.tgz",
|
"resolved": "https://registry.npmjs.org/@sapphire/async-queue/-/async-queue-1.1.4.tgz",
|
||||||
|
@ -527,6 +904,21 @@
|
||||||
"delayed-stream": "~1.0.0"
|
"delayed-stream": "~1.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"cross-spawn": {
|
||||||
|
"version": "7.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
|
||||||
|
"integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
|
||||||
|
"requires": {
|
||||||
|
"path-key": "^3.1.0",
|
||||||
|
"shebang-command": "^2.0.0",
|
||||||
|
"which": "^2.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"dargs": {
|
||||||
|
"version": "7.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/dargs/-/dargs-7.0.0.tgz",
|
||||||
|
"integrity": "sha512-2iy1EkLdlBzQGvbweYRFxmFath8+K7+AKB0TlhHWkNuH+TmovaMH/Wp7V7R4u7f4SnX3OgLsU9t1NI9ioDnUpg=="
|
||||||
|
},
|
||||||
"delayed-stream": {
|
"delayed-stream": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
|
||||||
|
@ -584,6 +976,22 @@
|
||||||
"resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz",
|
||||||
"integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ=="
|
"integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ=="
|
||||||
},
|
},
|
||||||
|
"execa": {
|
||||||
|
"version": "5.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz",
|
||||||
|
"integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==",
|
||||||
|
"requires": {
|
||||||
|
"cross-spawn": "^7.0.3",
|
||||||
|
"get-stream": "^6.0.0",
|
||||||
|
"human-signals": "^2.1.0",
|
||||||
|
"is-stream": "^2.0.0",
|
||||||
|
"merge-stream": "^2.0.0",
|
||||||
|
"npm-run-path": "^4.0.1",
|
||||||
|
"onetime": "^5.1.2",
|
||||||
|
"signal-exit": "^3.0.3",
|
||||||
|
"strip-final-newline": "^2.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"form-data": {
|
"form-data": {
|
||||||
"version": "4.0.0",
|
"version": "4.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
|
||||||
|
@ -594,16 +1002,68 @@
|
||||||
"mime-types": "^2.1.12"
|
"mime-types": "^2.1.12"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"get-stream": {
|
||||||
|
"version": "6.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz",
|
||||||
|
"integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg=="
|
||||||
|
},
|
||||||
|
"human-signals": {
|
||||||
|
"version": "2.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz",
|
||||||
|
"integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw=="
|
||||||
|
},
|
||||||
"is-obj": {
|
"is-obj": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz",
|
||||||
"integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w=="
|
"integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w=="
|
||||||
},
|
},
|
||||||
|
"is-stream": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz",
|
||||||
|
"integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg=="
|
||||||
|
},
|
||||||
|
"is-unix": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/is-unix/-/is-unix-2.0.1.tgz",
|
||||||
|
"integrity": "sha512-RyKp5JtlRnfOvnKtfBMPLw9ocqDe1NlPQ8Bt+geVzKGfMnLGj8z/Y2HOmk/aMf47P4EbrEt9dN6YGTT1fx4mZA=="
|
||||||
|
},
|
||||||
|
"isexe": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
|
||||||
|
"integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA="
|
||||||
|
},
|
||||||
|
"libsodium": {
|
||||||
|
"version": "0.7.9",
|
||||||
|
"resolved": "https://registry.npmjs.org/libsodium/-/libsodium-0.7.9.tgz",
|
||||||
|
"integrity": "sha512-gfeADtR4D/CM0oRUviKBViMGXZDgnFdMKMzHsvBdqLBHd9ySi6EtYnmuhHVDDYgYpAO8eU8hEY+F8vIUAPh08A=="
|
||||||
|
},
|
||||||
|
"libsodium-wrappers": {
|
||||||
|
"version": "0.7.9",
|
||||||
|
"resolved": "https://registry.npmjs.org/libsodium-wrappers/-/libsodium-wrappers-0.7.9.tgz",
|
||||||
|
"integrity": "sha512-9HaAeBGk1nKTRFRHkt7nzxqCvnkWTjn1pdjKgcUnZxj0FyOP4CnhgFhMdrFfgNsukijBGyBLpP2m2uKT1vuWhQ==",
|
||||||
|
"requires": {
|
||||||
|
"libsodium": "^0.7.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"lodash.isequal": {
|
"lodash.isequal": {
|
||||||
"version": "4.5.0",
|
"version": "4.5.0",
|
||||||
"resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz",
|
"resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz",
|
||||||
"integrity": "sha1-QVxEePK8wwEgwizhDtMib30+GOA="
|
"integrity": "sha1-QVxEePK8wwEgwizhDtMib30+GOA="
|
||||||
},
|
},
|
||||||
|
"m3u8stream": {
|
||||||
|
"version": "0.8.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/m3u8stream/-/m3u8stream-0.8.4.tgz",
|
||||||
|
"integrity": "sha512-sco80Db+30RvcaIOndenX6E6oQNgTiBKeJbFPc+yDXwPQIkryfboEbCvXPlBRq3mQTCVPQO93TDVlfRwqpD35w==",
|
||||||
|
"requires": {
|
||||||
|
"miniget": "^4.0.0",
|
||||||
|
"sax": "^1.2.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"merge-stream": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w=="
|
||||||
|
},
|
||||||
"mime-db": {
|
"mime-db": {
|
||||||
"version": "1.49.0",
|
"version": "1.49.0",
|
||||||
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.49.0.tgz",
|
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.49.0.tgz",
|
||||||
|
@ -617,14 +1077,45 @@
|
||||||
"mime-db": "1.49.0"
|
"mime-db": "1.49.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"mimic-fn": {
|
||||||
|
"version": "2.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz",
|
||||||
|
"integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg=="
|
||||||
|
},
|
||||||
|
"miniget": {
|
||||||
|
"version": "4.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/miniget/-/miniget-4.2.1.tgz",
|
||||||
|
"integrity": "sha512-O/DduzDR6f+oDtVype9S/Qu5hhnx73EDYGyZKwU/qN82lehFZdfhoa4DT51SpsO+8epYrB3gcRmws56ROfTIoQ=="
|
||||||
|
},
|
||||||
|
"mkdirp": {
|
||||||
|
"version": "1.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
|
||||||
|
"integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw=="
|
||||||
|
},
|
||||||
"node-fetch": {
|
"node-fetch": {
|
||||||
"version": "2.6.4",
|
"version": "2.6.6",
|
||||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.4.tgz",
|
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.6.tgz",
|
||||||
"integrity": "sha512-aD1fO+xtLiSCc9vuD+sYMxpIuQyhHscGSkBEo2o5LTV/3bTEAYvdUii29n8LlO5uLCmWdGP7uVUVXFo5SRdkLA==",
|
"integrity": "sha512-Z8/6vRlTUChSdIgMa51jxQ4lrw/Jy5SOW10ObaA47/RElsAN2c5Pn8bTgFGWn/ibwzXTE8qwr1Yzx28vsecXEA==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"whatwg-url": "^5.0.0"
|
"whatwg-url": "^5.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"npm-run-path": {
|
||||||
|
"version": "4.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz",
|
||||||
|
"integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==",
|
||||||
|
"requires": {
|
||||||
|
"path-key": "^3.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"onetime": {
|
||||||
|
"version": "5.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz",
|
||||||
|
"integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==",
|
||||||
|
"requires": {
|
||||||
|
"mimic-fn": "^2.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"ow": {
|
"ow": {
|
||||||
"version": "0.27.0",
|
"version": "0.27.0",
|
||||||
"resolved": "https://registry.npmjs.org/ow/-/ow-0.27.0.tgz",
|
"resolved": "https://registry.npmjs.org/ow/-/ow-0.27.0.tgz",
|
||||||
|
@ -638,6 +1129,50 @@
|
||||||
"vali-date": "^1.0.0"
|
"vali-date": "^1.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"path-key": {
|
||||||
|
"version": "3.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
|
||||||
|
"integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="
|
||||||
|
},
|
||||||
|
"prism-media": {
|
||||||
|
"version": "1.3.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/prism-media/-/prism-media-1.3.2.tgz",
|
||||||
|
"integrity": "sha512-L6UsGHcT6i4wrQhFF1aPK+MNYgjRqR2tUoIqEY+CG1NqVkMjPRKzS37j9f8GiYPlD6wG9ruBj+q5Ax+bH8Ik1g==",
|
||||||
|
"requires": {}
|
||||||
|
},
|
||||||
|
"sax": {
|
||||||
|
"version": "1.2.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
|
||||||
|
"integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw=="
|
||||||
|
},
|
||||||
|
"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==",
|
||||||
|
"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=="
|
||||||
|
},
|
||||||
|
"signal-exit": {
|
||||||
|
"version": "3.0.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.6.tgz",
|
||||||
|
"integrity": "sha512-sDl4qMFpijcGw22U5w63KmD3cZJfBuFlVNbVMKje2keoKML7X2UzWbc4XrmEbDwg0NXJc3yv4/ox7b+JWb57kQ=="
|
||||||
|
},
|
||||||
|
"strip-final-newline": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA=="
|
||||||
|
},
|
||||||
|
"tiny-typed-emitter": {
|
||||||
|
"version": "2.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/tiny-typed-emitter/-/tiny-typed-emitter-2.1.0.tgz",
|
||||||
|
"integrity": "sha512-qVtvMxeXbVej0cQWKqVSSAHmKZEHAvxdF8HEUBFWts8h+xEo5m/lEiPakuyZ3BnCBjOD8i24kzNOiOLLgsSxhA=="
|
||||||
|
},
|
||||||
"tr46": {
|
"tr46": {
|
||||||
"version": "0.0.3",
|
"version": "0.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
|
||||||
|
@ -683,11 +1218,41 @@
|
||||||
"webidl-conversions": "^3.0.0"
|
"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==",
|
||||||
|
"requires": {
|
||||||
|
"isexe": "^2.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"ws": {
|
"ws": {
|
||||||
"version": "7.5.5",
|
"version": "7.5.5",
|
||||||
"resolved": "https://registry.npmjs.org/ws/-/ws-7.5.5.tgz",
|
"resolved": "https://registry.npmjs.org/ws/-/ws-7.5.5.tgz",
|
||||||
"integrity": "sha512-BAkMFcAzl8as1G/hArkxOxq3G7pjUqQ3gzYbLL0/5zNkph70e+lCoxBGnm6AW1+/aiNeV4fnKqZ8m4GZewmH2w==",
|
"integrity": "sha512-BAkMFcAzl8as1G/hArkxOxq3G7pjUqQ3gzYbLL0/5zNkph70e+lCoxBGnm6AW1+/aiNeV4fnKqZ8m4GZewmH2w==",
|
||||||
"requires": {}
|
"requires": {}
|
||||||
|
},
|
||||||
|
"youtube-dl-exec": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/youtube-dl-exec/-/youtube-dl-exec-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-wD5BSkxC1o3rzj+1ktXdWObvkorW3Zvl1E+l56JQqYFTek3d9SR7o1RbjLiQZYQpXpoCPw0zV16SNDXjhVksXQ==",
|
||||||
|
"requires": {
|
||||||
|
"dargs": "~7.0.0",
|
||||||
|
"execa": "~5.1.0",
|
||||||
|
"is-unix": "~2.0.1",
|
||||||
|
"mkdirp": "~1.0.4",
|
||||||
|
"node-fetch": "~2.6.5"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ytdl-core": {
|
||||||
|
"version": "4.9.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/ytdl-core/-/ytdl-core-4.9.1.tgz",
|
||||||
|
"integrity": "sha512-6Jbp5RDhUEozlaJQAR+l8oV8AHsx3WUXxSyPxzE6wOIAaLql7Hjiy0ZM58wZoyj1YEenlEPjEqcJIjKYKxvHtQ==",
|
||||||
|
"requires": {
|
||||||
|
"m3u8stream": "^0.8.3",
|
||||||
|
"miniget": "^4.0.0",
|
||||||
|
"sax": "^1.1.3"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
11
package.json
11
package.json
|
@ -7,8 +7,9 @@
|
||||||
"test": "test"
|
"test": "test"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"run": "tsc && node src/index.js",
|
"build": "tsc",
|
||||||
"test": "echo \"Error: no test specified\" && exit 1"
|
"run": " node build/index.js",
|
||||||
|
"dev": "rm -fr build && tsc && node build/index.js"
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
|
@ -26,8 +27,12 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@discordjs/builders": "^0.6.0",
|
"@discordjs/builders": "^0.6.0",
|
||||||
"@discordjs/rest": "^0.1.0-canary.0",
|
"@discordjs/rest": "^0.1.0-canary.0",
|
||||||
|
"@discordjs/voice": "^0.7.5",
|
||||||
"discord-api-types": "^0.23.1",
|
"discord-api-types": "^0.23.1",
|
||||||
"discord.js": "^13.1.0"
|
"discord.js": "^13.1.0",
|
||||||
|
"libsodium-wrappers": "^0.7.9",
|
||||||
|
"youtube-dl-exec": "^2.0.0",
|
||||||
|
"ytdl-core": "^4.9.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"typescript": "^4.5.2"
|
"typescript": "^4.5.2"
|
||||||
|
|
25
src/index.ts
25
src/index.ts
|
@ -1,14 +1,20 @@
|
||||||
import "fs";
|
import "fs";
|
||||||
import { Intents } from "discord.js";
|
import {Intents, Message} from "discord.js";
|
||||||
import "./lib/Modules";
|
import "./lib/Modules";
|
||||||
import {AdministratorClient} from "./lib/AdministratorClient";
|
import {AdministratorClient} from "./lib/AdministratorClient";
|
||||||
|
|
||||||
const config = require("../config.json");
|
const config = require("../config.json");
|
||||||
const client = new AdministratorClient({ intents: [Intents.FLAGS.GUILDS] });
|
const client = new AdministratorClient({ intents: [Intents.FLAGS.GUILDS, Intents.FLAGS.GUILD_VOICE_STATES] });
|
||||||
|
|
||||||
|
|
||||||
client.once("ready", async () => {
|
client.once("ready", async () => {
|
||||||
client.application = await client.application?.fetch() ?? null;
|
client.application = await client.application?.fetch() ?? null;
|
||||||
|
if ("DEV" in process.env && process.env["DEV"] == "true") {
|
||||||
|
console.log("Dev mod enable");
|
||||||
|
await client.application?.commands.set([]);
|
||||||
|
for (const name in await client.guilds.fetch())
|
||||||
|
await (await client.guilds.fetch(name)).commands.set([]);
|
||||||
|
}
|
||||||
await client.modules.loadAllModules();
|
await client.modules.loadAllModules();
|
||||||
console.log("Started !");
|
console.log("Started !");
|
||||||
});
|
});
|
||||||
|
@ -24,7 +30,20 @@ client.on("interactionCreate", async interaction => {
|
||||||
await command.execute(interaction);
|
await command.execute(interaction);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
await interaction.reply({ content: "There was an error while executing this command !", ephemeral: true });
|
const msg = {content: "There was an error while executing this command !", ephemeral: true};
|
||||||
|
try {
|
||||||
|
await interaction.reply(msg);
|
||||||
|
} catch {
|
||||||
|
try {
|
||||||
|
await interaction.followUp(msg);
|
||||||
|
} catch {
|
||||||
|
try {
|
||||||
|
await (await interaction.fetchReply() as Message).reply(msg);
|
||||||
|
} catch {
|
||||||
|
console.warn("Cant send error message to the user :/");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,12 @@ export abstract class Command {
|
||||||
|
|
||||||
async register() {
|
async register() {
|
||||||
try {
|
try {
|
||||||
|
if ("DEV" in process.env && process.env["DEV"] == "true") {
|
||||||
|
const devGuild = await this.module.modules.client?.guilds.fetch(process.env["DEVGUILD"] as any);
|
||||||
|
this.scope = await devGuild.commands.create(this.data); // ToDo: use only one call to avoid spamming the api
|
||||||
|
} else {
|
||||||
this.scope = await this.module.modules.client?.application?.commands.create(this.data);
|
this.scope = await this.module.modules.client?.application?.commands.create(this.data);
|
||||||
|
}
|
||||||
|
|
||||||
console.log("Successfully registered commands " + this.scope?.name);
|
console.log("Successfully registered commands " + this.scope?.name);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
@ -30,7 +35,7 @@ export abstract class Command {
|
||||||
|
|
||||||
async isRegister(): Promise<boolean> {
|
async isRegister(): Promise<boolean> {
|
||||||
if (this.scope)
|
if (this.scope)
|
||||||
return !! await this.module.modules.client?.application?.commands.fetch(this.scope.id);
|
return !! await this.module.modules.client?.application?.commands.fetch(this.scope.id); // ToDo: use only one call to avoid spamming the api
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
131
src/modules/Music/Player.ts
Normal file
131
src/modules/Music/Player.ts
Normal file
|
@ -0,0 +1,131 @@
|
||||||
|
import {VoiceChannel} from "discord.js";
|
||||||
|
import {
|
||||||
|
AudioPlayer,
|
||||||
|
AudioPlayerState,
|
||||||
|
AudioPlayerStatus,
|
||||||
|
AudioResource,
|
||||||
|
createAudioPlayer,
|
||||||
|
entersState,
|
||||||
|
joinVoiceChannel,
|
||||||
|
VoiceConnection,
|
||||||
|
VoiceConnectionDisconnectReason,
|
||||||
|
VoiceConnectionState,
|
||||||
|
VoiceConnectionStatus
|
||||||
|
} from '@discordjs/voice';
|
||||||
|
import {promisify} from "util";
|
||||||
|
import {Track} from "./Track";
|
||||||
|
|
||||||
|
const wait = promisify(setTimeout);
|
||||||
|
|
||||||
|
|
||||||
|
export class Player {
|
||||||
|
readonly connexion: VoiceConnection;
|
||||||
|
readonly audio: AudioPlayer;
|
||||||
|
current: Track | null = null;
|
||||||
|
queue: Track[] = [];
|
||||||
|
readyLock: boolean = false;
|
||||||
|
queueLock: boolean = false;
|
||||||
|
|
||||||
|
constructor(voiceChanel: VoiceChannel) {
|
||||||
|
this.connexion = joinVoiceChannel({channelId: voiceChanel.id, guildId: voiceChanel.guildId, selfDeaf: true, selfMute: false, adapterCreator: voiceChanel.guild.voiceAdapterCreator as any});
|
||||||
|
this.audio = createAudioPlayer();
|
||||||
|
|
||||||
|
this.connexion.on("error", console.warn);
|
||||||
|
this.audio.on('error', (error: { resource: any; }) => (error.resource as AudioResource<Track>).metadata.onError(error as any));
|
||||||
|
this.connexion.on("stateChange", async (_: VoiceConnectionState, newState: VoiceConnectionState) => {
|
||||||
|
if (newState.status === VoiceConnectionStatus.Disconnected) {
|
||||||
|
if (newState.reason === VoiceConnectionDisconnectReason.WebSocketClose && newState.closeCode === 4014) {
|
||||||
|
try {
|
||||||
|
await entersState(this.connexion, VoiceConnectionStatus.Connecting, 5_000);
|
||||||
|
} catch {
|
||||||
|
this.connexion.destroy();
|
||||||
|
}
|
||||||
|
} else if (this.connexion.rejoinAttempts < 5) {
|
||||||
|
await wait((this.connexion.rejoinAttempts + 1) * 5_000);
|
||||||
|
this.connexion.rejoin();
|
||||||
|
} else {
|
||||||
|
this.connexion.destroy();
|
||||||
|
}
|
||||||
|
} else if (newState.status === VoiceConnectionStatus.Destroyed) {
|
||||||
|
this.stop();
|
||||||
|
} else if (
|
||||||
|
!this.readyLock &&
|
||||||
|
(newState.status === VoiceConnectionStatus.Connecting || newState.status === VoiceConnectionStatus.Signalling)
|
||||||
|
) {
|
||||||
|
this.readyLock = true;
|
||||||
|
try {
|
||||||
|
await entersState(this.connexion, VoiceConnectionStatus.Ready, 20_000);
|
||||||
|
} catch (e) {
|
||||||
|
if (this.connexion.state.status !== VoiceConnectionStatus.Destroyed) this.connexion.destroy();
|
||||||
|
} finally {
|
||||||
|
this.readyLock = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.audio.on('stateChange', (oldState: AudioPlayerState, newState: AudioPlayerState) => {
|
||||||
|
if (newState.status === AudioPlayerStatus.Idle && oldState.status !== AudioPlayerStatus.Idle) {
|
||||||
|
(oldState.resource as AudioResource<Track>).metadata.onFinish();
|
||||||
|
void this.processQueue();
|
||||||
|
} else if (newState.status === AudioPlayerStatus.Playing) {
|
||||||
|
(newState.resource as AudioResource<Track>).metadata.onStart();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.connexion.subscribe(this.audio);
|
||||||
|
}
|
||||||
|
|
||||||
|
public enqueue(track: Track) {
|
||||||
|
this.queue.push(track);
|
||||||
|
void this.processQueue();
|
||||||
|
}
|
||||||
|
|
||||||
|
public pause() {
|
||||||
|
this.audio.pause();
|
||||||
|
}
|
||||||
|
|
||||||
|
public resume() {
|
||||||
|
this.audio.unpause();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async skip() {
|
||||||
|
this.audio.stop(true);
|
||||||
|
await this.processQueue();
|
||||||
|
}
|
||||||
|
|
||||||
|
public stop() {
|
||||||
|
this.queueLock = true;
|
||||||
|
this.queue = [];
|
||||||
|
this.audio.stop(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public disconnect() {
|
||||||
|
if (this.audio.state.status != AudioPlayerStatus.Idle)
|
||||||
|
this.stop();
|
||||||
|
this.connexion.disconnect();
|
||||||
|
}
|
||||||
|
|
||||||
|
public flush() {
|
||||||
|
this.queue = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
private async processQueue(): Promise<void> {
|
||||||
|
if (this.queueLock || this.audio.state.status !== AudioPlayerStatus.Idle || this.queue.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.queueLock = true;
|
||||||
|
|
||||||
|
const nextTrack = this.queue.shift()!;
|
||||||
|
try {
|
||||||
|
const resource = await nextTrack.createAudioResource();
|
||||||
|
this.audio.play(resource);
|
||||||
|
this.queueLock = false;
|
||||||
|
this.current = nextTrack;
|
||||||
|
} catch (error) {
|
||||||
|
await nextTrack.onError(error as Error);
|
||||||
|
this.queueLock = false;
|
||||||
|
this.current = null;
|
||||||
|
return this.processQueue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
79
src/modules/Music/Track.ts
Normal file
79
src/modules/Music/Track.ts
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
import {getInfo, videoInfo} from "ytdl-core";
|
||||||
|
import { AudioResource, createAudioResource, demuxProbe } from "@discordjs/voice";
|
||||||
|
import {exec as ytdl} from "youtube-dl-exec";
|
||||||
|
import {CommandInteraction, Message} from "discord.js";
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
||||||
|
const noop = async () => {};
|
||||||
|
|
||||||
|
|
||||||
|
export class Track {
|
||||||
|
public readonly info: videoInfo;
|
||||||
|
private readonly interaction: CommandInteraction;
|
||||||
|
|
||||||
|
private constructor(info: videoInfo, interaction: CommandInteraction) {
|
||||||
|
this.info = info;
|
||||||
|
this.interaction = interaction
|
||||||
|
}
|
||||||
|
|
||||||
|
private async replyInteraction(message: string) {
|
||||||
|
try {
|
||||||
|
await this.interaction.followUp(message);
|
||||||
|
} catch {
|
||||||
|
await (await this.interaction.fetchReply() as Message).reply(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async onStart() {
|
||||||
|
this.onStart = noop;
|
||||||
|
await this.replyInteraction("Now playing");
|
||||||
|
}
|
||||||
|
|
||||||
|
async onFinish() {
|
||||||
|
this.onStart = noop;
|
||||||
|
}
|
||||||
|
|
||||||
|
async onError(error: Error) {
|
||||||
|
this.onStart = noop;
|
||||||
|
console.error(error);
|
||||||
|
await this.replyInteraction("Error with this song, sorry :/");
|
||||||
|
}
|
||||||
|
|
||||||
|
public createAudioResource(): Promise<AudioResource<Track>> {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const process = ytdl(
|
||||||
|
this.info.videoDetails.video_url,
|
||||||
|
{
|
||||||
|
output: "-",
|
||||||
|
quiet: true,
|
||||||
|
format: 'bestaudio[ext=webm+acodec=opus+asr=48000]/bestaudio',
|
||||||
|
limitRate: '100K'
|
||||||
|
},
|
||||||
|
{ stdio: ['ignore', 'pipe', 'ignore'] },
|
||||||
|
);
|
||||||
|
if (!process.stdout) {
|
||||||
|
reject(new Error('No stdout'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const stream = process.stdout;
|
||||||
|
const onError = (error: Error) => {
|
||||||
|
if (!process.killed) process.kill();
|
||||||
|
stream.resume();
|
||||||
|
reject(error);
|
||||||
|
};
|
||||||
|
process
|
||||||
|
.once('spawn', () => {
|
||||||
|
demuxProbe(stream)
|
||||||
|
.then((probe: { stream: any; type: any; }) => resolve(createAudioResource(probe.stream, { metadata: this, inputType: probe.type })))
|
||||||
|
.catch(onError);
|
||||||
|
})
|
||||||
|
.catch(onError);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async from(url: string, interaction: CommandInteraction): Promise<Track> {
|
||||||
|
const info = await getInfo(url);
|
||||||
|
|
||||||
|
return new Track(info, interaction);
|
||||||
|
}
|
||||||
|
}
|
39
src/modules/Music/disconnect.ts
Normal file
39
src/modules/Music/disconnect.ts
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
import {Command} from "../../lib/Command";
|
||||||
|
import {ChatInputApplicationCommandData, CommandInteraction, GuildMember} from "discord.js";
|
||||||
|
import {Music} from "./index";
|
||||||
|
import {AudioPlayerStatus} from "@discordjs/voice";
|
||||||
|
|
||||||
|
|
||||||
|
export class DisconnectCommand extends Command {
|
||||||
|
data: ChatInputApplicationCommandData = {
|
||||||
|
name: "disconnect",
|
||||||
|
description: "Stop the music"
|
||||||
|
};
|
||||||
|
module: Music;
|
||||||
|
|
||||||
|
constructor(module: Music) {
|
||||||
|
super(module);
|
||||||
|
this.module = module;
|
||||||
|
}
|
||||||
|
|
||||||
|
async execute(interaction: CommandInteraction) {
|
||||||
|
await interaction.deferReply();
|
||||||
|
if (!interaction.guild || ! (interaction.member instanceof GuildMember)) {
|
||||||
|
await interaction.editReply("This command is only usable in a guild :/");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let player = this.module.players.get(interaction.guild.id);
|
||||||
|
|
||||||
|
if (!player) {
|
||||||
|
await interaction.editReply("No music currently playing !");
|
||||||
|
return;
|
||||||
|
} else if (interaction.member.voice.channelId != player.connexion.joinConfig.channelId) {
|
||||||
|
await interaction.editReply("You must be in the same voice channel !");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
player.disconnect();
|
||||||
|
await interaction.followUp("Bot disconnected");
|
||||||
|
}
|
||||||
|
}
|
43
src/modules/Music/flush.ts
Normal file
43
src/modules/Music/flush.ts
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
import {Command} from "../../lib/Command";
|
||||||
|
import {ChatInputApplicationCommandData, CommandInteraction, GuildMember} from "discord.js";
|
||||||
|
import {Music} from "./index";
|
||||||
|
import {AudioPlayerPausedState, AudioPlayerStatus} from "@discordjs/voice";
|
||||||
|
|
||||||
|
|
||||||
|
export class FlushCommand extends Command {
|
||||||
|
data: ChatInputApplicationCommandData = {
|
||||||
|
name: "flush",
|
||||||
|
description: "Flush the music queue"
|
||||||
|
};
|
||||||
|
module: Music;
|
||||||
|
|
||||||
|
constructor(module: Music) {
|
||||||
|
super(module);
|
||||||
|
this.module = module;
|
||||||
|
}
|
||||||
|
|
||||||
|
async execute(interaction: CommandInteraction) {
|
||||||
|
await interaction.deferReply();
|
||||||
|
|
||||||
|
if (!interaction.guild || ! (interaction.member instanceof GuildMember)) {
|
||||||
|
await interaction.editReply("This command is only usable in a guild :/");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let player = this.module.players.get(interaction.guild.id);
|
||||||
|
|
||||||
|
if (!player) {
|
||||||
|
await interaction.editReply("No music currently playing !");
|
||||||
|
return;
|
||||||
|
} else if (interaction.member.voice.channelId != player.connexion.joinConfig.channelId) {
|
||||||
|
await interaction.editReply("You must be in the same voice channel !");
|
||||||
|
return;
|
||||||
|
} else if (!player.queue.length) {
|
||||||
|
await interaction.editReply("Can't flush queue, there is no music left");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
player.flush();
|
||||||
|
await interaction.followUp("Queue flushed");
|
||||||
|
}
|
||||||
|
}
|
30
src/modules/Music/index.ts
Normal file
30
src/modules/Music/index.ts
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
import {Module} from "../../lib/Module";
|
||||||
|
import {Modules} from "../../lib/Modules";
|
||||||
|
import {PlayCommand} from "./play";
|
||||||
|
import {Snowflake} from "discord-api-types";
|
||||||
|
import {Player} from "./Player";
|
||||||
|
import {StopCommand} from "./stop";
|
||||||
|
import {PauseCommand} from "./pause";
|
||||||
|
import {SkipCommand} from "./skip";
|
||||||
|
import {ResumeCommand} from "./resume";
|
||||||
|
import {FlushCommand} from "./flush";
|
||||||
|
import {QueueCommand} from "./queue";
|
||||||
|
import {DisconnectCommand} from "./disconnect";
|
||||||
|
|
||||||
|
|
||||||
|
export class Music extends Module {
|
||||||
|
players: Map<Snowflake, Player> = new Map<Snowflake, Player>();
|
||||||
|
|
||||||
|
constructor(modules: Modules) {
|
||||||
|
super(modules);
|
||||||
|
this.commands.push(new PlayCommand(this));
|
||||||
|
this.commands.push(new StopCommand(this));
|
||||||
|
this.commands.push(new PauseCommand(this));
|
||||||
|
this.commands.push(new ResumeCommand(this));
|
||||||
|
this.commands.push(new SkipCommand(this));
|
||||||
|
this.commands.push(new FlushCommand(this));
|
||||||
|
this.commands.push(new QueueCommand(this));
|
||||||
|
this.commands.push(new DisconnectCommand(this));
|
||||||
|
// ToDo: stop if nobody in the channel
|
||||||
|
}
|
||||||
|
}
|
43
src/modules/Music/pause.ts
Normal file
43
src/modules/Music/pause.ts
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
import {Command} from "../../lib/Command";
|
||||||
|
import {ChatInputApplicationCommandData, CommandInteraction, GuildMember} from "discord.js";
|
||||||
|
import {Music} from "./index";
|
||||||
|
import {AudioPlayerPausedState, AudioPlayerStatus} from "@discordjs/voice";
|
||||||
|
|
||||||
|
|
||||||
|
export class PauseCommand extends Command {
|
||||||
|
data: ChatInputApplicationCommandData = {
|
||||||
|
name: "pause",
|
||||||
|
description: "Pause the music"
|
||||||
|
};
|
||||||
|
module: Music;
|
||||||
|
|
||||||
|
constructor(module: Music) {
|
||||||
|
super(module);
|
||||||
|
this.module = module;
|
||||||
|
}
|
||||||
|
|
||||||
|
async execute(interaction: CommandInteraction) {
|
||||||
|
await interaction.deferReply();
|
||||||
|
|
||||||
|
if (!interaction.guild || ! (interaction.member instanceof GuildMember)) {
|
||||||
|
await interaction.editReply("This command is only usable in a guild :/");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let player = this.module.players.get(interaction.guild.id);
|
||||||
|
|
||||||
|
if (!player) {
|
||||||
|
await interaction.editReply("No music currently playing !");
|
||||||
|
return;
|
||||||
|
} else if (interaction.member.voice.channelId != player.connexion.joinConfig.channelId) {
|
||||||
|
await interaction.editReply("You must be in the same voice channel !");
|
||||||
|
return;
|
||||||
|
} else if ([AudioPlayerStatus.Playing, AudioPlayerStatus.Buffering].includes(player.audio.state.status)) {
|
||||||
|
await interaction.editReply(`Can't pause, the music is ${player.audio.state.status}`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
player.pause();
|
||||||
|
await interaction.followUp("Music paused");
|
||||||
|
}
|
||||||
|
}
|
72
src/modules/Music/play.ts
Normal file
72
src/modules/Music/play.ts
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
import {Command} from "../../lib/Command";
|
||||||
|
import {ChatInputApplicationCommandData, CommandInteraction, GuildMember, VoiceChannel} from "discord.js";
|
||||||
|
import {Music} from "./index";
|
||||||
|
import {Player} from "./Player";
|
||||||
|
import {Track} from "./Track";
|
||||||
|
import {entersState, VoiceConnectionStatus} from "@discordjs/voice";
|
||||||
|
const {Constants: { ApplicationCommandOptionTypes }} = require("discord.js");
|
||||||
|
|
||||||
|
export class PlayCommand extends Command {
|
||||||
|
data: ChatInputApplicationCommandData = {
|
||||||
|
name: "play",
|
||||||
|
description: "Play a music",
|
||||||
|
options: [{
|
||||||
|
type: ApplicationCommandOptionTypes.STRING,
|
||||||
|
name: "music",
|
||||||
|
description: "The music to play",
|
||||||
|
required: true
|
||||||
|
}]
|
||||||
|
};
|
||||||
|
module: Music;
|
||||||
|
|
||||||
|
constructor(module: Music) {
|
||||||
|
super(module);
|
||||||
|
this.module = module;
|
||||||
|
}
|
||||||
|
|
||||||
|
async execute(interaction: CommandInteraction) {
|
||||||
|
await interaction.deferReply();
|
||||||
|
|
||||||
|
if (!interaction.guild || ! (interaction.member instanceof GuildMember)) {
|
||||||
|
await interaction.editReply("This command is only usable in a guild :/");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let player = this.module.players.get(interaction.guild.id);
|
||||||
|
|
||||||
|
if (!player) {
|
||||||
|
if (! interaction.member.voice.channel || ! (interaction.member.voice.channel instanceof VoiceChannel)) {
|
||||||
|
await interaction.editReply("You must be connected into a voice channel !");
|
||||||
|
return;
|
||||||
|
} else if (!interaction.member.voice.channel.joinable) {
|
||||||
|
await interaction.editReply("The bot doesn't have the permission to join this voice channel :/");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
player = new Player(interaction.member.voice.channel);
|
||||||
|
this.module.players.set(interaction.guild.id, player);
|
||||||
|
} else if (interaction.member.voice.channelId != player.connexion.joinConfig.channelId) {
|
||||||
|
await interaction.editReply("You must be in the same voice channel !");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await entersState(player.connexion, VoiceConnectionStatus.Ready, 20e3);
|
||||||
|
} catch (error) {
|
||||||
|
console.warn("Fail to enter state Ready !");
|
||||||
|
await interaction.followUp("Failed to join voice channel within 20 seconds, please try again later !");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const url = interaction.options.get("music")!.value! as string;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const track = await Track.from(url, interaction);
|
||||||
|
player.enqueue(track);
|
||||||
|
await interaction.followUp(`${track.info.videoDetails.title} added to queue`);
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
await interaction.followUp("Fail to add to queue")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
67
src/modules/Music/queue.ts
Normal file
67
src/modules/Music/queue.ts
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
import {Command} from "../../lib/Command";
|
||||||
|
import {ChatInputApplicationCommandData, CommandInteraction, GuildMember} from "discord.js";
|
||||||
|
import {Music} from "./index";
|
||||||
|
import {AudioPlayerStatus} from "@discordjs/voice";
|
||||||
|
|
||||||
|
|
||||||
|
function millisecondsToTime(milli: number): string {
|
||||||
|
const seconds = Math.floor((milli / 1000) % 60);
|
||||||
|
const minutes = Math.floor((milli / (60 * 1000)) % 60);
|
||||||
|
|
||||||
|
return ('0' + minutes).slice(-2) + ":" + ('0' + seconds).slice(-2);
|
||||||
|
}
|
||||||
|
|
||||||
|
export class QueueCommand extends Command {
|
||||||
|
data: ChatInputApplicationCommandData = {
|
||||||
|
name: "queue",
|
||||||
|
description: "Display the current queue"
|
||||||
|
};
|
||||||
|
module: Music;
|
||||||
|
|
||||||
|
constructor(module: Music) {
|
||||||
|
super(module);
|
||||||
|
this.module = module;
|
||||||
|
}
|
||||||
|
|
||||||
|
async execute(interaction: CommandInteraction) {
|
||||||
|
await interaction.deferReply();
|
||||||
|
|
||||||
|
if (!interaction.guild || ! (interaction.member instanceof GuildMember)) {
|
||||||
|
await interaction.editReply("This command is only usable in a guild :/");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let player = this.module.players.get(interaction.guild.id);
|
||||||
|
|
||||||
|
if (!player) {
|
||||||
|
await interaction.editReply("No music currently playing !");
|
||||||
|
return;
|
||||||
|
} else if (interaction.member.voice.channelId != player.connexion.joinConfig.channelId) {
|
||||||
|
await interaction.editReply("You must be in the same voice channel !");
|
||||||
|
return;
|
||||||
|
} else if (player.audio.state.status == AudioPlayerStatus.Idle) {
|
||||||
|
await interaction.editReply("There is no queue to display");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let queue = "";
|
||||||
|
|
||||||
|
if (player.queue.length) {
|
||||||
|
queue = player.queue.map((m, n) => `${n}. ${m.info.videoDetails.title}`).join("\n") + "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
let barr = "";
|
||||||
|
if ([AudioPlayerStatus.Playing, AudioPlayerStatus.Paused, AudioPlayerStatus.AutoPaused].includes(player.audio.state.status)) {
|
||||||
|
// @ts-ignore
|
||||||
|
const duration: number = player.current?.info.videoDetails.lengthSeconds * 1000;
|
||||||
|
// @ts-ignore
|
||||||
|
const current: number = player.audio.state.playbackDuration;
|
||||||
|
|
||||||
|
const maxSize = 35;
|
||||||
|
const progress = Math.ceil((current/duration)*maxSize);
|
||||||
|
barr = `\n${player.current?.info.videoDetails.title}\n${millisecondsToTime(current)} [${"=".repeat(progress)}${"-".repeat(maxSize-progress)}] ${millisecondsToTime(duration)}\n`
|
||||||
|
}
|
||||||
|
|
||||||
|
await interaction.followUp(`\`\`\`md\n${queue}${barr}\`\`\``);
|
||||||
|
}
|
||||||
|
}
|
43
src/modules/Music/resume.ts
Normal file
43
src/modules/Music/resume.ts
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
import {Command} from "../../lib/Command";
|
||||||
|
import {ChatInputApplicationCommandData, CommandInteraction, GuildMember} from "discord.js";
|
||||||
|
import {Music} from "./index";
|
||||||
|
import {AudioPlayerStatus} from "@discordjs/voice";
|
||||||
|
|
||||||
|
|
||||||
|
export class ResumeCommand extends Command {
|
||||||
|
data: ChatInputApplicationCommandData = {
|
||||||
|
name: "resume",
|
||||||
|
description: "Resume the music"
|
||||||
|
};
|
||||||
|
module: Music;
|
||||||
|
|
||||||
|
constructor(module: Music) {
|
||||||
|
super(module);
|
||||||
|
this.module = module;
|
||||||
|
}
|
||||||
|
|
||||||
|
async execute(interaction: CommandInteraction) {
|
||||||
|
await interaction.deferReply();
|
||||||
|
|
||||||
|
if (!interaction.guild || ! (interaction.member instanceof GuildMember)) {
|
||||||
|
await interaction.editReply("This command is only usable in a guild :/");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let player = this.module.players.get(interaction.guild.id);
|
||||||
|
|
||||||
|
if (!player) {
|
||||||
|
await interaction.editReply("No music currently playing !");
|
||||||
|
return;
|
||||||
|
} else if (interaction.member.voice.channelId != player.connexion.joinConfig.channelId) {
|
||||||
|
await interaction.editReply("You must be in the same voice channel !");
|
||||||
|
return;
|
||||||
|
} else if ([AudioPlayerStatus.Paused, AudioPlayerStatus.AutoPaused].includes(player.audio.state.status)) {
|
||||||
|
await interaction.editReply(`Can't resume, the music is ${player.audio.state.status}`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
player.resume();
|
||||||
|
await interaction.followUp("Music resumed");
|
||||||
|
}
|
||||||
|
}
|
43
src/modules/Music/skip.ts
Normal file
43
src/modules/Music/skip.ts
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
import {Command} from "../../lib/Command";
|
||||||
|
import {ChatInputApplicationCommandData, CommandInteraction, GuildMember} from "discord.js";
|
||||||
|
import {Music} from "./index";
|
||||||
|
import {AudioPlayerStatus} from "@discordjs/voice";
|
||||||
|
|
||||||
|
|
||||||
|
export class SkipCommand extends Command {
|
||||||
|
data: ChatInputApplicationCommandData = {
|
||||||
|
name: "skip",
|
||||||
|
description: "Skip the music"
|
||||||
|
};
|
||||||
|
module: Music;
|
||||||
|
|
||||||
|
constructor(module: Music) {
|
||||||
|
super(module);
|
||||||
|
this.module = module;
|
||||||
|
}
|
||||||
|
|
||||||
|
async execute(interaction: CommandInteraction) {
|
||||||
|
await interaction.deferReply();
|
||||||
|
|
||||||
|
if (!interaction.guild || ! (interaction.member instanceof GuildMember)) {
|
||||||
|
await interaction.editReply("This command is only usable in a guild :/");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let player = this.module.players.get(interaction.guild.id);
|
||||||
|
|
||||||
|
if (!player) {
|
||||||
|
await interaction.editReply("No music currently playing !");
|
||||||
|
return;
|
||||||
|
} else if (interaction.member.voice.channelId != player.connexion.joinConfig.channelId) {
|
||||||
|
await interaction.editReply("You must be in the same voice channel !");
|
||||||
|
return;
|
||||||
|
} else if (player.audio.state.status == AudioPlayerStatus.Idle) {
|
||||||
|
await interaction.editReply("Can't skip, there is no music");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await player.skip();
|
||||||
|
await interaction.followUp("Music skipped");
|
||||||
|
}
|
||||||
|
}
|
42
src/modules/Music/stop.ts
Normal file
42
src/modules/Music/stop.ts
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
import {Command} from "../../lib/Command";
|
||||||
|
import {ChatInputApplicationCommandData, CommandInteraction, GuildMember} from "discord.js";
|
||||||
|
import {Music} from "./index";
|
||||||
|
import {AudioPlayerStatus} from "@discordjs/voice";
|
||||||
|
|
||||||
|
|
||||||
|
export class StopCommand extends Command {
|
||||||
|
data: ChatInputApplicationCommandData = {
|
||||||
|
name: "stop",
|
||||||
|
description: "Stop the music"
|
||||||
|
};
|
||||||
|
module: Music;
|
||||||
|
|
||||||
|
constructor(module: Music) {
|
||||||
|
super(module);
|
||||||
|
this.module = module;
|
||||||
|
}
|
||||||
|
|
||||||
|
async execute(interaction: CommandInteraction) {
|
||||||
|
await interaction.deferReply();
|
||||||
|
if (!interaction.guild || ! (interaction.member instanceof GuildMember)) {
|
||||||
|
await interaction.editReply("This command is only usable in a guild :/");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let player = this.module.players.get(interaction.guild.id);
|
||||||
|
|
||||||
|
if (!player) {
|
||||||
|
await interaction.editReply("No music currently playing !");
|
||||||
|
return;
|
||||||
|
} else if (interaction.member.voice.channelId != player.connexion.joinConfig.channelId) {
|
||||||
|
await interaction.editReply("You must be in the same voice channel !");
|
||||||
|
return;
|
||||||
|
} else if (player.audio.state.status == AudioPlayerStatus.Idle) {
|
||||||
|
await interaction.editReply("Can't stop, there is no music");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
player.stop();
|
||||||
|
await interaction.followUp("Music stopped");
|
||||||
|
}
|
||||||
|
}
|
|
@ -8,6 +8,7 @@ import {
|
||||||
TextChannel,
|
TextChannel,
|
||||||
VoiceChannel
|
VoiceChannel
|
||||||
} from "discord.js";
|
} from "discord.js";
|
||||||
|
|
||||||
const {Constants: { ApplicationCommandOptionTypes }} = require("discord.js");
|
const {Constants: { ApplicationCommandOptionTypes }} = require("discord.js");
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
"lib": ["es2021"],
|
"lib": ["es2021"],
|
||||||
"module": "commonjs",
|
"module": "commonjs",
|
||||||
"target": "es2021",
|
"target": "es2021",
|
||||||
|
"outDir": "build",
|
||||||
"strict": true,
|
"strict": true,
|
||||||
"esModuleInterop": true,
|
"esModuleInterop": true,
|
||||||
"skipLibCheck": true,
|
"skipLibCheck": true,
|
||||||
|
|
Loading…
Reference in a new issue