From 431d276ccb3e34f433efc634c5632392eca4337b Mon Sep 17 00:00:00 2001 From: hmes98318 <52697423+hmes98318@users.noreply.github.com> Date: Tue, 27 Jun 2023 22:04:02 +0800 Subject: [PATCH 01/64] intial commit --- .env | 6 +- Dockerfile | 17 - README.md | 121 +--- docker-compose.yml | 21 - package-lock.json | 921 ++++++++------------------- package.json | 22 +- src/commands/back.js | 34 - src/commands/dashboard.js | 69 -- src/commands/help.js | 84 --- src/commands/leave.js | 32 - src/commands/loop.js | 93 --- src/commands/nowplaying.js | 62 -- src/commands/pause.js | 28 - src/commands/ping.js | 20 - src/commands/play.js | 155 ----- src/commands/play.ts | 1 + src/commands/progress.js | 38 -- src/commands/queue.js | 65 -- src/commands/remove.js | 124 ---- src/commands/resume.js | 28 - src/commands/save.js | 56 -- src/commands/search.js | 233 ------- src/commands/seek.js | 77 --- src/commands/server.js | 29 - src/commands/shuffle.js | 28 - src/commands/skip.js | 55 -- src/commands/status.js | 58 -- src/commands/volume.js | 66 -- src/embeds/embeds.js | 139 ---- src/events/discord-player/player.js | 99 --- src/events/interactionCreate.js | 183 ------ src/events/messageCreate.js | 28 - src/events/ready.js | 42 -- src/events/voiceStateUpdate.js | 60 -- src/index.js | 191 ------ src/index.ts | 3 + src/utils/constants.js | 54 -- src/utils/functions/getOSVersion.js | 40 -- src/utils/functions/isValidUrl.js | 13 - src/utils/functions/timeToSeconds.js | 61 -- src/utils/functions/uptime.js | 22 - src/utils/functions/usage.js | 100 --- src/utils/functions/wait.js | 5 - src/utils/player/finishPlaying.js | 12 - src/utils/player/settings.js | 14 - tsconfig.json | 36 ++ 46 files changed, 309 insertions(+), 3336 deletions(-) delete mode 100644 Dockerfile delete mode 100644 docker-compose.yml delete mode 100644 src/commands/back.js delete mode 100644 src/commands/dashboard.js delete mode 100644 src/commands/help.js delete mode 100644 src/commands/leave.js delete mode 100644 src/commands/loop.js delete mode 100644 src/commands/nowplaying.js delete mode 100644 src/commands/pause.js delete mode 100644 src/commands/ping.js delete mode 100644 src/commands/play.js create mode 100644 src/commands/play.ts delete mode 100644 src/commands/progress.js delete mode 100644 src/commands/queue.js delete mode 100644 src/commands/remove.js delete mode 100644 src/commands/resume.js delete mode 100644 src/commands/save.js delete mode 100644 src/commands/search.js delete mode 100644 src/commands/seek.js delete mode 100644 src/commands/server.js delete mode 100644 src/commands/shuffle.js delete mode 100644 src/commands/skip.js delete mode 100644 src/commands/status.js delete mode 100644 src/commands/volume.js delete mode 100644 src/embeds/embeds.js delete mode 100644 src/events/discord-player/player.js delete mode 100644 src/events/interactionCreate.js delete mode 100644 src/events/messageCreate.js delete mode 100644 src/events/ready.js delete mode 100644 src/events/voiceStateUpdate.js delete mode 100644 src/index.js create mode 100644 src/index.ts delete mode 100644 src/utils/constants.js delete mode 100644 src/utils/functions/getOSVersion.js delete mode 100644 src/utils/functions/isValidUrl.js delete mode 100644 src/utils/functions/timeToSeconds.js delete mode 100644 src/utils/functions/uptime.js delete mode 100644 src/utils/functions/usage.js delete mode 100644 src/utils/functions/wait.js delete mode 100644 src/utils/player/finishPlaying.js delete mode 100644 src/utils/player/settings.js create mode 100644 tsconfig.json diff --git a/.env b/.env index 0d3ea8a..f2496ad 100644 --- a/.env +++ b/.env @@ -8,8 +8,4 @@ MAX_VOLUME = 100 AUTO_LEAVE = true AUTO_LEAVE_COOLDOWN = 5000 DISPLAY_VOICE_STATE = true -PORT = 33333 - -TEXT_QUERY_TYPE = "youtubeSearch" -URL_QUERY_TYPE = "auto" -DP_FORCE_YTDL_MOD = "play-dl" \ No newline at end of file +PORT = 33333 \ No newline at end of file diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index cc07b7e..0000000 --- a/Dockerfile +++ /dev/null @@ -1,17 +0,0 @@ -# FROM rockylinux:9.1.20230215 -FROM node:18.15 - -WORKDIR /bot - -# RUN dnf update -y -RUN apt update -y - -# RUN cd ~ && curl -sL https://rpm.nodesource.com/setup_18.x -o nodesource_setup.sh && bash nodesource_setup.sh -# RUN dnf install nodejs -y - -COPY . . - -RUN npm install -RUN npm install play-dl - -CMD [ "npm", "run", "start" ] \ No newline at end of file diff --git a/README.md b/README.md index 2106903..31a12c4 100644 --- a/README.md +++ b/README.md @@ -2,125 +2,6 @@ # Music Disc -GitHub package.json version - - -GitHub ### Discord.js v14 Music Bot -Supports **YouTube**, **Spotify**, **SoundCloud** streams. - - -### Reference version -[**node.js `v18.16.0`**](https://nodejs.org/en/) -[**discord.js `v14.11.0`**](https://www.npmjs.com/package/discord.js) - - -## Deploying with node.js - -### Clone the latest version of the repository -``` -git clone -b v1.4.2 https://github.com/hmes98318/Music-Disc.git -``` -or [**click here**](https://github.com/hmes98318/Music-Disc/releases) to download - - -### Install the dependencies -install all the dependencies from [`package.json`](./package.json) -``` -npm install -``` - -### Configure environment -[`.env`](./.env) -```env -TOKEN = "your_token" -NAME = "Music Disc" -PREFIX = "+" -PLAYING = "+help | music" -EMBEDS_COLOR = "#FFFFFF" -DEFAULT_VOLUME = 50 -MAX_VOLUME = 100 -AUTO_LEAVE = true -AUTO_LEAVE_COOLDOWN = 5000 -DISPLAY_VOICE_STATE = true -PORT = 33333 - -TEXT_QUERY_TYPE = "youtubeSearch" -URL_QUERY_TYPE = "auto" -DP_FORCE_YTDL_MOD = "play-dl" -``` - -
- Detailed description - - **`AUTO_LEAVE`** : After the music finished, can choose whether let the bot leave voice channel automatically or not. - **`AUTO_LEAVE_COOLDOWN`** : Timer for auto disconnect(ms). - **`DISPLAY_VOICE_STATE`** : Show voice channel status updates. -
- - **`TEXT_QUERY_TYPE`** : The default search engine for text search. - The following are the available options for **TEXT_QUERY_TYPE**: -
-      autoSearch, youtubeSearch, spotifySearch, soundcloudSearch, appleMusicSearch
-    
- - **`URL_QUERY_TYPE`** : The default search engine for links. - The following are the available options for **URL_QUERY_TYPE**: -
-      auto, youtube, spotifySong soundcloud, appleMusicSong
-    
- - **`DP_FORCE_YTDL_MOD`** : Streaming extractor settings. The default streaming library used is **play-dl**. - If you want to use another library, you can install one of the following libraries and change the `DP_FORCE_YTDL_MOD` setting. -
-      $ npm install ytdl-core
-      $ npm install @distube/ytdl-core
-    
-
- - -## Running the script -``` -npm run start -``` - - -## Deploying with Docker Compose -**image link** : https://hub.docker.com/r/hmes98318/music-disc -### put your Token into [`docker-compose.yml`](./docker-compose.yml) -```yml -version: '3.8' -services: - music-disc: - image: hmes98318/music-disc:1.4.2 - container_name: music-disc - restart: always - ports: - - 33333:33333 - environment: - TOKEN: "your_token" - PREFIX: "+" - PLAYING: "+help | music" - EMBEDS_COLOR: "#FFFFFF" - DEFAULT_VOLUME: 50 - MAX_VOLUME: 100 - AUTO_LEAVE: "true" - AUTO_LEAVE_COOLDOWN: 5000 - DISPLAY_VOICE_STATE: "true" - TEXT_QUERY_TYPE: "youtubeSearch" - URL_QUERY_TYPE: "auto" - DP_FORCE_YTDL_MOD: "play-dl" -``` - -### Start the container -``` -docker-compose up -d -``` - - -## Deploying with Replit -Watch it by clicking on the image down below -[![Music-Disc-with-Replit](https://img.youtube.com/vi/WH5aSHIebcc/0.jpg)](https://youtu.be/WH5aSHIebcc) - - +This is a version based on [LavaShark](https://lavashark.js.org/), currently under development. Stay tuned for updates. \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml deleted file mode 100644 index 45df1ff..0000000 --- a/docker-compose.yml +++ /dev/null @@ -1,21 +0,0 @@ -version: '3.8' -services: - music-disc: - image: hmes98318/music-disc:1.4.2 - container_name: music-disc - restart: always - ports: - - 33333:33333 - environment: - TOKEN: "your_token" - PREFIX: "+" - PLAYING: "+help | music" - EMBEDS_COLOR: "#FFFFFF" - DEFAULT_VOLUME: 50 - MAX_VOLUME: 100 - AUTO_LEAVE: "true" - AUTO_LEAVE_COOLDOWN: 5000 - DISPLAY_VOICE_STATE: "true" - TEXT_QUERY_TYPE: "youtubeSearch" - URL_QUERY_TYPE: "auto" - DP_FORCE_YTDL_MOD: "play-dl" \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 70738f7..3ff64bb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,56 +1,39 @@ { "name": "music-disc", - "version": "1.4.2", + "version": "2.0.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "music-disc", - "version": "1.4.2", + "version": "2.0.0", "license": "MIT", "dependencies": { - "@discord-player/equalizer": "^0.2.1", - "@discord-player/extractor": "^4.2.1", - "@discord-player/utils": "^0.2.1", - "@ffmpeg-installer/ffmpeg": "^1.1.0", "console-stamp": "^3.1.1", - "discord-player": "^6.3.0", "discord.js": "^14.11.0", "dotenv": "^16.0.3", "express": "^4.18.2", - "ms": "2.1.3", - "opusscript": "~0.0.8", - "play-dl": "^1.9.6" + "lavashark": "^1.1.0" + }, + "devDependencies": { + "@types/node": "^20.3.2", + "ts-node": "^10.9.1", + "typescript": "^4.9.5" }, "engines": { "node": ">=16.13.0" } }, - "node_modules/@discord-player/equalizer": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/@discord-player/equalizer/-/equalizer-0.2.1.tgz", - "integrity": "sha512-PPjX8TBwzM85YKEdpYYL8aGbdSLIk9RK1h/uU5jeyiF6Uu5CiLH/XctDfcGW8cSgoaU4J0R6a8svCs9yhzHXSw==" - }, - "node_modules/@discord-player/extractor": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@discord-player/extractor/-/extractor-4.2.1.tgz", - "integrity": "sha512-z1kqIyAteD5H22KE/VTuujdXq4D+lV9owv6SmpmoS1R/ss+skTCOe/jReHlQC2HBNo5flShgEzMDqtp/HxI7cA==", - "dependencies": { - "file-type": "^16.5.4", - "genius-lyrics": "^4.4.2", - "node-html-parser": "^6.1.4", - "reverbnation-scraper": "^2.0.0", - "soundcloud-scraper": "^5.0.3", - "spotify-url-info": "^3.2.3", - "youtube-sr": "^4.3.4" - } - }, - "node_modules/@discord-player/utils": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/@discord-player/utils/-/utils-0.2.1.tgz", - "integrity": "sha512-yPxfdO2N3i2YEEiwlLDNyuBEdnhV1mZaC7im2BI4FKn3ak1UAtVcbKeJhdd/va0A170+PZs3zUKVGldY0z/+ng==", + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dev": true, "dependencies": { - "@discordjs/collection": "^1.1.0" + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" } }, "node_modules/@discordjs/builders": { @@ -107,66 +90,6 @@ "node": ">=16.9.0" } }, - "node_modules/@discordjs/rest/node_modules/file-type": { - "version": "18.4.0", - "resolved": "https://registry.npmjs.org/file-type/-/file-type-18.4.0.tgz", - "integrity": "sha512-o6MQrZKTAK6WpvmQk3jqTVUmqxYBxW5bloUfrdH1ZnRFDvvAPNr+l+rgOxM3nkqWT+3khaj3FRMDydWe0xhu+w==", - "dependencies": { - "readable-web-to-node-stream": "^3.0.2", - "strtok3": "^7.0.0", - "token-types": "^5.0.1" - }, - "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/sindresorhus/file-type?sponsor=1" - } - }, - "node_modules/@discordjs/rest/node_modules/peek-readable": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/peek-readable/-/peek-readable-5.0.0.tgz", - "integrity": "sha512-YtCKvLUOvwtMGmrniQPdO7MwPjgkFBtFIrmfSbYmYuq3tKDV/mcfAhBth1+C3ru7uXIZasc/pHnb+YDYNkkj4A==", - "engines": { - "node": ">=14.16" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/Borewit" - } - }, - "node_modules/@discordjs/rest/node_modules/strtok3": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/strtok3/-/strtok3-7.0.0.tgz", - "integrity": "sha512-pQ+V+nYQdC5H3Q7qBZAz/MO6lwGhoC2gOAjuouGf/VO0m7vQRh8QNMl2Uf6SwAtzZ9bOw3UIeBukEGNJl5dtXQ==", - "dependencies": { - "@tokenizer/token": "^0.3.0", - "peek-readable": "^5.0.0" - }, - "engines": { - "node": ">=14.16" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/Borewit" - } - }, - "node_modules/@discordjs/rest/node_modules/token-types": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/token-types/-/token-types-5.0.1.tgz", - "integrity": "sha512-Y2fmSnZjQdDb9W4w4r1tswlMHylzWIeOKpx0aZH9BgGtACHhrk3OkT52AzwcuqTRBZtvvnTjDBh8eynMulu8Vg==", - "dependencies": { - "@tokenizer/token": "^0.3.0", - "ieee754": "^1.2.1" - }, - "engines": { - "node": ">=14.16" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/Borewit" - } - }, "node_modules/@discordjs/util": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/@discordjs/util/-/util-0.3.1.tgz", @@ -175,21 +98,6 @@ "node": ">=16.9.0" } }, - "node_modules/@discordjs/voice": { - "version": "0.16.0", - "resolved": "https://registry.npmjs.org/@discordjs/voice/-/voice-0.16.0.tgz", - "integrity": "sha512-ToGCvHD1cBscuW3p+C7zOF5+L7MJmU4GjdOARfNk9mkHyFFZq4grK+Sxr3QXKbp27DtfDBc9uqD4GUOYgxngfA==", - "dependencies": { - "@types/ws": "^8.5.4", - "discord-api-types": "^0.37.37", - "prism-media": "^1.3.5", - "tslib": "^2.5.0", - "ws": "^8.13.0" - }, - "engines": { - "node": ">=16.9.0" - } - }, "node_modules/@discordjs/ws": { "version": "0.8.3", "resolved": "https://registry.npmjs.org/@discordjs/ws/-/ws-0.8.3.tgz", @@ -209,122 +117,30 @@ "node": ">=16.9.0" } }, - "node_modules/@ffmpeg-installer/darwin-arm64": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/@ffmpeg-installer/darwin-arm64/-/darwin-arm64-4.1.5.tgz", - "integrity": "sha512-hYqTiP63mXz7wSQfuqfFwfLOfwwFChUedeCVKkBtl/cliaTM7/ePI9bVzfZ2c+dWu3TqCwLDRWNSJ5pqZl8otA==", - "cpu": [ - "arm64" - ], - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@ffmpeg-installer/darwin-x64": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@ffmpeg-installer/darwin-x64/-/darwin-x64-4.1.0.tgz", - "integrity": "sha512-Z4EyG3cIFjdhlY8wI9aLUXuH8nVt7E9SlMVZtWvSPnm2sm37/yC2CwjUzyCQbJbySnef1tQwGG2Sx+uWhd9IAw==", - "cpu": [ - "x64" - ], - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@ffmpeg-installer/ffmpeg": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@ffmpeg-installer/ffmpeg/-/ffmpeg-1.1.0.tgz", - "integrity": "sha512-Uq4rmwkdGxIa9A6Bd/VqqYbT7zqh1GrT5/rFwCwKM70b42W5gIjWeVETq6SdcL0zXqDtY081Ws/iJWhr1+xvQg==", - "optionalDependencies": { - "@ffmpeg-installer/darwin-arm64": "4.1.5", - "@ffmpeg-installer/darwin-x64": "4.1.0", - "@ffmpeg-installer/linux-arm": "4.1.3", - "@ffmpeg-installer/linux-arm64": "4.1.4", - "@ffmpeg-installer/linux-ia32": "4.1.0", - "@ffmpeg-installer/linux-x64": "4.1.0", - "@ffmpeg-installer/win32-ia32": "4.1.0", - "@ffmpeg-installer/win32-x64": "4.1.0" - } - }, - "node_modules/@ffmpeg-installer/linux-arm": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/@ffmpeg-installer/linux-arm/-/linux-arm-4.1.3.tgz", - "integrity": "sha512-NDf5V6l8AfzZ8WzUGZ5mV8O/xMzRag2ETR6+TlGIsMHp81agx51cqpPItXPib/nAZYmo55Bl2L6/WOMI3A5YRg==", - "cpu": [ - "arm" - ], - "hasInstallScript": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@ffmpeg-installer/linux-arm64": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/@ffmpeg-installer/linux-arm64/-/linux-arm64-4.1.4.tgz", - "integrity": "sha512-dljEqAOD0oIM6O6DxBW9US/FkvqvQwgJ2lGHOwHDDwu/pX8+V0YsDL1xqHbj1DMX/+nP9rxw7G7gcUvGspSoKg==", - "cpu": [ - "arm64" - ], - "hasInstallScript": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@ffmpeg-installer/linux-ia32": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@ffmpeg-installer/linux-ia32/-/linux-ia32-4.1.0.tgz", - "integrity": "sha512-0LWyFQnPf+Ij9GQGD034hS6A90URNu9HCtQ5cTqo5MxOEc7Rd8gLXrJvn++UmxhU0J5RyRE9KRYstdCVUjkNOQ==", - "cpu": [ - "ia32" - ], - "hasInstallScript": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@ffmpeg-installer/linux-x64": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@ffmpeg-installer/linux-x64/-/linux-x64-4.1.0.tgz", - "integrity": "sha512-Y5BWhGLU/WpQjOArNIgXD3z5mxxdV8c41C+U15nsE5yF8tVcdCGet5zPs5Zy3Ta6bU7haGpIzryutqCGQA/W8A==", - "cpu": [ - "x64" - ], - "hasInstallScript": true, - "optional": true, - "os": [ - "linux" - ] + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", + "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } }, - "node_modules/@ffmpeg-installer/win32-ia32": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@ffmpeg-installer/win32-ia32/-/win32-ia32-4.1.0.tgz", - "integrity": "sha512-FV2D7RlaZv/lrtdhaQ4oETwoFUsUjlUiasiZLDxhEUPdNDWcH1OU9K1xTvqz+OXLdsmYelUDuBS/zkMOTtlUAw==", - "cpu": [ - "ia32" - ], - "optional": true, - "os": [ - "win32" - ] + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", + "dev": true }, - "node_modules/@ffmpeg-installer/win32-x64": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@ffmpeg-installer/win32-x64/-/win32-x64-4.1.0.tgz", - "integrity": "sha512-Drt5u2vzDnIONf4ZEkKtFlbvwj6rI3kxw1Ck9fpudmtgaZIHD4ucsWB2lCZBXRxJgXR+2IMSti+4rtM4C4rXgg==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "win32" - ] + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } }, "node_modules/@sapphire/async-queue": { "version": "1.5.0", @@ -336,9 +152,9 @@ } }, "node_modules/@sapphire/shapeshift": { - "version": "3.9.0", - "resolved": "https://registry.npmjs.org/@sapphire/shapeshift/-/shapeshift-3.9.0.tgz", - "integrity": "sha512-iJpHmjAdwX9aSL6MvFpVyo+tkokDtInmSjoJHbz/k4VJfnim3DjvG0hgGEKWtWZgCu45RaLgcoNgR1fCPdIz3w==", + "version": "3.9.2", + "resolved": "https://registry.npmjs.org/@sapphire/shapeshift/-/shapeshift-3.9.2.tgz", + "integrity": "sha512-YRbCXWy969oGIdqR/wha62eX8GNHsvyYi0Rfd4rNW6tSVVa8p0ELiMEuOH/k8rgtvRoM+EMV7Csqz77YdwiDpA==", "dependencies": { "fast-deep-equal": "^3.1.3", "lodash": "^4.17.21" @@ -349,9 +165,9 @@ } }, "node_modules/@sapphire/snowflake": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/@sapphire/snowflake/-/snowflake-3.5.0.tgz", - "integrity": "sha512-SaluGqA1A233nK/Tc5obhnT/PCm6HboPo0sOKzS5vkYrgLa+CEDYgYrKKCBp3ky1nGbN0PRiyMKGYD1Rd0mZqg==", + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/@sapphire/snowflake/-/snowflake-3.5.1.tgz", + "integrity": "sha512-BxcYGzgEsdlG0dKAyOm0ehLGm2CafIrfQTZGWgkfKYbj+pNNsorZ7EotuZukc2MT70E0UbppVbtpBrqpzVzjNA==", "engines": { "node": ">=v14.0.0", "npm": ">=7.0.0" @@ -362,15 +178,39 @@ "resolved": "https://registry.npmjs.org/@tokenizer/token/-/token-0.3.0.tgz", "integrity": "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==" }, + "node_modules/@tsconfig/node10": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", + "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", + "dev": true + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "dev": true + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "dev": true + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", + "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", + "dev": true + }, "node_modules/@types/node": { - "version": "20.1.2", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.1.2.tgz", - "integrity": "sha512-CTO/wa8x+rZU626cL2BlbCDzydgnFNgc19h4YvizpTO88MFQxab8wqisxaofQJ/9bLGugRdWIuX/TbIs6VVF6g==" + "version": "20.3.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.3.2.tgz", + "integrity": "sha512-vOBLVQeCQfIcF/2Y7eKFTqrMnizK5lRNQ7ykML/5RuwVXVWxYkgwS7xbt4B6fKCUPgbSL5FSsjHQpaGQP/dQmw==" }, "node_modules/@types/ws": { - "version": "8.5.4", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.4.tgz", - "integrity": "sha512-zdQDHKUgcX/zBc4GrwsE/7dVdAD8JR4EuiAXiiUhhfyIJXXb2+PrGshFyeXWQPMmmZ2XxgaqclgpIC7eTXc1mg==", + "version": "8.5.5", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.5.tgz", + "integrity": "sha512-lwhs8hktwxSjf9UaZ9tG5M03PGogvFaH8gUgLNbN9HKIg0dvv6q+gkSuJ8HN4/VbyxkuLzCjlN7GquQ0gUJfIg==", "dependencies": { "@types/node": "*" } @@ -396,6 +236,27 @@ "node": ">= 0.6" } }, + "node_modules/acorn": { + "version": "8.9.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.9.0.tgz", + "integrity": "sha512-jaVNAFBHNLXspO543WnNNPZFRtavh3skAkITqD0/2aeMkKZTN+254PyhwxFYrk3vQ1xfY+2wbesJMs/JC8/PwQ==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", + "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -410,6 +271,12 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true + }, "node_modules/array-flatten": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", @@ -438,11 +305,6 @@ "npm": "1.2.8000 || >= 1.4.16" } }, - "node_modules/boolbase": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", - "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==" - }, "node_modules/busboy": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", @@ -489,42 +351,6 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/cheerio": { - "version": "1.0.0-rc.12", - "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.12.tgz", - "integrity": "sha512-VqR8m68vM46BNnuZ5NtnGBKIE/DfN0cRIzg9n40EIq9NOv90ayxLBXA8fXC5gquFRGJSTRqBq25Jt2ECLR431Q==", - "dependencies": { - "cheerio-select": "^2.1.0", - "dom-serializer": "^2.0.0", - "domhandler": "^5.0.3", - "domutils": "^3.0.1", - "htmlparser2": "^8.0.1", - "parse5": "^7.0.0", - "parse5-htmlparser2-tree-adapter": "^7.0.0" - }, - "engines": { - "node": ">= 6" - }, - "funding": { - "url": "https://github.com/cheeriojs/cheerio?sponsor=1" - } - }, - "node_modules/cheerio-select": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-2.1.0.tgz", - "integrity": "sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==", - "dependencies": { - "boolbase": "^1.0.0", - "css-select": "^5.1.0", - "css-what": "^6.1.0", - "domelementtype": "^2.3.0", - "domhandler": "^5.0.3", - "domutils": "^3.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/fb55" - } - }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -585,31 +411,11 @@ "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" }, - "node_modules/css-select": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz", - "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==", - "dependencies": { - "boolbase": "^1.0.0", - "css-what": "^6.1.0", - "domhandler": "^5.0.2", - "domutils": "^3.0.1", - "nth-check": "^2.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/fb55" - } - }, - "node_modules/css-what": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", - "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", - "engines": { - "node": ">= 6" - }, - "funding": { - "url": "https://github.com/sponsors/fb55" - } + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true }, "node_modules/dateformat": { "version": "4.6.3", @@ -627,11 +433,6 @@ "ms": "2.0.0" } }, - "node_modules/debug/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" - }, "node_modules/depd": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", @@ -649,30 +450,20 @@ "npm": "1.2.8000 || >= 1.4.16" } }, - "node_modules/discord-api-types": { - "version": "0.37.42", - "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.37.42.tgz", - "integrity": "sha512-1Huaj9cQ1W7/uryS8MZs/tZemnoKB94thM1cE40lep3rpU3q7WHqkdjN/veX0prTkYlPhcyLd/DeF/pBO8X8oQ==" - }, - "node_modules/discord-player": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/discord-player/-/discord-player-6.3.0.tgz", - "integrity": "sha512-+YA/ZsAOEMfZIWa2Xezcf9x1rIH9IP3Ak0uAt8e9x9Esv63v+hEtWgjeIgThxK+i5XgjUVQpPP2coesHA6MeUw==", - "dependencies": { - "@discord-player/equalizer": "^0.2.1", - "@discord-player/utils": "^0.2.1", - "@discordjs/voice": "latest", - "libsodium-wrappers": "^0.7.10" - }, - "funding": { - "url": "https://github.com/Androz2091/discord-player?sponsor=1" - }, - "peerDependencies": { - "@discord-player/extractor": "^4.2.1", - "discord.js": "14.x", - "youtube-sr": "4.x" + "node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true, + "engines": { + "node": ">=0.3.1" } }, + "node_modules/discord-api-types": { + "version": "0.37.46", + "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.37.46.tgz", + "integrity": "sha512-DeSi5WSWYTeXJJhdwACtpQycY3g4vLRvE2Ol5IlC0o//P2W+8jXPF447PuJn2fRH1nD7JGEJ3YMb0NB9+OQ7BQ==" + }, "node_modules/discord.js": { "version": "14.11.0", "resolved": "https://registry.npmjs.org/discord.js/-/discord.js-14.11.0.tgz", @@ -697,63 +488,15 @@ "node": ">=16.9.0" } }, - "node_modules/dom-serializer": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", - "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", - "dependencies": { - "domelementtype": "^2.3.0", - "domhandler": "^5.0.2", - "entities": "^4.2.0" - }, - "funding": { - "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" - } - }, - "node_modules/domelementtype": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", - "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fb55" - } - ] - }, - "node_modules/domhandler": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", - "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", - "dependencies": { - "domelementtype": "^2.3.0" - }, - "engines": { - "node": ">= 4" - }, - "funding": { - "url": "https://github.com/fb55/domhandler?sponsor=1" - } - }, - "node_modules/domutils": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz", - "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==", - "dependencies": { - "dom-serializer": "^2.0.0", - "domelementtype": "^2.3.0", - "domhandler": "^5.0.3" - }, - "funding": { - "url": "https://github.com/fb55/domutils?sponsor=1" - } - }, "node_modules/dotenv": { - "version": "16.0.3", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.3.tgz", - "integrity": "sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ==", + "version": "16.3.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.3.1.tgz", + "integrity": "sha512-IPzF4w4/Rd94bA9imS68tZBaYyBWSCE47V1RGuMrB94iyTOIEwRmVL2x/4An+6mETpLrKJ5hQkB8W4kFAadeIQ==", "engines": { "node": ">=12" + }, + "funding": { + "url": "https://github.com/motdotla/dotenv?sponsor=1" } }, "node_modules/ee-first": { @@ -769,17 +512,6 @@ "node": ">= 0.8" } }, - "node_modules/entities": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", - "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", - "engines": { - "node": ">=0.12" - }, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, "node_modules/escape-html": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", @@ -840,16 +572,16 @@ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" }, "node_modules/file-type": { - "version": "16.5.4", - "resolved": "https://registry.npmjs.org/file-type/-/file-type-16.5.4.tgz", - "integrity": "sha512-/yFHK0aGjFEgDJjEKP0pWCplsPFPhwyfwevf/pVxiN0tmE4L9LmwWxWukdJSHdoCli4VgQLehjJtwQBnqmsKcw==", + "version": "18.5.0", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-18.5.0.tgz", + "integrity": "sha512-yvpl5U868+V6PqXHMmsESpg6unQ5GfnPssl4dxdJudBrr9qy7Fddt7EVX1VLlddFfe8Gj9N7goCZH22FXuSQXQ==", "dependencies": { - "readable-web-to-node-stream": "^3.0.0", - "strtok3": "^6.2.4", - "token-types": "^4.1.1" + "readable-web-to-node-stream": "^3.0.2", + "strtok3": "^7.0.0", + "token-types": "^5.0.1" }, "engines": { - "node": ">=10" + "node": ">=14.16" }, "funding": { "url": "https://github.com/sindresorhus/file-type?sponsor=1" @@ -893,22 +625,14 @@ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" }, - "node_modules/genius-lyrics": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/genius-lyrics/-/genius-lyrics-4.4.3.tgz", - "integrity": "sha512-06L8GUg49FrUYEmSQvrSH74RH5S+qyerHwBpvk8vZLwWgpEw4mIWZDob5IpXT1ryhqazM9K6CXGNucKYPO8kng==", - "dependencies": { - "cheerio": "^1.0.0-rc.9", - "undici": "^5.8.2" - } - }, "node_modules/get-intrinsic": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.0.tgz", - "integrity": "sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz", + "integrity": "sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==", "dependencies": { "function-bind": "^1.1.1", "has": "^1.0.3", + "has-proto": "^1.0.1", "has-symbols": "^1.0.3" }, "funding": { @@ -934,6 +658,17 @@ "node": ">=8" } }, + "node_modules/has-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", + "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/has-symbols": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", @@ -945,37 +680,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/he": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", - "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", - "bin": { - "he": "bin/he" - } - }, - "node_modules/himalaya": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/himalaya/-/himalaya-1.1.0.tgz", - "integrity": "sha512-LLase1dHCRMel68/HZTFft0N0wti0epHr3nNY7ynpLbyZpmrKMQ8YIpiOV77TM97cNpC8Wb2n6f66IRggwdWPw==" - }, - "node_modules/htmlparser2": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz", - "integrity": "sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==", - "funding": [ - "https://github.com/fb55/htmlparser2?sponsor=1", - { - "type": "github", - "url": "https://github.com/sponsors/fb55" - } - ], - "dependencies": { - "domelementtype": "^2.3.0", - "domhandler": "^5.0.3", - "domutils": "^3.0.1", - "entities": "^4.4.0" - } - }, "node_modules/http-errors": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", @@ -1034,17 +738,17 @@ "node": ">= 0.10" } }, - "node_modules/libsodium": { - "version": "0.7.11", - "resolved": "https://registry.npmjs.org/libsodium/-/libsodium-0.7.11.tgz", - "integrity": "sha512-WPfJ7sS53I2s4iM58QxY3Inb83/6mjlYgcmZs7DJsvDlnmVUwNinBCi5vBT43P6bHRy01O4zsMU2CoVR6xJ40A==" - }, - "node_modules/libsodium-wrappers": { - "version": "0.7.11", - "resolved": "https://registry.npmjs.org/libsodium-wrappers/-/libsodium-wrappers-0.7.11.tgz", - "integrity": "sha512-SrcLtXj7BM19vUKtQuyQKiQCRJPgbpauzl3s0rSwD+60wtHqSUuqcoawlMDheCJga85nKOQwxNYQxf/CKAvs6Q==", + "node_modules/lavashark": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/lavashark/-/lavashark-1.1.0.tgz", + "integrity": "sha512-0/13pC/ZU7bIddfFbNX277otd3LVxS2GywTelc0bsY65ZRNQC0V8l4TNNNk1Y0SYGB1wiSXOGjF9N+ueiiDP+w==", "dependencies": { - "libsodium": "^0.7.11" + "discord.js": "^14.11.0", + "undici": "^5.22.1", + "ws": "^8.13.0" + }, + "engines": { + "node": ">=16.9.0" } }, "node_modules/lodash": { @@ -1057,17 +761,11 @@ "resolved": "https://registry.npmjs.org/lodash.snakecase/-/lodash.snakecase-4.1.1.tgz", "integrity": "sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw==" }, - "node_modules/m3u8stream": { - "version": "0.8.6", - "resolved": "https://registry.npmjs.org/m3u8stream/-/m3u8stream-0.8.6.tgz", - "integrity": "sha512-LZj8kIVf9KCphiHmH7sbFQTVe4tOemb202fWwvJwR9W5ENW/1hxJN6ksAWGhQgSBSa3jyWhnjKU1Fw1GaOdbyA==", - "dependencies": { - "miniget": "^4.2.2", - "sax": "^1.2.4" - }, - "engines": { - "node": ">=12" - } + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true }, "node_modules/media-typer": { "version": "0.3.0", @@ -1120,18 +818,10 @@ "node": ">= 0.6" } }, - "node_modules/miniget": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/miniget/-/miniget-4.2.2.tgz", - "integrity": "sha512-a7voNL1N5lDMxvTMExOkg+Fq89jM2vY8pAi9ZEWzZtfNmdfP6RXkvUtFnCAXoCv2T9k1v/fUJVaAEuepGcvLYA==", - "engines": { - "node": ">=12" - } - }, "node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" }, "node_modules/negotiator": { "version": "0.6.3", @@ -1141,45 +831,6 @@ "node": ">= 0.6" } }, - "node_modules/node-fetch": { - "version": "2.6.11", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.11.tgz", - "integrity": "sha512-4I6pdBY1EthSqDmJkiNk3JIT8cswwR9nfeW/cPdUagJYEQG7R95WRH74wpz7ma8Gh/9dI9FP+OU+0E4FvtA55w==", - "dependencies": { - "whatwg-url": "^5.0.0" - }, - "engines": { - "node": "4.x || >=6.0.0" - }, - "peerDependencies": { - "encoding": "^0.1.0" - }, - "peerDependenciesMeta": { - "encoding": { - "optional": true - } - } - }, - "node_modules/node-html-parser": { - "version": "6.1.5", - "resolved": "https://registry.npmjs.org/node-html-parser/-/node-html-parser-6.1.5.tgz", - "integrity": "sha512-fAaM511feX++/Chnhe475a0NHD8M7AxDInsqQpz6x63GRF7xYNdS8Vo5dKsIVPgsOvG7eioRRTZQnWBrhDHBSg==", - "dependencies": { - "css-select": "^5.1.0", - "he": "1.2.0" - } - }, - "node_modules/nth-check": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", - "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", - "dependencies": { - "boolbase": "^1.0.0" - }, - "funding": { - "url": "https://github.com/fb55/nth-check?sponsor=1" - } - }, "node_modules/object-inspect": { "version": "1.12.3", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", @@ -1199,34 +850,6 @@ "node": ">= 0.8" } }, - "node_modules/opusscript": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/opusscript/-/opusscript-0.0.8.tgz", - "integrity": "sha512-VSTi1aWFuCkRCVq+tx/BQ5q9fMnQ9pVZ3JU4UHKqTkf0ED3fKEPdr+gKAAl3IA2hj9rrP6iyq3hlcJq3HELtNQ==" - }, - "node_modules/parse5": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", - "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", - "dependencies": { - "entities": "^4.4.0" - }, - "funding": { - "url": "https://github.com/inikulin/parse5?sponsor=1" - } - }, - "node_modules/parse5-htmlparser2-tree-adapter": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-7.0.0.tgz", - "integrity": "sha512-B77tOZrqqfUfnVcOrUvfdLbz4pu4RopLD/4vmu3HUPswwTA8OH0EMW9BlWR2B0RCoiZRAHEUu7IxeP1Pd1UU+g==", - "dependencies": { - "domhandler": "^5.0.2", - "parse5": "^7.0.0" - }, - "funding": { - "url": "https://github.com/inikulin/parse5?sponsor=1" - } - }, "node_modules/parseurl": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", @@ -1241,58 +864,17 @@ "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" }, "node_modules/peek-readable": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/peek-readable/-/peek-readable-4.1.0.tgz", - "integrity": "sha512-ZI3LnwUv5nOGbQzD9c2iDG6toheuXSZP5esSHBjopsXH4dg19soufvpUGA3uohi5anFtGb2lhAVdHzH6R/Evvg==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/peek-readable/-/peek-readable-5.0.0.tgz", + "integrity": "sha512-YtCKvLUOvwtMGmrniQPdO7MwPjgkFBtFIrmfSbYmYuq3tKDV/mcfAhBth1+C3ru7uXIZasc/pHnb+YDYNkkj4A==", "engines": { - "node": ">=8" + "node": ">=14.16" }, "funding": { "type": "github", "url": "https://github.com/sponsors/Borewit" } }, - "node_modules/play-audio": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/play-audio/-/play-audio-0.5.2.tgz", - "integrity": "sha512-ZAqHUKkQLix2Iga7pPbsf1LpUoBjcpwU93F1l3qBIfxYddQLhxS6GKmS0d3jV8kSVaUbr6NnOEcEMFvuX93SWQ==" - }, - "node_modules/play-dl": { - "version": "1.9.6", - "resolved": "https://registry.npmjs.org/play-dl/-/play-dl-1.9.6.tgz", - "integrity": "sha512-JW44bQbME9fNfGhGXQ/rdcsHr4BfgJabVlSgpS9QY/NscfprFH1asv+q9atrZThP3+hHIpgtFNABccg9rFWlwg==", - "dependencies": { - "play-audio": "^0.5.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/prism-media": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/prism-media/-/prism-media-1.3.5.tgz", - "integrity": "sha512-IQdl0Q01m4LrkN1EGIE9lphov5Hy7WWlH6ulf5QdGePLlPas9p2mhgddTEHrlaXYjjFToM1/rWuwF37VF4taaA==", - "peerDependencies": { - "@discordjs/opus": ">=0.8.0 <1.0.0", - "ffmpeg-static": "^5.0.2 || ^4.2.7 || ^3.0.0 || ^2.4.0", - "node-opus": "^0.3.3", - "opusscript": "^0.0.8" - }, - "peerDependenciesMeta": { - "@discordjs/opus": { - "optional": true - }, - "ffmpeg-static": { - "optional": true - }, - "node-opus": { - "optional": true - }, - "opusscript": { - "optional": true - } - } - }, "node_modules/proxy-addr": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", @@ -1369,14 +951,6 @@ "url": "https://github.com/sponsors/Borewit" } }, - "node_modules/reverbnation-scraper": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/reverbnation-scraper/-/reverbnation-scraper-2.0.0.tgz", - "integrity": "sha512-t1Mew5QC9QEVEry5DXyagvci2O+TgXTGoMHbNoW5NRz6LTOzK/DLHUpnrQwloX8CVX5z1a802vwHM3YgUVOvKg==", - "dependencies": { - "node-fetch": "^2.6.0" - } - }, "node_modules/safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", @@ -1401,11 +975,6 @@ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, - "node_modules/sax": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", - "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" - }, "node_modules/send": { "version": "0.18.0", "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", @@ -1429,6 +998,11 @@ "node": ">= 0.8.0" } }, + "node_modules/send/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, "node_modules/serve-static": { "version": "1.15.0", "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", @@ -1461,36 +1035,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/soundcloud-scraper": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/soundcloud-scraper/-/soundcloud-scraper-5.0.3.tgz", - "integrity": "sha512-AmS9KmK7mMaPVzHzBk40rANpAttZila3+iAet6EA47EeiTBUzVwjq4B+1LCOLtgPmzDSGk0qn+LZOEd5UhnZTQ==", - "dependencies": { - "cheerio": "^1.0.0-rc.10", - "m3u8stream": "^0.8.4", - "node-fetch": "^2.6.1" - } - }, - "node_modules/spotify-uri": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/spotify-uri/-/spotify-uri-3.0.3.tgz", - "integrity": "sha512-mMstJ4dAMki6GbUjg94kp/h9ZH+7T7+ro/KUC00WVh+WKoLgMRrTKLkWMIwCZNO53Xa8DRHQw/6jwYtRZrVI3g==", - "engines": { - "node": ">= 12" - } - }, - "node_modules/spotify-url-info": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/spotify-url-info/-/spotify-url-info-3.2.3.tgz", - "integrity": "sha512-h7LCEM86kE68uWWAW0+NbKP+33qPC00SsbdJXzvmzNc18aIA/NukTi8gKZKEwHBENusLX0VRsHfIhyKDg7Fong==", - "dependencies": { - "himalaya": "~1.1.0", - "spotify-uri": "~3.0.3" - }, - "engines": { - "node": ">= 12" - } - }, "node_modules/statuses": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", @@ -1516,15 +1060,15 @@ } }, "node_modules/strtok3": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/strtok3/-/strtok3-6.3.0.tgz", - "integrity": "sha512-fZtbhtvI9I48xDSywd/somNqgUHl2L2cstmXCCif0itOf96jeW18MBSyrLuNicYQVkvpOxkZtkzujiTJ9LW5Jw==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/strtok3/-/strtok3-7.0.0.tgz", + "integrity": "sha512-pQ+V+nYQdC5H3Q7qBZAz/MO6lwGhoC2gOAjuouGf/VO0m7vQRh8QNMl2Uf6SwAtzZ9bOw3UIeBukEGNJl5dtXQ==", "dependencies": { "@tokenizer/token": "^0.3.0", - "peek-readable": "^4.1.0" + "peek-readable": "^5.0.0" }, "engines": { - "node": ">=10" + "node": ">=14.16" }, "funding": { "type": "github", @@ -1551,35 +1095,73 @@ } }, "node_modules/token-types": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/token-types/-/token-types-4.2.1.tgz", - "integrity": "sha512-6udB24Q737UD/SDsKAHI9FCRP7Bqc9D/MQUV02ORQg5iskjtLJlZJNdN4kKtcdtwCeWIwIHDGaUsTsCCAa8sFQ==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/token-types/-/token-types-5.0.1.tgz", + "integrity": "sha512-Y2fmSnZjQdDb9W4w4r1tswlMHylzWIeOKpx0aZH9BgGtACHhrk3OkT52AzwcuqTRBZtvvnTjDBh8eynMulu8Vg==", "dependencies": { "@tokenizer/token": "^0.3.0", "ieee754": "^1.2.1" }, "engines": { - "node": ">=10" + "node": ">=14.16" }, "funding": { "type": "github", "url": "https://github.com/sponsors/Borewit" } }, - "node_modules/tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" - }, "node_modules/ts-mixer": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/ts-mixer/-/ts-mixer-6.0.3.tgz", "integrity": "sha512-k43M7uCG1AkTyxgnmI5MPwKoUvS/bRvLvUb7+Pgpdlmok8AoqmUaZxUUw8zKM5B1lqZrt41GjYgnvAi0fppqgQ==" }, + "node_modules/ts-node": { + "version": "10.9.1", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", + "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", + "dev": true, + "dependencies": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, "node_modules/tslib": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", - "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==" + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.0.tgz", + "integrity": "sha512-7At1WUettjcSRHXCyYtTselblcHl9PJFFVKiCAy/bY97+BPZXSQ2wbq0P9s8tK2G7dFQfNnlJnPAiArVBVBsfA==" }, "node_modules/type-is": { "version": "1.6.18", @@ -1593,6 +1175,19 @@ "node": ">= 0.6" } }, + "node_modules/typescript": { + "version": "4.9.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", + "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, "node_modules/undici": { "version": "5.22.1", "resolved": "https://registry.npmjs.org/undici/-/undici-5.22.1.tgz", @@ -1625,6 +1220,12 @@ "node": ">= 0.4.0" } }, + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "dev": true + }, "node_modules/vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", @@ -1633,20 +1234,6 @@ "node": ">= 0.8" } }, - "node_modules/webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" - }, - "node_modules/whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", - "dependencies": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } - }, "node_modules/ws": { "version": "8.13.0", "resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz", @@ -1667,10 +1254,14 @@ } } }, - "node_modules/youtube-sr": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/youtube-sr/-/youtube-sr-4.3.4.tgz", - "integrity": "sha512-olSYcR80XigutCrePEXBX3/RJJrWfonJQj7+/ggBiWU0CzTDLE1q8+lpWTWCG0JpzhzILp/IB/Bq/glGqqr1TQ==" + "node_modules/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true, + "engines": { + "node": ">=6" + } } } } diff --git a/package.json b/package.json index 0d11ad0..3dce750 100644 --- a/package.json +++ b/package.json @@ -1,10 +1,12 @@ { "name": "music-disc", - "version": "1.4.2", + "version": "2.0.0", "description": "Discord Music Bot", - "main": "/src/index.js", + "main": "/src/index.ts", "scripts": { - "start": "node ./src/index.js" + "start": "node ./dist/src/index.js", + "build": "tsc", + "dev": "ts-node ./src/index.ts" }, "repository": { "type": "git", @@ -17,18 +19,16 @@ }, "homepage": "https://github.com/hmes98318/Music-Disc#readme", "dependencies": { - "@discord-player/equalizer": "^0.2.1", - "@discord-player/extractor": "^4.2.1", - "@discord-player/utils": "^0.2.1", - "@ffmpeg-installer/ffmpeg": "^1.1.0", "console-stamp": "^3.1.1", - "discord-player": "^6.3.0", "discord.js": "^14.11.0", "dotenv": "^16.0.3", "express": "^4.18.2", - "ms": "2.1.3", - "opusscript": "~0.0.8", - "play-dl": "^1.9.6" + "lavashark": "^1.1.0" + }, + "devDependencies": { + "@types/node": "^20.3.2", + "ts-node": "^10.9.1", + "typescript": "^4.9.5" }, "engines": { "node": ">=16.13.0" diff --git a/src/commands/back.js b/src/commands/back.js deleted file mode 100644 index 4580aa0..0000000 --- a/src/commands/back.js +++ /dev/null @@ -1,34 +0,0 @@ -module.exports = { - name: 'back', - aliases: ['b', 'rewind'], - description: 'Back to previous song', - usage: 'back', - voiceChannel: true, - options: [], - - async execute(client, message) { - const queue = client.player.nodes.get(message.guild.id); - - if (!queue || !queue.isPlaying()) - return message.reply({ content: `āŒ | No music currently playing.`, allowedMentions: { repliedUser: false } }); - - if (!queue.history.previousTrack) - return message.reply({ content: `āŒ | There was no music playing before.`, allowedMentions: { repliedUser: false } }); - - await queue.history.back(); - return await message.react('šŸ‘'); - }, - - async slashExecute(client, interaction) { - const queue = client.player.nodes.get(interaction.guild.id); - - if (!queue || !queue.isPlaying()) - return interaction.reply({ content: `āŒ | No music currently playing.`, allowedMentions: { repliedUser: false } }); - - if (!queue.history.previousTrack) - return interaction.reply({ content: `āŒ | There was no music playing before.`, allowedMentions: { repliedUser: false } }); - - await queue.history.back(); - return await interaction.reply("āœ… | Music rewound."); - }, -}; \ No newline at end of file diff --git a/src/commands/dashboard.js b/src/commands/dashboard.js deleted file mode 100644 index 1cc9433..0000000 --- a/src/commands/dashboard.js +++ /dev/null @@ -1,69 +0,0 @@ -const { ActionRowBuilder, ButtonBuilder, ButtonStyle } = require('discord.js'); - -const embed = require('../embeds/embeds'); -const { button } = require('../utils/constants'); -const { settings } = require('../utils/player/settings'); - - -module.exports = { - name: 'dashboard', - aliases: ['d', 'main'], - description: 'Move the dashboard embed to the bottom', - usage: 'dashboard', - voiceChannel: true, - options: [], - - async execute(client, message) { - const queue = client.player.nodes.get(message.guild.id); - - if (!queue || !queue.isPlaying()) - return message.reply({ content: `āŒ | No music currently playing.`, allowedMentions: { repliedUser: false } }); - - - try { - await queue.dashboard.delete(); - } catch (error) { - console.log('Dashboard delete error:', error); - } - - let playing = queue.node.isPaused(); - - const playPauseButton = new ButtonBuilder().setCustomId('Playing-PlayPause').setEmoji(playing ? button.play : button.pause).setStyle(ButtonStyle.Secondary); - const skipButton = new ButtonBuilder().setCustomId('Playing-Skip').setEmoji(button.skip).setStyle(ButtonStyle.Secondary); - const stopButton = new ButtonBuilder().setCustomId('Playing-Stop').setEmoji(button.stop).setStyle(ButtonStyle.Danger); - const loopButton = new ButtonBuilder().setCustomId('Playing-Loop').setEmoji(button.loop).setStyle(ButtonStyle.Secondary); - const shuffleButton = new ButtonBuilder().setCustomId('Playing-Shuffle').setEmoji(button.shuffle).setStyle(ButtonStyle.Secondary); - const row = new ActionRowBuilder().addComponents(playPauseButton, skipButton, stopButton, loopButton, shuffleButton); - - const cur = queue.currentTrack; - queue.dashboard = await queue.metadata.channel.send({ embeds: [embed.Embed_dashboard('Dashboard', cur.title, cur.url, cur.thumbnail, settings(queue))], components: [row] }); - return await message.react('šŸ‘'); - }, - - async slashExecute(client, interaction) { - const queue = client.player.nodes.get(interaction.guild.id); - - if (!queue || !queue.isPlaying()) - return interaction.reply({ content: `āŒ | No music currently playing.`, allowedMentions: { repliedUser: false } }); - - - try { - await queue.dashboard.delete(); - } catch (error) { - console.log('Dashboard delete error:', error); - } - - let playing = queue.node.isPaused(); - - const playPauseButton = new ButtonBuilder().setCustomId('Playing-PlayPause').setEmoji(playing ? button.play : button.pause).setStyle(ButtonStyle.Secondary); - const skipButton = new ButtonBuilder().setCustomId('Playing-Skip').setEmoji(button.skip).setStyle(ButtonStyle.Secondary); - const loopButton = new ButtonBuilder().setCustomId('Playing-Loop').setEmoji(button.loop).setStyle(ButtonStyle.Secondary); - const stopButton = new ButtonBuilder().setCustomId('Playing-Stop').setEmoji(button.stop).setStyle(ButtonStyle.Danger); - const shuffleButton = new ButtonBuilder().setCustomId('Playing-Shuffle').setEmoji(button.shuffle).setStyle(ButtonStyle.Secondary); - const row = new ActionRowBuilder().addComponents(playPauseButton, skipButton, loopButton, stopButton, shuffleButton); - - const cur = queue.currentTrack; - queue.dashboard = await queue.metadata.channel.send({ embeds: [embed.Embed_dashboard('Dashboard', cur.title, cur.url, cur.thumbnail, settings(queue))], components: [row] }); - return await interaction.reply("āœ… | Dashboard updated."); - }, -}; \ No newline at end of file diff --git a/src/commands/help.js b/src/commands/help.js deleted file mode 100644 index 0be850a..0000000 --- a/src/commands/help.js +++ /dev/null @@ -1,84 +0,0 @@ -const embed = require('../embeds/embeds'); - - -module.exports = { - name: 'help', - aliases: ['h'], - showHelp: false, - description: 'Get commands help', - usage: 'help [command]', - options: [ - { - name: "command", - description: "which command need help", - type: 3, - required: false - } - ], - - execute(client, message, args) { - const prefix = client.config.prefix; - - if (!args[0]) { - let title = client.user.username; - let thumbnail = client.user.displayAvatarURL(); - const commands = client.commands.filter(x => x.showHelp !== false); - - let description = `**Available Commands**\n` + commands.map(x => `ā€¢ \`${prefix}${x.name}${x.aliases[0] ? ` (${x.aliases.map(y => y).join(', ')})\`` : '\`'}`).join('\n'); - - return message.reply({ embeds: [embed.Embed_help(title, thumbnail, description)], allowedMentions: { repliedUser: false } }); - } - else { - let helpCmd = args[0]; - const commands = client.commands.filter(x => x.showHelp !== false); - //console.log('helpCmd', helpCmd); - - let found = false; - found = commands.find(x => { - if (helpCmd === x.name || x.aliases.includes(helpCmd)) { - let command = x.name - let description = `${x.description}\n\`\`\`${prefix}${x.usage}\`\`\``; - - message.reply({ embeds: [embed.Embed_help2(command, description)], allowedMentions: { repliedUser: false } }); - return true; - } - }); - - if (!Boolean(found)) return message.reply({ content: 'āŒ | The command not found.', allowedMentions: { repliedUser: false } }); - } - }, - - slashExecute(client, interaction) { - const prefix = client.config.prefix; - const command = interaction.options.getString("command"); - - if (!command) { - let title = client.user.username; - let thumbnail = client.user.displayAvatarURL(); - const commands = client.commands.filter(x => x.showHelp !== false); - - let description = `**Available Commands**\n` + commands.map(x => `ā€¢ \`${prefix}${x.name}${x.aliases[0] ? ` (${x.aliases.map(y => y).join(', ')})\`` : '\`'}`).join('\n'); - - return interaction.reply({ embeds: [embed.Embed_help(title, thumbnail, description)], allowedMentions: { repliedUser: false } }); - - } - else { - let helpCmd = command; - const commands = client.commands.filter(x => x.showHelp !== false); - //console.log('helpCmd', helpCmd); - - let found = false; - found = commands.find(x => { - if (helpCmd === x.name || x.aliases.includes(helpCmd)) { - let command = x.name - let description = `${x.description}\n\`\`\`${prefix}${x.usage}\`\`\``; - - interaction.reply({ embeds: [embed.Embed_help2(command, description)], allowedMentions: { repliedUser: false } }); - return true; - } - }); - - if (!Boolean(found)) return interaction.reply({ content: 'āŒ | The command not found.', allowedMentions: { repliedUser: false } }); - } - }, -}; diff --git a/src/commands/leave.js b/src/commands/leave.js deleted file mode 100644 index 8664192..0000000 --- a/src/commands/leave.js +++ /dev/null @@ -1,32 +0,0 @@ -module.exports = { - name: 'leave', - aliases: ['stop'], - description: 'Leave current voice channel', - usage: 'leave', - voiceChannel: true, - options: [], - - execute(client, message) { - const queue = client.player.nodes.get(message.guild.id); - - if (!queue || !queue.isPlaying()) - return message.reply({ content: `āŒ | There is no music currently playing.`, allowedMentions: { repliedUser: false } }); - - if (!queue.deleted) - queue.delete(); - - return message.react('šŸ‘'); - }, - - slashExecute(client, interaction) { - const queue = client.player.nodes.get(interaction.guild.id); - - if (!queue || !queue.isPlaying()) - return interaction.reply({ content: `āŒ | There is no music currently playing.`, allowedMentions: { repliedUser: false } }); - - if (!queue.deleted) - queue.delete(); - - return interaction.reply('āœ… | Bot leave.'); - }, -}; \ No newline at end of file diff --git a/src/commands/loop.js b/src/commands/loop.js deleted file mode 100644 index 08a238d..0000000 --- a/src/commands/loop.js +++ /dev/null @@ -1,93 +0,0 @@ -module.exports = { - name: 'loop', - aliases: ['lp'], - description: 'Turns the music loop mode on or off', - usage: 'loop ', - voiceChannel: true, - options: [ - { - name: "mode", - description: "The loop mode", - type: 3, - required: true, - choices: [ - { - name: "Off", - value: "off" - }, - { - name: "All", - value: "all" - }, - { - name: "One", - value: "one" - }, - { - name: "Autoplay", - value: "ap" - } - ] - } - ], - - execute(client, message, args) { - const queue = client.player.nodes.get(message.guild.id); - const prefix = client.config.prefix; - - if (!queue || !queue.isPlaying()) - return message.reply({ content: `āŒ | There is no music currently playing.`, allowedMentions: { repliedUser: false } }); - - let mode = null; - const methods = ['Off', 'Single', 'All', 'Autoplay']; - - if (!args[0]) - return message.reply({ content: `āŒ | ${prefix}loop `, allowedMentions: { repliedUser: false } }); - - switch (args[0].toLowerCase()) { - case 'off': - mode = 0; - break; - case 'one' || 'single': - mode = 1; - break; - case 'all' || 'queue': - mode = 2; - break; - case 'ap' || 'autoplay': - mode = 3; - break; - default: - return message.reply({ content: `āŒ | ${prefix}loop `, allowedMentions: { repliedUser: false } }); - } - queue.setRepeatMode(mode); - - message.react('šŸ‘'); - return message.reply({ content: `Set loop to \`${methods[mode]}\``, allowedMentions: { repliedUser: false } }); - }, - - slashExecute(client, interaction) { - const queue = client.player.nodes.get(interaction.guild.id); - - if (!queue || !queue.isPlaying()) - return interaction.reply({ content: `āŒ | There is no music currently playing.`, allowedMentions: { repliedUser: false } }); - - - const methods = { - off: 0, - one: 1, - all: 2, - ap: 3 - } - const names = { - off: "Off", - one: "Single", - all: "All", - ap: "Autoplay" - } - - queue.setRepeatMode(methods[interaction.options.getString("mode")]); - - return interaction.reply({ content: `Set loop to \`${names[interaction.options.getString("mode")]}\``, allowedMentions: { repliedUser: false } }); - }, -}; \ No newline at end of file diff --git a/src/commands/nowplaying.js b/src/commands/nowplaying.js deleted file mode 100644 index 74f86b6..0000000 --- a/src/commands/nowplaying.js +++ /dev/null @@ -1,62 +0,0 @@ -const { ActionRowBuilder, ButtonBuilder, ButtonStyle } = require('discord.js'); -const embed = require('../embeds/embeds'); - - -module.exports = { - name: 'nowplaying', - aliases: ['np'], - description: 'Show now playing song', - usage: 'nowplaying', - voiceChannel: true, - options: [], - - execute(client, message) { - const queue = client.player.nodes.get(message.guild.id); - - if (!queue || !queue.isPlaying()) - return message.reply({ content: `āŒ | There is no music currently playing.`, allowedMentions: { repliedUser: false } }); - - - const track = queue.currentTrack; - const progress = queue.node.createProgressBar(); - const timestamp = queue.node.getTimestamp(); - const trackDuration = timestamp.progress == 'Forever' ? 'Endless (Live)' : track.duration; - let description = `Author : **${track.author}**\nDuration **${trackDuration}**\n` - + '\n' - + `${progress} (**${timestamp.progress}**%)`; - - - const saveButton = new ButtonBuilder() - .setCustomId('Save Song') - .setLabel('Save Song') - .setStyle(ButtonStyle.Success); - const row = new ActionRowBuilder().addComponents(saveButton); - - return message.channel.send({ embeds: [embed.Embed_save(track.title, track.url, track.thumbnail, description)], components: [row] }); - }, - - slashExecute(client, interaction) { - const queue = client.player.nodes.get(interaction.guild.id); - - if (!queue || !queue.isPlaying()) - return interaction.reply({ content: `āŒ | There is no music currently playing.`, allowedMentions: { repliedUser: false } }); - - - const track = queue.currentTrack; - const progress = queue.node.createProgressBar(); - const timestamp = queue.node.getTimestamp(); - const trackDuration = timestamp.progress == 'Forever' ? 'Endless (Live)' : track.duration; - let description = `Author : **${track.author}**\nDuration **${trackDuration}**\n` - + '\n' - + `${progress} (**${timestamp.progress}**%)`; - - - const saveButton = new ButtonBuilder() - .setCustomId('Save Song') - .setLabel('Save Song') - .setStyle(ButtonStyle.Success); - const row = new ActionRowBuilder().addComponents(saveButton); - - return interaction.reply({ embeds: [embed.Embed_save(track.title, track.url, track.thumbnail, description)], components: [row] }); - }, -}; \ No newline at end of file diff --git a/src/commands/pause.js b/src/commands/pause.js deleted file mode 100644 index ed5ed50..0000000 --- a/src/commands/pause.js +++ /dev/null @@ -1,28 +0,0 @@ -module.exports = { - name: 'pause', - aliases: [], - description: 'Pause current song', - usage: 'pause', - voiceChannel: true, - options: [], - - execute(client, message) { - const queue = client.player.nodes.get(message.guild.id); - - if (!queue || !queue.isPlaying()) - return message.reply({ content: `āŒ | There is no music currently playing!.`, allowedMentions: { repliedUser: false } }); - - const success = queue.node.pause(); - return success ? message.react('āøļø') : message.reply({ content: `āŒ | Something went wrong.`, allowedMentions: { repliedUser: false } }); - }, - - slashExecute(client, interaction) { - const queue = client.player.nodes.get(interaction.guild.id); - - if (!queue || !queue.isPlaying()) - return interaction.reply({ content: `āŒ | There is no music currently playing!.`, allowedMentions: { repliedUser: false } }); - - const success = queue.node.pause(); - return success ? interaction.reply("āøļø | Music paused.") : interaction.reply({ content: `āŒ | Something went wrong.`, allowedMentions: { repliedUser: false } }); - }, -}; \ No newline at end of file diff --git a/src/commands/ping.js b/src/commands/ping.js deleted file mode 100644 index 7fcd3ef..0000000 --- a/src/commands/ping.js +++ /dev/null @@ -1,20 +0,0 @@ -const embed = require('../embeds/embeds'); - - -module.exports = { - name: 'ping', - aliases: [], - description: 'Get server ping', - usage: 'ping', - options: [], - - execute(client, message) { - const botPing = `${Date.now() - message.createdTimestamp}ms`; - message.reply({ embeds: [embed.Embed_ping(botPing, client.ws.ping)], allowedMentions: { repliedUser: false } }); - }, - - slashExecute(client, interaction) { - const botPing = `${Date.now() - interaction.createdTimestamp}ms`; - interaction.reply({ embeds: [embed.Embed_ping(botPing, client.ws.ping)], allowedMentions: { repliedUser: false } }); - }, -}; diff --git a/src/commands/play.js b/src/commands/play.js deleted file mode 100644 index e8693c7..0000000 --- a/src/commands/play.js +++ /dev/null @@ -1,155 +0,0 @@ -const { isValidUrl } = require(`../utils/functions/isValidUrl`); - - -module.exports = { - name: 'play', - aliases: ['p'], - description: 'Enter your song link or song name to play', - usage: 'play ', - voiceChannel: true, - options: [ - { - name: "search", - description: "The song link or song name", - type: 3, - required: true - } - ], - - async execute(client, message, args) { - if (!args[0]) - return message.reply({ content: `āŒ | Write the name of the music you want to search.`, allowedMentions: { repliedUser: false } }); - - const str = args.join(' '); - let queryType = ''; - - if (isValidUrl(str)) queryType = client.config.urlQuery; - else queryType = client.config.textQuery; - - const results = await client.player.search(str, { - requestedBy: message.member, - searchEngine: queryType - }) - .catch((error) => { - console.log(error); - return message.reply({ content: `āŒ | The service is experiencing some problems, please try again.`, allowedMentions: { repliedUser: false } }); - }); - - if (!results || !results.hasTracks()) - return message.reply({ content: `āŒ | No results found.`, allowedMentions: { repliedUser: false } }); - - - /* - const queue = await client.player.play(message.member.voice.channel.id, results, { - nodeOptions: { - metadata: { - channel: message.channel, - client: message.guild.members.me, - requestedBy: message.user - }, - selfDeaf: true, - leaveOnEmpty: client.config.autoLeave, - leaveOnEnd: client.config.autoLeave, - leaveOnEmptyCooldown: client.config.autoLeaveCooldown, - leaveOnEndCooldown: client.config.autoLeaveCooldown, - volume: client.config.defaultVolume, - } - }); // The two play methods are the same - */ - const queue = await client.player.nodes.create(message.guild, { - metadata: { - channel: message.channel, - client: message.guild.members.me, - requestedBy: message.user - }, - selfDeaf: true, - leaveOnEmpty: client.config.autoLeave, - leaveOnEnd: client.config.autoLeave, - leaveOnEmptyCooldown: client.config.autoLeaveCooldown, - leaveOnEndCooldown: client.config.autoLeaveCooldown, - skipOnNoStream: true, - volume: client.config.defaultVolume, - connectionTimeout: 999_999_999 - }); - - try { - if (!queue.connection) - await queue.connect(message.member.voice.channel); - } catch (error) { - console.log(error); - if (!queue?.deleted) queue?.delete(); - return message.reply({ content: `āŒ | I can't join audio channel.`, allowedMentions: { repliedUser: false } }); - } - - results.playlist ? queue.addTrack(results.tracks) : queue.addTrack(results.tracks[0]); - - if (!queue.isPlaying()) { - await queue.node.play() - .catch((error) => { - console.log(error); - return message.reply({ content: `āŒ | I can't play this track.`, allowedMentions: { repliedUser: false } }); - }); - } - - return message.react('šŸ‘'); - }, - - async slashExecute(client, interaction) { - - const str = interaction.options.getString("search"); - let queryType = ''; - - if (isValidUrl(str)) queryType = client.config.urlQuery; - else queryType = client.config.textQuery; - - const results = await client.player.search(str, { - requestedBy: interaction.member, - searchEngine: queryType - }) - .catch((error) => { - console.log(error); - return interaction.reply({ content: `āŒ | The service is experiencing some problems, please try again.`, allowedMentions: { repliedUser: false } }); - }); - - if (!results || !results.tracks.length) - return interaction.reply({ content: `āŒ | No results found.`, allowedMentions: { repliedUser: false } }); - - - const queue = await client.player.nodes.create(interaction.guild, { - metadata: { - channel: interaction.channel, - client: interaction.guild.members.me, - requestedBy: interaction.user - }, - selfDeaf: true, - leaveOnEmpty: client.config.autoLeave, - leaveOnEnd: client.config.autoLeave, - leaveOnEmptyCooldown: client.config.autoLeaveCooldown, - leaveOnEndCooldown: client.config.autoLeaveCooldown, - skipOnNoStream: true, - volume: client.config.defaultVolume, - connectionTimeout: 999_999_999 - }); - - try { - if (!queue.connection) - await queue.connect(interaction.member.voice.channel); - } catch (error) { - console.log(error); - if (!queue?.deleted) queue?.delete(); - return interaction.reply({ content: `āŒ | I can't join audio channel.`, allowedMentions: { repliedUser: false } }); - } - - results.playlist ? queue.addTrack(results.tracks) : queue.addTrack(results.tracks[0]); - - if (!queue.isPlaying()) { - await queue.node.play() - .catch((error) => { - console.log(error); - return interaction.reply({ content: `āŒ | I can't play this track.`, allowedMentions: { repliedUser: false } }); - }); - } - - return interaction.reply("āœ… | Music added."); - }, -}; \ No newline at end of file diff --git a/src/commands/play.ts b/src/commands/play.ts new file mode 100644 index 0000000..8cec2e9 --- /dev/null +++ b/src/commands/play.ts @@ -0,0 +1 @@ +export {}; \ No newline at end of file diff --git a/src/commands/progress.js b/src/commands/progress.js deleted file mode 100644 index a05e5a2..0000000 --- a/src/commands/progress.js +++ /dev/null @@ -1,38 +0,0 @@ -module.exports = { - name: 'time', - aliases: ["t"], - description: 'show the current time of the song', - usage: 'time', - voiceChannel: true, - options: [], - - async execute(client, message) { - const queue = client.player.nodes.get(message.guild.id); - - if (!queue || !queue.isPlaying()) - return message.reply({ content: `āŒ | There is no music currently playing!.`, allowedMentions: { repliedUser: false } }); - - const progress = queue.node.createProgressBar(); - const timestamp = queue.node.getTimestamp(); - - if (timestamp.progress == 'Infinity') - return message.reply({ content: `āŒ | This song is live streaming, no duration data to display.`, allowedMentions: { repliedUser: false } }); - - return message.reply({ content: `${progress} (**${timestamp.progress}**%)`, allowedMentions: { repliedUser: false } }); - }, - - async slashExecute(client, interaction) { - const queue = client.player.nodes.get(interaction.guild.id); - - if (!queue || !queue.isPlaying()) - return interaction.reply({ content: `āŒ | There is no music currently playing!.`, allowedMentions: { repliedUser: false } }); - - const progress = queue.node.createProgressBar(); - const timestamp = queue.node.getTimestamp(); - - if (timestamp.progress == 'Infinity') - return interaction.reply({ content: `āŒ | This song is live streaming, no duration data to display.`, allowedMentions: { repliedUser: false } }); - - return interaction.reply({ content: `${progress} (**${timestamp.progress}**%)`, allowedMentions: { repliedUser: false } }); - }, -}; \ No newline at end of file diff --git a/src/commands/queue.js b/src/commands/queue.js deleted file mode 100644 index 60442ee..0000000 --- a/src/commands/queue.js +++ /dev/null @@ -1,65 +0,0 @@ -const embed = require('../embeds/embeds'); - - -module.exports = { - name: 'queue', - aliases: ['q', 'list'], - description: 'Show playlist', - usage: 'queue', - voiceChannel: true, - options: [], - - execute(client, message) { - const queue = client.player.nodes.get(message.guild.id); - - if (!queue || !queue.currentTrack) - return message.reply({ content: `āŒ | There is no music currently playing.`, allowedMentions: { repliedUser: false } }); - - - const tracks = queue.tracks.map((track, index) => `${++index}. ${track.title}`); - - let nowplaying = `Now Playing : ${queue.currentTrack.title}\n\n`; - let tracksQueue = ''; - - if (tracks.length < 1) { - tracksQueue = '------------------------------'; - } - else if (tracks.length > 9) { - tracksQueue = tracks.slice(0, 10).join('\n'); - tracksQueue += `\nand ${tracks.length - 10} other songs`; - } - else { - tracksQueue = tracks.join('\n'); - } - - let loopStatus = queue.repeatMode ? (queue.repeatMode === 2 ? 'All' : 'One') : 'Off'; - return message.reply({ embeds: [embed.Embed_queue("Queue List", nowplaying, tracksQueue, loopStatus)], allowedMentions: { repliedUser: false } }); - }, - - slashExecute(client, interaction) { - const queue = client.player.nodes.get(interaction.guild.id); - - if (!queue || !queue.currentTrack) - return interaction.reply({ content: `āŒ | There is no music currently playing.`, allowedMentions: { repliedUser: false } }); - - - const tracks = queue.tracks.map((track, index) => `${++index}. ${track.title}`); - - let nowplaying = `Now Playing : ${queue.currentTrack.title}\n\n`; - let tracksQueue = ''; - - if (tracks.length < 1) { - tracksQueue = '------------------------------'; - } - else if (tracks.length > 9) { - tracksQueue = tracks.slice(0, 10).join('\n'); - tracksQueue += `\nand ${tracks.length - 10} other songs`; - } - else { - tracksQueue = tracks.join('\n'); - } - - let loopStatus = queue.repeatMode ? (queue.repeatMode === 2 ? 'All' : 'One') : 'Off'; - return interaction.reply({ embeds: [embed.Embed_queue("Queue List", nowplaying, tracksQueue, loopStatus)] }); - }, -}; \ No newline at end of file diff --git a/src/commands/remove.js b/src/commands/remove.js deleted file mode 100644 index df2a420..0000000 --- a/src/commands/remove.js +++ /dev/null @@ -1,124 +0,0 @@ -const embed = require('../embeds/embeds'); - - -module.exports = { - name: 'remove', - aliases: ['r'], - description: 'Select a song to remove from the playlist', - usage: 'remove ', - voiceChannel: true, - options: [], - - async execute(client, message) { - const queue = client.player.nodes.get(message.guild.id); - - if (!queue || !queue.isPlaying()) - return message.reply({ content: `āŒ | There is no music currently playing.`, allowedMentions: { repliedUser: false } }); - - - const tracks = queue.tracks.map((track, index) => `${++index}. ${track.title}`); - - if (tracks.length < 1) - return message.reply({ content: `āŒ | No music in queue after current.`, allowedMentions: { repliedUser: false } }); - - - let nowplaying = `Now Playing : ${queue.currentTrack.title}\n\n`; - let tracksQueue = ''; - - if (tracks.length > 9) { - tracksQueue = tracks.slice(0, 10).join('\n'); - tracksQueue += `\nand ${tracks.length - 10} other songs`; - } - else { - tracksQueue = tracks.join('\n'); - } - - const instruction = `Choose a song from **1** to **${tracks.length}** to **remove** or enter others to cancel selection. ā¬‡ļø`; - let loopStatus = queue.repeatMode ? (queue.repeatMode === 2 ? 'All' : 'ONE') : 'Off'; - await message.reply({ content: instruction, embeds: [embed.Embed_queue("Remove List", nowplaying, tracksQueue, loopStatus)], allowedMentions: { repliedUser: false } }); - - - const collector = message.channel.createMessageCollector({ - time: 10000, // 10s - errors: ['time'], - filter: m => m.author.id === message.author.id - }); - - collector.on('collect', async (query) => { - - const index = parseInt(query.content); - - if (!index || index <= 0 || index > tracks.length) { - return message.reply({ content: `āœ… | Cancelled remove.`, allowedMentions: { repliedUser: false } }) - && collector.stop(); - } - - collector.stop(); - await queue.node.remove(index - 1); - - query.reply({ embeds: [embed.Embed_remove("Removed Music", tracks[index - 1])], allowedMentions: { repliedUser: false } }); - return query.react('šŸ‘'); - }); - - collector.on('end', (msg, reason) => { - if (reason === 'time') - return message.reply({ content: `āŒ | Song remove time expired`, allowedMentions: { repliedUser: false } }); - }); - }, - - async slashExecute(client, interaction) { - const queue = client.player.nodes.get(interaction.guild.id); - - if (!queue || !queue.isPlaying()) - return interaction.reply({ content: `āŒ | There is no music currently playing.`, allowedMentions: { repliedUser: false } }); - - - const tracks = queue.tracks.map((track, index) => `${++index}. ${track.title}`); - - if (tracks.length < 1) - return interaction.reply({ content: `āŒ | No music in queue after current.`, allowedMentions: { repliedUser: false } }); - - - let nowplaying = `Now Playing : ${queue.currentTrack.title}\n\n`; - let tracksQueue = ''; - - if (tracks.length > 9) { - tracksQueue = tracks.slice(0, 10).join('\n'); - tracksQueue += `\nand ${tracks.length - 10} other songs`; - } - else { - tracksQueue = tracks.join('\n'); - } - - const instruction = `Choose a song from **1** to **${tracks.length}** to **remove** or enter others to cancel selection. ā¬‡ļø`; - let loopStatus = queue.repeatMode ? (queue.repeatMode === 2 ? 'All' : 'ONE') : 'Off'; - await interaction.reply({ content: instruction, embeds: [embed.Embed_queue("Remove List", nowplaying, tracksQueue, loopStatus)], allowedMentions: { repliedUser: false } }); - - - const collector = interaction.channel.createMessageCollector({ - time: 10000, // 10s - errors: ['time'], - filter: m => m.author.id === interaction.user.id - }); - - collector.on('collect', async (query) => { - const index = parseInt(query.content); - - if (!index || index <= 0 || index > tracks.length) { - return query.reply({ content: `āœ… | Cancelled remove.`, allowedMentions: { repliedUser: false } }) - && collector.stop(); - } - - collector.stop(); - await queue.node.remove(index - 1); - - query.reply({ embeds: [embed.Embed_remove("Removed Music", tracks[index - 1])], allowedMentions: { repliedUser: false } }); - return query.react('šŸ‘'); - }); - - collector.on('end', (msg, reason) => { - if (reason === 'time') - return interaction.reply({ content: `āŒ | Song remove time expired`, allowedMentions: { repliedUser: false } }); - }); - }, -}; \ No newline at end of file diff --git a/src/commands/resume.js b/src/commands/resume.js deleted file mode 100644 index b4f6638..0000000 --- a/src/commands/resume.js +++ /dev/null @@ -1,28 +0,0 @@ -module.exports = { - name: 'resume', - aliases: [], - description: 'Resume paused song', - usage: 'resume', - voiceChannel: true, - options: [], - - execute(client, message) { - const queue = client.player.nodes.get(message.guild.id); - - if (!queue) - return message.reply({ content: `āŒ | There is no music currently playing.`, allowedMentions: { repliedUser: false } }); - - const success = queue.node.resume(); - return success ? message.react('ā–¶ļø') : message.reply({ content: `āŒ | Something went wrong.`, allowedMentions: { repliedUser: false } }); - }, - - slashExecute(client, interaction) { - const queue = client.player.nodes.get(interaction.guild.id); - - if (!queue) - return interaction.reply({ content: `āŒ | There is no music currently playing.`, allowedMentions: { repliedUser: false } }); - - const success = queue.node.resume(); - return success ? interaction.reply("ā–¶ļø | Music resumed.") : interaction.reply({ content: `āŒ | Something went wrong.`, allowedMentions: { repliedUser: false } }); - }, -}; \ No newline at end of file diff --git a/src/commands/save.js b/src/commands/save.js deleted file mode 100644 index 72399e4..0000000 --- a/src/commands/save.js +++ /dev/null @@ -1,56 +0,0 @@ -const embed = require('../embeds/embeds'); - - -module.exports = { - name: 'save', - aliases: [], - description: 'Save the current song', - usage: 'save', - voiceChannel: true, - options: [], - - async execute(client, message) { - const queue = client.player.nodes.get(message.guild.id); - - if (!queue || !queue.isPlaying()) - return message.reply({ content: `āŒ | There is no music currently playing!. `, allowedMentions: { repliedUser: false } }); - - - const track = queue.currentTrack; - const timestamp = queue.node.getTimestamp(); - const trackDuration = timestamp.progress == 'Forever' ? 'Endless (Live)' : track.duration; - let description = `Author : **${track.author}**\nDuration **${trackDuration}**`; - - message.author.send({ embeds: [embed.Embed_save(track.title, track.url, track.thumbnail, description)] }) - //message.author.send(`Registered track: **${track.title}** | ${track.author}, Saved server: **${message.guild.name}** āœ…`) - .then(() => { - message.react('šŸ‘'); - }) - .catch(error => { - console.log('error: ' + error); - message.react('āŒ'); - }); - }, - - async slashExecute(client, interaction) { - const queue = client.player.nodes.get(interaction.guild.id); - - if (!queue || !queue.isPlaying()) - return interaction.reply({ content: `āŒ | There is no music currently playing!. `, allowedMentions: { repliedUser: false } }); - - - const track = queue.currentTrack; - const timestamp = queue.node.getTimestamp(); - const trackDuration = timestamp.progress == 'Forever' ? 'Endless (Live)' : track.duration; - let description = `Author : **${track.author}**\nDuration **${trackDuration}**`; - - interaction.user.send({ embeds: [embed.Embed_save(track.title, track.url, track.thumbnail, description)] }) - .then(() => { - interaction.reply("āœ… | Music sent.") - }) - .catch(error => { - console.log('error: ' + error); - interaction.reply("āŒ | I can't send you the music.") - }); - }, -}; \ No newline at end of file diff --git a/src/commands/search.js b/src/commands/search.js deleted file mode 100644 index dabb56b..0000000 --- a/src/commands/search.js +++ /dev/null @@ -1,233 +0,0 @@ -const { StringSelectMenuBuilder, ActionRowBuilder } = require("discord.js"); -const { isValidUrl } = require(`../utils/functions/isValidUrl`); - - -module.exports = { - name: 'search', - aliases: ['find'], - description: 'Enter song name to search', - usage: 'search ', - voiceChannel: true, - options: [ - { - name: "search", - description: "The song name", - type: 3, - required: true - } - ], - - async execute(client, message, args) { - if (!args[0]) - return message.reply({ content: `āŒ | Please enter a valid song name.`, allowedMentions: { repliedUser: false } }); - - const str = args.join(' '); - let queryType = ''; - - if (isValidUrl(str)) queryType = client.config.urlQuery; - else queryType = client.config.textQuery; - - const results = await client.player.search(str, { - requestedBy: message.member, - searchEngine: queryType - }) - .catch((error) => { - console.log(error); - return message.reply({ content: `āŒ | The service is experiencing some problems, please try again.`, allowedMentions: { repliedUser: false } }); - }); - - if (!results || !results.hasTracks()) - return message.reply({ content: `āŒ | No results found.`, allowedMentions: { repliedUser: false } }); - - - const queue = await client.player.nodes.create(message.guild, { - metadata: { - channel: message.channel, - client: message.guild.members.me, - requestedBy: message.user - }, - selfDeaf: true, - leaveOnEmpty: client.config.autoLeave, - leaveOnEnd: client.config.autoLeave, - leaveOnEmptyCooldown: client.config.autoLeaveCooldown, - leaveOnEndCooldown: client.config.autoLeaveCooldown, - skipOnNoStream: true, - volume: client.config.defaultVolume, - connectionTimeout: 999_999_999 - }); - - - try { - if (!queue.connection) - await queue.connect(message.member.voice.channel); - } catch (error) { - console.log(error); - if (!queue?.deleted) queue?.delete(); - return message.reply({ content: `āŒ | I can't join audio channel.`, allowedMentions: { repliedUser: false } }); - } - - await message.react('šŸ‘'); - - if (results.playlist || results.tracks.length == 1) { - queue.addTrack(results.tracks); - - if (!queue.isPlaying()) { - await queue.node.play() - .catch((error) => { - console.log(error); - return message.reply({ content: `āŒ | I can't play this track.`, allowedMentions: { repliedUser: false } }); - }); - } - - return message.reply({ content: "āœ… | Music added.", allowedMentions: { repliedUser: false } }); - } - else { - let select = new StringSelectMenuBuilder() - .setCustomId("musicSelect") - .setPlaceholder("Select the music") - .setOptions(results.tracks.map(x => { - return { - label: x.title.length >= 25 ? x.title.substring(0, 22) + "..." : x.title, - description: x.title.length >= 25 ? `[${x.duration}] ${x.title}`.substring(0, 100) : `Duration: ${x.duration}`, - value: x.id - } - })); - let row = new ActionRowBuilder().addComponents(select); - let msg = await message.reply({ components: [row] }); - - const collector = msg.createMessageComponentCollector({ - time: 20000, // 20s - filter: i => i.user.id === message.author.id - }); - - collector.on("collect", async i => { - if (i.customId != "musicSelect") return; - - queue.addTrack(results.tracks.find(x => x.id == i.values[0])); - - if (!queue.isPlaying()) { - await queue.node.play() - .catch((error) => { - console.log(error); - return message.reply({ content: `āŒ | I can't play this track.`, allowedMentions: { repliedUser: false } }); - }); - } - - i.deferUpdate(); - return msg.edit({ content: "āœ… | Music added.", components: [], allowedMentions: { repliedUser: false } }); - }); - - collector.on("end", (collected, reason) => { - if (reason == "time" && collected.size == 0) { - if (!queue?.deleted && !queue.isPlaying()) queue?.delete(); - return msg.edit({ content: "āŒ | Time expired.", components: [], allowedMentions: { repliedUser: false } }); - } - }); - } - }, - - async slashExecute(client, interaction) { - await interaction.deferReply(); - - const str = interaction.options.getString("search"); - let queryType = ''; - - if (isValidUrl(str)) queryType = client.config.urlQuery; - else queryType = client.config.textQuery; - - const results = await client.player.search(str, { - requestedBy: interaction.member, - searchEngine: queryType - }) - .catch((error) => { - console.log(error); - return interaction.reply({ content: `āŒ | The service is experiencing some problems, please try again.`, allowedMentions: { repliedUser: false } }); - }); - - if (!results || !results.hasTracks()) - return interaction.editReply({ content: `āŒ | No search results found.`, allowedMentions: { repliedUser: false } }); - - - const queue = await client.player.nodes.create(interaction.guild, { - metadata: { - channel: interaction.channel, - client: interaction.guild.members.me, - requestedBy: interaction.user - }, - selfDeaf: true, - leaveOnEmpty: client.config.autoLeave, - leaveOnEnd: client.config.autoLeave, - leaveOnEmptyCooldown: client.config.autoLeaveCooldown, - leaveOnEndCooldown: client.config.autoLeaveCooldown, - skipOnNoStream: true, - volume: client.config.defaultVolume, - connectionTimeout: 999_999_999 - }); - - try { - if (!queue.connection) - await queue.connect(interaction.member.voice.channel); - } catch { - await client.player.deleteQueue(interaction.guild.id); - return interaction.editReply({ content: `āŒ | I can't join audio channel.`, allowedMentions: { repliedUser: false } }); - } - - - if (results.playlist || results.tracks.length == 1) { - queue.addTrack(results.tracks); - - if (!queue.isPlaying()) { - await queue.node.play() - .catch((error) => { - console.log(error); - return interaction.reply({ content: `āŒ | I can't play this track.`, allowedMentions: { repliedUser: false } }); - }); - } - - return interaction.editReply("āœ… | Music added."); - } - else { - let select = new StringSelectMenuBuilder() - .setCustomId("musicSelect") - .setPlaceholder("Select the music") - .setOptions(results.tracks.map(x => { - return { - label: x.title.length >= 25 ? x.title.substring(0, 22) + "..." : x.title, - description: x.title.length >= 25 ? `[${x.duration}] ${x.title}`.substring(0, 100) : `Duration: ${x.duration}`, - value: x.id - } - })); - let row = new ActionRowBuilder().addComponents(select); - let msg = await interaction.editReply({ components: [row] }); - - const collector = msg.createMessageComponentCollector({ - time: 20000, // 20s - filter: i => i.user.id === interaction.user.id - }); - - collector.on("collect", async i => { - if (i.customId != "musicSelect") return; - - queue.addTrack(results.tracks.find(x => x.id == i.values[0])); - - if (!queue.isPlaying()) { - await queue.node.play() - .catch((error) => { - console.log(error); - return interaction.reply({ content: `āŒ | I can't play this track.`, allowedMentions: { repliedUser: false } }); - }); - } - - i.deferUpdate(); - return interaction.editReply({ content: "āœ… | Music added.", components: [] }); - }); - - collector.on("end", (collected, reason) => { - if (reason == "time" && collected.size == 0) { - if (!queue?.deleted && !queue.isPlaying()) queue?.delete(); - return interaction.editReply({ content: "āŒ | Time expired.", components: [] }); - } - }); - } - }, -}; \ No newline at end of file diff --git a/src/commands/seek.js b/src/commands/seek.js deleted file mode 100644 index 1a56571..0000000 --- a/src/commands/seek.js +++ /dev/null @@ -1,77 +0,0 @@ -const { timeToSeconds } = require('../utils/functions/timeToSeconds'); - - -module.exports = { - name: 'seek', - aliases: [], - description: 'seek', - usage: 'seek <[hhmm]ss/[hh:mm]:ss> (ex: 3m20s, 1:20:55)', - voiceChannel: true, - options: [ - { - name: "seek", - description: "traget time (ex: 3m20s, 1:20:55)", - type: 3, - required: true - } - ], - - execute(client, message, args) { - const queue = client.player.nodes.get(message.guild.id); - - if (!queue) - return message.reply({ content: `āŒ | There is no music currently playing.`, allowedMentions: { repliedUser: false } }); - - if (!args[0]) - return message.reply({ content: `āŒ | Write the time of the music you want to seek.`, allowedMentions: { repliedUser: false } }); - - - const track = queue.currentTrack; - const timestamp = queue.node.getTimestamp(); - if (timestamp.progress == 'Forever') - return message.reply({ content: `āŒ | Can't seek in a live stream.`, allowedMentions: { repliedUser: false } }); - - - const str = args.join(' '); - const tragetTime = timeToSeconds(str); - const musicLength = timeToSeconds(track.duration); - - if(!tragetTime) - return message.reply({ content: `āŒ | Invalid format for the target time.\n(**\`ex: 3m20s, 1m 50s, 1:20:55, 5:20\`**)`, allowedMentions: { repliedUser: false } }); - - if (tragetTime >= musicLength) - return message.reply({ content: `āŒ | Target time exceeds music duration. (\`${track.duration}\`)`, allowedMentions: { repliedUser: false } }); - - - const success = queue.node.seek(tragetTime * 1000); - return success ? message.react('šŸ‘') : message.reply({ content: `āŒ | Something went wrong.`, allowedMentions: { repliedUser: false } }); - }, - - slashExecute(client, interaction) { - const queue = client.player.nodes.get(interaction.guild.id); - - if (!queue) - return interaction.reply({ content: `āŒ | There is no music currently playing.`, allowedMentions: { repliedUser: false } }); - - - const track = queue.currentTrack; - const timestamp = queue.node.getTimestamp(); - if (timestamp.progress == 'Forever') - return interaction.reply({ content: `āŒ | Can't seek in a live stream.`, allowedMentions: { repliedUser: false } }); - - - const str = interaction.options.getString("seek"); - const tragetTime = timeToSeconds(str); - const musicLength = timeToSeconds(track.duration); - - if(!tragetTime) - return interaction.reply({ content: `āŒ | Invalid format for the target time.\n(**\`ex: 3m20s, 1m 50s, 1:20:55, 5:20\`**)`, allowedMentions: { repliedUser: false } }); - - if (tragetTime >= musicLength) - return interaction.reply({ content: `āŒ | Target time exceeds music duration. (\`${track.duration}\`)`, allowedMentions: { repliedUser: false } }); - - - const success = queue.node.seek(tragetTime * 1000); - return success ? interaction.reply("āœ… | Music seeked.") : interaction.reply({ content: `āŒ | Something went wrong.`, allowedMentions: { repliedUser: false } }); - }, -}; \ No newline at end of file diff --git a/src/commands/server.js b/src/commands/server.js deleted file mode 100644 index 5882ef1..0000000 --- a/src/commands/server.js +++ /dev/null @@ -1,29 +0,0 @@ -const embed = require('../embeds/embeds'); - - -module.exports = { - name: 'server', - aliases: [], - showHelp: false, - description: 'Show currently active servers', - usage: 'server', - options: [], - - execute(client, message) { - let serverlist = ''; - serverlist = client.guilds.cache - .map(g => `Guild ID: ${g.id}\n Guild: ${g.name}\n Members: ${g.memberCount}`) - .join('\n\n'); - - return message.reply({ embeds: [embed.Embed_server(serverlist)], allowedMentions: { repliedUser: false } }); - }, - - slashExecute(client, interaction) { - let serverlist = ''; - serverlist = client.guilds.cache - .map(g => `Guild ID: ${g.id}\n Guild: ${g.name}\n Members: ${g.memberCount}`) - .join('\n\n'); - - return interaction.reply({ embeds: [embed.Embed_server(serverlist)], allowedMentions: { repliedUser: false } }); - }, -}; \ No newline at end of file diff --git a/src/commands/shuffle.js b/src/commands/shuffle.js deleted file mode 100644 index 6aeee1a..0000000 --- a/src/commands/shuffle.js +++ /dev/null @@ -1,28 +0,0 @@ -module.exports = { - name: 'shuffle', - aliases: ['random'], - description: 'Shuffle Playlist', - usage: 'random', - voiceChannel: true, - options: [], - - async execute(client, message) { - const queue = client.player.nodes.get(message.guild.id); - - if (!queue || !queue.isPlaying()) - return message.reply({ content: `āŒ | There is no music currently playing!.`, allowedMentions: { repliedUser: false } }); - - queue.tracks.shuffle(); - return message.react('šŸ‘'); - }, - - slashExecute(client, interaction) { - const queue = client.player.nodes.get(interaction.guild.id); - - if (!queue || !queue.isPlaying()) - return interaction.reply({ content: `āŒ | There is no music currently playing!.`, allowedMentions: { repliedUser: false } }); - - queue.tracks.shuffle(); - return interaction.reply('āœ… | Music shuffled.'); - }, -}; \ No newline at end of file diff --git a/src/commands/skip.js b/src/commands/skip.js deleted file mode 100644 index 4ebbe4c..0000000 --- a/src/commands/skip.js +++ /dev/null @@ -1,55 +0,0 @@ -module.exports = { - name: 'skip', - aliases: ['s'], - description: 'Skip currnet song', - usage: 'skip', - voiceChannel: true, - options: [], - - async execute(client, message) { - const queue = client.player.nodes.get(message.guild.id); - - if (!queue || !queue.isPlaying()) - return message.reply({ content: `āŒ | There is no music currently playing.`, allowedMentions: { repliedUser: false } }); - - - if (queue.repeatMode === 1) { - queue.setRepeatMode(0); - queue.node.skip(); - await wait(500); - queue.setRepeatMode(1); - } - else { - queue.node.skip(); - } - - return message.react('šŸ‘'); - }, - - async slashExecute(client, interaction) { - const queue = client.player.nodes.get(interaction.guild.id); - - if (!queue || !queue.isPlaying()) - return interaction.reply({ content: `āŒ | There is no music currently playing.`, allowedMentions: { repliedUser: false } }); - - - if (queue.repeatMode === 1) { - queue.setRepeatMode(0); - queue.node.skip(); - await wait(500); - queue.setRepeatMode(1); - } - else { - queue.node.skip(); - } - - return interaction.reply('āœ… | Music skipped.'); - }, -}; - - - - -const wait = (ms) => { - return new Promise((resolve) => setTimeout(() => resolve(), ms)); -}; \ No newline at end of file diff --git a/src/commands/status.js b/src/commands/status.js deleted file mode 100644 index fc66bd6..0000000 --- a/src/commands/status.js +++ /dev/null @@ -1,58 +0,0 @@ -const embed = require('../embeds/embeds'); -const { uptime } = require('../utils/functions/uptime'); -const { usage } = require('../utils/functions/usage'); - - -module.exports = { - name: 'status', - aliases: ['usage'], - description: 'Show the bot status', - usage: 'status', - options: [], - - async execute(client, message) { //uptime, os, node_v, djs_v, cpu, cpu_usage, ram, ping, serverCount - const botPing = `${Date.now() - message.createdTimestamp}ms`; - const load = await usage.cpu(); - const memory = usage.ram(); - const heap = usage.heap(); - - return message.reply({ - embeds: [embed.Embed_status( - uptime(client.status.uptime), - client.status.os_version, - client.status.node_version, - client.status.discord_version, - client.status.cpu, - (`${load.percent} \`${load.detail}\``), - (`${memory.percent} \`${memory.detail}\``), - (`${heap.percent} \`${heap.detail}\``), - { bot: (botPing), api: client.ws.ping }, - client.guilds.cache.size - )], - allowedMentions: { repliedUser: false } - }); - }, - - async slashExecute(client, interaction) { - const botPing = `${Date.now() - interaction.createdTimestamp}ms`; - const load = await usage.cpu(); - const memory = usage.ram(); - const heap = usage.heap(); - - return await interaction.reply({ - embeds: [embed.Embed_status( - uptime(client.status.uptime), - client.status.os_version, - client.status.node_version, - client.status.discord_version, - client.status.cpu, - (`${load.percent} \`${load.detail}\``), - (`${memory.percent} \`${memory.detail}\``), - (`${heap.percent} \`${heap.detail}\``), - { bot: (botPing), api: client.ws.ping }, - client.guilds.cache.size - )], - allowedMentions: { repliedUser: false } - }); - } -}; \ No newline at end of file diff --git a/src/commands/volume.js b/src/commands/volume.js deleted file mode 100644 index c5514cd..0000000 --- a/src/commands/volume.js +++ /dev/null @@ -1,66 +0,0 @@ -module.exports = { - name: 'volume', - aliases: ['v'], - description: `Configure bot volume`, - usage: 'v <0-100>', - voiceChannel: true, - options: [ - { - name: "volume", - description: "The volume to set", - type: 4, - required: true, - min_value: 1 - } - ], - - async execute(client, message, args) { - const maxVolume = client.config.maxVolume; - const queue = client.player.nodes.get(message.guild.id); - - if (!queue || !queue.isPlaying()) - return message.reply({ content: `āŒ | There is no music currently playing.`, allowedMentions: { repliedUser: false } }); - - - await message.react('šŸ‘'); - const vol = parseInt(args[0], 10); - - if (!vol) - return message.reply({ content: `Current volume: **${queue.node.volume}** šŸ”Š\n**To change the volume, with \`1\` to \`${maxVolume}\` Type a number between.**`, allowedMentions: { repliedUser: false } }); - - if (queue.volume === vol) - return message.reply({ content: `āŒ | The volume you want to change is already the current volume.`, allowedMentions: { repliedUser: false } }); - - if (vol < 0 || vol > maxVolume) - return message.reply({ content: `āŒ | **Type a number from \`1\` to \`${maxVolume}\` to change the volume .**`, allowedMentions: { repliedUser: false } }); - - - const success = queue.node.setVolume(vol); - const replymsg = success ? `šŸ”Š **${vol}**/**${maxVolume}**%` : `āŒ | Something went wrong.`; - return message.reply({ content: replymsg, allowedMentions: { repliedUser: false } }); - }, - - async slashExecute(client, interaction) { - const maxVolume = client.config.maxVolume; - const queue = client.player.nodes.get(interaction.guild.id); - - if (!queue || !queue.isPlaying()) - return interaction.reply({ content: `āŒ | There is no music currently playing.`, allowedMentions: { repliedUser: false } }); - - const vol = parseInt(interaction.options.getInteger("volume"), 10); - - if (!vol) - return interaction.reply({ content: `Current volume: **${queue.node.volume}** šŸ”Š\n**To change the volume, with \`1\` to \`${maxVolume}\` Type a number between.**`, allowedMentions: { repliedUser: false } }); - - if (queue.volume === vol) - return interaction.reply({ content: `āŒ | The volume you want to change is already the current volume.`, allowedMentions: { repliedUser: false } }); - - if (vol < 0 || vol > maxVolume) - return interaction.reply({ content: `āŒ | **Type a number from \`1\` to \`${maxVolume}\` to change the volume .**`, allowedMentions: { repliedUser: false } }); - - - const success = queue.node.setVolume(vol); - const replymsg = success ? `šŸ”Š **${vol}**/**${maxVolume}**%` : `āŒ | Something went wrong.`; - return interaction.reply({ content: replymsg, allowedMentions: { repliedUser: false } }); - }, -}; \ No newline at end of file diff --git a/src/embeds/embeds.js b/src/embeds/embeds.js deleted file mode 100644 index e066c67..0000000 --- a/src/embeds/embeds.js +++ /dev/null @@ -1,139 +0,0 @@ -const dotenv = require('dotenv'); -const Discord = require('discord.js'); - -dotenv.config(); -const ENV = process.env; - -const github = 'https://github.com/hmes98318/Music-Disc'; -const bot_version = require('../../package.json').version; - -const bot_name = typeof (process.env.BOT_NAME) === 'undefined' ? 'Music Disc' : (ENV.BOT_NAME); -const color = typeof (process.env.EMBEDS_COLOR) === 'undefined' ? '#FFFFFF' : (ENV.EMBEDS_COLOR); - - -module.exports = { - Embed_dashboard: function (status, music_title, music_url, music_thumbnail, music_description) { - const Embed_dashboard = new Discord.EmbedBuilder() - .setColor(color) - .setTitle(music_title) - .setURL(music_url) - .setThumbnail(music_thumbnail) - .addFields({ name: status, value: music_description }) - .setTimestamp() - return Embed_dashboard; - }, - - Embed_add: function (status, music_title, music_url, music_thumbnail, music_author, music_length) { - const Embed_add = new Discord.EmbedBuilder() - .setColor(color) - .setTitle(music_title) - .setURL(music_url) - .setThumbnail(music_thumbnail) - .addFields({ name: status, value: `Author : **${music_author}**\nDuration **${music_length}**`, inline: true }) - .setTimestamp() - return Embed_add; - }, - - Embed_queue: function (status, nowplay, queueMsg, loopStatus) { - const Embed_queue = new Discord.EmbedBuilder() - .setColor(color) - .setTitle(status) - .addFields({ name: nowplay, value: queueMsg }) - .setTimestamp() - .setFooter({ text: `Loop: ${loopStatus}` }); - return Embed_queue; - }, - - Embed_remove: function (status, music_title) { - const Embed_remove = new Discord.EmbedBuilder() - .setColor(color) - .setTitle(status) - .setDescription(`${music_title}`) - .setTimestamp() - return Embed_remove; - }, - - Embed_save: function (music_title, music_url, music_thumbnail, description) { - const Embed_queue = new Discord.EmbedBuilder() - .setColor(color) - .setTitle(music_title) - .setURL(music_url) - .setThumbnail(music_thumbnail) - .setDescription(description) - .setTimestamp() - return Embed_queue; - }, - - Embed_search: function (music_title, description) { - const Embed_cantFindSong = new Discord.EmbedBuilder() - .setColor(color) - .setTitle(music_title) - .setDescription(description) - .setTimestamp() - return Embed_cantFindSong; - }, - - Embed_help: function (help_title, help_thumbnail, description) { - const Embed_help = new Discord.EmbedBuilder() - .setColor(color) - .setTitle(help_title) - .setURL(github) - .setThumbnail(help_thumbnail) - .setDescription(description) - .setTimestamp() - return Embed_help; - }, - - Embed_help2: function (command, description) { - const Embed_help2 = new Discord.EmbedBuilder() - .setColor(color) - .setTitle(`Command **${command}**`, '') - .setDescription(description) - return Embed_help2; - }, - - Embed_status: function (uptime, os, node_v, djs_v, cpu, cpu_usage, ram, heap, ping, serverCount) { - const Embed_status = new Discord.EmbedBuilder() - .setColor(color) - .setTitle(`${bot_name} v${bot_version}`) - .setURL(github) - .setDescription(`**ā€¢ Serving ${serverCount} servers**\nā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”`) - .addFields( - { name: `āš™ļø SYSTEM`, value: `OS : **${os}**\nNode.js : **${node_v}**\nDiscord.js : **${djs_v}**\nCPU : **${cpu}**\nUptime : **${uptime}**\nā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”`, inline: false }, - { name: `šŸ“Š USAGE`, value: `CPU : **${cpu_usage}**\nRam : **${ram}**\nHeap : **${heap}**\nā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”`, inline: false }, - { name: `šŸ›°ļø LATENCY`, value: `Bot : **${ping.bot}**\nAPI : **${ping.api}ms**`, inline: false } - ) - .setTimestamp() - return Embed_status; - }, - - Embed_server: function (serverlist) { - const Embed_server = new Discord.EmbedBuilder() - .setColor(color) - .setTitle(`Servers that have **${bot_name}**`, '') - .setDescription(serverlist) - return Embed_server; - }, - - Embed_ping: function (bot, api) { - const Embed_ping = new Discord.EmbedBuilder() - .setColor(color) - .setTitle('šŸ›°ļø LATENCY') - .setDescription(`Bot : **${bot}**\nAPI : **${api}ms**`) - return Embed_ping; - }, - - Embed_connect: function () { - const Embed_connect = new Discord.EmbedBuilder() - .setColor(color) - .setDescription('Voice channel connected successfully.') - return Embed_connect; - }, - - Embed_disconnect: function () { - const Embed_disconnect = new Discord.EmbedBuilder() - .setColor(color) - .setDescription('Finished playing.') - return Embed_disconnect; - } -} \ No newline at end of file diff --git a/src/events/discord-player/player.js b/src/events/discord-player/player.js deleted file mode 100644 index 41d5dab..0000000 --- a/src/events/discord-player/player.js +++ /dev/null @@ -1,99 +0,0 @@ -const { ActionRowBuilder, ButtonBuilder, ButtonStyle } = require('discord.js'); - -const embed = require(`${__dirname}/../../embeds/embeds`); -const { button } = require(`${__dirname}/../../utils/constants`); -const { settings } = require(`${__dirname}/../../utils/player/settings`); -const { finishPlaying } = require(`${__dirname}/../../utils/player/finishPlaying`); - - -const registerPlayerEvents = (player, client) => { - - player.events.on('connection', async (queue) => { - const playPauseButton = new ButtonBuilder().setCustomId('Playing-PlayPause').setEmoji(button.pause).setStyle(ButtonStyle.Secondary); - const skipButton = new ButtonBuilder().setCustomId('Playing-Skip').setEmoji(button.skip).setStyle(ButtonStyle.Secondary); - const stopButton = new ButtonBuilder().setCustomId('Playing-Stop').setEmoji(button.stop).setStyle(ButtonStyle.Danger); - const loopButton = new ButtonBuilder().setCustomId('Playing-Loop').setEmoji(button.loop).setStyle(ButtonStyle.Secondary); - const shuffleButton = new ButtonBuilder().setCustomId('Playing-Shuffle').setEmoji(button.shuffle).setStyle(ButtonStyle.Secondary); - const row = new ActionRowBuilder().addComponents(playPauseButton, skipButton, stopButton, loopButton, shuffleButton); - - queue.dashboard = await queue.metadata.channel.send({ embeds: [embed.Embed_connect()], components: [row] }); - return; - }); - - player.events.on('playerStart', async (queue, track) => { - let playing = queue.node.isPaused(); - - const playPauseButton = new ButtonBuilder().setCustomId('Playing-PlayPause').setEmoji(playing ? button.play : button.pause).setStyle(ButtonStyle.Secondary); - const skipButton = new ButtonBuilder().setCustomId('Playing-Skip').setEmoji(button.skip).setStyle(ButtonStyle.Secondary); - const stopButton = new ButtonBuilder().setCustomId('Playing-Stop').setEmoji(button.stop).setStyle(ButtonStyle.Danger); - const loopButton = new ButtonBuilder().setCustomId('Playing-Loop').setEmoji(button.loop).setStyle(ButtonStyle.Secondary); - const shuffleButton = new ButtonBuilder().setCustomId('Playing-Shuffle').setEmoji(button.shuffle).setStyle(ButtonStyle.Secondary); - const row = new ActionRowBuilder().addComponents(playPauseButton, skipButton, stopButton, loopButton, shuffleButton); - - return await queue.dashboard.edit({ embeds: [embed.Embed_dashboard('Dashboard', track.title, track.url, track.thumbnail, settings(queue))], components: [row] }); - }); - - player.events.on('audioTrackAdd', async (queue, track) => { - if (queue.isPlaying()) { - const author = track.author; - const timestamp = queue.node.getTimestamp(); - const trackDuration = timestamp.progress == 'Forever' ? 'Endless (Live)' : track.duration; - await queue.metadata.channel.send({ embeds: [embed.Embed_add('Added', track.title, track.url, track.thumbnail, author, trackDuration)] }); - - try { - await queue.dashboard.delete(); - } catch (error) { - console.log('Dashboard delete error:', error); - } - - let playing = queue.node.isPaused(); - - const playPauseButton = new ButtonBuilder().setCustomId('Playing-PlayPause').setEmoji(playing ? button.play : button.pause).setStyle(ButtonStyle.Secondary); - const skipButton = new ButtonBuilder().setCustomId('Playing-Skip').setEmoji(button.skip).setStyle(ButtonStyle.Secondary); - const stopButton = new ButtonBuilder().setCustomId('Playing-Stop').setEmoji(button.stop).setStyle(ButtonStyle.Danger); - const loopButton = new ButtonBuilder().setCustomId('Playing-Loop').setEmoji(button.loop).setStyle(ButtonStyle.Secondary); - const shuffleButton = new ButtonBuilder().setCustomId('Playing-Shuffle').setEmoji(button.shuffle).setStyle(ButtonStyle.Secondary); - const row = new ActionRowBuilder().addComponents(playPauseButton, skipButton, stopButton, loopButton, shuffleButton); - - const cur = queue.currentTrack; - queue.dashboard = await queue.metadata.channel.send({ embeds: [embed.Embed_dashboard('Dashboard', cur.title, cur.url, cur.thumbnail, settings(queue))], components: [row] }); - return; - } - }); - - player.events.on('playerError', (queue, error) => { - console.log(`I'm having trouble connecting => ${error.message}`); - - if (error.message.includes('Sign in to confirm your age')) { - if (queue.tracks.data.length < 1) { - if (!queue.deleted) queue.delete(); - finishPlaying(queue); - return queue.metadata.channel.send({ content: `āŒ | I can't play Age-restricted videos.`, allowedMentions: { repliedUser: false } }); - } - - else { - queue.node.skip(); - return queue.metadata.channel.send({ content: `āŒ | I skipped Age-restricted video.`, allowedMentions: { repliedUser: false } }); - } - } - }); - - player.events.on('error', (queue, error) => { - console.log(`There was a problem with the song queue => ${error.message}`); - }); - - player.events.on('emptyChannel', (queue) => { - if (!client.config.autoLeave) queue.node.stop(); - - finishPlaying(queue); - }); - - player.events.on('disconnect', (queue) => { - finishPlaying(queue); - }); - - player.events.on('emptyQueue', (queue) => { - finishPlaying(queue); - }); -} -module.exports = registerPlayerEvents; \ No newline at end of file diff --git a/src/events/interactionCreate.js b/src/events/interactionCreate.js deleted file mode 100644 index 1f2fab1..0000000 --- a/src/events/interactionCreate.js +++ /dev/null @@ -1,183 +0,0 @@ -const { ActionRowBuilder, ButtonBuilder, ButtonStyle, StringSelectMenuBuilder } = require('discord.js'); - -const embed = require(`${__dirname}/../embeds/embeds`); -const { settings } = require(`${__dirname}/../utils/player/settings`); -const { wait } = require(`${__dirname}/../utils/functions/wait`); -const { color, button } = require(`${__dirname}/../utils/constants`); - - -module.exports = async (client, int) => { - - if (int.isButton()) { - if (!int.member.voice.channel) - return int.reply({ content: `āŒ | You are not connected to an audio channel.`, ephemeral: true, components: [] }); - - if (int.guild.members.me.voice.channel && int.member.voice.channelId !== int.guild.members.me.voice.channelId) - return int.reply({ content: `āŒ | You are not on the same audio channel as me.`, ephemeral: true, components: [] }); - - - const queue = client.player.nodes.get(int.guildId); - - if (!queue || !queue.isPlaying()) - return int.reply({ content: `āŒ | There is no music currently playing.`, ephemeral: true, components: [] }); - - - let track = queue.currentTrack; - const timestamp = queue.node.getTimestamp(); - const trackDuration = timestamp.progress == 'Forever' ? 'Endless (Live)' : track.duration; - let description = `Author : **${track.author}**\nDuration **${trackDuration}**`; - - switch (int.customId) { - case 'Save Song': { - int.member.send({ embeds: [embed.Embed_save(track.title, track.url, track.thumbnail, description)] }) - .then(() => { - return int.reply({ content: `āœ… | I sent you the name of the music in a private message.`, ephemeral: true, components: [] }); - }) - .catch(error => { - console.log('error: ' + error); - return int.reply({ content: `āŒ | I can't send you a private message.`, ephemeral: true, components: [] }); - }); - } break; - - case 'Playing-PlayPause': { - let playing = !queue.node.isPaused(); - - if (playing) queue.node.pause(); - else queue.node.resume(); - - const playPauseButton = new ButtonBuilder().setCustomId('Playing-PlayPause').setEmoji(playing ? button.play : button.pause).setStyle(playing ? ButtonStyle.Success : ButtonStyle.Secondary); - const skipButton = new ButtonBuilder().setCustomId('Playing-Skip').setEmoji(button.skip).setStyle(ButtonStyle.Secondary); - const stopButton = new ButtonBuilder().setCustomId('Playing-Stop').setEmoji(button.stop).setStyle(ButtonStyle.Danger); - const loopButton = new ButtonBuilder().setCustomId('Playing-Loop').setEmoji(button.loop).setStyle(ButtonStyle.Secondary); - const shuffleButton = new ButtonBuilder().setCustomId('Playing-Shuffle').setEmoji(button.shuffle).setStyle(ButtonStyle.Secondary); - const row = new ActionRowBuilder().addComponents(playPauseButton, skipButton, stopButton, loopButton, shuffleButton); - - await int.update({ components: [row] }); - } break; - - case 'Playing-Skip': { - - if (queue.repeatMode === 1) { - queue.setRepeatMode(0); - queue.node.skip(); - await wait(500); - queue.setRepeatMode(1); - } - else { - queue.node.skip(); - await wait(500); - } - - let playing = queue.node.isPaused(); - track = queue.currentTrack; - - const playPauseButton = new ButtonBuilder().setCustomId('Playing-PlayPause').setEmoji(playing ? button.play : button.pause).setStyle(playing ? ButtonStyle.Success : ButtonStyle.Secondary); - const skipButton = new ButtonBuilder().setCustomId('Playing-Skip').setEmoji(button.skip).setStyle(ButtonStyle.Secondary); - const stopButton = new ButtonBuilder().setCustomId('Playing-Stop').setEmoji(button.stop).setStyle(ButtonStyle.Danger); - const loopButton = new ButtonBuilder().setCustomId('Playing-Loop').setEmoji(button.loop).setStyle(ButtonStyle.Secondary); - const shuffleButton = new ButtonBuilder().setCustomId('Playing-Shuffle').setEmoji(button.shuffle).setStyle(ButtonStyle.Secondary); - const row = new ActionRowBuilder().addComponents(playPauseButton, skipButton, stopButton, loopButton, shuffleButton); - - await int.update({ components: [row] }); - } break; - - case 'Playing-Loop': { - const methods = ['Off', 'Single', 'All', 'Autoplay']; - let mode = 0; - - const select = new StringSelectMenuBuilder() - .setCustomId("Playing-Loop Select") - .setPlaceholder("Select the loop mode") - .setOptions(methods.map(x => { - return { - label: x, - description: x, - value: x - } - })) - - const row = new ActionRowBuilder().addComponents(select); - let msg = await int.reply({ content: `Select a song loop mode.`, ephemeral: true, components: [row] }); - - const collector = msg.createMessageComponentCollector({ - time: 20000, // 20s - filter: i => i.user.id === int.user.id - }); - - collector.on("collect", async i => { - if (i.customId != "Playing-Loop Select") return; - - switch (i.values[0]) { - case 'Off': - mode = 0; - break; - case 'Single': - mode = 1; - break; - case 'All': - mode = 2; - break; - case 'Autoplay': - mode = 3; - break; - } - queue.setRepeatMode(mode); - - await i.deferUpdate(); - await int.editReply({ content: `āœ… | Set loop to \`${methods[mode]}\`.`, ephemeral: true, components: [] }); - - - let playing = queue.node.isPaused(); - track = queue.currentTrack; - - const playPauseButton = new ButtonBuilder().setCustomId('Playing-PlayPause').setEmoji(playing ? button.play : button.pause).setStyle(playing ? ButtonStyle.Success : ButtonStyle.Secondary); - const skipButton = new ButtonBuilder().setCustomId('Playing-Skip').setEmoji(button.skip).setStyle(ButtonStyle.Secondary); - const stopButton = new ButtonBuilder().setCustomId('Playing-Stop').setEmoji(button.stop).setStyle(ButtonStyle.Danger); - const loopButton = new ButtonBuilder().setCustomId('Playing-Loop').setEmoji(button.loop).setStyle(ButtonStyle.Secondary); - const shuffleButton = new ButtonBuilder().setCustomId('Playing-Shuffle').setEmoji(button.shuffle).setStyle(ButtonStyle.Secondary); - const row = new ActionRowBuilder().addComponents(playPauseButton, skipButton, stopButton, loopButton, shuffleButton); - - return await queue.dashboard.edit({ embeds: [embed.Embed_dashboard('Dashboard', track.title, track.url, track.thumbnail, settings(queue))], components: [row] }); - }); - - collector.on("end", (collected, reason) => { - if (reason == "time" && collected.size == 0) { - if (!queue?.deleted && !queue.isPlaying()) queue?.delete(); - return int.editReply({ content: "āŒ | Time expired.", ephemeral: true, components: [] }); - } - }); - } break; - - case 'Playing-Stop': { - if (!queue.deleted) - queue.delete(); - - await int.reply({ content: 'āœ… | Bot leave.', ephemeral: true, components: [] }); - } break; - - case 'Playing-Shuffle': { - queue.tracks.shuffle(); - await int.reply({ content: 'āœ… | Music shuffled.', ephemeral: true, components: [] }); - } break; - } - } - else { - if (!int.isCommand() || !int.inGuild() || int.member.user.bot) return; - - - const cmd = client.commands.get(int.commandName); - - if (cmd && cmd.voiceChannel) { - if (!int.member.voice.channel) - return int.reply({ content: `āŒ | You are not connected to an audio channel.`, allowedMentions: { repliedUser: false } }); - - if (int.guild.members.me.voice.channel && int.member.voice.channelId !== int.guild.members.me.voice.channelId) - return int.reply({ content: `āŒ | You are not on the same audio channel as me.`, allowedMentions: { repliedUser: false } }); - } - - if (cmd) { - console.log(`(${color.grey}${int.member.guild.name}${color.white}) ${int.user.username} : /${int.commandName}`); - cmd.slashExecute(client, int); - } - } -}; \ No newline at end of file diff --git a/src/events/messageCreate.js b/src/events/messageCreate.js deleted file mode 100644 index 83f1ee7..0000000 --- a/src/events/messageCreate.js +++ /dev/null @@ -1,28 +0,0 @@ -const { color } = require(`${__dirname}/../utils/constants`); - - -module.exports = (client, message) => { - if (message.author.bot || message.channel.type === 'dm') return; - - const prefix = client.config.prefix; - if (message.content.indexOf(prefix) !== 0) return; - - - const args = message.content.slice(prefix.length).trim().split(/ +/g); - const command = args.shift().toLowerCase(); - const cmd = client.commands.get(command) || client.commands.find(cmd => cmd.aliases && cmd.aliases.includes(command)); - - if (cmd && cmd.voiceChannel) { - if (!message.member.voice.channel) - return message.reply({ content: `āŒ | You are not connected to an audio channel.`, allowedMentions: { repliedUser: false } }); - - if (message.guild.members.me.voice.channel && message.member.voice.channelId !== message.guild.members.me.voice.channelId) - return message.reply({ content: `āŒ | You are not on the same audio channel as me.`, allowedMentions: { repliedUser: false } }); - } - - if (cmd) { - console.log(`(${color.grey}${message.guild.name}${color.white}) ${message.author.username} : ${message.content}`); - message.channel.sendTyping(); - cmd.execute(client, message, args); - } -}; diff --git a/src/events/ready.js b/src/events/ready.js deleted file mode 100644 index a1616f7..0000000 --- a/src/events/ready.js +++ /dev/null @@ -1,42 +0,0 @@ -const os = require('os'); -const Discord = require('discord.js'); - -const package = require(`${__dirname}/../../package.json`); -const { getOSVersion } = require(`${__dirname}/../utils/functions/getOSVersion`); -const { color } = require(`${__dirname}/../utils/constants`); - - -module.exports = async (client) => { - client.status = { - uptime: new Date(), - os_version: await getOSVersion(), - node_version: process.version, - discord_version: `v${Discord.version}`, - bot_version: `v${package.version}`, - cpu: `${os.cpus()[0].model}` - }; - - - const release = { - bot: `${client.config.name}: ${color.cyan}${client.status.bot_version}${color.white}`, - nodejs: `Node.js: ${color.cyan}${client.status.node_version}${color.white}`, - djs: `Discord.js: ${color.cyan}${client.status.discord_version}${color.white}` - } - console.log(`+-----------------------+`); - console.log(`| ${release.bot.padEnd(30, ' ')} |`); - console.log(`| ${release.nodejs.padEnd(30, ' ')} |`); - console.log(`| ${release.djs.padEnd(30, ' ')} |`); - console.log(`+-----------------------+`); - - - client.application.commands.set(client.commands.map(cmd => { - return { - name: cmd.name, - description: cmd.description, - options: cmd.options - } - })); - - client.user.setActivity(client.config.playing); - console.log(`>>> Logged in as ${client.user.username}`); -}; \ No newline at end of file diff --git a/src/events/voiceStateUpdate.js b/src/events/voiceStateUpdate.js deleted file mode 100644 index 3fce494..0000000 --- a/src/events/voiceStateUpdate.js +++ /dev/null @@ -1,60 +0,0 @@ -const { color } = require(`${__dirname}/../utils/constants`); - - -let pool = []; - -module.exports = async (client, oldState, newState) => { - const display = client.config.displayVoiceState; - - if (newState.channelId === null) { - if (display) console.log(`${color.grey}-- ${newState.member.user.username} left channel${color.white}`); - } - else if (oldState.channelId === null) { - if (display) console.log(`${color.grey}-- ${newState.member.user.username} joined channel ${newState.channel.name}${color.white}`); - } - else { - if (display) console.log(`${color.grey}-- ${newState.member.user.username} moved channel ${oldState.channel.name} to ${newState.channel.name}${color.white}`); - - - // If the member who left the channel is not bot, check if the channel still has members - if (!oldState.member.user.bot) { - const queue = await client.player.nodes.get(oldState.guild.id); - const botChannelId = queue?.connection?.channel?.id; - const oldChannelId = oldState.channel.id; - const newChannelId = newState.channel.id; - - if (botChannelId === oldChannelId) { - - // If the channel only has bot, then start counting timeout until leave - if (oldState.channel.members.size <= 1) { - - let timeoutID = setTimeout(() => { - client.player.deleteQueue(oldState.guild.id); - }, client.config.autoLeaveCooldown); - - pool.push({ - guildId: oldState.guild.id, - timeoutId: timeoutID - }); - //console.log(pool); - } - } - else if (botChannelId === newChannelId) { - - // When bot is in the target channel and only one member joined - // If there are two members or more (not include bot) in the channel, it will not trigger - if (newState.channel.members.size > 1 && newState.channel.members.size <= 2) { - - // If member join bot channel, then find current channel's timeoutID to clear - for (var i = 0; i < pool.length; i++) { - //console.log(pool[i]); - if (pool[i].guildId === newState.guild.id) { - clearTimeout(pool[i].timeoutId); - pool.splice(i, 1); - } - } - } - } - } - } -}; \ No newline at end of file diff --git a/src/index.js b/src/index.js deleted file mode 100644 index 6a687e4..0000000 --- a/src/index.js +++ /dev/null @@ -1,191 +0,0 @@ -'use strict'; - -const fs = require('fs'); - -const dotenv = require('dotenv'); -const { Client, GatewayIntentBits, Partials, Collection } = require('discord.js'); -const { Player } = require('discord-player'); -const express = require('express'); -require('console-stamp')(console, { format: ':date(yyyy/mm/dd HH:MM:ss)' }); - -const registerPlayerEvents = require(`${__dirname}/events/discord-player/player`); -const cst = require(`${__dirname}/utils/constants`); - -dotenv.config(); -const ENV = process.env; - - -let client = new Client({ - intents: [ - GatewayIntentBits.Guilds, - GatewayIntentBits.GuildMembers, - GatewayIntentBits.GuildMessages, - GatewayIntentBits.MessageContent, - GatewayIntentBits.GuildVoiceStates, - ], - partials: [Partials.Channel], - disableMentions: 'everyone', -}); - -client.config = cst.config; -client.commands = new Collection(); -client.player = new Player(client, { - autoRegisterExtractor: false, - ytdlOptions: cst.ytdlOptions -}); - - -const player = client.player; - - - - -const setEnvironment = () => { - return new Promise((resolve, reject) => { - client.config.name = typeof (ENV.BOT_NAME) === 'undefined' - ? client.config.name - : ENV.BOT_NAME; - - client.config.prefix = typeof (ENV.PREFIX) === 'undefined' - ? client.config.prefix - : ENV.PREFIX; - - client.config.playing = typeof (ENV.PLAYING) === 'undefined' - ? client.config.playing - : ENV.PLAYING; - - client.config.defaultVolume = typeof (ENV.DEFAULT_VOLUME) === 'undefined' - ? client.config.defaultVolume - : Number(ENV.DEFAULT_VOLUME); - - client.config.maxVolume = typeof (ENV.MAX_VOLUME) === 'undefined' - ? client.config.maxVolume - : Number(ENV.MAX_VOLUME); - - client.config.autoLeave = typeof (ENV.AUTO_LEAVE) === 'undefined' - ? client.config.autoLeave - : (String(ENV.AUTO_LEAVE) === 'true' ? true : false); - - client.config.autoLeaveCooldown = typeof (ENV.AUTO_LEAVE_COOLDOWN) === 'undefined' - ? client.config.autoLeaveCooldown - : Number(ENV.AUTO_LEAVE_COOLDOWN); - - client.config.displayVoiceState = typeof (ENV.DISPLAY_VOICE_STATE) === 'undefined' - ? client.config.displayVoiceState - : (String(ENV.DISPLAY_VOICE_STATE) === 'true' ? true : false); - - client.config.port = typeof (ENV.PORT) === 'undefined' - ? client.config.port - : Number(ENV.PORT); - - client.config.textQuery = typeof (ENV.TEXT_QUERY_TYPE) === 'undefined' - ? client.config.textQuery - : ENV.TEXT_QUERY_TYPE - - client.config.urlQuery = typeof (ENV.URL_QUERY_TYPE) === 'undefined' - ? client.config.urlQuery - : ENV.URL_QUERY_TYPE; - - //console.log('setEnvironment: ', client.config); - resolve(); - }); -} - - -const loadFramework = () => { - console.log(`-> loading Web Framework ......`); - return new Promise((resolve, reject) => { - const app = express(); - const port = client.config.port || 33333; - - app.get('/', function (req, res) { - res.send('200 ok.') - }); - - app.listen(port, function () { - console.log(`Server start listening port on ${port}`); - resolve(); - }); - }) -} - - -const loadEvents = () => { - console.log(`-> loading Events ......`); - return new Promise((resolve, reject) => { - const files = fs.readdirSync(`${__dirname}/events/`).filter(file => file.endsWith('.js')); - - console.log(`+--------------------------------+`); - for (const file of files) { - try { - const event = require(`${__dirname}/events/${file}`); - console.log(`| Loaded event ${file.split('.')[0].padEnd(17, ' ')} |`); - - client.on(file.split('.')[0], event.bind(null, client)); - delete require.cache[require.resolve(`${__dirname}/events/${file}`)]; - } catch (error) { - reject(error); - } - }; - console.log(`+--------------------------------+`); - console.log(`${cst.color.grey}-- loading Events finished --${cst.color.white}`); - resolve(); - }) -} - -const loadPlayer = () => { - return new Promise(async (resolve, reject) => { - try { - await player.extractors.loadDefault(); - registerPlayerEvents(player, client); - } catch (error) { - reject(error); - } - console.log('-> loading Player Events finished'); - resolve(); - }) -} - - -const loadCommands = () => { - console.log(`-> loading Commands ......`); - return new Promise((resolve, reject) => { - const files = fs.readdirSync(`${__dirname}/commands/`).filter(file => file.endsWith('.js')); - - console.log(`+---------------------------+`); - for (const file of files) { - try { - const command = require(`${__dirname}/commands/${file}`); - - console.log(`| Loaded Command ${command.name.toLowerCase().padEnd(10, ' ')} |`); - - client.commands.set(command.name.toLowerCase(), command); - delete require.cache[require.resolve(`${__dirname}/commands/${file}`)]; - } catch (error) { - reject(error); - } - }; - console.log(`+---------------------------+`); - console.log(`${cst.color.grey}-- loading Commands finished --${cst.color.white}`); - resolve(); - }) -} - - -Promise.resolve() - .then(() => setEnvironment()) - .then(() => loadFramework()) - .then(() => loadEvents()) - .then(() => loadPlayer()) - .then(() => loadCommands()) - .then(() => { - console.log(`${cst.color.green}*** All loaded successfully ***${cst.color.white}`); - client.login(ENV.TOKEN); - }); - - - - -process.on('unhandledRejection', error => { - console.error('Unhandled promise rejection:', error); -}); diff --git a/src/index.ts b/src/index.ts new file mode 100644 index 0000000..ad43aea --- /dev/null +++ b/src/index.ts @@ -0,0 +1,3 @@ +import { VERSION } from "lavashark"; + +console.log('lavashark:', VERSION); \ No newline at end of file diff --git a/src/utils/constants.js b/src/utils/constants.js deleted file mode 100644 index accf9a5..0000000 --- a/src/utils/constants.js +++ /dev/null @@ -1,54 +0,0 @@ -const { QueryType } = require('discord-player'); -const ffmpeg = require('@ffmpeg-installer/ffmpeg'); - - -/** - * Custom ffmpeg source - * Starting from discord-player@6.3.0 requires manually setting the ffmpeg path - */ -process.env.FFMPEG_PATH = ffmpeg.path; -process.env.DP_NO_FFMPEG_WARN = true; // Mute ffmpeg warning - - -/** - * Constants variables - */ -const cst = { - // Dashboard button config - button: { - play : '<:w_play:1106270709644271656>', - pause : '<:w_pause:1106270708243386428>', - skip : '<:w_skip:1106270714664849448>', - back : '<:w_back:1106270704049061928>', - stop : '<:w_stop:1106272001909346386>', - loop : '<:w_loop:1106270705575792681>', - shuffle : '<:w_shuffle:1106270712542531624>', - }, - // Default config - config: { - name : 'Music Disc', - prefix : '+', - playing : '+help | music', - defaultVolume : 50, - maxVolume : 100, - autoLeave : true, - autoLeaveCooldown : 5000, - displayVoiceState : true, - port : 33333, - urlQuery : QueryType.AUTO, - textQuery : QueryType.AUTO - }, - ytdlOptions: { - filter : 'audioonly', - quality : 'highestaudio', - highWaterMark : 1 << 27 - }, - color: { - white : '\x1B[0m', - grey : '\x1B[2m', - green : '\x1B[32m', - cyan : '\x1B[36m' - } -}; - -module.exports = cst; \ No newline at end of file diff --git a/src/utils/functions/getOSVersion.js b/src/utils/functions/getOSVersion.js deleted file mode 100644 index 3db23f9..0000000 --- a/src/utils/functions/getOSVersion.js +++ /dev/null @@ -1,40 +0,0 @@ -const os = require('os'); -const { exec } = require('child_process'); - - -const getOSVersion = () => { - return new Promise((resolve, reject) => { - const platform = process.platform; - - if (platform === "win32") { - resolve(os.version()); - } - else if (platform === "linux" || platform === "freebsd") { - exec('cat /etc/*release | grep -E ^PRETTY_NAME', - (error, stdout, stderr) => { - if (error) { - resolve(os.type()); - } else { - const os_version = stdout.split('"')[1]; - resolve(os_version); - } - }); - } - else if (platform === "darwin") { - exec('system_profiler SPSoftwareDataType', - (error, stdout, stderr) => { - if (error) { - resolve(os.type()); - } else { - const os_version = stdout.match(/System Version: (.+)\n/)[1]; - resolve(os_version); - } - }); - } - else { - resolve(os.type()); - } - }); -} - -module.exports.getOSVersion = getOSVersion; \ No newline at end of file diff --git a/src/utils/functions/isValidUrl.js b/src/utils/functions/isValidUrl.js deleted file mode 100644 index 8c2d7b8..0000000 --- a/src/utils/functions/isValidUrl.js +++ /dev/null @@ -1,13 +0,0 @@ -const { URL } = require('url'); - - -const isValidUrl = (str) => { - try { - new URL(str); - return true; - } catch (err) { - return false; - } -} - -module.exports.isValidUrl = isValidUrl; \ No newline at end of file diff --git a/src/utils/functions/timeToSeconds.js b/src/utils/functions/timeToSeconds.js deleted file mode 100644 index 331d9b2..0000000 --- a/src/utils/functions/timeToSeconds.js +++ /dev/null @@ -1,61 +0,0 @@ -const timeToSeconds = (time) => { - const timeString = time.toLowerCase(); - let hours = 0, - minutes = 0, - seconds = 0; - - // Check if the timeString consists only of digits - if (/^\d+$/.test(timeString)) { - seconds = parseInt(timeString); - } - - // Check if the timeString is in the format "m:s" or "h:m:s" - else if (/^\d+:\d+(\:\d+)?$/.test(timeString)) { - const timeParts = timeString.split(":"); - const numParts = timeParts.length; - - if (numParts === 2) { - minutes = parseInt(timeParts[0]); - seconds = parseInt(timeParts[1]); - } else if (numParts === 3) { - hours = parseInt(timeParts[0]); - minutes = parseInt(timeParts[1]); - seconds = parseInt(timeParts[2]); - } - } - - // Otherwise, parse the timeString into hours, minutes, and seconds - else { - const regex = /(\d+)\s*(h|m|s)/g; - let match; - let valid = false; // Flag to track if any valid match is found - - while ((match = regex.exec(timeString)) !== null) { - const value = parseInt(match[1]); - - if (match[2] === 'h') { - hours = value; - valid = true; - } - else if (match[2] === 'm') { - minutes = value; - valid = true; - } - else if (match[2] === 's') { - seconds = value; - valid = true; - } - } - - // If no valid match is found, return false - if (!valid) { - return false; - } - } - - - const totalSeconds = hours * 3600 + minutes * 60 + seconds; - return totalSeconds; -} - -module.exports.timeToSeconds = timeToSeconds; \ No newline at end of file diff --git a/src/utils/functions/uptime.js b/src/utils/functions/uptime.js deleted file mode 100644 index 2b80113..0000000 --- a/src/utils/functions/uptime.js +++ /dev/null @@ -1,22 +0,0 @@ -const uptime = (startTime) => { - - let Today = new Date(); - let date1 = startTime.getTime(); - let date2 = Today.getTime(); - let total = (date2 - date1) / 1000; - - let day = parseInt(total / (24 * 60 * 60)); // č؈ē®—ę•“ę•ø天ę•ø - let afterDay = total - day * 24 * 60 * 60; // 取得ē®—å‡ŗ天ę•ø後剩餘ēš„ē§’ę•ø - let hour = parseInt(afterDay / (60 * 60)); // č؈ē®—ę•“ę•øå°ę™‚ę•ø - let afterHour = total - day * 24 * 60 * 60 - hour * 60 * 60; // 取得ē®—å‡ŗå°ę™‚ę•ø後剩餘ēš„ē§’ę•ø - let min = parseInt(afterHour / 60); // č؈ē®—ę•“ę•ø分 - let afterMin = Math.round(total - day * 24 * 60 * 60 - hour * 60 * 60 - min * 60); // 取得ē®—å‡ŗ分後剩餘ēš„ē§’ę•ø - console.log(`Uptime: ${day} / ${hour} : ${min} : ${afterMin}`); - - if (day >= 1) - return day + ' Day(s) ' + hour + 'Hour(s)'/* + min + 'Minute(s)' + afterMin*/; - else - return /*day + ' Days' +*/ hour + 'Hour(s) ' + min + 'Minute(s)' /*+ afterMin + 'Second(s)'*/; -}; - -module.exports.uptime = uptime; \ No newline at end of file diff --git a/src/utils/functions/usage.js b/src/utils/functions/usage.js deleted file mode 100644 index 49b1585..0000000 --- a/src/utils/functions/usage.js +++ /dev/null @@ -1,100 +0,0 @@ -const os = require('os'); -const util = require('util'); -const exec = util.promisify(require('child_process').exec); - - -const usage = { - cpu: async () => { - const platform = os.platform(); - const load = os.loadavg(); - const strLoad = `[${load[0].toFixed(2)}, ${load[1].toFixed(2)}, ${load[2].toFixed(2)}]`; - let cpuPercent = '0%'; - - if (platform === 'win32') { - try { - const { stdout, stderr } = await exec('wmic cpu get LoadPercentage'); - if (stderr) { - throw new Error(stderr); - } - - const loadArr = stdout.split('\r\r\n').filter((item) => !isNaN(parseInt(item))); - const totalLoad = loadArr.reduce((acc, load) => acc + parseInt(load), 0); - const avgLoad = Math.round(totalLoad / loadArr.length); - cpuPercent = avgLoad + '%'; - } catch (error) { - console.error('Error getting CPU load:', error); - } - } - else { - cpuPercent = await getCpuPercentage() + '%'; - } - - console.log(`CPU: ${cpuPercent} ${strLoad}`); - return { - percent: cpuPercent, - detail: strLoad - }; - }, - ram: () => { - const totalRam = os.totalmem(); - const usedRam = process.memoryUsage().rss; - const usedRatio = ((usedRam / totalRam * 10000) / 100).toFixed(1); - const totalMb = (totalRam / (1024 * 1024)).toFixed(0); - const usedMb = (usedRam / (1024 * 1024)).toFixed(0); - - console.log(`Ram: ${usedRatio}% (${usedMb} / ${totalMb} MB)`); - return { - percent: `${usedRatio}%`, - detail: `(${usedMb} / ${totalMb} MB)` - }; - }, - heap: () => { - const totalHeap = process.memoryUsage().heapTotal; - const usedHeap = process.memoryUsage().heapUsed; - const usedRatio = ((usedHeap / totalHeap * 10000) / 100).toFixed(1); - const totalMb = (totalHeap / (1024 * 1024)).toFixed(0); - const usedMb = (usedHeap / (1024 * 1024)).toFixed(0); - - console.log(`Heap: ${usedRatio}% (${usedMb} / ${totalMb} MB)`); - return { - percent: `${usedRatio}%`, - detail: `(${usedMb} / ${totalMb} MB)` - }; - } -}; - -module.exports.usage = usage; - - -const getCpuLoad = () => { - const cpus = os.cpus(); - - let totalIdle = 0, - totalTick = 0; - cpus.forEach(cpu => { - for (type in cpu.times) { - totalTick += cpu.times[type]; - } - totalIdle += cpu.times.idle; - }); - - return { - idle: totalIdle / cpus.length, - total: totalTick / cpus.length - }; -} - -const getCpuPercentage = () => { - const firstLoad = getCpuLoad(); - - return new Promise(resolve => { - setTimeout(() => { - const secondLoad = getCpuLoad(); - - const idleDiff = secondLoad.idle - firstLoad.idle; - const totalDiff = secondLoad.total - firstLoad.total; - const avgLoad = 100 - ~~(100 * idleDiff / totalDiff); - resolve(avgLoad); - }, 1000); - }); -} \ No newline at end of file diff --git a/src/utils/functions/wait.js b/src/utils/functions/wait.js deleted file mode 100644 index 36dd112..0000000 --- a/src/utils/functions/wait.js +++ /dev/null @@ -1,5 +0,0 @@ -const wait = (ms) => { - return new Promise((resolve) => setTimeout(() => resolve(), ms)); -}; - -module.exports.wait = wait; \ No newline at end of file diff --git a/src/utils/player/finishPlaying.js b/src/utils/player/finishPlaying.js deleted file mode 100644 index d91fff3..0000000 --- a/src/utils/player/finishPlaying.js +++ /dev/null @@ -1,12 +0,0 @@ -const embed = require(`${__dirname}/../../embeds/embeds`); - - -const finishPlaying = async (queue) => { - try { - await queue.dashboard.edit({ embeds: [embed.Embed_disconnect()], components: [] }); - } catch (error) { - console.log('Dashboard error:', error); - } -}; - -module.exports.finishPlaying = finishPlaying; \ No newline at end of file diff --git a/src/utils/player/settings.js b/src/utils/player/settings.js deleted file mode 100644 index a1c10c9..0000000 --- a/src/utils/player/settings.js +++ /dev/null @@ -1,14 +0,0 @@ -const settings = (queue) => { - const loop = queue.repeatMode ? (queue.repeatMode === 2 ? 'All' : (queue.repeatMode === 1 ? 'Single' : (queue.repeatMode === 3 ? 'Autoplay' : 'Off' ))) : 'Off'; - const volume = queue.node.volume; - const track = queue.currentTrack; - const author = track.author; - const timestamp = queue.node.getTimestamp(); - const trackDuration = timestamp.progress == 'Forever' ? 'Endless (Live)' : track.duration; - - return `Author : **${author}**\nDuration **${trackDuration}**\n` - + `ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€\n` - + `Volume: \`${volume}%\` | Loop: \`${loop}\``; -}; - -module.exports.settings = settings; \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..bb09f98 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,36 @@ +{ + "compilerOptions": { + "incremental": true, + "target": "ES2022", + "module": "CommonJS", + "moduleResolution": "node", + "lib": [ + "ES2022" + ], + "rootDirs": [ + "src/" + ], + "outDir": "dist/", + "resolveJsonModule": true, + "allowJs": false, + "checkJs": false, + "declaration": false, + "noEmit": false, + "isolatedModules": true, + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "strict": true, + "strictNullChecks": true, + "strictPropertyInitialization": false, + "skipDefaultLibCheck": true, + "skipLibCheck": true + }, + "include": [ + "src/*.ts", + "src/**/*.ts" + ], + "exclude": [ + "node_modules", + "dist" + ] +} \ No newline at end of file From 4c0e418b07fcc167ac4ef4cd28b1b254369fc1d1 Mon Sep 17 00:00:00 2001 From: hmes98318 <52697423+hmes98318@users.noreply.github.com> Date: Wed, 28 Jun 2023 22:04:22 +0800 Subject: [PATCH 02/64] Add basic framework --- node-list.json | 8 ++ src/events/interactionCreate.ts | 17 ++++ src/events/messageCreate.ts | 21 +++++ src/events/ready.ts | 42 ++++++++++ src/index.ts | 117 +++++++++++++++++++++++++++- src/utils/constants.ts | 23 ++++++ src/utils/functions/getOSVersion.ts | 42 ++++++++++ 7 files changed, 268 insertions(+), 2 deletions(-) create mode 100644 node-list.json create mode 100644 src/events/interactionCreate.ts create mode 100644 src/events/messageCreate.ts create mode 100644 src/events/ready.ts create mode 100644 src/utils/constants.ts create mode 100644 src/utils/functions/getOSVersion.ts diff --git a/node-list.json b/node-list.json new file mode 100644 index 0000000..30931b9 --- /dev/null +++ b/node-list.json @@ -0,0 +1,8 @@ +[ + { + "id": "Node 1", + "hostname": "localhost", + "port": 2333, + "password": "youshallnotpass" + } +] \ No newline at end of file diff --git a/src/events/interactionCreate.ts b/src/events/interactionCreate.ts new file mode 100644 index 0000000..a87b755 --- /dev/null +++ b/src/events/interactionCreate.ts @@ -0,0 +1,17 @@ +import { Client, Interaction } from "discord.js"; + + +export default async (client: Client, int: Interaction) => { + + if (int.isButton()) { } + else { + if (!int.isCommand() || !int.inGuild() || int.member.user.bot) return; + + const cmd = client.commands.get(int.commandName); + if (cmd) { + console.log(`(\x1B[2m${int.guild?.name}\x1B[0m) ${int.user.username} : /${int.commandName}`); + await int.deferReply(); + cmd.slashExecute(client, int); + } + } +}; \ No newline at end of file diff --git a/src/events/messageCreate.ts b/src/events/messageCreate.ts new file mode 100644 index 0000000..1f4e6d8 --- /dev/null +++ b/src/events/messageCreate.ts @@ -0,0 +1,21 @@ +import { Client, Message, ChannelType } from "discord.js"; + + +export default async (client: Client, message: Message) => { + const prefix = client.config.prefix; + + if (message.author.bot || message.channel.type !== ChannelType.GuildText) return; + if (message.content.indexOf(prefix) !== 0) return; + + + const args = message.content.slice(prefix.length).trim().split(/ +/g); + const command = args.shift()?.toLowerCase(); + + const cmd = client.commands.get(command) || client.commands.find(cmd => cmd.aliases && cmd.aliases.includes(command)); + + if (cmd) { + console.log(`(\x1B[2m${message.guild?.name}\x1B[0m) ${message.author.username} : ${message.content}`); + await message.channel.sendTyping(); + cmd.execute(client, message, args); + } +}; \ No newline at end of file diff --git a/src/events/ready.ts b/src/events/ready.ts new file mode 100644 index 0000000..90d58a8 --- /dev/null +++ b/src/events/ready.ts @@ -0,0 +1,42 @@ +import os from 'os'; +import Discord, { Client } from 'discord.js'; + +import { version } from '../../package.json'; +import { getOSVersion } from '../utils/functions/getOSVersion'; +import { cst } from '../utils/constants'; + + +module.exports = async (client: Client) => { + client.status = { + uptime: new Date(), + os_version: await getOSVersion(), + node_version: process.version, + discord_version: `v${Discord.version}`, + bot_version: `v${version}`, + cpu: `${os.cpus()[0].model}` + }; + + + const release = { + bot: `${client.config.name}: ${cst.color.cyan}${client.status.bot_version}${cst.color.white}`, + nodejs: `Node.js: ${cst.color.cyan}${client.status.node_version}${cst.color.white}`, + djs: `Discord.js: ${cst.color.cyan}${client.status.discord_version}${cst.color.white}` + } + console.log(`+-----------------------+`); + console.log(`| ${release.bot.padEnd(30, ' ')} |`); + console.log(`| ${release.nodejs.padEnd(30, ' ')} |`); + console.log(`| ${release.djs.padEnd(30, ' ')} |`); + console.log(`+-----------------------+`); + + + client.application?.commands.set(client.commands.map(cmd => { + return { + name: cmd.name, + description: cmd.description, + options: cmd.options + } + })); + + client.user?.setActivity(client.config.playing); + console.log(`>>> Logged in as ${client.user?.username}`); +}; \ No newline at end of file diff --git a/src/index.ts b/src/index.ts index ad43aea..216e7c7 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,3 +1,116 @@ -import { VERSION } from "lavashark"; +import * as fs from 'fs'; -console.log('lavashark:', VERSION); \ No newline at end of file +import * as dotenv from 'dotenv'; +import { Client, GatewayIntentBits, Collection } from 'discord.js'; +import { LavaShark } from "lavashark"; +import consoleStamp from 'console-stamp'; + +import { cst } from "./utils/constants"; +import nodeList from "../node-list.json"; + +dotenv.config(); +consoleStamp(console, { format: ':date(yyyy/mm/dd HH:MM:ss)' }); + + +declare module 'discord.js' { + export interface Client { + commands: Collection, + player: LavaShark, + config: { + name: string, + prefix: string, + playing: string, + defaultVolume: number, + maxVolume: number, + autoLeave: boolean, + autoLeaveCooldown: number, + displayVoiceState: boolean, + port: number + }, + status: { + uptime: Date, + os_version: string, + node_version: string, + discord_version: string, + bot_version: string, + cpu: string + } + } +} + + + + +let client = new Client({ + intents: [ + GatewayIntentBits.Guilds, + GatewayIntentBits.GuildMembers, + GatewayIntentBits.GuildMessages, + GatewayIntentBits.MessageContent, + GatewayIntentBits.GuildVoiceStates, + ] +}); +client.commands = new Collection(); +client.player = new LavaShark({ + nodes: nodeList, + sendWS: (guildId, payload) => { client.guilds.cache.get(guildId)?.shard.send(payload); } +}) +client.config = cst.config; + + + + +const loadEvents = () => { + console.log(`-> loading Events ......`); + return new Promise(async (resolve, reject) => { + const events = fs.readdirSync(`${__dirname}/events/`); + + console.log(`+--------------------------------+`); + for (const file of events) { + try { + const event = await import(`${__dirname}/events/${file}`); + client.on(file.split('.')[0], event.default.bind(null, client)); + console.log(`| Loaded event ${file.split('.')[0].padEnd(17, ' ')} |`); + } + catch (error) { + reject(error); + } + } + console.log(`+--------------------------------+`); + console.log(`${cst.color.grey}-- loading Events finished --${cst.color.white}`); + + resolve(); + }); +} + +const loadCommands = () => { + console.log(`-> loading Commands ......`); + return new Promise(async (resolve, reject) => { + const jsFiles = fs.readdirSync(`${__dirname}/commands/`); + + console.log(`+---------------------------+`); + for (const file of jsFiles) { + try { + const command = await import(`${__dirname}/commands/${file}`); + client.commands.set(command.name.toLowerCase(), command); + console.log(`| Loaded Command ${command.name.toLowerCase().padEnd(10, ' ')} |`); + } + catch (error) { + reject(error); + } + } + console.log(`+---------------------------+`); + console.log(`${cst.color.grey}-- loading Commands finished --${cst.color.white}`); + + resolve(); + }); +} + + +Promise.resolve() + .then(() => loadEvents()) + .then(() => loadCommands()) + .then(() => { + console.log(`${cst.color.green}*** All loaded successfully ***${cst.color.white}`); + client.login(process.env.TOKEN); + }); \ No newline at end of file diff --git a/src/utils/constants.ts b/src/utils/constants.ts new file mode 100644 index 0000000..5339b74 --- /dev/null +++ b/src/utils/constants.ts @@ -0,0 +1,23 @@ +/** + * Constants variables + */ +export const cst = { + // Default config + config: { + name : 'Music Disc', + prefix : '+', + playing : '+help | music', + defaultVolume : 50, + maxVolume : 100, + autoLeave : true, + autoLeaveCooldown : 5000, + displayVoiceState : true, + port : 33333 + }, + color: { + white : '\x1B[0m', + grey : '\x1B[2m', + green : '\x1B[32m', + cyan : '\x1B[36m' + } +} \ No newline at end of file diff --git a/src/utils/functions/getOSVersion.ts b/src/utils/functions/getOSVersion.ts new file mode 100644 index 0000000..ea9f1bb --- /dev/null +++ b/src/utils/functions/getOSVersion.ts @@ -0,0 +1,42 @@ +import os from 'os'; +import { exec } from 'child_process'; + + +const getOSVersion = (): Promise => { + return new Promise((resolve, reject) => { + const platform = process.platform; + + if (platform === "win32") { + resolve(os.version()); + } + else if (platform === "linux" || platform === "freebsd") { + exec('cat /etc/*release | grep -E ^PRETTY_NAME', + (error, stdout, stderr) => { + if (error) { + resolve(os.type()); + } + else { + const os_version = stdout.split('"')[1]; + resolve(os_version); + } + }); + } + else if (platform === "darwin") { + exec('system_profiler SPSoftwareDataType', + (error, stdout, stderr) => { + if (error) { + resolve(os.type()); + } + else { + const os_version = (stdout.match(/System Version: (.+)\n/)?.[1]) ?? os.type(); + resolve(os_version); + } + }); + } + else { + resolve(os.type()); + } + }); +} + +export { getOSVersion }; \ No newline at end of file From 8428bed2bf34782f0c6dfbc3b4893ee951babe13 Mon Sep 17 00:00:00 2001 From: hmes98318 <52697423+hmes98318@users.noreply.github.com> Date: Wed, 28 Jun 2023 22:08:04 +0800 Subject: [PATCH 03/64] Update naming --- src/events/ready.ts | 6 +++--- src/index.ts | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/events/ready.ts b/src/events/ready.ts index 90d58a8..7236ea4 100644 --- a/src/events/ready.ts +++ b/src/events/ready.ts @@ -1,5 +1,5 @@ import os from 'os'; -import Discord, { Client } from 'discord.js'; +import { Client, version as dcVersion } from 'discord.js'; import { version } from '../../package.json'; import { getOSVersion } from '../utils/functions/getOSVersion'; @@ -11,7 +11,7 @@ module.exports = async (client: Client) => { uptime: new Date(), os_version: await getOSVersion(), node_version: process.version, - discord_version: `v${Discord.version}`, + dc_version: `v${dcVersion}`, bot_version: `v${version}`, cpu: `${os.cpus()[0].model}` }; @@ -20,7 +20,7 @@ module.exports = async (client: Client) => { const release = { bot: `${client.config.name}: ${cst.color.cyan}${client.status.bot_version}${cst.color.white}`, nodejs: `Node.js: ${cst.color.cyan}${client.status.node_version}${cst.color.white}`, - djs: `Discord.js: ${cst.color.cyan}${client.status.discord_version}${cst.color.white}` + djs: `Discord.js: ${cst.color.cyan}${client.status.dc_version}${cst.color.white}` } console.log(`+-----------------------+`); console.log(`| ${release.bot.padEnd(30, ' ')} |`); diff --git a/src/index.ts b/src/index.ts index 216e7c7..a3e573b 100644 --- a/src/index.ts +++ b/src/index.ts @@ -31,7 +31,7 @@ declare module 'discord.js' { uptime: Date, os_version: string, node_version: string, - discord_version: string, + dc_version: string, bot_version: string, cpu: string } From 5aa0b60c951c9603b199f42e39a1cf6adc72a40e Mon Sep 17 00:00:00 2001 From: hmes98318 <52697423+hmes98318@users.noreply.github.com> Date: Thu, 29 Jun 2023 22:10:35 +0800 Subject: [PATCH 04/64] Add event handling --- src/events/interactionCreate.ts | 28 ++++++++++++++++++++-------- src/events/messageCreate.ts | 16 ++++++++++++---- src/events/raw.ts | 4 ++++ src/events/ready.ts | 10 ++++++++-- 4 files changed, 44 insertions(+), 14 deletions(-) create mode 100644 src/events/raw.ts diff --git a/src/events/interactionCreate.ts b/src/events/interactionCreate.ts index a87b755..767b65e 100644 --- a/src/events/interactionCreate.ts +++ b/src/events/interactionCreate.ts @@ -1,17 +1,29 @@ -import { Client, Interaction } from "discord.js"; +import { Client, ChatInputCommandInteraction } from "discord.js"; +import { cst } from "../utils/constants"; -export default async (client: Client, int: Interaction) => { +export default async (client: Client, interaction: ChatInputCommandInteraction) => { - if (int.isButton()) { } + if (interaction.isButton()) { } else { - if (!int.isCommand() || !int.inGuild() || int.member.user.bot) return; + if (!interaction.isCommand() || !interaction.inGuild() || interaction.member.user.bot) return; + + + const cmd = client.commands.get(interaction.commandName); + const guildMember = interaction.guild!.members.cache.get(interaction.user.id); + const voiceChannel = guildMember!.voice.channel; + + if (cmd && cmd.voiceChannel) { + if (!voiceChannel) + return interaction.reply({ content: `āŒ | You are not connected to an audio channel.`, allowedMentions: { repliedUser: false } }); + + if (interaction.guild?.members.me?.voice.channel && voiceChannel.id !== interaction.guild.members.me.voice.channelId) + return interaction.reply({ content: `āŒ | You are not on the same audio channel as me.`, allowedMentions: { repliedUser: false } }); + } - const cmd = client.commands.get(int.commandName); if (cmd) { - console.log(`(\x1B[2m${int.guild?.name}\x1B[0m) ${int.user.username} : /${int.commandName}`); - await int.deferReply(); - cmd.slashExecute(client, int); + console.log(`(${cst.color.grey}${guildMember?.guild.name}${cst.color.white}) ${interaction.user.username} : /${interaction.commandName}`); + cmd.slashExecute(client, interaction); } } }; \ No newline at end of file diff --git a/src/events/messageCreate.ts b/src/events/messageCreate.ts index 1f4e6d8..f1add5a 100644 --- a/src/events/messageCreate.ts +++ b/src/events/messageCreate.ts @@ -1,4 +1,5 @@ import { Client, Message, ChannelType } from "discord.js"; +import { cst } from "../utils/constants"; export default async (client: Client, message: Message) => { @@ -9,13 +10,20 @@ export default async (client: Client, message: Message) => { const args = message.content.slice(prefix.length).trim().split(/ +/g); - const command = args.shift()?.toLowerCase(); - + const command = String(args.shift()).toLowerCase(); const cmd = client.commands.get(command) || client.commands.find(cmd => cmd.aliases && cmd.aliases.includes(command)); + if (cmd && cmd.voiceChannel) { + if (!message.member?.voice.channel) + return message.reply({ content: `āŒ | You are not connected to an audio channel.`, allowedMentions: { repliedUser: false } }); + + if (message.guild?.members.me?.voice.channel && message.member.voice.channelId !== message.guild.members.me.voice.channelId) + return message.reply({ content: `āŒ | You are not on the same audio channel as me.`, allowedMentions: { repliedUser: false } }); + } + if (cmd) { - console.log(`(\x1B[2m${message.guild?.name}\x1B[0m) ${message.author.username} : ${message.content}`); - await message.channel.sendTyping(); + console.log(`(${cst.color.grey}${message.guild?.name}${cst.color.white}) ${message.author.username} : ${message.content}`); + message.channel.sendTyping(); cmd.execute(client, message, args); } }; \ No newline at end of file diff --git a/src/events/raw.ts b/src/events/raw.ts new file mode 100644 index 0000000..40c9cbb --- /dev/null +++ b/src/events/raw.ts @@ -0,0 +1,4 @@ +import { Client } from "discord.js"; +import { IncomingDiscordPayload } from "lavashark/typings/src/@types"; + +export default async (client: Client, packet: unknown) => client.lavashark.handleVoiceUpdate(packet as IncomingDiscordPayload); \ No newline at end of file diff --git a/src/events/ready.ts b/src/events/ready.ts index 7236ea4..09d6d84 100644 --- a/src/events/ready.ts +++ b/src/events/ready.ts @@ -1,5 +1,6 @@ import os from 'os'; import { Client, version as dcVersion } from 'discord.js'; +import { VERSION } from 'lavashark'; import { version } from '../../package.json'; import { getOSVersion } from '../utils/functions/getOSVersion'; @@ -10,9 +11,10 @@ module.exports = async (client: Client) => { client.status = { uptime: new Date(), os_version: await getOSVersion(), + bot_version: `v${version}`, node_version: process.version, dc_version: `v${dcVersion}`, - bot_version: `v${version}`, + shark_version: `v${VERSION}`, cpu: `${os.cpus()[0].model}` }; @@ -20,12 +22,15 @@ module.exports = async (client: Client) => { const release = { bot: `${client.config.name}: ${cst.color.cyan}${client.status.bot_version}${cst.color.white}`, nodejs: `Node.js: ${cst.color.cyan}${client.status.node_version}${cst.color.white}`, - djs: `Discord.js: ${cst.color.cyan}${client.status.dc_version}${cst.color.white}` + djs: `Discord.js: ${cst.color.cyan}${client.status.dc_version}${cst.color.white}`, + shark: `LavaShark: ${cst.color.cyan}${client.status.shark_version}${cst.color.white}`, } + console.log(`+-----------------------+`); console.log(`| ${release.bot.padEnd(30, ' ')} |`); console.log(`| ${release.nodejs.padEnd(30, ' ')} |`); console.log(`| ${release.djs.padEnd(30, ' ')} |`); + console.log(`| ${release.shark.padEnd(30, ' ')} |`); console.log(`+-----------------------+`); @@ -37,6 +42,7 @@ module.exports = async (client: Client) => { } })); + client.lavashark.start(String(client.user?.id)); client.user?.setActivity(client.config.playing); console.log(`>>> Logged in as ${client.user?.username}`); }; \ No newline at end of file From 61b4ec770e6af6fede9f6bc73637b0f046097051 Mon Sep 17 00:00:00 2001 From: hmes98318 <52697423+hmes98318@users.noreply.github.com> Date: Thu, 29 Jun 2023 22:11:05 +0800 Subject: [PATCH 05/64] Rename player --- src/index.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/index.ts b/src/index.ts index a3e573b..672151e 100644 --- a/src/index.ts +++ b/src/index.ts @@ -15,7 +15,7 @@ consoleStamp(console, { format: ':date(yyyy/mm/dd HH:MM:ss)' }); declare module 'discord.js' { export interface Client { commands: Collection, - player: LavaShark, + lavashark: LavaShark, config: { name: string, prefix: string, @@ -30,9 +30,10 @@ declare module 'discord.js' { status: { uptime: Date, os_version: string, + bot_version: string, node_version: string, dc_version: string, - bot_version: string, + shark_version: string, cpu: string } } @@ -51,7 +52,7 @@ let client = new Client({ ] }); client.commands = new Collection(); -client.player = new LavaShark({ +client.lavashark = new LavaShark({ nodes: nodeList, sendWS: (guildId, payload) => { client.guilds.cache.get(guildId)?.shard.send(payload); } }) From 34cd7f4c582b7f036d9edcf009e196a9877b97ad Mon Sep 17 00:00:00 2001 From: hmes98318 <52697423+hmes98318@users.noreply.github.com> Date: Thu, 29 Jun 2023 22:11:58 +0800 Subject: [PATCH 06/64] Add `play` command --- src/commands/play.ts | 132 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 131 insertions(+), 1 deletion(-) diff --git a/src/commands/play.ts b/src/commands/play.ts index 8cec2e9..1a6660f 100644 --- a/src/commands/play.ts +++ b/src/commands/play.ts @@ -1 +1,131 @@ -export {}; \ No newline at end of file +import { Client, Message, ChatInputCommandInteraction } from "discord.js"; + +export const name = 'play'; +export const aliases = ['p']; +export const description = 'Enter your song link or song name to play'; +export const usage = 'play ' +export const voiceChannel = true; +export const showHelp = true; +export const options = [ + { + name: "search", + description: "The song link or song name", + type: 3, + required: true + } +]; + + +export const execute = async (client: Client, message: Message, args: string[]) => { + if (!args[0]) + return message.reply({ content: `āŒ | Write the name of the music you want to search.`, allowedMentions: { repliedUser: false } }); + + const str = args.join(' '); + const res = await client.lavashark.search(str); + + if (res.loadType === "LOAD_FAILED") { + console.log(`Search Error: ${res.exception?.message}`); + return message.reply({ content: `āŒ | No results found.`, allowedMentions: { repliedUser: false } }); + } + else if (res.loadType === "NO_MATCHES") { + return message.reply({ content: `āŒ | No matches.`, allowedMentions: { repliedUser: false } }); + } + + let player; + try { + // Creates the audio player + player = client.lavashark.createPlayer({ + guildId: String(message.guild?.id), + voiceChannelId: String(message.member?.voice.channelId), + textChannelId: message.channel.id, + selfDeaf: true + }); + + // Connects to the voice channel + player.connect(); + } catch (error) { + console.log(error); + return message.reply({ content: `āŒ | I can't join voice channel.`, allowedMentions: { repliedUser: false } }); + } + + + if (res.loadType === 'PLAYLIST_LOADED') { + for (const track of res.tracks) { + track.setRequester(client.user); + player.queue.add(track); + } + + message.reply(`Playlist \`${res.playlistInfo.name}\` loaded!`); + } + else { + const track = res.tracks[0]; + track.setRequester(client.user); + + player.queue.add(track); + message.reply(`Queued \`${track.title}\``); + } + + if (!player.playing) await player.play() + .catch((error) => { + console.log(error); + return message.reply({ content: `āŒ | I can't play this track.`, allowedMentions: { repliedUser: false } }); + }); + + return message.react('šŸ‘'); +} + +export const slashExecute = async (client: Client, interaction: ChatInputCommandInteraction) => { + + const str = String(interaction.options.get("search", true).value); + const res = await client.lavashark.search(str); + + if (res.loadType === "LOAD_FAILED") { + console.log(`Search Error: ${res.exception?.message}`); + return interaction.editReply({ content: `āŒ | No results found.`, allowedMentions: { repliedUser: false } }); + } + else if (res.loadType === "NO_MATCHES") { + return interaction.editReply({ content: `āŒ | No matches.`, allowedMentions: { repliedUser: false } }); + } + + let player; + try { + const guildMember = interaction.guild!.members.cache.get(interaction.user.id); + const { channel } = guildMember!.voice; + // Creates the audio player + player = client.lavashark.createPlayer({ + guildId: String(interaction.guild?.id), + voiceChannelId: String(channel?.id), + textChannelId: interaction.channel?.id, + selfDeaf: true + }); + + // Connects to the voice channel + player.connect(); + } catch (error) { + console.log(error); + return interaction.editReply({ content: `āŒ | I can't join voice channel.`, allowedMentions: { repliedUser: false } }); + } + + + if (res.loadType === 'PLAYLIST_LOADED') { + for (const track of res.tracks) { + track.setRequester(client.user); + player.queue.add(track); + } + + interaction.editReply(`Playlist \`${res.playlistInfo.name}\` loaded!`); + } + else { + const track = res.tracks[0]; + track.setRequester(client.user); + + player.queue.add(track); + interaction.editReply(`Queued \`${track.title}\``); + } + + if (!player.playing) await player.play() + .catch((error) => { + console.log(error); + return interaction.editReply({ content: `āŒ | I can't play this track.`, allowedMentions: { repliedUser: false } }); + }); +} \ No newline at end of file From 3accaf73411f28074d6a8bd60cb015e2bda3eb48 Mon Sep 17 00:00:00 2001 From: hmes98318 <52697423+hmes98318@users.noreply.github.com> Date: Sat, 1 Jul 2023 23:45:39 +0800 Subject: [PATCH 07/64] Add `search` command --- src/commands/search.ts | 200 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 200 insertions(+) create mode 100644 src/commands/search.ts diff --git a/src/commands/search.ts b/src/commands/search.ts new file mode 100644 index 0000000..9218b58 --- /dev/null +++ b/src/commands/search.ts @@ -0,0 +1,200 @@ +import { + ActionRowBuilder, + ButtonInteraction, + ChatInputCommandInteraction, + Client, + Collection, + Message, + StringSelectMenuBuilder, + StringSelectMenuInteraction, +} from "discord.js"; +import { Player } from "lavashark"; + + +export const name = 'search'; +export const aliases = ['find']; +export const description = 'Enter song name to search'; +export const usage = 'search ' +export const voiceChannel = true; +export const showHelp = true; +export const options = [ + { + name: "search", + description: "The song name", + type: 3, + required: true + } +]; + + +export const execute = async (client: Client, message: Message, args: string[]) => { + if (!args[0]) { + return message.reply({ content: `āŒ | Write the name of the music you want to search.`, allowedMentions: { repliedUser: false } }); + } + + const str = args.join(' '); + const res = await client.lavashark.search(str); + + if (res.loadType === "LOAD_FAILED") { + console.log(`Search Error: ${res.exception?.message}`); + return message.reply({ content: `āŒ | No results found.`, allowedMentions: { repliedUser: false } }); + } + else if (res.loadType === "NO_MATCHES") { + return message.reply({ content: `āŒ | No matches.`, allowedMentions: { repliedUser: false } }); + } + + let player: Player; + try { + // Creates the audio player + player = client.lavashark.createPlayer({ + guildId: String(message.guild?.id), + voiceChannelId: String(message.member?.voice.channelId), + textChannelId: message.channel.id, + selfDeaf: true + }); + + // Connects to the voice channel + player.connect(); + } catch (error) { + console.log(error); + return message.reply({ content: `āŒ | I can't join voice channel.`, allowedMentions: { repliedUser: false } }); + } + + await message.react('šŸ‘'); + + + + if (res.loadType === 'PLAYLIST_LOADED') { + for (const track of res.tracks) { + track.setRequester(client.user); + player.queue.add(track); + } + + return message.reply({ content: "āœ… | Music added.", allowedMentions: { repliedUser: false } }); + } + else { + let select = new StringSelectMenuBuilder() + .setCustomId("musicSelect") + .setPlaceholder("Select the music") + .setOptions(res.tracks.map(x => { + return { + label: x.title.length >= 25 ? x.title.substring(0, 22) + "..." : x.title, + description: `Duration: ${x.duration.label}`, + value: x.uri + } + })); + let row = new ActionRowBuilder().addComponents(select); + let msg = await message.reply({ components: [row.toJSON()] }); + + const collector = msg.createMessageComponentCollector({ + time: 20000, // 20s + filter: i => i.user.id === message.author.id + }); + + collector.on("collect", async (i: StringSelectMenuInteraction) => { + if (i.customId != "musicSelect") return; + + player.queue.add(res.tracks.find(x => x.uri == i.values[0])!); + + if (!player.playing) await player.play() + .catch((error: any) => { + console.log(error); + return message.reply({ content: `āŒ | I can't play this track.`, allowedMentions: { repliedUser: false } }); + }); + + i.deferUpdate(); + await msg.edit({ content: "āœ… | Music added.", components: [], allowedMentions: { repliedUser: false } }); + }); + + collector.on("end", async (collected: Collection, reason: string) => { + if (reason == "time" && collected.size == 0) { + if (!player.playing) player.destroy(); + await msg.edit({ content: "āŒ | Time expired.", components: [], allowedMentions: { repliedUser: false } }); + } + }); + } +} + +export const slashExecute = async (client: Client, interaction: ChatInputCommandInteraction) => { + const str = String(interaction.options.get("search", true).value); + const res = await client.lavashark.search(str); + + if (res.loadType === "LOAD_FAILED") { + console.log(`Search Error: ${res.exception?.message}`); + return interaction.editReply({ content: `āŒ | No results found.`, allowedMentions: { repliedUser: false } }); + } + else if (res.loadType === "NO_MATCHES") { + return interaction.editReply({ content: `āŒ | No matches.`, allowedMentions: { repliedUser: false } }); + } + + let player: Player; + try { + const guildMember = interaction.guild!.members.cache.get(interaction.user.id); + const { channel } = guildMember!.voice; + // Creates the audio player + player = client.lavashark.createPlayer({ + guildId: String(interaction.guild?.id), + voiceChannelId: String(channel?.id), + textChannelId: interaction.channel?.id, + selfDeaf: true + }); + + // Connects to the voice channel + player.connect(); + } catch (error) { + console.log(error); + return interaction.editReply({ content: `āŒ | I can't join voice channel.`, allowedMentions: { repliedUser: false } }); + } + + + + if (res.loadType === 'PLAYLIST_LOADED') { + for (const track of res.tracks) { + track.setRequester(client.user); + player.queue.add(track); + } + + return interaction.reply({ content: "āœ… | Music added.", allowedMentions: { repliedUser: false } }); + } + else { + let select = new StringSelectMenuBuilder() + .setCustomId("musicSelect") + .setPlaceholder("Select the music") + .setOptions(res.tracks.map(x => { + return { + label: x.title.length >= 25 ? x.title.substring(0, 22) + "..." : x.title, + description: `Duration: ${x.duration.label}`, + value: x.uri + } + })); + let row = new ActionRowBuilder().addComponents(select); + let msg = await interaction.reply({ components: [row.toJSON()] }); + + const collector = msg.createMessageComponentCollector({ + time: 20000, // 20s + filter: i => i.user.id === interaction.user.id + }); + + collector.on("collect", async (i: StringSelectMenuInteraction) => { + if (i.customId != "musicSelect") return; + + player.queue.add(res.tracks.find(x => x.uri == i.values[0])!); + + if (!player.playing) await player.play() + .catch((error: any) => { + console.log(error); + return interaction.reply({ content: `āŒ | I can't play this track.`, allowedMentions: { repliedUser: false } }); + }); + + i.deferUpdate(); + await msg.edit({ content: "āœ… | Music added.", components: [], allowedMentions: { repliedUser: false } }); + }); + + collector.on("end", async (collected: Collection, reason: string) => { + if (reason == "time" && collected.size == 0) { + if (!player.playing) player.destroy(); + await msg.edit({ content: "āŒ | Time expired.", components: [], allowedMentions: { repliedUser: false } }); + } + }); + } +} \ No newline at end of file From 5967ad6dcb5deb7e854cbd529b21ac32efbe6839 Mon Sep 17 00:00:00 2001 From: hmes98318 <52697423+hmes98318@users.noreply.github.com> Date: Sat, 1 Jul 2023 23:45:54 +0800 Subject: [PATCH 08/64] Add `leave` command --- src/commands/leave.ts | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 src/commands/leave.ts diff --git a/src/commands/leave.ts b/src/commands/leave.ts new file mode 100644 index 0000000..7d3cdc5 --- /dev/null +++ b/src/commands/leave.ts @@ -0,0 +1,38 @@ +import { ChatInputCommandInteraction, Client, Message } from "discord.js"; +import { Player } from "lavashark"; + + +export const name = 'leave'; +export const aliases = ['stop']; +export const description = 'Leave current voice channel'; +export const usage = 'leave' +export const voiceChannel = true; +export const showHelp = true; +export const options = []; + + +export const execute = async (client: Client, message: Message, args: string[]) => { + let player: Player; + try { + player = client.lavashark.getPlayer(message.guild!.id); + } catch (_) { + return message.reply({ content: `āŒ | There is no music currently playing.`, allowedMentions: { repliedUser: false } }); + } + + await player.destroy(); + + return await message.react('šŸ‘'); +} + +export const slashExecute = async (client: Client, interaction: ChatInputCommandInteraction) => { + let player: Player; + try { + player = client.lavashark.getPlayer(interaction.guild!.id); + } catch (_) { + return interaction.reply({ content: `āŒ | There is no music currently playing.`, allowedMentions: { repliedUser: false } }); + } + + await player.destroy(); + + return await interaction.reply('āœ… | Bot leave.'); +} \ No newline at end of file From 3abbfa56a4ad66478f434fbb16462557e38bd11f Mon Sep 17 00:00:00 2001 From: hmes98318 <52697423+hmes98318@users.noreply.github.com> Date: Sun, 2 Jul 2023 23:00:59 +0800 Subject: [PATCH 09/64] Update dependencies --- package-lock.json | 20 ++++++++++---------- package.json | 2 +- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/package-lock.json b/package-lock.json index 3ff64bb..6f7add7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,7 +13,7 @@ "discord.js": "^14.11.0", "dotenv": "^16.0.3", "express": "^4.18.2", - "lavashark": "^1.1.0" + "lavashark": "^1.1.1" }, "devDependencies": { "@types/node": "^20.3.2", @@ -203,9 +203,9 @@ "dev": true }, "node_modules/@types/node": { - "version": "20.3.2", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.3.2.tgz", - "integrity": "sha512-vOBLVQeCQfIcF/2Y7eKFTqrMnizK5lRNQ7ykML/5RuwVXVWxYkgwS7xbt4B6fKCUPgbSL5FSsjHQpaGQP/dQmw==" + "version": "20.3.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.3.3.tgz", + "integrity": "sha512-wheIYdr4NYML61AjC8MKj/2jrR/kDQri/CIpVoZwldwhnIrD/j9jIU5bJ8yBKuB2VhpFV7Ab6G2XkBjv9r9Zzw==" }, "node_modules/@types/ws": { "version": "8.5.5", @@ -460,9 +460,9 @@ } }, "node_modules/discord-api-types": { - "version": "0.37.46", - "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.37.46.tgz", - "integrity": "sha512-DeSi5WSWYTeXJJhdwACtpQycY3g4vLRvE2Ol5IlC0o//P2W+8jXPF447PuJn2fRH1nD7JGEJ3YMb0NB9+OQ7BQ==" + "version": "0.37.47", + "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.37.47.tgz", + "integrity": "sha512-rNif8IAv6duS2z47BMXq/V9kkrLfkAoiwpFY3sLxxbyKprk065zqf3HLTg4bEoxRSmi+Lhc7yqGDrG8C3j8GFA==" }, "node_modules/discord.js": { "version": "14.11.0", @@ -739,9 +739,9 @@ } }, "node_modules/lavashark": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/lavashark/-/lavashark-1.1.0.tgz", - "integrity": "sha512-0/13pC/ZU7bIddfFbNX277otd3LVxS2GywTelc0bsY65ZRNQC0V8l4TNNNk1Y0SYGB1wiSXOGjF9N+ueiiDP+w==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/lavashark/-/lavashark-1.1.1.tgz", + "integrity": "sha512-bIbxomcPet5dV2LKsmSf5FkCDujIpusmTHRjMpcklbGwU4U6eAdE1yOeMVVkEgq7OhJXzEHmrXzFawvFHrsrBA==", "dependencies": { "discord.js": "^14.11.0", "undici": "^5.22.1", diff --git a/package.json b/package.json index 3dce750..9ebd3c9 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,7 @@ "discord.js": "^14.11.0", "dotenv": "^16.0.3", "express": "^4.18.2", - "lavashark": "^1.1.0" + "lavashark": "^1.1.1" }, "devDependencies": { "@types/node": "^20.3.2", From e8e655287d1f010da7dda760802f0060d14154d0 Mon Sep 17 00:00:00 2001 From: hmes98318 <52697423+hmes98318@users.noreply.github.com> Date: Mon, 3 Jul 2023 20:59:10 +0800 Subject: [PATCH 10/64] Refactor getPlayer method --- src/commands/leave.ts | 21 +++++++++------------ src/commands/play.ts | 6 +++--- 2 files changed, 12 insertions(+), 15 deletions(-) diff --git a/src/commands/leave.ts b/src/commands/leave.ts index 7d3cdc5..ef264d0 100644 --- a/src/commands/leave.ts +++ b/src/commands/leave.ts @@ -1,5 +1,4 @@ import { ChatInputCommandInteraction, Client, Message } from "discord.js"; -import { Player } from "lavashark"; export const name = 'leave'; @@ -11,12 +10,11 @@ export const showHelp = true; export const options = []; -export const execute = async (client: Client, message: Message, args: string[]) => { - let player: Player; - try { - player = client.lavashark.getPlayer(message.guild!.id); - } catch (_) { - return message.reply({ content: `āŒ | There is no music currently playing.`, allowedMentions: { repliedUser: false } }); +export const execute = async (client: Client, message: Message) => { + const player = client.lavashark.getPlayer(message.guild!.id); + + if (!player) { + return message.reply({ content: 'āŒ | There is no music currently playing.', allowedMentions: { repliedUser: false } }); } await player.destroy(); @@ -25,11 +23,10 @@ export const execute = async (client: Client, message: Message, args: string[]) } export const slashExecute = async (client: Client, interaction: ChatInputCommandInteraction) => { - let player: Player; - try { - player = client.lavashark.getPlayer(interaction.guild!.id); - } catch (_) { - return interaction.reply({ content: `āŒ | There is no music currently playing.`, allowedMentions: { repliedUser: false } }); + const player = client.lavashark.getPlayer(interaction.guild!.id); + + if (!player) { + return interaction.reply({ content: 'āŒ | There is no music currently playing.', allowedMentions: { repliedUser: false } }); } await player.destroy(); diff --git a/src/commands/play.ts b/src/commands/play.ts index 1a6660f..ef504ae 100644 --- a/src/commands/play.ts +++ b/src/commands/play.ts @@ -1,4 +1,4 @@ -import { Client, Message, ChatInputCommandInteraction } from "discord.js"; +import { ChatInputCommandInteraction, Client, Message } from "discord.js"; export const name = 'play'; export const aliases = ['p']; @@ -17,8 +17,9 @@ export const options = [ export const execute = async (client: Client, message: Message, args: string[]) => { - if (!args[0]) + if (!args[0]) { return message.reply({ content: `āŒ | Write the name of the music you want to search.`, allowedMentions: { repliedUser: false } }); + } const str = args.join(' '); const res = await client.lavashark.search(str); @@ -75,7 +76,6 @@ export const execute = async (client: Client, message: Message, args: string[]) } export const slashExecute = async (client: Client, interaction: ChatInputCommandInteraction) => { - const str = String(interaction.options.get("search", true).value); const res = await client.lavashark.search(str); From 1c67244daba7f56538f3d4907ae75b0b82e86520 Mon Sep 17 00:00:00 2001 From: hmes98318 <52697423+hmes98318@users.noreply.github.com> Date: Mon, 3 Jul 2023 21:01:36 +0800 Subject: [PATCH 11/64] Extract interface types --- src/@types/index.ts | 46 +++++++++++++++++++++++++++++++++++++++++++++ src/index.ts | 27 ++++++-------------------- 2 files changed, 52 insertions(+), 21 deletions(-) create mode 100644 src/@types/index.ts diff --git a/src/@types/index.ts b/src/@types/index.ts new file mode 100644 index 0000000..2b88900 --- /dev/null +++ b/src/@types/index.ts @@ -0,0 +1,46 @@ +import { HexColorString } from "discord.js"; + + +export interface Config { + name: string; + prefix: string; + playing: string; + embedsColor: HexColorString | string | number; + defaultVolume: number; + maxVolume: number; + autoLeave: boolean; + autoLeaveCooldown: number; + displayVoiceState: boolean; + port: number; +} + +export interface Info { + uptime: Date; + os_version: string; + bot_version: string; + node_version: string; + dc_version: string; + shark_version: string; + cpu: string; +} + +export interface SystemStatus { + load: { + percent: string; + detail: string; + }; + memory: { + percent: string; + detail: string; + }; + heap: { + percent: string; + detail: string; + }; + uptime: string; + ping: { + bot: string; + api: number; + }; + serverCount: number; +} \ No newline at end of file diff --git a/src/index.ts b/src/index.ts index 672151e..b3083a9 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,13 +1,16 @@ import * as fs from 'fs'; import * as dotenv from 'dotenv'; -import { Client, GatewayIntentBits, Collection } from 'discord.js'; +import { Client, Collection, GatewayIntentBits } from 'discord.js'; import { LavaShark } from "lavashark"; import consoleStamp from 'console-stamp'; import { cst } from "./utils/constants"; import nodeList from "../node-list.json"; +import { Config, Info } from "./@types"; + + dotenv.config(); consoleStamp(console, { format: ':date(yyyy/mm/dd HH:MM:ss)' }); @@ -16,26 +19,8 @@ declare module 'discord.js' { export interface Client { commands: Collection, lavashark: LavaShark, - config: { - name: string, - prefix: string, - playing: string, - defaultVolume: number, - maxVolume: number, - autoLeave: boolean, - autoLeaveCooldown: number, - displayVoiceState: boolean, - port: number - }, - status: { - uptime: Date, - os_version: string, - bot_version: string, - node_version: string, - dc_version: string, - shark_version: string, - cpu: string - } + config: Config, + info: Info } } From 2499faf8312e6c4e35693ed9ca3ea54a5d8e72e3 Mon Sep 17 00:00:00 2001 From: hmes98318 <52697423+hmes98318@users.noreply.github.com> Date: Mon, 3 Jul 2023 22:12:37 +0800 Subject: [PATCH 12/64] Refactor ready event types --- src/events/ready.ts | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/events/ready.ts b/src/events/ready.ts index 09d6d84..f4e8108 100644 --- a/src/events/ready.ts +++ b/src/events/ready.ts @@ -1,29 +1,30 @@ import os from 'os'; + import { Client, version as dcVersion } from 'discord.js'; -import { VERSION } from 'lavashark'; +import { VERSION as sharkVersion } from 'lavashark'; -import { version } from '../../package.json'; +import { version as botVersion } from '../../package.json'; import { getOSVersion } from '../utils/functions/getOSVersion'; import { cst } from '../utils/constants'; module.exports = async (client: Client) => { - client.status = { + client.info = { uptime: new Date(), os_version: await getOSVersion(), - bot_version: `v${version}`, + bot_version: `v${botVersion}`, node_version: process.version, dc_version: `v${dcVersion}`, - shark_version: `v${VERSION}`, + shark_version: `v${sharkVersion}`, cpu: `${os.cpus()[0].model}` }; const release = { - bot: `${client.config.name}: ${cst.color.cyan}${client.status.bot_version}${cst.color.white}`, - nodejs: `Node.js: ${cst.color.cyan}${client.status.node_version}${cst.color.white}`, - djs: `Discord.js: ${cst.color.cyan}${client.status.dc_version}${cst.color.white}`, - shark: `LavaShark: ${cst.color.cyan}${client.status.shark_version}${cst.color.white}`, + bot: `${client.config.name}: ${cst.color.cyan}${client.info.bot_version}${cst.color.white}`, + nodejs: `Node.js: ${cst.color.cyan}${client.info.node_version}${cst.color.white}`, + djs: `Discord.js: ${cst.color.cyan}${client.info.dc_version}${cst.color.white}`, + shark: `LavaShark: ${cst.color.cyan}${client.info.shark_version}${cst.color.white}`, } console.log(`+-----------------------+`); From 0a141022fb53974dba687ee17e87368c51fc0330 Mon Sep 17 00:00:00 2001 From: hmes98318 <52697423+hmes98318@users.noreply.github.com> Date: Mon, 3 Jul 2023 22:13:04 +0800 Subject: [PATCH 13/64] Add `loop` command --- src/commands/loop.ts | 103 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 103 insertions(+) create mode 100644 src/commands/loop.ts diff --git a/src/commands/loop.ts b/src/commands/loop.ts new file mode 100644 index 0000000..793fd8b --- /dev/null +++ b/src/commands/loop.ts @@ -0,0 +1,103 @@ +import { Client, Message, ChatInputCommandInteraction } from "discord.js"; +import { Player, RepeatMode } from "lavashark"; + + +export const name = 'loop'; +export const aliases = ['lp']; +export const description = 'Turns the music loop mode on or off'; +export const usage = 'loop ' +export const voiceChannel = true; +export const showHelp = true; +export const options = [{ + name: "mode", + description: "The loop mode", + type: 3, + required: true, + choices: [ + { + name: "Off", + value: "off" + }, + { + name: "One", + value: "one" + }, + { + name: "All", + value: "all" + } + ] +}]; + + +export const execute = async (client: Client, message: Message, args: string[]) => { + const player = client.lavashark.getPlayer(message.guild!.id); + + if (!player) { + return message.reply({ content: 'āŒ | There is no music currently playing.', allowedMentions: { repliedUser: false } }); + } + + let mode = null; + const methods = ['Off', 'Single', 'All']; + + if (!args[0]) return message.reply({ content: `āŒ | ${client.config.prefix}${usage}`, allowedMentions: { repliedUser: false } }); + + switch (args[0].toLowerCase()) { + case 'off': { + mode = 0; + player.setRepeatMode(RepeatMode.OFF); + break; + } + case 'one' || 'single': { + mode = 1; + player.setRepeatMode(RepeatMode.TRACK); + break; + } + case 'all' || 'queue': { + mode = 2; + player.setRepeatMode(RepeatMode.QUEUE); + break; + } + default: { + return message.reply({ content: `āŒ | ${client.config.prefix}${usage}`, allowedMentions: { repliedUser: false } }); + } + } + + await message.react('šŸ‘'); + return message.reply({ content: `Set loop to \`${methods[mode]}\``, allowedMentions: { repliedUser: false } }); +} + + +export const slashExecute = async (client: Client, interaction: ChatInputCommandInteraction) => { + const player = client.lavashark.getPlayer(interaction.guild!.id); + + if (!player) { + return interaction.reply({ content: 'āŒ | There is no music currently playing.', allowedMentions: { repliedUser: false } }); + } + + let mode = null; + const methods = ['Off', 'Single', 'All']; + + switch (interaction.options.getString("mode")) { + case 'off': { + mode = 0; + player.setRepeatMode(RepeatMode.OFF); + break; + } + case 'one': { + mode = 1; + player.setRepeatMode(RepeatMode.TRACK); + break; + } + case 'all': { + mode = 2; + player.setRepeatMode(RepeatMode.QUEUE); + break; + } + default: { + return interaction.reply({ content: `āŒ | ${client.config.prefix}${usage}`, allowedMentions: { repliedUser: false } }); + } + } + + return interaction.reply({ content: `Set loop to \`${methods[mode!]}\``, allowedMentions: { repliedUser: false } }); +} \ No newline at end of file From 04d17bfcf848dae79dc03228e7f33a91a58dd88c Mon Sep 17 00:00:00 2001 From: hmes98318 <52697423+hmes98318@users.noreply.github.com> Date: Mon, 3 Jul 2023 22:16:30 +0800 Subject: [PATCH 14/64] Formatting `loop` command --- src/commands/loop.ts | 44 +++++++++++++++++++++++--------------------- 1 file changed, 23 insertions(+), 21 deletions(-) diff --git a/src/commands/loop.ts b/src/commands/loop.ts index 793fd8b..84f921c 100644 --- a/src/commands/loop.ts +++ b/src/commands/loop.ts @@ -1,5 +1,5 @@ import { Client, Message, ChatInputCommandInteraction } from "discord.js"; -import { Player, RepeatMode } from "lavashark"; +import { RepeatMode } from "lavashark"; export const name = 'loop'; @@ -8,26 +8,28 @@ export const description = 'Turns the music loop mode on or off'; export const usage = 'loop ' export const voiceChannel = true; export const showHelp = true; -export const options = [{ - name: "mode", - description: "The loop mode", - type: 3, - required: true, - choices: [ - { - name: "Off", - value: "off" - }, - { - name: "One", - value: "one" - }, - { - name: "All", - value: "all" - } - ] -}]; +export const options = [ + { + name: "mode", + description: "The loop mode", + type: 3, + required: true, + choices: [ + { + name: "Off", + value: "off" + }, + { + name: "One", + value: "one" + }, + { + name: "All", + value: "all" + } + ] + } +]; export const execute = async (client: Client, message: Message, args: string[]) => { From 6046d90a3c19470c71bba26d0d2223ea48a6fa98 Mon Sep 17 00:00:00 2001 From: hmes98318 <52697423+hmes98318@users.noreply.github.com> Date: Mon, 3 Jul 2023 22:37:15 +0800 Subject: [PATCH 15/64] Add `skip` command --- src/commands/skip.ts | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 src/commands/skip.ts diff --git a/src/commands/skip.ts b/src/commands/skip.ts new file mode 100644 index 0000000..b00fd6c --- /dev/null +++ b/src/commands/skip.ts @@ -0,0 +1,33 @@ +import { ChatInputCommandInteraction, Client, Message } from "discord.js"; + + +export const name = 'skip'; +export const aliases = ['s']; +export const description = 'Skip currnet track'; +export const usage = 'leave' +export const voiceChannel = true; +export const showHelp = true; +export const options = []; + + +export const execute = async (client: Client, message: Message) => { + const player = client.lavashark.getPlayer(message.guild!.id); + + if (!player) { + return message.reply({ content: 'āŒ | There is no music currently playing.', allowedMentions: { repliedUser: false } }); + } + + const SUCCESS = await player.skip(); + return SUCCESS ? message.react('šŸ‘') : message.react('āŒ'); +} + +export const slashExecute = async (client: Client, interaction: ChatInputCommandInteraction) => { + const player = client.lavashark.getPlayer(interaction.guild!.id); + + if (!player) { + return interaction.reply({ content: 'āŒ | There is no music currently playing.', allowedMentions: { repliedUser: false } }); + } + + const SUCCESS = await player.skip(); + return SUCCESS ? interaction.reply('āœ… | Music skipped.') : interaction.reply('āŒ | Music skip failed.'); +} \ No newline at end of file From a0c19c4a5ab642f99a2e46742fcf2b678710141c Mon Sep 17 00:00:00 2001 From: hmes98318 <52697423+hmes98318@users.noreply.github.com> Date: Tue, 4 Jul 2023 22:36:46 +0800 Subject: [PATCH 16/64] Add `pause`, `resume` command --- src/commands/pause.ts | 41 +++++++++++++++++++++++++++++++++++++++++ src/commands/resmue.ts | 41 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+) create mode 100644 src/commands/pause.ts create mode 100644 src/commands/resmue.ts diff --git a/src/commands/pause.ts b/src/commands/pause.ts new file mode 100644 index 0000000..e0df47c --- /dev/null +++ b/src/commands/pause.ts @@ -0,0 +1,41 @@ +import { ChatInputCommandInteraction, Client, Message } from "discord.js"; + + +export const name = 'pause'; +export const aliases = []; +export const description = 'Pause current track'; +export const usage = 'pause' +export const voiceChannel = true; +export const showHelp = true; +export const options = []; + + +export const execute = async (client: Client, message: Message) => { + const player = client.lavashark.getPlayer(message.guild!.id); + + if (!player) { + return message.reply({ content: 'āŒ | There is no music currently playing.', allowedMentions: { repliedUser: false } }); + } + + if(player.paused) { + return message.reply({ content: 'āŒ | The music has been paused.', allowedMentions: { repliedUser: false } }); + } + + const SUCCESS = await player.pause(); + return SUCCESS ? message.react('āøļø') : message.react('āŒ'); +} + +export const slashExecute = async (client: Client, interaction: ChatInputCommandInteraction) => { + const player = client.lavashark.getPlayer(interaction.guild!.id); + + if (!player) { + return interaction.reply({ content: 'āŒ | There is no music currently playing.', allowedMentions: { repliedUser: false } }); + } + + if(player.paused) { + return interaction.reply({ content: 'āŒ | The music has been paused.', allowedMentions: { repliedUser: false } }); + } + + const SUCCESS = await player.pause(); + return SUCCESS ? interaction.reply("āøļø | Music paused.") : interaction.reply('āŒ | Music pause failed.'); +} \ No newline at end of file diff --git a/src/commands/resmue.ts b/src/commands/resmue.ts new file mode 100644 index 0000000..b47be8c --- /dev/null +++ b/src/commands/resmue.ts @@ -0,0 +1,41 @@ +import { ChatInputCommandInteraction, Client, Message } from "discord.js"; + + +export const name = 'resume'; +export const aliases = []; +export const description = 'Resume paused track'; +export const usage = 'resume' +export const voiceChannel = true; +export const showHelp = true; +export const options = []; + + +export const execute = async (client: Client, message: Message) => { + const player = client.lavashark.getPlayer(message.guild!.id); + + if (!player) { + return message.reply({ content: 'āŒ | There is no music currently playing.', allowedMentions: { repliedUser: false } }); + } + + if(!player.paused) { + return message.reply({ content: 'āŒ | The music has been resumed.', allowedMentions: { repliedUser: false } }); + } + + const SUCCESS = await player.resume(); + return SUCCESS ? message.react('ā–¶ļø') : message.react('āŒ'); +} + +export const slashExecute = async (client: Client, interaction: ChatInputCommandInteraction) => { + const player = client.lavashark.getPlayer(interaction.guild!.id); + + if (!player) { + return interaction.reply({ content: 'āŒ | There is no music currently playing.', allowedMentions: { repliedUser: false } }); + } + + if(!player.paused) { + return interaction.reply({ content: 'āŒ | The music has been resumed.', allowedMentions: { repliedUser: false } }); + } + + const SUCCESS = await player.resume(); + return SUCCESS ? interaction.reply("ā–¶ļø | Music resumed.") : interaction.reply('āŒ | Music pause failed.'); +} \ No newline at end of file From 453074ae3cd38122d433daa821a6aa4719d9ba41 Mon Sep 17 00:00:00 2001 From: hmes98318 <52697423+hmes98318@users.noreply.github.com> Date: Tue, 4 Jul 2023 22:37:29 +0800 Subject: [PATCH 17/64] Add `voiceStateUpdate` event --- src/events/voiceStateUpdate.ts | 105 +++++++++++++++++++++++++++++++++ 1 file changed, 105 insertions(+) create mode 100644 src/events/voiceStateUpdate.ts diff --git a/src/events/voiceStateUpdate.ts b/src/events/voiceStateUpdate.ts new file mode 100644 index 0000000..1374268 --- /dev/null +++ b/src/events/voiceStateUpdate.ts @@ -0,0 +1,105 @@ +import { Client, VoiceState } from "discord.js"; + + +let pool: any = []; + +export default async (client: Client, oldState: VoiceState, newState: VoiceState) => { + const display = client.config.displayVoiceState ?? true; + + if (newState.channelId === null) { + if (display) console.log(`-- ${newState.member?.user.username} left channel`); + + // If the member who left the channel is not bot, check if the channel still has members + if (!oldState.member?.user.bot) { + let player: any; + try { player = client.lavashark.getPlayer(oldState.guild.id); } catch (_) { return; } + const botChannelId = player?.voiceChannelId; + const oldChannelId = oldState.channel?.id; + + if (botChannelId === oldChannelId) { + // If the channel only has bot, then start counting timeout until leave + if (oldState.channel!.members.size <= 1) { + let timeoutID = setTimeout(() => { + player.destroy(); + }, client.config.autoLeaveCooldown); + + pool.push({ + guildId: oldState.guild.id, + timeoutId: timeoutID + }); + // console.log('pool.add', pool); + } + } + } + } + else if (oldState.channelId === null) { + if (display) console.log(`-- ${newState.member?.user.username} joined channel ${newState.channel?.name}`); + + // If the member who left the channel is not bot, check if the channel still has members + if (!oldState.member?.user.bot) { + let player: any; + try { player = client.lavashark.getPlayer(oldState.guild.id); } catch (_) { return; } + const botChannelId = player?.voiceChannelId; + const newChannelId = newState.channel?.id; + + if (botChannelId === newChannelId) { + // When bot is in the target channel and only one member joined + // If there are two members or more (not include bot) in the channel, it will not trigger + if (newState.channel!.members.size > 1 && newState.channel!.members.size <= 2) { + // If member join bot channel, then find current channel's timeoutID to clear + for (var i = 0; i < pool.length; i++) { + // console.log('pool.del',pool[i]); + + if (pool[i].guildId === newState.guild.id) { + clearTimeout(pool[i].timeoutId); + pool.splice(i, 1); + } + } + } + } + } + } + else { + if (display) console.log(`-- ${newState.member?.user.username} moved channel ${oldState.channel?.name} to ${newState.channel?.name}`); + + + // If the member who left the channel is not bot, check if the channel still has members + if (!oldState.member?.user.bot) { + let player: any; + try { player = client.lavashark.getPlayer(oldState.guild.id); } catch (_) { return; } + const botChannelId = player?.voiceChannelId; + const oldChannelId = oldState.channel?.id; + const newChannelId = newState.channel?.id; + + if (botChannelId === oldChannelId) { + // If the channel only has bot, then start counting timeout until leave + if (oldState.channel!.members.size <= 1) { + let timeoutID = setTimeout(() => { + player.destroy(); + }, client.config.autoLeaveCooldown); + + pool.push({ + guildId: oldState.guild.id, + timeoutId: timeoutID + }); + // console.log('pool.add', pool); + } + } + else if (botChannelId === newChannelId) { + // When bot is in the target channel and only one member joined + // If there are two members or more (not include bot) in the channel, it will not trigger + if (newState.channel!.members.size > 1 && newState.channel!.members.size <= 2) { + // If member join bot channel, then find current channel's timeoutID to clear + for (var i = 0; i < pool.length; i++) { + // console.log('pool.del',pool[i]); + + if (pool[i].guildId === newState.guild.id) { + clearTimeout(pool[i].timeoutId); + pool.splice(i, 1); + } + } + } + } + } + } +}; \ No newline at end of file From 03f4aba5111089b683b716c7f78a2ecb04320b57 Mon Sep 17 00:00:00 2001 From: hmes98318 <52697423+hmes98318@users.noreply.github.com> Date: Wed, 5 Jul 2023 20:44:16 +0800 Subject: [PATCH 18/64] Add `status` command --- src/commands/status.ts | 52 ++++++++++++++++ src/embeds/index.ts | 8 +++ src/embeds/status.ts | 24 ++++++++ src/utils/functions/sysusage.ts | 106 ++++++++++++++++++++++++++++++++ src/utils/functions/uptime.ts | 24 ++++++++ 5 files changed, 214 insertions(+) create mode 100644 src/commands/status.ts create mode 100644 src/embeds/index.ts create mode 100644 src/embeds/status.ts create mode 100644 src/utils/functions/sysusage.ts create mode 100644 src/utils/functions/uptime.ts diff --git a/src/commands/status.ts b/src/commands/status.ts new file mode 100644 index 0000000..28452a4 --- /dev/null +++ b/src/commands/status.ts @@ -0,0 +1,52 @@ +import { ChatInputCommandInteraction, Client, Message } from "discord.js"; +import { embeds } from "../embeds"; + +import { uptime } from "../utils/functions/uptime"; +import { sysusage } from "../utils/functions/sysusage"; + +export const name = 'status'; +export const aliases = ['info']; +export const description = 'Show the bot status'; +export const usage = 'leave' +export const voiceChannel = false; +export const showHelp = true; +export const options = []; + + +export const execute = async (client: Client, message: Message) => { + const systemStatus = { + load: await sysusage.cpu(), + memory: sysusage.ram(), + heap: sysusage.heap(), + uptime: uptime(client.info.uptime), + ping: { + bot: (`${Date.now() - message.createdTimestamp}ms`), + api: client.ws.ping + }, + serverCount: client.guilds.cache.size + } + + return message.reply({ + embeds: [embeds.status(client.config, client.info, systemStatus)], + allowedMentions: { repliedUser: false } + }); +} + +export const slashExecute = async (client: Client, interaction: ChatInputCommandInteraction) => { + const systemStatus = { + load: await sysusage.cpu(), + memory: sysusage.ram(), + heap: sysusage.heap(), + uptime: uptime(client.info.uptime), + ping: { + bot: (`${Date.now() - interaction.createdTimestamp}ms`), + api: client.ws.ping + }, + serverCount: client.guilds.cache.size + } + + return interaction.reply({ + embeds: [embeds.status(client.config, client.info, systemStatus)], + allowedMentions: { repliedUser: false } + }); +} \ No newline at end of file diff --git a/src/embeds/index.ts b/src/embeds/index.ts new file mode 100644 index 0000000..77466c5 --- /dev/null +++ b/src/embeds/index.ts @@ -0,0 +1,8 @@ +import { status } from "./status"; + + +const embeds = { + status, +} + +export { embeds }; \ No newline at end of file diff --git a/src/embeds/status.ts b/src/embeds/status.ts new file mode 100644 index 0000000..4655223 --- /dev/null +++ b/src/embeds/status.ts @@ -0,0 +1,24 @@ +import { EmbedBuilder, HexColorString } from "discord.js"; +import { Config, Info, SystemStatus } from "../@types"; + + +const status = (config: Config, info: Info, systemStatus: SystemStatus) => { + const cpuUsage = `${systemStatus.load.percent} \`${systemStatus.load.detail}\``; + const ramUsage = `${systemStatus.memory.percent} \`${systemStatus.memory.detail}\``; + const heapUsage = `${systemStatus.heap.percent} \`${systemStatus.heap.detail}\``; + + const embed_ = new EmbedBuilder() + .setColor(config.embedsColor as HexColorString | number) + .setTitle(`${config.name} ${info.bot_version}`) + .setURL('https://github.com/hmes98318/Music-Disc') + .setDescription(`**ā€¢ Serving ${systemStatus.serverCount} servers**\nā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”`) + .addFields( + { name: `āš™ļø SYSTEM`, value: `OS : **${info.os_version}**\nNode.js : **${info.node_version}**\nDiscord.js : **${info.dc_version}**\nLavaShark : **${info.shark_version}**\nCPU : **${info.cpu}**\nUptime : **${systemStatus.uptime}**\nā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”`, inline: false }, + { name: `šŸ“Š USAGE`, value: `CPU : **${cpuUsage}**\nRam : **${ramUsage}**\nHeap : **${heapUsage}**\nā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”`, inline: false }, + { name: `šŸ›°ļø LATENCY`, value: `Bot : **${systemStatus.ping.bot}**\nAPI : **${systemStatus.ping.api}ms**`, inline: false } + ) + .setTimestamp() + return embed_; +} + +export { status }; \ No newline at end of file diff --git a/src/utils/functions/sysusage.ts b/src/utils/functions/sysusage.ts new file mode 100644 index 0000000..fc81384 --- /dev/null +++ b/src/utils/functions/sysusage.ts @@ -0,0 +1,106 @@ +import os from 'os'; +import util from 'util'; +import { exec } from "child_process"; + +import { CpuInfo } from 'os'; + +const execPromisify = util.promisify(exec); + + +const sysusage = { + cpu: async () => { + const platform = os.platform(); + const load = os.loadavg(); + const strLoad = `[${load[0].toFixed(2)}, ${load[1].toFixed(2)}, ${load[2].toFixed(2)}]`; + let cpuPercent = '0%'; + + if (platform === 'win32') { + try { + const { stdout, stderr } = await execPromisify('wmic cpu get LoadPercentage'); + if (stderr) { + throw new Error(stderr); + } + + const loadArr = stdout.split('\r\r\n').filter((item) => !isNaN(parseInt(item))); + const totalLoad = loadArr.reduce((acc, load) => acc + parseInt(load), 0); + const avgLoad = Math.round(totalLoad / loadArr.length); + cpuPercent = avgLoad + '%'; + } catch (error) { + console.error('Error getting CPU load:', error); + } + } + else { + cpuPercent = await getCpuPercentage() + '%'; + } + + console.log(`CPU: ${cpuPercent} ${strLoad}`); + return { + percent: cpuPercent, + detail: strLoad + }; + }, + ram: () => { + const totalRam = os.totalmem(); + const usedRam = process.memoryUsage().rss; + const usedRatio = ((usedRam / totalRam * 10000) / 100).toFixed(1); + const totalMb = (totalRam / (1024 * 1024)).toFixed(0); + const usedMb = (usedRam / (1024 * 1024)).toFixed(0); + + console.log(`Ram: ${usedRatio}% (${usedMb} / ${totalMb} MB)`); + return { + percent: `${usedRatio}%`, + detail: `(${usedMb} / ${totalMb} MB)` + }; + }, + heap: () => { + const totalHeap = process.memoryUsage().heapTotal; + const usedHeap = process.memoryUsage().heapUsed; + const usedRatio = ((usedHeap / totalHeap * 10000) / 100).toFixed(1); + const totalMb = (totalHeap / (1024 * 1024)).toFixed(0); + const usedMb = (usedHeap / (1024 * 1024)).toFixed(0); + + console.log(`Heap: ${usedRatio}% (${usedMb} / ${totalMb} MB)`); + return { + percent: `${usedRatio}%`, + detail: `(${usedMb} / ${totalMb} MB)` + }; + } +}; + +export { sysusage }; + + +const getCpuLoad = () => { + const cpus = os.cpus(); + + let totalIdle = 0, + totalTick = 0; + + cpus.forEach(cpu => { + for (let type in cpu.times) { + totalTick += cpu.times[type as keyof CpuInfo["times"]]; + } + totalIdle += cpu.times.idle; + }); + + return { + idle: totalIdle / cpus.length, + total: totalTick / cpus.length + }; +} + +const getCpuPercentage = () => { + const firstLoad = getCpuLoad(); + + return new Promise(resolve => { + setTimeout(() => { + const secondLoad = getCpuLoad(); + + const idleDiff = secondLoad.idle - firstLoad.idle; + const totalDiff = secondLoad.total - firstLoad.total; + const avgLoad = 100 - ~~(100 * idleDiff / totalDiff); + + resolve(avgLoad); + }, 1000); + }); +} \ No newline at end of file diff --git a/src/utils/functions/uptime.ts b/src/utils/functions/uptime.ts new file mode 100644 index 0000000..383bf21 --- /dev/null +++ b/src/utils/functions/uptime.ts @@ -0,0 +1,24 @@ +const uptime = (startTime: Date) => { + + let Today = new Date(); + let date1 = startTime.getTime(); + let date2 = Today.getTime(); + let total = (date2 - date1) / 1000; + + let day = Math.floor(total / (24 * 60 * 60)); // č؈ē®—ę•“ę•ø天ę•ø + let afterDay = total - day * 24 * 60 * 60; // 取得ē®—å‡ŗ天ę•ø後剩餘ēš„ē§’ę•ø + let hour = Math.floor(afterDay / (60 * 60)); // č؈ē®—ę•“ę•øå°ę™‚ę•ø + let afterHour = total - day * 24 * 60 * 60 - hour * 60 * 60; // 取得ē®—å‡ŗå°ę™‚ę•ø後剩餘ēš„ē§’ę•ø + let min = Math.floor(afterHour / 60); // č؈ē®—ę•“ę•ø分 + let afterMin = Math.round(total - day * 24 * 60 * 60 - hour * 60 * 60 - min * 60); // 取得ē®—å‡ŗ分後剩餘ēš„ē§’ę•ø + console.log(`Uptime: ${day} / ${hour} : ${min} : ${afterMin}`); + + if (day >= 1) { + return day + ' Day(s) ' + hour + 'Hour(s)'/* + min + 'Minute(s)' + afterMin*/; + } + else { + return /*day + ' Days' +*/ hour + 'Hour(s) ' + min + 'Minute(s)' /*+ afterMin + 'Second(s)'*/; + } +}; + +export { uptime }; \ No newline at end of file From c5145f4108cc4bb5eb15e7c8db2faa1314a90a5f Mon Sep 17 00:00:00 2001 From: hmes98318 <52697423+hmes98318@users.noreply.github.com> Date: Wed, 5 Jul 2023 21:40:20 +0800 Subject: [PATCH 19/64] Add `volume` command --- src/commands/volume.ts | 69 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 src/commands/volume.ts diff --git a/src/commands/volume.ts b/src/commands/volume.ts new file mode 100644 index 0000000..2386f29 --- /dev/null +++ b/src/commands/volume.ts @@ -0,0 +1,69 @@ +import { ChatInputCommandInteraction, Client, Message } from "discord.js"; + + +export const name = 'volume'; +export const aliases = ['v']; +export const description = 'Configure bot volume'; +export const usage = 'v <0-100>' +export const voiceChannel = true; +export const showHelp = true; +export const options = [ + { + name: "volume", + description: "The volume to set", + type: 4, + required: true, + min_value: 1 + } +]; + + +export const execute = async (client: Client, message: Message, args: string[]) => { + const maxVolume = client.config.maxVolume; + const player = client.lavashark.getPlayer(message.guild!.id); + + if (!player) { + return message.reply({ content: 'āŒ | There is no music currently playing.', allowedMentions: { repliedUser: false } }); + } + + await message.react('šŸ‘'); + const vol = parseInt(args[0], 10); + + if (!vol) { + return message.reply({ content: `Current volume: **${player.volume}** šŸ”Š\n**To change the volume, with \`1\` to \`${maxVolume}\` Type a number between.**`, allowedMentions: { repliedUser: false } }); + } + if (player.volume === vol) { + return message.reply({ content: `āŒ | The volume you want to change is already the current volume.`, allowedMentions: { repliedUser: false } }); + } + if (vol < 0 || vol > maxVolume) { + return message.reply({ content: `āŒ | **Type a number from \`1\` to \`${maxVolume}\` to change the volume .**`, allowedMentions: { repliedUser: false } }); + } + + player.filters.setVolume(vol); + return message.reply({ content: `šŸ”Š **${vol}**/**${maxVolume}**%`, allowedMentions: { repliedUser: false } }); +} + +export const slashExecute = async (client: Client, interaction: ChatInputCommandInteraction) => { + + const maxVolume = client.config.maxVolume; + const player = client.lavashark.getPlayer(interaction.guild!.id); + + if (!player) { + return interaction.reply({ content: 'āŒ | There is no music currently playing.', allowedMentions: { repliedUser: false } }); + } + + const vol = Math.floor(interaction.options.getInteger("volume")!); + + if (!vol) { + return interaction.reply({ content: `Current volume: **${player.volume}** šŸ”Š\n**To change the volume, with \`1\` to \`${maxVolume}\` Type a number between.**`, allowedMentions: { repliedUser: false } }); + } + if (player.volume === vol) { + return interaction.reply({ content: `āŒ | The volume you want to change is already the current volume.`, allowedMentions: { repliedUser: false } }); + } + if (vol < 0 || vol > maxVolume) { + return interaction.reply({ content: `āŒ | **Type a number from \`1\` to \`${maxVolume}\` to change the volume .**`, allowedMentions: { repliedUser: false } }); + } + + player.filters.setVolume(vol); + return interaction.reply({ content: `šŸ”Š **${vol}**/**${maxVolume}**%`, allowedMentions: { repliedUser: false } }); +} \ No newline at end of file From 9762e874bf04f96a2fb1b380e3752bae743ac7ec Mon Sep 17 00:00:00 2001 From: hmes98318 <52697423+hmes98318@users.noreply.github.com> Date: Wed, 5 Jul 2023 22:19:19 +0800 Subject: [PATCH 20/64] Formatting files --- src/commands/leave.ts | 2 +- src/commands/loop.ts | 2 +- src/commands/pause.ts | 2 +- src/commands/play.ts | 2 +- src/commands/resmue.ts | 2 +- src/commands/search.ts | 2 +- src/commands/skip.ts | 2 +- src/commands/status.ts | 2 +- src/commands/volume.ts | 2 +- 9 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/commands/leave.ts b/src/commands/leave.ts index ef264d0..213aff5 100644 --- a/src/commands/leave.ts +++ b/src/commands/leave.ts @@ -4,7 +4,7 @@ import { ChatInputCommandInteraction, Client, Message } from "discord.js"; export const name = 'leave'; export const aliases = ['stop']; export const description = 'Leave current voice channel'; -export const usage = 'leave' +export const usage = 'leave'; export const voiceChannel = true; export const showHelp = true; export const options = []; diff --git a/src/commands/loop.ts b/src/commands/loop.ts index 84f921c..c43b3a9 100644 --- a/src/commands/loop.ts +++ b/src/commands/loop.ts @@ -5,7 +5,7 @@ import { RepeatMode } from "lavashark"; export const name = 'loop'; export const aliases = ['lp']; export const description = 'Turns the music loop mode on or off'; -export const usage = 'loop ' +export const usage = 'loop '; export const voiceChannel = true; export const showHelp = true; export const options = [ diff --git a/src/commands/pause.ts b/src/commands/pause.ts index e0df47c..9c2c5c8 100644 --- a/src/commands/pause.ts +++ b/src/commands/pause.ts @@ -4,7 +4,7 @@ import { ChatInputCommandInteraction, Client, Message } from "discord.js"; export const name = 'pause'; export const aliases = []; export const description = 'Pause current track'; -export const usage = 'pause' +export const usage = 'pause'; export const voiceChannel = true; export const showHelp = true; export const options = []; diff --git a/src/commands/play.ts b/src/commands/play.ts index ef504ae..ce08e0c 100644 --- a/src/commands/play.ts +++ b/src/commands/play.ts @@ -3,7 +3,7 @@ import { ChatInputCommandInteraction, Client, Message } from "discord.js"; export const name = 'play'; export const aliases = ['p']; export const description = 'Enter your song link or song name to play'; -export const usage = 'play ' +export const usage = 'play '; export const voiceChannel = true; export const showHelp = true; export const options = [ diff --git a/src/commands/resmue.ts b/src/commands/resmue.ts index b47be8c..3d26a3f 100644 --- a/src/commands/resmue.ts +++ b/src/commands/resmue.ts @@ -4,7 +4,7 @@ import { ChatInputCommandInteraction, Client, Message } from "discord.js"; export const name = 'resume'; export const aliases = []; export const description = 'Resume paused track'; -export const usage = 'resume' +export const usage = 'resume'; export const voiceChannel = true; export const showHelp = true; export const options = []; diff --git a/src/commands/search.ts b/src/commands/search.ts index 9218b58..0840bfd 100644 --- a/src/commands/search.ts +++ b/src/commands/search.ts @@ -14,7 +14,7 @@ import { Player } from "lavashark"; export const name = 'search'; export const aliases = ['find']; export const description = 'Enter song name to search'; -export const usage = 'search ' +export const usage = 'search '; export const voiceChannel = true; export const showHelp = true; export const options = [ diff --git a/src/commands/skip.ts b/src/commands/skip.ts index b00fd6c..99c7e71 100644 --- a/src/commands/skip.ts +++ b/src/commands/skip.ts @@ -4,7 +4,7 @@ import { ChatInputCommandInteraction, Client, Message } from "discord.js"; export const name = 'skip'; export const aliases = ['s']; export const description = 'Skip currnet track'; -export const usage = 'leave' +export const usage = 'skip'; export const voiceChannel = true; export const showHelp = true; export const options = []; diff --git a/src/commands/status.ts b/src/commands/status.ts index 28452a4..bdb3686 100644 --- a/src/commands/status.ts +++ b/src/commands/status.ts @@ -7,7 +7,7 @@ import { sysusage } from "../utils/functions/sysusage"; export const name = 'status'; export const aliases = ['info']; export const description = 'Show the bot status'; -export const usage = 'leave' +export const usage = 'status'; export const voiceChannel = false; export const showHelp = true; export const options = []; diff --git a/src/commands/volume.ts b/src/commands/volume.ts index 2386f29..75ced26 100644 --- a/src/commands/volume.ts +++ b/src/commands/volume.ts @@ -4,7 +4,7 @@ import { ChatInputCommandInteraction, Client, Message } from "discord.js"; export const name = 'volume'; export const aliases = ['v']; export const description = 'Configure bot volume'; -export const usage = 'v <0-100>' +export const usage = 'v <0-100>'; export const voiceChannel = true; export const showHelp = true; export const options = [ From 7b95f536d6f9d7b801e2717646768c5c15048fdb Mon Sep 17 00:00:00 2001 From: hmes98318 <52697423+hmes98318@users.noreply.github.com> Date: Wed, 5 Jul 2023 22:58:03 +0800 Subject: [PATCH 21/64] Refactor interaction reply --- src/commands/leave.ts | 4 ++-- src/commands/loop.ts | 6 +++--- src/commands/pause.ts | 6 +++--- src/commands/play.ts | 6 +++--- src/commands/resmue.ts | 6 +++--- src/commands/search.ts | 10 +++++----- src/commands/skip.ts | 4 ++-- src/commands/status.ts | 2 +- src/commands/volume.ts | 10 +++++----- src/events/interactionCreate.ts | 1 + 10 files changed, 28 insertions(+), 27 deletions(-) diff --git a/src/commands/leave.ts b/src/commands/leave.ts index 213aff5..fa6e329 100644 --- a/src/commands/leave.ts +++ b/src/commands/leave.ts @@ -26,10 +26,10 @@ export const slashExecute = async (client: Client, interaction: ChatInputCommand const player = client.lavashark.getPlayer(interaction.guild!.id); if (!player) { - return interaction.reply({ content: 'āŒ | There is no music currently playing.', allowedMentions: { repliedUser: false } }); + return interaction.editReply({ content: 'āŒ | There is no music currently playing.', allowedMentions: { repliedUser: false } }); } await player.destroy(); - return await interaction.reply('āœ… | Bot leave.'); + return await interaction.editReply('āœ… | Bot leave.'); } \ No newline at end of file diff --git a/src/commands/loop.ts b/src/commands/loop.ts index c43b3a9..f5aa775 100644 --- a/src/commands/loop.ts +++ b/src/commands/loop.ts @@ -74,7 +74,7 @@ export const slashExecute = async (client: Client, interaction: ChatInputCommand const player = client.lavashark.getPlayer(interaction.guild!.id); if (!player) { - return interaction.reply({ content: 'āŒ | There is no music currently playing.', allowedMentions: { repliedUser: false } }); + return interaction.editReply({ content: 'āŒ | There is no music currently playing.', allowedMentions: { repliedUser: false } }); } let mode = null; @@ -97,9 +97,9 @@ export const slashExecute = async (client: Client, interaction: ChatInputCommand break; } default: { - return interaction.reply({ content: `āŒ | ${client.config.prefix}${usage}`, allowedMentions: { repliedUser: false } }); + return interaction.editReply({ content: `āŒ | ${client.config.prefix}${usage}`, allowedMentions: { repliedUser: false } }); } } - return interaction.reply({ content: `Set loop to \`${methods[mode!]}\``, allowedMentions: { repliedUser: false } }); + return interaction.editReply({ content: `Set loop to \`${methods[mode!]}\``, allowedMentions: { repliedUser: false } }); } \ No newline at end of file diff --git a/src/commands/pause.ts b/src/commands/pause.ts index 9c2c5c8..a0fd9d8 100644 --- a/src/commands/pause.ts +++ b/src/commands/pause.ts @@ -29,13 +29,13 @@ export const slashExecute = async (client: Client, interaction: ChatInputCommand const player = client.lavashark.getPlayer(interaction.guild!.id); if (!player) { - return interaction.reply({ content: 'āŒ | There is no music currently playing.', allowedMentions: { repliedUser: false } }); + return interaction.editReply({ content: 'āŒ | There is no music currently playing.', allowedMentions: { repliedUser: false } }); } if(player.paused) { - return interaction.reply({ content: 'āŒ | The music has been paused.', allowedMentions: { repliedUser: false } }); + return interaction.editReply({ content: 'āŒ | The music has been paused.', allowedMentions: { repliedUser: false } }); } const SUCCESS = await player.pause(); - return SUCCESS ? interaction.reply("āøļø | Music paused.") : interaction.reply('āŒ | Music pause failed.'); + return SUCCESS ? interaction.editReply("āøļø | Music paused.") : interaction.editReply('āŒ | Music pause failed.'); } \ No newline at end of file diff --git a/src/commands/play.ts b/src/commands/play.ts index ce08e0c..0e8a665 100644 --- a/src/commands/play.ts +++ b/src/commands/play.ts @@ -8,7 +8,7 @@ export const voiceChannel = true; export const showHelp = true; export const options = [ { - name: "search", + name: "play", description: "The song link or song name", type: 3, required: true @@ -76,8 +76,8 @@ export const execute = async (client: Client, message: Message, args: string[]) } export const slashExecute = async (client: Client, interaction: ChatInputCommandInteraction) => { - const str = String(interaction.options.get("search", true).value); - const res = await client.lavashark.search(str); + const str = interaction.options.getString("play"); + const res = await client.lavashark.search(str!); if (res.loadType === "LOAD_FAILED") { console.log(`Search Error: ${res.exception?.message}`); diff --git a/src/commands/resmue.ts b/src/commands/resmue.ts index 3d26a3f..b888c21 100644 --- a/src/commands/resmue.ts +++ b/src/commands/resmue.ts @@ -29,13 +29,13 @@ export const slashExecute = async (client: Client, interaction: ChatInputCommand const player = client.lavashark.getPlayer(interaction.guild!.id); if (!player) { - return interaction.reply({ content: 'āŒ | There is no music currently playing.', allowedMentions: { repliedUser: false } }); + return interaction.editReply({ content: 'āŒ | There is no music currently playing.', allowedMentions: { repliedUser: false } }); } if(!player.paused) { - return interaction.reply({ content: 'āŒ | The music has been resumed.', allowedMentions: { repliedUser: false } }); + return interaction.editReply({ content: 'āŒ | The music has been resumed.', allowedMentions: { repliedUser: false } }); } const SUCCESS = await player.resume(); - return SUCCESS ? interaction.reply("ā–¶ļø | Music resumed.") : interaction.reply('āŒ | Music pause failed.'); + return SUCCESS ? interaction.editReply("ā–¶ļø | Music resumed.") : interaction.editReply('āŒ | Music pause failed.'); } \ No newline at end of file diff --git a/src/commands/search.ts b/src/commands/search.ts index 0840bfd..e1cd08b 100644 --- a/src/commands/search.ts +++ b/src/commands/search.ts @@ -116,8 +116,8 @@ export const execute = async (client: Client, message: Message, args: string[]) } export const slashExecute = async (client: Client, interaction: ChatInputCommandInteraction) => { - const str = String(interaction.options.get("search", true).value); - const res = await client.lavashark.search(str); + const str = interaction.options.getString("search"); + const res = await client.lavashark.search(str!); if (res.loadType === "LOAD_FAILED") { console.log(`Search Error: ${res.exception?.message}`); @@ -154,7 +154,7 @@ export const slashExecute = async (client: Client, interaction: ChatInputCommand player.queue.add(track); } - return interaction.reply({ content: "āœ… | Music added.", allowedMentions: { repliedUser: false } }); + return interaction.editReply({ content: "āœ… | Music added.", allowedMentions: { repliedUser: false } }); } else { let select = new StringSelectMenuBuilder() @@ -168,7 +168,7 @@ export const slashExecute = async (client: Client, interaction: ChatInputCommand } })); let row = new ActionRowBuilder().addComponents(select); - let msg = await interaction.reply({ components: [row.toJSON()] }); + let msg = await interaction.editReply({ components: [row.toJSON()] }); const collector = msg.createMessageComponentCollector({ time: 20000, // 20s @@ -183,7 +183,7 @@ export const slashExecute = async (client: Client, interaction: ChatInputCommand if (!player.playing) await player.play() .catch((error: any) => { console.log(error); - return interaction.reply({ content: `āŒ | I can't play this track.`, allowedMentions: { repliedUser: false } }); + return interaction.editReply({ content: `āŒ | I can't play this track.`, allowedMentions: { repliedUser: false } }); }); i.deferUpdate(); diff --git a/src/commands/skip.ts b/src/commands/skip.ts index 99c7e71..9de3eb2 100644 --- a/src/commands/skip.ts +++ b/src/commands/skip.ts @@ -25,9 +25,9 @@ export const slashExecute = async (client: Client, interaction: ChatInputCommand const player = client.lavashark.getPlayer(interaction.guild!.id); if (!player) { - return interaction.reply({ content: 'āŒ | There is no music currently playing.', allowedMentions: { repliedUser: false } }); + return interaction.editReply({ content: 'āŒ | There is no music currently playing.', allowedMentions: { repliedUser: false } }); } const SUCCESS = await player.skip(); - return SUCCESS ? interaction.reply('āœ… | Music skipped.') : interaction.reply('āŒ | Music skip failed.'); + return SUCCESS ? interaction.editReply('āœ… | Music skipped.') : interaction.editReply('āŒ | Music skip failed.'); } \ No newline at end of file diff --git a/src/commands/status.ts b/src/commands/status.ts index bdb3686..03d6252 100644 --- a/src/commands/status.ts +++ b/src/commands/status.ts @@ -45,7 +45,7 @@ export const slashExecute = async (client: Client, interaction: ChatInputCommand serverCount: client.guilds.cache.size } - return interaction.reply({ + return interaction.editReply({ embeds: [embeds.status(client.config, client.info, systemStatus)], allowedMentions: { repliedUser: false } }); diff --git a/src/commands/volume.ts b/src/commands/volume.ts index 75ced26..e7841f7 100644 --- a/src/commands/volume.ts +++ b/src/commands/volume.ts @@ -49,21 +49,21 @@ export const slashExecute = async (client: Client, interaction: ChatInputCommand const player = client.lavashark.getPlayer(interaction.guild!.id); if (!player) { - return interaction.reply({ content: 'āŒ | There is no music currently playing.', allowedMentions: { repliedUser: false } }); + return interaction.editReply({ content: 'āŒ | There is no music currently playing.', allowedMentions: { repliedUser: false } }); } const vol = Math.floor(interaction.options.getInteger("volume")!); if (!vol) { - return interaction.reply({ content: `Current volume: **${player.volume}** šŸ”Š\n**To change the volume, with \`1\` to \`${maxVolume}\` Type a number between.**`, allowedMentions: { repliedUser: false } }); + return interaction.editReply({ content: `Current volume: **${player.volume}** šŸ”Š\n**To change the volume, with \`1\` to \`${maxVolume}\` Type a number between.**`, allowedMentions: { repliedUser: false } }); } if (player.volume === vol) { - return interaction.reply({ content: `āŒ | The volume you want to change is already the current volume.`, allowedMentions: { repliedUser: false } }); + return interaction.editReply({ content: `āŒ | The volume you want to change is already the current volume.`, allowedMentions: { repliedUser: false } }); } if (vol < 0 || vol > maxVolume) { - return interaction.reply({ content: `āŒ | **Type a number from \`1\` to \`${maxVolume}\` to change the volume .**`, allowedMentions: { repliedUser: false } }); + return interaction.editReply({ content: `āŒ | **Type a number from \`1\` to \`${maxVolume}\` to change the volume .**`, allowedMentions: { repliedUser: false } }); } player.filters.setVolume(vol); - return interaction.reply({ content: `šŸ”Š **${vol}**/**${maxVolume}**%`, allowedMentions: { repliedUser: false } }); + return interaction.editReply({ content: `šŸ”Š **${vol}**/**${maxVolume}**%`, allowedMentions: { repliedUser: false } }); } \ No newline at end of file diff --git a/src/events/interactionCreate.ts b/src/events/interactionCreate.ts index 767b65e..14de47e 100644 --- a/src/events/interactionCreate.ts +++ b/src/events/interactionCreate.ts @@ -23,6 +23,7 @@ export default async (client: Client, interaction: ChatInputCommandInteraction) if (cmd) { console.log(`(${cst.color.grey}${guildMember?.guild.name}${cst.color.white}) ${interaction.user.username} : /${interaction.commandName}`); + await interaction.deferReply(); cmd.slashExecute(client, interaction); } } From 41474d9f3f9882018d4c493a150b6f8004e3b76e Mon Sep 17 00:00:00 2001 From: hmes98318 <52697423+hmes98318@users.noreply.github.com> Date: Thu, 6 Jul 2023 20:53:04 +0800 Subject: [PATCH 22/64] Add `queue` command --- src/commands/queue.ts | 72 +++++++++++++++++++++++++++++++++++++++++++ src/embeds/index.ts | 2 ++ src/embeds/queue.ts | 15 +++++++++ 3 files changed, 89 insertions(+) create mode 100644 src/commands/queue.ts create mode 100644 src/embeds/queue.ts diff --git a/src/commands/queue.ts b/src/commands/queue.ts new file mode 100644 index 0000000..d669490 --- /dev/null +++ b/src/commands/queue.ts @@ -0,0 +1,72 @@ +import { ChatInputCommandInteraction, Client, Message } from "discord.js"; +import { embeds } from "../embeds"; + + +export const name = 'queue'; +export const aliases = ['q', 'list']; +export const description = 'Show currnet playlist'; +export const usage = 'queue'; +export const voiceChannel = true; +export const showHelp = true; +export const options = []; + + +export const execute = async (client: Client, message: Message) => { + const player = client.lavashark.getPlayer(message.guild!.id); + + if (!player) { + return message.reply({ content: 'āŒ | There is no music currently playing.', allowedMentions: { repliedUser: false } }); + } + + let nowplaying = `Now Playing : ${player.current?.title}\n\n`; + let tracksQueue = ''; + const tracks = player.queue.tracks.map((track, index) => { return `${++index}. \`${track.title}\`` }); + + if (tracks.length < 1) { + tracksQueue = '------------------------------'; + } + else if (tracks.length > 9) { + tracksQueue = tracks.slice(0, 10).join('\n'); + tracksQueue += `\nand ${tracks.length - 10} other songs`; + } + else { + tracksQueue = tracks.join('\n'); + } + + let repeatMode = player.queueRepeat ? 'All' : (player.trackRepeat ? 'One' : 'Off'); + + return message.reply({ + embeds: [embeds.queue(client.config.embedsColor, nowplaying, tracksQueue, repeatMode)], + allowedMentions: { repliedUser: false } + }); +} + +export const slashExecute = async (client: Client, interaction: ChatInputCommandInteraction) => { + const player = client.lavashark.getPlayer(interaction.guild!.id); + + if (!player) { + return interaction.editReply({ content: 'āŒ | There is no music currently playing.', allowedMentions: { repliedUser: false } }); + } + + let nowplaying = `Now Playing : ${player.current?.title}\n\n`; + let tracksQueue = ''; + const tracks = player.queue.tracks.map((track, index) => { return `${++index}. \`${track.title}\`` }); + + if (tracks.length < 1) { + tracksQueue = '------------------------------'; + } + else if (tracks.length > 9) { + tracksQueue = tracks.slice(0, 10).join('\n'); + tracksQueue += `\nand ${tracks.length - 10} other songs`; + } + else { + tracksQueue = tracks.join('\n'); + } + + let repeatMode = player.queueRepeat ? 'All' : (player.trackRepeat ? 'One' : 'Off'); + + return interaction.editReply({ + embeds: [embeds.queue(client.config.embedsColor, nowplaying, tracksQueue, repeatMode)], + allowedMentions: { repliedUser: false } + }); +} \ No newline at end of file diff --git a/src/embeds/index.ts b/src/embeds/index.ts index 77466c5..70f535a 100644 --- a/src/embeds/index.ts +++ b/src/embeds/index.ts @@ -1,8 +1,10 @@ import { status } from "./status"; +import { queue } from "./queue"; const embeds = { status, + queue } export { embeds }; \ No newline at end of file diff --git a/src/embeds/queue.ts b/src/embeds/queue.ts new file mode 100644 index 0000000..8ca671f --- /dev/null +++ b/src/embeds/queue.ts @@ -0,0 +1,15 @@ +import { EmbedBuilder, HexColorString } from "discord.js"; + + +const queue = (embedsColor: HexColorString | string | number, nowPlaying: string, queueList: string, repeatMode: string) => { + + const embed_ = new EmbedBuilder() + .setColor(embedsColor as HexColorString | number) + .setTitle('Queue List') + .addFields({ name: nowPlaying, value: queueList }) + .setTimestamp() + .setFooter({ text: `Loop: ${repeatMode}` }); + return embed_; +} + +export { queue }; \ No newline at end of file From 0fea7e0a91c41969d6a24e382bef7cb95316c80a Mon Sep 17 00:00:00 2001 From: hmes98318 <52697423+hmes98318@users.noreply.github.com> Date: Thu, 6 Jul 2023 23:04:22 +0800 Subject: [PATCH 23/64] Add `seek` command --- src/commands/seek.ts | 73 ++++++++++++++++++++++++++++ src/utils/functions/timeToSeconds.ts | 61 +++++++++++++++++++++++ 2 files changed, 134 insertions(+) create mode 100644 src/commands/seek.ts create mode 100644 src/utils/functions/timeToSeconds.ts diff --git a/src/commands/seek.ts b/src/commands/seek.ts new file mode 100644 index 0000000..d84b491 --- /dev/null +++ b/src/commands/seek.ts @@ -0,0 +1,73 @@ +import { ChatInputCommandInteraction, Client, Message } from "discord.js"; +import { timeToSeconds } from "../utils/functions/timeToSeconds"; + + +export const name = 'seek'; +export const aliases = []; +export const description = 'Seeks to a certain time in the track'; +export const usage = 'seek <[hh]mm]ss/[hh:mm]:ss> (ex: 3m20s, 1:20:55)'; +export const voiceChannel = true; +export const showHelp = true; +export const options = [ + { + name: "seek", + description: "traget time (ex: 3m20s, 1:20:55)", + type: 3, + required: true + } +]; + + +export const execute = async (client: Client, message: Message, args: string[]) => { + const player = client.lavashark.getPlayer(message.guild!.id); + + if (!player) { + return message.reply({ content: 'āŒ | There is no music currently playing.', allowedMentions: { repliedUser: false } }); + } + + const str = args.join(' '); + const tragetTime = timeToSeconds(str); + + if (!tragetTime) { + return message.reply({ content: `āŒ | Invalid format for the target time.\n(**\`ex: 3m20s, 1m 50s, 1:20:55, 5:20\`**)`, allowedMentions: { repliedUser: false } }); + } + + const tragetTimeMs = tragetTime * 1000; + + await message.react('šŸ‘'); + await player.seek(tragetTimeMs); + + if(tragetTimeMs >= player.current!.duration.value){ + return message.reply({ content: `āœ… | The seek position is beyond the duration of this track. (\`${player.current!.duration.label}\`)\nSkipping to the next song.`, allowedMentions: { repliedUser: false } }); + } + else{ + return message.reply({ content: `āœ… | Music has been seeked to \`${str}\`.`, allowedMentions: { repliedUser: false } }); + } +} + +export const slashExecute = async (client: Client, interaction: ChatInputCommandInteraction) => { + const player = client.lavashark.getPlayer(interaction.guild!.id); + + if (!player) { + return interaction.editReply({ content: 'āŒ | There is no music currently playing.', allowedMentions: { repliedUser: false } }); + } + + const str = interaction.options.getString("seek"); + const tragetTime = timeToSeconds(str!); + + if (!tragetTime) { + return interaction.editReply({ content: `āŒ | Invalid format for the target time.\n(**\`ex: 3m20s, 1m 50s, 1:20:55, 5:20\`**)`, allowedMentions: { repliedUser: false } }); + } + + const tragetTimeMs = tragetTime * 1000; + + await player.seek(tragetTimeMs); + + if(tragetTimeMs >= player.current!.duration.value){ + return interaction.editReply({ content: `āœ… | The seek position is beyond the duration of this track. (\`${player.current!.duration.label}\`)\nSkipping to the next song.`, allowedMentions: { repliedUser: false } }); + } + else{ + return interaction.editReply({ content: `āœ… | Music has been seeked to \`${str}\`.`, allowedMentions: { repliedUser: false } }); + } + +} \ No newline at end of file diff --git a/src/utils/functions/timeToSeconds.ts b/src/utils/functions/timeToSeconds.ts new file mode 100644 index 0000000..18914ca --- /dev/null +++ b/src/utils/functions/timeToSeconds.ts @@ -0,0 +1,61 @@ +const timeToSeconds = (time: string) => { + const timeString = time.toLowerCase(); + let hours = 0, + minutes = 0, + seconds = 0; + + // Check if the timeString consists only of digits + if (/^\d+$/.test(timeString)) { + seconds = parseInt(timeString); + } + + // Check if the timeString is in the format "m:s" or "h:m:s" + else if (/^\d+:\d+(\:\d+)?$/.test(timeString)) { + const timeParts = timeString.split(":"); + const numParts = timeParts.length; + + if (numParts === 2) { + minutes = parseInt(timeParts[0]); + seconds = parseInt(timeParts[1]); + } else if (numParts === 3) { + hours = parseInt(timeParts[0]); + minutes = parseInt(timeParts[1]); + seconds = parseInt(timeParts[2]); + } + } + + // Otherwise, parse the timeString into hours, minutes, and seconds + else { + const regex = /(\d+)\s*(h|m|s)/g; + let match; + let valid = false; // Flag to track if any valid match is found + + while ((match = regex.exec(timeString)) !== null) { + const value = parseInt(match[1]); + + if (match[2] === 'h') { + hours = value; + valid = true; + } + else if (match[2] === 'm') { + minutes = value; + valid = true; + } + else if (match[2] === 's') { + seconds = value; + valid = true; + } + } + + // If no valid match is found, return false + if (!valid) { + return false; + } + } + + + const totalSeconds = hours * 3600 + minutes * 60 + seconds; + return totalSeconds; +} + +export { timeToSeconds }; \ No newline at end of file From 137ea2b457a4ae45f2ab267ca5c1e2c505f85ede Mon Sep 17 00:00:00 2001 From: hmes98318 <52697423+hmes98318@users.noreply.github.com> Date: Thu, 6 Jul 2023 23:05:06 +0800 Subject: [PATCH 24/64] Add `shuffle` command --- src/commands/shuffle.ts | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 src/commands/shuffle.ts diff --git a/src/commands/shuffle.ts b/src/commands/shuffle.ts new file mode 100644 index 0000000..086091b --- /dev/null +++ b/src/commands/shuffle.ts @@ -0,0 +1,33 @@ +import { ChatInputCommandInteraction, Client, Message } from "discord.js"; + + +export const name = 'shuffle'; +export const aliases = ['random']; +export const description = 'Shuffle Playlist'; +export const usage = 'shuffle'; +export const voiceChannel = true; +export const showHelp = true; +export const options = []; + + +export const execute = async (client: Client, message: Message) => { + const player = client.lavashark.getPlayer(message.guild!.id); + + if (!player) { + return message.reply({ content: 'āŒ | There is no music currently playing.', allowedMentions: { repliedUser: false } }); + } + + player.queue.shuffle(); + return message.react('šŸ‘'); +} + +export const slashExecute = async (client: Client, interaction: ChatInputCommandInteraction) => { + const player = client.lavashark.getPlayer(interaction.guild!.id); + + if (!player) { + return interaction.editReply({ content: 'āŒ | There is no music currently playing.', allowedMentions: { repliedUser: false } }); + } + + player.queue.shuffle(); + return interaction.editReply('āœ… | Music shuffled.'); +} \ No newline at end of file From 2571df56fcadf95877d82c30ac8d31108dcbafbc Mon Sep 17 00:00:00 2001 From: hmes98318 <52697423+hmes98318@users.noreply.github.com> Date: Fri, 7 Jul 2023 22:59:24 +0800 Subject: [PATCH 25/64] Add default volume --- src/commands/play.ts | 3 +++ src/commands/search.ts | 2 ++ 2 files changed, 5 insertions(+) diff --git a/src/commands/play.ts b/src/commands/play.ts index 0e8a665..a854b5c 100644 --- a/src/commands/play.ts +++ b/src/commands/play.ts @@ -72,6 +72,7 @@ export const execute = async (client: Client, message: Message, args: string[]) return message.reply({ content: `āŒ | I can't play this track.`, allowedMentions: { repliedUser: false } }); }); + player.filters.setVolume(client.config.defaultVolume); return message.react('šŸ‘'); } @@ -128,4 +129,6 @@ export const slashExecute = async (client: Client, interaction: ChatInputCommand console.log(error); return interaction.editReply({ content: `āŒ | I can't play this track.`, allowedMentions: { repliedUser: false } }); }); + + return player.filters.setVolume(client.config.defaultVolume); } \ No newline at end of file diff --git a/src/commands/search.ts b/src/commands/search.ts index e1cd08b..9cefcb9 100644 --- a/src/commands/search.ts +++ b/src/commands/search.ts @@ -102,6 +102,7 @@ export const execute = async (client: Client, message: Message, args: string[]) return message.reply({ content: `āŒ | I can't play this track.`, allowedMentions: { repliedUser: false } }); }); + player.filters.setVolume(client.config.defaultVolume); i.deferUpdate(); await msg.edit({ content: "āœ… | Music added.", components: [], allowedMentions: { repliedUser: false } }); }); @@ -186,6 +187,7 @@ export const slashExecute = async (client: Client, interaction: ChatInputCommand return interaction.editReply({ content: `āŒ | I can't play this track.`, allowedMentions: { repliedUser: false } }); }); + player.filters.setVolume(client.config.defaultVolume); i.deferUpdate(); await msg.edit({ content: "āœ… | Music added.", components: [], allowedMentions: { repliedUser: false } }); }); From 6aa734f03e5b68813180811c00eaf3897eb84478 Mon Sep 17 00:00:00 2001 From: hmes98318 <52697423+hmes98318@users.noreply.github.com> Date: Fri, 7 Jul 2023 23:23:53 +0800 Subject: [PATCH 26/64] Fix `search` command can't directly play links --- src/commands/search.ts | 44 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/src/commands/search.ts b/src/commands/search.ts index 9cefcb9..147e883 100644 --- a/src/commands/search.ts +++ b/src/commands/search.ts @@ -70,6 +70,28 @@ export const execute = async (client: Client, message: Message, args: string[]) player.queue.add(track); } + if (!player.playing) await player.play() + .catch((error: any) => { + console.log(error); + return message.reply({ content: `āŒ | I can't play this track.`, allowedMentions: { repliedUser: false } }); + }); + + player.filters.setVolume(client.config.defaultVolume); + return message.reply({ content: "āœ… | Music added.", allowedMentions: { repliedUser: false } }); + } + else if (res.tracks.length === 1) { + const track = res.tracks[0]; + track.setRequester(client.user); + + player.queue.add(track); + + if (!player.playing) await player.play() + .catch((error: any) => { + console.log(error); + return message.reply({ content: `āŒ | I can't play this track.`, allowedMentions: { repliedUser: false } }); + }); + + player.filters.setVolume(client.config.defaultVolume); return message.reply({ content: "āœ… | Music added.", allowedMentions: { repliedUser: false } }); } else { @@ -155,6 +177,28 @@ export const slashExecute = async (client: Client, interaction: ChatInputCommand player.queue.add(track); } + if (!player.playing) await player.play() + .catch((error: any) => { + console.log(error); + return interaction.reply({ content: `āŒ | I can't play this track.`, allowedMentions: { repliedUser: false } }); + }); + + player.filters.setVolume(client.config.defaultVolume); + return interaction.editReply({ content: "āœ… | Music added.", allowedMentions: { repliedUser: false } }); + } + else if (res.tracks.length === 1) { + const track = res.tracks[0]; + track.setRequester(client.user); + + player.queue.add(track); + + if (!player.playing) await player.play() + .catch((error: any) => { + console.log(error); + return interaction.reply({ content: `āŒ | I can't play this track.`, allowedMentions: { repliedUser: false } }); + }); + + player.filters.setVolume(client.config.defaultVolume); return interaction.editReply({ content: "āœ… | Music added.", allowedMentions: { repliedUser: false } }); } else { From 2826be8bef3d67d6679fc5d14aa39f44906895d7 Mon Sep 17 00:00:00 2001 From: hmes98318 <52697423+hmes98318@users.noreply.github.com> Date: Sat, 8 Jul 2023 00:25:50 +0800 Subject: [PATCH 27/64] Add `remove` command --- src/commands/remove.ts | 233 +++++++++++++++++++++++++++++++++++++++++ src/embeds/index.ts | 5 +- src/embeds/remove.ts | 25 +++++ 3 files changed, 262 insertions(+), 1 deletion(-) create mode 100644 src/commands/remove.ts create mode 100644 src/embeds/remove.ts diff --git a/src/commands/remove.ts b/src/commands/remove.ts new file mode 100644 index 0000000..cf5cc40 --- /dev/null +++ b/src/commands/remove.ts @@ -0,0 +1,233 @@ +import { ChatInputCommandInteraction, Client, Collection, Message } from "discord.js"; +import { embeds } from "../embeds"; + + +export const name = 'remove'; +export const aliases = ['rm']; +export const description = 'Select a song to remove from the playlist'; +export const usage = 'remove [from index to index 2 track]'; +export const voiceChannel = true; +export const showHelp = true; +export const options = [ + { + name: "index", + description: "track index number", + type: 10, + required: false + }, + { + name: "index2", + description: "from index to index 2 track", + type: 10, + required: false + } +]; + + +export const execute = async (client: Client, message: Message, args: string[]) => { + const player = client.lavashark.getPlayer(message.guild!.id); + + if (!player) { + return message.reply({ content: 'āŒ | There is no music currently playing.', allowedMentions: { repliedUser: false } }); + } + + const tracks = player.queue.tracks.map((track, index) => { return `${++index}. \`${track.title}\`` }); + + if (tracks.length < 1) { + return message.reply({ content: `āŒ | No music in queue after current.`, allowedMentions: { repliedUser: false } }); + } + + let SUCCESS = false; + + if (args.length === 1) { // +rm 1 + let index = parseInt(args[0]); + SUCCESS = player.queue.remove(index); + + if (!SUCCESS) { + return message.react('āŒ'); + } + else { + await message.react('šŸ‘'); + return message.reply({ + embeds: [embeds.removeTrack(client.config.embedsColor, tracks[index - 1])], + allowedMentions: { repliedUser: false } + }); + } + } + else if (args.length === 2) { // +rm 3 4 + let index1 = parseInt(args[0]), + index2 = parseInt(args[1]); + SUCCESS = player.queue.remove(index1, index2); + + if (!SUCCESS) { + return message.react('āŒ'); + } + else { + const musicTitle = tracks.slice(index1 - 1, index2).join('\n'); + await message.react('šŸ‘'); + return message.reply({ + embeds: [embeds.removeTrack(client.config.embedsColor, musicTitle)], + allowedMentions: { repliedUser: false } + }); + } + } + else if (args.length < 1) { // +rm + let nowplaying = `Now Playing : ${player.current?.title}\n\n`; + let tracksQueue = ''; + + if (tracks.length < 1) { + tracksQueue = '------------------------------'; + } + else if (tracks.length > 9) { + tracksQueue = tracks.slice(0, 10).join('\n'); + tracksQueue += `\nand ${tracks.length - 10} other songs`; + } + else { + tracksQueue = tracks.join('\n'); + } + + let repeatMode = player.queueRepeat ? 'All' : (player.trackRepeat ? 'One' : 'Off'); + const instruction = `Choose a song from **1** to **${tracks.length}** to **remove** or enter others to cancel selection. ā¬‡ļø`; + + await message.react('šŸ‘'); + await message.reply({ + content: instruction, + embeds: [embeds.removeList(client.config.embedsColor, nowplaying, tracksQueue, repeatMode)], + allowedMentions: { repliedUser: false } + }); + + + const collector = message.channel.createMessageCollector({ + time: 10000, // 10s + filter: m => m.author.id === message.author.id + }); + + collector.on('collect', async (query: Message) => { + + const index = parseInt(query.content); + + if (!index || index <= 0 || index > tracks.length) { + await message.reply({ content: `āœ… | Cancelled remove.`, allowedMentions: { repliedUser: false } }); + return collector.stop(); + } + + await query.react('šŸ‘'); + player.queue.remove(index); + + await query.reply({ + embeds: [embeds.removeTrack(client.config.embedsColor, tracks[index - 1])], + allowedMentions: { repliedUser: false } + }); + return collector.stop(); + }); + + collector.on('end', async (_msg: Collection>, reason: string) => { + if (reason === 'time') { + await message.reply({ content: `āŒ | Song remove time expired`, allowedMentions: { repliedUser: false } }); + } + }); + } +} + +export const slashExecute = async (client: Client, interaction: ChatInputCommandInteraction) => { + const player = client.lavashark.getPlayer(interaction.guild!.id); + + if (!player) { + return interaction.editReply({ content: 'āŒ | There is no music currently playing.', allowedMentions: { repliedUser: false } }); + } + + const tracks = player.queue.tracks.map((track, index) => { return `${++index}. \`${track.title}\`` }); + + if (tracks.length < 1) { + return interaction.editReply({ content: `āŒ | No music in queue after current.`, allowedMentions: { repliedUser: false } }); + } + + const index1 = interaction.options.getNumber('index'); + const index2 = interaction.options.getNumber('index2'); + let SUCCESS = false; + + if ((index1 === null && index2 !== null) || (index1 !== null && index2 === null)) { // +rm 1 + let index = index1 || index2; + SUCCESS = player.queue.remove(index!); + + if (!SUCCESS) { + return interaction.editReply('āŒ | Music remove failed.'); + } + else { + return interaction.editReply({ + embeds: [embeds.removeTrack(client.config.embedsColor, tracks[index! - 1])], + allowedMentions: { repliedUser: false } + }); + } + } + else if (index1 !== null && index2 !== null) { // +rm 3 4 + SUCCESS = player.queue.remove(index1, index2); + + if (!SUCCESS) { + return interaction.editReply('āŒ | Music remove failed.'); + } + else { + const musicTitle = tracks.slice(index1 - 1, index2).join('\n'); + return interaction.editReply({ + embeds: [embeds.removeTrack(client.config.embedsColor, musicTitle)], + allowedMentions: { repliedUser: false } + }); + } + } + else if (index1 === null && index2 === null) { // +rm + let nowplaying = `Now Playing : ${player.current?.title}\n\n`; + let tracksQueue = ''; + + if (tracks.length < 1) { + tracksQueue = '------------------------------'; + } + else if (tracks.length > 9) { + tracksQueue = tracks.slice(0, 10).join('\n'); + tracksQueue += `\nand ${tracks.length - 10} other songs`; + } + else { + tracksQueue = tracks.join('\n'); + } + + let repeatMode = player.queueRepeat ? 'All' : (player.trackRepeat ? 'One' : 'Off'); + const instruction = `Choose a song from **1** to **${tracks.length}** to **remove** or enter others to cancel selection. ā¬‡ļø`; + + await interaction.editReply({ + content: instruction, + embeds: [embeds.removeList(client.config.embedsColor, nowplaying, tracksQueue, repeatMode)], + allowedMentions: { repliedUser: false } + }); + + + const collector = interaction.channel!.createMessageCollector({ + time: 10000, // 10s + filter: m => m.author.id === interaction.user.id + }); + + collector.on('collect', async (query: Message) => { + + const index = parseInt(query.content); + + if (!index || index <= 0 || index > tracks.length) { + await interaction.editReply({ content: `āœ… | Cancelled remove.`, allowedMentions: { repliedUser: false } }); + return collector.stop(); + } + + await query.react('šŸ‘'); + player.queue.remove(index); + + await query.reply({ + embeds: [embeds.removeTrack(client.config.embedsColor, tracks[index - 1])], + allowedMentions: { repliedUser: false } + }); + return collector.stop(); + }); + + collector.on('end', async (_msg: Collection>, reason: string) => { + if (reason === 'time') { + await interaction.editReply({ content: `āŒ | Song remove time expired`, allowedMentions: { repliedUser: false } }); + } + }); + } + +} \ No newline at end of file diff --git a/src/embeds/index.ts b/src/embeds/index.ts index 70f535a..ba3547b 100644 --- a/src/embeds/index.ts +++ b/src/embeds/index.ts @@ -1,10 +1,13 @@ import { status } from "./status"; import { queue } from "./queue"; +import { removeList, removeTrack } from "./remove"; const embeds = { status, - queue + queue, + removeList, + removeTrack } export { embeds }; \ No newline at end of file diff --git a/src/embeds/remove.ts b/src/embeds/remove.ts new file mode 100644 index 0000000..1f2c5ef --- /dev/null +++ b/src/embeds/remove.ts @@ -0,0 +1,25 @@ +import { EmbedBuilder, HexColorString } from "discord.js"; + + +const removeList = (embedsColor: HexColorString | string | number, nowPlaying: string, queueList: string, repeatMode: string) => { + + const embed_ = new EmbedBuilder() + .setColor(embedsColor as HexColorString | number) + .setTitle('Remove List') + .addFields({ name: nowPlaying, value: queueList }) + .setTimestamp() + .setFooter({ text: `Loop: ${repeatMode}` }); + return embed_; +} + +const removeTrack = (embedsColor: HexColorString | string | number, musicTitle: string) => { + + const embed_ = new EmbedBuilder() + .setColor(embedsColor as HexColorString | number) + .setTitle('Removed Music') + .setDescription(musicTitle) + .setTimestamp() + return embed_; +} + +export { removeList, removeTrack }; \ No newline at end of file From 2a09b7226993af13aba53a29b9804b7622742e73 Mon Sep 17 00:00:00 2001 From: hmes98318 <52697423+hmes98318@users.noreply.github.com> Date: Sat, 8 Jul 2023 00:27:37 +0800 Subject: [PATCH 28/64] Update constants variables --- src/utils/constants.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/utils/constants.ts b/src/utils/constants.ts index 5339b74..eb294ca 100644 --- a/src/utils/constants.ts +++ b/src/utils/constants.ts @@ -7,6 +7,7 @@ export const cst = { name : 'Music Disc', prefix : '+', playing : '+help | music', + embedsColor : '#FFFFFF', defaultVolume : 50, maxVolume : 100, autoLeave : true, From 3278f514452c06fa4e1ebcf5381c002f0371a7ee Mon Sep 17 00:00:00 2001 From: hmes98318 <52697423+hmes98318@users.noreply.github.com> Date: Sat, 8 Jul 2023 00:41:58 +0800 Subject: [PATCH 29/64] Add env loader --- src/index.ts | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/index.ts b/src/index.ts index b3083a9..81cb140 100644 --- a/src/index.ts +++ b/src/index.ts @@ -46,6 +46,23 @@ client.config = cst.config; +const setEnvironment = (): Promise => { + return new Promise((resolve, _reject) => { + client.config.name = process.env.BOT_NAME ?? client.config.name; + client.config.prefix = process.env.PREFIX ?? client.config.prefix; + client.config.playing = process.env.PLAYING ?? client.config.playing; + client.config.defaultVolume = Number(process.env.DEFAULT_VOLUME) ?? client.config.defaultVolume; + client.config.maxVolume = Number(process.env.MAX_VOLUME) ?? client.config.maxVolume; + client.config.autoLeave = process.env.AUTO_LEAVE === 'true' ?? client.config.autoLeave; + client.config.autoLeaveCooldown = Number(process.env.AUTO_LEAVE_COOLDOWN) ?? client.config.autoLeaveCooldown; + client.config.displayVoiceState = process.env.DISPLAY_VOICE_STATE === 'true' ?? client.config.displayVoiceState; + client.config.port = Number(process.env.PORT) ?? client.config.port; + + // console.log('setEnvironment: ', client.config); + resolve(); + }); +}; + const loadEvents = () => { console.log(`-> loading Events ......`); return new Promise(async (resolve, reject) => { @@ -94,6 +111,7 @@ const loadCommands = () => { Promise.resolve() + .then(() => setEnvironment()) .then(() => loadEvents()) .then(() => loadCommands()) .then(() => { From 7e00bddaf6781cdeee304fdacfedc325430e9320 Mon Sep 17 00:00:00 2001 From: hmes98318 <52697423+hmes98318@users.noreply.github.com> Date: Sat, 8 Jul 2023 19:06:12 +0800 Subject: [PATCH 30/64] Add `help` command --- src/commands/help.ts | 171 +++++++++++++++++++++++++++++++++++++++++++ src/embeds/help.ts | 13 ++++ src/embeds/index.ts | 4 +- 3 files changed, 187 insertions(+), 1 deletion(-) create mode 100644 src/commands/help.ts create mode 100644 src/embeds/help.ts diff --git a/src/commands/help.ts b/src/commands/help.ts new file mode 100644 index 0000000..c2f8fe2 --- /dev/null +++ b/src/commands/help.ts @@ -0,0 +1,171 @@ +import { + ActionRowBuilder, + ButtonInteraction, + ChatInputCommandInteraction, + Client, + Collection, + Message, + StringSelectMenuBuilder, + StringSelectMenuInteraction +} from "discord.js"; +import { embeds } from "../embeds"; + + +export const name = 'help'; +export const aliases = ['h']; +export const description = 'Get commands help'; +export const usage = 'help [command]'; +export const voiceChannel = false; +export const showHelp = true; +export const options = [ + { + name: "command", + description: "which command need help", + type: 3, + required: false + } +]; + + +export const execute = async (client: Client, message: Message, args: string[]) => { + const prefix = client.config.prefix; + + if (!args[0]) { + let title = client.user?.username; + const commands = client.commands.filter(x => x.showHelp !== false); + + let select = new StringSelectMenuBuilder() + .setCustomId("helpSelect") + .setPlaceholder("Select the help") + .setOptions(commands.map(x => { + return { + label: x.name, + description: `Aliases: ${x.aliases[0] ? x.aliases.map((y: string) => y).join(', ') : x.name}`, + value: x.name + } + })); + let row = new ActionRowBuilder().addComponents(select); + let msg = await message.reply({ + content: 'Choose a command to get help. ā¬‡ļø', + components: [row.toJSON()], + allowedMentions: { repliedUser: false } + }); + + const collector = msg.createMessageComponentCollector({ + time: 20000, // 20s + filter: i => i.user.id === message.author.id + }); + + collector.on("collect", async (i: StringSelectMenuInteraction) => { + if (i.customId != "helpSelect") return; + + const cmd = commands.find(x => x.name === i.values[0]); + const usage = `${cmd.description}\n\`\`\`${prefix}${cmd.usage}\`\`\``; + + i.deferUpdate(); + await msg.edit({ + embeds: [embeds.help(client.config.embedsColor, title!, usage)], + components: [], + allowedMentions: { repliedUser: false } + }); + }); + + collector.on("end", async (collected: Collection, reason: string) => { + if (reason == "time" && collected.size == 0) { + await msg.edit({ content: "āŒ | Time expired.", components: [], allowedMentions: { repliedUser: false } }); + } + }); + } + else { + const helpCmd = args[0]; + const commands = client.commands.filter(x => x.showHelp !== false); + + let found = false; + found = commands.find(x => { + if (helpCmd === x.name || x.aliases.includes(helpCmd)) { + let command = x.name + let description = `${x.description}\n\`\`\`${prefix}${x.usage}\`\`\``; + + message.reply({ + embeds: [embeds.help(client.config.embedsColor, command, description)], + allowedMentions: { repliedUser: false } + }); + return true; + } + }); + + if (!Boolean(found)) return message.reply({ content: 'āŒ | The command not found.', allowedMentions: { repliedUser: false } }); + } +} + +export const slashExecute = async (client: Client, interaction: ChatInputCommandInteraction) => { + const prefix = client.config.prefix; + const command = interaction.options.getString("command"); + + if (!command) { + let title = client.user?.username; + const commands = client.commands.filter(x => x.showHelp !== false); + + let select = new StringSelectMenuBuilder() + .setCustomId("helpSelect") + .setPlaceholder("Select the help") + .setOptions(commands.map(x => { + return { + label: x.name, + description: `Aliases: ${x.aliases[0] ? x.aliases.map((y: string) => y).join(', ') : x.name}`, + value: x.name + } + })); + let row = new ActionRowBuilder().addComponents(select); + let msg = await interaction.editReply({ + content: 'Choose a command to get help. ā¬‡ļø', + components: [row.toJSON()], + allowedMentions: { repliedUser: false } + }); + + const collector = msg.createMessageComponentCollector({ + time: 20000, // 20s + filter: i => i.user.id === interaction.user.id + }); + + collector.on("collect", async (i: StringSelectMenuInteraction) => { + if (i.customId != "helpSelect") return; + + const cmd = commands.find(x => x.name === i.values[0]); + const usage = `${cmd.description}\n\`\`\`${prefix}${cmd.usage}\`\`\``; + + i.deferUpdate(); + await msg.edit({ + embeds: [embeds.help(client.config.embedsColor, title!, usage)], + components: [], + allowedMentions: { repliedUser: false } + }); + }); + + collector.on("end", async (collected: Collection, reason: string) => { + if (reason == "time" && collected.size == 0) { + await msg.edit({ content: "āŒ | Time expired.", components: [], allowedMentions: { repliedUser: false } }); + } + }); + } + else { + const helpCmd = command; + const commands = client.commands.filter(x => x.showHelp !== false); + + let found = false; + found = commands.find(x => { + if (helpCmd === x.name || x.aliases.includes(helpCmd)) { + let command = x.name + let description = `${x.description}\n\`\`\`${prefix}${x.usage}\`\`\``; + + interaction.editReply({ + embeds: [embeds.help(client.config.embedsColor, command, description)], + allowedMentions: { repliedUser: false } + }); + return true; + } + }); + + if (!Boolean(found)) return interaction.editReply({ content: 'āŒ | The command not found.', allowedMentions: { repliedUser: false } }); + } +} \ No newline at end of file diff --git a/src/embeds/help.ts b/src/embeds/help.ts new file mode 100644 index 0000000..f64b3a2 --- /dev/null +++ b/src/embeds/help.ts @@ -0,0 +1,13 @@ +import { EmbedBuilder, HexColorString } from "discord.js"; + + +const help = (embedsColor: HexColorString | string | number, command: string, description: string) => { + + const embed_ = new EmbedBuilder() + .setColor(embedsColor as HexColorString | number) + .setTitle(`Command **${command}**`) + .setDescription(description) + return embed_; +} + +export { help }; \ No newline at end of file diff --git a/src/embeds/index.ts b/src/embeds/index.ts index ba3547b..7246942 100644 --- a/src/embeds/index.ts +++ b/src/embeds/index.ts @@ -1,13 +1,15 @@ import { status } from "./status"; import { queue } from "./queue"; import { removeList, removeTrack } from "./remove"; +import { help } from "./help"; const embeds = { status, queue, removeList, - removeTrack + removeTrack, + help } export { embeds }; \ No newline at end of file From c1fb3c7cc13728d72ebcbdf1f72a51aa2a33c249 Mon Sep 17 00:00:00 2001 From: hmes98318 <52697423+hmes98318@users.noreply.github.com> Date: Sat, 8 Jul 2023 19:13:15 +0800 Subject: [PATCH 31/64] Formatting files --- src/embeds/help.ts | 8 ++++---- src/embeds/queue.ts | 12 ++++++------ src/embeds/remove.ts | 22 +++++++++++----------- src/embeds/status.ts | 3 ++- 4 files changed, 23 insertions(+), 22 deletions(-) diff --git a/src/embeds/help.ts b/src/embeds/help.ts index f64b3a2..e155b88 100644 --- a/src/embeds/help.ts +++ b/src/embeds/help.ts @@ -2,11 +2,11 @@ import { EmbedBuilder, HexColorString } from "discord.js"; const help = (embedsColor: HexColorString | string | number, command: string, description: string) => { - const embed_ = new EmbedBuilder() - .setColor(embedsColor as HexColorString | number) - .setTitle(`Command **${command}**`) - .setDescription(description) + .setColor(embedsColor as HexColorString | number) + .setTitle(`Command **${command}**`) + .setDescription(description) + return embed_; } diff --git a/src/embeds/queue.ts b/src/embeds/queue.ts index 8ca671f..7a297c2 100644 --- a/src/embeds/queue.ts +++ b/src/embeds/queue.ts @@ -2,13 +2,13 @@ import { EmbedBuilder, HexColorString } from "discord.js"; const queue = (embedsColor: HexColorString | string | number, nowPlaying: string, queueList: string, repeatMode: string) => { - const embed_ = new EmbedBuilder() - .setColor(embedsColor as HexColorString | number) - .setTitle('Queue List') - .addFields({ name: nowPlaying, value: queueList }) - .setTimestamp() - .setFooter({ text: `Loop: ${repeatMode}` }); + .setColor(embedsColor as HexColorString | number) + .setTitle('Queue List') + .addFields({ name: nowPlaying, value: queueList }) + .setTimestamp() + .setFooter({ text: `Loop: ${repeatMode}` }); + return embed_; } diff --git a/src/embeds/remove.ts b/src/embeds/remove.ts index 1f2c5ef..1d2ef08 100644 --- a/src/embeds/remove.ts +++ b/src/embeds/remove.ts @@ -2,23 +2,23 @@ import { EmbedBuilder, HexColorString } from "discord.js"; const removeList = (embedsColor: HexColorString | string | number, nowPlaying: string, queueList: string, repeatMode: string) => { - const embed_ = new EmbedBuilder() - .setColor(embedsColor as HexColorString | number) - .setTitle('Remove List') - .addFields({ name: nowPlaying, value: queueList }) - .setTimestamp() - .setFooter({ text: `Loop: ${repeatMode}` }); + .setColor(embedsColor as HexColorString | number) + .setTitle('Remove List') + .addFields({ name: nowPlaying, value: queueList }) + .setTimestamp() + .setFooter({ text: `Loop: ${repeatMode}` }); + return embed_; } const removeTrack = (embedsColor: HexColorString | string | number, musicTitle: string) => { - const embed_ = new EmbedBuilder() - .setColor(embedsColor as HexColorString | number) - .setTitle('Removed Music') - .setDescription(musicTitle) - .setTimestamp() + .setColor(embedsColor as HexColorString | number) + .setTitle('Removed Music') + .setDescription(musicTitle) + .setTimestamp(); + return embed_; } diff --git a/src/embeds/status.ts b/src/embeds/status.ts index 4655223..4655333 100644 --- a/src/embeds/status.ts +++ b/src/embeds/status.ts @@ -17,7 +17,8 @@ const status = (config: Config, info: Info, systemStatus: SystemStatus) => { { name: `šŸ“Š USAGE`, value: `CPU : **${cpuUsage}**\nRam : **${ramUsage}**\nHeap : **${heapUsage}**\nā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”`, inline: false }, { name: `šŸ›°ļø LATENCY`, value: `Bot : **${systemStatus.ping.bot}**\nAPI : **${systemStatus.ping.api}ms**`, inline: false } ) - .setTimestamp() + .setTimestamp(); + return embed_; } From 728ff8a115fefa06d842e4c7f8daa3206ca2930e Mon Sep 17 00:00:00 2001 From: hmes98318 <52697423+hmes98318@users.noreply.github.com> Date: Sat, 8 Jul 2023 19:31:32 +0800 Subject: [PATCH 32/64] Add check whether to send sendTyping status --- src/commands/help.ts | 1 + src/commands/leave.ts | 1 + src/commands/loop.ts | 1 + src/commands/pause.ts | 1 + src/commands/play.ts | 1 + src/commands/queue.ts | 1 + src/commands/remove.ts | 1 + src/commands/resmue.ts | 1 + src/commands/search.ts | 1 + src/commands/seek.ts | 1 + src/commands/shuffle.ts | 1 + src/commands/skip.ts | 1 + src/commands/status.ts | 1 + src/commands/volume.ts | 1 + src/events/messageCreate.ts | 3 ++- 15 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/commands/help.ts b/src/commands/help.ts index c2f8fe2..a7ee0cd 100644 --- a/src/commands/help.ts +++ b/src/commands/help.ts @@ -17,6 +17,7 @@ export const description = 'Get commands help'; export const usage = 'help [command]'; export const voiceChannel = false; export const showHelp = true; +export const sendTyping = true; export const options = [ { name: "command", diff --git a/src/commands/leave.ts b/src/commands/leave.ts index fa6e329..8685860 100644 --- a/src/commands/leave.ts +++ b/src/commands/leave.ts @@ -7,6 +7,7 @@ export const description = 'Leave current voice channel'; export const usage = 'leave'; export const voiceChannel = true; export const showHelp = true; +export const sendTyping = false; export const options = []; diff --git a/src/commands/loop.ts b/src/commands/loop.ts index f5aa775..a959cbd 100644 --- a/src/commands/loop.ts +++ b/src/commands/loop.ts @@ -8,6 +8,7 @@ export const description = 'Turns the music loop mode on or off'; export const usage = 'loop '; export const voiceChannel = true; export const showHelp = true; +export const sendTyping = true; export const options = [ { name: "mode", diff --git a/src/commands/pause.ts b/src/commands/pause.ts index a0fd9d8..87cf085 100644 --- a/src/commands/pause.ts +++ b/src/commands/pause.ts @@ -7,6 +7,7 @@ export const description = 'Pause current track'; export const usage = 'pause'; export const voiceChannel = true; export const showHelp = true; +export const sendTyping = false; export const options = []; diff --git a/src/commands/play.ts b/src/commands/play.ts index a854b5c..e639897 100644 --- a/src/commands/play.ts +++ b/src/commands/play.ts @@ -6,6 +6,7 @@ export const description = 'Enter your song link or song name to play'; export const usage = 'play '; export const voiceChannel = true; export const showHelp = true; +export const sendTyping = true; export const options = [ { name: "play", diff --git a/src/commands/queue.ts b/src/commands/queue.ts index d669490..90e6e35 100644 --- a/src/commands/queue.ts +++ b/src/commands/queue.ts @@ -8,6 +8,7 @@ export const description = 'Show currnet playlist'; export const usage = 'queue'; export const voiceChannel = true; export const showHelp = true; +export const sendTyping = true; export const options = []; diff --git a/src/commands/remove.ts b/src/commands/remove.ts index cf5cc40..534dff9 100644 --- a/src/commands/remove.ts +++ b/src/commands/remove.ts @@ -8,6 +8,7 @@ export const description = 'Select a song to remove from the playlist'; export const usage = 'remove [from index to index 2 track]'; export const voiceChannel = true; export const showHelp = true; +export const sendTyping = true; export const options = [ { name: "index", diff --git a/src/commands/resmue.ts b/src/commands/resmue.ts index b888c21..34a620c 100644 --- a/src/commands/resmue.ts +++ b/src/commands/resmue.ts @@ -7,6 +7,7 @@ export const description = 'Resume paused track'; export const usage = 'resume'; export const voiceChannel = true; export const showHelp = true; +export const sendTyping = false; export const options = []; diff --git a/src/commands/search.ts b/src/commands/search.ts index 147e883..6b753bf 100644 --- a/src/commands/search.ts +++ b/src/commands/search.ts @@ -17,6 +17,7 @@ export const description = 'Enter song name to search'; export const usage = 'search '; export const voiceChannel = true; export const showHelp = true; +export const sendTyping = true; export const options = [ { name: "search", diff --git a/src/commands/seek.ts b/src/commands/seek.ts index d84b491..c5655c2 100644 --- a/src/commands/seek.ts +++ b/src/commands/seek.ts @@ -8,6 +8,7 @@ export const description = 'Seeks to a certain time in the track'; export const usage = 'seek <[hh]mm]ss/[hh:mm]:ss> (ex: 3m20s, 1:20:55)'; export const voiceChannel = true; export const showHelp = true; +export const sendTyping = true; export const options = [ { name: "seek", diff --git a/src/commands/shuffle.ts b/src/commands/shuffle.ts index 086091b..5277ff7 100644 --- a/src/commands/shuffle.ts +++ b/src/commands/shuffle.ts @@ -7,6 +7,7 @@ export const description = 'Shuffle Playlist'; export const usage = 'shuffle'; export const voiceChannel = true; export const showHelp = true; +export const sendTyping = false; export const options = []; diff --git a/src/commands/skip.ts b/src/commands/skip.ts index 9de3eb2..b3295b5 100644 --- a/src/commands/skip.ts +++ b/src/commands/skip.ts @@ -7,6 +7,7 @@ export const description = 'Skip currnet track'; export const usage = 'skip'; export const voiceChannel = true; export const showHelp = true; +export const sendTyping = false; export const options = []; diff --git a/src/commands/status.ts b/src/commands/status.ts index 03d6252..789a82f 100644 --- a/src/commands/status.ts +++ b/src/commands/status.ts @@ -10,6 +10,7 @@ export const description = 'Show the bot status'; export const usage = 'status'; export const voiceChannel = false; export const showHelp = true; +export const sendTyping = true; export const options = []; diff --git a/src/commands/volume.ts b/src/commands/volume.ts index e7841f7..ae59548 100644 --- a/src/commands/volume.ts +++ b/src/commands/volume.ts @@ -7,6 +7,7 @@ export const description = 'Configure bot volume'; export const usage = 'v <0-100>'; export const voiceChannel = true; export const showHelp = true; +export const sendTyping = true; export const options = [ { name: "volume", diff --git a/src/events/messageCreate.ts b/src/events/messageCreate.ts index f1add5a..e655f4c 100644 --- a/src/events/messageCreate.ts +++ b/src/events/messageCreate.ts @@ -23,7 +23,8 @@ export default async (client: Client, message: Message) => { if (cmd) { console.log(`(${cst.color.grey}${message.guild?.name}${cst.color.white}) ${message.author.username} : ${message.content}`); - message.channel.sendTyping(); + + if (cmd.sendTyping) message.channel.sendTyping(); cmd.execute(client, message, args); } }; \ No newline at end of file From 0eacb5d078e218aff8dc8881a5fcb923897ee711 Mon Sep 17 00:00:00 2001 From: hmes98318 <52697423+hmes98318@users.noreply.github.com> Date: Sat, 8 Jul 2023 22:54:46 +0800 Subject: [PATCH 33/64] Add `server` command --- src/commands/server.ts | 35 +++++++++++++++++++++++++++++++++++ src/embeds/index.ts | 4 +++- src/embeds/server.ts | 14 ++++++++++++++ 3 files changed, 52 insertions(+), 1 deletion(-) create mode 100644 src/commands/server.ts create mode 100644 src/embeds/server.ts diff --git a/src/commands/server.ts b/src/commands/server.ts new file mode 100644 index 0000000..bba05a7 --- /dev/null +++ b/src/commands/server.ts @@ -0,0 +1,35 @@ +import { ChatInputCommandInteraction, Client, Message } from "discord.js"; +import { embeds } from "../embeds"; + + +export const name = 'server'; +export const aliases = []; +export const description = 'Show currently active servers'; +export const usage = 'server'; +export const voiceChannel = false; +export const showHelp = true; +export const sendTyping = false; +export const options = []; + + +export const execute = async (client: Client, message: Message) => { + const serverlist = client.guilds.cache + .map(g => `Guild ID: ${g.id}\n Guild: ${g.name}\n Members: ${g.memberCount}`) + .join('\n\n'); + + return message.reply({ + embeds: [embeds.server(client.config, serverlist)], + allowedMentions: { repliedUser: false } + }); +} + +export const slashExecute = async (client: Client, interaction: ChatInputCommandInteraction) => { + const serverlist = client.guilds.cache + .map(g => `Guild ID: ${g.id}\n Guild: ${g.name}\n Members: ${g.memberCount}`) + .join('\n\n'); + + return interaction.editReply({ + embeds: [embeds.server(client.config, serverlist)], + allowedMentions: { repliedUser: false } + }); +} \ No newline at end of file diff --git a/src/embeds/index.ts b/src/embeds/index.ts index 7246942..985e5ac 100644 --- a/src/embeds/index.ts +++ b/src/embeds/index.ts @@ -2,6 +2,7 @@ import { status } from "./status"; import { queue } from "./queue"; import { removeList, removeTrack } from "./remove"; import { help } from "./help"; +import { server } from "./server"; const embeds = { @@ -9,7 +10,8 @@ const embeds = { queue, removeList, removeTrack, - help + help, + server } export { embeds }; \ No newline at end of file diff --git a/src/embeds/server.ts b/src/embeds/server.ts new file mode 100644 index 0000000..55d5532 --- /dev/null +++ b/src/embeds/server.ts @@ -0,0 +1,14 @@ +import { EmbedBuilder, HexColorString } from "discord.js"; +import { Config } from "../@types"; + + +const server = (config: Config, serverlist: string) => { + const embed_ = new EmbedBuilder() + .setColor(config.embedsColor as HexColorString | number) + .setTitle(`Servers that have **${config.name}**`) + .setDescription(serverlist); + + return embed_; +} + +export { server }; \ No newline at end of file From b6b36d99aa4da93c99907107623efb75148eeb9b Mon Sep 17 00:00:00 2001 From: hmes98318 <52697423+hmes98318@users.noreply.github.com> Date: Sat, 8 Jul 2023 23:10:23 +0800 Subject: [PATCH 34/64] Add `nowplaying` command --- src/commands/nowplaying.ts | 68 +++++++++++++++++++++++++++++++++ src/embeds/index.ts | 4 +- src/embeds/save.ts | 16 ++++++++ src/events/interactionCreate.ts | 52 +++++++++++++++++++++---- 4 files changed, 131 insertions(+), 9 deletions(-) create mode 100644 src/commands/nowplaying.ts create mode 100644 src/embeds/save.ts diff --git a/src/commands/nowplaying.ts b/src/commands/nowplaying.ts new file mode 100644 index 0000000..9b2527f --- /dev/null +++ b/src/commands/nowplaying.ts @@ -0,0 +1,68 @@ +import { + ActionRowBuilder, + ButtonBuilder, + ButtonStyle, + ChatInputCommandInteraction, + Client, + Message +} from "discord.js"; +import { embeds } from "../embeds"; + + +export const name = 'nowplaying'; +export const aliases = ['np', 'save']; +export const description = 'Show now playing song'; +export const usage = 'nowplaying'; +export const voiceChannel = false; +export const showHelp = true; +export const sendTyping = true; +export const options = []; + + +export const execute = async (client: Client, message: Message) => { + const player = client.lavashark.getPlayer(message.guild!.id); + + if (!player) { + return message.reply({ content: 'āŒ | There is no music currently playing.', allowedMentions: { repliedUser: false } }); + } + + const track = player.current; + const subtitle = `Author : **${track?.author}**\nDuration **${track?.duration.label}**\n`; + + const saveButton = new ButtonBuilder() + .setCustomId('musicSave') + .setLabel('Save Song') + .setStyle(ButtonStyle.Success); + const row = new ActionRowBuilder() + .addComponents(saveButton); + + return message.channel.send({ + embeds: [embeds.save(client.config.embedsColor, track!.title, subtitle, track!.uri, track!.thumbnail!)], + components: [row], + allowedMentions: { repliedUser: false } + }); +} + +export const slashExecute = async (client: Client, interaction: ChatInputCommandInteraction) => { + const player = client.lavashark.getPlayer(interaction.guild!.id); + + if (!player) { + return interaction.reply({ content: 'āŒ | There is no music currently playing.', allowedMentions: { repliedUser: false } }); + } + + const track = player.current; + const subtitle = `Author : **${track?.author}**\nDuration **${track?.duration.label}**\n`; + + const saveButton = new ButtonBuilder() + .setCustomId('musicSave') + .setLabel('Save Song') + .setStyle(ButtonStyle.Success); + const row = new ActionRowBuilder() + .addComponents(saveButton); + + return interaction.editReply({ + embeds: [embeds.save(client.config.embedsColor, track!.title, subtitle, track!.uri, track!.thumbnail!)], + components: [row], + allowedMentions: { repliedUser: false } + }); +} \ No newline at end of file diff --git a/src/embeds/index.ts b/src/embeds/index.ts index 985e5ac..baf1f2a 100644 --- a/src/embeds/index.ts +++ b/src/embeds/index.ts @@ -3,6 +3,7 @@ import { queue } from "./queue"; import { removeList, removeTrack } from "./remove"; import { help } from "./help"; import { server } from "./server"; +import { save } from "./save"; const embeds = { @@ -11,7 +12,8 @@ const embeds = { removeList, removeTrack, help, - server + server, + save } export { embeds }; \ No newline at end of file diff --git a/src/embeds/save.ts b/src/embeds/save.ts new file mode 100644 index 0000000..10006b7 --- /dev/null +++ b/src/embeds/save.ts @@ -0,0 +1,16 @@ +import { EmbedBuilder, HexColorString } from "discord.js"; + + +const save = (embedsColor: HexColorString | string | number, title: string, subtitle: string, url: string, thumbnail: string) => { + const embed_ = new EmbedBuilder() + .setColor(embedsColor as HexColorString | number) + .setTitle(title) + .setURL(url) + .setThumbnail(thumbnail) + .setDescription(subtitle) + .setTimestamp() + + return embed_; +} + +export { save }; \ No newline at end of file diff --git a/src/events/interactionCreate.ts b/src/events/interactionCreate.ts index 14de47e..29e9233 100644 --- a/src/events/interactionCreate.ts +++ b/src/events/interactionCreate.ts @@ -1,24 +1,60 @@ -import { Client, ChatInputCommandInteraction } from "discord.js"; +import { Client, Interaction } from "discord.js"; import { cst } from "../utils/constants"; +import { embeds } from "../embeds"; -export default async (client: Client, interaction: ChatInputCommandInteraction) => { +export default async (client: Client, interaction: Interaction) => { + const guildMember = interaction.guild!.members.cache.get(interaction.user.id); + const voiceChannel = guildMember!.voice.channel; + + if (interaction.isButton()) { + if (!voiceChannel) { + return interaction.reply({ content: `āŒ | You are not connected to an audio channel.`, ephemeral: true, components: [] }); + } + if (interaction.guild?.members.me?.voice.channel && voiceChannel.id !== interaction.guild.members.me.voice.channelId) { + return interaction.reply({ content: `āŒ | You are not on the same audio channel as me.`, ephemeral: true, components: [] }); + } + + + const player = client.lavashark.getPlayer(interaction.guild!.id); + + if (!player) { + return interaction.reply({ content: 'āŒ | There is no music currently playing.', allowedMentions: { repliedUser: false } }); + } + + switch (interaction.customId) { + case 'musicSave': { + const track = player.current; + const subtitle = `Author : **${track?.author}**\nDuration **${track?.duration.label}**\n`; + + guildMember?.send({ embeds: [embeds.save(client.config.embedsColor, track!.title, subtitle, track!.uri, track!.thumbnail!)] }) + .then(() => { + return interaction.reply({ content: `āœ… | I sent you the name of the music in a private message.`, ephemeral: true, components: [] }); + }) + .catch((error) => { + console.log('error:', error); + return interaction.reply({ content: `āŒ | I can't send you a private message.`, ephemeral: true, components: [] }); + }); + + break; + } + } + } + - if (interaction.isButton()) { } else { if (!interaction.isCommand() || !interaction.inGuild() || interaction.member.user.bot) return; const cmd = client.commands.get(interaction.commandName); - const guildMember = interaction.guild!.members.cache.get(interaction.user.id); - const voiceChannel = guildMember!.voice.channel; if (cmd && cmd.voiceChannel) { - if (!voiceChannel) + if (!voiceChannel) { return interaction.reply({ content: `āŒ | You are not connected to an audio channel.`, allowedMentions: { repliedUser: false } }); - - if (interaction.guild?.members.me?.voice.channel && voiceChannel.id !== interaction.guild.members.me.voice.channelId) + } + if (interaction.guild?.members.me?.voice.channel && voiceChannel.id !== interaction.guild.members.me.voice.channelId) { return interaction.reply({ content: `āŒ | You are not on the same audio channel as me.`, allowedMentions: { repliedUser: false } }); + } } if (cmd) { From dfd19f4d0f5b392ef078888163f0d6e6f6163956 Mon Sep 17 00:00:00 2001 From: hmes98318 <52697423+hmes98318@users.noreply.github.com> Date: Sun, 9 Jul 2023 19:36:35 +0800 Subject: [PATCH 35/64] Refactor discord events path --- src/events/{ => discord}/interactionCreate.ts | 4 ++-- src/events/{ => discord}/messageCreate.ts | 2 +- src/events/{ => discord}/raw.ts | 0 src/events/{ => discord}/ready.ts | 6 +++--- src/events/{ => discord}/voiceStateUpdate.ts | 15 +++++++++------ src/index.ts | 9 ++++++--- 6 files changed, 21 insertions(+), 15 deletions(-) rename src/events/{ => discord}/interactionCreate.ts (97%) rename src/events/{ => discord}/messageCreate.ts (96%) rename src/events/{ => discord}/raw.ts (100%) rename src/events/{ => discord}/ready.ts (90%) rename src/events/{ => discord}/voiceStateUpdate.ts (91%) diff --git a/src/events/interactionCreate.ts b/src/events/discord/interactionCreate.ts similarity index 97% rename from src/events/interactionCreate.ts rename to src/events/discord/interactionCreate.ts index 29e9233..ab6709a 100644 --- a/src/events/interactionCreate.ts +++ b/src/events/discord/interactionCreate.ts @@ -1,6 +1,6 @@ import { Client, Interaction } from "discord.js"; -import { cst } from "../utils/constants"; -import { embeds } from "../embeds"; +import { cst } from "../../utils/constants"; +import { embeds } from "../../embeds"; export default async (client: Client, interaction: Interaction) => { diff --git a/src/events/messageCreate.ts b/src/events/discord/messageCreate.ts similarity index 96% rename from src/events/messageCreate.ts rename to src/events/discord/messageCreate.ts index e655f4c..d602b4a 100644 --- a/src/events/messageCreate.ts +++ b/src/events/discord/messageCreate.ts @@ -1,5 +1,5 @@ import { Client, Message, ChannelType } from "discord.js"; -import { cst } from "../utils/constants"; +import { cst } from "../../utils/constants"; export default async (client: Client, message: Message) => { diff --git a/src/events/raw.ts b/src/events/discord/raw.ts similarity index 100% rename from src/events/raw.ts rename to src/events/discord/raw.ts diff --git a/src/events/ready.ts b/src/events/discord/ready.ts similarity index 90% rename from src/events/ready.ts rename to src/events/discord/ready.ts index f4e8108..495ddf9 100644 --- a/src/events/ready.ts +++ b/src/events/discord/ready.ts @@ -3,9 +3,9 @@ import os from 'os'; import { Client, version as dcVersion } from 'discord.js'; import { VERSION as sharkVersion } from 'lavashark'; -import { version as botVersion } from '../../package.json'; -import { getOSVersion } from '../utils/functions/getOSVersion'; -import { cst } from '../utils/constants'; +import { version as botVersion } from '../../../package.json'; +import { getOSVersion } from '../../utils/functions/getOSVersion'; +import { cst } from '../../utils/constants'; module.exports = async (client: Client) => { diff --git a/src/events/voiceStateUpdate.ts b/src/events/discord/voiceStateUpdate.ts similarity index 91% rename from src/events/voiceStateUpdate.ts rename to src/events/discord/voiceStateUpdate.ts index 1374268..356ef0a 100644 --- a/src/events/voiceStateUpdate.ts +++ b/src/events/discord/voiceStateUpdate.ts @@ -11,8 +11,9 @@ export default async (client: Client, oldState: VoiceState, newState: VoiceState // If the member who left the channel is not bot, check if the channel still has members if (!oldState.member?.user.bot) { - let player: any; - try { player = client.lavashark.getPlayer(oldState.guild.id); } catch (_) { return; } + const player = client.lavashark.getPlayer(oldState.guild.id); + if (!player) return; + const botChannelId = player?.voiceChannelId; const oldChannelId = oldState.channel?.id; @@ -37,8 +38,9 @@ export default async (client: Client, oldState: VoiceState, newState: VoiceState // If the member who left the channel is not bot, check if the channel still has members if (!oldState.member?.user.bot) { - let player: any; - try { player = client.lavashark.getPlayer(oldState.guild.id); } catch (_) { return; } + const player = client.lavashark.getPlayer(newState.guild.id); + if (!player) return; + const botChannelId = player?.voiceChannelId; const newChannelId = newState.channel?.id; @@ -65,8 +67,9 @@ export default async (client: Client, oldState: VoiceState, newState: VoiceState // If the member who left the channel is not bot, check if the channel still has members if (!oldState.member?.user.bot) { - let player: any; - try { player = client.lavashark.getPlayer(oldState.guild.id); } catch (_) { return; } + const player = client.lavashark.getPlayer(oldState.guild.id); + if (!player) return; + const botChannelId = player?.voiceChannelId; const oldChannelId = oldState.channel?.id; const newChannelId = newState.channel?.id; diff --git a/src/index.ts b/src/index.ts index 81cb140..584c0d4 100644 --- a/src/index.ts +++ b/src/index.ts @@ -9,6 +9,7 @@ import { cst } from "./utils/constants"; import nodeList from "../node-list.json"; import { Config, Info } from "./@types"; +import { EventListeners } from 'lavashark/typings/src/@types'; dotenv.config(); @@ -66,13 +67,15 @@ const setEnvironment = (): Promise => { const loadEvents = () => { console.log(`-> loading Events ......`); return new Promise(async (resolve, reject) => { - const events = fs.readdirSync(`${__dirname}/events/`); + const events = fs.readdirSync(`${__dirname}/events/discord/`); console.log(`+--------------------------------+`); for (const file of events) { try { - const event = await import(`${__dirname}/events/${file}`); - client.on(file.split('.')[0], event.default.bind(null, client)); + const event = await import(`${__dirname}/events/discord/${file}`); + const eventName = file.split('.')[0]; + + client.on(eventName, event.default.bind(null, client)); console.log(`| Loaded event ${file.split('.')[0].padEnd(17, ' ')} |`); } catch (error) { From 2ea66b91d6f7decc7cce229331bb77f0c17e595c Mon Sep 17 00:00:00 2001 From: hmes98318 <52697423+hmes98318@users.noreply.github.com> Date: Mon, 10 Jul 2023 21:28:44 +0800 Subject: [PATCH 36/64] Add auto leave config --- src/commands/leave.ts | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/commands/leave.ts b/src/commands/leave.ts index 8685860..615b73e 100644 --- a/src/commands/leave.ts +++ b/src/commands/leave.ts @@ -18,7 +18,13 @@ export const execute = async (client: Client, message: Message) => { return message.reply({ content: 'āŒ | There is no music currently playing.', allowedMentions: { repliedUser: false } }); } - await player.destroy(); + if (client.config.autoLeave) { + await player.destroy(); + } + else { + player.queue.clear(); + await player.skip(); + } return await message.react('šŸ‘'); } @@ -30,7 +36,13 @@ export const slashExecute = async (client: Client, interaction: ChatInputCommand return interaction.editReply({ content: 'āŒ | There is no music currently playing.', allowedMentions: { repliedUser: false } }); } - await player.destroy(); + if (client.config.autoLeave) { + await player.destroy(); + } + else { + player.queue.clear(); + await player.skip(); + } return await interaction.editReply('āœ… | Bot leave.'); } \ No newline at end of file From 3d3538d2cedf4d10e3e04bd5024717a866d743a0 Mon Sep 17 00:00:00 2001 From: hmes98318 <52697423+hmes98318@users.noreply.github.com> Date: Tue, 11 Jul 2023 23:34:40 +0800 Subject: [PATCH 37/64] Add dashboard --- src/commands/dashboard.ts | 49 +++++++++ src/commands/leave.ts | 7 +- src/commands/play.ts | 22 ++-- src/dashboard/destroy.ts | 16 +++ src/dashboard/index.ts | 12 +++ src/dashboard/initial.ts | 43 ++++++++ src/dashboard/update.ts | 30 ++++++ src/embeds/dashboard.ts | 31 ++++++ src/embeds/index.ts | 6 +- src/events/discord/interactionCreate.ts | 132 +++++++++++++++++++++++- src/events/lavashark/playerConnect.ts | 8 ++ src/events/lavashark/playerDestroy.ts | 11 ++ src/events/lavashark/queueEnd.ts | 16 +++ src/events/lavashark/trackEnd.ts | 7 ++ src/events/lavashark/trackStart.ts | 12 +++ src/index.ts | 35 ++++++- src/utils/constants.ts | 13 ++- 17 files changed, 435 insertions(+), 15 deletions(-) create mode 100644 src/commands/dashboard.ts create mode 100644 src/dashboard/destroy.ts create mode 100644 src/dashboard/index.ts create mode 100644 src/dashboard/initial.ts create mode 100644 src/dashboard/update.ts create mode 100644 src/embeds/dashboard.ts create mode 100644 src/events/lavashark/playerConnect.ts create mode 100644 src/events/lavashark/playerDestroy.ts create mode 100644 src/events/lavashark/queueEnd.ts create mode 100644 src/events/lavashark/trackEnd.ts create mode 100644 src/events/lavashark/trackStart.ts diff --git a/src/commands/dashboard.ts b/src/commands/dashboard.ts new file mode 100644 index 0000000..059099c --- /dev/null +++ b/src/commands/dashboard.ts @@ -0,0 +1,49 @@ +import { ChatInputCommandInteraction, Client, Message } from "discord.js"; +import { dashboard } from "../dashboard"; + + +export const name = 'dashboard'; +export const aliases = ['d', 'console']; +export const description = 'Move the dashboard embed to the bottom'; +export const usage = 'dashboard'; +export const voiceChannel = true; +export const showHelp = true; +export const sendTyping = false; +export const options = []; + + +export const execute = async (client: Client, message: Message) => { + const player = client.lavashark.getPlayer(message.guild!.id); + + if (!player || !player.dashboard) { + return message.reply({ content: 'āŒ | There is no music currently playing.', allowedMentions: { repliedUser: false } }); + } + + try { + await player.dashboard?.delete(); + } catch (error) { + console.log('Dashboard delete error:', error); + } + + await dashboard.initial(client, message, player); + await dashboard.update(client, player, player.current!); + return message.react('šŸ‘'); +} + +export const slashExecute = async (client: Client, interaction: ChatInputCommandInteraction) => { + const player = client.lavashark.getPlayer(interaction.guild!.id); + + if (!player || !player.dashboard) { + return interaction.editReply({ content: 'āŒ | There is no music currently playing.', allowedMentions: { repliedUser: false } }); + } + + try { + await player.dashboard?.delete(); + } catch (error) { + console.log('Dashboard delete error:', error); + } + + await dashboard.initial(client, interaction, player); + await dashboard.update(client, player, player.current!); + return interaction.editReply("āœ… | Dashboard updated."); +} \ No newline at end of file diff --git a/src/commands/leave.ts b/src/commands/leave.ts index 615b73e..740e930 100644 --- a/src/commands/leave.ts +++ b/src/commands/leave.ts @@ -1,4 +1,5 @@ import { ChatInputCommandInteraction, Client, Message } from "discord.js"; +import { dashboard } from "../dashboard"; export const name = 'leave'; @@ -24,9 +25,10 @@ export const execute = async (client: Client, message: Message) => { else { player.queue.clear(); await player.skip(); + await dashboard.destroy(client, player); } - return await message.react('šŸ‘'); + return message.react('šŸ‘'); } export const slashExecute = async (client: Client, interaction: ChatInputCommandInteraction) => { @@ -42,7 +44,8 @@ export const slashExecute = async (client: Client, interaction: ChatInputCommand else { player.queue.clear(); await player.skip(); + await dashboard.destroy(client, player); } - return await interaction.editReply('āœ… | Bot leave.'); + return interaction.editReply('āœ… | Bot leave.'); } \ No newline at end of file diff --git a/src/commands/play.ts b/src/commands/play.ts index e639897..20864b0 100644 --- a/src/commands/play.ts +++ b/src/commands/play.ts @@ -1,4 +1,8 @@ import { ChatInputCommandInteraction, Client, Message } from "discord.js"; +import { Player } from "lavashark"; + +import { dashboard } from "../dashboard"; + export const name = 'play'; export const aliases = ['p']; @@ -33,7 +37,7 @@ export const execute = async (client: Client, message: Message, args: string[]) return message.reply({ content: `āŒ | No matches.`, allowedMentions: { repliedUser: false } }); } - let player; + let player: Player; try { // Creates the audio player player = client.lavashark.createPlayer({ @@ -45,6 +49,9 @@ export const execute = async (client: Client, message: Message, args: string[]) // Connects to the voice channel player.connect(); + + // Intial dashboard + if (!player.dashboard) await dashboard.initial(client, message, player); } catch (error) { console.log(error); return message.reply({ content: `āŒ | I can't join voice channel.`, allowedMentions: { repliedUser: false } }); @@ -53,7 +60,7 @@ export const execute = async (client: Client, message: Message, args: string[]) if (res.loadType === 'PLAYLIST_LOADED') { for (const track of res.tracks) { - track.setRequester(client.user); + track.setRequester(message.author); player.queue.add(track); } @@ -61,7 +68,7 @@ export const execute = async (client: Client, message: Message, args: string[]) } else { const track = res.tracks[0]; - track.setRequester(client.user); + track.setRequester(message.author); player.queue.add(track); message.reply(`Queued \`${track.title}\``); @@ -89,7 +96,7 @@ export const slashExecute = async (client: Client, interaction: ChatInputCommand return interaction.editReply({ content: `āŒ | No matches.`, allowedMentions: { repliedUser: false } }); } - let player; + let player: Player; try { const guildMember = interaction.guild!.members.cache.get(interaction.user.id); const { channel } = guildMember!.voice; @@ -103,6 +110,9 @@ export const slashExecute = async (client: Client, interaction: ChatInputCommand // Connects to the voice channel player.connect(); + + // Intial dashboard + if (!player.dashboard) await dashboard.initial(client, interaction, player); } catch (error) { console.log(error); return interaction.editReply({ content: `āŒ | I can't join voice channel.`, allowedMentions: { repliedUser: false } }); @@ -111,7 +121,7 @@ export const slashExecute = async (client: Client, interaction: ChatInputCommand if (res.loadType === 'PLAYLIST_LOADED') { for (const track of res.tracks) { - track.setRequester(client.user); + track.setRequester(interaction.user); player.queue.add(track); } @@ -119,7 +129,7 @@ export const slashExecute = async (client: Client, interaction: ChatInputCommand } else { const track = res.tracks[0]; - track.setRequester(client.user); + track.setRequester(interaction.user); player.queue.add(track); interaction.editReply(`Queued \`${track.title}\``); diff --git a/src/dashboard/destroy.ts b/src/dashboard/destroy.ts new file mode 100644 index 0000000..f224afe --- /dev/null +++ b/src/dashboard/destroy.ts @@ -0,0 +1,16 @@ +import { Client } from "discord.js"; +import { Player } from "lavashark"; + +import { embeds } from "../embeds"; + + +async function destroy(client: Client, player: Player) { + await player.dashboard!.edit({ + embeds: [embeds.disconnect(client.config.embedsColor)], + components: [] + }); + + player.dashboard = null; +} + +export { destroy }; \ No newline at end of file diff --git a/src/dashboard/index.ts b/src/dashboard/index.ts new file mode 100644 index 0000000..f452254 --- /dev/null +++ b/src/dashboard/index.ts @@ -0,0 +1,12 @@ +import { initial } from "./initial"; +import { update } from "./update"; +import { destroy } from "./destroy"; + + +const dashboard = { + initial, + update, + destroy +} + +export { dashboard }; \ No newline at end of file diff --git a/src/dashboard/initial.ts b/src/dashboard/initial.ts new file mode 100644 index 0000000..c5c5036 --- /dev/null +++ b/src/dashboard/initial.ts @@ -0,0 +1,43 @@ +import { + ActionRowBuilder, + ButtonBuilder, + ButtonStyle, + ChatInputCommandInteraction, + Client, + Message +} from "discord.js"; +import { Player } from "lavashark"; + +import { cst } from "../utils/constants"; +import { embeds } from "../embeds"; + + +async function initial(client: Client, message: Message, player: Player): Promise; +async function initial(client: Client, interaction: ChatInputCommandInteraction, player: Player): Promise; +async function initial(client: Client, interactionOrMessage: ChatInputCommandInteraction | Message, player: Player): Promise { + let channel; + + if (interactionOrMessage instanceof Message) { + channel = (interactionOrMessage as Message).channel; + } + else if (interactionOrMessage instanceof ChatInputCommandInteraction) { + channel = (interactionOrMessage as ChatInputCommandInteraction).channel; + } + else { + throw TypeError("Invalid Interaction or Message type"); + } + + const playPauseButton = new ButtonBuilder().setCustomId('Dashboard-PlayPause').setEmoji(cst.button.pause).setStyle(ButtonStyle.Secondary); + const skipButton = new ButtonBuilder().setCustomId('Dashboard-Skip').setEmoji(cst.button.skip).setStyle(ButtonStyle.Secondary); + const stopButton = new ButtonBuilder().setCustomId('Dashboard-Stop').setEmoji(cst.button.stop).setStyle(ButtonStyle.Danger); + const loopButton = new ButtonBuilder().setCustomId('Dashboard-Loop').setEmoji(cst.button.loop).setStyle(ButtonStyle.Secondary); + const shuffleButton = new ButtonBuilder().setCustomId('Dashboard-Shuffle').setEmoji(cst.button.shuffle).setStyle(ButtonStyle.Secondary); + const row = new ActionRowBuilder().addComponents(playPauseButton, skipButton, stopButton, loopButton, shuffleButton); + + player.dashboard = await channel!.send({ + embeds: [embeds.connected(client.config.embedsColor)], + components: [row] + }); +} + +export { initial }; \ No newline at end of file diff --git a/src/dashboard/update.ts b/src/dashboard/update.ts new file mode 100644 index 0000000..e2d3f54 --- /dev/null +++ b/src/dashboard/update.ts @@ -0,0 +1,30 @@ +import { + ActionRowBuilder, + ButtonBuilder, + ButtonStyle, + Client, +} from "discord.js"; +import { Player, Track } from "lavashark"; + +import { cst } from "../utils/constants"; +import { embeds } from "../embeds"; + + +async function update(client: Client, player: Player, track: Track): Promise { + const playing = !(player.paused); + const subtitle = `Author : **${track?.author}**\nDuration **${track?.duration.label}**\n`; + + const playPauseButton = new ButtonBuilder().setCustomId('Dashboard-PlayPause').setEmoji(playing ? cst.button.pause : cst.button.play).setStyle(playing ? ButtonStyle.Secondary : ButtonStyle.Success) + const skipButton = new ButtonBuilder().setCustomId('Dashboard-Skip').setEmoji(cst.button.skip).setStyle(ButtonStyle.Secondary); + const stopButton = new ButtonBuilder().setCustomId('Dashboard-Stop').setEmoji(cst.button.stop).setStyle(ButtonStyle.Danger); + const loopButton = new ButtonBuilder().setCustomId('Dashboard-Loop').setEmoji(cst.button.loop).setStyle(ButtonStyle.Secondary); + const shuffleButton = new ButtonBuilder().setCustomId('Dashboard-Shuffle').setEmoji(cst.button.shuffle).setStyle(ButtonStyle.Secondary); + const row = new ActionRowBuilder().addComponents(playPauseButton, skipButton, stopButton, loopButton, shuffleButton); + + await player.dashboard!.edit({ + embeds: [embeds.dashboard(client.config.embedsColor, 'Dashboard', track!.title, subtitle, track!.uri, track!.thumbnail!)], + components: [row] + }); +} + +export { update }; \ No newline at end of file diff --git a/src/embeds/dashboard.ts b/src/embeds/dashboard.ts new file mode 100644 index 0000000..ee0c055 --- /dev/null +++ b/src/embeds/dashboard.ts @@ -0,0 +1,31 @@ +import { EmbedBuilder, HexColorString } from "discord.js"; + + +const connected = (embedsColor: HexColorString | string | number) => { + const embed_ = new EmbedBuilder() + .setColor(embedsColor as HexColorString | number) + .setDescription('Voice channel connected successfully.') + + return embed_; +} + +const disconnect = (embedsColor: HexColorString | string | number) => { + const embed_ = new EmbedBuilder() + .setColor(embedsColor as HexColorString | number) + .setDescription('Finished playing.') + + return embed_; +} + +const dashboard = (embedsColor: HexColorString | string | number, status: string, title: string, subtitle: string, url: string, thumbnail: string) => { + const embed_ = new EmbedBuilder() + .setColor(embedsColor as HexColorString | number) + .setTitle(title) + .setURL(url) + .setThumbnail(thumbnail) + .addFields({ name: status, value: subtitle }) + .setTimestamp() + + return embed_; +} +export { connected, disconnect, dashboard }; \ No newline at end of file diff --git a/src/embeds/index.ts b/src/embeds/index.ts index baf1f2a..f3863fe 100644 --- a/src/embeds/index.ts +++ b/src/embeds/index.ts @@ -4,6 +4,7 @@ import { removeList, removeTrack } from "./remove"; import { help } from "./help"; import { server } from "./server"; import { save } from "./save"; +import { connected, disconnect, dashboard } from "./dashboard"; const embeds = { @@ -13,7 +14,10 @@ const embeds = { removeTrack, help, server, - save + save, + connected, + disconnect, + dashboard } export { embeds }; \ No newline at end of file diff --git a/src/events/discord/interactionCreate.ts b/src/events/discord/interactionCreate.ts index ab6709a..dbff152 100644 --- a/src/events/discord/interactionCreate.ts +++ b/src/events/discord/interactionCreate.ts @@ -1,6 +1,17 @@ -import { Client, Interaction } from "discord.js"; +import { + ActionRowBuilder, + ButtonBuilder, + ButtonStyle, + Client, + Interaction, + StringSelectMenuBuilder, + StringSelectMenuInteraction +} from "discord.js"; +import { RepeatMode } from "lavashark"; + import { cst } from "../../utils/constants"; import { embeds } from "../../embeds"; +import { dashboard } from "../../dashboard"; export default async (client: Client, interaction: Interaction) => { @@ -38,10 +49,125 @@ export default async (client: Client, interaction: Interaction) => { break; } - } - } + case 'Dashboard-PlayPause': { + const playing = !(player.paused); + + if (playing) { + player.pause(); + } + else { + player.resume(); + } + + const playPauseButton = new ButtonBuilder().setCustomId('Dashboard-PlayPause').setEmoji(playing ? cst.button.play : cst.button.pause).setStyle(playing ? ButtonStyle.Success : ButtonStyle.Secondary); + const skipButton = new ButtonBuilder().setCustomId('Dashboard-Skip').setEmoji(cst.button.skip).setStyle(ButtonStyle.Secondary); + const stopButton = new ButtonBuilder().setCustomId('Dashboard-Stop').setEmoji(cst.button.stop).setStyle(ButtonStyle.Danger); + const loopButton = new ButtonBuilder().setCustomId('Dashboard-Loop').setEmoji(cst.button.loop).setStyle(ButtonStyle.Secondary); + const shuffleButton = new ButtonBuilder().setCustomId('Dashboard-Shuffle').setEmoji(cst.button.shuffle).setStyle(ButtonStyle.Secondary); + const row = new ActionRowBuilder().addComponents(playPauseButton, skipButton, stopButton, loopButton, shuffleButton); + + await interaction.update({ components: [row] }); + break; + } + + case 'Dashboard-Skip': { + const playing = !(player.paused); + const repeatMode = player.queueRepeat ? RepeatMode.QUEUE : (player.trackRepeat ? RepeatMode.TRACK : RepeatMode.OFF); + + if (repeatMode === RepeatMode.TRACK) { + player.setRepeatMode(RepeatMode.OFF); + await player.skip(); + player.setRepeatMode(RepeatMode.TRACK); + } + else { + await player.skip(); + } + + const playPauseButton = new ButtonBuilder().setCustomId('Dashboard-PlayPause').setEmoji(playing ? cst.button.play : cst.button.pause).setStyle(playing ? ButtonStyle.Success : ButtonStyle.Secondary); + const skipButton = new ButtonBuilder().setCustomId('Dashboard-Skip').setEmoji(cst.button.skip).setStyle(ButtonStyle.Secondary); + const stopButton = new ButtonBuilder().setCustomId('Dashboard-Stop').setEmoji(cst.button.stop).setStyle(ButtonStyle.Danger); + const loopButton = new ButtonBuilder().setCustomId('Dashboard-Loop').setEmoji(cst.button.loop).setStyle(ButtonStyle.Secondary); + const shuffleButton = new ButtonBuilder().setCustomId('Dashboard-Shuffle').setEmoji(cst.button.shuffle).setStyle(ButtonStyle.Secondary); + const row = new ActionRowBuilder().addComponents(playPauseButton, skipButton, stopButton, loopButton, shuffleButton); + + await interaction.update({ components: [row] }); + break; + } + + case 'Dashboard-Loop': { + let mode = 0; + const methods = ['Off', 'Single', 'All']; + + const select = new StringSelectMenuBuilder() + .setCustomId("Playing-Loop Select") + .setPlaceholder("Select the loop mode") + .setOptions(methods.map(x => { + return { + label: x, + description: x, + value: x + } + })); + const row = new ActionRowBuilder().addComponents(select); + let msg = await interaction.reply({ content: `Select a song loop mode.`, ephemeral: true, components: [row] }); + + const collector = msg.createMessageComponentCollector({ + time: 20000, // 20s + filter: i => i.user.id === interaction.user.id + }); + + collector.on("collect", async (i: StringSelectMenuInteraction) => { + if (i.customId != "Playing-Loop Select") return; + + switch (i.values[0]) { + case 'off': { + mode = 0; + player.setRepeatMode(RepeatMode.OFF); + break; + } + case 'one' || 'single': { + mode = 1; + player.setRepeatMode(RepeatMode.TRACK); + break; + } + case 'all' || 'queue': { + mode = 2; + player.setRepeatMode(RepeatMode.QUEUE); + break; + } + } + await dashboard.update(client, player, player.current!); + + await i.deferUpdate(); + await interaction.reply({ content: `āœ… | Set loop to \`${methods[mode]}\`.`, ephemeral: true, components: [] }); + }) + break; + } + + case 'Dashboard-Stop': { + if (client.config.autoLeave) { + await player.destroy(); + } + else { + player.queue.clear(); + await player.skip(); + await dashboard.destroy(client, player); + } + + await interaction.reply({ content: 'āœ… | Bot leave.', ephemeral: true, components: [] }); + break; + } + + case 'Dashboard-Shuffle': { + player.queue.shuffle(); + + await interaction.reply({ content: 'āœ… | Music shuffled.', ephemeral: true, components: [] }); + break; + } + } + } else { if (!interaction.isCommand() || !interaction.inGuild() || interaction.member.user.bot) return; diff --git a/src/events/lavashark/playerConnect.ts b/src/events/lavashark/playerConnect.ts new file mode 100644 index 0000000..c2b10cf --- /dev/null +++ b/src/events/lavashark/playerConnect.ts @@ -0,0 +1,8 @@ +import { Client } from "discord.js"; +import { Player } from "lavashark"; + + +export default async (client: Client, player: Player): Promise => { + console.log('// -------- player Connect -------- //'); + +}; \ No newline at end of file diff --git a/src/events/lavashark/playerDestroy.ts b/src/events/lavashark/playerDestroy.ts new file mode 100644 index 0000000..3cb85f8 --- /dev/null +++ b/src/events/lavashark/playerDestroy.ts @@ -0,0 +1,11 @@ +import { Client } from "discord.js"; +import { Player } from "lavashark"; + +import { dashboard } from "../../dashboard"; + + +export default async (client: Client, player: Player) => { + console.log('// -------- player Destroy -------- //'); + + await dashboard.destroy(client, player); +}; \ No newline at end of file diff --git a/src/events/lavashark/queueEnd.ts b/src/events/lavashark/queueEnd.ts new file mode 100644 index 0000000..d907866 --- /dev/null +++ b/src/events/lavashark/queueEnd.ts @@ -0,0 +1,16 @@ +import { Client } from "discord.js"; +import { Player } from "lavashark"; + +import { dashboard } from "../../dashboard"; + + +export default async (client: Client, player: Player) => { + console.log('// -------- queue end -------- //'); + + if (client.config.autoLeave) { + await player.destroy(); + } + else { + await dashboard.destroy(client, player); + } +}; \ No newline at end of file diff --git a/src/events/lavashark/trackEnd.ts b/src/events/lavashark/trackEnd.ts new file mode 100644 index 0000000..0072557 --- /dev/null +++ b/src/events/lavashark/trackEnd.ts @@ -0,0 +1,7 @@ +import { Client } from "discord.js"; +import { Player, Track } from "lavashark"; + + +export default async (client: Client, player: Player, track: Track, reason: any) => { + console.log('// -------- track end -------- //'); +}; \ No newline at end of file diff --git a/src/events/lavashark/trackStart.ts b/src/events/lavashark/trackStart.ts new file mode 100644 index 0000000..f175a7e --- /dev/null +++ b/src/events/lavashark/trackStart.ts @@ -0,0 +1,12 @@ +import { Client } from "discord.js"; +import { Player, Track } from "lavashark"; + +import { dashboard } from "../../dashboard"; + + +export default async (client: Client, player: Player/*, track: Track*/) => { + console.log('// -------- track start -------- //'); + + const track = player.current; //-------------------------- + await dashboard.update(client, player, track!); +}; \ No newline at end of file diff --git a/src/index.ts b/src/index.ts index 584c0d4..f820243 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,7 +1,7 @@ import * as fs from 'fs'; import * as dotenv from 'dotenv'; -import { Client, Collection, GatewayIntentBits } from 'discord.js'; +import { Client, Collection, GatewayIntentBits, Message } from 'discord.js'; import { LavaShark } from "lavashark"; import consoleStamp from 'console-stamp'; @@ -23,7 +23,12 @@ declare module 'discord.js' { config: Config, info: Info } -} +}; +declare module 'lavashark' { + export interface Player { + dashboard: Message | null + } +}; @@ -89,6 +94,31 @@ const loadEvents = () => { }); } +const loadLavaSharkEvents = () => { + console.log(`-> loading LavaShark Events ......`); + return new Promise(async (resolve, reject) => { + const events = fs.readdirSync(`${__dirname}/events/lavashark/`); + + console.log(`+--------------------------------+`); + for (const file of events) { + try { + const event = await import(`${__dirname}/events/lavashark/${file}`); + const eventName = file.split('.')[0] as keyof EventListeners; + + client.lavashark.on(eventName, event.default.bind(null, client)); + console.log(`| Loaded event ${file.split('.')[0].padEnd(17, ' ')} |`); + } + catch (error) { + reject(error); + } + } + console.log(`+--------------------------------+`); + console.log(`${cst.color.grey}-- loading LavaShark Events finished --${cst.color.white}`); + + resolve(); + }); +} + const loadCommands = () => { console.log(`-> loading Commands ......`); return new Promise(async (resolve, reject) => { @@ -116,6 +146,7 @@ const loadCommands = () => { Promise.resolve() .then(() => setEnvironment()) .then(() => loadEvents()) + .then(() => loadLavaSharkEvents()) .then(() => loadCommands()) .then(() => { console.log(`${cst.color.green}*** All loaded successfully ***${cst.color.white}`); diff --git a/src/utils/constants.ts b/src/utils/constants.ts index eb294ca..9f0174b 100644 --- a/src/utils/constants.ts +++ b/src/utils/constants.ts @@ -15,10 +15,21 @@ export const cst = { displayVoiceState : true, port : 33333 }, + // Console color color: { white : '\x1B[0m', grey : '\x1B[2m', green : '\x1B[32m', cyan : '\x1B[36m' + }, + // Dashboard button icon + button: { + play : '<:w_play:1106270709644271656>', + pause : '<:w_pause:1106270708243386428>', + skip : '<:w_skip:1106270714664849448>', + back : '<:w_back:1106270704049061928>', + stop : '<:w_stop:1106272001909346386>', + loop : '<:w_loop:1106270705575792681>', + shuffle : '<:w_shuffle:1106270712542531624>', } -} \ No newline at end of file +}; \ No newline at end of file From 28cd50fd16796750957f1bf142acedd654a38330 Mon Sep 17 00:00:00 2001 From: hmes98318 <52697423+hmes98318@users.noreply.github.com> Date: Wed, 12 Jul 2023 21:17:23 +0800 Subject: [PATCH 38/64] Add `ping` command --- src/commands/ping.ts | 35 +++++++++++++++++++++++++++++++++++ src/embeds/index.ts | 24 +++++++++++++----------- src/embeds/ping.ts | 13 +++++++++++++ 3 files changed, 61 insertions(+), 11 deletions(-) create mode 100644 src/commands/ping.ts create mode 100644 src/embeds/ping.ts diff --git a/src/commands/ping.ts b/src/commands/ping.ts new file mode 100644 index 0000000..0f0eb43 --- /dev/null +++ b/src/commands/ping.ts @@ -0,0 +1,35 @@ +import { ChatInputCommandInteraction, Client, Message } from "discord.js"; +import { embeds } from "../embeds"; + + +export const name = 'ping'; +export const aliases = []; +export const description = 'Get server ping'; +export const usage = 'ping'; +export const voiceChannel = false; +export const showHelp = true; +export const sendTyping = true; +export const options = []; + + +export const execute = async (client: Client, message: Message) => { + const botPing = `${Date.now() - message.createdTimestamp}ms`; + const apiPing = client.ws.ping.toString(); + + await message.react('šŸ‘'); + + return message.reply({ + embeds: [embeds.ping(client.config.embedsColor, botPing, apiPing)], + allowedMentions: { repliedUser: false } + }); +} + +export const slashExecute = async (client: Client, interaction: ChatInputCommandInteraction) => { + const botPing = `${Date.now() - interaction.createdTimestamp}ms`; + const apiPing = client.ws.ping.toString(); + + return interaction.editReply({ + embeds: [embeds.ping(client.config.embedsColor, botPing, apiPing)], + allowedMentions: { repliedUser: false } + }); +} \ No newline at end of file diff --git a/src/embeds/index.ts b/src/embeds/index.ts index f3863fe..7be17ec 100644 --- a/src/embeds/index.ts +++ b/src/embeds/index.ts @@ -1,23 +1,25 @@ -import { status } from "./status"; +import { connected, dashboard, disconnect } from "./dashboard"; +import { help } from "./help"; +import { ping } from "./ping"; import { queue } from "./queue"; import { removeList, removeTrack } from "./remove"; -import { help } from "./help"; -import { server } from "./server"; import { save } from "./save"; -import { connected, disconnect, dashboard } from "./dashboard"; +import { server } from "./server"; +import { status } from "./status"; const embeds = { - status, + connected, + dashboard, + disconnect, + help, + ping, queue, removeList, removeTrack, - help, - server, save, - connected, - disconnect, - dashboard -} + server, + status, +}; export { embeds }; \ No newline at end of file diff --git a/src/embeds/ping.ts b/src/embeds/ping.ts new file mode 100644 index 0000000..efaf845 --- /dev/null +++ b/src/embeds/ping.ts @@ -0,0 +1,13 @@ +import { EmbedBuilder, HexColorString } from "discord.js"; + + +const ping = (embedsColor: HexColorString | string | number, botPing: string, apiPing: string) => { + const embed_ = new EmbedBuilder() + .setColor(embedsColor as HexColorString | number) + .setTitle('šŸ›°ļø LATENCY') + .setDescription(`Bot : **${botPing}**\nAPI : **${apiPing}ms**`) + + return embed_; +} + +export { ping }; \ No newline at end of file From 46bec86e27b4871c012b0144995fdeca6e5cf742 Mon Sep 17 00:00:00 2001 From: hmes98318 <52697423+hmes98318@users.noreply.github.com> Date: Wed, 19 Jul 2023 21:38:42 +0800 Subject: [PATCH 39/64] Update naming conventions for embed module --- src/embeds/{dashboard.ts => dashboard.embed.ts} | 0 src/embeds/{help.ts => help.embed.ts} | 0 src/embeds/index.ts | 16 ++++++++-------- src/embeds/{ping.ts => ping.embed.ts} | 0 src/embeds/{queue.ts => queue.embed.ts} | 0 src/embeds/{remove.ts => remove.embed.ts} | 0 src/embeds/{save.ts => save.embed.ts} | 0 src/embeds/{server.ts => server.embed.ts} | 0 src/embeds/{status.ts => status.embed.ts} | 0 9 files changed, 8 insertions(+), 8 deletions(-) rename src/embeds/{dashboard.ts => dashboard.embed.ts} (100%) rename src/embeds/{help.ts => help.embed.ts} (100%) rename src/embeds/{ping.ts => ping.embed.ts} (100%) rename src/embeds/{queue.ts => queue.embed.ts} (100%) rename src/embeds/{remove.ts => remove.embed.ts} (100%) rename src/embeds/{save.ts => save.embed.ts} (100%) rename src/embeds/{server.ts => server.embed.ts} (100%) rename src/embeds/{status.ts => status.embed.ts} (100%) diff --git a/src/embeds/dashboard.ts b/src/embeds/dashboard.embed.ts similarity index 100% rename from src/embeds/dashboard.ts rename to src/embeds/dashboard.embed.ts diff --git a/src/embeds/help.ts b/src/embeds/help.embed.ts similarity index 100% rename from src/embeds/help.ts rename to src/embeds/help.embed.ts diff --git a/src/embeds/index.ts b/src/embeds/index.ts index 7be17ec..195767c 100644 --- a/src/embeds/index.ts +++ b/src/embeds/index.ts @@ -1,11 +1,11 @@ -import { connected, dashboard, disconnect } from "./dashboard"; -import { help } from "./help"; -import { ping } from "./ping"; -import { queue } from "./queue"; -import { removeList, removeTrack } from "./remove"; -import { save } from "./save"; -import { server } from "./server"; -import { status } from "./status"; +import { connected, dashboard, disconnect } from "./dashboard.embed"; +import { help } from "./help.embed"; +import { ping } from "./ping.embed"; +import { queue } from "./queue.embed"; +import { removeList, removeTrack } from "./remove.embed"; +import { save } from "./save.embed"; +import { server } from "./server.embed"; +import { status } from "./status.embed"; const embeds = { diff --git a/src/embeds/ping.ts b/src/embeds/ping.embed.ts similarity index 100% rename from src/embeds/ping.ts rename to src/embeds/ping.embed.ts diff --git a/src/embeds/queue.ts b/src/embeds/queue.embed.ts similarity index 100% rename from src/embeds/queue.ts rename to src/embeds/queue.embed.ts diff --git a/src/embeds/remove.ts b/src/embeds/remove.embed.ts similarity index 100% rename from src/embeds/remove.ts rename to src/embeds/remove.embed.ts diff --git a/src/embeds/save.ts b/src/embeds/save.embed.ts similarity index 100% rename from src/embeds/save.ts rename to src/embeds/save.embed.ts diff --git a/src/embeds/server.ts b/src/embeds/server.embed.ts similarity index 100% rename from src/embeds/server.ts rename to src/embeds/server.embed.ts diff --git a/src/embeds/status.ts b/src/embeds/status.embed.ts similarity index 100% rename from src/embeds/status.ts rename to src/embeds/status.embed.ts From 6fe1df646f52e0ea2dd836d4bb8170a2d543eaf7 Mon Sep 17 00:00:00 2001 From: hmes98318 <52697423+hmes98318@users.noreply.github.com> Date: Wed, 19 Jul 2023 21:43:59 +0800 Subject: [PATCH 40/64] Fix dashboard destroy not working --- src/dashboard/destroy.ts | 1 + src/events/lavashark/queueEnd.ts | 5 ++--- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/dashboard/destroy.ts b/src/dashboard/destroy.ts index f224afe..70ff7fb 100644 --- a/src/dashboard/destroy.ts +++ b/src/dashboard/destroy.ts @@ -11,6 +11,7 @@ async function destroy(client: Client, player: Player) { }); player.dashboard = null; + return; } export { destroy }; \ No newline at end of file diff --git a/src/events/lavashark/queueEnd.ts b/src/events/lavashark/queueEnd.ts index d907866..a9cae5b 100644 --- a/src/events/lavashark/queueEnd.ts +++ b/src/events/lavashark/queueEnd.ts @@ -10,7 +10,6 @@ export default async (client: Client, player: Player) => { if (client.config.autoLeave) { await player.destroy(); } - else { - await dashboard.destroy(client, player); - } + + await dashboard.destroy(client, player); }; \ No newline at end of file From 4952412a99bfa8a860647e4611c9ba7ede6a24b7 Mon Sep 17 00:00:00 2001 From: hmes98318 <52697423+hmes98318@users.noreply.github.com> Date: Wed, 19 Jul 2023 22:08:45 +0800 Subject: [PATCH 41/64] Add dashboard exception handling --- src/dashboard/destroy.ts | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/dashboard/destroy.ts b/src/dashboard/destroy.ts index 70ff7fb..ae34024 100644 --- a/src/dashboard/destroy.ts +++ b/src/dashboard/destroy.ts @@ -5,10 +5,14 @@ import { embeds } from "../embeds"; async function destroy(client: Client, player: Player) { - await player.dashboard!.edit({ - embeds: [embeds.disconnect(client.config.embedsColor)], - components: [] - }); + try { + await player.dashboard!.edit({ + embeds: [embeds.disconnect(client.config.embedsColor)], + components: [] + }); + } catch (error) { + console.log('Dashboard error:', error); + } player.dashboard = null; return; From dec7fc39de18f2e85d3a219adf58f7b4e5170eae Mon Sep 17 00:00:00 2001 From: hmes98318 <52697423+hmes98318@users.noreply.github.com> Date: Wed, 19 Jul 2023 22:09:58 +0800 Subject: [PATCH 42/64] Fix the display error of the dashboard button --- src/dashboard/update.ts | 2 +- src/events/discord/interactionCreate.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/dashboard/update.ts b/src/dashboard/update.ts index e2d3f54..25f8e9b 100644 --- a/src/dashboard/update.ts +++ b/src/dashboard/update.ts @@ -14,7 +14,7 @@ async function update(client: Client, player: Player, track: Track): Promise { player.resume(); } - const playPauseButton = new ButtonBuilder().setCustomId('Dashboard-PlayPause').setEmoji(playing ? cst.button.play : cst.button.pause).setStyle(playing ? ButtonStyle.Success : ButtonStyle.Secondary); + const playPauseButton = new ButtonBuilder().setCustomId('Dashboard-PlayPause').setEmoji(!playing ? cst.button.pause : cst.button.play).setStyle(!playing ? ButtonStyle.Secondary : ButtonStyle.Success); const skipButton = new ButtonBuilder().setCustomId('Dashboard-Skip').setEmoji(cst.button.skip).setStyle(ButtonStyle.Secondary); const stopButton = new ButtonBuilder().setCustomId('Dashboard-Stop').setEmoji(cst.button.stop).setStyle(ButtonStyle.Danger); const loopButton = new ButtonBuilder().setCustomId('Dashboard-Loop').setEmoji(cst.button.loop).setStyle(ButtonStyle.Secondary); @@ -84,7 +84,7 @@ export default async (client: Client, interaction: Interaction) => { await player.skip(); } - const playPauseButton = new ButtonBuilder().setCustomId('Dashboard-PlayPause').setEmoji(playing ? cst.button.play : cst.button.pause).setStyle(playing ? ButtonStyle.Success : ButtonStyle.Secondary); + const playPauseButton = new ButtonBuilder().setCustomId('Dashboard-PlayPause').setEmoji(playing ? cst.button.pause : cst.button.play).setStyle(playing ? ButtonStyle.Secondary : ButtonStyle.Success); const skipButton = new ButtonBuilder().setCustomId('Dashboard-Skip').setEmoji(cst.button.skip).setStyle(ButtonStyle.Secondary); const stopButton = new ButtonBuilder().setCustomId('Dashboard-Stop').setEmoji(cst.button.stop).setStyle(ButtonStyle.Danger); const loopButton = new ButtonBuilder().setCustomId('Dashboard-Loop').setEmoji(cst.button.loop).setStyle(ButtonStyle.Secondary); From 211c6356fb74e0a56cfb9ae0f37cca40b685c597 Mon Sep 17 00:00:00 2001 From: hmes98318 <52697423+hmes98318@users.noreply.github.com> Date: Thu, 27 Jul 2023 19:30:52 +0800 Subject: [PATCH 43/64] Update .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 3ec544c..f94630c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ node_modules/ +dist/ .env \ No newline at end of file From f5741eabd8cd5e462e45521999e1b403d149eb0b Mon Sep 17 00:00:00 2001 From: hmes98318 <52697423+hmes98318@users.noreply.github.com> Date: Fri, 28 Jul 2023 14:15:18 +0800 Subject: [PATCH 44/64] Update dependencies --- package-lock.json | 45 ++++++++++++++++++++++----------------------- package.json | 8 ++++---- 2 files changed, 26 insertions(+), 27 deletions(-) diff --git a/package-lock.json b/package-lock.json index 6f7add7..3deb156 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,12 +13,12 @@ "discord.js": "^14.11.0", "dotenv": "^16.0.3", "express": "^4.18.2", - "lavashark": "^1.1.1" + "lavashark": "^1.2.0" }, "devDependencies": { - "@types/node": "^20.3.2", + "@types/node": "^20.4.5", "ts-node": "^10.9.1", - "typescript": "^4.9.5" + "typescript": "^5.1.6" }, "engines": { "node": ">=16.13.0" @@ -203,9 +203,9 @@ "dev": true }, "node_modules/@types/node": { - "version": "20.3.3", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.3.3.tgz", - "integrity": "sha512-wheIYdr4NYML61AjC8MKj/2jrR/kDQri/CIpVoZwldwhnIrD/j9jIU5bJ8yBKuB2VhpFV7Ab6G2XkBjv9r9Zzw==" + "version": "20.4.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.4.5.tgz", + "integrity": "sha512-rt40Nk13II9JwQBdeYqmbn2Q6IVTA5uPhvSO+JVqdXw/6/4glI6oR9ezty/A9Hg5u7JH4OmYmuQ+XvjKm0Datg==" }, "node_modules/@types/ws": { "version": "8.5.5", @@ -237,9 +237,9 @@ } }, "node_modules/acorn": { - "version": "8.9.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.9.0.tgz", - "integrity": "sha512-jaVNAFBHNLXspO543WnNNPZFRtavh3skAkITqD0/2aeMkKZTN+254PyhwxFYrk3vQ1xfY+2wbesJMs/JC8/PwQ==", + "version": "8.10.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz", + "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==", "dev": true, "bin": { "acorn": "bin/acorn" @@ -460,9 +460,9 @@ } }, "node_modules/discord-api-types": { - "version": "0.37.47", - "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.37.47.tgz", - "integrity": "sha512-rNif8IAv6duS2z47BMXq/V9kkrLfkAoiwpFY3sLxxbyKprk065zqf3HLTg4bEoxRSmi+Lhc7yqGDrG8C3j8GFA==" + "version": "0.37.50", + "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.37.50.tgz", + "integrity": "sha512-X4CDiMnDbA3s3RaUXWXmgAIbY1uxab3fqe3qwzg5XutR3wjqi7M3IkgQbsIBzpqBN2YWr/Qdv7JrFRqSgb4TFg==" }, "node_modules/discord.js": { "version": "14.11.0", @@ -739,11 +739,10 @@ } }, "node_modules/lavashark": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/lavashark/-/lavashark-1.1.1.tgz", - "integrity": "sha512-bIbxomcPet5dV2LKsmSf5FkCDujIpusmTHRjMpcklbGwU4U6eAdE1yOeMVVkEgq7OhJXzEHmrXzFawvFHrsrBA==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/lavashark/-/lavashark-1.2.0.tgz", + "integrity": "sha512-Sb73k1tdfRbVZTac0OJcKOjvx6uQTi7if9CXY2PD1WqnfMuzPbx8/TjuenDtF+v71XkMBb5nDMtDcdzAbuwjFw==", "dependencies": { - "discord.js": "^14.11.0", "undici": "^5.22.1", "ws": "^8.13.0" }, @@ -1159,9 +1158,9 @@ } }, "node_modules/tslib": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.0.tgz", - "integrity": "sha512-7At1WUettjcSRHXCyYtTselblcHl9PJFFVKiCAy/bY97+BPZXSQ2wbq0P9s8tK2G7dFQfNnlJnPAiArVBVBsfA==" + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.1.tgz", + "integrity": "sha512-t0hLfiEKfMUoqhG+U1oid7Pva4bbDPHYfJNiB7BiIjRkj1pyC++4N3huJfqY6aRH6VTB0rvtzQwjM4K6qpfOig==" }, "node_modules/type-is": { "version": "1.6.18", @@ -1176,16 +1175,16 @@ } }, "node_modules/typescript": { - "version": "4.9.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", - "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.1.6.tgz", + "integrity": "sha512-zaWCozRZ6DLEWAWFrVDz1H6FVXzUSfTy5FUMWsQlU8Ym5JP9eO4xkTIROFCQvhQf61z6O/G6ugw3SgAnvvm+HA==", "dev": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" }, "engines": { - "node": ">=4.2.0" + "node": ">=14.17" } }, "node_modules/undici": { diff --git a/package.json b/package.json index 9ebd3c9..404a861 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "description": "Discord Music Bot", "main": "/src/index.ts", "scripts": { - "start": "node ./dist/src/index.js", + "start": "npm run build && node ./dist/src/index.js", "build": "tsc", "dev": "ts-node ./src/index.ts" }, @@ -23,12 +23,12 @@ "discord.js": "^14.11.0", "dotenv": "^16.0.3", "express": "^4.18.2", - "lavashark": "^1.1.1" + "lavashark": "^1.2.0" }, "devDependencies": { - "@types/node": "^20.3.2", + "@types/node": "^20.4.5", "ts-node": "^10.9.1", - "typescript": "^4.9.5" + "typescript": "^5.1.6" }, "engines": { "node": ">=16.13.0" From 12afdb9b0d7979395722a088fd2f2dd19d966206 Mon Sep 17 00:00:00 2001 From: hmes98318 <52697423+hmes98318@users.noreply.github.com> Date: Fri, 28 Jul 2023 15:03:59 +0800 Subject: [PATCH 45/64] Refactor dashboard destory method --- src/commands/leave.ts | 4 ++-- src/dashboard/destroy.ts | 4 ++-- src/events/discord/interactionCreate.ts | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/commands/leave.ts b/src/commands/leave.ts index 740e930..5b59abb 100644 --- a/src/commands/leave.ts +++ b/src/commands/leave.ts @@ -25,7 +25,7 @@ export const execute = async (client: Client, message: Message) => { else { player.queue.clear(); await player.skip(); - await dashboard.destroy(client, player); + await dashboard.destroy(player, client.config.embedsColor); } return message.react('šŸ‘'); @@ -44,7 +44,7 @@ export const slashExecute = async (client: Client, interaction: ChatInputCommand else { player.queue.clear(); await player.skip(); - await dashboard.destroy(client, player); + await dashboard.destroy(player, client.config.embedsColor); } return interaction.editReply('āœ… | Bot leave.'); diff --git a/src/dashboard/destroy.ts b/src/dashboard/destroy.ts index ae34024..af616d0 100644 --- a/src/dashboard/destroy.ts +++ b/src/dashboard/destroy.ts @@ -4,10 +4,10 @@ import { Player } from "lavashark"; import { embeds } from "../embeds"; -async function destroy(client: Client, player: Player) { +async function destroy(player: Player, embedsColor: string | number) { try { await player.dashboard!.edit({ - embeds: [embeds.disconnect(client.config.embedsColor)], + embeds: [embeds.disconnect(embedsColor)], components: [] }); } catch (error) { diff --git a/src/events/discord/interactionCreate.ts b/src/events/discord/interactionCreate.ts index 912a4e5..a53382c 100644 --- a/src/events/discord/interactionCreate.ts +++ b/src/events/discord/interactionCreate.ts @@ -153,7 +153,7 @@ export default async (client: Client, interaction: Interaction) => { else { player.queue.clear(); await player.skip(); - await dashboard.destroy(client, player); + await dashboard.destroy(player, client.config.embedsColor); } await interaction.reply({ content: 'āœ… | Bot leave.', ephemeral: true, components: [] }); From 7b425bae7de54ca7dffa93f453df06014b4e41b4 Mon Sep 17 00:00:00 2001 From: hmes98318 <52697423+hmes98318@users.noreply.github.com> Date: Fri, 28 Jul 2023 15:04:59 +0800 Subject: [PATCH 46/64] Refactor Player.addTracks and Player.repeatMode --- src/commands/play.ts | 20 ++++++------------- src/commands/queue.ts | 10 ++++++---- src/commands/remove.ts | 10 ++++++---- src/commands/search.ts | 26 ++++++++----------------- src/events/discord/interactionCreate.ts | 2 +- 5 files changed, 27 insertions(+), 41 deletions(-) diff --git a/src/commands/play.ts b/src/commands/play.ts index 20864b0..0d8ba9f 100644 --- a/src/commands/play.ts +++ b/src/commands/play.ts @@ -48,7 +48,7 @@ export const execute = async (client: Client, message: Message, args: string[]) }); // Connects to the voice channel - player.connect(); + await player.connect(); // Intial dashboard if (!player.dashboard) await dashboard.initial(client, message, player); @@ -59,18 +59,14 @@ export const execute = async (client: Client, message: Message, args: string[]) if (res.loadType === 'PLAYLIST_LOADED') { - for (const track of res.tracks) { - track.setRequester(message.author); - player.queue.add(track); - } + player.addTracks(res.tracks, message.author); message.reply(`Playlist \`${res.playlistInfo.name}\` loaded!`); } else { const track = res.tracks[0]; - track.setRequester(message.author); + player.addTracks(track, message.author); - player.queue.add(track); message.reply(`Queued \`${track.title}\``); } @@ -109,7 +105,7 @@ export const slashExecute = async (client: Client, interaction: ChatInputCommand }); // Connects to the voice channel - player.connect(); + await player.connect(); // Intial dashboard if (!player.dashboard) await dashboard.initial(client, interaction, player); @@ -120,18 +116,14 @@ export const slashExecute = async (client: Client, interaction: ChatInputCommand if (res.loadType === 'PLAYLIST_LOADED') { - for (const track of res.tracks) { - track.setRequester(interaction.user); - player.queue.add(track); - } + player.addTracks(res.tracks, interaction.user); interaction.editReply(`Playlist \`${res.playlistInfo.name}\` loaded!`); } else { const track = res.tracks[0]; - track.setRequester(interaction.user); + player.addTracks(track, interaction.user); - player.queue.add(track); interaction.editReply(`Queued \`${track.title}\``); } diff --git a/src/commands/queue.ts b/src/commands/queue.ts index 90e6e35..e81ef6e 100644 --- a/src/commands/queue.ts +++ b/src/commands/queue.ts @@ -34,10 +34,11 @@ export const execute = async (client: Client, message: Message) => { tracksQueue = tracks.join('\n'); } - let repeatMode = player.queueRepeat ? 'All' : (player.trackRepeat ? 'One' : 'Off'); + const methods = ['Off', 'Single', 'All']; + const repeatMode = player.repeatMode; return message.reply({ - embeds: [embeds.queue(client.config.embedsColor, nowplaying, tracksQueue, repeatMode)], + embeds: [embeds.queue(client.config.embedsColor, nowplaying, tracksQueue, methods[repeatMode])], allowedMentions: { repliedUser: false } }); } @@ -64,10 +65,11 @@ export const slashExecute = async (client: Client, interaction: ChatInputCommand tracksQueue = tracks.join('\n'); } - let repeatMode = player.queueRepeat ? 'All' : (player.trackRepeat ? 'One' : 'Off'); + const methods = ['Off', 'Single', 'All']; + const repeatMode = player.repeatMode; return interaction.editReply({ - embeds: [embeds.queue(client.config.embedsColor, nowplaying, tracksQueue, repeatMode)], + embeds: [embeds.queue(client.config.embedsColor, nowplaying, tracksQueue, methods[repeatMode])], allowedMentions: { repliedUser: false } }); } \ No newline at end of file diff --git a/src/commands/remove.ts b/src/commands/remove.ts index 534dff9..17b9295 100644 --- a/src/commands/remove.ts +++ b/src/commands/remove.ts @@ -87,13 +87,14 @@ export const execute = async (client: Client, message: Message, args: string[]) tracksQueue = tracks.join('\n'); } - let repeatMode = player.queueRepeat ? 'All' : (player.trackRepeat ? 'One' : 'Off'); + const methods = ['Off', 'Single', 'All']; + const repeatMode = player.repeatMode; const instruction = `Choose a song from **1** to **${tracks.length}** to **remove** or enter others to cancel selection. ā¬‡ļø`; await message.react('šŸ‘'); await message.reply({ content: instruction, - embeds: [embeds.removeList(client.config.embedsColor, nowplaying, tracksQueue, repeatMode)], + embeds: [embeds.removeList(client.config.embedsColor, nowplaying, tracksQueue, methods[repeatMode])], allowedMentions: { repliedUser: false } }); @@ -190,12 +191,13 @@ export const slashExecute = async (client: Client, interaction: ChatInputCommand tracksQueue = tracks.join('\n'); } - let repeatMode = player.queueRepeat ? 'All' : (player.trackRepeat ? 'One' : 'Off'); + const methods = ['Off', 'Single', 'All']; + const repeatMode = player.repeatMode; const instruction = `Choose a song from **1** to **${tracks.length}** to **remove** or enter others to cancel selection. ā¬‡ļø`; await interaction.editReply({ content: instruction, - embeds: [embeds.removeList(client.config.embedsColor, nowplaying, tracksQueue, repeatMode)], + embeds: [embeds.removeList(client.config.embedsColor, nowplaying, tracksQueue, methods[repeatMode])], allowedMentions: { repliedUser: false } }); diff --git a/src/commands/search.ts b/src/commands/search.ts index 6b753bf..85d2779 100644 --- a/src/commands/search.ts +++ b/src/commands/search.ts @@ -55,7 +55,7 @@ export const execute = async (client: Client, message: Message, args: string[]) }); // Connects to the voice channel - player.connect(); + await player.connect(); } catch (error) { console.log(error); return message.reply({ content: `āŒ | I can't join voice channel.`, allowedMentions: { repliedUser: false } }); @@ -66,10 +66,7 @@ export const execute = async (client: Client, message: Message, args: string[]) if (res.loadType === 'PLAYLIST_LOADED') { - for (const track of res.tracks) { - track.setRequester(client.user); - player.queue.add(track); - } + player.addTracks(res.tracks, message.author); if (!player.playing) await player.play() .catch((error: any) => { @@ -82,9 +79,7 @@ export const execute = async (client: Client, message: Message, args: string[]) } else if (res.tracks.length === 1) { const track = res.tracks[0]; - track.setRequester(client.user); - - player.queue.add(track); + player.addTracks(track, message.author); if (!player.playing) await player.play() .catch((error: any) => { @@ -117,7 +112,7 @@ export const execute = async (client: Client, message: Message, args: string[]) collector.on("collect", async (i: StringSelectMenuInteraction) => { if (i.customId != "musicSelect") return; - player.queue.add(res.tracks.find(x => x.uri == i.values[0])!); + player.addTracks(res.tracks.find(x => x.uri == i.values[0])!, message.author); if (!player.playing) await player.play() .catch((error: any) => { @@ -164,7 +159,7 @@ export const slashExecute = async (client: Client, interaction: ChatInputCommand }); // Connects to the voice channel - player.connect(); + await player.connect(); } catch (error) { console.log(error); return interaction.editReply({ content: `āŒ | I can't join voice channel.`, allowedMentions: { repliedUser: false } }); @@ -173,10 +168,7 @@ export const slashExecute = async (client: Client, interaction: ChatInputCommand if (res.loadType === 'PLAYLIST_LOADED') { - for (const track of res.tracks) { - track.setRequester(client.user); - player.queue.add(track); - } + player.addTracks(res.tracks, interaction.user); if (!player.playing) await player.play() .catch((error: any) => { @@ -189,9 +181,7 @@ export const slashExecute = async (client: Client, interaction: ChatInputCommand } else if (res.tracks.length === 1) { const track = res.tracks[0]; - track.setRequester(client.user); - - player.queue.add(track); + player.addTracks(track, interaction.user); if (!player.playing) await player.play() .catch((error: any) => { @@ -224,7 +214,7 @@ export const slashExecute = async (client: Client, interaction: ChatInputCommand collector.on("collect", async (i: StringSelectMenuInteraction) => { if (i.customId != "musicSelect") return; - player.queue.add(res.tracks.find(x => x.uri == i.values[0])!); + player.addTracks(res.tracks.find(x => x.uri == i.values[0])!, interaction.user); if (!player.playing) await player.play() .catch((error: any) => { diff --git a/src/events/discord/interactionCreate.ts b/src/events/discord/interactionCreate.ts index a53382c..ecfb472 100644 --- a/src/events/discord/interactionCreate.ts +++ b/src/events/discord/interactionCreate.ts @@ -73,7 +73,7 @@ export default async (client: Client, interaction: Interaction) => { case 'Dashboard-Skip': { const playing = !(player.paused); - const repeatMode = player.queueRepeat ? RepeatMode.QUEUE : (player.trackRepeat ? RepeatMode.TRACK : RepeatMode.OFF); + const repeatMode = player.repeatMode; if (repeatMode === RepeatMode.TRACK) { player.setRepeatMode(RepeatMode.OFF); From bfda49f4f2d97c91ec73aa56cd1cceae0f16abe6 Mon Sep 17 00:00:00 2001 From: hmes98318 <52697423+hmes98318@users.noreply.github.com> Date: Fri, 28 Jul 2023 16:40:51 +0800 Subject: [PATCH 47/64] Refactor remove index calculation --- src/commands/remove.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/commands/remove.ts b/src/commands/remove.ts index 17b9295..b3cd651 100644 --- a/src/commands/remove.ts +++ b/src/commands/remove.ts @@ -42,7 +42,7 @@ export const execute = async (client: Client, message: Message, args: string[]) if (args.length === 1) { // +rm 1 let index = parseInt(args[0]); - SUCCESS = player.queue.remove(index); + SUCCESS = player.queue.remove(index - 1); if (!SUCCESS) { return message.react('āŒ'); @@ -58,7 +58,7 @@ export const execute = async (client: Client, message: Message, args: string[]) else if (args.length === 2) { // +rm 3 4 let index1 = parseInt(args[0]), index2 = parseInt(args[1]); - SUCCESS = player.queue.remove(index1, index2); + SUCCESS = player.queue.remove(index1 - 1, index2 - index1 + 1); if (!SUCCESS) { return message.react('āŒ'); @@ -114,7 +114,7 @@ export const execute = async (client: Client, message: Message, args: string[]) } await query.react('šŸ‘'); - player.queue.remove(index); + player.queue.remove(index - 1); await query.reply({ embeds: [embeds.removeTrack(client.config.embedsColor, tracks[index - 1])], @@ -150,7 +150,7 @@ export const slashExecute = async (client: Client, interaction: ChatInputCommand if ((index1 === null && index2 !== null) || (index1 !== null && index2 === null)) { // +rm 1 let index = index1 || index2; - SUCCESS = player.queue.remove(index!); + SUCCESS = player.queue.remove(index! - 1); if (!SUCCESS) { return interaction.editReply('āŒ | Music remove failed.'); @@ -163,7 +163,7 @@ export const slashExecute = async (client: Client, interaction: ChatInputCommand } } else if (index1 !== null && index2 !== null) { // +rm 3 4 - SUCCESS = player.queue.remove(index1, index2); + SUCCESS = player.queue.remove(index1 - 1, index2 - index1 + 1); if (!SUCCESS) { return interaction.editReply('āŒ | Music remove failed.'); @@ -217,7 +217,7 @@ export const slashExecute = async (client: Client, interaction: ChatInputCommand } await query.react('šŸ‘'); - player.queue.remove(index); + player.queue.remove(index - 1); await query.reply({ embeds: [embeds.removeTrack(client.config.embedsColor, tracks[index - 1])], From 444b1e6f59272fe07cd0a247f30fd9112892ae8d Mon Sep 17 00:00:00 2001 From: hmes98318 <52697423+hmes98318@users.noreply.github.com> Date: Fri, 28 Jul 2023 16:52:15 +0800 Subject: [PATCH 48/64] Refactor dashboard initial method --- src/dashboard/initial.ts | 21 +++------------------ 1 file changed, 3 insertions(+), 18 deletions(-) diff --git a/src/dashboard/initial.ts b/src/dashboard/initial.ts index c5c5036..97ef80a 100644 --- a/src/dashboard/initial.ts +++ b/src/dashboard/initial.ts @@ -1,14 +1,6 @@ -import { - ActionRowBuilder, - ButtonBuilder, - ButtonStyle, - ChatInputCommandInteraction, - Client, - Message -} from "discord.js"; +import { ChatInputCommandInteraction, Client, Message } from "discord.js"; import { Player } from "lavashark"; -import { cst } from "../utils/constants"; import { embeds } from "../embeds"; @@ -24,19 +16,12 @@ async function initial(client: Client, interactionOrMessage: ChatInputCommandInt channel = (interactionOrMessage as ChatInputCommandInteraction).channel; } else { - throw TypeError("Invalid Interaction or Message type"); + throw new TypeError("Invalid Interaction or Message type"); } - const playPauseButton = new ButtonBuilder().setCustomId('Dashboard-PlayPause').setEmoji(cst.button.pause).setStyle(ButtonStyle.Secondary); - const skipButton = new ButtonBuilder().setCustomId('Dashboard-Skip').setEmoji(cst.button.skip).setStyle(ButtonStyle.Secondary); - const stopButton = new ButtonBuilder().setCustomId('Dashboard-Stop').setEmoji(cst.button.stop).setStyle(ButtonStyle.Danger); - const loopButton = new ButtonBuilder().setCustomId('Dashboard-Loop').setEmoji(cst.button.loop).setStyle(ButtonStyle.Secondary); - const shuffleButton = new ButtonBuilder().setCustomId('Dashboard-Shuffle').setEmoji(cst.button.shuffle).setStyle(ButtonStyle.Secondary); - const row = new ActionRowBuilder().addComponents(playPauseButton, skipButton, stopButton, loopButton, shuffleButton); - player.dashboard = await channel!.send({ embeds: [embeds.connected(client.config.embedsColor)], - components: [row] + components: [] }); } From 0f9262a7f761c6ee12de2bcbba48c3f583a50f06 Mon Sep 17 00:00:00 2001 From: hmes98318 <52697423+hmes98318@users.noreply.github.com> Date: Fri, 28 Jul 2023 17:04:00 +0800 Subject: [PATCH 49/64] Add handle `trackAdd` event --- src/commands/play.ts | 15 +++++---------- src/commands/search.ts | 11 ++++++++++- src/embeds/index.ts | 4 +++- src/embeds/queue.embed.ts | 26 +++++++++++++++++++++++++- src/events/lavashark/trackAdd.ts | 32 ++++++++++++++++++++++++++++++++ src/index.ts | 23 ++++++++++++++--------- 6 files changed, 89 insertions(+), 22 deletions(-) create mode 100644 src/events/lavashark/trackAdd.ts diff --git a/src/commands/play.ts b/src/commands/play.ts index 0d8ba9f..adc9223 100644 --- a/src/commands/play.ts +++ b/src/commands/play.ts @@ -49,6 +49,7 @@ export const execute = async (client: Client, message: Message, args: string[]) // Connects to the voice channel await player.connect(); + player.metadata = message; // Intial dashboard if (!player.dashboard) await dashboard.initial(client, message, player); @@ -60,14 +61,10 @@ export const execute = async (client: Client, message: Message, args: string[]) if (res.loadType === 'PLAYLIST_LOADED') { player.addTracks(res.tracks, message.author); - - message.reply(`Playlist \`${res.playlistInfo.name}\` loaded!`); } else { const track = res.tracks[0]; player.addTracks(track, message.author); - - message.reply(`Queued \`${track.title}\``); } if (!player.playing) await player.play() @@ -106,6 +103,7 @@ export const slashExecute = async (client: Client, interaction: ChatInputCommand // Connects to the voice channel await player.connect(); + player.metadata = interaction; // Intial dashboard if (!player.dashboard) await dashboard.initial(client, interaction, player); @@ -116,15 +114,11 @@ export const slashExecute = async (client: Client, interaction: ChatInputCommand if (res.loadType === 'PLAYLIST_LOADED') { - player.addTracks(res.tracks, interaction.user); - - interaction.editReply(`Playlist \`${res.playlistInfo.name}\` loaded!`); + player.addTracks(res.tracks, interaction.user); } else { const track = res.tracks[0]; player.addTracks(track, interaction.user); - - interaction.editReply(`Queued \`${track.title}\``); } if (!player.playing) await player.play() @@ -133,5 +127,6 @@ export const slashExecute = async (client: Client, interaction: ChatInputCommand return interaction.editReply({ content: `āŒ | I can't play this track.`, allowedMentions: { repliedUser: false } }); }); - return player.filters.setVolume(client.config.defaultVolume); + player.filters.setVolume(client.config.defaultVolume); + return interaction.editReply({ content: "āœ… | Music added.", allowedMentions: { repliedUser: false } }); } \ No newline at end of file diff --git a/src/commands/search.ts b/src/commands/search.ts index 85d2779..2706e91 100644 --- a/src/commands/search.ts +++ b/src/commands/search.ts @@ -9,6 +9,7 @@ import { StringSelectMenuInteraction, } from "discord.js"; import { Player } from "lavashark"; +import { dashboard } from "../dashboard"; export const name = 'search'; @@ -56,6 +57,10 @@ export const execute = async (client: Client, message: Message, args: string[]) // Connects to the voice channel await player.connect(); + player.metadata = message; + + // Intial dashboard + if (!player.dashboard) await dashboard.initial(client, message, player); } catch (error) { console.log(error); return message.reply({ content: `āŒ | I can't join voice channel.`, allowedMentions: { repliedUser: false } }); @@ -112,7 +117,7 @@ export const execute = async (client: Client, message: Message, args: string[]) collector.on("collect", async (i: StringSelectMenuInteraction) => { if (i.customId != "musicSelect") return; - player.addTracks(res.tracks.find(x => x.uri == i.values[0])!, message.author); + player.addTracks(res.tracks.find(x => x.uri == i.values[0])!, message.author); if (!player.playing) await player.play() .catch((error: any) => { @@ -160,6 +165,10 @@ export const slashExecute = async (client: Client, interaction: ChatInputCommand // Connects to the voice channel await player.connect(); + player.metadata = interaction; + + // Intial dashboard + if (!player.dashboard) await dashboard.initial(client, interaction, player); } catch (error) { console.log(error); return interaction.editReply({ content: `āŒ | I can't join voice channel.`, allowedMentions: { repliedUser: false } }); diff --git a/src/embeds/index.ts b/src/embeds/index.ts index 195767c..4e71919 100644 --- a/src/embeds/index.ts +++ b/src/embeds/index.ts @@ -1,7 +1,7 @@ import { connected, dashboard, disconnect } from "./dashboard.embed"; import { help } from "./help.embed"; import { ping } from "./ping.embed"; -import { queue } from "./queue.embed"; +import { addTrack, addPlaylist, queue } from "./queue.embed"; import { removeList, removeTrack } from "./remove.embed"; import { save } from "./save.embed"; import { server } from "./server.embed"; @@ -9,6 +9,8 @@ import { status } from "./status.embed"; const embeds = { + addTrack, + addPlaylist, connected, dashboard, disconnect, diff --git a/src/embeds/queue.embed.ts b/src/embeds/queue.embed.ts index 7a297c2..0a7fe4e 100644 --- a/src/embeds/queue.embed.ts +++ b/src/embeds/queue.embed.ts @@ -1,6 +1,30 @@ import { EmbedBuilder, HexColorString } from "discord.js"; +const addTrack = (embedsColor: HexColorString | string | number, title: string, subtitle: string, url: string, thumbnail: string) => { + const embed_ = new EmbedBuilder() + .setColor(embedsColor as HexColorString | number) + .setTitle(title) + .setURL(url) + .setThumbnail(thumbnail) + .addFields({ name: 'Added Track', value: subtitle, inline: true }) + .setTimestamp() + + return embed_; +} + +const addPlaylist = (embedsColor: HexColorString | string | number, title: string, subtitle: string, url: string, thumbnail: string) => { + const embed_ = new EmbedBuilder() + .setColor(embedsColor as HexColorString | number) + .setTitle(title) + .setURL(url) + .setThumbnail(thumbnail) + .addFields({ name: 'Added Playlist', value: subtitle, inline: true }) + .setTimestamp() + + return embed_; +} + const queue = (embedsColor: HexColorString | string | number, nowPlaying: string, queueList: string, repeatMode: string) => { const embed_ = new EmbedBuilder() .setColor(embedsColor as HexColorString | number) @@ -12,4 +36,4 @@ const queue = (embedsColor: HexColorString | string | number, nowPlaying: string return embed_; } -export { queue }; \ No newline at end of file +export { addTrack, addPlaylist, queue }; \ No newline at end of file diff --git a/src/events/lavashark/trackAdd.ts b/src/events/lavashark/trackAdd.ts new file mode 100644 index 0000000..3450c86 --- /dev/null +++ b/src/events/lavashark/trackAdd.ts @@ -0,0 +1,32 @@ +import { Client, Message } from "discord.js"; +import { Player, Track } from "lavashark"; + +import { dashboard } from "../../dashboard"; +import { embeds } from "../../embeds"; + + +export default async (client: Client, player: Player, tracks: Track | Track[]) => { + if (player.playing) { + if (Array.isArray(tracks)) { // PLAYLIST_LOADED + const playlist = tracks as unknown as Track[]; + const subtitle = `Author : **${playlist[0]?.author}**\nDuration **${playlist[0]?.duration.label}**\n`; + + await player.metadata?.channel?.send({ embeds: [embeds.addPlaylist(client.config.embedsColor, playlist[0].title, subtitle, playlist[0].uri, playlist[0].thumbnail!)] }) + } + else { + const track = tracks as Track; + const subtitle = `Author : **${track?.author}**\nDuration **${track?.duration.label}**\n`; + + await player.metadata?.channel?.send({ embeds: [embeds.addTrack(client.config.embedsColor, track.title, subtitle, track.uri, track.thumbnail!)] }) + } + + try { + await player.dashboard?.delete(); + } catch (error) { + console.log('Dashboard delete error:', error); + } + + await dashboard.initial(client, (player.metadata as Message), player); + await dashboard.update(client, player, player.current!); + } +}; \ No newline at end of file diff --git a/src/index.ts b/src/index.ts index f820243..bb5c4e0 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,19 +1,21 @@ import * as fs from 'fs'; import * as dotenv from 'dotenv'; -import { Client, Collection, GatewayIntentBits, Message } from 'discord.js'; +import { + ChatInputCommandInteraction, + Client, + Collection, + GatewayIntentBits, + Message +} from 'discord.js'; import { LavaShark } from "lavashark"; import consoleStamp from 'console-stamp'; import { cst } from "./utils/constants"; import nodeList from "../node-list.json"; -import { Config, Info } from "./@types"; -import { EventListeners } from 'lavashark/typings/src/@types'; - - -dotenv.config(); -consoleStamp(console, { format: ':date(yyyy/mm/dd HH:MM:ss)' }); +import type { Config, Info } from "./@types"; +import type { EventListeners } from 'lavashark/typings/src/@types'; declare module 'discord.js' { @@ -26,11 +28,14 @@ declare module 'discord.js' { }; declare module 'lavashark' { export interface Player { - dashboard: Message | null + dashboard: Message | null, + metadata: Message | ChatInputCommandInteraction | null } }; +dotenv.config(); +consoleStamp(console, { format: ':date(yyyy/mm/dd HH:MM:ss)' }); let client = new Client({ @@ -52,7 +57,7 @@ client.config = cst.config; -const setEnvironment = (): Promise => { +const setEnvironment = () => { return new Promise((resolve, _reject) => { client.config.name = process.env.BOT_NAME ?? client.config.name; client.config.prefix = process.env.PREFIX ?? client.config.prefix; From c6047d0b2411712c02386164a5738230ac2d0578 Mon Sep 17 00:00:00 2001 From: hmes98318 <52697423+hmes98318@users.noreply.github.com> Date: Fri, 28 Jul 2023 20:32:09 +0800 Subject: [PATCH 50/64] Add initial nodes stats check --- src/index.ts | 22 +++++++++++++++++++--- src/utils/constants.ts | 3 ++- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/src/index.ts b/src/index.ts index bb5c4e0..50d25cb 100644 --- a/src/index.ts +++ b/src/index.ts @@ -15,6 +15,7 @@ import { cst } from "./utils/constants"; import nodeList from "../node-list.json"; import type { Config, Info } from "./@types"; +import type { Node } from "lavashark"; import type { EventListeners } from 'lavashark/typings/src/@types'; @@ -129,30 +130,45 @@ const loadCommands = () => { return new Promise(async (resolve, reject) => { const jsFiles = fs.readdirSync(`${__dirname}/commands/`); - console.log(`+---------------------------+`); + console.log(`+--------------------------------+`); for (const file of jsFiles) { try { const command = await import(`${__dirname}/commands/${file}`); client.commands.set(command.name.toLowerCase(), command); - console.log(`| Loaded Command ${command.name.toLowerCase().padEnd(10, ' ')} |`); + console.log(`| Loaded Command ${command.name.toLowerCase().padEnd(15, ' ')} |`); } catch (error) { reject(error); } } - console.log(`+---------------------------+`); + console.log(`+--------------------------------+`); console.log(`${cst.color.grey}-- loading Commands finished --${cst.color.white}`); resolve(); }); } +const checkNodesStats = async (nodes: Node[]) => { + console.log(`-> Checking stats for all nodes ......`); + console.log(`+--------------------------------+`); + for (const node of nodes) { + try { + await node.getStats(); + console.log(`| ${node.identifier}: ${cst.color.green}CONNECTED${cst.color.white}`.padEnd(42, ' ') + '|'); + } catch (_) { + console.log(`| ${node.identifier}: ${cst.color.red}DISCONNECTED${cst.color.white}`.padEnd(42, ' ') + '|'); + } + } + console.log(`+--------------------------------+`); + console.log(`${cst.color.grey}-- All node stats have been checked --${cst.color.white}`); +}; Promise.resolve() .then(() => setEnvironment()) .then(() => loadEvents()) .then(() => loadLavaSharkEvents()) .then(() => loadCommands()) + .then(() => checkNodesStats(client.lavashark.nodes)) .then(() => { console.log(`${cst.color.green}*** All loaded successfully ***${cst.color.white}`); client.login(process.env.TOKEN); diff --git a/src/utils/constants.ts b/src/utils/constants.ts index 9f0174b..ab13892 100644 --- a/src/utils/constants.ts +++ b/src/utils/constants.ts @@ -20,7 +20,8 @@ export const cst = { white : '\x1B[0m', grey : '\x1B[2m', green : '\x1B[32m', - cyan : '\x1B[36m' + cyan : '\x1B[36m', + red : '\x1B[31m' }, // Dashboard button icon button: { From 4fbb705a4f5e81fbbfddd073d37a50b22eccfc67 Mon Sep 17 00:00:00 2001 From: hmes98318 <52697423+hmes98318@users.noreply.github.com> Date: Fri, 28 Jul 2023 21:02:31 +0800 Subject: [PATCH 51/64] Update handling of LavaShark events --- src/events/lavashark/error.ts | 7 +++++++ src/events/lavashark/playerConnect.ts | 4 +--- src/events/lavashark/playerDestroy.ts | 4 +--- src/events/lavashark/queueEnd.ts | 4 +--- 4 files changed, 10 insertions(+), 9 deletions(-) create mode 100644 src/events/lavashark/error.ts diff --git a/src/events/lavashark/error.ts b/src/events/lavashark/error.ts new file mode 100644 index 0000000..80def76 --- /dev/null +++ b/src/events/lavashark/error.ts @@ -0,0 +1,7 @@ +import { Client } from "discord.js"; +import { Node } from "lavashark"; + + +export default async (_client:Client, node: Node, error: any) => { + console.error(`[LavaShark] Error on node "${node.identifier}":`, error.message); +}; \ No newline at end of file diff --git a/src/events/lavashark/playerConnect.ts b/src/events/lavashark/playerConnect.ts index c2b10cf..818d707 100644 --- a/src/events/lavashark/playerConnect.ts +++ b/src/events/lavashark/playerConnect.ts @@ -2,7 +2,5 @@ import { Client } from "discord.js"; import { Player } from "lavashark"; -export default async (client: Client, player: Player): Promise => { - console.log('// -------- player Connect -------- //'); - +export default async (_client: Client, _player: Player): Promise => { }; \ No newline at end of file diff --git a/src/events/lavashark/playerDestroy.ts b/src/events/lavashark/playerDestroy.ts index 3cb85f8..e259aac 100644 --- a/src/events/lavashark/playerDestroy.ts +++ b/src/events/lavashark/playerDestroy.ts @@ -5,7 +5,5 @@ import { dashboard } from "../../dashboard"; export default async (client: Client, player: Player) => { - console.log('// -------- player Destroy -------- //'); - - await dashboard.destroy(client, player); + await dashboard.destroy(player, client.config.embedsColor); }; \ No newline at end of file diff --git a/src/events/lavashark/queueEnd.ts b/src/events/lavashark/queueEnd.ts index a9cae5b..3607262 100644 --- a/src/events/lavashark/queueEnd.ts +++ b/src/events/lavashark/queueEnd.ts @@ -5,11 +5,9 @@ import { dashboard } from "../../dashboard"; export default async (client: Client, player: Player) => { - console.log('// -------- queue end -------- //'); - if (client.config.autoLeave) { await player.destroy(); } - await dashboard.destroy(client, player); + await dashboard.destroy(player, client.config.embedsColor); }; \ No newline at end of file From 9bf3d2b87d5fa3b2126c406c5cd77a88e31c2a9a Mon Sep 17 00:00:00 2001 From: hmes98318 <52697423+hmes98318@users.noreply.github.com> Date: Sat, 29 Jul 2023 00:12:48 +0800 Subject: [PATCH 52/64] Add handling of unhandledRejection event --- src/index.ts | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/index.ts b/src/index.ts index 50d25cb..9c5126f 100644 --- a/src/index.ts +++ b/src/index.ts @@ -14,8 +14,8 @@ import consoleStamp from 'console-stamp'; import { cst } from "./utils/constants"; import nodeList from "../node-list.json"; -import type { Config, Info } from "./@types"; import type { Node } from "lavashark"; +import type { Config, Info } from "./@types"; import type { EventListeners } from 'lavashark/typings/src/@types'; @@ -27,6 +27,7 @@ declare module 'discord.js' { info: Info } }; + declare module 'lavashark' { export interface Player { dashboard: Message | null, @@ -172,4 +173,11 @@ Promise.resolve() .then(() => { console.log(`${cst.color.green}*** All loaded successfully ***${cst.color.white}`); client.login(process.env.TOKEN); - }); \ No newline at end of file + }); + + + + +process.on('unhandledRejection', (error) => { + console.error('Unhandled promise rejection:', error); +}); \ No newline at end of file From 15546e772afdbfac34ea5da1ad0452f7da8f58e1 Mon Sep 17 00:00:00 2001 From: hmes98318 <52697423+hmes98318@users.noreply.github.com> Date: Sat, 29 Jul 2023 16:43:29 +0800 Subject: [PATCH 53/64] Add `nodestatus` command --- src/commands/nodestatus.ts | 69 ++++++++++++++++++++++++++++++++++++++ src/commands/status.ts | 4 +-- src/embeds/index.ts | 5 +-- src/embeds/status.embed.ts | 15 +++++++-- 4 files changed, 87 insertions(+), 6 deletions(-) create mode 100644 src/commands/nodestatus.ts diff --git a/src/commands/nodestatus.ts b/src/commands/nodestatus.ts new file mode 100644 index 0000000..ec4a218 --- /dev/null +++ b/src/commands/nodestatus.ts @@ -0,0 +1,69 @@ +import { ChatInputCommandInteraction, Client, Message } from "discord.js"; +import { embeds } from "../embeds"; + + +export const name = 'nodestatus'; +export const aliases = ['node', 'nodes', 'nodesstatus']; +export const description = 'Show nodes connection status'; +export const usage = 'nodestatus'; +export const voiceChannel = false; +export const showHelp = true; +export const sendTyping = true; +export const options = []; + + +export const execute = async (client: Client, message: Message) => { + const nodes = client.lavashark.nodes; + const pingList = await client.lavashark.nodesPing(); + const nodesStatus = []; + let healthValue = 0; + + for (let i = 0; i < nodes.length; i++) { + const node = nodes[i]; + const ping = pingList[i]; + + if (ping === -1) { + healthValue++; + nodesStatus.push({ name: `āŒ ${node.identifier}`, value: '**DISCONNECTED**' }); + } + else { + nodesStatus.push({ name: `āœ… ${node.identifier}`, value: `ping: **${ping}ms**` }); + } + } + console.log('nodesStatus', nodesStatus); + + const nodeHealth = healthValue === 0 ? 'All nodes are active' : `āš ļø There are ${healthValue} nodes disconnected`; + + return message.reply({ + embeds: [embeds.nodesStatus(client.config.embedsColor, nodeHealth, nodesStatus)], + allowedMentions: { repliedUser: false } + }); +} + +export const slashExecute = async (client: Client, interaction: ChatInputCommandInteraction) => { + const nodes = client.lavashark.nodes; + const pingList = await client.lavashark.nodesPing(); + const nodesStatus = []; + let healthValue = 0; + + for (let i = 0; i < nodes.length; i++) { + const node = nodes[i]; + const ping = pingList[i]; + + if (ping === -1) { + nodesStatus.push({ name: `āŒ ${node.identifier}`, value: 'DISCONNECTED' }); + healthValue++; + } + else { + nodesStatus.push({ name: `āœ… ${node.identifier}`, value: `ping: ${ping}ms` }); + } + } + console.log('nodesStatus', nodesStatus); + + const nodeHealth = healthValue === 0 ? 'āœ… All nodes are active' : `āš ļø There are ${healthValue} nodes disconnected`; + + return interaction.editReply({ + embeds: [embeds.nodesStatus(client.config.embedsColor, nodeHealth, nodesStatus)], + allowedMentions: { repliedUser: false } + }); +} \ No newline at end of file diff --git a/src/commands/status.ts b/src/commands/status.ts index 789a82f..78f2a80 100644 --- a/src/commands/status.ts +++ b/src/commands/status.ts @@ -28,7 +28,7 @@ export const execute = async (client: Client, message: Message) => { } return message.reply({ - embeds: [embeds.status(client.config, client.info, systemStatus)], + embeds: [embeds.botStatus(client.config, client.info, systemStatus)], allowedMentions: { repliedUser: false } }); } @@ -47,7 +47,7 @@ export const slashExecute = async (client: Client, interaction: ChatInputCommand } return interaction.editReply({ - embeds: [embeds.status(client.config, client.info, systemStatus)], + embeds: [embeds.botStatus(client.config, client.info, systemStatus)], allowedMentions: { repliedUser: false } }); } \ No newline at end of file diff --git a/src/embeds/index.ts b/src/embeds/index.ts index 4e71919..10918da 100644 --- a/src/embeds/index.ts +++ b/src/embeds/index.ts @@ -5,23 +5,24 @@ import { addTrack, addPlaylist, queue } from "./queue.embed"; import { removeList, removeTrack } from "./remove.embed"; import { save } from "./save.embed"; import { server } from "./server.embed"; -import { status } from "./status.embed"; +import { nodesStatus, botStatus } from "./status.embed"; const embeds = { addTrack, addPlaylist, + botStatus, connected, dashboard, disconnect, help, + nodesStatus, ping, queue, removeList, removeTrack, save, server, - status, }; export { embeds }; \ No newline at end of file diff --git a/src/embeds/status.embed.ts b/src/embeds/status.embed.ts index 4655333..810fda8 100644 --- a/src/embeds/status.embed.ts +++ b/src/embeds/status.embed.ts @@ -2,7 +2,7 @@ import { EmbedBuilder, HexColorString } from "discord.js"; import { Config, Info, SystemStatus } from "../@types"; -const status = (config: Config, info: Info, systemStatus: SystemStatus) => { +const botStatus = (config: Config, info: Info, systemStatus: SystemStatus) => { const cpuUsage = `${systemStatus.load.percent} \`${systemStatus.load.detail}\``; const ramUsage = `${systemStatus.memory.percent} \`${systemStatus.memory.detail}\``; const heapUsage = `${systemStatus.heap.percent} \`${systemStatus.heap.detail}\``; @@ -22,4 +22,15 @@ const status = (config: Config, info: Info, systemStatus: SystemStatus) => { return embed_; } -export { status }; \ No newline at end of file +const nodesStatus = (embedsColor: HexColorString | string | number, nodeHealth: string, nodesStatus: { name: string; value: string; }[]) => { + const embed_ = new EmbedBuilder() + .setColor(embedsColor as HexColorString | number) + .setTitle(`šŸ›°ļø Active Nodes`) + .setDescription(`**${nodeHealth}**\nā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”`) + .addFields(nodesStatus) + .setTimestamp(); + + return embed_; +} + +export { botStatus, nodesStatus }; \ No newline at end of file From 705efd6de74cfb4fbbebdbdf811e13e8495498f3 Mon Sep 17 00:00:00 2001 From: hmes98318 <52697423+hmes98318@users.noreply.github.com> Date: Sun, 30 Jul 2023 00:21:43 +0800 Subject: [PATCH 54/64] Update lavashark patch version --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 3deb156..3321d64 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,7 +13,7 @@ "discord.js": "^14.11.0", "dotenv": "^16.0.3", "express": "^4.18.2", - "lavashark": "^1.2.0" + "lavashark": "^1.2.1" }, "devDependencies": { "@types/node": "^20.4.5", @@ -739,9 +739,9 @@ } }, "node_modules/lavashark": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/lavashark/-/lavashark-1.2.0.tgz", - "integrity": "sha512-Sb73k1tdfRbVZTac0OJcKOjvx6uQTi7if9CXY2PD1WqnfMuzPbx8/TjuenDtF+v71XkMBb5nDMtDcdzAbuwjFw==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/lavashark/-/lavashark-1.2.1.tgz", + "integrity": "sha512-iFRSL2Pf/j2uAHk2phXujpKd13MO0XThtU9Jn6dEphp7Cu1Vlo2nUYbDzz0C3JRATPMLOiaX/U4Oc84b1KzIkg==", "dependencies": { "undici": "^5.22.1", "ws": "^8.13.0" diff --git a/package.json b/package.json index 404a861..79477c2 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,7 @@ "discord.js": "^14.11.0", "dotenv": "^16.0.3", "express": "^4.18.2", - "lavashark": "^1.2.0" + "lavashark": "^1.2.1" }, "devDependencies": { "@types/node": "^20.4.5", From 687572bb17c6385f15790b3368664a1fa218c9b3 Mon Sep 17 00:00:00 2001 From: hmes98318 <52697423+hmes98318@users.noreply.github.com> Date: Sun, 30 Jul 2023 00:22:19 +0800 Subject: [PATCH 55/64] Update nodesStatus embed --- src/embeds/status.embed.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/embeds/status.embed.ts b/src/embeds/status.embed.ts index 810fda8..c0de90c 100644 --- a/src/embeds/status.embed.ts +++ b/src/embeds/status.embed.ts @@ -25,7 +25,7 @@ const botStatus = (config: Config, info: Info, systemStatus: SystemStatus) => { const nodesStatus = (embedsColor: HexColorString | string | number, nodeHealth: string, nodesStatus: { name: string; value: string; }[]) => { const embed_ = new EmbedBuilder() .setColor(embedsColor as HexColorString | number) - .setTitle(`šŸ›°ļø Active Nodes`) + .setTitle(`šŸ›°ļø Nodes Status`) .setDescription(`**${nodeHealth}**\nā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”ā”`) .addFields(nodesStatus) .setTimestamp(); From 4bb77262542956e39585b372fb186f622b5aeb90 Mon Sep 17 00:00:00 2001 From: hmes98318 <52697423+hmes98318@users.noreply.github.com> Date: Sun, 30 Jul 2023 13:47:31 +0800 Subject: [PATCH 56/64] Update the node startup checker --- src/index.ts | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/src/index.ts b/src/index.ts index 9c5126f..f169475 100644 --- a/src/index.ts +++ b/src/index.ts @@ -151,19 +151,26 @@ const loadCommands = () => { const checkNodesStats = async (nodes: Node[]) => { console.log(`-> Checking stats for all nodes ......`); + + const pingList = await client.lavashark.nodesPing(); + console.log(`+--------------------------------+`); - for (const node of nodes) { - try { - await node.getStats(); - console.log(`| ${node.identifier}: ${cst.color.green}CONNECTED${cst.color.white}`.padEnd(42, ' ') + '|'); - } catch (_) { + for (let i = 0; i < nodes.length; i++) { + const node = nodes[i]; + const ping = pingList[i]; + + if (ping === -1) { console.log(`| ${node.identifier}: ${cst.color.red}DISCONNECTED${cst.color.white}`.padEnd(42, ' ') + '|'); } + else { + console.log(`| ${node.identifier}: ${cst.color.green}CONNECTED${cst.color.white}${cst.color.grey} (${ping}ms)${cst.color.white}`.padEnd(50, ' ') + '|'); + } } console.log(`+--------------------------------+`); console.log(`${cst.color.grey}-- All node stats have been checked --${cst.color.white}`); }; + Promise.resolve() .then(() => setEnvironment()) .then(() => loadEvents()) From f2c40632543c9a18790654ae50d8da05474e4cb1 Mon Sep 17 00:00:00 2001 From: hmes98318 <52697423+hmes98318@users.noreply.github.com> Date: Sun, 30 Jul 2023 15:12:10 +0800 Subject: [PATCH 57/64] Add blacklist util --- src/@types/index.ts | 1 + src/events/discord/interactionCreate.ts | 2 ++ src/events/discord/messageCreate.ts | 1 + src/events/discord/voiceStateUpdate.ts | 26 ++++++++++++++++--------- src/index.ts | 18 +++++++++++++++++ src/utils/constants.ts | 3 ++- 6 files changed, 41 insertions(+), 10 deletions(-) diff --git a/src/@types/index.ts b/src/@types/index.ts index 2b88900..96912a2 100644 --- a/src/@types/index.ts +++ b/src/@types/index.ts @@ -12,6 +12,7 @@ export interface Config { autoLeaveCooldown: number; displayVoiceState: boolean; port: number; + blacklist: string[]; } export interface Info { diff --git a/src/events/discord/interactionCreate.ts b/src/events/discord/interactionCreate.ts index ecfb472..983ac5b 100644 --- a/src/events/discord/interactionCreate.ts +++ b/src/events/discord/interactionCreate.ts @@ -15,6 +15,8 @@ import { dashboard } from "../../dashboard"; export default async (client: Client, interaction: Interaction) => { + if (client.config.blacklist && client.config.blacklist.includes(interaction.user.id)) return; + const guildMember = interaction.guild!.members.cache.get(interaction.user.id); const voiceChannel = guildMember!.voice.channel; diff --git a/src/events/discord/messageCreate.ts b/src/events/discord/messageCreate.ts index d602b4a..aec4ee0 100644 --- a/src/events/discord/messageCreate.ts +++ b/src/events/discord/messageCreate.ts @@ -6,6 +6,7 @@ export default async (client: Client, message: Message) => { const prefix = client.config.prefix; if (message.author.bot || message.channel.type !== ChannelType.GuildText) return; + if (client.config.blacklist && client.config.blacklist.includes(message.author.id)) return; if (message.content.indexOf(prefix) !== 0) return; diff --git a/src/events/discord/voiceStateUpdate.ts b/src/events/discord/voiceStateUpdate.ts index 356ef0a..55ac8b3 100644 --- a/src/events/discord/voiceStateUpdate.ts +++ b/src/events/discord/voiceStateUpdate.ts @@ -1,10 +1,18 @@ -import { Client, VoiceState } from "discord.js"; +import { Client, VoiceBasedChannel, VoiceState } from "discord.js"; let pool: any = []; +const checkBlacklistUsers = (channel: VoiceBasedChannel | null, blacklist: string[]) => { + if (!channel) return false; + const membersInChannel = channel.members.filter(member => !member.user.bot); + return membersInChannel.every(member => blacklist.includes(member.user.id)); +}; + + export default async (client: Client, oldState: VoiceState, newState: VoiceState) => { const display = client.config.displayVoiceState ?? true; + const blacklist = client.config.blacklist || []; if (newState.channelId === null) { if (display) console.log(`-- ${newState.member?.user.username} left channel`); @@ -18,8 +26,8 @@ export default async (client: Client, oldState: VoiceState, newState: VoiceState const oldChannelId = oldState.channel?.id; if (botChannelId === oldChannelId) { - // If the channel only has bot, then start counting timeout until leave - if (oldState.channel!.members.size <= 1) { + // If the channel only has the bot or users in the blacklist, then start counting timeout until leave + if (oldState.channel!.members.size <= 1 || checkBlacklistUsers(oldState.channel, blacklist)) { let timeoutID = setTimeout(() => { player.destroy(); }, client.config.autoLeaveCooldown); @@ -46,8 +54,8 @@ export default async (client: Client, oldState: VoiceState, newState: VoiceState if (botChannelId === newChannelId) { // When bot is in the target channel and only one member joined - // If there are two members or more (not include bot) in the channel, it will not trigger - if (newState.channel!.members.size > 1 && newState.channel!.members.size <= 2) { + // If there are two members or more (include bot) in the channel, it will not trigger + if (newState.channel!.members.size >= 2 && !checkBlacklistUsers(newState.channel, blacklist)) { // If member join bot channel, then find current channel's timeoutID to clear for (var i = 0; i < pool.length; i++) { // console.log('pool.del',pool[i]); @@ -75,8 +83,8 @@ export default async (client: Client, oldState: VoiceState, newState: VoiceState const newChannelId = newState.channel?.id; if (botChannelId === oldChannelId) { - // If the channel only has bot, then start counting timeout until leave - if (oldState.channel!.members.size <= 1) { + // If the channel only has the bot or users in the blacklist, then start counting timeout until leave + if (oldState.channel!.members.size <= 1 || checkBlacklistUsers(oldState.channel, blacklist)) { let timeoutID = setTimeout(() => { player.destroy(); }, client.config.autoLeaveCooldown); @@ -90,8 +98,8 @@ export default async (client: Client, oldState: VoiceState, newState: VoiceState } else if (botChannelId === newChannelId) { // When bot is in the target channel and only one member joined - // If there are two members or more (not include bot) in the channel, it will not trigger - if (newState.channel!.members.size > 1 && newState.channel!.members.size <= 2) { + // If there are two members or more (include bot) in the channel, it will not trigger + if (newState.channel!.members.size >= 2 && !checkBlacklistUsers(newState.channel, blacklist)) { // If member join bot channel, then find current channel's timeoutID to clear for (var i = 0; i < pool.length; i++) { // console.log('pool.del',pool[i]); diff --git a/src/index.ts b/src/index.ts index f169475..a065035 100644 --- a/src/index.ts +++ b/src/index.ts @@ -170,6 +170,23 @@ const checkNodesStats = async (nodes: Node[]) => { console.log(`${cst.color.grey}-- All node stats have been checked --${cst.color.white}`); }; +const loadBlacklist = async () => { + try { + const jsonString = fs.readFileSync('blacklist.json', 'utf-8'); + const blacklistArray = JSON.parse(jsonString); + + if (Array.isArray(blacklistArray) && blacklistArray.length > 0) { + client.config.blacklist = blacklistArray; + console.log('Blacklist loaded:', client.config.blacklist.length, 'users'); + } + else { + console.log('No blacklist entries found.'); + } + } catch (error) { + console.error('Error loading blacklist:', error); + } +} + Promise.resolve() .then(() => setEnvironment()) @@ -177,6 +194,7 @@ Promise.resolve() .then(() => loadLavaSharkEvents()) .then(() => loadCommands()) .then(() => checkNodesStats(client.lavashark.nodes)) + .then(() => loadBlacklist()) .then(() => { console.log(`${cst.color.green}*** All loaded successfully ***${cst.color.white}`); client.login(process.env.TOKEN); diff --git a/src/utils/constants.ts b/src/utils/constants.ts index ab13892..8362822 100644 --- a/src/utils/constants.ts +++ b/src/utils/constants.ts @@ -13,7 +13,8 @@ export const cst = { autoLeave : true, autoLeaveCooldown : 5000, displayVoiceState : true, - port : 33333 + port : 33333, + blacklist : [] // It must be the user ID }, // Console color color: { From aa893afda41ba922d0a5e581203802e828d13de5 Mon Sep 17 00:00:00 2001 From: hmes98318 <52697423+hmes98318@users.noreply.github.com> Date: Sun, 30 Jul 2023 15:17:40 +0800 Subject: [PATCH 58/64] Add blacklist.json --- blacklist.json | 1 + 1 file changed, 1 insertion(+) create mode 100644 blacklist.json diff --git a/blacklist.json b/blacklist.json new file mode 100644 index 0000000..fe51488 --- /dev/null +++ b/blacklist.json @@ -0,0 +1 @@ +[] From 8a7e8c0457dc97b79221ccd13c787ad162e895b2 Mon Sep 17 00:00:00 2001 From: hmes98318 <52697423+hmes98318@users.noreply.github.com> Date: Sun, 30 Jul 2023 15:36:11 +0800 Subject: [PATCH 59/64] Update README --- README.md | 74 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 73 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 31a12c4..e834770 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,78 @@ # Music Disc +GitHub package.json version + + +GitHub ### Discord.js v14 Music Bot -This is a version based on [LavaShark](https://lavashark.js.org/), currently under development. Stay tuned for updates. \ No newline at end of file +This is a music bot developed based on [**LavaShark**](https://lavashark.js.org/). +If you need the version of [**discord-player**](https://github.com/Androz2091/discord-player), please refer to this [**branch**](https://github.com/hmes98318/Music-Disc/tree/discord-player). + + +## Deploying with node.js + +### Clone the latest version of the repository +``` +git clone -b v2.0.0 https://github.com/hmes98318/Music-Disc.git +``` +or [**click here**](https://github.com/hmes98318/Music-Disc/releases) to download + + +### Install the dependencies +install all the dependencies from [**package.json**](./package.json) +``` +npm install +``` + + +### Add Lavalink node +Please refer to this [**documentation**](https://lavashark.js.org/docs/server-config) for detailed information. +Edit the file [**node-list.json**](./node-list.json) +```json +[ + { + "id": "Node 1", + "hostname": "localhost", + "port": 2333, + "password": "youshallnotpass" + } +] +``` + + +### Configure environment +Edit the file [**.env**](./.env) +```env +TOKEN = "your_token" +NAME = "Music Disc" +PREFIX = "+" +PLAYING = "+help | music" +EMBEDS_COLOR = "#FFFFFF" +DEFAULT_VOLUME = 50 +MAX_VOLUME = 100 +AUTO_LEAVE = true +AUTO_LEAVE_COOLDOWN = 5000 +DISPLAY_VOICE_STATE = true +PORT = 33333 +``` + +
+ Detailed description + + **`AUTO_LEAVE`** : After the music finished, can choose whether let the bot leave voice channel automatically or not. + **`AUTO_LEAVE_COOLDOWN`** : Timer for auto disconnect(ms). + **`DISPLAY_VOICE_STATE`** : Show voice channel status updates. +
+ + +### Running the script +``` +npm run start +``` + + + + + From a1194c563ba20a7ac44898fdb5915d9630774fa8 Mon Sep 17 00:00:00 2001 From: hmes98318 <52697423+hmes98318@users.noreply.github.com> Date: Sun, 30 Jul 2023 15:45:32 +0800 Subject: [PATCH 60/64] Add docker-compose --- Dockerfile | 11 ++++++ application.yml | 91 ++++++++++++++++++++++++++++++++++++++++++++++ docker-compose.yml | 45 +++++++++++++++++++++++ 3 files changed, 147 insertions(+) create mode 100644 Dockerfile create mode 100644 application.yml create mode 100644 docker-compose.yml diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..0594770 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,11 @@ +FROM node:18.17.0 + +WORKDIR /bot +COPY . . + +RUN apt update -y + +RUN npm install +RUN npm install play-dl + +CMD [ "npm", "run", "start" ] \ No newline at end of file diff --git a/application.yml b/application.yml new file mode 100644 index 0000000..880e803 --- /dev/null +++ b/application.yml @@ -0,0 +1,91 @@ +server: # REST and WS server + port: 2333 + address: 0.0.0.0 +plugins: +# name: # Name of the plugin +# some_key: some_value # Some key-value pair for the plugin +# another_key: another_value +lavalink: + plugins: +# - dependency: "group:artifact:version" +# repository: "repository" + server: + password: "youshallnotpass" + sources: + youtube: true + bandcamp: true + soundcloud: true + twitch: true + vimeo: true + http: true + local: false + filters: # All filters are enabled by default + volume: true + equalizer: true + karaoke: true + timescale: true + tremolo: true + vibrato: true + distortion: true + rotation: true + channelMix: true + lowPass: true + bufferDurationMs: 400 # The duration of the NAS buffer. Higher values fare better against longer GC pauses. Duration <= 0 to disable JDA-NAS. Minimum of 40ms, lower values may introduce pauses. + frameBufferDurationMs: 5000 # How many milliseconds of audio to keep buffered + opusEncodingQuality: 10 # Opus encoder quality. Valid values range from 0 to 10, where 10 is best quality but is the most expensive on the CPU. + resamplingQuality: LOW # Quality of resampling operations. Valid values are LOW, MEDIUM and HIGH, where HIGH uses the most CPU. + trackStuckThresholdMs: 10000 # The threshold for how long a track can be stuck. A track is stuck if does not return any audio data. + useSeekGhosting: true # Seek ghosting is the effect where whilst a seek is in progress, the audio buffer is read from until empty, or until seek is ready. + youtubePlaylistLoadLimit: 6 # Number of pages at 100 each + playerUpdateInterval: 5 # How frequently to send player updates to clients, in seconds + youtubeSearchEnabled: true + soundcloudSearchEnabled: true + gc-warnings: true + #ratelimit: + #ipBlocks: ["1.0.0.0/8", "..."] # list of ip blocks + #excludedIps: ["...", "..."] # ips which should be explicit excluded from usage by lavalink + #strategy: "RotateOnBan" # RotateOnBan | LoadBalance | NanoSwitch | RotatingNanoSwitch + #searchTriggersFail: true # Whether a search 429 should trigger marking the ip as failing + #retryLimit: -1 # -1 = use default lavaplayer value | 0 = infinity | >0 = retry will happen this numbers times + #youtubeConfig: # Required for avoiding all age restrictions by YouTube, some restricted videos still can be played without. + #email: "" # Email of Google account + #password: "" # Password of Google account + #httpConfig: # Useful for blocking bad-actors from ip-grabbing your music node and attacking it, this way only the http proxy will be attacked + #proxyHost: "localhost" # Hostname of the proxy, (ip or domain) + #proxyPort: 3128 # Proxy port, 3128 is the default for squidProxy + #proxyUser: "" # Optional user for basic authentication fields, leave blank if you don't use basic auth + #proxyPassword: "" # Password for basic authentication + +metrics: + prometheus: + enabled: false + endpoint: /metrics + +sentry: + dsn: "" + environment: "" +# tags: +# some_key: some_value +# another_key: another_value + +logging: + file: + path: ./logs/ + + level: + root: INFO + lavalink: INFO + + request: + enabled: true + includeClientInfo: true + includeHeaders: false + includeQueryString: true + includePayload: true + maxPayloadLength: 10000 + + + logback: + rollingpolicy: + max-file-size: 1GB + max-history: 30 \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..e3d9b7f --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,45 @@ +version: '3.8' +services: + music-disc: + image: hmes98318/music-disc:2.0.0 + container_name: music-disc + restart: always + environment: + TOKEN: "your_token" + PREFIX: "+" + PLAYING: "+help | music" + EMBEDS_COLOR: "#FFFFFF" + DEFAULT_VOLUME: 50 + MAX_VOLUME: 100 + AUTO_LEAVE: "true" + AUTO_LEAVE_COOLDOWN: 5000 + DISPLAY_VOICE_STATE: "true" + volumes: + - ./node-list.json:/bot/node-list.json + - ./blacklist.json:/bot/blacklist.json + networks: + - lavalink + ports: + - 33333:33333 + + lavalink: + image: ghcr.io/lavalink-devs/lavalink:3 + container_name: lavalink_v3 + restart: unless-stopped + environment: + - _JAVA_OPTIONS=-Xmx6G + - SERVER_PORT=2333 + - LAVALINK_SERVER_PASSWORD=youshallnotpass + volumes: + - ./application.yml:/opt/Lavalink/application.yml + - ./plugins/:/opt/Lavalink/plugins/ + networks: + - lavalink + expose: + - 2333 + ports: + - 2333:2333 + +networks: + lavalink: + name: lavalink \ No newline at end of file From 5be6d837520c3b2e11e927609340beabdd193159 Mon Sep 17 00:00:00 2001 From: hmes98318 <52697423+hmes98318@users.noreply.github.com> Date: Sun, 30 Jul 2023 16:28:41 +0800 Subject: [PATCH 61/64] Update Docker configuration --- docker-compose.yml | 26 +---------------------- application.yml => server/application.yml | 0 server/server-docker-compose.yml | 23 ++++++++++++++++++++ 3 files changed, 24 insertions(+), 25 deletions(-) rename application.yml => server/application.yml (100%) create mode 100644 server/server-docker-compose.yml diff --git a/docker-compose.yml b/docker-compose.yml index e3d9b7f..60df2d4 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -17,29 +17,5 @@ services: volumes: - ./node-list.json:/bot/node-list.json - ./blacklist.json:/bot/blacklist.json - networks: - - lavalink ports: - - 33333:33333 - - lavalink: - image: ghcr.io/lavalink-devs/lavalink:3 - container_name: lavalink_v3 - restart: unless-stopped - environment: - - _JAVA_OPTIONS=-Xmx6G - - SERVER_PORT=2333 - - LAVALINK_SERVER_PASSWORD=youshallnotpass - volumes: - - ./application.yml:/opt/Lavalink/application.yml - - ./plugins/:/opt/Lavalink/plugins/ - networks: - - lavalink - expose: - - 2333 - ports: - - 2333:2333 - -networks: - lavalink: - name: lavalink \ No newline at end of file + - 33333:33333 \ No newline at end of file diff --git a/application.yml b/server/application.yml similarity index 100% rename from application.yml rename to server/application.yml diff --git a/server/server-docker-compose.yml b/server/server-docker-compose.yml new file mode 100644 index 0000000..c213044 --- /dev/null +++ b/server/server-docker-compose.yml @@ -0,0 +1,23 @@ +version: "3.8" + +services: + lavalink: + image: ghcr.io/lavalink-devs/lavalink:3 # pin the image version to Lavalink v3 + container_name: lavalink + restart: unless-stopped + environment: + - _JAVA_OPTIONS=-Xmx6G # set Java options here + - SERVER_PORT=2333 # set lavalink server port + - LAVALINK_SERVER_PASSWORD=youshallnotpass # set password for lavalink + volumes: + - ./application.yml:/opt/Lavalink/application.yml # mount application.yml from the same directory or use environment variables + - ./plugins/:/opt/Lavalink/plugins/ # persist plugins between restarts, make sure to set the correct permissions (user: 322, group: 322) + networks: + - lavalink + expose: + - 2333 # lavalink exposes port 2333 to connect to for other containers (this is for documentation purposes only) + ports: + - 2333:2333 # you only need this if you want to make your lavalink accessible from outside of containers +networks: + lavalink: # create a lavalink network you can add other containers to, to give them access to Lavalink + name: lavalink \ No newline at end of file From 8c14a60c4379a3c725d2ab52cf70d8f54e3e8c46 Mon Sep 17 00:00:00 2001 From: hmes98318 <52697423+hmes98318@users.noreply.github.com> Date: Sun, 30 Jul 2023 16:41:47 +0800 Subject: [PATCH 62/64] Update lavashark events --- src/events/lavashark/trackEnd.ts | 2 +- src/events/lavashark/trackStart.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/events/lavashark/trackEnd.ts b/src/events/lavashark/trackEnd.ts index 0072557..5e8504d 100644 --- a/src/events/lavashark/trackEnd.ts +++ b/src/events/lavashark/trackEnd.ts @@ -3,5 +3,5 @@ import { Player, Track } from "lavashark"; export default async (client: Client, player: Player, track: Track, reason: any) => { - console.log('// -------- track end -------- //'); + // console.log('// -------- track end -------- //'); }; \ No newline at end of file diff --git a/src/events/lavashark/trackStart.ts b/src/events/lavashark/trackStart.ts index f175a7e..08e9b07 100644 --- a/src/events/lavashark/trackStart.ts +++ b/src/events/lavashark/trackStart.ts @@ -5,7 +5,7 @@ import { dashboard } from "../../dashboard"; export default async (client: Client, player: Player/*, track: Track*/) => { - console.log('// -------- track start -------- //'); + // console.log('// -------- track start -------- //'); const track = player.current; //-------------------------- await dashboard.update(client, player, track!); From 186349952880a4d3a92a445c38f622a1fe8adb18 Mon Sep 17 00:00:00 2001 From: hmes98318 <52697423+hmes98318@users.noreply.github.com> Date: Sun, 30 Jul 2023 16:50:14 +0800 Subject: [PATCH 63/64] Update Docker configuration --- Dockerfile | 2 -- server/{server-docker-compose.yml => docker-compose.yml} | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) rename server/{server-docker-compose.yml => docker-compose.yml} (96%) diff --git a/Dockerfile b/Dockerfile index 0594770..17943ee 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,8 +4,6 @@ WORKDIR /bot COPY . . RUN apt update -y - RUN npm install -RUN npm install play-dl CMD [ "npm", "run", "start" ] \ No newline at end of file diff --git a/server/server-docker-compose.yml b/server/docker-compose.yml similarity index 96% rename from server/server-docker-compose.yml rename to server/docker-compose.yml index c213044..5a5d418 100644 --- a/server/server-docker-compose.yml +++ b/server/docker-compose.yml @@ -3,7 +3,7 @@ version: "3.8" services: lavalink: image: ghcr.io/lavalink-devs/lavalink:3 # pin the image version to Lavalink v3 - container_name: lavalink + container_name: lavalink_v3 restart: unless-stopped environment: - _JAVA_OPTIONS=-Xmx6G # set Java options here From 062ffbbe50106497b236ab9d5b0ebf98b2b4ee7b Mon Sep 17 00:00:00 2001 From: hmes98318 <52697423+hmes98318@users.noreply.github.com> Date: Sun, 30 Jul 2023 17:04:14 +0800 Subject: [PATCH 64/64] Update README --- README.md | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/README.md b/README.md index e834770..13f7f50 100644 --- a/README.md +++ b/README.md @@ -74,6 +74,59 @@ npm run start ``` +## Deploying with Docker +**image link** : https://hub.docker.com/r/hmes98318/music-disc +If you don't have any available nodes, you need to first start the server container using [Docker Compose](server/docker-compose.yml) in the server directory. +### Start with Docker +Use the following command to start the container: +Please put your **token** into the `TOKEN` variable. +``` +docker run -d \ + --name music-disc \ + -e TOKEN="your_token" \ + -e PREFIX="+" \ + -e PLAYING="+help | music" \ + -e EMBEDS_COLOR="#FFFFFF" \ + -e DEFAULT_VOLUME=50 \ + -e MAX_VOLUME=100 \ + -e AUTO_LEAVE="true" \ + -e AUTO_LEAVE_COOLDOWN=5000 \ + -e DISPLAY_VOICE_STATE="true" \ + -v ./node-list.json:/bot/node-list.json \ + -v ./blacklist.json:/bot/blacklist.json \ + -p 33333:33333 \ + hmes98318/music-disc:2.0.0 +``` +### Start with Docker-Compose +Please put your **token** into the `TOKEN` variable. +```yml +version: '3.8' +services: + music-disc: + image: hmes98318/music-disc:2.0.0 + container_name: music-disc + restart: always + environment: + TOKEN: "your_token" + PREFIX: "+" + PLAYING: "+help | music" + EMBEDS_COLOR: "#FFFFFF" + DEFAULT_VOLUME: 50 + MAX_VOLUME: 100 + AUTO_LEAVE: "true" + AUTO_LEAVE_COOLDOWN: 5000 + DISPLAY_VOICE_STATE: "true" + volumes: + - ./node-list.json:/bot/node-list.json + - ./blacklist.json:/bot/blacklist.json + ports: + - 33333:33333 +``` + +#### Start the container +``` +docker-compose up -d +``` \ No newline at end of file