diff --git a/.env-example b/.env-example new file mode 100644 index 0000000..82e3412 --- /dev/null +++ b/.env-example @@ -0,0 +1,6 @@ +TOKEN=TOKEN_HERE +DEVTOKEN=DEV_TOKEN_HERE +SOUNDCLOUD_CLIENT_ID=CLIENT_ID_HERE +SPOTIFY_SECRET_ID=SECRET_ID_HERE +SPOTIFY_CLIENT_ID=CLIENT_ID_HERE +SPOTIFY_REFRESH_TOKEN=REFRESH_TOKEN_HERE \ No newline at end of file diff --git a/README.md b/README.md index 8c59023..5bae683 100644 --- a/README.md +++ b/README.md @@ -22,9 +22,10 @@ - Install latest Node.JS LTS and Git. - Install the bot's dependencies (pnpm, npm or whatever you use). -- Modify the `Bot.ts` and `config.ts` files in `./src/components/` for your bot's configuration. +- Modify the `Bot.ts`files in `./src/components/` for your bot's configuration. +- Either make a `.env` file based off the config in `.env-example` or configure the `config.ts` in `./src/components/` for your bot. - Run the `build` script. -- Run the `bundle.js` output file in the `dist` folder. +- Run the `bundle.js` output file in the `dist` folder or the `start` script. ## 🛠️ Contributions diff --git a/build.mjs b/build.mjs new file mode 100644 index 0000000..65044e1 --- /dev/null +++ b/build.mjs @@ -0,0 +1,51 @@ +import { execSync } from "child_process"; +import { version } from "typescript" +import { buildSync } from "esbuild"; + +function hash() { + try { + return execSync("git rev-parse --short HEAD").toString().trim(); + } catch (e) { + return "null"; + } +} + +try { + console.log("Building Music Bot..."); + + buildSync({ + entryPoints: ["src/index.ts"], + bundle: true, + packages: "external", + platform: "node", + target: "node22", + format: "esm", + minify: true, + minifyIdentifiers: true, + minifySyntax: true, + minifyWhitespace: true, + mangleQuoted: true, + ignoreAnnotations: true, + treeShaking: true, + outfile: "dist/bundle.js", + define: { + __VERSION__: `"${hash()}"`, + __TYPESCRIPTVERSION__: `"${version}"` + }, + }); + + console.log("Successfully built Music Bot!"); +} catch (err) { + console.error(`Failed to build Music Bot:\n ${err}`); + process.exit(1); +} + + +if (process.argv.includes("--run")) { + console.log("Running Music Bot bundle..."); + try { + execSync("node ./dist/bundle.js", { stdio: "inherit" }); + } catch (_x) { + console.log("Music Bot closed."); + } +} \ No newline at end of file diff --git a/package.json b/package.json index e99737f..6716387 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "music-bot", - "version": "3.3.2", + "version": "3.4.0", "description": "A general music Discord bot.", "main": "./src/bot.ts", "type": "module", @@ -22,30 +22,25 @@ "array-move": "^4.0.0", "bufferutil": "^4.0.8", "chalk": "^5.3.0", - "discord.js": "^14.15.2", + "discord.js": "^14.16.2", + "dotenv": "^16.4.5", "ffmpeg-static": "^5.2.0", "opusscript": "^0.1.1", "play-dl": "^1.9.7", - "sodium-native": "^4.1.1", + "sodium-native": "^4.2.0", "string-progressbar": "^1.0.4", "utf-8-validate": "^6.0.4" }, "devDependencies": { - "@rollup/plugin-typescript": "^11.1.6", - "@types/node": "^20.12.12", - "esbuild": "^0.21.3", - "rollup": "^4.18.0", - "rollup-plugin-esbuild": "^6.1.1", - "rollup-plugin-typescript-paths": "^1.5.0", - "tslib": "^2.6.2", - "typescript": "^5.4.5" + "@types/node": "^20.16.5", + "esbuild": "^0.23.1", + "typescript": "^5.6.2" }, "scripts": { "start": "node ./dist/bundle.js", - "startb": "rollup -c --configPlugin @rollup/plugin-typescript && node ./dist/bundle.js", + "dev": "node build.mjs --run", "lint": "eslint . --fix", - "build": "rollup -c --configPlugin @rollup/plugin-typescript" + "build": "node build.mjs" }, - "keywords": [], "license": "GPL-3.0" } \ No newline at end of file diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index aac3609..3bbfaa8 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -24,8 +24,11 @@ importers: specifier: ^5.3.0 version: 5.3.0 discord.js: - specifier: ^14.15.2 - version: 14.15.2(bufferutil@4.0.8)(utf-8-validate@6.0.4) + specifier: ^14.16.2 + version: 14.16.2(bufferutil@4.0.8)(utf-8-validate@6.0.4) + dotenv: + specifier: ^16.4.5 + version: 16.4.5 ffmpeg-static: specifier: ^5.2.0 version: 5.2.0 @@ -45,30 +48,15 @@ importers: specifier: ^6.0.4 version: 6.0.4 devDependencies: - '@rollup/plugin-typescript': - specifier: ^11.1.6 - version: 11.1.6(rollup@4.18.0)(tslib@2.6.2)(typescript@5.4.5) '@types/node': - specifier: ^20.12.12 - version: 20.12.12 + specifier: ^20.16.5 + version: 20.16.5 esbuild: - specifier: ^0.21.3 - version: 0.21.3 - rollup: - specifier: ^4.18.0 - version: 4.18.0 - rollup-plugin-esbuild: - specifier: ^6.1.1 - version: 6.1.1(esbuild@0.21.3)(rollup@4.18.0) - rollup-plugin-typescript-paths: - specifier: ^1.5.0 - version: 1.5.0(typescript@5.4.5) - tslib: - specifier: ^2.6.2 - version: 2.6.2 + specifier: ^0.23.1 + version: 0.23.1 typescript: - specifier: ^5.4.5 - version: 5.4.5 + specifier: ^5.6.2 + version: 5.6.2 packages: @@ -76,9 +64,9 @@ packages: resolution: {integrity: sha512-F9rL9k9Xjf5blCz8HsJRO4diy111cayL2vkY2XE4r4t3n0yPXVYy3KD3nJ1qbrSn9743UWSXH4IwuCa/HWlGFw==} engines: {node: '>=6.0.0'} - '@discordjs/builders@1.8.1': - resolution: {integrity: sha512-GkF+HM01FHy+NSoTaUPR8z44otfQgJ1AIsRxclYGUZDyUbdZEFyD/5QVv2Y1Flx6M+B0bQLzg2M9CJv5lGTqpA==} - engines: {node: '>=16.11.0'} + '@discordjs/builders@1.9.0': + resolution: {integrity: sha512-0zx8DePNVvQibh5ly5kCEei5wtPBIUbSoE9n+91Rlladz4tgtFbJ36PZMxxZrTEOQ7AHMZ/b0crT/0fCy6FTKg==} + engines: {node: '>=18'} '@discordjs/collection@1.5.3': resolution: {integrity: sha512-SVb428OMd3WO1paV3rm6tSjM4wC+Kecaa1EUGX7vc6/fddvw/6lg90z4QtCqm21zvVe92vMMDt9+DkIvjXImQQ==} @@ -88,161 +76,171 @@ packages: resolution: {integrity: sha512-mLcTACtXUuVgutoznkh6hS3UFqYirDYAg5Dc1m8xn6OvPjetnUlf/xjtqnnc47OwWdaoCQnHmHh9KofhD6uRqw==} engines: {node: '>=18'} - '@discordjs/formatters@0.4.0': - resolution: {integrity: sha512-fJ06TLC1NiruF35470q3Nr1bi95BdvKFAF+T5bNfZJ4bNdqZ3VZ+Ttg6SThqTxm6qumSG3choxLBHMC69WXNXQ==} - engines: {node: '>=16.11.0'} + '@discordjs/collection@2.1.1': + resolution: {integrity: sha512-LiSusze9Tc7qF03sLCujF5iZp7K+vRNEDBZ86FT9aQAv3vxMLihUvKvpsCWiQ2DJq1tVckopKm1rxomgNUc9hg==} + engines: {node: '>=18'} - '@discordjs/rest@2.3.0': - resolution: {integrity: sha512-C1kAJK8aSYRv3ZwMG8cvrrW4GN0g5eMdP8AuN8ODH5DyOCbHgJspze1my3xHOAgwLJdKUbWNVyAeJ9cEdduqIg==} - engines: {node: '>=16.11.0'} + '@discordjs/formatters@0.5.0': + resolution: {integrity: sha512-98b3i+Y19RFq1Xke4NkVY46x8KjJQjldHUuEbCqMvp1F5Iq9HgnGpu91jOi/Ufazhty32eRsKnnzS8n4c+L93g==} + engines: {node: '>=18'} - '@discordjs/util@1.1.0': - resolution: {integrity: sha512-IndcI5hzlNZ7GS96RV3Xw1R2kaDuXEp7tRIy/KlhidpN/BQ1qh1NZt3377dMLTa44xDUNKT7hnXkA/oUAzD/lg==} - engines: {node: '>=16.11.0'} + '@discordjs/rest@2.4.0': + resolution: {integrity: sha512-Xb2irDqNcq+O8F0/k/NaDp7+t091p+acb51iA4bCKfIn+WFWd6HrNvcsSbMMxIR9NjcMZS6NReTKygqiQN+ntw==} + engines: {node: '>=18'} + + '@discordjs/util@1.1.1': + resolution: {integrity: sha512-eddz6UnOBEB1oITPinyrB2Pttej49M9FZQY8NxgEvc3tq6ZICZ19m70RsmzRdDHk80O9NoYN/25AqJl8vPVf/g==} + engines: {node: '>=18'} '@discordjs/voice@0.17.0': resolution: {integrity: sha512-hArn9FF5ZYi1IkxdJEVnJi+OxlwLV0NJYWpKXsmNOojtGtAZHxmsELA+MZlu2KW1F/K1/nt7lFOfcMXNYweq9w==} engines: {node: '>=16.11.0'} - '@discordjs/ws@1.1.0': - resolution: {integrity: sha512-O97DIeSvfNTn5wz5vaER6ciyUsr7nOqSEtsLoMhhIgeFkhnxLRqSr00/Fpq2/ppLgjDGLbQCDzIK7ilGoB/M7A==} + '@discordjs/ws@1.1.1': + resolution: {integrity: sha512-PZ+vLpxGCRtmr2RMkqh8Zp+BenUaJqlS6xhgWKEZcgC/vfHLEzpHtKkB0sl3nZWpwtcKk6YWy+pU3okL2I97FA==} engines: {node: '>=16.11.0'} - '@esbuild/aix-ppc64@0.21.3': - resolution: {integrity: sha512-yTgnwQpFVYfvvo4SvRFB0SwrW8YjOxEoT7wfMT7Ol5v7v5LDNvSGo67aExmxOb87nQNeWPVvaGBNfQ7BXcrZ9w==} - engines: {node: '>=12'} + '@esbuild/aix-ppc64@0.23.1': + resolution: {integrity: sha512-6VhYk1diRqrhBAqpJEdjASR/+WVRtfjpqKuNw11cLiaWpAT/Uu+nokB+UJnevzy/P9C/ty6AOe0dwueMrGh/iQ==} + engines: {node: '>=18'} cpu: [ppc64] os: [aix] - '@esbuild/android-arm64@0.21.3': - resolution: {integrity: sha512-c+ty9necz3zB1Y+d/N+mC6KVVkGUUOcm4ZmT5i/Fk5arOaY3i6CA3P5wo/7+XzV8cb4GrI/Zjp8NuOQ9Lfsosw==} - engines: {node: '>=12'} + '@esbuild/android-arm64@0.23.1': + resolution: {integrity: sha512-xw50ipykXcLstLeWH7WRdQuysJqejuAGPd30vd1i5zSyKK3WE+ijzHmLKxdiCMtH1pHz78rOg0BKSYOSB/2Khw==} + engines: {node: '>=18'} cpu: [arm64] os: [android] - '@esbuild/android-arm@0.21.3': - resolution: {integrity: sha512-bviJOLMgurLJtF1/mAoJLxDZDL6oU5/ztMHnJQRejbJrSc9FFu0QoUoFhvi6qSKJEw9y5oGyvr9fuDtzJ30rNQ==} - engines: {node: '>=12'} + '@esbuild/android-arm@0.23.1': + resolution: {integrity: sha512-uz6/tEy2IFm9RYOyvKl88zdzZfwEfKZmnX9Cj1BHjeSGNuGLuMD1kR8y5bteYmwqKm1tj8m4cb/aKEorr6fHWQ==} + engines: {node: '>=18'} cpu: [arm] os: [android] - '@esbuild/android-x64@0.21.3': - resolution: {integrity: sha512-JReHfYCRK3FVX4Ra+y5EBH1b9e16TV2OxrPAvzMsGeES0X2Ndm9ImQRI4Ket757vhc5XBOuGperw63upesclRw==} - engines: {node: '>=12'} + '@esbuild/android-x64@0.23.1': + resolution: {integrity: sha512-nlN9B69St9BwUoB+jkyU090bru8L0NA3yFvAd7k8dNsVH8bi9a8cUAUSEcEEgTp2z3dbEDGJGfP6VUnkQnlReg==} + engines: {node: '>=18'} cpu: [x64] os: [android] - '@esbuild/darwin-arm64@0.21.3': - resolution: {integrity: sha512-U3fuQ0xNiAkXOmQ6w5dKpEvXQRSpHOnbw7gEfHCRXPeTKW9sBzVck6C5Yneb8LfJm0l6le4NQfkNPnWMSlTFUQ==} - engines: {node: '>=12'} + '@esbuild/darwin-arm64@0.23.1': + resolution: {integrity: sha512-YsS2e3Wtgnw7Wq53XXBLcV6JhRsEq8hkfg91ESVadIrzr9wO6jJDMZnCQbHm1Guc5t/CdDiFSSfWP58FNuvT3Q==} + engines: {node: '>=18'} cpu: [arm64] os: [darwin] - '@esbuild/darwin-x64@0.21.3': - resolution: {integrity: sha512-3m1CEB7F07s19wmaMNI2KANLcnaqryJxO1fXHUV5j1rWn+wMxdUYoPyO2TnAbfRZdi7ADRwJClmOwgT13qlP3Q==} - engines: {node: '>=12'} + '@esbuild/darwin-x64@0.23.1': + resolution: {integrity: sha512-aClqdgTDVPSEGgoCS8QDG37Gu8yc9lTHNAQlsztQ6ENetKEO//b8y31MMu2ZaPbn4kVsIABzVLXYLhCGekGDqw==} + engines: {node: '>=18'} cpu: [x64] os: [darwin] - '@esbuild/freebsd-arm64@0.21.3': - resolution: {integrity: sha512-fsNAAl5pU6wmKHq91cHWQT0Fz0vtyE1JauMzKotrwqIKAswwP5cpHUCxZNSTuA/JlqtScq20/5KZ+TxQdovU/g==} - engines: {node: '>=12'} + '@esbuild/freebsd-arm64@0.23.1': + resolution: {integrity: sha512-h1k6yS8/pN/NHlMl5+v4XPfikhJulk4G+tKGFIOwURBSFzE8bixw1ebjluLOjfwtLqY0kewfjLSrO6tN2MgIhA==} + engines: {node: '>=18'} cpu: [arm64] os: [freebsd] - '@esbuild/freebsd-x64@0.21.3': - resolution: {integrity: sha512-tci+UJ4zP5EGF4rp8XlZIdq1q1a/1h9XuronfxTMCNBslpCtmk97Q/5qqy1Mu4zIc0yswN/yP/BLX+NTUC1bXA==} - engines: {node: '>=12'} + '@esbuild/freebsd-x64@0.23.1': + resolution: {integrity: sha512-lK1eJeyk1ZX8UklqFd/3A60UuZ/6UVfGT2LuGo3Wp4/z7eRTRYY+0xOu2kpClP+vMTi9wKOfXi2vjUpO1Ro76g==} + engines: {node: '>=18'} cpu: [x64] os: [freebsd] - '@esbuild/linux-arm64@0.21.3': - resolution: {integrity: sha512-vvG6R5g5ieB4eCJBQevyDMb31LMHthLpXTc2IGkFnPWS/GzIFDnaYFp558O+XybTmYrVjxnryru7QRleJvmZ6Q==} - engines: {node: '>=12'} + '@esbuild/linux-arm64@0.23.1': + resolution: {integrity: sha512-/93bf2yxencYDnItMYV/v116zff6UyTjo4EtEQjUBeGiVpMmffDNUyD9UN2zV+V3LRV3/on4xdZ26NKzn6754g==} + engines: {node: '>=18'} cpu: [arm64] os: [linux] - '@esbuild/linux-arm@0.21.3': - resolution: {integrity: sha512-f6kz2QpSuyHHg01cDawj0vkyMwuIvN62UAguQfnNVzbge2uWLhA7TCXOn83DT0ZvyJmBI943MItgTovUob36SQ==} - engines: {node: '>=12'} + '@esbuild/linux-arm@0.23.1': + resolution: {integrity: sha512-CXXkzgn+dXAPs3WBwE+Kvnrf4WECwBdfjfeYHpMeVxWE0EceB6vhWGShs6wi0IYEqMSIzdOF1XjQ/Mkm5d7ZdQ==} + engines: {node: '>=18'} cpu: [arm] os: [linux] - '@esbuild/linux-ia32@0.21.3': - resolution: {integrity: sha512-HjCWhH7K96Na+66TacDLJmOI9R8iDWDDiqe17C7znGvvE4sW1ECt9ly0AJ3dJH62jHyVqW9xpxZEU1jKdt+29A==} - engines: {node: '>=12'} + '@esbuild/linux-ia32@0.23.1': + resolution: {integrity: sha512-VTN4EuOHwXEkXzX5nTvVY4s7E/Krz7COC8xkftbbKRYAl96vPiUssGkeMELQMOnLOJ8k3BY1+ZY52tttZnHcXQ==} + engines: {node: '>=18'} cpu: [ia32] os: [linux] - '@esbuild/linux-loong64@0.21.3': - resolution: {integrity: sha512-BGpimEccmHBZRcAhdlRIxMp7x9PyJxUtj7apL2IuoG9VxvU/l/v1z015nFs7Si7tXUwEsvjc1rOJdZCn4QTU+Q==} - engines: {node: '>=12'} + '@esbuild/linux-loong64@0.23.1': + resolution: {integrity: sha512-Vx09LzEoBa5zDnieH8LSMRToj7ir/Jeq0Gu6qJ/1GcBq9GkfoEAoXvLiW1U9J1qE/Y/Oyaq33w5p2ZWrNNHNEw==} + engines: {node: '>=18'} cpu: [loong64] os: [linux] - '@esbuild/linux-mips64el@0.21.3': - resolution: {integrity: sha512-5rMOWkp7FQGtAH3QJddP4w3s47iT20hwftqdm7b+loe95o8JU8ro3qZbhgMRy0VuFU0DizymF1pBKkn3YHWtsw==} - engines: {node: '>=12'} + '@esbuild/linux-mips64el@0.23.1': + resolution: {integrity: sha512-nrFzzMQ7W4WRLNUOU5dlWAqa6yVeI0P78WKGUo7lg2HShq/yx+UYkeNSE0SSfSure0SqgnsxPvmAUu/vu0E+3Q==} + engines: {node: '>=18'} cpu: [mips64el] os: [linux] - '@esbuild/linux-ppc64@0.21.3': - resolution: {integrity: sha512-h0zj1ldel89V5sjPLo5H1SyMzp4VrgN1tPkN29TmjvO1/r0MuMRwJxL8QY05SmfsZRs6TF0c/IDH3u7XYYmbAg==} - engines: {node: '>=12'} + '@esbuild/linux-ppc64@0.23.1': + resolution: {integrity: sha512-dKN8fgVqd0vUIjxuJI6P/9SSSe/mB9rvA98CSH2sJnlZ/OCZWO1DJvxj8jvKTfYUdGfcq2dDxoKaC6bHuTlgcw==} + engines: {node: '>=18'} cpu: [ppc64] os: [linux] - '@esbuild/linux-riscv64@0.21.3': - resolution: {integrity: sha512-dkAKcTsTJ+CRX6bnO17qDJbLoW37npd5gSNtSzjYQr0svghLJYGYB0NF1SNcU1vDcjXLYS5pO4qOW4YbFama4A==} - engines: {node: '>=12'} + '@esbuild/linux-riscv64@0.23.1': + resolution: {integrity: sha512-5AV4Pzp80fhHL83JM6LoA6pTQVWgB1HovMBsLQ9OZWLDqVY8MVobBXNSmAJi//Csh6tcY7e7Lny2Hg1tElMjIA==} + engines: {node: '>=18'} cpu: [riscv64] os: [linux] - '@esbuild/linux-s390x@0.21.3': - resolution: {integrity: sha512-vnD1YUkovEdnZWEuMmy2X2JmzsHQqPpZElXx6dxENcIwTu+Cu5ERax6+Ke1QsE814Zf3c6rxCfwQdCTQ7tPuXA==} - engines: {node: '>=12'} + '@esbuild/linux-s390x@0.23.1': + resolution: {integrity: sha512-9ygs73tuFCe6f6m/Tb+9LtYxWR4c9yg7zjt2cYkjDbDpV/xVn+68cQxMXCjUpYwEkze2RcU/rMnfIXNRFmSoDw==} + engines: {node: '>=18'} cpu: [s390x] os: [linux] - '@esbuild/linux-x64@0.21.3': - resolution: {integrity: sha512-IOXOIm9WaK7plL2gMhsWJd+l2bfrhfilv0uPTptoRoSb2p09RghhQQp9YY6ZJhk/kqmeRt6siRdMSLLwzuT0KQ==} - engines: {node: '>=12'} + '@esbuild/linux-x64@0.23.1': + resolution: {integrity: sha512-EV6+ovTsEXCPAp58g2dD68LxoP/wK5pRvgy0J/HxPGB009omFPv3Yet0HiaqvrIrgPTBuC6wCH1LTOY91EO5hQ==} + engines: {node: '>=18'} cpu: [x64] os: [linux] - '@esbuild/netbsd-x64@0.21.3': - resolution: {integrity: sha512-uTgCwsvQ5+vCQnqM//EfDSuomo2LhdWhFPS8VL8xKf+PKTCrcT/2kPPoWMTs22aB63MLdGMJiE3f1PHvCDmUOw==} - engines: {node: '>=12'} + '@esbuild/netbsd-x64@0.23.1': + resolution: {integrity: sha512-aevEkCNu7KlPRpYLjwmdcuNz6bDFiE7Z8XC4CPqExjTvrHugh28QzUXVOZtiYghciKUacNktqxdpymplil1beA==} + engines: {node: '>=18'} cpu: [x64] os: [netbsd] - '@esbuild/openbsd-x64@0.21.3': - resolution: {integrity: sha512-vNAkR17Ub2MgEud2Wag/OE4HTSI6zlb291UYzHez/psiKarp0J8PKGDnAhMBcHFoOHMXHfExzmjMojJNbAStrQ==} - engines: {node: '>=12'} + '@esbuild/openbsd-arm64@0.23.1': + resolution: {integrity: sha512-3x37szhLexNA4bXhLrCC/LImN/YtWis6WXr1VESlfVtVeoFJBRINPJ3f0a/6LV8zpikqoUg4hyXw0sFBt5Cr+Q==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + + '@esbuild/openbsd-x64@0.23.1': + resolution: {integrity: sha512-aY2gMmKmPhxfU+0EdnN+XNtGbjfQgwZj43k8G3fyrDM/UdZww6xrWxmDkuz2eCZchqVeABjV5BpildOrUbBTqA==} + engines: {node: '>=18'} cpu: [x64] os: [openbsd] - '@esbuild/sunos-x64@0.21.3': - resolution: {integrity: sha512-W8H9jlGiSBomkgmouaRoTXo49j4w4Kfbl6I1bIdO/vT0+0u4f20ko3ELzV3hPI6XV6JNBVX+8BC+ajHkvffIJA==} - engines: {node: '>=12'} + '@esbuild/sunos-x64@0.23.1': + resolution: {integrity: sha512-RBRT2gqEl0IKQABT4XTj78tpk9v7ehp+mazn2HbUeZl1YMdaGAQqhapjGTCe7uw7y0frDi4gS0uHzhvpFuI1sA==} + engines: {node: '>=18'} cpu: [x64] os: [sunos] - '@esbuild/win32-arm64@0.21.3': - resolution: {integrity: sha512-EjEomwyLSCg8Ag3LDILIqYCZAq/y3diJ04PnqGRgq8/4O3VNlXyMd54j/saShaN4h5o5mivOjAzmU6C3X4v0xw==} - engines: {node: '>=12'} + '@esbuild/win32-arm64@0.23.1': + resolution: {integrity: sha512-4O+gPR5rEBe2FpKOVyiJ7wNDPA8nGzDuJ6gN4okSA1gEOYZ67N8JPk58tkWtdtPeLz7lBnY6I5L3jdsr3S+A6A==} + engines: {node: '>=18'} cpu: [arm64] os: [win32] - '@esbuild/win32-ia32@0.21.3': - resolution: {integrity: sha512-WGiE/GgbsEwR33++5rzjiYsKyHywE8QSZPF7Rfx9EBfK3Qn3xyR6IjyCr5Uk38Kg8fG4/2phN7sXp4NPWd3fcw==} - engines: {node: '>=12'} + '@esbuild/win32-ia32@0.23.1': + resolution: {integrity: sha512-BcaL0Vn6QwCwre3Y717nVHZbAa4UBEigzFm6VdsVdT/MbZ38xoj1X9HPkZhbmaBGUD1W8vxAfffbDe8bA6AKnQ==} + engines: {node: '>=18'} cpu: [ia32] os: [win32] - '@esbuild/win32-x64@0.21.3': - resolution: {integrity: sha512-xRxC0jaJWDLYvcUvjQmHCJSfMrgmUuvsoXgDeU/wTorQ1ngDdUBuFtgY3W1Pc5sprGAvZBtWdJX7RPg/iZZUqA==} - engines: {node: '>=12'} + '@esbuild/win32-x64@0.23.1': + resolution: {integrity: sha512-BHpFFeslkWrXWyUPnbKm+xYYVYruCinGcftSBaa8zoF9hZO4BcSCFUvHVTtzpIY6YzUnYtuEhZ+C9iEXjxnasg==} + engines: {node: '>=18'} cpu: [x64] os: [win32] @@ -250,128 +248,27 @@ packages: resolution: {integrity: sha512-20jz6LtMqq6cQlOh5LYdrtPR7NmkPQD1LbQx0ZJw+AABbBCcqnILi/qbDNkA8dGgzMXotvgoaG4qfyijnmxnFg==} engines: {node: '>=12'} - '@rollup/plugin-typescript@11.1.6': - resolution: {integrity: sha512-R92yOmIACgYdJ7dJ97p4K69I8gg6IEHt8M7dUBxN3W6nrO8uUxX5ixl0yU/N3aZTi8WhPuICvOHXQvF6FaykAA==} - engines: {node: '>=14.0.0'} - peerDependencies: - rollup: ^2.14.0||^3.0.0||^4.0.0 - tslib: '*' - typescript: '>=3.7.0' - peerDependenciesMeta: - rollup: - optional: true - tslib: - optional: true - - '@rollup/pluginutils@5.1.0': - resolution: {integrity: sha512-XTIWOPPcpvyKI6L1NHo0lFlCyznUEyPmPY1mc3KpPVDYulHSTvyeLNVW00QTLIAFNhR3kYnJTQHeGqU4M3n09g==} - engines: {node: '>=14.0.0'} - peerDependencies: - rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 - peerDependenciesMeta: - rollup: - optional: true - - '@rollup/rollup-android-arm-eabi@4.18.0': - resolution: {integrity: sha512-Tya6xypR10giZV1XzxmH5wr25VcZSncG0pZIjfePT0OVBvqNEurzValetGNarVrGiq66EBVAFn15iYX4w6FKgQ==} - cpu: [arm] - os: [android] - - '@rollup/rollup-android-arm64@4.18.0': - resolution: {integrity: sha512-avCea0RAP03lTsDhEyfy+hpfr85KfyTctMADqHVhLAF3MlIkq83CP8UfAHUssgXTYd+6er6PaAhx/QGv4L1EiA==} - cpu: [arm64] - os: [android] - - '@rollup/rollup-darwin-arm64@4.18.0': - resolution: {integrity: sha512-IWfdwU7KDSm07Ty0PuA/W2JYoZ4iTj3TUQjkVsO/6U+4I1jN5lcR71ZEvRh52sDOERdnNhhHU57UITXz5jC1/w==} - cpu: [arm64] - os: [darwin] - - '@rollup/rollup-darwin-x64@4.18.0': - resolution: {integrity: sha512-n2LMsUz7Ynu7DoQrSQkBf8iNrjOGyPLrdSg802vk6XT3FtsgX6JbE8IHRvposskFm9SNxzkLYGSq9QdpLYpRNA==} - cpu: [x64] - os: [darwin] - - '@rollup/rollup-linux-arm-gnueabihf@4.18.0': - resolution: {integrity: sha512-C/zbRYRXFjWvz9Z4haRxcTdnkPt1BtCkz+7RtBSuNmKzMzp3ZxdM28Mpccn6pt28/UWUCTXa+b0Mx1k3g6NOMA==} - cpu: [arm] - os: [linux] - - '@rollup/rollup-linux-arm-musleabihf@4.18.0': - resolution: {integrity: sha512-l3m9ewPgjQSXrUMHg93vt0hYCGnrMOcUpTz6FLtbwljo2HluS4zTXFy2571YQbisTnfTKPZ01u/ukJdQTLGh9A==} - cpu: [arm] - os: [linux] - - '@rollup/rollup-linux-arm64-gnu@4.18.0': - resolution: {integrity: sha512-rJ5D47d8WD7J+7STKdCUAgmQk49xuFrRi9pZkWoRD1UeSMakbcepWXPF8ycChBoAqs1pb2wzvbY6Q33WmN2ftw==} - cpu: [arm64] - os: [linux] - - '@rollup/rollup-linux-arm64-musl@4.18.0': - resolution: {integrity: sha512-be6Yx37b24ZwxQ+wOQXXLZqpq4jTckJhtGlWGZs68TgdKXJgw54lUUoFYrg6Zs/kjzAQwEwYbp8JxZVzZLRepQ==} - cpu: [arm64] - os: [linux] - - '@rollup/rollup-linux-powerpc64le-gnu@4.18.0': - resolution: {integrity: sha512-hNVMQK+qrA9Todu9+wqrXOHxFiD5YmdEi3paj6vP02Kx1hjd2LLYR2eaN7DsEshg09+9uzWi2W18MJDlG0cxJA==} - cpu: [ppc64] - os: [linux] - - '@rollup/rollup-linux-riscv64-gnu@4.18.0': - resolution: {integrity: sha512-ROCM7i+m1NfdrsmvwSzoxp9HFtmKGHEqu5NNDiZWQtXLA8S5HBCkVvKAxJ8U+CVctHwV2Gb5VUaK7UAkzhDjlg==} - cpu: [riscv64] - os: [linux] - - '@rollup/rollup-linux-s390x-gnu@4.18.0': - resolution: {integrity: sha512-0UyyRHyDN42QL+NbqevXIIUnKA47A+45WyasO+y2bGJ1mhQrfrtXUpTxCOrfxCR4esV3/RLYyucGVPiUsO8xjg==} - cpu: [s390x] - os: [linux] - - '@rollup/rollup-linux-x64-gnu@4.18.0': - resolution: {integrity: sha512-xuglR2rBVHA5UsI8h8UbX4VJ470PtGCf5Vpswh7p2ukaqBGFTnsfzxUBetoWBWymHMxbIG0Cmx7Y9qDZzr648w==} - cpu: [x64] - os: [linux] - - '@rollup/rollup-linux-x64-musl@4.18.0': - resolution: {integrity: sha512-LKaqQL9osY/ir2geuLVvRRs+utWUNilzdE90TpyoX0eNqPzWjRm14oMEE+YLve4k/NAqCdPkGYDaDF5Sw+xBfg==} - cpu: [x64] - os: [linux] - - '@rollup/rollup-win32-arm64-msvc@4.18.0': - resolution: {integrity: sha512-7J6TkZQFGo9qBKH0pk2cEVSRhJbL6MtfWxth7Y5YmZs57Pi+4x6c2dStAUvaQkHQLnEQv1jzBUW43GvZW8OFqA==} - cpu: [arm64] - os: [win32] - - '@rollup/rollup-win32-ia32-msvc@4.18.0': - resolution: {integrity: sha512-Txjh+IxBPbkUB9+SXZMpv+b/vnTEtFyfWZgJ6iyCmt2tdx0OF5WhFowLmnh8ENGNpfUlUZkdI//4IEmhwPieNg==} - cpu: [ia32] - os: [win32] - - '@rollup/rollup-win32-x64-msvc@4.18.0': - resolution: {integrity: sha512-UOo5FdvOL0+eIVTgS4tIdbW+TtnBLWg1YBCcU2KWM7nuNwRz9bksDX1bekJJCpu25N1DVWaCwnT39dVQxzqS8g==} - cpu: [x64] - os: [win32] - '@sapphire/async-queue@1.5.2': resolution: {integrity: sha512-7X7FFAA4DngXUl95+hYbUF19bp1LGiffjJtu7ygrZrbdCSsdDDBaSjB7Akw0ZbOu6k0xpXyljnJ6/RZUvLfRdg==} engines: {node: '>=v14.0.0', npm: '>=7.0.0'} - '@sapphire/shapeshift@3.9.7': - resolution: {integrity: sha512-4It2mxPSr4OGn4HSQWGmhFMsNFGfFVhWeRPCRwbH972Ek2pzfGRZtb0pJ4Ze6oIzcyh2jw7nUDa6qGlWofgd9g==} + '@sapphire/async-queue@1.5.3': + resolution: {integrity: sha512-x7zadcfJGxFka1Q3f8gCts1F0xMwCKbZweM85xECGI0hBTeIZJGGCrHgLggihBoprlQ/hBmDR5LKfIPqnmHM3w==} + engines: {node: '>=v14.0.0', npm: '>=7.0.0'} + + '@sapphire/shapeshift@4.0.0': + resolution: {integrity: sha512-d9dUmWVA7MMiKobL3VpLF8P2aeanRTu6ypG2OIaEv/ZHH/SUQ2iHOVyi5wAPjQ+HmnMuL0whK9ez8I/raWbtIg==} engines: {node: '>=v16'} '@sapphire/snowflake@3.5.3': resolution: {integrity: sha512-jjmJywLAFoWeBi1W7994zZyiNWPIiqRRNAmSERxyg93xRGzNYvGjlZ0gR6x0F4gPRi2+0O6S71kOZYyr3cxaIQ==} engines: {node: '>=v14.0.0', npm: '>=7.0.0'} - '@types/estree@1.0.5': - resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==} - '@types/node@10.17.60': resolution: {integrity: sha512-F0KIgDJfy2nA3zMLmWGKxcH2ZVEtCZXHHdOQs2gSaQ27+lNeEfGxzkIw90aXswATX7AZ33tahPbzy6KAfUreVw==} - '@types/node@20.12.12': - resolution: {integrity: sha512-eWLDGF/FOSPtAvEqeRAQ4C8LSA7M1I7i0ky1I8U7kD1J5ITyW3AsRhQrKVoWf5pFKZ2kILsEGJhsI9r93PYnOw==} + '@types/node@20.16.5': + resolution: {integrity: sha512-VwYCweNo3ERajwy0IUlqqcyZ8/A7Zwa9ZP3MnENWcB11AejO+tLy3pu850goUW2FC/IJMdZUfKpX/yxL1gymCA==} '@types/ws@8.5.10': resolution: {integrity: sha512-vmQSUcfalpIq0R9q7uTo2lXs6eGIpt9wtnLdMv9LVpIjCA/+ufZRozlVoVelIYixx1ugCBKDhn89vnsEGOCx9A==} @@ -380,6 +277,10 @@ packages: resolution: {integrity: sha512-ButUPz9E9cXMLgvAW8aLAKKJJsPu1dY1/l/E8xzLFuysowXygs6GBcyunK9rnGC4zTsnIc2mQo71rGw9U+Ykug==} engines: {node: '>=v14.0.0', npm: '>=7.0.0'} + '@vladfrangu/async_event_emitter@2.4.6': + resolution: {integrity: sha512-RaI5qZo6D2CVS6sTHFKg1v5Ohq/+Bo2LZ5gzUEwZ/WkHhwtGTCB/sVLw8ijOkAUxasZ+WshN/Rzj4ywsABJ5ZA==} + engines: {node: '>=v14.0.0', npm: '>=7.0.0'} + agent-base@6.0.2: resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} engines: {node: '>= 6.0.0'} @@ -428,9 +329,12 @@ packages: discord-api-types@0.37.83: resolution: {integrity: sha512-urGGYeWtWNYMKnYlZnOnDHm8fVRffQs3U0SpE8RHeiuLKb/u92APS8HoQnPTFbnXmY1vVnXjXO4dOxcAn3J+DA==} - discord.js@14.15.2: - resolution: {integrity: sha512-wGD37YCaTUNprtpqMIRuNiswwsvSWXrHykBSm2SAosoTYut0VUDj9yo9t4iLtMKvuhI49zYkvKc2TNdzdvpJhg==} - engines: {node: '>=16.11.0'} + discord-api-types@0.37.97: + resolution: {integrity: sha512-No1BXPcVkyVD4ZVmbNgDKaBoqgeQ+FJpzZ8wqHkfmBnTZig1FcH3iPPersiK1TUIAzgClh2IvOuVUYfcWLQAOA==} + + discord.js@14.16.2: + resolution: {integrity: sha512-VGNi9WE2dZIxYM8/r/iatQQ+3LT8STW4hhczJOwm+DBeHq66vsKDCk8trChNCB01sMO9crslYuEMeZl2d7r3xw==} + engines: {node: '>=18'} dom-serializer@2.0.0: resolution: {integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==} @@ -449,6 +353,10 @@ packages: resolution: {integrity: sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q==} engines: {node: '>=10'} + dotenv@16.4.5: + resolution: {integrity: sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==} + engines: {node: '>=12'} + entities@4.5.0: resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} engines: {node: '>=0.12'} @@ -457,17 +365,11 @@ packages: resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==} engines: {node: '>=6'} - es-module-lexer@1.4.1: - resolution: {integrity: sha512-cXLGjP0c4T3flZJKQSuziYoq7MlT+rnvfZjfp7h+I7K9BNX54kP9nyWvdbwjQ4u1iWbOL4u96fgeZLToQlZC7w==} - - esbuild@0.21.3: - resolution: {integrity: sha512-Kgq0/ZsAPzKrbOjCQcjoSmPoWhlcVnGAUo7jvaLHoxW1Drto0KGkR1xBNg2Cp43b9ImvxmPEJZ9xkfcnqPsfBw==} - engines: {node: '>=12'} + esbuild@0.23.1: + resolution: {integrity: sha512-VVNz/9Sa0bs5SELtn3f7qhJCDPCF5oMEl5cO9/SSinpE9hbPVvxbd572HH5AKiP7WD8INO53GgfDDhRjkylHEg==} + engines: {node: '>=18'} hasBin: true - estree-walker@2.0.2: - resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} - fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} @@ -475,24 +377,9 @@ packages: resolution: {integrity: sha512-WrM7kLW+do9HLr+H6tk7LzQ7kPqbAgLjdzNE32+u3Ff11gXt9Kkkd2nusGFrlWMIe+XaA97t+I8JS7sZIrvRgA==} engines: {node: '>=16'} - fsevents@2.3.3: - resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} - engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} - os: [darwin] - - function-bind@1.1.2: - resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} - genius-lyrics@4.4.7: resolution: {integrity: sha512-cgO5nSeFqtLZAUyWB+8XWMRBIRzPUSUC42N3CoDGRgKX1anGAyDUhM6/RVIJXCNnQa6XHZHswKcKgHaRiyl+GQ==} - get-tsconfig@4.7.2: - resolution: {integrity: sha512-wuMsz4leaj5hbGgg4IvDU0bqJagpftG5l5cXIAvo8uZrqn0NJqwtfupTN00VnkQJPcIRrxYrm1Ue24btpCha2A==} - - hasown@2.0.1: - resolution: {integrity: sha512-1/th4MHjnwncwXsIW6QMzlvYL9kG5e/CpVvLRZe4XPa8TOUNbCELqmvhDmnkNsAjwaG4+I8gJJL0JBvTTLO9qA==} - engines: {node: '>= 0.4'} - he@1.2.0: resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==} hasBin: true @@ -507,9 +394,6 @@ packages: inherits@2.0.4: resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} - is-core-module@2.13.1: - resolution: {integrity: sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==} - lodash.snakecase@4.1.1: resolution: {integrity: sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw==} @@ -538,13 +422,6 @@ packages: parse-cache-control@1.0.1: resolution: {integrity: sha512-60zvsJReQPX5/QP0Kzfd/VrpjScIQ7SHBW6bFCYfEP+fp0Eppr1SHhIO5nd1PjZtvclzSzES9D/p5nFJurwfWg==} - path-parse@1.0.7: - resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} - - picomatch@2.3.1: - resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} - engines: {node: '>=8.6'} - play-audio@0.5.2: resolution: {integrity: sha512-ZAqHUKkQLix2Iga7pPbsf1LpUoBjcpwU93F1l3qBIfxYddQLhxS6GKmS0d3jV8kSVaUbr6NnOEcEMFvuX93SWQ==} @@ -577,30 +454,6 @@ packages: resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} engines: {node: '>= 6'} - resolve-pkg-maps@1.0.0: - resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} - - resolve@1.22.8: - resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==} - hasBin: true - - rollup-plugin-esbuild@6.1.1: - resolution: {integrity: sha512-CehMY9FAqJD5OUaE/Mi1r5z0kNeYxItmRO2zG4Qnv2qWKF09J2lTy5GUzjJR354ZPrLkCj4fiBN41lo8PzBUhw==} - engines: {node: '>=14.18.0'} - peerDependencies: - esbuild: '>=0.18.0' - rollup: ^1.20.0 || ^2.0.0 || ^3.0.0 || ^4.0.0 - - rollup-plugin-typescript-paths@1.5.0: - resolution: {integrity: sha512-zly2aiGNjYJNq5YUi6eyGrQnCYUQ8b5czOtHZIGriwG9U3Ba2F9hlSklafXCdsNulK/IlNmE0Kzj0h+fVV32pA==} - peerDependencies: - typescript: '>=3.4' - - rollup@4.18.0: - resolution: {integrity: sha512-QmJz14PX3rzbJCN1SG4Xe/bAAX2a6NpCP8ab2vfu2GiUr8AQcr2nCV/oEO3yneFarB67zk8ShlIyWb2LGTb3Sg==} - engines: {node: '>=18.0.0', npm: '>=8.0.0'} - hasBin: true - safe-buffer@5.2.1: resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} @@ -613,31 +466,34 @@ packages: string_decoder@1.3.0: resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} - supports-preserve-symlinks-flag@1.0.0: - resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} - engines: {node: '>= 0.4'} - ts-mixer@6.0.4: resolution: {integrity: sha512-ufKpbmrugz5Aou4wcr5Wc1UUFWOLhq+Fm6qa6P0w0K5Qw2yhaUoiWszhCVuNQyNwrlGiscHOmqYoAox1PtvgjA==} tslib@2.6.2: resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==} + tslib@2.7.0: + resolution: {integrity: sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==} + typedarray@0.0.6: resolution: {integrity: sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==} - typescript@5.4.5: - resolution: {integrity: sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==} + typescript@5.6.2: + resolution: {integrity: sha512-NW8ByodCSNCwZeghjN3o+JX5OFH0Ojg6sadjEKY4huZ52TqbJTJnDo5+Tw98lSy63NZvi4n+ez5m2u5d4PkZyw==} engines: {node: '>=14.17'} hasBin: true - undici-types@5.26.5: - resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} + undici-types@6.19.8: + resolution: {integrity: sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==} undici@6.13.0: resolution: {integrity: sha512-Q2rtqmZWrbP8nePMq7mOJIN98M0fYvSgV89vwl/BQRT4mDOeY2GXZngfGpcBBhtky3woM7G24wZV3Q304Bv6cw==} engines: {node: '>=18.0'} + undici@6.19.8: + resolution: {integrity: sha512-U8uCCl2x9TK3WANvmBavymRzxbfFYG+tAu+fgx3zxQy3qdagQqBLwJVrdyO1TBfUXvfKveMKJZhpvUYoOjM+4g==} + engines: {node: '>=18.17'} + utf-8-validate@6.0.4: resolution: {integrity: sha512-xu9GQDeFp+eZ6LnCywXN/zBancWvOpUMzgjLPSjy4BRHSmTelvn2E0DG0o1sTiw5hkCKBHo8rwSKncfRfv2EEQ==} engines: {node: '>=6.14.2'} @@ -666,37 +522,39 @@ snapshots: http-response-object: 3.0.2 parse-cache-control: 1.0.1 - '@discordjs/builders@1.8.1': + '@discordjs/builders@1.9.0': dependencies: - '@discordjs/formatters': 0.4.0 - '@discordjs/util': 1.1.0 - '@sapphire/shapeshift': 3.9.7 - discord-api-types: 0.37.83 + '@discordjs/formatters': 0.5.0 + '@discordjs/util': 1.1.1 + '@sapphire/shapeshift': 4.0.0 + discord-api-types: 0.37.97 fast-deep-equal: 3.1.3 ts-mixer: 6.0.4 - tslib: 2.6.2 + tslib: 2.7.0 '@discordjs/collection@1.5.3': {} '@discordjs/collection@2.1.0': {} - '@discordjs/formatters@0.4.0': + '@discordjs/collection@2.1.1': {} + + '@discordjs/formatters@0.5.0': dependencies: - discord-api-types: 0.37.83 + discord-api-types: 0.37.97 - '@discordjs/rest@2.3.0': + '@discordjs/rest@2.4.0': dependencies: - '@discordjs/collection': 2.1.0 - '@discordjs/util': 1.1.0 - '@sapphire/async-queue': 1.5.2 + '@discordjs/collection': 2.1.1 + '@discordjs/util': 1.1.1 + '@sapphire/async-queue': 1.5.3 '@sapphire/snowflake': 3.5.3 - '@vladfrangu/async_event_emitter': 2.2.4 - discord-api-types: 0.37.83 + '@vladfrangu/async_event_emitter': 2.4.6 + discord-api-types: 0.37.97 magic-bytes.js: 1.10.0 - tslib: 2.6.2 - undici: 6.13.0 + tslib: 2.7.0 + undici: 6.19.8 - '@discordjs/util@1.1.0': {} + '@discordjs/util@1.1.1': {} '@discordjs/voice@0.17.0(bufferutil@4.0.8)(ffmpeg-static@5.2.0)(opusscript@0.1.1)(utf-8-validate@6.0.4)': dependencies: @@ -713,88 +571,91 @@ snapshots: - opusscript - utf-8-validate - '@discordjs/ws@1.1.0(bufferutil@4.0.8)(utf-8-validate@6.0.4)': + '@discordjs/ws@1.1.1(bufferutil@4.0.8)(utf-8-validate@6.0.4)': dependencies: '@discordjs/collection': 2.1.0 - '@discordjs/rest': 2.3.0 - '@discordjs/util': 1.1.0 + '@discordjs/rest': 2.4.0 + '@discordjs/util': 1.1.1 '@sapphire/async-queue': 1.5.2 '@types/ws': 8.5.10 '@vladfrangu/async_event_emitter': 2.2.4 discord-api-types: 0.37.83 - tslib: 2.6.2 + tslib: 2.7.0 ws: 8.16.0(bufferutil@4.0.8)(utf-8-validate@6.0.4) transitivePeerDependencies: - bufferutil - utf-8-validate - '@esbuild/aix-ppc64@0.21.3': + '@esbuild/aix-ppc64@0.23.1': optional: true - '@esbuild/android-arm64@0.21.3': + '@esbuild/android-arm64@0.23.1': optional: true - '@esbuild/android-arm@0.21.3': + '@esbuild/android-arm@0.23.1': optional: true - '@esbuild/android-x64@0.21.3': + '@esbuild/android-x64@0.23.1': optional: true - '@esbuild/darwin-arm64@0.21.3': + '@esbuild/darwin-arm64@0.23.1': optional: true - '@esbuild/darwin-x64@0.21.3': + '@esbuild/darwin-x64@0.23.1': optional: true - '@esbuild/freebsd-arm64@0.21.3': + '@esbuild/freebsd-arm64@0.23.1': optional: true - '@esbuild/freebsd-x64@0.21.3': + '@esbuild/freebsd-x64@0.23.1': optional: true - '@esbuild/linux-arm64@0.21.3': + '@esbuild/linux-arm64@0.23.1': optional: true - '@esbuild/linux-arm@0.21.3': + '@esbuild/linux-arm@0.23.1': optional: true - '@esbuild/linux-ia32@0.21.3': + '@esbuild/linux-ia32@0.23.1': optional: true - '@esbuild/linux-loong64@0.21.3': + '@esbuild/linux-loong64@0.23.1': optional: true - '@esbuild/linux-mips64el@0.21.3': + '@esbuild/linux-mips64el@0.23.1': optional: true - '@esbuild/linux-ppc64@0.21.3': + '@esbuild/linux-ppc64@0.23.1': optional: true - '@esbuild/linux-riscv64@0.21.3': + '@esbuild/linux-riscv64@0.23.1': optional: true - '@esbuild/linux-s390x@0.21.3': + '@esbuild/linux-s390x@0.23.1': optional: true - '@esbuild/linux-x64@0.21.3': + '@esbuild/linux-x64@0.23.1': optional: true - '@esbuild/netbsd-x64@0.21.3': + '@esbuild/netbsd-x64@0.23.1': optional: true - '@esbuild/openbsd-x64@0.21.3': + '@esbuild/openbsd-arm64@0.23.1': optional: true - '@esbuild/sunos-x64@0.21.3': + '@esbuild/openbsd-x64@0.23.1': optional: true - '@esbuild/win32-arm64@0.21.3': + '@esbuild/sunos-x64@0.23.1': optional: true - '@esbuild/win32-ia32@0.21.3': + '@esbuild/win32-arm64@0.23.1': optional: true - '@esbuild/win32-x64@0.21.3': + '@esbuild/win32-ia32@0.23.1': + optional: true + + '@esbuild/win32-x64@0.23.1': optional: true '@joehoel/lyric-finder@1.0.2': @@ -802,94 +663,31 @@ snapshots: dotenv: 10.0.0 genius-lyrics: 4.4.7 - '@rollup/plugin-typescript@11.1.6(rollup@4.18.0)(tslib@2.6.2)(typescript@5.4.5)': - dependencies: - '@rollup/pluginutils': 5.1.0(rollup@4.18.0) - resolve: 1.22.8 - typescript: 5.4.5 - optionalDependencies: - rollup: 4.18.0 - tslib: 2.6.2 - - '@rollup/pluginutils@5.1.0(rollup@4.18.0)': - dependencies: - '@types/estree': 1.0.5 - estree-walker: 2.0.2 - picomatch: 2.3.1 - optionalDependencies: - rollup: 4.18.0 - - '@rollup/rollup-android-arm-eabi@4.18.0': - optional: true - - '@rollup/rollup-android-arm64@4.18.0': - optional: true - - '@rollup/rollup-darwin-arm64@4.18.0': - optional: true - - '@rollup/rollup-darwin-x64@4.18.0': - optional: true - - '@rollup/rollup-linux-arm-gnueabihf@4.18.0': - optional: true - - '@rollup/rollup-linux-arm-musleabihf@4.18.0': - optional: true - - '@rollup/rollup-linux-arm64-gnu@4.18.0': - optional: true - - '@rollup/rollup-linux-arm64-musl@4.18.0': - optional: true - - '@rollup/rollup-linux-powerpc64le-gnu@4.18.0': - optional: true - - '@rollup/rollup-linux-riscv64-gnu@4.18.0': - optional: true - - '@rollup/rollup-linux-s390x-gnu@4.18.0': - optional: true - - '@rollup/rollup-linux-x64-gnu@4.18.0': - optional: true - - '@rollup/rollup-linux-x64-musl@4.18.0': - optional: true - - '@rollup/rollup-win32-arm64-msvc@4.18.0': - optional: true - - '@rollup/rollup-win32-ia32-msvc@4.18.0': - optional: true - - '@rollup/rollup-win32-x64-msvc@4.18.0': - optional: true - '@sapphire/async-queue@1.5.2': {} - '@sapphire/shapeshift@3.9.7': + '@sapphire/async-queue@1.5.3': {} + + '@sapphire/shapeshift@4.0.0': dependencies: fast-deep-equal: 3.1.3 lodash: 4.17.21 '@sapphire/snowflake@3.5.3': {} - '@types/estree@1.0.5': {} - '@types/node@10.17.60': {} - '@types/node@20.12.12': + '@types/node@20.16.5': dependencies: - undici-types: 5.26.5 + undici-types: 6.19.8 '@types/ws@8.5.10': dependencies: - '@types/node': 20.12.12 + '@types/node': 20.16.5 '@vladfrangu/async_event_emitter@2.2.4': {} + '@vladfrangu/async_event_emitter@2.4.6': {} + agent-base@6.0.2: dependencies: debug: 4.3.4 @@ -933,20 +731,22 @@ snapshots: discord-api-types@0.37.83: {} - discord.js@14.15.2(bufferutil@4.0.8)(utf-8-validate@6.0.4): + discord-api-types@0.37.97: {} + + discord.js@14.16.2(bufferutil@4.0.8)(utf-8-validate@6.0.4): dependencies: - '@discordjs/builders': 1.8.1 + '@discordjs/builders': 1.9.0 '@discordjs/collection': 1.5.3 - '@discordjs/formatters': 0.4.0 - '@discordjs/rest': 2.3.0 - '@discordjs/util': 1.1.0 - '@discordjs/ws': 1.1.0(bufferutil@4.0.8)(utf-8-validate@6.0.4) + '@discordjs/formatters': 0.5.0 + '@discordjs/rest': 2.4.0 + '@discordjs/util': 1.1.1 + '@discordjs/ws': 1.1.1(bufferutil@4.0.8)(utf-8-validate@6.0.4) '@sapphire/snowflake': 3.5.3 - discord-api-types: 0.37.83 + discord-api-types: 0.37.97 fast-deep-equal: 3.1.3 lodash.snakecase: 4.1.1 - tslib: 2.6.2 - undici: 6.13.0 + tslib: 2.7.0 + undici: 6.19.8 transitivePeerDependencies: - bufferutil - utf-8-validate @@ -971,39 +771,38 @@ snapshots: dotenv@10.0.0: {} + dotenv@16.4.5: {} + entities@4.5.0: {} env-paths@2.2.1: {} - es-module-lexer@1.4.1: {} - - esbuild@0.21.3: + esbuild@0.23.1: optionalDependencies: - '@esbuild/aix-ppc64': 0.21.3 - '@esbuild/android-arm': 0.21.3 - '@esbuild/android-arm64': 0.21.3 - '@esbuild/android-x64': 0.21.3 - '@esbuild/darwin-arm64': 0.21.3 - '@esbuild/darwin-x64': 0.21.3 - '@esbuild/freebsd-arm64': 0.21.3 - '@esbuild/freebsd-x64': 0.21.3 - '@esbuild/linux-arm': 0.21.3 - '@esbuild/linux-arm64': 0.21.3 - '@esbuild/linux-ia32': 0.21.3 - '@esbuild/linux-loong64': 0.21.3 - '@esbuild/linux-mips64el': 0.21.3 - '@esbuild/linux-ppc64': 0.21.3 - '@esbuild/linux-riscv64': 0.21.3 - '@esbuild/linux-s390x': 0.21.3 - '@esbuild/linux-x64': 0.21.3 - '@esbuild/netbsd-x64': 0.21.3 - '@esbuild/openbsd-x64': 0.21.3 - '@esbuild/sunos-x64': 0.21.3 - '@esbuild/win32-arm64': 0.21.3 - '@esbuild/win32-ia32': 0.21.3 - '@esbuild/win32-x64': 0.21.3 - - estree-walker@2.0.2: {} + '@esbuild/aix-ppc64': 0.23.1 + '@esbuild/android-arm': 0.23.1 + '@esbuild/android-arm64': 0.23.1 + '@esbuild/android-x64': 0.23.1 + '@esbuild/darwin-arm64': 0.23.1 + '@esbuild/darwin-x64': 0.23.1 + '@esbuild/freebsd-arm64': 0.23.1 + '@esbuild/freebsd-x64': 0.23.1 + '@esbuild/linux-arm': 0.23.1 + '@esbuild/linux-arm64': 0.23.1 + '@esbuild/linux-ia32': 0.23.1 + '@esbuild/linux-loong64': 0.23.1 + '@esbuild/linux-mips64el': 0.23.1 + '@esbuild/linux-ppc64': 0.23.1 + '@esbuild/linux-riscv64': 0.23.1 + '@esbuild/linux-s390x': 0.23.1 + '@esbuild/linux-x64': 0.23.1 + '@esbuild/netbsd-x64': 0.23.1 + '@esbuild/openbsd-arm64': 0.23.1 + '@esbuild/openbsd-x64': 0.23.1 + '@esbuild/sunos-x64': 0.23.1 + '@esbuild/win32-arm64': 0.23.1 + '@esbuild/win32-ia32': 0.23.1 + '@esbuild/win32-x64': 0.23.1 fast-deep-equal@3.1.3: {} @@ -1016,24 +815,11 @@ snapshots: transitivePeerDependencies: - supports-color - fsevents@2.3.3: - optional: true - - function-bind@1.1.2: {} - genius-lyrics@4.4.7: dependencies: node-html-parser: 6.1.13 undici: 6.13.0 - get-tsconfig@4.7.2: - dependencies: - resolve-pkg-maps: 1.0.0 - - hasown@2.0.1: - dependencies: - function-bind: 1.1.2 - he@1.2.0: {} http-response-object@3.0.2: @@ -1049,10 +835,6 @@ snapshots: inherits@2.0.4: {} - is-core-module@2.13.1: - dependencies: - hasown: 2.0.1 - lodash.snakecase@4.1.1: {} lodash@4.17.21: {} @@ -1076,10 +858,6 @@ snapshots: parse-cache-control@1.0.1: {} - path-parse@1.0.7: {} - - picomatch@2.3.1: {} - play-audio@0.5.2: {} play-dl@1.9.7: @@ -1099,51 +877,6 @@ snapshots: string_decoder: 1.3.0 util-deprecate: 1.0.2 - resolve-pkg-maps@1.0.0: {} - - resolve@1.22.8: - dependencies: - is-core-module: 2.13.1 - path-parse: 1.0.7 - supports-preserve-symlinks-flag: 1.0.0 - - rollup-plugin-esbuild@6.1.1(esbuild@0.21.3)(rollup@4.18.0): - dependencies: - '@rollup/pluginutils': 5.1.0(rollup@4.18.0) - debug: 4.3.4 - es-module-lexer: 1.4.1 - esbuild: 0.21.3 - get-tsconfig: 4.7.2 - rollup: 4.18.0 - transitivePeerDependencies: - - supports-color - - rollup-plugin-typescript-paths@1.5.0(typescript@5.4.5): - dependencies: - typescript: 5.4.5 - - rollup@4.18.0: - dependencies: - '@types/estree': 1.0.5 - optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.18.0 - '@rollup/rollup-android-arm64': 4.18.0 - '@rollup/rollup-darwin-arm64': 4.18.0 - '@rollup/rollup-darwin-x64': 4.18.0 - '@rollup/rollup-linux-arm-gnueabihf': 4.18.0 - '@rollup/rollup-linux-arm-musleabihf': 4.18.0 - '@rollup/rollup-linux-arm64-gnu': 4.18.0 - '@rollup/rollup-linux-arm64-musl': 4.18.0 - '@rollup/rollup-linux-powerpc64le-gnu': 4.18.0 - '@rollup/rollup-linux-riscv64-gnu': 4.18.0 - '@rollup/rollup-linux-s390x-gnu': 4.18.0 - '@rollup/rollup-linux-x64-gnu': 4.18.0 - '@rollup/rollup-linux-x64-musl': 4.18.0 - '@rollup/rollup-win32-arm64-msvc': 4.18.0 - '@rollup/rollup-win32-ia32-msvc': 4.18.0 - '@rollup/rollup-win32-x64-msvc': 4.18.0 - fsevents: 2.3.3 - safe-buffer@5.2.1: {} sodium-native@4.1.1: @@ -1156,20 +889,22 @@ snapshots: dependencies: safe-buffer: 5.2.1 - supports-preserve-symlinks-flag@1.0.0: {} - ts-mixer@6.0.4: {} tslib@2.6.2: {} + tslib@2.7.0: {} + typedarray@0.0.6: {} - typescript@5.4.5: {} + typescript@5.6.2: {} - undici-types@5.26.5: {} + undici-types@6.19.8: {} undici@6.13.0: {} + undici@6.19.8: {} + utf-8-validate@6.0.4: dependencies: node-gyp-build: 4.8.0 diff --git a/rollup.config.ts b/rollup.config.ts deleted file mode 100644 index d77d9b4..0000000 --- a/rollup.config.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { defineConfig } from "rollup"; -import { typescriptPaths } from "rollup-plugin-typescript-paths"; -import { execSync } from "node:child_process"; -import ts from "typescript"; -import esbuild from 'rollup-plugin-esbuild'; - -function hash(): string { - try { - return execSync("git rev-parse --short HEAD").toString().trim(); - } catch (e: any | Error) { - return "null"; - } -} - -export default defineConfig([{ - input: "src/index.ts", - treeshake: true, - external: ["discord.js", "play-dl", "lyrics-finder", "array-move", "string-progressbar", "@discordjs/voice", "chalk", "typescript", "node:util", "node:os", "node:process", "@joehoel/lyric-finder"], - cache: true, - output: { - name: "bundle.js", - file: "dist/bundle.js", - dynamicImportInCjs: true, - inlineDynamicImports: true, - minifyInternalExports: true, - compact: true, - format: "esm", - strict: true, - sourcemap: false, - }, - plugins: [ - typescriptPaths({ preserveExtensions: true, nonRelative: true }), - esbuild({ - platform: "node", - target: "esnext", - minify: true, - minifyIdentifiers: true, - minifySyntax: true, - minifyWhitespace: true, - mangleQuoted: true, - ignoreAnnotations: true, - define: { - __VERSION__: `"${hash()}"`, - __TYPESCRIPTVERSION__: `"${ts.version}"` - }, - treeShaking: true - }) - ] -}]); \ No newline at end of file diff --git a/src/commands/info/changelogs.ts b/src/commands/info/changelogs.ts index d599509..1ddec67 100644 --- a/src/commands/info/changelogs.ts +++ b/src/commands/info/changelogs.ts @@ -7,12 +7,9 @@ export default { .setDescription("Displays information about the latest Music Bot update."), async execute(interaction) { - const bugfixes = `- handlers(command): Fix crash when replying to a already replied and/or deferred interaction - - lyrics: Fix possible crash`; + const bugfixes = `- None`; - const whatsnew = `- bot: Updated and upgraded - - playlist: Removed unnecessary similar code for the playlist message - - music(internals): Added one check in the inactivity leave`; + const whatsnew = `- bot: Updated and upgraded`; const UpdateEmbed = new EmbedBuilder() .setColor("NotQuiteBlack") @@ -30,6 +27,6 @@ export default { } ); - return interaction.reply({ embeds: [UpdateEmbed] }); + return await interaction.reply({ embeds: [UpdateEmbed] }); }, } as Command; diff --git a/src/commands/info/info.ts b/src/commands/info/info.ts index c782cfe..e093f10 100644 --- a/src/commands/info/info.ts +++ b/src/commands/info/info.ts @@ -47,6 +47,6 @@ export default { } ) .setFooter({ text: `Uptime: ${timeConverter.formatSeconds(Math.floor(process.uptime()))} | Git Hash: ${hash}` }); - return interaction.reply({ embeds: [infoEmbed] }).catch((err: any) => Logger.error({ type: "INFOCMDS", err })); + return await interaction.reply({ embeds: [infoEmbed] }).catch((err: any) => Logger.error({ type: "INFOCMDS", err })); }, } as Command; diff --git a/src/commands/info/membercount.ts b/src/commands/info/membercount.ts index 982adc3..874079b 100644 --- a/src/commands/info/membercount.ts +++ b/src/commands/info/membercount.ts @@ -5,7 +5,7 @@ export default { data: new SlashCommandBuilder() .setName("membercount") .setDescription("Displays the number of members in the guild."), - execute(interaction) { + async execute(interaction) { const guild = interaction.guild! const countEmbed = new EmbedBuilder() .setColor("NotQuiteBlack") @@ -13,6 +13,6 @@ export default { .addFields({ name: `${guild.name} Members`, value: `**${guild.memberCount}**` }); - return interaction.reply({ embeds: [countEmbed] }); + return await interaction.reply({ embeds: [countEmbed] }); }, } as Command; \ No newline at end of file diff --git a/src/commands/info/ping.ts b/src/commands/info/ping.ts index 71dfea8..a5fefbd 100644 --- a/src/commands/info/ping.ts +++ b/src/commands/info/ping.ts @@ -6,7 +6,7 @@ export default { data: new SlashCommandBuilder() .setName("ping") .setDescription("Check the API and Bot latency."), - execute(interaction) { + async execute(interaction) { const pingEmbed = new EmbedBuilder() .setColor("NotQuiteBlack") .setTitle("Info | Latency") @@ -19,6 +19,6 @@ export default { name: "API Latency", value: `${Math.round(interaction.client.ws.ping)}ms`, inline: true } ); - return interaction.reply({ embeds: [pingEmbed], ephemeral: true }).catch((err: Error) => Logger.error({ type: "INFOCMDS", err: err })); + return await interaction.reply({ embeds: [pingEmbed], ephemeral: true }).catch((err: Error) => Logger.error({ type: "INFOCMDS", err: err })); }, } as Command; \ No newline at end of file diff --git a/src/commands/music/loop.ts b/src/commands/music/loop.ts index ee1cf68..f9d519e 100644 --- a/src/commands/music/loop.ts +++ b/src/commands/music/loop.ts @@ -7,7 +7,7 @@ export default { .setName("loop") .setDescription("Toggles the bot queue loop."), async execute(interaction) { - const queue = interaction.client.queues.get(interaction.guild?.id as string); + const queue = interaction.client.queues.get(interaction.guild!.id); const nothingPlaying = new EmbedBuilder() .setColor("NotQuiteBlack") @@ -19,8 +19,8 @@ export default { .setTitle("Track Player") .setDescription("You need to join the voice channel the bot is in."); - if (!canModifyQueue({ member: interaction.member as GuildMember })) return interaction.reply({ embeds: [notInBotChannel], ephemeral: true }); - if (!queue) return interaction.reply({ embeds: [nothingPlaying], ephemeral: true }); + if (!canModifyQueue({ member: interaction.member as GuildMember })) return await interaction.reply({ embeds: [notInBotChannel], ephemeral: true }); + if (!queue) return await interaction.reply({ embeds: [nothingPlaying], ephemeral: true }); queue.loop = !queue.loop; @@ -29,6 +29,6 @@ export default { .setTitle("Track Player") .setDescription(`Loop ${queue.loop ? "**enabled**." : "**disabled**."}`); - return interaction.reply({ embeds: [loopEmbed] }); + return await interaction.reply({ embeds: [loopEmbed] }); }, } as Command; diff --git a/src/commands/music/lyrics.ts b/src/commands/music/lyrics.ts index 0e63d8a..603aefb 100644 --- a/src/commands/music/lyrics.ts +++ b/src/commands/music/lyrics.ts @@ -8,14 +8,14 @@ export default { .setName("lyrics") .setDescription("Fetch lyrics for the currently playing song."), async execute(interaction) { - const queue = interaction.client.queues.get(interaction.guild?.id as string); + const queue = interaction.client.queues.get(interaction.guild!.id); const nothingPlaying = new EmbedBuilder() .setColor("NotQuiteBlack") .setTitle("Track Player") .setDescription("There is nothing playing in the queue currently."); - if (!queue || !queue.songs || !queue.songs.length) return interaction.reply({ embeds: [nothingPlaying], ephemeral: true }); + if (!queue || !queue.songs || !queue.songs.length) return await interaction.reply({ embeds: [nothingPlaying], ephemeral: true }); let lyricsSearch = null; const title = queue.songs[0].title; @@ -36,7 +36,7 @@ export default { try { lyricsSearch = await lyrics.default(title); - if (!lyricsSearch?.lyrics) return interaction.editReply({ embeds: [lyricsNotFound] }); + if (!lyricsSearch?.lyrics) return await interaction.editReply({ embeds: [lyricsNotFound] }); const lyricsEmbed = new EmbedBuilder() .setColor("NotQuiteBlack") @@ -45,10 +45,10 @@ export default { if ((lyricsEmbed.data.description?.length as number) >= 2048) lyricsEmbed.data.description = lyricsEmbed.data.description?.substring(0, 2045) + "..."; - return interaction.editReply({ embeds: [lyricsEmbed] }); + return await interaction.editReply({ embeds: [lyricsEmbed] }); } catch (err: any) { Logger.error({ type: "MUSICCMDS", err: err }); - return interaction.editReply({ embeds: [lyricsNotFound] }); + return await interaction.editReply({ embeds: [lyricsNotFound] }); } }, } as Command; diff --git a/src/commands/music/move.ts b/src/commands/music/move.ts index 9713fe8..4f8f62d 100644 --- a/src/commands/music/move.ts +++ b/src/commands/music/move.ts @@ -19,10 +19,10 @@ export default { .setDescription("Position to move the song to.") .setRequired(true) ), - execute(interaction) { - const queue = interaction.client.queues.get(interaction.guild?.id as string); - const firstPos: number = interaction.options.getNumber("first_position") as number; - const secondPos: number = interaction.options.getNumber("second_position") as number; + async execute(interaction) { + const queue = interaction.client.queues.get(interaction.guild!.id); + const firstPos = interaction.options.getNumber("first_position", true); + const secondPos = interaction.options.getNumber("second_position", true); const nothingPlaying = new EmbedBuilder() .setColor("NotQuiteBlack") @@ -34,9 +34,9 @@ export default { .setTitle("Track Player") .setDescription("You need to join the voice channel the bot is in."); - if (!canModifyQueue({ member: interaction.member as GuildMember })) return interaction.reply({ embeds: [notInBotChannel], ephemeral: true }); - if (!queue) return interaction.reply({ embeds: [nothingPlaying], ephemeral: true }); - if (firstPos <= 1) return interaction.reply({ content: "Provide valid position numbers.", ephemeral: true }); + if (!canModifyQueue({ member: interaction.member as GuildMember })) return await interaction.reply({ embeds: [notInBotChannel], ephemeral: true }); + if (!queue) return await interaction.reply({ embeds: [nothingPlaying], ephemeral: true }); + if (firstPos <= 1) return await interaction.reply({ content: "Provide valid position numbers.", ephemeral: true }); const song = queue.songs[firstPos - 1]; queue.songs = arrayMoveImmutable(queue.songs, firstPos - 1, secondPos == 1 ? 1 : secondPos - 1); @@ -46,6 +46,6 @@ export default { .setTitle("Track Player") .setDescription(`${interaction.user} moved **${song.title}** to ${secondPos} in the queue.`); - interaction.reply({ embeds: [moveEmbed] }); + return await interaction.reply({ embeds: [moveEmbed] }); }, } as Command; diff --git a/src/commands/music/nowplaying.ts b/src/commands/music/nowplaying.ts index 5d83d19..754ac7a 100644 --- a/src/commands/music/nowplaying.ts +++ b/src/commands/music/nowplaying.ts @@ -7,15 +7,15 @@ export default { data: new SlashCommandBuilder() .setName("nowplaying") .setDescription("Shows the current playing song."), - execute(interaction) { - const queue = interaction.client.queues.get(interaction.guild?.id as string); + async execute(interaction) { + const queue = interaction.client.queues.get(interaction.guild!.id); const nothingPlaying = new EmbedBuilder() .setColor("NotQuiteBlack") .setTitle("Track Player") .setDescription("There is nothing playing in the queue currently."); - if (!queue) return interaction.reply({ embeds: [nothingPlaying], ephemeral: true }); + if (!queue) return await interaction.reply({ embeds: [nothingPlaying], ephemeral: true }); const song = queue.songs[0]; const seek = queue.resource.playbackDuration / 1000; @@ -44,7 +44,7 @@ export default { nowPlaying.setFooter({ text: "Time Remaining: " + new Date(left * 1000).toISOString().substring(11, 8) }); } - return interaction.reply({ embeds: [nowPlaying] }); + return await interaction.reply({ embeds: [nowPlaying] }); } catch (err: any | Error) { interaction.reply("An error has occured. Error has been reported."); return Logger.error({ type: "MUSICCMDS", err: err }); diff --git a/src/commands/music/pause.ts b/src/commands/music/pause.ts index a8b86ea..e75483d 100644 --- a/src/commands/music/pause.ts +++ b/src/commands/music/pause.ts @@ -6,8 +6,8 @@ export default { data: new SlashCommandBuilder() .setName("pause") .setDescription("Pauses the queue."), - execute(interaction) { - const queue = interaction.client.queues.get(interaction.guild?.id as string); + async execute(interaction) { + const queue = interaction.client.queues.get(interaction.guild!.id); const nothingPlaying = new EmbedBuilder() .setColor("NotQuiteBlack") @@ -19,11 +19,10 @@ export default { .setTitle("Track Player") .setDescription("You need to join the voice channel the bot is in."); - if (!canModifyQueue({ member: interaction.member as GuildMember })) return interaction.reply({ embeds: [notInBotChannel], ephemeral: true }); - if (!queue) return interaction.reply({ embeds: [nothingPlaying], ephemeral: true }); + if (!canModifyQueue({ member: interaction.member as GuildMember })) return await interaction.reply({ embeds: [notInBotChannel], ephemeral: true }); + if (!queue) return await interaction.reply({ embeds: [nothingPlaying], ephemeral: true }); if (queue.player.pause()) { - const pauseEmbed = new EmbedBuilder() .setColor("NotQuiteBlack") .setTitle("Track Player") @@ -38,6 +37,6 @@ export default { .setTitle("Track Player") .setDescription(`The queue is already paused.`); - return interaction.reply({ embeds: [alreadyPaused] }); + return await interaction.reply({ embeds: [alreadyPaused] }); }, } as Command; diff --git a/src/commands/music/play.ts b/src/commands/music/play.ts index 96c1d20..73bc8b0 100644 --- a/src/commands/music/play.ts +++ b/src/commands/music/play.ts @@ -18,8 +18,8 @@ export default { ), async execute(interaction) { const { channel } = (interaction.member as GuildMember).voice; - const queue = interaction.client.queues.get(interaction.guild?.id as string); - const url: string = interaction.options.getString("query") as string; + const queue = interaction.client.queues.get(interaction.guild!.id); + const url = interaction.options.getString("query", true); const notInVC = new EmbedBuilder() .setColor("NotQuiteBlack") @@ -31,8 +31,8 @@ export default { .setTitle("Track Player") .setDescription(`You must be in the same channel as ${interaction.client?.user}.`); - if (!channel) return interaction.reply({ embeds: [notInVC], ephemeral: true }); - if (queue && channel.id !== queue.connection.joinConfig.channelId) return interaction.reply({ embeds: [notInBotChannel], ephemeral: true }); + if (!channel) return await interaction.reply({ embeds: [notInVC], ephemeral: true }); + if (queue && channel.id !== queue.connection.joinConfig.channelId) return await interaction.reply({ embeds: [notInBotChannel], ephemeral: true }); const permissions = channel.permissionsFor(interaction.client?.user); const botNoPermissions = new EmbedBuilder() @@ -40,10 +40,10 @@ export default { .setTitle("Track Player") .setDescription("I am missing permissions to join your channel or speak in your voice channel."); - if (!permissions?.has([PermissionFlagsBits.Connect, PermissionFlagsBits.Speak])) return interaction.reply({ embeds: [botNoPermissions], ephemeral: true }); + if (!permissions?.has([PermissionFlagsBits.Connect, PermissionFlagsBits.Speak])) return await interaction.reply({ embeds: [botNoPermissions], ephemeral: true }); if (yt_validate(url) === "playlist" || await so_validate(url) === "playlist" || sp_validate(url) === "album" || sp_validate(url) === "playlist") { - return interaction.reply({ content: "Playlist was provided, please use the `playlist` command.", ephemeral: true }); + return await interaction.reply({ content: "Playlist was provided, please use the `playlist` command.", ephemeral: true }); } await interaction.reply({ content: "⏳ Loading..." }); @@ -82,7 +82,7 @@ export default { } }); - interaction.client.queues.set(interaction.guild?.id as string, newQueue); + interaction.client.queues.set(interaction.guild!.id, newQueue); await interaction.deleteReply(); return await newQueue.enqueue({ songs: [song] }); diff --git a/src/commands/music/playlist.ts b/src/commands/music/playlist.ts index f2a058e..2402483 100644 --- a/src/commands/music/playlist.ts +++ b/src/commands/music/playlist.ts @@ -14,11 +14,12 @@ export default { option .setName("query") .setDescription("The query to search for.") + .setRequired(true) ), async execute(interaction) { const { channel } = (interaction.member as GuildMember).voice; - let queue = interaction.client.queues.get(interaction.guild?.id as string); - const url = interaction.options.getString("query") as string; + let queue = interaction.client.queues.get(interaction.guild!.id); + const url = interaction.options.getString("query", true); /* Embeds for music */ const notInVC = new EmbedBuilder() @@ -31,8 +32,8 @@ export default { .setTitle("Track Player") .setDescription("You need to join the voice channel the bot is in."); - if (!channel) return interaction.reply({ embeds: [notInVC], ephemeral: true }); - if (queue && channel.id !== queue.connection.joinConfig.channelId) return interaction.reply({ embeds: [notInBotChannel], ephemeral: true }); + if (!channel) return await interaction.reply({ embeds: [notInVC], ephemeral: true }); + if (queue && channel.id !== queue.connection.joinConfig.channelId) return await interaction.reply({ embeds: [notInBotChannel], ephemeral: true }); const permissions = channel.permissionsFor(interaction.client?.user); const botNoPermissions = new EmbedBuilder() @@ -40,7 +41,7 @@ export default { .setTitle("Track Player") .setDescription("I am missing permissions to join your channel or speak in your voice channel."); - if (!permissions?.has([PermissionFlagsBits.Connect, PermissionFlagsBits.Speak])) return interaction.reply({ embeds: [botNoPermissions], ephemeral: true }); + if (!permissions?.has([PermissionFlagsBits.Connect, PermissionFlagsBits.Speak])) return await interaction.reply({ embeds: [botNoPermissions], ephemeral: true }); if (!interaction.deferred) interaction.deferReply(); @@ -49,7 +50,7 @@ export default { playlist = await Playlist.from({ search: url, interaction }); } catch (err: any | Error) { Logger.error({ type: "INTERNAL:PLAYLIST", err: err }); - return interaction.editReply({ content: "Playlist not found." }).catch((err) => Logger.error({ type: "MUSICCMDS", err: err })); + return await interaction.editReply({ content: "Playlist not found." }).catch((err) => Logger.error({ type: "MUSICCMDS", err: err })); } if (queue) { @@ -69,7 +70,7 @@ export default { }) } }); - interaction.client.queues.set(interaction.guild?.id as string, queue); + interaction.client.queues.set(interaction.guild!.id as string, queue); await queue.enqueue({ songs: playlist.videos }); } @@ -83,6 +84,6 @@ export default { }) .setURL(playlist.data.url as string); - return interaction.editReply({ embeds: [playlistEmbed] }).catch((err: Error) => Logger.error({ type: "MUSICCMDS", err })); + return await interaction.editReply({ embeds: [playlistEmbed] }).catch((err: Error) => Logger.error({ type: "MUSICCMDS", err })); }, } as Command; diff --git a/src/commands/music/pruning.ts b/src/commands/music/pruning.ts index 9c766c9..0eb4dbc 100644 --- a/src/commands/music/pruning.ts +++ b/src/commands/music/pruning.ts @@ -1,19 +1,25 @@ import { EmbedBuilder, SlashCommandBuilder } from "discord.js"; import type { Command } from "@common"; -import { config } from "@components/config"; export default { data: new SlashCommandBuilder() .setName("pruning") .setDescription("Toggles pruning of bot messages."), async execute(interaction) { - config.PRUNING = !config.PRUNING; + const queue = interaction.client.queues.get(interaction.guild!.id); + const nothingPlaying = new EmbedBuilder() + .setColor("NotQuiteBlack") + .setTitle("Track Player") + .setDescription("There is no queue currently."); + if (!queue) return interaction.reply({ embeds: [nothingPlaying], ephemeral: true }); + + queue.pruning = !queue.pruning; const pruneEmbed = new EmbedBuilder() .setColor("NotQuiteBlack") .setTitle("Track Player") - .setDescription(`Message pruning ${config?.PRUNING ? "**enabled**." : "**disabled**."}`); + .setDescription(`Message pruning ${queue.pruning ? "**enabled**." : "**disabled**."}`); - return interaction.reply({ embeds: [pruneEmbed] }); + return await interaction.reply({ embeds: [pruneEmbed] }); }, } as Command; diff --git a/src/commands/music/queue.ts b/src/commands/music/queue.ts index 889d72d..d8d4001 100644 --- a/src/commands/music/queue.ts +++ b/src/commands/music/queue.ts @@ -1,23 +1,22 @@ -import { EmbedBuilder, ActionRowBuilder, ButtonBuilder, SlashCommandBuilder, ButtonStyle, type CollectedInteraction, type CacheType, type ChatInputCommandInteraction } from "discord.js"; +import { EmbedBuilder, ActionRowBuilder, ButtonBuilder, SlashCommandBuilder, ButtonStyle, type CollectedInteraction, type CacheType, type ChatInputCommandInteraction, type GuildTextBasedChannel } from "discord.js"; import { Logger } from "@components/Logger"; import type { Song } from "@components/Song"; import type { Command } from "@common"; -let currentPage: number = 0 as number; - export default { data: new SlashCommandBuilder() .setName("queue") .setDescription("Shows the bot queue and what is currently playing."), async execute(interaction) { - const queue = interaction.client.queues.get(interaction.guild?.id as string); + const queue = interaction.client.queues.get(interaction.guild!.id); const nothingPlaying = new EmbedBuilder() .setColor("NotQuiteBlack") .setTitle("Track Player") .setDescription("There is nothing playing in the queue currently."); - if (!queue || !queue.songs || !queue.songs.length) return interaction.reply({ embeds: [nothingPlaying], ephemeral: true }); + if (!queue || !queue.songs || !queue.songs.length) return await interaction.reply({ embeds: [nothingPlaying], ephemeral: true }); + let currentPage: number = 0 as number; const embeds = generateQueueEmbed(interaction, queue.songs); const queueButtons = new ActionRowBuilder() @@ -41,9 +40,9 @@ export default { embeds: [embeds[currentPage]], components: embeds.length > 1 ? [queueButtons] : [] }); if (embeds.length > 1) { - const collector = interaction.channel?.createMessageComponentCollector({ time: 60000 }); + const collector = (interaction.channel as GuildTextBasedChannel).createMessageComponentCollector({ time: 60000 }); - collector?.on("collect", async (i: CollectedInteraction): Promise => { + collector.on("collect", async (i: CollectedInteraction): Promise => { try { if (i.customId === "next") { await i.deferUpdate(); @@ -89,7 +88,7 @@ function generateQueueEmbed(interaction: ChatInputCommandInteraction, .setAuthor({ name: "Track Queue" }) .setTitle(`Current Song - ${songs[0].title}`) .setURL(songs[0].url) - .setThumbnail(interaction.guild?.iconURL() as string) + .setThumbnail(interaction.guild!.iconURL() as string) .setDescription(`**Displaying the queue list below:**\n\n${info}`) .setFooter({ text: `${songs.length} tracks.` }); diff --git a/src/commands/music/remove.ts b/src/commands/music/remove.ts index 7f83818..af87473 100644 --- a/src/commands/music/remove.ts +++ b/src/commands/music/remove.ts @@ -12,9 +12,9 @@ export default { .setDescription("The number of the track that you want to remove.") .setRequired(true) ), - execute(interaction) { - const queue = interaction.client.queues.get(interaction.guild?.id as string); - const removeArgs: number = interaction.options.getNumber("tracks") as number; + async execute(interaction) { + const queue = interaction.client.queues.get(interaction.guild!.id); + const removeArgs = interaction.options.getNumber("tracks", true); const nothingToRemove = new EmbedBuilder() .setColor("NotQuiteBlack") @@ -26,8 +26,8 @@ export default { .setTitle("Track Player") .setDescription("You need to join the voice channel the bot is in."); - if (!canModifyQueue({ member: interaction.member as GuildMember })) return interaction.reply({ embeds: [notInBotChannel], ephemeral: true }); - if (!queue) return interaction.reply({ embeds: [nothingToRemove], ephemeral: true }); + if (!canModifyQueue({ member: interaction.member as GuildMember })) return await interaction.reply({ embeds: [notInBotChannel], ephemeral: true }); + if (!queue) return await interaction.reply({ embeds: [nothingToRemove], ephemeral: true }); const song = queue.songs.splice(removeArgs - 1, 1); const removeEmbed1 = new EmbedBuilder() @@ -35,6 +35,6 @@ export default { .setTitle("Track Player") .setDescription(`${interaction.user} removed **${song[0].title}** from the queue.`); - interaction.reply({ embeds: [removeEmbed1] }); + return await interaction.reply({ embeds: [removeEmbed1] }); } } as Command; diff --git a/src/commands/music/resume.ts b/src/commands/music/resume.ts index 7f1c3e9..53e542a 100644 --- a/src/commands/music/resume.ts +++ b/src/commands/music/resume.ts @@ -7,7 +7,7 @@ export default { .setName("resume") .setDescription("Resumes the currently non-playing track."), async execute(interaction) { - const queue = interaction.client.queues.get(interaction.guild?.id as string); + const queue = interaction.client.queues.get(interaction.guild!.id); const nothingPlaying = new EmbedBuilder() .setColor("NotQuiteBlack") @@ -19,17 +19,16 @@ export default { .setTitle("Track Player") .setDescription("You need to join the voice channel the bot is in."); - if (!canModifyQueue({ member: interaction.member as GuildMember })) return interaction.reply({ embeds: [notInBotChannel], ephemeral: true }); - if (!queue) return interaction.reply({ embeds: [nothingPlaying], ephemeral: true }); + if (!canModifyQueue({ member: interaction.member as GuildMember })) return await interaction.reply({ embeds: [notInBotChannel], ephemeral: true }); + if (!queue) return await interaction.reply({ embeds: [nothingPlaying], ephemeral: true }); if (queue.player.unpause()) { - const resumeEmbed = new EmbedBuilder() .setColor("NotQuiteBlack") .setTitle("Track Player") .setDescription(`${interaction.user} resumed the queue.`); - interaction.reply({ embeds: [resumeEmbed] }); + await interaction.reply({ embeds: [resumeEmbed] }); return true; } @@ -38,6 +37,6 @@ export default { .setTitle("Track Player") .setDescription("The queue is not paused."); - return interaction.reply({ embeds: [notPaused] }); + return await interaction.reply({ embeds: [notPaused] }); }, } as Command; diff --git a/src/commands/music/shuffle.ts b/src/commands/music/shuffle.ts index 2116173..c6fd5ef 100644 --- a/src/commands/music/shuffle.ts +++ b/src/commands/music/shuffle.ts @@ -6,8 +6,8 @@ export default { data: new SlashCommandBuilder() .setName("shuffle") .setDescription("Shuffles the queue."), - execute(interaction) { - const queue = interaction.client.queues.get(interaction.guild?.id as string); + async execute(interaction) { + const queue = interaction.client.queues.get(interaction.guild!.id); const nothingPlaying = new EmbedBuilder() .setColor("NotQuiteBlack") @@ -19,8 +19,8 @@ export default { .setTitle("Track Player") .setDescription("You need to join the voice channel the bot is in."); - if (!canModifyQueue({ member: interaction.member as GuildMember })) return interaction.reply({ embeds: [notInBotChannel], ephemeral: true }); - if (!queue) return interaction.reply({ embeds: [nothingPlaying], ephemeral: true }); + if (!canModifyQueue({ member: interaction.member as GuildMember })) return await interaction.reply({ embeds: [notInBotChannel], ephemeral: true }); + if (!queue) return await interaction.reply({ embeds: [nothingPlaying], ephemeral: true }); const songs = queue.songs; for (let i = songs.length - 1; i > 1; i--) { @@ -34,6 +34,6 @@ export default { .setTitle("Track Player") .setDescription(`${interaction.user} started queue shuffle.`); - interaction.reply({ embeds: [shuffleEmbed] }); + return await interaction.reply({ embeds: [shuffleEmbed] }); }, } as Command; diff --git a/src/commands/music/skip.ts b/src/commands/music/skip.ts index 7a7c830..450fb1e 100644 --- a/src/commands/music/skip.ts +++ b/src/commands/music/skip.ts @@ -6,8 +6,8 @@ export default { data: new SlashCommandBuilder() .setName("skip") .setDescription("Skips the currently playing song."), - execute(interaction) { - const queue = interaction.client.queues.get(interaction.guild?.id as string); + async execute(interaction) { + const queue = interaction.client.queues.get(interaction.guild!.id); const nothingPlaying = new EmbedBuilder() .setColor("NotQuiteBlack") @@ -19,8 +19,8 @@ export default { .setTitle("Track Player") .setDescription("You need to join the voice channel the bot is in."); - if (!canModifyQueue({ member: (interaction.member as GuildMember) })) return interaction.reply({ embeds: [notInBotChannel], ephemeral: true }); - if (!queue) return interaction.reply({ embeds: [nothingPlaying], ephemeral: true }); + if (!canModifyQueue({ member: (interaction.member as GuildMember) })) return await interaction.reply({ embeds: [notInBotChannel], ephemeral: true }); + if (!queue) return await interaction.reply({ embeds: [nothingPlaying], ephemeral: true }); queue.player.stop(true); @@ -29,6 +29,6 @@ export default { .setTitle("Track Player") .setDescription(`${interaction.user} skipped the track.`); - interaction.reply({ embeds: [skipEmbed] }); + return await interaction.reply({ embeds: [skipEmbed] }); }, } as Command; diff --git a/src/commands/music/skipto.ts b/src/commands/music/skipto.ts index cc7cb89..6173d39 100644 --- a/src/commands/music/skipto.ts +++ b/src/commands/music/skipto.ts @@ -1,6 +1,5 @@ import { type GuildMember, EmbedBuilder, SlashCommandBuilder } from "discord.js"; import { canModifyQueue } from "@components/QueueUtils"; -import type { Song } from "@components/Song"; import type { Command } from "@common"; export default { @@ -13,9 +12,9 @@ export default { .setDescription("The queue number to skip to.") .setRequired(true) ), - execute(interaction) { - const queue = interaction.client.queues.get(interaction.guild?.id as string); - const skipNum: number = interaction.options.getNumber("queue_number") as number; + async execute(interaction) { + const queue = interaction.client.queues.get(interaction.guild!.id); + const skipNum = interaction.options.getNumber("queue_number", true); const nothingPlaying = new EmbedBuilder() .setColor("NotQuiteBlack") @@ -32,13 +31,13 @@ export default { .setTitle("Track Player") .setDescription("You need to join the voice channel the bot is in."); - if (!canModifyQueue({ member: interaction.member as GuildMember })) return interaction.reply({ embeds: [notInBotChannel], ephemeral: true }); - if (!queue) return interaction.reply({ embeds: [nothingPlaying], ephemeral: true }); - if (skipNum > queue.songs.length) return interaction.reply({ embeds: [queueLength], ephemeral: true }); + if (!canModifyQueue({ member: interaction.member as GuildMember })) return await interaction.reply({ embeds: [notInBotChannel], ephemeral: true }); + if (!queue) return await interaction.reply({ embeds: [nothingPlaying], ephemeral: true }); + if (skipNum > queue.songs.length) return await interaction.reply({ embeds: [queueLength], ephemeral: true }); if (queue.loop) { for (let i = 0; i < skipNum - 2; i++) { - queue.songs.push(queue.songs.shift() as Song); + queue.songs.push(queue.songs.shift()!); } } else { queue.songs = queue.songs.slice(skipNum - 2); @@ -50,6 +49,6 @@ export default { .setTitle("Track Player") .setDescription(`${interaction.user} skipped ${skipNum - 1} tracks.`); - return interaction.reply({ embeds: [skipEmbed] }); + return await interaction.reply({ embeds: [skipEmbed] }); }, } as Command; diff --git a/src/commands/music/stop.ts b/src/commands/music/stop.ts index dc0ebfa..1bba3e8 100644 --- a/src/commands/music/stop.ts +++ b/src/commands/music/stop.ts @@ -6,8 +6,8 @@ export default { data: new SlashCommandBuilder() .setName("stop") .setDescription("Stops the queue."), - execute(interaction) { - const queue = interaction.client.queues.get(interaction.guild?.id as string); + async execute(interaction) { + const queue = interaction.client.queues.get(interaction.guild!.id); const nothingPlaying = new EmbedBuilder() .setColor("NotQuiteBlack") @@ -19,8 +19,8 @@ export default { .setTitle("Track Player") .setDescription("You need to join the voice channel the bot is in."); - if (!canModifyQueue({ member: interaction.member as GuildMember })) return interaction.reply({ embeds: [notInBotChannel], ephemeral: true }); - if (!queue) return interaction.reply({ embeds: [nothingPlaying], ephemeral: true }); + if (!canModifyQueue({ member: interaction.member as GuildMember })) return await interaction.reply({ embeds: [notInBotChannel], ephemeral: true }); + if (!queue) return await interaction.reply({ embeds: [nothingPlaying], ephemeral: true }); queue.songs = []; queue.player.stop(true); @@ -30,6 +30,6 @@ export default { .setTitle("Track Player") .setDescription(`${interaction.user} stopped the queue.`); - return interaction.reply({ embeds: [stopEmbed] }); + return await interaction.reply({ embeds: [stopEmbed] }); }, } as Command; diff --git a/src/commands/music/volume.ts b/src/commands/music/volume.ts index f1fecee..f9f59e5 100644 --- a/src/commands/music/volume.ts +++ b/src/commands/music/volume.ts @@ -11,9 +11,9 @@ export default { .setName("level") .setDescription("The volume level to set the music to.") ), - execute(interaction) { - const queue = interaction.client.queues.get(interaction.guild?.id as string); - const volTarget: number = interaction.options.getNumber("level") as number; + async execute(interaction) { + const queue = interaction.client.queues.get(interaction.guild!.id as string); + const volTarget = interaction.options.getNumber("level") as number; const notInVC = new EmbedBuilder() .setColor("NotQuiteBlack") @@ -30,16 +30,16 @@ export default { .setTitle("Track Player") .setDescription(`The current volume is: **${queue?.volume}%**.`); - if (!canModifyQueue({ member: interaction.member as GuildMember })) return interaction.reply({ embeds: [notInVC], ephemeral: true }); - if (!queue) return interaction.reply({ embeds: [nothingPlaying], ephemeral: true }); - if (!volTarget) return interaction.reply({ embeds: [currentVolume], ephemeral: true }); + if (!canModifyQueue({ member: interaction.member as GuildMember })) return await interaction.reply({ embeds: [notInVC], ephemeral: true }); + if (!queue) return await interaction.reply({ embeds: [nothingPlaying], ephemeral: true }); + if (!volTarget) return await interaction.reply({ embeds: [currentVolume], ephemeral: true }); const useNum0100 = new EmbedBuilder() .setColor("NotQuiteBlack") .setTitle("Track Player") .setDescription("Please use a number between 0 - 100."); - if (Number(volTarget) > 100 || Number(volTarget) < 0) return interaction.reply({ embeds: [useNum0100], ephemeral: true }); + if (Number(volTarget) > 100 || Number(volTarget) < 0) return await interaction.reply({ embeds: [useNum0100], ephemeral: true }); queue.volume = volTarget; queue.resource.volume?.setVolumeLogarithmic(volTarget / 100); @@ -49,6 +49,6 @@ export default { .setTitle("Track Player") .setDescription(`Volume set to: **${queue.volume}%**.`); - return interaction.reply({ embeds: [volumeEmbed] }); + return await interaction.reply({ embeds: [volumeEmbed] }); }, } as Command; diff --git a/src/commands/utility/serverinfo.ts b/src/commands/utility/serverinfo.ts index d8c2f36..ad0257d 100644 --- a/src/commands/utility/serverinfo.ts +++ b/src/commands/utility/serverinfo.ts @@ -8,7 +8,7 @@ export default { .setDescription("Displays information about the guild."), async execute(interaction) { const guild = interaction.guild!; - const owner = await guild.fetchOwner(); + const owner = await guild.fetchOwner({ cache: true }); const verificationLevels = { 0: "No level set.", 1: "Low.", diff --git a/src/commands/utility/userinfo.ts b/src/commands/utility/userinfo.ts index ce2b7f1..0e259f6 100644 --- a/src/commands/utility/userinfo.ts +++ b/src/commands/utility/userinfo.ts @@ -16,9 +16,9 @@ export default { await interaction.deferReply(); const user = interaction.options.getUser("user"); - const member = user ? interaction.guild?.members.resolve(user) : interaction.member as GuildMember; + const member = user ? interaction.guild!.members.resolve(user) : interaction.member as GuildMember; - if (!member) return interaction.editReply("Could not resolve the provided user."); + if (!member) return await interaction.editReply("Could not resolve the provided user."); const desiredPermissions = [ "KickMembers", @@ -34,9 +34,9 @@ export default { "ManageGuildExpressions", ]; - const permissions = member.permissions.toArray().filter(permission => desiredPermissions.includes(permission)).map(perm => PermissionFlagsBits[perm]); + const permissions = member.permissions.toArray().filter(permission => desiredPermissions.includes(permission)).map(perm => perm); - const acknowledgements = member.user.id === interaction.guild?.ownerId + const acknowledgements = member.user.id === interaction.guild!.ownerId ? "Server Owner" : member.permissions.has(PermissionFlagsBits.ManageGuild) ? "Server Manager" @@ -54,7 +54,7 @@ export default { .setThumbnail(member.user.avatarURL()) .addFields( { - name: "Joined " + interaction.guild?.name, + name: "Joined " + interaction.guild!.name, value: member.joinedAt!.toLocaleString(), inline: true, }, diff --git a/src/common/types.ts b/src/common/types.ts index 08cb101..2575eb8 100644 --- a/src/common/types.ts +++ b/src/common/types.ts @@ -15,21 +15,18 @@ declare module "discord.js" { export type Config = { TOKEN: string; DEVTOKEN: string; - DEVID: string; - CLIENT_ID: string; MAX_PLAYLIST_SIZE: number; SOUNDCLOUD_CLIENT_ID: string; SPOTIFY_SECRET_ID: string; SPOTIFY_CLIENT_ID: string; SPOTIFY_REFRESH_TOKEN: string; - PRUNING: boolean; STAY_TIME: number; DEFAULT_VOLUME: number; } export type Command = { data: SlashCommandBuilder | SlashCommandSubcommandsOnlyBuilder | SlashCommandOptionsOnlyBuilder | SlashCommandSubcommandBuilder | Omit; - execute(interaction: ChatInputCommandInteraction): Promise | any; + execute(interaction: ChatInputCommandInteraction): Promise; } export type QueueOptions = { diff --git a/src/components/Bot.ts b/src/components/Bot.ts index d9d0446..4e0343e 100644 --- a/src/components/Bot.ts +++ b/src/components/Bot.ts @@ -1,41 +1,51 @@ import { Client, type ClientOptions, Collection } from "discord.js"; +import { configDotenv } from "dotenv"; import type { Command } from "@common"; import { config } from "@components/config"; import { Manager } from "@manager"; import type { MusicQueue } from "@components/MusicQueue"; import { getFreeClientID, setToken } from "play-dl"; import { Logger } from "@components/Logger"; +import { hash } from "@utils"; export class Bot extends Client { public commands = new Collection(); public queues = new Collection(); public readonly debug: boolean = false; - public readonly version: string = "3.3.2"; - public readonly branch: string; + public readonly version: string = `3.4.0 (${hash})`; + public readonly branch: string = this.debug ? "development" : "stable"; constructor(options: ClientOptions) { - super(options); - Logger.log({ type: "STARTUP", msg: "Music Bot is initializing..." }); + try { + super(options); + if (this.debug) Logger.info({ type: "DEVELOPMENT", msg: "⚠️ Debug mode is enabled. ⚠️" }); - this.branch = this.debug ? "development" : "stable"; + /* Read .env values if configured */ + configDotenv(); - /* Music Authentication */ - getFreeClientID().then(id => - setToken({ - soundcloud: { - client_id: config.SOUNDCLOUD_CLIENT_ID.length ? config.SOUNDCLOUD_CLIENT_ID : id - }, - /* Spotify auth is not needed, you can delete this. */ - spotify: { - client_id: config.SPOTIFY_CLIENT_ID, - client_secret: config.SPOTIFY_SECRET_ID, - /* Put your country's region code. example: "gr", "us", "uk" */ - market: "gr", - refresh_token: config.SPOTIFY_REFRESH_TOKEN - } - })); + Logger.log({ type: "STARTUP", msg: "Music Bot is initializing..." }); - /* Bot Manager */ - this.login(this.debug ? config.DEVTOKEN : config.TOKEN).finally(() => new Manager(this)); + /* Music Authentication */ + getFreeClientID().then(id => + setToken({ + soundcloud: { + client_id: config.SOUNDCLOUD_CLIENT_ID.length ? config.SOUNDCLOUD_CLIENT_ID : id + }, + /* Spotify auth is not needed, you can delete this. */ + spotify: { + client_id: config.SPOTIFY_CLIENT_ID, + client_secret: config.SPOTIFY_SECRET_ID, + /* Put your country's region code. example: "gr", "us", "uk" */ + market: "gr", + refresh_token: config.SPOTIFY_REFRESH_TOKEN + } + })); + + this.login(this.debug ? config.DEVTOKEN : config.TOKEN); + + new Manager(this); + } catch (e: any) { + Logger.error({ type: "STARTUP", err: e }); + } } } diff --git a/src/components/Logger.ts b/src/components/Logger.ts index 85f3a8a..a14fb5b 100644 --- a/src/components/Logger.ts +++ b/src/components/Logger.ts @@ -5,41 +5,42 @@ import chalk from "chalk"; * @description The Music Bot Logger System. * @methods error, log, info, debug */ -export class Logger { +export const Logger = { /** * @name error * @description Error logger * @param type * @param err */ - public static error({ type, err }: { type: string; err: any; }): void { - return console.error(chalk.red(`${chalk.red.bold(`[${type}]`)} Error logged! ${err}`)); - } + error({ type, err }: { type: string; err: Error | string }): void { + const errorMessage = typeof err === "string" ? err : (err as Error).stack || String(err); + console.error(chalk.red(`${chalk.bold(`[${type}]`)} Error logged! ${errorMessage}`)); + }, /** * @name log * @description Normal Logger * @param type * @param msg */ - public static log({ type, msg }: { type: string; msg: string; }): void { - return console.log(chalk.green(`${chalk.green.bold(`[${type}]`)} ${msg}`)); - } + log({ type, msg }: { type: string; msg: string }): void { + console.log(chalk.yellowBright(`${chalk.bold(`[${type}]`)} ${msg}`)); + }, /** * @name info * @description Info Logger * @param type * @param msg */ - public static info({ type, msg }: { type: string; msg: string; }): void { - console.log(chalk.blueBright(`${chalk.blueBright.bold(`[${type}]`)} ${msg}`)); - } + info({ type, msg }: { type: string; msg: string }): void { + console.log(chalk.hex('#FFA500')(`${chalk.bold(`[${type}]`)} ${msg}`)); + }, /** * @name debug * @description Debug Logger * @param type * @param msg */ - public static debug({ type, msg }: { type: string; msg: string; }): void { - console.debug(chalk.blueBright(`${chalk.blueBright.bold(`[${type}]`)} ${msg}`)); + debug({ type, msg }: { type: string; msg: string; }): void { + console.debug(chalk.blueBright(`${chalk.bold(`[${type}]`)} ${msg}`)); } -} +}; \ No newline at end of file diff --git a/src/components/MusicQueue.ts b/src/components/MusicQueue.ts index dc1611e..255c93e 100644 --- a/src/components/MusicQueue.ts +++ b/src/components/MusicQueue.ts @@ -39,6 +39,7 @@ export class MusicQueue { public volume = config.DEFAULT_VOLUME || 50; public loop = false; public muted = false; + public pruning = false; public waitTimeout!: NodeJS.Timeout | null; private queueLock = false; private readyLock = false; @@ -128,7 +129,7 @@ export class MusicQueue { this.loop = false; this.player.stop(); - !config.PRUNING && this.textChannel.send("Queue ended.").catch((err) => Logger.error({ type: "MUSICCMDS", err: err })); + !this.pruning && this.textChannel.send("Queue ended.").catch((err) => Logger.error({ type: "MUSICCMDS", err: err })); if (this.waitTimeout !== null) return; @@ -141,7 +142,7 @@ export class MusicQueue { if (this.player.state.status == AudioPlayerStatus.Playing || this.songs.length) return; - this.bot.queues.delete(this.interaction.guild?.id as string); + this.bot.queues.delete(this.interaction.guild!.id as string); this.textChannel.send("Left channel due to inactivity."); }, config.STAY_TIME * 1000); } @@ -178,7 +179,7 @@ export class MusicQueue { try { const playingMessage = await this.textChannel.send((newState.resource as AudioResource).metadata.startMessage()); - if (config.PRUNING) setTimeout((): void => { + if (this.pruning) setTimeout((): void => { playingMessage.delete().catch(); }, 3000); } catch (err: any | Error) { diff --git a/src/components/config.ts b/src/components/config.ts index 016c5be..08339dd 100644 --- a/src/components/config.ts +++ b/src/components/config.ts @@ -2,15 +2,12 @@ import { Config } from "@common"; export const config: Config = { TOKEN: process.env.TOKEN || "", - CLIENT_ID: process.env.CLIENT_ID || "", DEVTOKEN: process.env.DEVTOKEN || "", - DEVID: process.env.DEVID || "", SOUNDCLOUD_CLIENT_ID: process.env.SOUNDCLOUD_CLIENT_ID || "", MAX_PLAYLIST_SIZE: Number(process.env.MAX_PLAYLIST_SIZE) || Number(20), SPOTIFY_CLIENT_ID: process.env.SPOTIFY_CLIENT_ID || "", SPOTIFY_SECRET_ID: process.env.SPOTIFY_SECRET_ID || "", SPOTIFY_REFRESH_TOKEN: process.env.SPOTIFY_REFRESH_TOKEN || "", - PRUNING: process.env.PRUNING === "true" ? true : false, STAY_TIME: Number(process.env.STAY_TIME) || Number(30), DEFAULT_VOLUME: Number(process.env.DEFAULT_VOLUME) || Number(50), }; diff --git a/src/manager/index.ts b/src/manager/index.ts index 6415727..f9cdf11 100644 --- a/src/manager/index.ts +++ b/src/manager/index.ts @@ -12,25 +12,30 @@ import type { Bot } from "@components/Bot"; export class Manager { private async loadModule(client: Bot, moduleFn: (client: Bot) => Promise, moduleName: string): Promise { try { + Logger.log({ type: "MANAGER", msg: `${moduleName} module is initializing.` }); await moduleFn(client); Logger.log({ type: "MANAGER", msg: `${moduleName} module has been initialized.` }); - } catch (err: any | Error) { + } catch (err: any) { Logger.error({ type: "MANAGER", err }); } } private async loadModules(client: Bot): Promise { + Logger.log({ type: "MANAGER", msg: "Initializing modules."}); + const modules = [ { fn: commands, name: "Commands Handler" }, { fn: ready, name: "Ready" }, ]; - const promises = modules.map(({ fn, name }) => this.loadModule(client, fn, name)); + for (const { fn, name } of modules) { + await this.loadModule(client, fn, name); + } - await Promise.all(promises); + Logger.log({ type: "MANAGER", msg: "All modules have been initialized." }); } public constructor(client: Bot) { - this.loadModules(client).then(() => Logger.log({ type: "MANAGER", msg: "All modules have been initialized." })); + this.loadModules(client).finally(() => Logger.log({ type: "STARTUP", msg: "Music Bot has initialized." })); } -} +} \ No newline at end of file diff --git a/src/manager/modules/commands.ts b/src/manager/modules/commands.ts index ea33a74..0edae65 100644 --- a/src/manager/modules/commands.ts +++ b/src/manager/modules/commands.ts @@ -13,16 +13,15 @@ export async function commands(client: Bot): Promise { try { await command.execute(interaction); } catch (err: any) { - Logger.error({ type: "INTERNALS/CMDHANDLER", err: err }); - interaction.replied || interaction.deferred ? await interaction.editReply({ content: "An error occurred while executing this command.", embeds: [] }) : await interaction.reply({ content: "An error occurred while executing this command.", embeds: [], ephemeral: true }); + Logger.error({ type: "CMDHANDLER", err: err.stack }); + if (!interaction.replied) await interaction.reply({ content: "An error occurred while executing this command.", ephemeral: true }).catch(e => Logger.error({ type: "CMDHANDLER", err: e })); } }); } -function isCommandInteraction(interaction: Interaction): interaction is ChatInputCommandInteraction { +function isCommandInteraction(interaction: Interaction): interaction is ChatInputCommandInteraction { return ( interaction.isChatInputCommand() && - !interaction.user.bot && - interaction.inGuild() + !interaction.user.bot ); } \ No newline at end of file diff --git a/src/manager/modules/ready.ts b/src/manager/modules/ready.ts index 75cd4fd..f09d905 100644 --- a/src/manager/modules/ready.ts +++ b/src/manager/modules/ready.ts @@ -3,53 +3,53 @@ import { Logger } from "@components/Logger"; import { commands as musicCmds } from "commands/music/index.js"; import { commands as infoCmds } from "commands/info/index.js"; import { commands as utilCmds } from "commands/utility/index.js"; -import { config } from "@components/config"; import type { Bot } from "@components/Bot"; +import chalk from "chalk"; export async function ready(client: Bot): Promise { - client.once("ready", async (): Promise => { - Logger.log({ type: "STARTUP", msg: "Music Bot has initialized." }); + await new Promise(async (resolve) => { + if (client.isReady() || client.once("ready", (c) => c.isReady())) { + await registerCommands(); + setupAutomaticPresence(); - await registerCommands(); - setupAutomaticPresence(); + resolve(); + }; }); async function registerCommands(): Promise { const commands = [...musicCmds, ...infoCmds, ...utilCmds]; - const auth = { - TOKEN: client.debug ? config.DEVTOKEN : config.TOKEN, - CLIENT_ID: client.debug ? config.DEVID : config.CLIENT_ID, - }; try { - // Add commands to Bot's commands collection for (let i = 0; i < commands.length; i++) { client.commands.set(commands[i].data.name, commands[i]); - if (client.debug) Logger.log({ type: "IMPORTER", msg: `${commands[i].data.name} has been loaded.` }); + if (client.debug) Logger.info({ type: "DEVELOPMENT READY/CMDS", msg: `${commands[i].data.name} has been loaded.` }); }; - // Register on the Discord API - await client.rest.put(Routes.applicationCommands(auth.CLIENT_ID), { - body: commands.map((cmd) => cmd.data.toJSON()) + await client.rest.put(Routes.applicationCommands(client.user!.id), { + body: commands.map(cmd => cmd.data.toJSON()) }); - Logger.log({ type: "SLASHCMDS", msg: `Successfully registered ${commands.length} commands on Discord.` }); - } catch (err: any | Error) { - Logger.error({ type: "SLASHCMDS/REST", err }); + Logger.log({ type: "READY/CMDS", msg: `Registered ${chalk.blueBright(commands.length)} commands on Discord.` }); + } catch (err: any) { + Logger.error({ type: "READY/CMDS", err }); } } function setupAutomaticPresence(): void { - let state = 0; + try { + let state = 0; - setInterval(() => { - const presences: [{ type: ActivityType, message: string }] = [ - { type: ActivityType.Listening, message: `music.` }, - ]; + setInterval(() => { + const presences: { type: ActivityType, message: string }[] = [ + { type: ActivityType.Listening, message: `music.` }, + ]; - state = (state + 1) % presences.length; - const presence = presences[state]; + state = (state + 1) % presences.length; + const presence = presences[state]; - client.user?.setActivity({ name: presence.message, type: presence.type }); - }, 10000); + client.user?.setActivity({ name: presence.message, type: presence.type }); + }, 10000); + } catch (e: any) { + Logger.error({ type: "READY/PRESENCE", err: e }); + } } } diff --git a/src/utils/queue.ts b/src/utils/queue.ts index d36bbfb..da69b79 100644 --- a/src/utils/queue.ts +++ b/src/utils/queue.ts @@ -1,5 +1,5 @@ import type { GuildMember } from "discord.js"; export function canModifyQueue({ member }: { member: GuildMember; }): boolean { - return member.voice.channelId === member.guild.members?.me?.voice.channelId; + return member.voice.channelId === member.guild.members.me?.voice.channelId; } diff --git a/src/utils/sleep.ts b/src/utils/sleep.ts index 0e77af9..8712113 100644 --- a/src/utils/sleep.ts +++ b/src/utils/sleep.ts @@ -2,6 +2,6 @@ * Sleep function with promises * */ -export function sleep({ ms }: { ms: number }): Promise { - return new Promise(resolve => setTimeout(resolve, ms)); -} +export function sleep({ ms }: { ms: number; }): Promise { + return new Promise((resolve) => setTimeout(resolve, ms)); +} \ No newline at end of file diff --git a/src/utils/timeConverter.ts b/src/utils/timeConverter.ts index e1e5b03..39b1808 100644 --- a/src/utils/timeConverter.ts +++ b/src/utils/timeConverter.ts @@ -23,4 +23,4 @@ export class timeConverter { return this.formatTime([days, hours, minutes, secs % 60]); } -} +} \ No newline at end of file