diff --git a/Lavalink/example.application.yml b/Lavalink/example.application.yml index c043ace92..9a21091e6 100644 --- a/Lavalink/example.application.yml +++ b/Lavalink/example.application.yml @@ -91,17 +91,17 @@ plugins: - IOS lavalink: plugins: - - dependency: "com.github.appujet:jiosaavn-plugin:v0.1.6" + - dependency: "com.github.appujet:jiosaavn-plugin:0.1.7" repository: "https://jitpack.io" - dependency: "com.dunctebot:skybot-lavalink-plugin:1.7.0" snapshot: false # set to true if you want to use snapshot builds. - dependency: "com.github.topi314.lavasearch:lavasearch-plugin:1.0.0" - snapshot: false # set to true if you want to use snapshot builds (see below) + snapshot: false # set to true if you want to use snapshot builds. - dependency: "com.github.topi314.lavasrc:lavasrc-plugin:4.2.0" snapshot: false # set to true if you want to use snapshot builds. - dependency: "com.github.topi314.sponsorblock:sponsorblock-plugin:3.0.1" snapshot: false # set to true if you want to use snapshot builds. - - dependency: "dev.lavalink.youtube:youtube-plugin:1.5.1" + - dependency: "dev.lavalink.youtube:youtube-plugin:1.5.2" snapshot: false # set to true if you want to use snapshot builds. pluginsDir: './plugins' server: diff --git a/README.md b/README.md index 2c6637a3b..c2a2993c6 100644 --- a/README.md +++ b/README.md @@ -46,7 +46,6 @@ ### 🔍 Default Sources -- ![YouTube](https://img.shields.io/badge/YouTube-FF0000?style=plastic&logo=youtube&logoColor=white) ([Required Plugin][youtube-source]) - ![SoundCloud](https://img.shields.io/badge/SoundCloud-FF3300?style=plastic&logo=soundcloud&logoColor=white) - ![Twitch](https://img.shields.io/badge/Twitch-9146FF?style=plastic&logo=twitch&logoColor=white) - ![Bandcamp](https://img.shields.io/badge/Bandcamp-629AA9?style=plastic&logo=bandcamp&logoColor=white) @@ -55,10 +54,11 @@ - ![Mixer](https://img.shields.io/badge/Mixer-FFA500?style=plastic&logo=mixer&logoColor=white) - ![http](https://img.shields.io/badge/http-FFA500?style=plastic&logo=http&logoColor=white) -### 🔌 Plugin Sources: `(Require: LavaSrc and Skybot Plugin)` +### 🔌 Plugin Sources **Note: You need to install the plugins to use these sources** +- ![YouTube](https://img.shields.io/badge/YouTube-FF0000?style=plastic&logo=youtube&logoColor=white) ([Required Plugin][youtube-source]) - ![Spotify](https://img.shields.io/badge/Spotify-1ED760?style=plastic&logo=spotify&logoColor=white) ([Required Plugin][LavaSrc]) - ![Deezer](https://img.shields.io/badge/Deezer-FF0000?style=plastic&logo=deezer&logoColor=white) ([Required Plugin][LavaSrc]) - ![Apple Music](https://img.shields.io/badge/Apple%20Music-000000?style=plastic&logo=apple-music&logoColor=white) ([Required Plugin][LavaSrc]) @@ -78,9 +78,11 @@ [youtube-source]: https://github.com/lavalink-devs/youtube-source [jiosaavn]: https://github.com/appujet/jiosaavn-plugin -To Setup a Lavalink server on Windows, Linux, or Replit, [Click Here.](https://github.com/LucasB25/lavalink-server) +To Setup a Lavalink server on Windows, Linux, or Replit, [Click Here!](https://github.com/LucasB25/lavalink-server) -### **Need Help with plugins?** Join our [Discord Server](https://discord.gg/YsJCtDuTXp) and ask for help in the `#support` channel +### **Need help with plugins?** + +Join our [Discord Server](https://discord.gg/YsJCtDuTXp) and ask for help in the `#support` channel! ## 🔧 Requirements @@ -116,33 +118,8 @@ cd lavamusic npm i ``` -4. Set up your environment variables: -Create a .env file in the root directory of your project with the following variables: -or you can use the [.env.example](https://raw.githubusercontent.com/appujet/lavamusic/main/.env.example) file - -```bash -TOKEN= "" # Your bot token. -CLIENT_ID= "" # Your bot's client ID (If this value is left blank, bots cannot be invited using /invite or /about commands.). -PREFIX= "!" # Your prefix. -OWNER_IDS= ["",""] # Your discord id (You can add multiple ids.). -GUILD_ID= "" # Your server ID (If you want to use the bot for a single server). -PRODUCTION= "true" # true for production. -TOPGG= "" # Your Top.gg API key. Obtain this from https://top.gg -KEEP_ALIVE= "false" # true for keep alive in https://replit.com -LOG_CHANNEL_ID= "" # If you enter this, you will be able to receive the status of Lavalink nodes and guild join/leave logs through the corresponding channel. -LOG_COMMANDS_ID= "" # The channel ID where command usage logs will be sent. -BOT_STATUS= "online" # Your bot status (online, dnd, idle, invisible or offline). -BOT_ACTIVITY_TYPE= 0 # Activity type is a number from 0 to 5. See more here: https://discord.com/developers/docs/topics/gateway-events#activity-object-activity-types -BOT_ACTIVITY= "Lavamusic" # Your bot activity. -DATABASE_URL= "" # Your database url (If you want to use sqlite, then you can leave it blank.). -AUTO_NODE= "false" # true for auto node. It is given from lavainfo-api (https://lavainfo-api.deno.dev). -LAVALINK_URL= "localhost:2333" # Your Lavalink url (If auto node is true, then you can leave it blank). -LAVALINK_AUTH= "youshallnotpass" # Your Lavalink password (If auto node is true, then you can leave it blank.). -LAVALINK_NAME= "Lavamusic" # Your Lavalink name (If auto node is true, then you can leave it blank.). -LAVALINK_SECURE= "false" # true for secure Lavalink (If auto node is true, then you can leave it blank.). -MAX_PLAYLIST_SIZE= "100" # Max playlist size. -MAX_QUEUE_SIZE= "100" # Max queue size. -``` +4. Copy the .env.example file to .env and fill in all required values. +Note: Optional values ​​are noted as comments in the settings. 5. Generate the Prisma client: @@ -150,7 +127,7 @@ MAX_QUEUE_SIZE= "100" # Max queue size. npm run db:push ``` -6. Run the migrations (Only if you want to migrate your database) +6. Run the migrations (Only if you want to migrate your database): ```bash npm run db:migrate @@ -166,17 +143,17 @@ npm start 8. Invite the bot to your server: -Generate an invite link for your bot and invite it to your server using the Discord Developer Portal or using Permissions Calculator. +Generate an invite link for your bot and invite it to your server using the [Discord Developer Portal](https://discord.com/developers/applications) or [Permissions Calculator](https://discordapi.com/permissions.html). ## 🚀 Installation using Docker Compose This section assumes you have Docker and Docker Compose installed and running correctly. -Download the [docker-compose.yml file](https://raw.githubusercontent.com/appujet/lavamusic/main/docker-compose.yml) in a separate folder like lavamusic. Edit docker-compose.yml and make sure to set the following variables: -Your .env file should look like this or you can use the [.env.example](https://raw.githubusercontent.com/appujet/lavamusic/main/.env.example) file. +Your .env file should look like this or you can use the .env.example file. ```yaml TOKEN="." # Your bot token and remember, don't show everyone your bot token +DEFAULT_LANGUAGE= "EnglishUS" # Default language for bot PREFIX="!" # Your prefix OWNER_IDS=["859640640640640640","859640640640640640"] # Your discord id, you can add multiple ids GUILD_ID="859640640640640640" # Your server ID (if you want to use it for a single server) @@ -192,6 +169,8 @@ docker-compose up -d ``` The above command will start all your services and your bot should be up and running! +If you want to run it from the console, remove the -d argument. + To update, you only have to type the following: ```bash @@ -223,7 +202,7 @@ Do note that the bot will restart itself to update to the latest! ## 📝 Tutorial -A tutorial has been uploaded on YouTube. Watch it by clicking [here](https://youtu.be/x5lQD2rguz0). +A tutorial has been uploaded on YouTube. Watch it by [clicking here](https://youtu.be/x5lQD2rguz0). ## 📜 Contributing diff --git a/Translation.md b/Translation.md index fd8042e62..397afd3bf 100644 --- a/Translation.md +++ b/Translation.md @@ -18,7 +18,7 @@ - [x] German - `German.json` [by @LucasB25](https://github.com/LucasB25) - [x] Russian - `Russian.json` [by @LucasB25](https://github.com/LucasB25) - [x] Korean - `Korean.json` [by @hwangsihu](https://github.com/hwangsihu) -- [ ] Indonesian - `Indonesian.json` (Not Started) +- [x] Indonesian - `Indonesian.json` [by @iaMJ](https://github.com/idMJA) - [ ] English (GB) - `EnglishGB.json` (Not Started) - [ ] Bulgarian - `Bulgarian.json` (Not Started) - [x] Chinese (CN) - `ChineseCN.json` [by @appujet](https://github.com/Appujet) (Ai Translation - Not Accurate) diff --git a/biome.json b/biome.json index 6332633c0..86a5d20f8 100644 --- a/biome.json +++ b/biome.json @@ -46,25 +46,25 @@ } } }, - "files": { - "ignoreUnknown": true, - "ignore": [".vscode", "dist", "locales", "node_modules"] - }, - "json": { - "formatter": { - "enabled": true, - "indentWidth": 2, - "lineWidth": 100 - } - }, "formatter": { "enabled": true, "indentWidth": 4, "indentStyle": "space", - "lineWidth": 140, "lineEnding": "crlf", + "lineWidth": 140, "formatWithErrors": true }, + "json": { + "linter": { + "enabled": true + }, + "formatter": { + "enabled": true, + "indentWidth": 2, + "lineEnding": "crlf", + "lineWidth": 80 + } + }, "javascript": { "formatter": { "quoteStyle": "double", @@ -72,5 +72,9 @@ "bracketSameLine": true, "semicolons": "always" } + }, + "files": { + "ignoreUnknown": true, + "ignore": [".vscode", "dist", "locales", "node_modules"] } } diff --git a/locales/Indonesian.json b/locales/Indonesian.json index 75c53c9ea..cc71d4f10 100644 --- a/locales/Indonesian.json +++ b/locales/Indonesian.json @@ -1,630 +1,630 @@ { "cmd": { "247": { - "description": "Set the bot to stay in the voice channel", + "description": "Atur bot untuk tetap berada di voice channel", "errors": { - "not_in_voice": "You need to be in a voice channel to use this command.", - "generic": "An error occurred while trying to execute this command." + "not_in_voice": "Anda perlu berada di voice channel untuk menggunakan command ini.", + "generic": "Terjadi kesalahan saat mencoba menjalankan command ini." }, "messages": { - "disabled": "`✅` | 24/7 mode has been `DISABLED`", - "enabled": "`✅` | 24/7 mode has been `ENABLED`. \n**The bot will not leave the voice channel even if there are no people in the voice channel.**" + "disabled": "`✅` | Mode 24/7 telah `DINONAKTIFKAN`", + "enabled": "`✅` | Mode 24/7 telah `DIAKTIFKAN`. \n**Bot tidak akan meninggalkan voice channel meskipun tidak ada orang di voice channel.**" } }, "ping": { - "description": "Shows the bot's ping.", - "content": "Pinging...", - "bot_latency": "Bot Latency", - "api_latency": "API Latency", - "requested_by": "Requested by {author}" + "description": "Menampilkan ping bot.", + "content": "Mengukur ping...", + "bot_latency": "Latensi Bot", + "api_latency": "Latensi API", + "requested_by": "Direquest oleh {author}" }, "lavalink": { - "description": "Shows the current Lavalink stats.", - "title": "Lavalink Stats", - "content": "Player: {players}\nPlaying Players: {playingPlayers}\nUptime: {uptime}\nCores: {cores} Core(s)\nMemory Usage: {used} / {reservable}\nSystem Load: {systemLoad}%\nLavalink Load: {lavalinkLoad}%" + "description": "Menampilkan statistik Lavalink saat ini.", + "title": "Statistik Lavalink", + "content": "Player: {players}\nPlayer Aktif: {playingPlayers}\nUptime: {uptime}\nCore: {cores} Core\nMemory Usage: {used} / {reservable}\nSystem Load: {systemLoad}%\nLavalink Load: {lavalinkLoad}%" }, "invite": { - "description": "Get the bot invite link.", - "content": "You can invite me by clicking the button below. Any bugs or outages? Join the support server!" + "description": "Dapatkan tautan undangan bot.", + "content": "Anda dapat mengundang saya dengan mengklik tombol di bawah. Ada bug atau gangguan? Bergabunglah dengan server support!" }, "help": { - "description": "Shows the help menu.", + "description": "Menampilkan menu bantuan.", "options": { - "command": "The command you want to get info on" + "command": "command yang ingin Anda dapatkan informasinya" }, - "content": "Hey there! I'm {bot}, a music bot made with [Lavamusic](https://github.com/appujet/lavamusic) and Discord. You can use `{prefix}help ` to get more info on a command.", - "title": "Help Menu", - "not_found": "This `{cmdName}` command does not exist.", - "help_cmd": "**Description:** {description}\n**Usage:** {usage}\n**Examples:** {examples}\n**Aliases:** {aliases}\n**Category:** {category}\n**Cooldown:** {cooldown} seconds\n**Permissions:** {premUser}\n**Bot Permissions:** {premBot}\n**Developer Only:** {dev}\n**Slash Command:** {slash}\n**Args:** {args}\n**Player:** {player}\n**DJ:** {dj}\n**DJ Permissions:** {djPerm}\n**Voice:** {voice}", - "footer": "Use {prefix}help for more info on a command" + "content": "Halo! Saya {bot}, bot musik yang dibuat dengan [Lavamusic](https://github.com/appujet/lavamusic) dan Discord. Anda dapat menggunakan `{prefix}help ` untuk mendapatkan informasi lebih lanjut tentang command.", + "title": "Menu Bantuan", + "not_found": "command `{cmdName}` ini tidak ada.", + "help_cmd": "**Deskripsi:** {description}\n**Penggunaan:** {usage}\n**Contoh:** {examples}\n**Alias:** {aliases}\n**Kategori:** {category}\n**Cooldown:** {cooldown} detik\n**Izin:** {premUser}\n**Izin Bot:** {premBot}\n**Hanya Pengembang:** {dev}\n**command Slash:** {slash}\n**Argumen:** {args}\n**Player:** {player}\n**DJ:** {dj}\n**Izin DJ:** {djPerm}\n**Suara:** {voice}", + "footer": "Gunakan {prefix}help untuk informasi lebih lanjut tentang command" }, "botinfo": { - "description": "Information about the bot", - "content": "Bot Information:\n- **Operating System**: {osInfo}\n- **Uptime**: {osUptime}\n- **Hostname**: {osHostname}\n- **CPU Architecture**: {cpuInfo}\n- **CPU Usage**: {cpuUsed}%\n- **Memory Usage**: {memUsed}MB / {memTotal}GB\n- **Node Version**: {nodeVersion}\n- **Discord Version**: {discordJsVersion}\n- **Connected to** {guilds} guilds, {channels} channels, and {users} users\n- **Total Commands**: {commands}" + "description": "Informasi tentang bot", + "content": "Informasi Bot:\n- **Sistem Operasi**: {osInfo}\n- **Uptime**: {osUptime}\n- **Nama Host**: {osHostname}\n- **Arsitektur CPU**: {cpuInfo}\n- **Penggunaan CPU**: {cpuUsed}%\n- **Penggunaan Memori**: {memUsed}MB / {memTotal}GB\n- **Versi Node**: {nodeVersion}\n- **Versi Discord**: {discordJsVersion}\n- **Terhubung ke** {guilds} guild, {channels} saluran, dan {users} pengguna\n- **Total command**: {commands}" }, "about": { - "description": "Shows information about the bot", + "description": "Menampilkan informasi tentang bot", "fields": { - "creator": "Creator", - "repository": "Repository", - "support": "Support", - "description": "He really wanted to make his first open source project ever for more coding experience. In this project, he was challenged to make a project with fewer bugs. Hope you enjoy using LavaMusic!" + "creator": "Pembuat", + "repository": "Repositori", + "support": "Dukungan", + "description": "Dia sangat ingin membuat proyek open source pertamanya untuk pengalaman coding yang lebih banyak. Dalam proyek ini, dia ditantang untuk membuat proyek dengan lebih sedikit bug. Semoga Anda menikmati menggunakan LavaMusic!" } }, "dj": { - "description": "Manage the DJ mode and associated roles", + "description": "Mengelola mode DJ dan peran terkait", "errors": { - "provide_role": "Please provide a role.", - "no_roles": "The DJ role is empty.", - "invalid_subcommand": "Please provide a valid subcommand." + "provide_role": "Harap berikan peran.", + "no_roles": "Peran DJ kosong.", + "invalid_subcommand": "Harap berikan subcommand yang valid." }, "messages": { - "role_exists": "The DJ role <@&{roleId}> is already added.", - "role_added": "The DJ role <@&{roleId}> has been added.", - "role_not_found": "The DJ role <@&{roleId}> is not added.", - "role_removed": "The DJ role <@&{roleId}> has been removed.", - "all_roles_cleared": "All DJ roles have been removed.", - "toggle": "The DJ mode has been toggled to {status}." + "role_exists": "Peran DJ <@&{roleId}> sudah ditambahkan.", + "role_added": "Peran DJ <@&{roleId}> telah ditambahkan.", + "role_not_found": "Peran DJ <@&{roleId}> tidak ditambahkan.", + "role_removed": "Peran DJ <@&{roleId}> telah dihapus.", + "all_roles_cleared": "Semua peran DJ telah dihapus.", + "toggle": "Mode DJ telah diubah menjadi {status}." }, "options": { - "add": "The DJ role you want to add", - "remove": "The DJ role you want to remove", - "clear": "Clears all DJ roles", - "toggle": "Toggles the DJ role", - "role": "The DJ role" + "add": "Peran DJ yang ingin Anda tambahkan", + "remove": "Peran DJ yang ingin Anda hapus", + "clear": "Menghapus semua peran DJ", + "toggle": "Mengaktifkan/menonaktifkan peran DJ", + "role": "Peran DJ" }, - "subcommands": "Subcommands" + "subcommands": "Subcommand" }, "language": { - "description": "Set the language for the bot", - "invalid_language": "Please provide a valid language. Example: `EnglishUS` for English (United States)\n\nYou can find the list of supported languages [here](https://discord.com/developers/docs/reference#locales)\n\n**Available Languages:**\n{languages}", - "already_set": "The language is already set to `{language}`", - "not_set": "The language is not set.", - "set": "`✅` | The language has been set to `{language}`", - "reset": "`✅` | The language has been reset to the default language.", + "description": "Mengatur bahasa untuk bot", + "invalid_language": "Harap berikan bahasa yang valid. Contoh: `EnglishUS` untuk Bahasa Inggris (Amerika Serikat)\n\nAnda dapat menemukan list bahasa yang disupport [di sini](https://discord.com/developers/docs/reference#locales)\n\n**Bahasa yang Tersedia:**\n{languages}", + "already_set": "Bahasa sudah diatur ke `{language}`", + "not_set": "Bahasa belum diatur.", + "set": "`✅` | Bahasa telah diatur ke `{language}`", + "reset": "`✅` | Bahasa telah direset ke bahasa default.", "options": { - "set": "Set the language for the bot", - "language": "The language you want to set", - "reset": "Change the language back to the default language" + "set": "Mengatur bahasa untuk bot", + "language": "Bahasa yang ingin Anda atur", + "reset": "Mengubah bahasa kembali ke bahasa default" } }, "prefix": { - "description": "Shows or sets the bot's prefix", + "description": "Menampilkan atau mengatur prefix bot", "errors": { - "prefix_too_long": "The prefix cannot be longer than 3 characters." + "prefix_too_long": "prefix tidak boleh lebih dari 3 karakter." }, "messages": { - "current_prefix": "The prefix for this server is `{prefix}`", - "prefix_set": "The prefix for this server is now `{prefix}`", - "prefix_reset": "The prefix for this server is now `{prefix}`" + "current_prefix": "prefix untuk server ini adalah `{prefix}`", + "prefix_set": "prefix untuk server ini sekarang adalah `{prefix}`", + "prefix_reset": "prefix untuk server ini sekarang adalah `{prefix}`" }, "options": { - "set": "Sets the prefix", - "prefix": "The prefix you want to set", - "reset": "Resets the prefix to the default one" + "set": "Mengatur prefix", + "prefix": "prefix yang ingin Anda atur", + "reset": "Mengatur ulang prefix ke default" } }, "setup": { - "description": "Sets up the bot", + "description": "Mengatur bot", "errors": { - "channel_exists": "The song request channel already exists.", - "channel_not_exists": "The song request channel doesn't exist.", - "channel_delete_fail": "The song request channel has been deleted. If the channel is not deleted normally, please delete it yourself." + "channel_exists": "Channel Song Request sudah ada.", + "channel_not_exists": "Channel Song Request tidak ada.", + "channel_delete_fail": "Channel Song Request telah dihapus. Jika channel tidak terhapus secara normal, mohon untuk menghapus sendiri." }, "messages": { - "channel_created": "The song request channel has been created in <#{channelId}>.", - "channel_deleted": "The song request channel has been deleted.", - "channel_info": "The song request channel is <#{channelId}>." + "channel_created": "Channel Song Request telah dibuat di <#{channelId}>.", + "channel_deleted": "Channel Song Request telah dihapus.", + "channel_info": "Channel Song Request adalah <#{channelId}>." }, "options": { - "create": "Creates the song request channel", - "delete": "Deletes the song request channel", - "info": "Shows the song request channel" + "create": "Membuat Channel Song Request", + "delete": "Menghapus Channel Song Request", + "info": "Menampilkan Channel Song Request" } }, "8d": { - "description": "on/off 8d filter", + "description": "Mengaktifkan/menonaktifkan filter 8d", "messages": { - "filter_enabled": "`✅` | 8D filter has been `ENABLED`.", - "filter_disabled": "`✅` | 8D filter has been `DISABLED`." + "filter_enabled": "`✅` | Filter 8D telah `DIAKTIFKAN`.", + "filter_disabled": "`✅` | Filter 8D telah `DINONAKTIFKAN`." } }, "bassboost": { - "description": "on/off bassboost filter", + "description": "Mengaktifkan/menonaktifkan filter bassboost", "messages": { - "filter_enabled": "`✅` | Bassboost filter has been `ENABLED`. \n**Be careful, listening too loudly can damage your hearing!**", - "filter_disabled": "`✅` | Bassboost filter has been `DISABLED`." + "filter_enabled": "`✅` | Filter bassboost telah `DIAKTIFKAN`. \n**Hati-hati, mendengarkan terlalu keras dapat merusak pendengaran Anda!**", + "filter_disabled": "`✅` | Filter bassboost telah `DINONAKTIFKAN`." } }, "distorsion": { - "description": "Toggle the distorsion filter on/off", + "description": "Mengaktifkan/menonaktifkan filter distorsi", "messages": { - "filter_enabled": "`✅` | Distorsion filter has been `ENABLED`.", - "filter_disabled": "`✅` | Distorsion filter has been `DISABLED`." + "filter_enabled": "`✅` | Filter distorsi telah `DIAKTIFKAN`.", + "filter_disabled": "`✅` | Filter distorsi telah `DINONAKTIFKAN`." } }, "karaoke": { - "description": "Toggle the karaoke filter on/off", + "description": "Mengaktifkan/menonaktifkan filter karaoke", "messages": { - "filter_enabled": "`✅` | Karaoke filter has been `ENABLED`.", - "filter_disabled": "`✅` | Karaoke filter has been `DISABLED`." + "filter_enabled": "`✅` | Filter karaoke telah `DIAKTIFKAN`.", + "filter_disabled": "`✅` | Filter karaoke telah `DINONAKTIFKAN`." } }, "lowpass": { - "description": "Toggle the lowpass filter on/off", + "description": "Mengaktifkan/menonaktifkan filter lowpass", "messages": { - "filter_enabled": "`✅` | Lowpass filter has been `ENABLED`.", - "filter_disabled": "`✅` | Lowpass filter has been `DISABLED`." + "filter_enabled": "`✅` | Filter lowpass telah `DIAKTIFKAN`.", + "filter_disabled": "`✅` | Filter lowpass telah `DINONAKTIFKAN`." } }, "nightcore": { - "description": "Toggle the nightcore filter on/off", + "description": "Mengaktifkan/menonaktifkan filter nightcore", "messages": { - "filter_enabled": "`✅` | Nightcore filter has been `ENABLED`.", - "filter_disabled": "`✅` | Nightcore filter has been `DISABLED`." + "filter_enabled": "`✅` | Filter nightcore telah `DIAKTIFKAN`.", + "filter_disabled": "`✅` | Filter nightcore telah `DINONAKTIFKAN`." } }, "pitch": { - "description": "Toggle the pitch filter on/off", + "description": "Mengaktifkan/menonaktifkan filter pitch", "options": { - "pitch": "The number you want to set the pitch to (between 0.5 and 5)" + "pitch": "Angka yang ingin Anda atur untuk pitch (antara 0,5 dan 5)" }, "errors": { - "invalid_number": "Please provide a valid number between 0.5 and 5." + "invalid_number": "Harap berikan angka yang valid antara 0,5 dan 5." }, "messages": { - "pitch_set": "`✅` | Pitch has been set to **{pitch}**." + "pitch_set": "`✅` | Pitch telah diatur ke **{pitch}**." } }, "rate": { - "description": "Change the rate of the song", + "description": "Mengubah kecepatan lagu", "options": { - "rate": "The number you want to set the rate to (between 0.5 and 5)" + "rate": "Angka yang ingin Anda atur untuk kecepatan (antara 0,5 dan 5)" }, "errors": { - "invalid_number": "Please provide a valid number between 0.5 and 5." + "invalid_number": "Harap berikan angka yang valid antara 0,5 dan 5." }, "messages": { - "rate_set": "`✅` | Rate has been set to **{rate}**." + "rate_set": "`✅` | Kecepatan telah diatur ke **{rate}**." } }, "reset": { - "description": "Resets the active filters", + "description": "Mengatur ulang filter aktif", "messages": { - "filters_reset": "`✅` | Filters have been reset." + "filters_reset": "`✅` | Filter telah direset." } }, "rotation": { - "description": "Toggle the rotation filter on/off", + "description": "Mengaktifkan/menonaktifkan filter rotasi", "messages": { - "enabled": "`✅` | Rotation filter has been `ENABLED`.", - "disabled": "`✅` | Rotation filter has been `DISABLED`." + "enabled": "`✅` | Filter rotasi telah `DIAKTIFKAN`.", + "disabled": "`✅` | Filter rotasi telah `DINONAKTIFKAN`." } }, "speed": { - "description": "Change the speed of the song", + "description": "Mengubah kecepatan lagu", "options": { - "speed": "The speed you want to set" + "speed": "Kecepatan yang ingin Anda atur" }, "messages": { - "invalid_number": "Please provide a valid number between 0.5 and 5.", - "set_speed": "`✅` | Speed has been set to **{speed}**." + "invalid_number": "Harap berikan angka yang valid antara 0,5 dan 5.", + "set_speed": "`✅` | Kecepatan telah diatur ke **{speed}**." } }, "tremolo": { - "description": "Toggle the tremolo filter on/off", + "description": "Mengaktifkan/menonaktifkan filter tremolo", "messages": { - "enabled": "`✅` | Tremolo filter has been `ENABLED`.", - "disabled": "`✅` | Tremolo filter has been `DISABLED`." + "enabled": "`✅` | Filter tremolo telah `DIAKTIFKAN`.", + "disabled": "`✅` | Filter tremolo telah `DINONAKTIFKAN`." } }, "vibrato": { - "description": "Toggle the vibrato filter on/off", + "description": "Mengaktifkan/menonaktifkan filter vibrato", "messages": { - "enabled": "`✅` | Vibrato filter has been `ENABLED`.", - "disabled": "`✅` | Vibrato filter has been `DISABLED`." + "enabled": "`✅` | Filter vibrato telah `DIAKTIFKAN`.", + "disabled": "`✅` | Filter vibrato telah `DINONAKTIFKAN`." } }, "autoplay": { - "description": "Toggles autoplay", + "description": "Mengaktifkan/menonaktifkan pemutaran otomatis", "messages": { - "enabled": "`✅` | Autoplay has been `ENABLED`.", - "disabled": "`✅` | Autoplay has been `DISABLED`." + "enabled": "`✅` | Pemutaran otomatis telah `DIAKTIFKAN`.", + "disabled": "`✅` | Pemutaran otomatis telah `DINONAKTIFKAN`." } }, "clearqueue": { - "description": "Clears the queue", + "description": "Membersihkan antrean", "messages": { - "cleared": "The queue has been cleared." + "cleared": "Antrean telah dibersihkan." } }, "grab": { - "description": "Grabs the current playing song on your DM", - "content": "**Duration:** {length}\n**Requested by:** <@{requester}>\n**Link:** [Click here]({uri})", - "check_dm": "Please check your DM.", - "dm_failed": "I couldn't send you a DM. Please make sure allow direct messages is turned on." + "description": "Mengambil lagu yang sedang diputar ke DM Anda", + "content": "**Durasi:** {length}\n**Direquest oleh:** <@{requester}>\n**Link:** [Klik di sini]({uri})", + "check_dm": "Silakan periksa DM Anda.", + "dm_failed": "Saya tidak bisa mengirim DM kepada Anda. Pastikan allow direct messages diaktifkan." }, "join": { - "description": "Joins the voice channel", - "already_connected": "I'm already connected to <#{channelId}>.", - "no_voice_channel": "You need to be in a voice channel to use this command.", - "joined": "Successfully joined <#{channelId}>." + "description": "Join ke voice channel", + "already_connected": "Saya sudah terhubung ke <#{channelId}>.", + "no_voice_channel": "Anda perlu berada di voice channel untuk menggunakan command ini.", + "joined": "Berhasil join ke <#{channelId}>." }, "leave": { - "description": "Leaves the voice channel", - "left": "Successfully left <#{channelId}>.", - "not_in_channel": "I'm not in a voice channel." + "description": "Meninggalkan voice channel", + "left": "Berhasil meninggalkan <#{channelId}>.", + "not_in_channel": "Saya tidak berada di voice channel." }, "loop": { - "description": "Loop the current song or the queue", - "looping_song": "**Looping the song.**", - "looping_queue": "**Looping the queue.**", - "looping_off": "**Looping is now off.**" + "description": "Mengulang lagu saat ini atau antrean", + "looping_song": "**Mengulang lagu.**", + "looping_queue": "**Mengulang antrean.**", + "looping_off": "**Pengulangan sekarang dimatikan.**" }, "nowplaying": { - "description": "Shows the currently playing song", - "now_playing": "Now Playing", - "track_info": "[{title}]({uri}) - Requested By: <@{requester}>\n\n`{bar}`" + "description": "Menampilkan lagu yang sedang diputar", + "now_playing": "Sedang Diputar", + "track_info": "[{title}]({uri}) - Direquest Oleh: <@{requester}>\n\n`{bar}`" }, "pause": { - "description": "Pauses the current song", - "successfully_paused": "Successfully paused the song." + "description": "Menjeda lagu saat ini", + "successfully_paused": "Berhasil menjeda lagu." }, "play": { - "description": "Plays a song from YouTube, Spotify or http", + "description": "Memutar lagu dari YouTube, Spotify atau http", "options": { - "song": "The song you want to play" + "song": "Lagu yang ingin Anda putar" }, - "loading": "Loading...", + "loading": "Memuat...", "errors": { - "search_error": "There was an error while searching.", - "no_results": "There were no results found.", - "queue_too_long": "The queue is too long. The maximum length is {maxQueueSize} songs.", - "playlist_too_long": "The playlist is too long. The maximum length is {maxPlaylistSize} songs." + "search_error": "Terjadi kesalahan saat mencari.", + "no_results": "Tidak ditemukan hasil.", + "queue_too_long": "Antrean terlalu panjang. Panjang maksimum adalah {maxQueueSize} lagu.", + "playlist_too_long": "Playlist terlalu panjang. Panjang maksimum adalah {maxPlaylistSize} lagu." }, - "added_to_queue": "Added [{title}]({uri}) to the queue.", - "added_playlist_to_queue": "Added {length} songs to the queue." + "added_to_queue": "Menambahkan [{title}]({uri}) ke antrean.", + "added_playlist_to_queue": "Menambahkan {length} lagu ke antrean." }, "playnext": { - "description": "Add the song to play next in queue", + "description": "Menambahkan lagu untuk diputar selanjutnya dalam antrean", "options": { - "song": "The song you want to play" + "song": "Lagu yang ingin Anda putar" }, - "loading": "Loading...", + "loading": "Memuat...", "errors": { - "search_error": "There was an error while searching.", - "no_results": "There were no results found.", - "queue_too_long": "The queue is too long. The maximum length is {maxQueueSize} songs.", - "playlist_too_long": "The playlist is too long. The maximum length is {maxPlaylistSize} songs." + "search_error": "Terjadi kesalahan saat mencari.", + "no_results": "Tidak ditemukan hasil.", + "queue_too_long": "Antrean terlalu panjang. Maksimum {maxQueueSize} lagu.", + "playlist_too_long": "Playlist terlalu panjang. Maksimum {maxPlaylistSize} lagu." }, - "added_to_play_next": "Added [{title}]({uri}) to play next in the queue.", - "added_playlist_to_play_next": "Added {length} songs to play next in the queue." + "added_to_play_next": "Menambahkan [{title}]({uri}) untuk diputar selanjutnya dalam antrean.", + "added_playlist_to_play_next": "Menambahkan {length} lagu untuk diputar selanjutnya dalam antrean." }, "queue": { - "description": "Shows the current queue", - "now_playing": "Now playing: [{title}]({uri}) - Requested By: <@{requester}> - Duration: `{duration}`", - "live": "LIVE", - "track_info": "{index}. [{title}]({uri}) - Requested By: <@{requester}> - Duration: `{duration}`", - "title": "Queue", - "page_info": "Page {index} of {total}" + "description": "Menampilkan antrean saat ini", + "now_playing": "Sedang diputar: [{title}]({uri}) - Direquest oleh: <@{requester}> - Durasi: `{duration}`", + "live": "LANGSUNG", + "track_info": "{index}. [{title}]({uri}) - Direquest oleh: <@{requester}> - Durasi: `{duration}`", + "title": "Antrean", + "page_info": "Halaman {index} dari {total}" }, "remove": { - "description": "Removes a song from the queue", + "description": "Menghapus lagu dari antrean", "options": { - "song": "The song number you want to remove" + "song": "Nomor lagu yang ingin Anda hapus" }, "errors": { - "no_songs": "There are no songs in the queue.", - "invalid_number": "Please provide a valid song number." + "no_songs": "Tidak ada lagu dalam antrean.", + "invalid_number": "Harap berikan nomor lagu yang valid." }, "messages": { - "removed": "Removed song number {songNumber} from the queue." + "removed": "Menghapus lagu nomor {songNumber} dari antrean." } }, "replay": { - "description": "Replays the current track", + "description": "Memutar ulang lagu saat ini", "errors": { - "not_seekable": "Cannot replay this track as it is not seekable." + "not_seekable": "Tidak dapat memutar ulang lagu ini karena tidak dapat dicari." }, "messages": { - "replaying": "Replaying the current track." + "replaying": "Memutar ulang lagu saat ini." } }, "resume": { - "description": "Resumes the current song", + "description": "Melanjutkan lagu saat ini", "errors": { - "not_paused": "The player is not paused." + "not_paused": "Player tidak sedang dijeda." }, "messages": { - "resumed": "Resumed the player." + "resumed": "Melanjutkan lagu." } }, "search": { - "description": "Searches for a song", + "description": "Mencari lagu", "options": { - "song": "The song you want to search" + "song": "Lagu yang ingin Anda cari" }, "errors": { - "no_results": "No results found.", - "search_error": "There was an error while searching." + "no_results": "Tidak ditemukan hasil.", + "search_error": "Terjadi kesalahan saat mencari." }, "messages": { - "added_to_queue": "Added [{title}]({uri}) to the queue." + "added_to_queue": "Menambahkan [{title}]({uri}) ke antrean." } }, "seek": { - "description": "Seeks to a certain time in the song", + "description": "Mencari ke waktu tertentu dalam lagu", "options": { - "duration": "The duration to seek to" + "duration": "Durasi yang ingin dicari" }, "errors": { - "invalid_format": "Invalid time format. Examples: seek 1m, seek 1h 30m", - "not_seekable": "This track is not seekable.", - "beyond_duration": "Cannot seek beyond the song duration of {length}." + "invalid_format": "Format waktu tidak valid. Contoh: seek 1m, seek 1h 30m", + "not_seekable": "Lagu ini tidak dapat dicari.", + "beyond_duration": "Tidak dapat mencari melewati durasi lagu {length}." }, "messages": { - "seeked_to": "Seeked to {duration}" + "seeked_to": "Mencari ke {duration}" } }, "shuffle": { - "description": "Shuffles the queue", + "description": "Mengacak antrean", "messages": { - "shuffled": "Shuffled the queue." + "shuffled": "Mengacak antrean." } }, "skip": { - "description": "Skips the current song", + "description": "Melewati lagu saat ini", "messages": { - "skipped": "Skipped [{title}]({uri})." + "skipped": "Melewati [{title}]({uri})." } }, "skipto": { - "description": "Skips to a specific song in the queue", + "description": "Melewati ke lagu tertentu dalam antrean", "options": { - "number": "The number of the song you want to skip to" + "number": "Nomor lagu yang ingin Anda lewati" }, "errors": { - "invalid_number": "Please provide a valid number." + "invalid_number": "Harap berikan nomor yang valid." }, "messages": { - "skipped_to": "Skipped to song number {number}." + "skipped_to": "Melewati ke lagu nomor {number}." } }, "stop": { - "description": "Stops the music and clears the queue", + "description": "Menghentikan musik dan membersihkan antrean", "messages": { - "stopped": "Stopped the music and cleared the queue." + "stopped": "Menghentikan musik dan membersihkan antrean." } }, "volume": { - "description": "Sets the volume of the player", + "description": "Mengatur volume musik", "options": { - "number": "The volume you want to set" + "number": "Volume yang ingin Anda atur" }, "messages": { - "invalid_number": "Please provide a valid number.", - "too_low": "The volume can't be lower than 0.", - "too_high": "The volume can't be higher than 200. Do you want to damage your hearing or speakers? Hmmm, I don't think that's such a good idea.", - "set": "Set the volume to {volume}" + "invalid_number": "Harap berikan nomor yang valid.", + "too_low": "Volume tidak boleh lebih rendah dari 0.", + "too_high": "Volume tidak boleh lebih tinggi dari 200. Apakah Anda ingin merusak pendengaran atau speaker Anda? Hmm, saya rasa itu bukan ide yang bagus.", + "set": "Mengatur volume ke {volume}" } }, "addsong": { - "description": "Adds a song to the playlist", + "description": "Menambahkan lagu ke playlist", "options": { - "playlist": "The playlist you want to add", - "song": "The song you want to add" + "playlist": "Playlist yang ingin Anda tambahkan", + "song": "Lagu yang ingin Anda tambahkan" }, "messages": { - "no_playlist": "Please provide a playlist", - "no_song": "Please provide a song", - "playlist_not_found": "That playlist doesn't exist", - "no_songs_found": "No songs found", - "added": "Added {count} song(s) to {playlist}" + "no_playlist": "Harap berikan playlist", + "no_song": "Harap berikan lagu", + "playlist_not_found": "Playlist itu tidak ada", + "no_songs_found": "Tidak ditemukan lagu", + "added": "Menambahkan {count} lagu ke {playlist}" } }, "create": { - "description": "Creates a playlist", + "description": "Membuat playlist", "options": { - "name": "The name of the playlist" + "name": "Nama Playlist" }, "messages": { - "name_too_long": "Playlist names can only be 50 characters long.", - "playlist_exists": "A playlist with that name already exists. Please use a different name.", - "playlist_created": "Playlist **{name}** has been created." + "name_too_long": "Nama playlist hanya boleh 50 karakter.", + "playlist_exists": "Playlist dengan nama itu sudah ada. Harap gunakan nama yang berbeda.", + "playlist_created": "Playlist **{name}** telah dibuat." } }, "delete": { - "description": "Deletes a playlist", + "description": "Menghapus playlist", "options": { - "playlist": "The playlist you want to delete" + "playlist": "Playlist yang ingin Anda hapus" }, "messages": { - "playlist_not_found": "That playlist doesn't exist.", - "playlist_deleted": "Deleted playlist **{playlistName}**." + "playlist_not_found": "Playlist itu tidak ada.", + "playlist_deleted": "Menghapus playlist **{playlistName}**." } }, "list": { - "description": "Retrieves all playlists for the user", + "description": "Mengambil semua playlist untuk user", "options": { - "user": "The user whose playlists you want to retrieve" + "user": "User yang playlistnya ingin Anda ambil" }, "messages": { - "no_playlists": "This user has no playlists.", - "your": "Your", - "playlists_title": "{username}'s Playlists", - "error": "An error occurred while retrieving the playlists." + "no_playlists": "User ini tidak memiliki Playlist.", + "your": "Anda", + "playlists_title": "Playlist {username}", + "error": "Terjadi kesalahan saat mengambil Playlist." } }, "load": { - "description": "Loads a playlist", + "description": "Memuat playlist", "options": { - "playlist": "The playlist you want to load" + "playlist": "Playlist yang ingin Anda muat" }, "messages": { - "playlist_not_exist": "That playlist doesn't exist.", - "playlist_empty": "That playlist is empty.", - "playlist_loaded": "Loaded `{name}` with `{count}` songs." + "playlist_not_exist": "Playlist itu tidak ada.", + "playlist_empty": "Playlist itu kosong.", + "playlist_loaded": "Memuat `{name}` dengan `{count}` lagu." } }, "removesong": { - "description": "Removes a song from the playlist", + "description": "Menghapus lagu dari playlist", "options": { - "playlist": "The playlist you want to remove from", - "song": "The song you want to remove" + "playlist": "Playlist yang ingin Anda hapus dari", + "song": "Lagu yang ingin Anda hapus" }, "messages": { - "provide_playlist": "Please provide a playlist.", - "provide_song": "Please provide a song.", - "playlist_not_exist": "That playlist doesn't exist.", - "song_not_found": "No matching song found.", - "song_removed": "Removed {song} from {playlist}.", - "error_occurred": "An error occurred while removing the song." + "provide_playlist": "Harap berikan playlist.", + "provide_song": "Harap berikan lagu.", + "playlist_not_exist": "Playlist itu tidak ada.", + "song_not_found": "Tidak ditemukan lagu yang cocok.", + "song_removed": "Menghapus {song} dari {playlist}.", + "error_occurred": "Terjadi kesalahan saat menghapus lagu." } }, "steal": { - "description": "Steals a playlist from another user and adds it to your playlists", + "description": "Mencuri playlist dari user lain dan menambahkannya ke playlist Anda", "options": { - "playlist": "The playlist you want to steal", - "user": "The user from whom you want to steal the playlist" + "playlist": "Playlist yang ingin Anda curi", + "user": "User yang ingin Anda curi Playlistnya" }, "messages": { - "provide_playlist": "Please provide a playlist name.", - "provide_user": "Please mention a user.", - "playlist_not_exist": "That playlist doesn't exist for the mentioned user.", - "playlist_stolen": "Successfully stole the playlist `{playlist}` from {user}.", - "error_occurred": "An error occurred while stealing the playlist." + "provide_playlist": "Harap berikan nama playlist.", + "provide_user": "Harap sebutkan user.", + "playlist_not_exist": "Playlist itu tidak ada untuk user yang disebutkan.", + "playlist_stolen": "Berhasil mencuri playlist `{playlist}` dari {user}.", + "error_occurred": "Terjadi kesalahan saat mencuri Playlist." } } }, "buttons": { "invite": "Invite", - "support": "Support Server", - "previous": "Previous", - "resume": "Resume", + "support": "Server Support", + "previous": "Sebelumnya", + "resume": "Lanjutkan", "stop": "Stop", "skip": "Skip", "loop": "Loop", "errors": { - "not_author": "You can't use this button." + "not_author": "Anda tidak dapat menggunakan tombol ini." } }, "player": { "errors": { - "no_player": "There is no active player in this guild.", - "no_channel": "You need to be in a voice channel to use this command.", - "queue_empty": "The queue is empty.", - "no_previous": "There are no previous songs in the queue.", - "no_song": "There are no songs in the queue.", - "already_paused": "The song is already paused." + "no_player": "Tidak ada player yang aktif di server ini.", + "no_channel": "Anda perlu berada di voice channel untuk menggunakan command ini.", + "queue_empty": "Antrean kosong.", + "no_previous": "Tidak ada lagu sebelumnya dalam antrean.", + "no_song": "Tidak ada lagu dalam antrean.", + "already_paused": "Lagu sudah dijeda." }, "trackStart": { - "now_playing": "Now Playing", - "requested_by": "Requested by {user}", - "duration": "Duration", + "now_playing": "Sedang diputar", + "requested_by": "Direquest oleh {user}", + "duration": "Durasi", "author": "Author", - "not_connected_to_voice_channel": "You are not connected to <#{channel}> to use these buttons.", - "need_dj_role": "You need to have the DJ role to use this command.", - "previous_by": "Previous by {user}", - "no_previous_song": "There is no previous song.", - "paused_by": "Paused by {user}", - "resumed_by": "Resumed by {user}", - "skipped_by": "Skipped by {user}", - "no_more_songs_in_queue": "There is no more song in the queue.", - "looping_by": "Looping by {user}", - "looping_queue_by": "Looping Queue by {user}", - "looping_off_by": "Looping Off by {user}" + "not_connected_to_voice_channel": "Anda tidak terhubung ke <#{channel}> untuk menggunakan tombol-tombol ini.", + "need_dj_role": "Anda perlu memiliki role DJ untuk menggunakan command ini.", + "previous_by": "Sebelumnya oleh {user}", + "no_previous_song": "Tidak ada lagu sebelumnya.", + "paused_by": "Dijeda oleh {user}", + "resumed_by": "Dilanjutkan oleh {user}", + "skipped_by": "Dilewati oleh {user}", + "no_more_songs_in_queue": "Tidak ada lagi lagu dalam antrean.", + "looping_by": "Loop oleh {user}", + "looping_queue_by": "Loop antrean oleh {user}", + "looping_off_by": "Loop mati oleh {user}" }, "setupStart": { - "now_playing": "Now Playing", - "description": "[{title}]({uri}) by {author} • `[{length}]` - Requested by <@{requester}>", - "error_searching": "There was an error while searching.", - "no_results": "There were no results found.", - "nothing_playing": "Nothing playing right now.", - "queue_too_long": "The queue is too long. The maximum length is {maxQueueSize} songs.", - "playlist_too_long": "The playlist is too long. The maximum length is {maxPlaylistSize} songs.", - "added_to_queue": "Added [{title}]({uri}) to the queue.", - "added_playlist_to_queue": "Added [{length}] songs from the playlist to the queue." + "now_playing": "Sedang diputar", + "description": "[{title}]({uri}) oleh {author} • `[{length}]` - Direquest oleh <@{requester}>", + "error_searching": "Terjadi kesalahan saat mencari.", + "no_results": "Tidak ditemukan hasil.", + "nothing_playing": "Tidak ada yang diputar saat ini.", + "queue_too_long": "Antrean terlalu panjang. Maksimum {maxQueueSize} lagu.", + "playlist_too_long": "Playlist terlalu panjang. Maksimum {maxPlaylistSize} lagu.", + "added_to_queue": "Menambahkan [{title}]({uri}) ke antrean.", + "added_playlist_to_queue": "Menambahkan [{length}] lagu dari playlist ke antrean." } }, "event": { "interaction": { - "setup_channel": "You can't use this command in the setup channel.", - "no_send_message": "I don't have **`SendMessage`** permission in `{guild}`\nchannel: {channel}.", - "no_embed_links": "I don't have **`EmbedLinks`** permission.", - "no_permission": "I don't have enough permissions to execute this command.", - "no_user_permission": "You don't have enough permissions to use this command.", - "no_voice_channel": "You must be connected to a voice channel to use this `{command}` command.", - "no_connect_permission": "I don't have `CONNECT` permissions to execute this `{command}` command.", - "no_speak_permission": "I don't have `SPEAK` permissions to execute this `{command}` command.", - "no_request_to_speak": "I don't have `REQUEST TO SPEAK` permission to execute this `{command}` command.", - "different_voice_channel": "You are not connected to {channel} to use this `{command}` command.", - "no_music_playing": "Nothing is playing right now.", - "no_dj_role": "DJ role is not set.", - "no_dj_permission": "You need to have the DJ role to use this command.", - "cooldown": "Please wait {time} more second(s) before reusing the `{command}` command.", - "error": "An error occurred: `{error}`" + "setup_channel": "Anda tidak dapat menggunakan command ini di setup channel.", + "no_send_message": "Saya tidak memiliki izin **`SendMessage`** di `{guild}`\nChannel: {channel}.", + "no_embed_links": "Saya tidak memiliki izin **`EmbedLinks`**.", + "no_permission": "Saya tidak memiliki cukup izin untuk menjalankan command ini.", + "no_user_permission": "Anda tidak memiliki cukup izin untuk menggunakan command ini.", + "no_voice_channel": "Anda harus terhubung ke voice channel untuk menggunakan command `{command}` ini.", + "no_connect_permission": "Saya tidak memiliki izin `CONNECT` untuk menjalankan command `{command}` ini.", + "no_speak_permission": "Saya tidak memiliki izin `SPEAK` untuk menjalankan command `{command}` ini.", + "no_request_to_speak": "Saya tidak memiliki izin `REQUEST TO SPEAK` untuk menjalankan command `{command}` ini.", + "different_voice_channel": "Anda tidak terhubung ke {channel} untuk menggunakan command `{command}` ini.", + "no_music_playing": "Tidak ada lagu yang sedang diputar saat ini.", + "no_dj_role": "Role DJ belum diatur.", + "no_dj_permission": "Anda perlu memiliki role DJ untuk menggunakan command ini.", + "cooldown": "Harap tunggu {time} detik lagi sebelum menggunakan kembali command `{command}`.", + "error": "Terjadi kesalahan: `{error}`" }, "message": { - "prefix_mention": "Hey, my prefix for this server is `{prefix}`. Want more info? then do `{prefix}help`\nStay Safe, Stay Awesome!", - "no_send_message": "I don't have **`SendMessage`** permission in `{guild}`\nchannel: {channel}.", - "no_embed_links": "I don't have **`EmbedLinks`** permission.", - "no_permission": "I don't have enough permissions to execute this command.", - "no_user_permission": "You don't have enough permissions to use this command.", - "no_voice_channel": "You must be connected to a voice channel to use this `{command}` command.", - "no_connect_permission": "I don't have `CONNECT` permissions to execute this `{command}` command.", - "no_speak_permission": "I don't have `SPEAK` permissions to execute this `{command}` command.", - "no_request_to_speak": "I don't have `REQUEST TO SPEAK` permission to execute this `{command}` command.", - "different_voice_channel": "You are not connected to {channel} to use this `{command}` command.", - "no_music_playing": "Nothing is playing right now.", - "no_dj_role": "DJ role is not set.", - "no_dj_permission": "You need to have the DJ role to use this command.", - "missing_arguments": "Missing Arguments", - "missing_arguments_description": "Please provide the required arguments for the `{command}` command.\n\nExamples:\n{examples}", - "syntax_footer": "Syntax: [] = optional, <> = required", - "cooldown": "Please wait {time} more second(s) before reusing the `{command}` command.", - "no_mention_everyone": "You can't use this command with everyone or here. Please use slash command.", - "error": "An error occurred: `{error}`", - "no_voice_channel_queue": "You are not connected to a voice channel to queue songs.", - "no_permission_connect_speak": "I don't have enough permission to connect/speak in <#{channel}>.", - "different_voice_channel_queue": "You are not connected to <#{channel}> to queue songs." + "prefix_mention": "Hai, prefix saya untuk server ini adalah `{prefix}`. Ingin informasi lebih lanjut? Lakukan `{prefix}help`\nTetap Aman, Tetap Luar Biasa!", + "no_send_message": "Saya tidak memiliki izin **`SendMessage`** di `{guild}`\nChannel: {channel}.", + "no_embed_links": "Saya tidak memiliki izin **`EmbedLinks`**.", + "no_permission": "Saya tidak memiliki cukup izin untuk menjalankan command ini.", + "no_user_permission": "Anda tidak memiliki cukup izin untuk menggunakan command ini.", + "no_voice_channel": "Anda harus terhubung ke voice channel untuk menggunakan command `{command}` ini.", + "no_connect_permission": "Saya tidak memiliki izin `CONNECT` untuk menjalankan command `{command}` ini.", + "no_speak_permission": "Saya tidak memiliki izin `SPEAK` untuk menjalankan command `{command}` ini.", + "no_request_to_speak": "Saya tidak memiliki izin `REQUEST TO SPEAK` untuk menjalankan command `{command}` ini.", + "different_voice_channel": "Anda tidak terhubung ke {channel} untuk menggunakan command `{command}` ini.", + "no_music_playing": "Tidak ada lagu yang sedang diputar saat ini.", + "no_dj_role": "Role DJ belum diatur.", + "no_dj_permission": "Anda perlu memiliki role DJ untuk menggunakan command ini.", + "missing_arguments": "Argumen tidak lengkap", + "missing_arguments_description": "Harap berikan argumen yang diperlukan untuk command `{command}`.\n\nContoh:\n{examples}", + "syntax_footer": "Sintaks: [] = opsional, <> = wajib", + "cooldown": "Harap tunggu {time} detik lagi sebelum menggunakan kembali command `{command}`.", + "no_mention_everyone": "Anda tidak dapat menggunakan command ini dengan everyone atau here. Silakan gunakan slash command.", + "error": "Terjadi kesalahan: `{error}`", + "no_voice_channel_queue": "Anda tidak terhubung ke voice channel untuk menambahkan lagu ke antrean.", + "no_permission_connect_speak": "Saya tidak memiliki cukup izin untuk terhubung/berbicara di <#{channel}>.", + "different_voice_channel_queue": "Anda tidak terhubung ke <#{channel}> untuk menambahkan lagu ke antrean." }, "setupButton": { - "no_voice_channel_button": "You are not connected to a voice channel to use this button.", - "different_voice_channel_button": "You are not connected to {channel} to use these buttons.", - "now_playing": "Now Playing", + "no_voice_channel_button": "Anda tidak terhubung ke voice channel untuk menggunakan tombol ini.", + "different_voice_channel_button": "Anda tidak terhubung ke {channel} untuk menggunakan tombol-tombol ini.", + "now_playing": "Sedang diputar", "live": "LIVE", - "requested_by": "Requested by <@{requester}>", - "no_dj_permission": "You need to have the DJ role to use this button.", - "volume_set": "Volume set to {vol}%", + "requested_by": "Direquest oleh <@{requester}>", + "no_dj_permission": "Anda perlu memiliki role DJ untuk menggunakan tombol ini.", + "volume_set": "Volume diatur ke {vol}%", "volume_footer": "Volume: {vol}%", - "paused": "Paused", - "resumed": "Resumed", - "pause_resume": "{name} the music.", - "pause_resume_footer": "{name} by {displayName}", - "no_music_to_skip": "There is no music to skip.", - "skipped": "Skipped the music.", - "skipped_footer": "Skipped by {displayName}", - "stopped": "Stopped the music.", - "stopped_footer": "Stopped by {displayName}", - "nothing_playing": "Nothing playing right now.", - "loop_set": "Loop set to {loop}.", - "loop_footer": "Loop set to {loop} by {displayName}", - "shuffled": "Shuffled the queue.", - "no_previous_track": "There is no previous track.", - "playing_previous": "Playing the previous track.", - "previous_footer": "Playing the previous track by {displayName}", - "rewind_limit": "You cannot rewind the music more than the length of the song.", - "rewinded": "Rewinded the music.", - "rewind_footer": "Rewinded by {displayName}", - "forward_limit": "You cannot forward the music more than the length of the song.", - "forwarded": "Forwarded the music.", - "forward_footer": "Forwarded by {displayName}", - "button_not_available": "This button is not available.", - "no_music_playing": "There is no music playing in this server." + "paused": "Dipause", + "resumed": "Diresume", + "pause_resume": "{name} lagu.", + "pause_resume_footer": "{name} oleh {displayName}", + "no_music_to_skip": "Tidak ada lagu untuk dilewati.", + "skipped": "Melewati lagu.", + "skipped_footer": "Dilewati oleh {displayName}", + "stopped": "Menghentikan lagu.", + "stopped_footer": "Dihentikan oleh {displayName}", + "nothing_playing": "Tidak ada yang diputar saat ini.", + "loop_set": "Loop diatur ke {loop}.", + "loop_footer": "Loop diatur ke {loop} oleh {displayName}", + "shuffled": "Mengacak antrean.", + "no_previous_track": "Tidak ada lagu sebelumnya.", + "playing_previous": "Memutar lagu sebelumnya.", + "previous_footer": "Memutar lagu sebelumnya oleh {displayName}", + "rewind_limit": "Anda tidak dapat memutar mundur lagu lebih dari panjang lagu.", + "rewinded": "Memutar mundur lagu.", + "rewind_footer": "Diputar mundur oleh {displayName}", + "forward_limit": "Anda tidak dapat memajukan lagu lebih dari panjang lagu.", + "forwarded": "Memajukan lagu.", + "forward_footer": "Dimajukan oleh {displayName}", + "button_not_available": "Tombol ini tidak tersedia.", + "no_music_playing": "Tidak ada lagu yang diputar di server ini." } }, - "Evaluate code": "Evaluate code", - "Leave a guild": "Leave a guild", - "List all guilds the bot is in": "List all guilds the bot is in", - "Restart the bot": "Restart the bot" -} \ No newline at end of file + "Evaluate code": "Evaluasi kode", + "Leave a guild": "Tinggalkan server", + "List all guilds the bot is in": "Daftar semua server tempat bot berada", + "Restart the bot": "Restart bot" +} diff --git a/locales/Japanese.json b/locales/Japanese.json index 45c6d8f56..07de728d6 100644 --- a/locales/Japanese.json +++ b/locales/Japanese.json @@ -240,7 +240,7 @@ }, "grab": { "description": "現在再生中の曲をDMに送信します", - "content": "**再生時間:** {length}\n**リクエスト者:** {requester}\n**リンク:** [ここをクリック]({uri})", + "content": "**再生時間:** {length}\n**リクエスト者:** <@{requester}>\n**リンク:** [ここをクリック]({uri})", "check_dm": "DMを確認してください。", "dm_failed": "DMを送信できませんでした。" }, @@ -264,7 +264,7 @@ "nowplaying": { "description": "現在再生中の曲を表示します", "now_playing": "再生中", - "track_info": "[{title}]({uri}) - リクエスト者: {requester}\n\n`{bar}`" + "track_info": "[{title}]({uri}) - リクエスト者: <@{requester}>\n\n`{bar}`" }, "pause": { "description": "現在の曲を一時停止します", @@ -536,7 +536,7 @@ }, "setupStart": { "now_playing": "再生中", - "description": "[{title}]({uri}) by {author} • `[${length}]` - <@{requester}> によってリクエストされました", + "description": "[{title}]({uri}) by {author} • `[{length}]` - <@{requester}> によってリクエストされました", "error_searching": "検索中にエラーが発生しました。", "no_results": "結果が見つかりませんでした。", "nothing_playing": "現在再生中の曲はありません。", @@ -593,7 +593,7 @@ "different_voice_channel_button": "これらのボタンを使用するために {channel} に接続されていません。", "now_playing": "再生中", "live": "ライブ", - "requested_by": "{requester} によってリクエストされました", + "requested_by": "<@{requester}> によってリクエストされました", "no_dj_permission": "このコマンドを使用するにはDJロールが必要です。", "volume_set": "音量を {vol}% に設定しました。", "volume_footer": "音量: {vol}%", @@ -619,7 +619,8 @@ "forward_limit": "曲の長さ以上に早送りすることはできません。", "forwarded": "音楽を早送りしました。", "forward_footer": "{displayName} によって早送りされました", - "button_not_available": "このボタンは使用できません。" + "button_not_available": "このボタンは使用できません。", + "no_music_playing": "現在、何も再生されていません。" } }, "Evaluate code": "コードを評価", diff --git a/locales/Korean.json b/locales/Korean.json index 1e062de03..fcf424ff3 100644 --- a/locales/Korean.json +++ b/locales/Korean.json @@ -314,7 +314,7 @@ "song": "삭제할 노래의 대기열 번호" }, "errors": { - "no_songs": "대기열에 노래가 없어요.", + "no_songs": "그 대기열 번호에 등록된 노래가 없어요.", "invalid_number": "올바른 노래 번호를 지정해주세요." }, "messages": { @@ -513,8 +513,8 @@ "no_player": "이 서버에 활성 플레이어가 없어요.", "no_channel": "이 명령어를 사용하려면 먼저 음성 채널에 접속해주세요.", "queue_empty": "대기열이 비어있어요.", - "no_previous": "대기열에 이전 노래가 없어요.", - "no_song": "대기열에 노래가 없어요.", + "no_previous": "이전 노래가 없어요.", + "no_song": "스킵할 노래가 없어요.", "already_paused": "노래가 이미 일시정지되어있어요." }, "trackStart": { @@ -536,7 +536,7 @@ }, "setupStart": { "now_playing": "재생 중", - "description": "[{title}]({uri}), 제작자 {author} • `[${length}]` - 요청자: <@{requester}>", + "description": "[{title}]({uri}), 제작자 {author} • `[{length}]` - 요청자: <@{requester}>", "error_searching": "노래를 검색하는 도중 오류가 발생했어요.", "no_results": "검색결과가 없어요.", "nothing_playing": "현재 재생 중인 노래가 없어요.", @@ -619,7 +619,8 @@ "forward_limit": "현재 노래 길이보다 더 빨리감기할 수 없어요.", "forwarded": "노래를 빨리감기했어요.", "forward_footer": "{displayName}에 의해 빨리감기됨", - "button_not_available": "이 버튼은 사용할 수 없어요." + "button_not_available": "이 버튼은 사용할 수 없어요.", + "no_music_playing": "현재 재생 중인 노래가 없어요." } }, "Evaluate code": "코드를 실행해요", diff --git a/locales/SpanishES.json b/locales/SpanishES.json index 6f4dd6fae..c27a668e1 100644 --- a/locales/SpanishES.json +++ b/locales/SpanishES.json @@ -336,7 +336,7 @@ "search_error": "Se ha producido un error durante la búsqueda." }, "messages": { - "added_to_queue": "Se ha añadido [{{title}}]({{uri}}) a la cola." + "added_to_queue": "Se ha añadido [{title}]({uri}) a la cola." } }, "seek": { diff --git a/locales/Vietnamese.json b/locales/Vietnamese.json index b3d05a3bb..92f7d1b08 100644 --- a/locales/Vietnamese.json +++ b/locales/Vietnamese.json @@ -1,630 +1,630 @@ { - "cmd": { - "247": { - "description": "Đặt bot ở lại trong kênh thoại", - "errors": { - "not_in_voice": "Bạn cần phải ở trong một kênh thoại để sử dụng lệnh này.", - "generic": "Đã xảy ra lỗi khi cố gắng thực thi lệnh này." - }, - "messages": { - "disabled": "`✅` | Chế độ 24/7 đã được `TẮT`", - "enabled": "`✅` | Chế độ 24/7 đã được `BẬT`. \n**Bot sẽ không rời khỏi kênh thoại ngay cả khi không có người trong kênh thoại.**" - } - }, - "ping": { - "description": "Hiển thị độ trễ của bot.", - "content": "Đang kiểm tra độ trễ...", - "bot_latency": "Độ trễ của Bot", - "api_latency": "Độ trễ của API", - "requested_by": "Yêu cầu bởi {author}" - }, - "lavalink": { - "description": "Hiển thị thông tin hiện tại của Lavalink.", - "title": "Thông tin Lavalink", - "content": "Trình phát: {players}\nTrình phát đang hoạt động: {playingPlayers}\nThời gian hoạt động: {uptime}\nSố lõi: {cores} Lõi\nSử dụng bộ nhớ: {used} / {reservable}\nTải hệ thống: {systemLoad}%\nTải Lavalink: {lavalinkLoad}%" - }, - "invite": { - "description": "Nhận liên kết mời bot.", - "content": "Bạn có thể mời tôi bằng cách nhấp vào nút dưới đây. Có lỗi hoặc sự cố? Tham gia máy chủ hỗ trợ!" - }, - "help": { - "description": "Hiển thị menu trợ giúp.", - "options": { - "command": "Lệnh bạn muốn xem thông tin" - }, - "content": "Chào bạn! Tôi là {bot}, một bot phát nhạc được tạo bởi [Lavamusic](https://github.com/appujet/lavamusic) và Discord. Bạn có thể sử dụng `{prefix}help ` để biết thêm thông tin về lệnh.", - "title": "Menu trợ giúp", - "not_found": "Lệnh `{cmdName}` này không tồn tại.", - "help_cmd": "**Mô tả:** {description}\n**Cách sử dụng:** {usage}\n**Ví dụ:** {examples}\n**Biệt danh:** {aliases}\n**Danh mục:** {category}\n**Thời gian chờ:** {cooldown} giây\n**Quyền:** {premUser}\n**Quyền của bot:** {premBot}\n**Chỉ dành cho nhà phát triển:** {dev}\n**Lệnh Slash:** {slash}\n**Tham số:** {args}\n**Trình phát:** {player}\n**DJ:** {dj}\n**Quyền của DJ:** {djPerm}\n**Giọng nói:** {voice}", - "footer": "Sử dụng {prefix}help để biết thêm thông tin về lệnh" - }, - "botinfo": { - "description": "Thông tin về bot", - "content": "Thông tin bot:\n- **Hệ điều hành**: {osInfo}\n- **Thời gian hoạt động**: {osUptime}\n- **Tên máy chủ**: {osHostname}\n- **Kiến trúc CPU**: {cpuInfo}\n- **Sử dụng CPU**: {cpuUsed}%\n- **Sử dụng bộ nhớ**: {memUsed}MB / {memTotal}GB\n- **Phiên bản Node**: {nodeVersion}\n- **Phiên bản Discord**: {discordJsVersion}\n- **Kết nối với** {guilds} máy chủ, {channels} kênh, và {users} người dùng\n- **Tổng số lệnh**: {commands}" - }, - "about": { - "description": "Hiển thị thông tin về bot", - "fields": { - "creator": "Người tạo", - "repository": "Kho lưu trữ", - "support": "Hỗ trợ", - "description": "Anh ấy thực sự muốn tạo dự án mã nguồn mở đầu tiên của mình để có thêm kinh nghiệm lập trình. Trong dự án này, anh ấy đã thách thức bản thân để tạo ra một dự án với ít lỗi hơn. Hy vọng bạn thích sử dụng LavaMusic!" - } - }, - "dj": { - "description": "Quản lý chế độ DJ và các vai trò liên quan", - "errors": { - "provide_role": "Vui lòng cung cấp một vai trò.", - "no_roles": "Vai trò DJ rỗng.", - "invalid_subcommand": "Vui lòng cung cấp một lệnh phụ hợp lệ." - }, - "messages": { - "role_exists": "Vai trò DJ <@&{roleId}> đã được thêm.", - "role_added": "Vai trò DJ <@&{roleId}> đã được thêm.", - "role_not_found": "Vai trò DJ <@&{roleId}> chưa được thêm.", - "role_removed": "Vai trò DJ <@&{roleId}> đã được xóa.", - "all_roles_cleared": "Tất cả vai trò DJ đã được xóa.", - "toggle": "Chế độ DJ đã được chuyển sang {status}." - }, - "options": { - "add": "Vai trò DJ bạn muốn thêm", - "remove": "Vai trò DJ bạn muốn xóa", - "clear": "Xóa tất cả các vai trò DJ", - "toggle": "Chuyển đổi chế độ DJ", - "role": "Vai trò DJ" - }, - "subcommands": "Lệnh phụ" - }, - "language": { - "description": "Đặt ngôn ngữ cho bot", - "invalid_language": "Vui lòng cung cấp một ngôn ngữ hợp lệ. Ví dụ: `EnglishUS` cho tiếng Anh (Hoa Kỳ)\n\nBạn có thể tìm danh sách các ngôn ngữ được hỗ trợ [tại đây](https://discord.com/developers/docs/reference#locales)\n\n**Ngôn ngữ có sẵn:**\n{languages}", - "already_set": "Ngôn ngữ đã được đặt thành `{language}`", - "not_set": "Ngôn ngữ chưa được đặt.", - "set": "`✅` | Ngôn ngữ đã được đặt thành `{language}`", - "reset": "`✅` | Ngôn ngữ đã được đặt lại về ngôn ngữ mặc định.", - "options": { - "set": "Đặt ngôn ngữ cho bot", - "language": "Ngôn ngữ bạn muốn đặt", - "reset": "Đặt lại ngôn ngữ về ngôn ngữ mặc định" - } - }, - "prefix": { - "description": "Hiển thị hoặc đặt tiền tố của bot", - "errors": { - "prefix_too_long": "Tiền tố không được dài hơn 3 ký tự." - }, - "messages": { - "current_prefix": "Tiền tố cho máy chủ này là `{prefix}`", - "prefix_set": "Tiền tố cho máy chủ này bây giờ là `{prefix}`", - "prefix_reset": "Tiền tố cho máy chủ này bây giờ là `{prefix}`" - }, - "options": { - "set": "Đặt tiền tố", - "prefix": "Tiền tố bạn muốn đặt", - "reset": "Đặt lại tiền tố về mặc định" - } - }, - "setup": { - "description": "Thiết lập bot", - "errors": { - "channel_exists": "Kênh yêu cầu bài hát đã tồn tại.", - "channel_not_exists": "Kênh yêu cầu bài hát không tồn tại.", - "channel_delete_fail": "Kênh yêu cầu bài hát đã bị xóa. Nếu kênh không bị xóa bình thường, vui lòng tự xóa nó." - }, - "messages": { - "channel_created": "Kênh yêu cầu bài hát đã được tạo trong <#{channelId}>.", - "channel_deleted": "Kênh yêu cầu bài hát đã bị xóa.", - "channel_info": "Kênh yêu cầu bài hát là <#{channelId}>." - }, - "options": { - "create": "Tạo kênh yêu cầu bài hát", - "delete": "Xóa kênh yêu cầu bài hát", - "info": "Hiển thị kênh yêu cầu bài hát" - } - }, - "8d": { - "description": "bật/tắt bộ lọc 8d", - "messages": { - "filter_enabled": "`✅` | Bộ lọc 8D đã được `BẬT`.", - "filter_disabled": "`✅` | Bộ lọc 8D đã được `TẮT`." - } - }, - "bassboost": { - "description": "bật/tắt bộ lọc bassboost", - "messages": { - "filter_enabled": "`✅` | Bộ lọc Bassboost đã được `BẬT`. \n**Cẩn thận, nghe quá to có thể gây hại cho thính giác của bạn!**", - "filter_disabled": "`✅` | Bộ lọc Bassboost đã được `TẮT`." - } - }, - "distorsion": { - "description": "Bật/tắt bộ lọc distortion", - "messages": { - "filter_enabled": "`✅` | Bộ lọc Distortion đã được `BẬT`.", - "filter_disabled": "`✅` | Bộ lọc Distortion đã được `TẮT`." - } - }, - "karaoke": { - "description": "Bật/tắt bộ lọc karaoke", - "messages": { - "filter_enabled": "`✅` | Bộ lọc Karaoke đã được `BẬT`.", - "filter_disabled": "`✅` | Bộ lọc Karaoke đã được `TẮT`." - } - }, - "lowpass": { - "description": "Bật/tắt bộ lọc lowpass", - "messages": { - "filter_enabled": "`✅` | Bộ lọc Lowpass đã được `BẬT`.", - "filter_disabled": "`✅` | Bộ lọc Lowpass đã được `TẮT`." - } - }, - "nightcore": { - "description": "Bật/tắt bộ lọc nightcore", - "messages": { - "filter_enabled": "`✅` | Bộ lọc Nightcore đã được `BẬT`.", - "filter_disabled": "`✅` | Bộ lọc Nightcore đã được `TẮT`." - } - }, - "pitch": { - "description": "Bật/tắt bộ lọc pitch", - "options": { - "pitch": "Số bạn muốn đặt độ cao (giữa 0.5 và 5)" - }, - "errors": { - "invalid_number": "Vui lòng cung cấp một số hợp lệ giữa 0.5 và 5." - }, - "messages": { - "pitch_set": "`✅` | Độ cao đã được đặt thành **{pitch}**." - } - }, - "rate": { - "description": "Thay đổi tốc độ của bài hát", - "options": { - "rate": "Số bạn muốn đặt tốc độ (giữa 0.5 và 5)" - }, - "errors": { - "invalid_number": "Vui lòng cung cấp một số hợp lệ giữa 0.5 và 5." - }, - "messages": { - "rate_set": "`✅` | Tốc độ đã được đặt thành **{rate}**." - } - }, - "reset": { - "description": "Đặt lại các bộ lọc đang hoạt động", - "messages": { - "filters_reset": "`✅` | Các bộ lọc đã được đặt lại." - } - }, - "rotation": { - "description": "Bật/tắt bộ lọc rotation", - "messages": { - "enabled": "`✅` | Bộ lọc Rotation đã được `BẬT`.", - "disabled": "`✅` | Bộ lọc Rotation đã được `TẮT`." - } - }, - "speed": { - "description": "Thay đổi tốc độ của bài hát", - "options": { - "speed": "Tốc độ bạn muốn đặt" - }, - "messages": { - "invalid_number": "Vui lòng cung cấp một số hợp lệ giữa 0.5 và 5.", - "set_speed": "`✅` | Tốc độ đã được đặt thành **{speed}**." - } - }, - "tremolo": { - "description": "Bật/tắt bộ lọc tremolo", - "messages": { - "enabled": "`✅` | Bộ lọc Tremolo đã được `BẬT`.", - "disabled": "`✅` | Bộ lọc Tremolo đã được `TẮT`." - } - }, - "vibrato": { - "description": "Bật/tắt bộ lọc vibrato", - "messages": { - "enabled": "`✅` | Bộ lọc Vibrato đã được `BẬT`.", - "disabled": "`✅` | Bộ lọc Vibrato đã được `TẮT`." - } - }, - "autoplay": { - "description": "Bật/tắt chế độ tự động phát", - "messages": { - "enabled": "`✅` | Chế độ tự động phát đã được `BẬT`.", - "disabled": "`✅` | Chế độ tự động phát đã được `TẮT`." - } - }, - "clearqueue": { - "description": "Xóa hàng chờ", - "messages": { - "cleared": "Hàng chờ đã được xóa." - } - }, - "grab": { - "description": "Lấy bài hát đang phát hiện tại vào tin nhắn trực tiếp của bạn", - "content": "**Thời lượng:** {length}\n**Yêu cầu bởi:** <@{requester}>\n**Liên kết:** [Nhấp vào đây]({uri})", - "check_dm": "Vui lòng kiểm tra tin nhắn trực tiếp của bạn.", - "dm_failed": "Tôi không thể gửi tin nhắn trực tiếp cho bạn. Vui lòng đảm bảo rằng tin nhắn trực tiếp đã được bật." - }, - "join": { - "description": "Tham gia kênh thoại", - "already_connected": "Tôi đã kết nối với <#{channelId}>.", - "no_voice_channel": "Bạn cần phải ở trong một kênh thoại để sử dụng lệnh này.", - "joined": "Đã tham gia thành công <#{channelId}>." - }, - "leave": { - "description": "Rời khỏi kênh thoại", - "left": "Đã rời khỏi <#{channelId}> thành công.", - "not_in_channel": "Tôi không có trong kênh thoại." - }, - "loop": { - "description": "Lặp lại bài hát hiện tại hoặc hàng chờ", - "looping_song": "**Đang lặp lại bài hát.**", - "looping_queue": "**Đang lặp lại hàng chờ.**", - "looping_off": "**Đã tắt chế độ lặp lại.**" - }, - "nowplaying": { - "description": "Hiển thị bài hát đang phát hiện tại", - "now_playing": "Đang phát", - "track_info": "[{title}]({uri}) - Yêu cầu bởi: <@{requester}>\n\n`{bar}`" - }, - "pause": { - "description": "Tạm dừng bài hát hiện tại", - "successfully_paused": "Đã tạm dừng bài hát thành công." - }, - "play": { - "description": "Phát một bài hát từ YouTube, Spotify hoặc http", - "options": { - "song": "Bài hát bạn muốn phát" - }, - "loading": "Đang tải...", - "errors": { - "search_error": "Đã xảy ra lỗi khi tìm kiếm.", - "no_results": "Không tìm thấy kết quả.", - "queue_too_long": "Hàng chờ quá dài. Độ dài tối đa là {maxQueueSize} bài hát.", - "playlist_too_long": "Danh sách phát quá dài. Độ dài tối đa là {maxPlaylistSize} bài hát." - }, - "added_to_queue": "Đã thêm [{title}]({uri}) vào hàng chờ.", - "added_playlist_to_queue": "Đã thêm {length} bài hát vào hàng chờ." - }, - "playnext": { - "description": "Thêm bài hát để phát tiếp theo trong hàng chờ", - "options": { - "song": "Bài hát bạn muốn phát" - }, - "loading": "Đang tải...", - "errors": { - "search_error": "Đã xảy ra lỗi khi tìm kiếm.", - "no_results": "Không tìm thấy kết quả.", - "queue_too_long": "Hàng chờ quá dài. Độ dài tối đa là {maxQueueSize} bài hát.", - "playlist_too_long": "Danh sách phát quá dài. Độ dài tối đa là {maxPlaylistSize} bài hát." - }, - "added_to_play_next": "Đã thêm [{title}]({uri}) để phát tiếp theo trong hàng chờ.", - "added_playlist_to_play_next": "Đã thêm {length} bài hát để phát tiếp theo trong hàng chờ." - }, - "queue": { - "description": "Hiển thị hàng chờ hiện tại", - "now_playing": "Đang phát: [{title}]({uri}) - Yêu cầu bởi: <@{requester}> - Thời lượng: `{duration}`", - "live": "TRỰC TIẾP", - "track_info": "{index}. [{title}]({uri}) - Yêu cầu bởi: <@{requester}> - Thời lượng: `{duration}`", - "title": "Hàng chờ", - "page_info": "Trang {index} của {total}" - }, - "remove": { - "description": "Xóa một bài hát khỏi hàng chờ", - "options": { - "song": "Số bài hát bạn muốn xóa" - }, - "errors": { - "no_songs": "Không có bài hát nào trong hàng chờ.", - "invalid_number": "Vui lòng cung cấp một số hợp lệ." - }, - "messages": { - "removed": "Đã xóa bài hát số {songNumber} khỏi hàng chờ." - } - }, - "replay": { - "description": "Phát lại bài hát hiện tại", - "errors": { - "not_seekable": "Không thể phát lại bài hát này vì không thể tìm kiếm được." - }, - "messages": { - "replaying": "Đang phát lại bài hát hiện tại." - } - }, - "resume": { - "description": "Tiếp tục phát bài hát hiện tại", - "errors": { - "not_paused": "Trình phát không bị tạm dừng." - }, - "messages": { - "resumed": "Trình phát đã được tiếp tục." - } - }, - "search": { - "description": "Tìm kiếm một bài hát", - "options": { - "song": "Bài hát bạn muốn tìm kiếm" - }, - "errors": { - "no_results": "Không tìm thấy kết quả.", - "search_error": "Đã xảy ra lỗi khi tìm kiếm." - }, - "messages": { - "added_to_queue": "Đã thêm [{title}]({uri}) vào hàng chờ." - } - }, - "seek": { - "description": "Tìm đến một thời điểm nhất định trong bài hát", - "options": { - "duration": "Thời gian bạn muốn tìm đến" - }, - "errors": { - "invalid_format": "Định dạng thời gian không hợp lệ. Ví dụ: seek 1m, seek 1h 30m", - "not_seekable": "Không thể tìm kiếm bài hát này.", - "beyond_duration": "Không thể tìm kiếm vượt quá thời lượng bài hát {length}." - }, - "messages": { - "seeked_to": "Đã tìm đến {duration}" - } - }, - "shuffle": { - "description": "Trộn hàng chờ", - "messages": { - "shuffled": "Hàng chờ đã được trộn." - } - }, - "skip": { - "description": "Bỏ qua bài hát hiện tại", - "messages": { - "skipped": "Đã bỏ qua [{title}]({uri})." - } - }, - "skipto": { - "description": "Bỏ qua đến một bài hát cụ thể trong hàng chờ", - "options": { - "number": "Số của bài hát bạn muốn bỏ qua đến" - }, - "errors": { - "invalid_number": "Vui lòng cung cấp một số hợp lệ." - }, - "messages": { - "skipped_to": "Đã bỏ qua đến bài hát số {number}." - } - }, - "stop": { - "description": "Dừng nhạc và xóa hàng chờ", - "messages": { - "stopped": "Đã dừng nhạc và xóa hàng chờ." - } - }, - "volume": { - "description": "Đặt âm lượng của trình phát", - "options": { - "number": "Âm lượng bạn muốn đặt" - }, - "messages": { - "invalid_number": "Vui lòng cung cấp một số hợp lệ.", - "too_low": "Âm lượng không thể thấp hơn 0.", - "too_high": "Âm lượng không thể cao hơn 200. Bạn có muốn làm hỏng tai hoặc loa của mình không? Hmmm, tôi không nghĩ đó là một ý kiến hay.", - "set": "Âm lượng đã được đặt thành {volume}" - } - }, - "addsong": { - "description": "Thêm một bài hát vào danh sách phát", - "options": { - "playlist": "Danh sách phát bạn muốn thêm", - "song": "Bài hát bạn muốn thêm" - }, - "messages": { - "no_playlist": "Vui lòng cung cấp một danh sách phát", - "no_song": "Vui lòng cung cấp một bài hát", - "playlist_not_found": "Danh sách phát đó không tồn tại", - "no_songs_found": "Không tìm thấy bài hát nào", - "added": "Đã thêm {count} bài hát vào {playlist}" - } - }, - "create": { - "description": "Tạo một danh sách phát", - "options": { - "name": "Tên của danh sách phát" - }, - "messages": { - "name_too_long": "Tên danh sách phát chỉ có thể dài 50 ký tự.", - "playlist_exists": "Danh sách phát với tên đó đã tồn tại. Vui lòng sử dụng tên khác.", - "playlist_created": "Danh sách phát **{name}** đã được tạo." - } - }, - "delete": { - "description": "Xóa một danh sách phát", - "options": { - "playlist": "Danh sách phát bạn muốn xóa" - }, - "messages": { - "playlist_not_found": "Danh sách phát đó không tồn tại.", - "playlist_deleted": "Đã xóa danh sách phát **{playlistName}**." - } - }, - "list": { - "description": "Lấy tất cả danh sách phát của người dùng", - "options": { - "user": "Người dùng mà bạn muốn lấy danh sách phát" - }, - "messages": { - "no_playlists": "Người dùng này không có danh sách phát nào.", - "your": "Danh sách phát của bạn", - "playlists_title": "Danh sách phát của {username}", - "error": "Đã xảy ra lỗi khi lấy danh sách phát." - } - }, - "load": { - "description": "Tải một danh sách phát", - "options": { - "playlist": "Danh sách phát bạn muốn tải" - }, - "messages": { - "playlist_not_exist": "Danh sách phát đó không tồn tại.", - "playlist_empty": "Danh sách phát đó trống.", - "playlist_loaded": "Đã tải `{name}` với `{count}` bài hát." - } - }, - "removesong": { - "description": "Xóa một bài hát khỏi danh sách phát", - "options": { - "playlist": "Danh sách phát bạn muốn xóa khỏi", - "song": "Bài hát bạn muốn xóa" - }, - "messages": { - "provide_playlist": "Vui lòng cung cấp một danh sách phát.", - "provide_song": "Vui lòng cung cấp một bài hát.", - "playlist_not_exist": "Danh sách phát đó không tồn tại.", - "song_not_found": "Không tìm thấy bài hát phù hợp.", - "song_removed": "Đã xóa {song} khỏi {playlist}.", - "error_occurred": "Đã xảy ra lỗi khi xóa bài hát." - } - }, - "steal": { - "description": "Đánh cắp một danh sách phát từ người dùng khác và thêm vào danh sách phát của bạn", - "options": { - "playlist": "Danh sách phát bạn muốn đánh cắp", - "user": "Người dùng mà bạn muốn đánh cắp danh sách phát" - }, - "messages": { - "provide_playlist": "Vui lòng cung cấp tên danh sách phát.", - "provide_user": "Vui lòng nhắc đến một người dùng.", - "playlist_not_exist": "Danh sách phát đó không tồn tại cho người dùng được đề cập.", - "playlist_stolen": "Đã đánh cắp danh sách phát `{playlist}` từ {user} thành công.", - "error_occurred": "Đã xảy ra lỗi khi đánh cắp danh sách phát." - } - } - }, - "buttons": { - "invite": "Mời", - "support": "Máy chủ hỗ trợ", - "previous": "Trước", - "resume": "Tiếp tục", - "stop": "Dừng", - "skip": "Bỏ qua", - "loop": "Lặp lại", - "errors": { - "not_author": "Bạn không thể sử dụng nút này." - } - }, - "player": { - "errors": { - "no_player": "Không có player hoạt động trong guild này.", - "no_channel": "Bạn cần phải ở trong một kênh thoại để sử dụng lệnh này.", - "queue_empty": "Danh sách phát đang trống.", - "no_previous": "Không có bài hát trước trong danh sách phát.", - "no_song": "Không có bài hát nào trong danh sách phát.", - "already_paused": "Bài hát đã được tạm dừng rồi." - }, - "trackStart": { - "now_playing": "Đang phát", - "requested_by": "Yêu cầu bởi {user}", - "duration": "Thời gian", - "author": "Tác giả", - "not_connected_to_voice_channel": "Bạn không kết nối với <#{channel}> để sử dụng các nút này.", - "need_dj_role": "Bạn cần có vai trò DJ để sử dụng lệnh này.", - "previous_by": "Trước đó bởi {user}", - "no_previous_song": "Không có bài hát trước.", - "paused_by": "Tạm dừng bởi {user}", - "resumed_by": "Tiếp tục bởi {user}", - "skipped_by": "Bỏ qua bởi {user}", - "no_more_songs_in_queue": "Không còn bài hát nào trong danh sách phát.", - "looping_by": "Lặp lại bởi {user}", - "looping_queue_by": "Lặp lại danh sách phát bởi {user}", - "looping_off_by": "Tắt lặp lại bởi {user}" - }, - "setupStart": { - "now_playing": "Đang phát", - "description": "[{title}]({uri}) của {author} • `[{length}]` - Yêu cầu bởi <@{requester}>", - "error_searching": "Đã xảy ra lỗi khi tìm kiếm.", - "no_results": "Không tìm thấy kết quả.", - "nothing_playing": "Hiện tại không có gì đang phát.", - "queue_too_long": "Danh sách phát quá dài. Độ dài tối đa là {maxQueueSize} bài hát.", - "playlist_too_long": "Danh sách phát quá dài. Độ dài tối đa là {maxPlaylistSize} bài hát.", - "added_to_queue": "Đã thêm [{title}]({uri}) vào danh sách phát.", - "added_playlist_to_queue": "Đã thêm [{length}] bài hát từ danh sách phát vào danh sách phát." - } - }, - "event": { - "interaction": { - "setup_channel": "Bạn không thể sử dụng lệnh này trong kênh thiết lập.", - "no_send_message": "Tôi không có quyền **`SendMessage`** trong `{guild}`\nKênh: {channel}.", - "no_embed_links": "Tôi không có quyền **`EmbedLinks`**.", - "no_permission": "Tôi không có đủ quyền để thực hiện lệnh này.", - "no_user_permission": "Bạn không có đủ quyền để sử dụng lệnh này.", - "no_voice_channel": "Bạn phải kết nối với một kênh thoại để sử dụng lệnh `{command}` này.", - "no_connect_permission": "Tôi không có quyền `CONNECT` để thực hiện lệnh `{command}` này.", - "no_speak_permission": "Tôi không có quyền `SPEAK` để thực hiện lệnh `{command}` này.", - "no_request_to_speak": "Tôi không có quyền `REQUEST TO SPEAK` để thực hiện lệnh `{command}` này.", - "different_voice_channel": "Bạn không kết nối với {channel} để sử dụng lệnh `{command}` này.", - "no_music_playing": "Hiện tại không có gì đang phát.", - "no_dj_role": "Vai trò DJ chưa được thiết lập.", - "no_dj_permission": "Bạn cần có vai trò DJ để sử dụng lệnh này.", - "cooldown": "Vui lòng đợi {time} giây nữa trước khi sử dụng lệnh `{command}` này.", - "error": "Đã xảy ra lỗi: `{error}`" - }, - "message": { - "prefix_mention": "Chào, tiền tố của tôi cho máy chủ này là `{prefix}`. Muốn biết thêm thông tin? thì hãy dùng `{prefix}help`\nHãy an toàn, hãy tuyệt vời!", - "no_send_message": "Tôi không có quyền **`SendMessage`** trong `{guild}`\nKênh: {channel}.", - "no_embed_links": "Tôi không có quyền **`EmbedLinks`**.", - "no_permission": "Tôi không có đủ quyền để thực hiện lệnh này.", - "no_user_permission": "Bạn không có đủ quyền để sử dụng lệnh này.", - "no_voice_channel": "Bạn phải kết nối với một kênh thoại để sử dụng lệnh `{command}` này.", - "no_connect_permission": "Tôi không có quyền `CONNECT` để thực hiện lệnh `{command}` này.", - "no_speak_permission": "Tôi không có quyền `SPEAK` để thực hiện lệnh `{command}` này.", - "no_request_to_speak": "Tôi không có quyền `REQUEST TO SPEAK` để thực hiện lệnh `{command}` này.", - "different_voice_channel": "Bạn không kết nối với {channel} để sử dụng lệnh `{command}` này.", - "no_music_playing": "Hiện tại không có gì đang phát.", - "no_dj_role": "Vai trò DJ chưa được thiết lập.", - "no_dj_permission": "Bạn cần có vai trò DJ để sử dụng lệnh này.", - "missing_arguments": "Thiếu đối số", - "missing_arguments_description": "Vui lòng cung cấp các đối số cần thiết cho lệnh `{command}`.\n\nVí dụ:\n{examples}", - "syntax_footer": "Cú pháp: [] = tùy chọn, <> = bắt buộc", - "cooldown": "Vui lòng đợi {time} giây nữa trước khi sử dụng lệnh `{command}` này.", - "no_mention_everyone": "Bạn không thể sử dụng lệnh này với everyone hoặc here. Vui lòng sử dụng lệnh slash.", - "error": "Đã xảy ra lỗi: `{error}`", - "no_voice_channel_queue": "Bạn không kết nối với kênh thoại để xếp hàng bài hát.", - "no_permission_connect_speak": "Tôi không có đủ quyền để kết nối/nói trong <#{channel}>.", - "different_voice_channel_queue": "Bạn không kết nối với <#{channel}> để xếp hàng bài hát." - }, - "setupButton": { - "no_voice_channel_button": "Bạn không kết nối với kênh thoại để sử dụng nút này.", - "different_voice_channel_button": "Bạn không kết nối với {channel} để sử dụng các nút này.", - "now_playing": "Đang phát", - "live": "LIVE", - "requested_by": "Yêu cầu bởi <@{requester}>", - "no_dj_permission": "Bạn cần có vai trò DJ để sử dụng nút này.", - "volume_set": "Âm lượng đã được đặt thành {vol}%", - "volume_footer": "Âm lượng: {vol}%", - "paused": "Tạm dừng", - "resumed": "Tiếp tục", - "pause_resume": "{name} nhạc.", - "pause_resume_footer": "{name} bởi {displayName}", - "no_music_to_skip": "Không có nhạc để bỏ qua.", - "skipped": "Đã bỏ qua nhạc.", - "skipped_footer": "Bỏ qua bởi {displayName}", - "stopped": "Đã dừng nhạc.", - "stopped_footer": "Dừng bởi {displayName}", - "nothing_playing": "Hiện tại không có gì đang phát.", - "loop_set": "Lặp lại đã được đặt thành {loop}.", - "loop_footer": "Lặp lại đã được đặt thành {loop} bởi {displayName}", - "shuffled": "Đã xáo trộn danh sách phát.", - "no_previous_track": "Không có bài hát trước.", - "playing_previous": "Đang phát bài hát trước.", - "previous_footer": "Đang phát bài hát trước bởi {displayName}", - "rewind_limit": "Bạn không thể quay lại nhạc nhiều hơn độ dài của bài hát.", - "rewinded": "Đã quay lại nhạc.", - "rewind_footer": "Quay lại bởi {displayName}", - "forward_limit": "Bạn không thể tiến tới nhạc nhiều hơn độ dài của bài hát.", - "forwarded": "Đã tiến tới nhạc.", - "forward_footer": "Tiến tới bởi {displayName}", - "button_not_available": "Nút này không có sẵn.", - "no_music_playing": "Không có nhạc nào đang phát trong máy chủ này." - } - }, - "Evaluate code": "Đánh giá mã", - "Leave a guild": "Rời khỏi một guild", - "List all guilds the bot is in": "Danh sách tất cả guild mà bot đang ở", - "Restart the bot": "Khởi động lại bot" + "cmd": { + "247": { + "description": "Đặt bot ở lại trong kênh thoại", + "errors": { + "not_in_voice": "Bạn cần phải ở trong một kênh thoại để sử dụng lệnh này.", + "generic": "Đã xảy ra lỗi khi cố gắng thực thi lệnh này." + }, + "messages": { + "disabled": "`✅` | Chế độ 24/7 đã được `TẮT`", + "enabled": "`✅` | Chế độ 24/7 đã được `BẬT`. \n**Bot sẽ không rời khỏi kênh thoại ngay cả khi không có người trong kênh thoại.**" + } + }, + "ping": { + "description": "Hiển thị độ trễ của bot.", + "content": "Đang kiểm tra độ trễ...", + "bot_latency": "Độ trễ của Bot", + "api_latency": "Độ trễ của API", + "requested_by": "Yêu cầu bởi {author}" + }, + "lavalink": { + "description": "Hiển thị thông tin hiện tại của Lavalink.", + "title": "Thông tin Lavalink", + "content": "Trình phát: {players}\nTrình phát đang hoạt động: {playingPlayers}\nThời gian hoạt động: {uptime}\nSố lõi: {cores} Lõi\nSử dụng bộ nhớ: {used} / {reservable}\nTải hệ thống: {systemLoad}%\nTải Lavalink: {lavalinkLoad}%" + }, + "invite": { + "description": "Nhận liên kết mời bot.", + "content": "Bạn có thể mời tôi bằng cách nhấp vào nút dưới đây. Có lỗi hoặc sự cố? Tham gia máy chủ hỗ trợ!" + }, + "help": { + "description": "Hiển thị menu trợ giúp.", + "options": { + "command": "Lệnh bạn muốn xem thông tin" + }, + "content": "Chào bạn! Tôi là {bot}, một bot phát nhạc được tạo bởi [Lavamusic](https://github.com/appujet/lavamusic) và Discord. Bạn có thể sử dụng `{prefix}help ` để biết thêm thông tin về lệnh.", + "title": "Menu trợ giúp", + "not_found": "Lệnh `{cmdName}` này không tồn tại.", + "help_cmd": "**Mô tả:** {description}\n**Cách sử dụng:** {usage}\n**Ví dụ:** {examples}\n**Biệt danh:** {aliases}\n**Danh mục:** {category}\n**Thời gian chờ:** {cooldown} giây\n**Quyền:** {premUser}\n**Quyền của bot:** {premBot}\n**Chỉ dành cho nhà phát triển:** {dev}\n**Lệnh Slash:** {slash}\n**Tham số:** {args}\n**Trình phát:** {player}\n**DJ:** {dj}\n**Quyền của DJ:** {djPerm}\n**Giọng nói:** {voice}", + "footer": "Sử dụng {prefix}help để biết thêm thông tin về lệnh" + }, + "botinfo": { + "description": "Thông tin về bot", + "content": "Thông tin bot:\n- **Hệ điều hành**: {osInfo}\n- **Thời gian hoạt động**: {osUptime}\n- **Tên máy chủ**: {osHostname}\n- **Kiến trúc CPU**: {cpuInfo}\n- **Sử dụng CPU**: {cpuUsed}%\n- **Sử dụng bộ nhớ**: {memUsed}MB / {memTotal}GB\n- **Phiên bản Node**: {nodeVersion}\n- **Phiên bản Discord**: {discordJsVersion}\n- **Kết nối với** {guilds} máy chủ, {channels} kênh, và {users} người dùng\n- **Tổng số lệnh**: {commands}" + }, + "about": { + "description": "Hiển thị thông tin về bot", + "fields": { + "creator": "Người tạo", + "repository": "Kho lưu trữ", + "support": "Hỗ trợ", + "description": "Anh ấy thực sự muốn tạo dự án mã nguồn mở đầu tiên của mình để có thêm kinh nghiệm lập trình. Trong dự án này, anh ấy đã thách thức bản thân để tạo ra một dự án với ít lỗi hơn. Hy vọng bạn thích sử dụng LavaMusic!" + } + }, + "dj": { + "description": "Quản lý chế độ DJ và các vai trò liên quan", + "errors": { + "provide_role": "Vui lòng cung cấp một vai trò.", + "no_roles": "Vai trò DJ rỗng.", + "invalid_subcommand": "Vui lòng cung cấp một lệnh phụ hợp lệ." + }, + "messages": { + "role_exists": "Vai trò DJ <@&{roleId}> đã được thêm.", + "role_added": "Vai trò DJ <@&{roleId}> đã được thêm.", + "role_not_found": "Vai trò DJ <@&{roleId}> chưa được thêm.", + "role_removed": "Vai trò DJ <@&{roleId}> đã được xóa.", + "all_roles_cleared": "Tất cả vai trò DJ đã được xóa.", + "toggle": "Chế độ DJ đã được chuyển sang {status}." + }, + "options": { + "add": "Vai trò DJ bạn muốn thêm", + "remove": "Vai trò DJ bạn muốn xóa", + "clear": "Xóa tất cả các vai trò DJ", + "toggle": "Chuyển đổi chế độ DJ", + "role": "Vai trò DJ" + }, + "subcommands": "Lệnh phụ" + }, + "language": { + "description": "Đặt ngôn ngữ cho bot", + "invalid_language": "Vui lòng cung cấp một ngôn ngữ hợp lệ. Ví dụ: `EnglishUS` cho tiếng Anh (Hoa Kỳ)\n\nBạn có thể tìm danh sách các ngôn ngữ được hỗ trợ [tại đây](https://discord.com/developers/docs/reference#locales)\n\n**Ngôn ngữ có sẵn:**\n{languages}", + "already_set": "Ngôn ngữ đã được đặt thành `{language}`", + "not_set": "Ngôn ngữ chưa được đặt.", + "set": "`✅` | Ngôn ngữ đã được đặt thành `{language}`", + "reset": "`✅` | Ngôn ngữ đã được đặt lại về ngôn ngữ mặc định.", + "options": { + "set": "Đặt ngôn ngữ cho bot", + "language": "Ngôn ngữ bạn muốn đặt", + "reset": "Đặt lại ngôn ngữ về ngôn ngữ mặc định" + } + }, + "prefix": { + "description": "Hiển thị hoặc đặt tiền tố của bot", + "errors": { + "prefix_too_long": "Tiền tố không được dài hơn 3 ký tự." + }, + "messages": { + "current_prefix": "Tiền tố cho máy chủ này là `{prefix}`", + "prefix_set": "Tiền tố cho máy chủ này bây giờ là `{prefix}`", + "prefix_reset": "Tiền tố cho máy chủ này bây giờ là `{prefix}`" + }, + "options": { + "set": "Đặt tiền tố", + "prefix": "Tiền tố bạn muốn đặt", + "reset": "Đặt lại tiền tố về mặc định" + } + }, + "setup": { + "description": "Thiết lập bot", + "errors": { + "channel_exists": "Kênh yêu cầu bài hát đã tồn tại.", + "channel_not_exists": "Kênh yêu cầu bài hát không tồn tại.", + "channel_delete_fail": "Kênh yêu cầu bài hát đã bị xóa. Nếu kênh không bị xóa bình thường, vui lòng tự xóa nó." + }, + "messages": { + "channel_created": "Kênh yêu cầu bài hát đã được tạo trong <#{channelId}>.", + "channel_deleted": "Kênh yêu cầu bài hát đã bị xóa.", + "channel_info": "Kênh yêu cầu bài hát là <#{channelId}>." + }, + "options": { + "create": "Tạo kênh yêu cầu bài hát", + "delete": "Xóa kênh yêu cầu bài hát", + "info": "Hiển thị kênh yêu cầu bài hát" + } + }, + "8d": { + "description": "bật/tắt bộ lọc 8d", + "messages": { + "filter_enabled": "`✅` | Bộ lọc 8D đã được `BẬT`.", + "filter_disabled": "`✅` | Bộ lọc 8D đã được `TẮT`." + } + }, + "bassboost": { + "description": "bật/tắt bộ lọc bassboost", + "messages": { + "filter_enabled": "`✅` | Bộ lọc Bassboost đã được `BẬT`. \n**Cẩn thận, nghe quá to có thể gây hại cho thính giác của bạn!**", + "filter_disabled": "`✅` | Bộ lọc Bassboost đã được `TẮT`." + } + }, + "distorsion": { + "description": "Bật/tắt bộ lọc distortion", + "messages": { + "filter_enabled": "`✅` | Bộ lọc Distortion đã được `BẬT`.", + "filter_disabled": "`✅` | Bộ lọc Distortion đã được `TẮT`." + } + }, + "karaoke": { + "description": "Bật/tắt bộ lọc karaoke", + "messages": { + "filter_enabled": "`✅` | Bộ lọc Karaoke đã được `BẬT`.", + "filter_disabled": "`✅` | Bộ lọc Karaoke đã được `TẮT`." + } + }, + "lowpass": { + "description": "Bật/tắt bộ lọc lowpass", + "messages": { + "filter_enabled": "`✅` | Bộ lọc Lowpass đã được `BẬT`.", + "filter_disabled": "`✅` | Bộ lọc Lowpass đã được `TẮT`." + } + }, + "nightcore": { + "description": "Bật/tắt bộ lọc nightcore", + "messages": { + "filter_enabled": "`✅` | Bộ lọc Nightcore đã được `BẬT`.", + "filter_disabled": "`✅` | Bộ lọc Nightcore đã được `TẮT`." + } + }, + "pitch": { + "description": "Bật/tắt bộ lọc pitch", + "options": { + "pitch": "Số bạn muốn đặt độ cao (giữa 0.5 và 5)" + }, + "errors": { + "invalid_number": "Vui lòng cung cấp một số hợp lệ giữa 0.5 và 5." + }, + "messages": { + "pitch_set": "`✅` | Độ cao đã được đặt thành **{pitch}**." + } + }, + "rate": { + "description": "Thay đổi tốc độ của bài hát", + "options": { + "rate": "Số bạn muốn đặt tốc độ (giữa 0.5 và 5)" + }, + "errors": { + "invalid_number": "Vui lòng cung cấp một số hợp lệ giữa 0.5 và 5." + }, + "messages": { + "rate_set": "`✅` | Tốc độ đã được đặt thành **{rate}**." + } + }, + "reset": { + "description": "Đặt lại các bộ lọc đang hoạt động", + "messages": { + "filters_reset": "`✅` | Các bộ lọc đã được đặt lại." + } + }, + "rotation": { + "description": "Bật/tắt bộ lọc rotation", + "messages": { + "enabled": "`✅` | Bộ lọc Rotation đã được `BẬT`.", + "disabled": "`✅` | Bộ lọc Rotation đã được `TẮT`." + } + }, + "speed": { + "description": "Thay đổi tốc độ của bài hát", + "options": { + "speed": "Tốc độ bạn muốn đặt" + }, + "messages": { + "invalid_number": "Vui lòng cung cấp một số hợp lệ giữa 0.5 và 5.", + "set_speed": "`✅` | Tốc độ đã được đặt thành **{speed}**." + } + }, + "tremolo": { + "description": "Bật/tắt bộ lọc tremolo", + "messages": { + "enabled": "`✅` | Bộ lọc Tremolo đã được `BẬT`.", + "disabled": "`✅` | Bộ lọc Tremolo đã được `TẮT`." + } + }, + "vibrato": { + "description": "Bật/tắt bộ lọc vibrato", + "messages": { + "enabled": "`✅` | Bộ lọc Vibrato đã được `BẬT`.", + "disabled": "`✅` | Bộ lọc Vibrato đã được `TẮT`." + } + }, + "autoplay": { + "description": "Bật/tắt chế độ tự động phát", + "messages": { + "enabled": "`✅` | Chế độ tự động phát đã được `BẬT`.", + "disabled": "`✅` | Chế độ tự động phát đã được `TẮT`." + } + }, + "clearqueue": { + "description": "Xóa hàng chờ", + "messages": { + "cleared": "Hàng chờ đã được xóa." + } + }, + "grab": { + "description": "Lấy bài hát đang phát hiện tại vào tin nhắn trực tiếp của bạn", + "content": "**Thời lượng:** {length}\n**Yêu cầu bởi:** <@{requester}>\n**Liên kết:** [Nhấp vào đây]({uri})", + "check_dm": "Vui lòng kiểm tra tin nhắn trực tiếp của bạn.", + "dm_failed": "Tôi không thể gửi tin nhắn trực tiếp cho bạn. Vui lòng đảm bảo rằng tin nhắn trực tiếp đã được bật." + }, + "join": { + "description": "Tham gia kênh thoại", + "already_connected": "Tôi đã kết nối với <#{channelId}>.", + "no_voice_channel": "Bạn cần phải ở trong một kênh thoại để sử dụng lệnh này.", + "joined": "Đã tham gia thành công <#{channelId}>." + }, + "leave": { + "description": "Rời khỏi kênh thoại", + "left": "Đã rời khỏi <#{channelId}> thành công.", + "not_in_channel": "Tôi không có trong kênh thoại." + }, + "loop": { + "description": "Lặp lại bài hát hiện tại hoặc hàng chờ", + "looping_song": "**Đang lặp lại bài hát.**", + "looping_queue": "**Đang lặp lại hàng chờ.**", + "looping_off": "**Đã tắt chế độ lặp lại.**" + }, + "nowplaying": { + "description": "Hiển thị bài hát đang phát hiện tại", + "now_playing": "Đang phát", + "track_info": "[{title}]({uri}) - Yêu cầu bởi: <@{requester}>\n\n`{bar}`" + }, + "pause": { + "description": "Tạm dừng bài hát hiện tại", + "successfully_paused": "Đã tạm dừng bài hát thành công." + }, + "play": { + "description": "Phát một bài hát từ YouTube, Spotify hoặc http", + "options": { + "song": "Bài hát bạn muốn phát" + }, + "loading": "Đang tải...", + "errors": { + "search_error": "Đã xảy ra lỗi khi tìm kiếm.", + "no_results": "Không tìm thấy kết quả.", + "queue_too_long": "Hàng chờ quá dài. Độ dài tối đa là {maxQueueSize} bài hát.", + "playlist_too_long": "Danh sách phát quá dài. Độ dài tối đa là {maxPlaylistSize} bài hát." + }, + "added_to_queue": "Đã thêm [{title}]({uri}) vào hàng chờ.", + "added_playlist_to_queue": "Đã thêm {length} bài hát vào hàng chờ." + }, + "playnext": { + "description": "Thêm bài hát để phát tiếp theo trong hàng chờ", + "options": { + "song": "Bài hát bạn muốn phát" + }, + "loading": "Đang tải...", + "errors": { + "search_error": "Đã xảy ra lỗi khi tìm kiếm.", + "no_results": "Không tìm thấy kết quả.", + "queue_too_long": "Hàng chờ quá dài. Độ dài tối đa là {maxQueueSize} bài hát.", + "playlist_too_long": "Danh sách phát quá dài. Độ dài tối đa là {maxPlaylistSize} bài hát." + }, + "added_to_play_next": "Đã thêm [{title}]({uri}) để phát tiếp theo trong hàng chờ.", + "added_playlist_to_play_next": "Đã thêm {length} bài hát để phát tiếp theo trong hàng chờ." + }, + "queue": { + "description": "Hiển thị hàng chờ hiện tại", + "now_playing": "Đang phát: [{title}]({uri}) - Yêu cầu bởi: <@{requester}> - Thời lượng: `{duration}`", + "live": "TRỰC TIẾP", + "track_info": "{index}. [{title}]({uri}) - Yêu cầu bởi: <@{requester}> - Thời lượng: `{duration}`", + "title": "Hàng chờ", + "page_info": "Trang {index} của {total}" + }, + "remove": { + "description": "Xóa một bài hát khỏi hàng chờ", + "options": { + "song": "Số bài hát bạn muốn xóa" + }, + "errors": { + "no_songs": "Không có bài hát nào trong hàng chờ.", + "invalid_number": "Vui lòng cung cấp một số hợp lệ." + }, + "messages": { + "removed": "Đã xóa bài hát số {songNumber} khỏi hàng chờ." + } + }, + "replay": { + "description": "Phát lại bài hát hiện tại", + "errors": { + "not_seekable": "Không thể phát lại bài hát này vì không thể tìm kiếm được." + }, + "messages": { + "replaying": "Đang phát lại bài hát hiện tại." + } + }, + "resume": { + "description": "Tiếp tục phát bài hát hiện tại", + "errors": { + "not_paused": "Trình phát không bị tạm dừng." + }, + "messages": { + "resumed": "Trình phát đã được tiếp tục." + } + }, + "search": { + "description": "Tìm kiếm một bài hát", + "options": { + "song": "Bài hát bạn muốn tìm kiếm" + }, + "errors": { + "no_results": "Không tìm thấy kết quả.", + "search_error": "Đã xảy ra lỗi khi tìm kiếm." + }, + "messages": { + "added_to_queue": "Đã thêm [{title}]({uri}) vào hàng chờ." + } + }, + "seek": { + "description": "Tìm đến một thời điểm nhất định trong bài hát", + "options": { + "duration": "Thời gian bạn muốn tìm đến" + }, + "errors": { + "invalid_format": "Định dạng thời gian không hợp lệ. Ví dụ: seek 1m, seek 1h 30m", + "not_seekable": "Không thể tìm kiếm bài hát này.", + "beyond_duration": "Không thể tìm kiếm vượt quá thời lượng bài hát {length}." + }, + "messages": { + "seeked_to": "Đã tìm đến {duration}" + } + }, + "shuffle": { + "description": "Trộn hàng chờ", + "messages": { + "shuffled": "Hàng chờ đã được trộn." + } + }, + "skip": { + "description": "Bỏ qua bài hát hiện tại", + "messages": { + "skipped": "Đã bỏ qua [{title}]({uri})." + } + }, + "skipto": { + "description": "Bỏ qua đến một bài hát cụ thể trong hàng chờ", + "options": { + "number": "Số của bài hát bạn muốn bỏ qua đến" + }, + "errors": { + "invalid_number": "Vui lòng cung cấp một số hợp lệ." + }, + "messages": { + "skipped_to": "Đã bỏ qua đến bài hát số {number}." + } + }, + "stop": { + "description": "Dừng nhạc và xóa hàng chờ", + "messages": { + "stopped": "Đã dừng nhạc và xóa hàng chờ." + } + }, + "volume": { + "description": "Đặt âm lượng của trình phát", + "options": { + "number": "Âm lượng bạn muốn đặt" + }, + "messages": { + "invalid_number": "Vui lòng cung cấp một số hợp lệ.", + "too_low": "Âm lượng không thể thấp hơn 0.", + "too_high": "Âm lượng không thể cao hơn 200. Bạn có muốn làm hỏng tai hoặc loa của mình không? Hmmm, tôi không nghĩ đó là một ý kiến hay.", + "set": "Âm lượng đã được đặt thành {volume}" + } + }, + "addsong": { + "description": "Thêm một bài hát vào danh sách phát", + "options": { + "playlist": "Danh sách phát bạn muốn thêm", + "song": "Bài hát bạn muốn thêm" + }, + "messages": { + "no_playlist": "Vui lòng cung cấp một danh sách phát", + "no_song": "Vui lòng cung cấp một bài hát", + "playlist_not_found": "Danh sách phát đó không tồn tại", + "no_songs_found": "Không tìm thấy bài hát nào", + "added": "Đã thêm {count} bài hát vào {playlist}" + } + }, + "create": { + "description": "Tạo một danh sách phát", + "options": { + "name": "Tên của danh sách phát" + }, + "messages": { + "name_too_long": "Tên danh sách phát chỉ có thể dài 50 ký tự.", + "playlist_exists": "Danh sách phát với tên đó đã tồn tại. Vui lòng sử dụng tên khác.", + "playlist_created": "Danh sách phát **{name}** đã được tạo." + } + }, + "delete": { + "description": "Xóa một danh sách phát", + "options": { + "playlist": "Danh sách phát bạn muốn xóa" + }, + "messages": { + "playlist_not_found": "Danh sách phát đó không tồn tại.", + "playlist_deleted": "Đã xóa danh sách phát **{playlistName}**." + } + }, + "list": { + "description": "Lấy tất cả danh sách phát của người dùng", + "options": { + "user": "Người dùng mà bạn muốn lấy danh sách phát" + }, + "messages": { + "no_playlists": "Người dùng này không có danh sách phát nào.", + "your": "Danh sách phát của bạn", + "playlists_title": "Danh sách phát của {username}", + "error": "Đã xảy ra lỗi khi lấy danh sách phát." + } + }, + "load": { + "description": "Tải một danh sách phát", + "options": { + "playlist": "Danh sách phát bạn muốn tải" + }, + "messages": { + "playlist_not_exist": "Danh sách phát đó không tồn tại.", + "playlist_empty": "Danh sách phát đó trống.", + "playlist_loaded": "Đã tải `{name}` với `{count}` bài hát." + } + }, + "removesong": { + "description": "Xóa một bài hát khỏi danh sách phát", + "options": { + "playlist": "Danh sách phát bạn muốn xóa khỏi", + "song": "Bài hát bạn muốn xóa" + }, + "messages": { + "provide_playlist": "Vui lòng cung cấp một danh sách phát.", + "provide_song": "Vui lòng cung cấp một bài hát.", + "playlist_not_exist": "Danh sách phát đó không tồn tại.", + "song_not_found": "Không tìm thấy bài hát phù hợp.", + "song_removed": "Đã xóa {song} khỏi {playlist}.", + "error_occurred": "Đã xảy ra lỗi khi xóa bài hát." + } + }, + "steal": { + "description": "Đánh cắp một danh sách phát từ người dùng khác và thêm vào danh sách phát của bạn", + "options": { + "playlist": "Danh sách phát bạn muốn đánh cắp", + "user": "Người dùng mà bạn muốn đánh cắp danh sách phát" + }, + "messages": { + "provide_playlist": "Vui lòng cung cấp tên danh sách phát.", + "provide_user": "Vui lòng nhắc đến một người dùng.", + "playlist_not_exist": "Danh sách phát đó không tồn tại cho người dùng được đề cập.", + "playlist_stolen": "Đã đánh cắp danh sách phát `{playlist}` từ {user} thành công.", + "error_occurred": "Đã xảy ra lỗi khi đánh cắp danh sách phát." + } + } + }, + "buttons": { + "invite": "Mời", + "support": "Máy chủ hỗ trợ", + "previous": "Trước", + "resume": "Tiếp tục", + "stop": "Dừng", + "skip": "Bỏ qua", + "loop": "Lặp lại", + "errors": { + "not_author": "Bạn không thể sử dụng nút này." + } + }, + "player": { + "errors": { + "no_player": "Không có player hoạt động trong guild này.", + "no_channel": "Bạn cần phải ở trong một kênh thoại để sử dụng lệnh này.", + "queue_empty": "Danh sách phát đang trống.", + "no_previous": "Không có bài hát trước trong danh sách phát.", + "no_song": "Không có bài hát nào trong danh sách phát.", + "already_paused": "Bài hát đã được tạm dừng rồi." + }, + "trackStart": { + "now_playing": "Đang phát", + "requested_by": "Yêu cầu bởi {user}", + "duration": "Thời gian", + "author": "Tác giả", + "not_connected_to_voice_channel": "Bạn không kết nối với <#{channel}> để sử dụng các nút này.", + "need_dj_role": "Bạn cần có vai trò DJ để sử dụng lệnh này.", + "previous_by": "Trước đó bởi {user}", + "no_previous_song": "Không có bài hát trước.", + "paused_by": "Tạm dừng bởi {user}", + "resumed_by": "Tiếp tục bởi {user}", + "skipped_by": "Bỏ qua bởi {user}", + "no_more_songs_in_queue": "Không còn bài hát nào trong danh sách phát.", + "looping_by": "Lặp lại bởi {user}", + "looping_queue_by": "Lặp lại danh sách phát bởi {user}", + "looping_off_by": "Tắt lặp lại bởi {user}" + }, + "setupStart": { + "now_playing": "Đang phát", + "description": "[{title}]({uri}) của {author} • `[{length}]` - Yêu cầu bởi <@{requester}>", + "error_searching": "Đã xảy ra lỗi khi tìm kiếm.", + "no_results": "Không tìm thấy kết quả.", + "nothing_playing": "Hiện tại không có gì đang phát.", + "queue_too_long": "Danh sách phát quá dài. Độ dài tối đa là {maxQueueSize} bài hát.", + "playlist_too_long": "Danh sách phát quá dài. Độ dài tối đa là {maxPlaylistSize} bài hát.", + "added_to_queue": "Đã thêm [{title}]({uri}) vào danh sách phát.", + "added_playlist_to_queue": "Đã thêm [{length}] bài hát từ danh sách phát vào danh sách phát." + } + }, + "event": { + "interaction": { + "setup_channel": "Bạn không thể sử dụng lệnh này trong kênh thiết lập.", + "no_send_message": "Tôi không có quyền **`SendMessage`** trong `{guild}`\nKênh: {channel}.", + "no_embed_links": "Tôi không có quyền **`EmbedLinks`**.", + "no_permission": "Tôi không có đủ quyền để thực hiện lệnh này.", + "no_user_permission": "Bạn không có đủ quyền để sử dụng lệnh này.", + "no_voice_channel": "Bạn phải kết nối với một kênh thoại để sử dụng lệnh `{command}` này.", + "no_connect_permission": "Tôi không có quyền `CONNECT` để thực hiện lệnh `{command}` này.", + "no_speak_permission": "Tôi không có quyền `SPEAK` để thực hiện lệnh `{command}` này.", + "no_request_to_speak": "Tôi không có quyền `REQUEST TO SPEAK` để thực hiện lệnh `{command}` này.", + "different_voice_channel": "Bạn không kết nối với {channel} để sử dụng lệnh `{command}` này.", + "no_music_playing": "Hiện tại không có gì đang phát.", + "no_dj_role": "Vai trò DJ chưa được thiết lập.", + "no_dj_permission": "Bạn cần có vai trò DJ để sử dụng lệnh này.", + "cooldown": "Vui lòng đợi {time} giây nữa trước khi sử dụng lệnh `{command}` này.", + "error": "Đã xảy ra lỗi: `{error}`" + }, + "message": { + "prefix_mention": "Chào, tiền tố của tôi cho máy chủ này là `{prefix}`. Muốn biết thêm thông tin? thì hãy dùng `{prefix}help`\nHãy an toàn, hãy tuyệt vời!", + "no_send_message": "Tôi không có quyền **`SendMessage`** trong `{guild}`\nKênh: {channel}.", + "no_embed_links": "Tôi không có quyền **`EmbedLinks`**.", + "no_permission": "Tôi không có đủ quyền để thực hiện lệnh này.", + "no_user_permission": "Bạn không có đủ quyền để sử dụng lệnh này.", + "no_voice_channel": "Bạn phải kết nối với một kênh thoại để sử dụng lệnh `{command}` này.", + "no_connect_permission": "Tôi không có quyền `CONNECT` để thực hiện lệnh `{command}` này.", + "no_speak_permission": "Tôi không có quyền `SPEAK` để thực hiện lệnh `{command}` này.", + "no_request_to_speak": "Tôi không có quyền `REQUEST TO SPEAK` để thực hiện lệnh `{command}` này.", + "different_voice_channel": "Bạn không kết nối với {channel} để sử dụng lệnh `{command}` này.", + "no_music_playing": "Hiện tại không có gì đang phát.", + "no_dj_role": "Vai trò DJ chưa được thiết lập.", + "no_dj_permission": "Bạn cần có vai trò DJ để sử dụng lệnh này.", + "missing_arguments": "Thiếu đối số", + "missing_arguments_description": "Vui lòng cung cấp các đối số cần thiết cho lệnh `{command}`.\n\nVí dụ:\n{examples}", + "syntax_footer": "Cú pháp: [] = tùy chọn, <> = bắt buộc", + "cooldown": "Vui lòng đợi {time} giây nữa trước khi sử dụng lệnh `{command}` này.", + "no_mention_everyone": "Bạn không thể sử dụng lệnh này với everyone hoặc here. Vui lòng sử dụng lệnh slash.", + "error": "Đã xảy ra lỗi: `{error}`", + "no_voice_channel_queue": "Bạn không kết nối với kênh thoại để xếp hàng bài hát.", + "no_permission_connect_speak": "Tôi không có đủ quyền để kết nối/nói trong <#{channel}>.", + "different_voice_channel_queue": "Bạn không kết nối với <#{channel}> để xếp hàng bài hát." + }, + "setupButton": { + "no_voice_channel_button": "Bạn không kết nối với kênh thoại để sử dụng nút này.", + "different_voice_channel_button": "Bạn không kết nối với {channel} để sử dụng các nút này.", + "now_playing": "Đang phát", + "live": "LIVE", + "requested_by": "Yêu cầu bởi <@{requester}>", + "no_dj_permission": "Bạn cần có vai trò DJ để sử dụng nút này.", + "volume_set": "Âm lượng đã được đặt thành {vol}%", + "volume_footer": "Âm lượng: {vol}%", + "paused": "Tạm dừng", + "resumed": "Tiếp tục", + "pause_resume": "{name} nhạc.", + "pause_resume_footer": "{name} bởi {displayName}", + "no_music_to_skip": "Không có nhạc để bỏ qua.", + "skipped": "Đã bỏ qua nhạc.", + "skipped_footer": "Bỏ qua bởi {displayName}", + "stopped": "Đã dừng nhạc.", + "stopped_footer": "Dừng bởi {displayName}", + "nothing_playing": "Hiện tại không có gì đang phát.", + "loop_set": "Lặp lại đã được đặt thành {loop}.", + "loop_footer": "Lặp lại đã được đặt thành {loop} bởi {displayName}", + "shuffled": "Đã xáo trộn danh sách phát.", + "no_previous_track": "Không có bài hát trước.", + "playing_previous": "Đang phát bài hát trước.", + "previous_footer": "Đang phát bài hát trước bởi {displayName}", + "rewind_limit": "Bạn không thể quay lại nhạc nhiều hơn độ dài của bài hát.", + "rewinded": "Đã quay lại nhạc.", + "rewind_footer": "Quay lại bởi {displayName}", + "forward_limit": "Bạn không thể tiến tới nhạc nhiều hơn độ dài của bài hát.", + "forwarded": "Đã tiến tới nhạc.", + "forward_footer": "Tiến tới bởi {displayName}", + "button_not_available": "Nút này không có sẵn.", + "no_music_playing": "Không có nhạc nào đang phát trong máy chủ này." + } + }, + "Evaluate code": "Đánh giá mã", + "Leave a guild": "Rời khỏi một guild", + "List all guilds the bot is in": "Danh sách tất cả guild mà bot đang ở", + "Restart the bot": "Khởi động lại bot" } \ No newline at end of file diff --git a/package.json b/package.json index 13da587ca..1f0d0ba58 100644 --- a/package.json +++ b/package.json @@ -10,8 +10,8 @@ "db:migrate": "npx prisma migrate dev --name init", "build": "tsc --project tsconfig.json", "clean": "node scripts/clean.js && npm run build", - "lint": "biome lint --write src/", - "format": "biome format --write src/" + "lint": "biome lint --write", + "format": "biome format --write" }, "repository": { "type": "git", @@ -38,21 +38,21 @@ "@types/i18n": "^0.13.12", "@types/node": "^22.1.0", "@types/signale": "^1.4.7", - "prisma": "^5.17.0", + "prisma": "^5.18.0", "typescript": "^5.5.4" }, "dependencies": { - "@prisma/client": "^5.17.0", + "@prisma/client": "^5.18.0", "@top-gg/sdk": "^3.1.6", "discord.js": "^14.15.3", "dotenv": "^16.4.5", "i18n": "^0.15.1", "node-system-stats": "^1.3.0", - "shoukaku": "github:shipgirlproject/Shoukaku", + "shoukaku": "github:shipgirlproject/Shoukaku#master", "signale": "^1.4.0", "topgg-autoposter": "^2.0.2", "tslib": "^2.6.3", - "undici": "^6.19.5" + "undici": "^6.19.6" }, "signale": { "displayScope": true, diff --git a/scripts/clean.js b/scripts/clean.js index 4ce4104c4..ee300b1aa 100644 --- a/scripts/clean.js +++ b/scripts/clean.js @@ -1,5 +1,8 @@ +// biome-ignore lint/correctness/noNodejsModules: import { existsSync } from "node:fs"; +// biome-ignore lint/correctness/noNodejsModules: import { rm } from "node:fs/promises"; +// biome-ignore lint/correctness/noNodejsModules: import { resolve } from "node:path"; async function clean() { diff --git a/scripts/restart.ts b/scripts/restart.ts index f2ba2a50f..67e4e1085 100644 --- a/scripts/restart.ts +++ b/scripts/restart.ts @@ -1,3 +1,4 @@ +// biome-ignore lint/correctness/noNodejsModules: import { exec } from "node:child_process"; async function startLavamusic(): Promise { diff --git a/src/commands/config/Dj.ts b/src/commands/config/Dj.ts index 3d74fd3de..2cafdaf6e 100644 --- a/src/commands/config/Dj.ts +++ b/src/commands/config/Dj.ts @@ -92,13 +92,25 @@ export default class Dj extends Command { } if (await client.db.getRoles(ctx.guild!.id).then((r) => r.some((re) => re.roleId === role.id))) { return ctx.sendMessage({ - embeds: [embed.setDescription(ctx.locale("cmd.dj.messages.role_exists", { roleId: role.id }))], + embeds: [ + embed.setDescription( + ctx.locale("cmd.dj.messages.role_exists", { + roleId: role.id, + }), + ), + ], }); } await client.db.addRole(ctx.guild!.id, role.id); await client.db.setDj(ctx.guild!.id, true); return ctx.sendMessage({ - embeds: [embed.setDescription(ctx.locale("cmd.dj.messages.role_added", { roleId: role.id }))], + embeds: [ + embed.setDescription( + ctx.locale("cmd.dj.messages.role_added", { + roleId: role.id, + }), + ), + ], }); case "remove": @@ -109,12 +121,24 @@ export default class Dj extends Command { } if (!(await client.db.getRoles(ctx.guild!.id).then((r) => r.some((re) => re.roleId === role.id)))) { return ctx.sendMessage({ - embeds: [embed.setDescription(ctx.locale("cmd.dj.messages.role_not_found", { roleId: role.id }))], + embeds: [ + embed.setDescription( + ctx.locale("cmd.dj.messages.role_not_found", { + roleId: role.id, + }), + ), + ], }); } await client.db.removeRole(ctx.guild!.id, role.id); return ctx.sendMessage({ - embeds: [embed.setDescription(ctx.locale("cmd.dj.messages.role_removed", { roleId: role.id }))], + embeds: [ + embed.setDescription( + ctx.locale("cmd.dj.messages.role_removed", { + roleId: role.id, + }), + ), + ], }); case "clear": @@ -136,15 +160,22 @@ export default class Dj extends Command { } await client.db.setDj(ctx.guild!.id, !dj.mode); return ctx.sendMessage({ - embeds: [embed.setDescription(ctx.locale("cmd.dj.messages.toggle", { status: dj.mode ? "disabled" : "enabled" }))], + embeds: [ + embed.setDescription( + ctx.locale("cmd.dj.messages.toggle", { + status: dj.mode ? "disabled" : "enabled", + }), + ), + ], }); default: return ctx.sendMessage({ embeds: [ - embed - .setDescription(ctx.locale("cmd.dj.errors.invalid_subcommand")) - .addFields({ name: ctx.locale("cmd.dj.subcommands"), value: "`add`, `remove`, `clear`, `toggle`" }), + embed.setDescription(ctx.locale("cmd.dj.errors.invalid_subcommand")).addFields({ + name: ctx.locale("cmd.dj.subcommands"), + value: "`add`, `remove`, `clear`, `toggle`", + }), ], }); } diff --git a/src/commands/config/Language.ts b/src/commands/config/Language.ts index a844b50f7..050160751 100644 --- a/src/commands/config/Language.ts +++ b/src/commands/config/Language.ts @@ -1,3 +1,4 @@ +import type { AutocompleteInteraction } from "discord.js"; import { Command, type Context, type Lavamusic } from "../../structures/index.js"; import { Language, LocaleFlags } from "../../types.js"; @@ -82,18 +83,34 @@ export default class LanguageCommand extends Command { return `${acc + curr}\n`; }, ""); return ctx.sendMessage({ - embeds: [embed.setDescription(ctx.locale("cmd.language.invalid_language", { languages: availableLanguages }))], + embeds: [ + embed.setDescription( + ctx.locale("cmd.language.invalid_language", { + languages: availableLanguages, + }), + ), + ], }); } if (locale && locale === lang) { - return ctx.sendMessage({ embeds: [embed.setDescription(ctx.locale("cmd.language.already_set", { language: lang }))] }); + return ctx.sendMessage({ + embeds: [ + embed.setDescription( + ctx.locale("cmd.language.already_set", { + language: lang, + }), + ), + ], + }); } await client.db.updateLanguage(ctx.guild!.id, lang); ctx.guildLocale = lang; - return ctx.sendMessage({ embeds: [embed.setDescription(ctx.locale("cmd.language.set", { language: lang }))] }); + return ctx.sendMessage({ + embeds: [embed.setDescription(ctx.locale("cmd.language.set", { language: lang }))], + }); } if (subCommand === "reset") { const embed = client.embed().setColor(this.client.color.main); @@ -101,33 +118,30 @@ export default class LanguageCommand extends Command { const locale = await client.db.getLanguage(ctx.guild!.id); if (!locale) { - return ctx.sendMessage({ embeds: [embed.setDescription(ctx.locale("cmd.language.not_set"))] }); + return ctx.sendMessage({ + embeds: [embed.setDescription(ctx.locale("cmd.language.not_set"))], + }); } await client.db.updateLanguage(ctx.guild!.id, Language.EnglishUS); ctx.guildLocale = Language.EnglishUS; - return ctx.sendMessage({ embeds: [embed.setDescription(ctx.locale("cmd.language.reset"))] }); + return ctx.sendMessage({ + embeds: [embed.setDescription(ctx.locale("cmd.language.reset"))], + }); } } - public async autocomplete(interaction) { + public async autocomplete(interaction: AutocompleteInteraction): Promise { const focusedValue = interaction.options.getFocused(); - // Fetch all available languages - const languages = Object.values(Language).map(language => ({ + const languages = Object.values(Language).map((language) => ({ name: language, value: language, })); - // Filter languages based on the focused value - const filtered = languages.filter(language => - language.name.toLowerCase().includes(focusedValue.toLowerCase()) - ); + const filtered = languages.filter((language) => language.name.toLowerCase().includes(focusedValue.toLowerCase())); - // Respond with the filtered language options await interaction.respond(filtered.slice(0, 25)).catch(console.error); } - - } diff --git a/src/commands/config/Prefix.ts b/src/commands/config/Prefix.ts index d78c5a124..b745b03bd 100644 --- a/src/commands/config/Prefix.ts +++ b/src/commands/config/Prefix.ts @@ -69,7 +69,11 @@ export default class Prefix extends Command { case "set": { if (!prefix) { const currentPrefix = guildData ? guildData.prefix : client.config.prefix; - embed.setDescription(ctx.locale("cmd.prefix.messages.current_prefix", { prefix: currentPrefix })); + embed.setDescription( + ctx.locale("cmd.prefix.messages.current_prefix", { + prefix: currentPrefix, + }), + ); return await ctx.sendMessage({ embeds: [embed] }); } if (prefix.length > 3) { @@ -83,12 +87,20 @@ export default class Prefix extends Command { case "reset": { const defaultPrefix = client.config.prefix; await client.db.setPrefix(guildId, defaultPrefix); - embed.setDescription(ctx.locale("cmd.prefix.messages.prefix_reset", { prefix: defaultPrefix })); + embed.setDescription( + ctx.locale("cmd.prefix.messages.prefix_reset", { + prefix: defaultPrefix, + }), + ); return await ctx.sendMessage({ embeds: [embed] }); } default: { const currentPrefix = guildData ? guildData.prefix : client.config.prefix; - embed.setDescription(ctx.locale("cmd.prefix.messages.current_prefix", { prefix: currentPrefix })); + embed.setDescription( + ctx.locale("cmd.prefix.messages.current_prefix", { + prefix: currentPrefix, + }), + ); return await ctx.sendMessage({ embeds: [embed] }); } } diff --git a/src/commands/config/Setup.ts b/src/commands/config/Setup.ts index 7e3047b00..f261efd97 100644 --- a/src/commands/config/Setup.ts +++ b/src/commands/config/Setup.ts @@ -97,9 +97,14 @@ export default class Setup extends Command { ? `[${player.current.info.title}](${player.current.info.uri})` : ctx.locale("player.setupStart.nothing_playing"); embed.setDescription(desc).setImage(image); - await textChannel.send({ embeds: [embed], components: getButtons(player, client) }).then((msg) => { - client.db.setSetup(ctx.guild!.id, textChannel.id, msg.id); - }); + await textChannel + .send({ + embeds: [embed], + components: getButtons(player, client), + }) + .then((msg) => { + client.db.setSetup(ctx.guild!.id, textChannel.id, msg.id); + }); await ctx.sendMessage({ embeds: [ { @@ -149,7 +154,11 @@ export default class Setup extends Command { } const channel = ctx.guild.channels.cache.get(data3.textId); if (channel) { - embed.setDescription(ctx.locale("cmd.setup.messages.channel_info", { channelId: channel.id })); + embed.setDescription( + ctx.locale("cmd.setup.messages.channel_info", { + channelId: channel.id, + }), + ); await ctx.sendMessage({ embeds: [embed] }); } else { await ctx.sendMessage({ diff --git a/src/commands/dev/Deploy.ts b/src/commands/dev/Deploy.ts index a07574190..1748b15ca 100644 --- a/src/commands/dev/Deploy.ts +++ b/src/commands/dev/Deploy.ts @@ -43,7 +43,10 @@ export default class Deploy extends Command { const filter = (interaction: ButtonInteraction<"cached">) => { if (interaction.user.id !== ctx.author.id) { - interaction.reply({ content: "You can't interact with this message", ephemeral: true }); + interaction.reply({ + content: "You can't interact with this message", + ephemeral: true, + }); return false; } return true; @@ -58,10 +61,16 @@ export default class Deploy extends Command { collector.on("collect", async (interaction) => { if (interaction.customId === "deploy-global") { await client.deployCommands(); - await interaction.update({ content: "Commands deployed globally.", components: [] }); + await interaction.update({ + content: "Commands deployed globally.", + components: [], + }); } else if (interaction.customId === "deploy-guild") { await client.deployCommands(interaction.guild.id); - await interaction.update({ content: "Commands deployed in this guild.", components: [] }); + await interaction.update({ + content: "Commands deployed in this guild.", + components: [], + }); } }); diff --git a/src/commands/dev/Eval.ts b/src/commands/dev/Eval.ts index 6f0e890fc..8c746c95a 100644 --- a/src/commands/dev/Eval.ts +++ b/src/commands/dev/Eval.ts @@ -1,3 +1,4 @@ +// biome-ignore lint/correctness/noNodejsModules: import util from "node:util"; import { ActionRowBuilder, ButtonBuilder, ButtonStyle } from "discord.js"; import { fetch } from "undici"; diff --git a/src/commands/dev/GuildLeave.ts b/src/commands/dev/GuildLeave.ts index d623cec93..35886858c 100644 --- a/src/commands/dev/GuildLeave.ts +++ b/src/commands/dev/GuildLeave.ts @@ -1,3 +1,4 @@ +import { ChannelType, type TextChannel } from "discord.js"; import { Command, type Context, type Lavamusic } from "../../structures/index.js"; export default class GuildLeave extends Command { @@ -31,14 +32,46 @@ export default class GuildLeave extends Command { public async run(client: Lavamusic, ctx: Context, args: string[]): Promise { const guildId = args[0]; - const guild = client.guilds.cache.get(guildId); - if (!guild) return await ctx.sendMessage("Guild not found."); + + // Broadcast to all shards to find the guild + const guild = await client.shard + .broadcastEval( + (c, { guildId }) => { + const guild = c.guilds.cache.get(guildId); + return guild ? { id: guild.id, name: guild.name } : null; + }, + { context: { guildId } }, + ) + .then((results) => results.find((g) => g !== null)); + + if (!guild) { + return await ctx.sendMessage("Guild not found."); + } + try { - await guild.leave(); + // Broadcast to the correct shard to leave the guild + await client.shard.broadcastEval( + async (c, { guildId }) => { + const guild = c.guilds.cache.get(guildId); + if (guild) { + await guild.leave(); + } + }, + { context: { guildId } }, + ); await ctx.sendMessage(`Left guild ${guild.name}`); } catch { await ctx.sendMessage(`Failed to leave guild ${guild.name}`); } + + // Logging + const logChannelId = process.env.LOG_CHANNEL_ID; + if (logChannelId) { + const logChannel = client.channels.cache.get(logChannelId) as TextChannel; + if (logChannel && logChannel.type === ChannelType.GuildText) { + await logChannel.send(`Bot has left guild: ${guild.name} (ID: ${guild.id})`); + } + } } } diff --git a/src/commands/dev/GuildList.ts b/src/commands/dev/GuildList.ts index ecb652914..1f25ddd61 100644 --- a/src/commands/dev/GuildList.ts +++ b/src/commands/dev/GuildList.ts @@ -30,8 +30,13 @@ export default class GuildList extends Command { } public async run(client: Lavamusic, ctx: Context): Promise { - const guilds = client.guilds.cache.map((guild) => `- **${guild.name}** - (${guild.id})`); - const chunks = client.utils.chunk(guilds, 10) || [[]]; + // Fetch guilds from all shards + const guilds = await client.shard.broadcastEval((c) => c.guilds.cache.map((guild) => ({ name: guild.name, id: guild.id }))); + // Flatten the array of arrays + const allGuilds = guilds.reduce((acc, val) => acc.concat(val), []); + + const guildList = allGuilds.map((guild) => `- **${guild.name}** - (${guild.id})`); + const chunks = client.utils.chunk(guildList, 10) || [[]]; const pages = chunks.map((chunk, index) => { return this.client .embed() diff --git a/src/commands/dev/Restart.ts b/src/commands/dev/Restart.ts index 35b32e762..04ad6dbf0 100644 --- a/src/commands/dev/Restart.ts +++ b/src/commands/dev/Restart.ts @@ -1,3 +1,4 @@ +// biome-ignore lint/correctness/noNodejsModules: import { exec } from "node:child_process"; import { ActionRowBuilder, ButtonBuilder, ButtonStyle } from "discord.js"; import { Command, type Context, type Lavamusic } from "../../structures/index.js"; @@ -46,11 +47,18 @@ export default class Restart extends Command { }); const filter = (i: any) => i.customId === "confirm-restart" && i.user.id === ctx.author.id; - const collector = msg.createMessageComponentCollector({ time: 30000, filter }); + const collector = msg.createMessageComponentCollector({ + time: 30000, + filter, + }); collector.on("collect", async (i) => { await i.deferUpdate(); - await msg.edit({ content: "Restarting the bot...", embeds: [], components: [] }); + await msg.edit({ + content: "Restarting the bot...", + embeds: [], + components: [], + }); await client.destroy(); exec("node scripts/restart.ts"); process.exit(0); @@ -58,7 +66,10 @@ export default class Restart extends Command { collector.on("end", async () => { if (!collector.collected.size) { - await msg.edit({ content: "Restart cancelled.", components: [] }); + await msg.edit({ + content: "Restart cancelled.", + components: [], + }); } }); } diff --git a/src/commands/filters/Pitch.ts b/src/commands/filters/Pitch.ts index 6eab969dd..5cb2105d4 100644 --- a/src/commands/filters/Pitch.ts +++ b/src/commands/filters/Pitch.ts @@ -59,7 +59,9 @@ export default class Pitch extends Command { await ctx.sendMessage({ embeds: [ { - description: ctx.locale("cmd.pitch.messages.pitch_set", { pitch }), + description: ctx.locale("cmd.pitch.messages.pitch_set", { + pitch, + }), color: this.client.color.main, }, ], diff --git a/src/commands/filters/Rate.ts b/src/commands/filters/Rate.ts index 86aecc6d9..f9e1733d3 100644 --- a/src/commands/filters/Rate.ts +++ b/src/commands/filters/Rate.ts @@ -59,7 +59,9 @@ export default class Rate extends Command { await ctx.sendMessage({ embeds: [ { - description: ctx.locale("cmd.rate.messages.rate_set", { rate }), + description: ctx.locale("cmd.rate.messages.rate_set", { + rate, + }), color: this.client.color.main, }, ], diff --git a/src/commands/filters/Speed.ts b/src/commands/filters/Speed.ts index ccfc02e56..cc467c539 100644 --- a/src/commands/filters/Speed.ts +++ b/src/commands/filters/Speed.ts @@ -59,7 +59,9 @@ export default class Speed extends Command { await ctx.sendMessage({ embeds: [ { - description: ctx.locale("cmd.speed.messages.set_speed", { speed }), + description: ctx.locale("cmd.speed.messages.set_speed", { + speed, + }), color: this.client.color.main, }, ], diff --git a/src/commands/info/Botinfo.ts b/src/commands/info/Botinfo.ts index c4038bfea..3f3bc0688 100644 --- a/src/commands/info/Botinfo.ts +++ b/src/commands/info/Botinfo.ts @@ -1,3 +1,4 @@ +// biome-ignore lint/correctness/noNodejsModules: import os from "node:os"; import { version } from "discord.js"; import { showTotalMemory, usagePercent } from "node-system-stats"; diff --git a/src/commands/info/Help.ts b/src/commands/info/Help.ts index 9075facc6..eddcc5617 100644 --- a/src/commands/info/Help.ts +++ b/src/commands/info/Help.ts @@ -47,7 +47,13 @@ export default class Help extends Command { const command = this.client.commands.get(args[0].toLowerCase()); if (!command) { return await ctx.sendMessage({ - embeds: [embed.setColor(this.client.color.red).setDescription(ctx.locale("cmd.help.not_found", { cmdName: args[0] }))], + embeds: [ + embed.setColor(this.client.color.red).setDescription( + ctx.locale("cmd.help.not_found", { + cmdName: args[0], + }), + ), + ], }); } const helpEmbed = embed @@ -88,8 +94,15 @@ export default class Help extends Command { const helpEmbed = embed .setColor(client.color.main) .setTitle(ctx.locale("cmd.help.title")) - .setDescription(ctx.locale("cmd.help.content", { bot: client.user.username, prefix: guild.prefix })) - .setFooter({ text: ctx.locale("cmd.help.footer", { prefix: guild.prefix }) }) + .setDescription( + ctx.locale("cmd.help.content", { + bot: client.user.username, + prefix: guild.prefix, + }), + ) + .setFooter({ + text: ctx.locale("cmd.help.footer", { prefix: guild.prefix }), + }) .addFields(...fields); return await ctx.sendMessage({ embeds: [helpEmbed] }); diff --git a/src/commands/info/Ping.ts b/src/commands/info/Ping.ts index 61d5ac481..576d6d45a 100644 --- a/src/commands/info/Ping.ts +++ b/src/commands/info/Ping.ts @@ -34,7 +34,10 @@ export default class Ping extends Command { const msg = await ctx.sendDeferMessage(ctx.locale("cmd.ping.content")); const embed = this.client .embed() - .setAuthor({ name: "Pong", iconURL: this.client.user.displayAvatarURL() }) + .setAuthor({ + name: "Pong", + iconURL: this.client.user.displayAvatarURL(), + }) .setColor(this.client.color.main) .addFields([ { @@ -49,7 +52,9 @@ export default class Ping extends Command { }, ]) .setFooter({ - text: ctx.locale("cmd.ping.requested_by", { author: ctx.author.tag }), + text: ctx.locale("cmd.ping.requested_by", { + author: ctx.author.tag, + }), iconURL: ctx.author.avatarURL({}), }) .setTimestamp(); diff --git a/src/commands/music/Autoplay.ts b/src/commands/music/Autoplay.ts index 0a0e5b649..d3266b486 100644 --- a/src/commands/music/Autoplay.ts +++ b/src/commands/music/Autoplay.ts @@ -36,7 +36,7 @@ export default class Autoplay extends Command { return await ctx.sendMessage({ embeds: [ { - description: ctx.locale("cmd.player.errors.no_player"), + description: ctx.locale("player.errors.no_player"), color: this.client.color.red, }, ], diff --git a/src/commands/music/ClearQueue.ts b/src/commands/music/ClearQueue.ts index 421355f75..3087c0f82 100644 --- a/src/commands/music/ClearQueue.ts +++ b/src/commands/music/ClearQueue.ts @@ -36,13 +36,13 @@ export default class ClearQueue extends Command { if (!player) { return await ctx.sendMessage({ - embeds: [embed.setColor(this.client.color.red).setDescription(ctx.locale("cmd.player.errors.no_player"))], + embeds: [embed.setColor(this.client.color.red).setDescription(ctx.locale("player.errors.no_player"))], }); } if (player.queue.length === 0) { return await ctx.sendMessage({ - embeds: [embed.setColor(this.client.color.red).setDescription(ctx.locale("cmd.player.errors.no_songs"))], + embeds: [embed.setColor(this.client.color.red).setDescription(ctx.locale("player.errors.no_song"))], }); } diff --git a/src/commands/music/Grab.ts b/src/commands/music/Grab.ts index d1bef360b..ae4205fab 100644 --- a/src/commands/music/Grab.ts +++ b/src/commands/music/Grab.ts @@ -35,7 +35,7 @@ export default class Grab extends Command { if (!player?.current) { return await ctx.sendMessage({ - embeds: [this.client.embed().setColor(this.client.color.red).setDescription(ctx.locale("cmd.player.errors.no_song"))], + embeds: [this.client.embed().setColor(this.client.color.red).setDescription(ctx.locale("player.errors.no_song"))], }); } diff --git a/src/commands/music/Join.ts b/src/commands/music/Join.ts index eb1cc0cb3..7f2eab587 100644 --- a/src/commands/music/Join.ts +++ b/src/commands/music/Join.ts @@ -37,7 +37,13 @@ export default class Join extends Command { if (player) { const channelId = player.node.manager.connections.get(ctx.guild!.id)!.channelId; return await ctx.sendMessage({ - embeds: [embed.setColor(this.client.color.main).setDescription(ctx.locale("cmd.join.already_connected", { channelId }))], + embeds: [ + embed.setColor(this.client.color.main).setDescription( + ctx.locale("cmd.join.already_connected", { + channelId, + }), + ), + ], }); } @@ -57,7 +63,13 @@ export default class Join extends Command { const joinedChannelId = player.node.manager.connections.get(ctx.guild!.id)!.channelId; return await ctx.sendMessage({ - embeds: [embed.setColor(this.client.color.main).setDescription(ctx.locale("cmd.join.joined", { channelId: joinedChannelId }))], + embeds: [ + embed.setColor(this.client.color.main).setDescription( + ctx.locale("cmd.join.joined", { + channelId: joinedChannelId, + }), + ), + ], }); } } diff --git a/src/commands/music/Nowplaying.ts b/src/commands/music/Nowplaying.ts index a93bfd1ae..55766cceb 100644 --- a/src/commands/music/Nowplaying.ts +++ b/src/commands/music/Nowplaying.ts @@ -40,7 +40,10 @@ export default class Nowplaying extends Command { const embed = this.client .embed() .setColor(this.client.color.main) - .setAuthor({ name: ctx.locale("cmd.nowplaying.now_playing"), iconURL: ctx.guild?.iconURL({})! }) + .setAuthor({ + name: ctx.locale("cmd.nowplaying.now_playing"), + iconURL: ctx.guild?.iconURL({})!, + }) .setThumbnail(track.info.artworkUrl!) .setDescription( ctx.locale("cmd.nowplaying.track_info", { diff --git a/src/commands/music/Pause.ts b/src/commands/music/Pause.ts index 2a56e4dca..48923906b 100644 --- a/src/commands/music/Pause.ts +++ b/src/commands/music/Pause.ts @@ -36,7 +36,7 @@ export default class Pause extends Command { if (player?.paused) { return await ctx.sendMessage({ - embeds: [embed.setColor(this.client.color.red).setDescription(ctx.locale("cmd.player.errors.already_paused"))], + embeds: [embed.setColor(this.client.color.red).setDescription(ctx.locale("player.errors.already_paused"))], }); } diff --git a/src/commands/music/Play.ts b/src/commands/music/Play.ts index 692065a57..73ffe07a3 100644 --- a/src/commands/music/Play.ts +++ b/src/commands/music/Play.ts @@ -1,3 +1,4 @@ +import type { AutocompleteInteraction } from "discord.js"; import { LoadType } from "shoukaku"; import { Command, type Context, type Lavamusic } from "../../structures/index.js"; @@ -72,9 +73,11 @@ export default class Play extends Command { return await ctx.editMessage({ content: "", embeds: [ - embed - .setColor(this.client.color.red) - .setDescription(ctx.locale("cmd.play.errors.queue_too_long", { maxQueueSize: client.config.maxQueueSize })), + embed.setColor(this.client.color.red).setDescription( + ctx.locale("cmd.play.errors.queue_too_long", { + maxQueueSize: client.config.maxQueueSize, + }), + ), ], }); player.queue.push(track); @@ -82,9 +85,12 @@ export default class Play extends Command { ctx.editMessage({ content: "", embeds: [ - embed - .setColor(this.client.color.main) - .setDescription(ctx.locale("cmd.play.added_to_queue", { title: res.data.info.title, uri: res.data.info.uri })), + embed.setColor(this.client.color.main).setDescription( + ctx.locale("cmd.play.added_to_queue", { + title: res.data.info.title, + uri: res.data.info.uri, + }), + ), ], }); break; @@ -94,11 +100,11 @@ export default class Play extends Command { return await ctx.editMessage({ content: "", embeds: [ - embed - .setColor(this.client.color.red) - .setDescription( - ctx.locale("cmd.play.errors.playlist_too_long", { maxPlaylistSize: client.config.maxPlaylistSize }), - ), + embed.setColor(this.client.color.red).setDescription( + ctx.locale("cmd.play.errors.playlist_too_long", { + maxPlaylistSize: client.config.maxPlaylistSize, + }), + ), ], }); for (const track of res.data.tracks) { @@ -107,11 +113,11 @@ export default class Play extends Command { return await ctx.editMessage({ content: "", embeds: [ - embed - .setColor(this.client.color.red) - .setDescription( - ctx.locale("cmd.play.errors.queue_too_long", { maxQueueSize: client.config.maxQueueSize }), - ), + embed.setColor(this.client.color.red).setDescription( + ctx.locale("cmd.play.errors.queue_too_long", { + maxQueueSize: client.config.maxQueueSize, + }), + ), ], }); player.queue.push(pl); @@ -120,9 +126,11 @@ export default class Play extends Command { ctx.editMessage({ content: "", embeds: [ - embed - .setColor(this.client.color.main) - .setDescription(ctx.locale("cmd.play.added_playlist_to_queue", { length: res.data.tracks.length })), + embed.setColor(this.client.color.main).setDescription( + ctx.locale("cmd.play.added_playlist_to_queue", { + length: res.data.tracks.length, + }), + ), ], }); break; @@ -133,9 +141,11 @@ export default class Play extends Command { return await ctx.editMessage({ content: "", embeds: [ - embed - .setColor(this.client.color.red) - .setDescription(ctx.locale("cmd.play.errors.queue_too_long", { maxQueueSize: client.config.maxQueueSize })), + embed.setColor(this.client.color.red).setDescription( + ctx.locale("cmd.play.errors.queue_too_long", { + maxQueueSize: client.config.maxQueueSize, + }), + ), ], }); player.queue.push(track1); @@ -143,11 +153,12 @@ export default class Play extends Command { ctx.editMessage({ content: "", embeds: [ - embed - .setColor(this.client.color.main) - .setDescription( - ctx.locale("cmd.play.added_to_queue", { title: res.data[0].info.title, uri: res.data[0].info.uri }), - ), + embed.setColor(this.client.color.main).setDescription( + ctx.locale("cmd.play.added_to_queue", { + title: res.data[0].info.title, + uri: res.data[0].info.uri, + }), + ), ], }); break; @@ -155,25 +166,27 @@ export default class Play extends Command { } } - public async autocomplete(interaction) { + public async autocomplete(interaction: AutocompleteInteraction): Promise { const focusedValue = interaction.options.getFocused(); try { const res = await this.client.queue.search(focusedValue); const songs = []; - if(res?.loadType) { + if (res?.loadType) { if (res.loadType === LoadType.SEARCH && res.data.length) { res.data.slice(0, 10).forEach((track) => { + const name = `${track.info.title} by ${track.info.author}`; songs.push({ - name: `${track.info.title} by ${track.info.author}`, + name: name.length > 100 ? `${name.substring(0, 97)}...` : name, value: track.info.uri, }); }); } else if (res.loadType === LoadType.PLAYLIST && res.data.tracks.length) { res.data.tracks.slice(0, 10).forEach((track) => { + const name = `${track.info.title} by ${track.info.author}`; songs.push({ - name: `${track.info.title} by ${track.info.author}`, + name: name.length > 100 ? `${name.substring(0, 97)}...` : name, value: track.info.uri, }); }); @@ -186,7 +199,6 @@ export default class Play extends Command { await interaction.respond([]).catch(console.error); } } - } /** diff --git a/src/commands/music/PlayNext.ts b/src/commands/music/PlayNext.ts index 5cfdf8476..c16240fdc 100644 --- a/src/commands/music/PlayNext.ts +++ b/src/commands/music/PlayNext.ts @@ -1,3 +1,4 @@ +import type { AutocompleteInteraction } from "discord.js"; import { LoadType } from "shoukaku"; import { Command, type Context, type Lavamusic } from "../../structures/index.js"; @@ -68,22 +69,23 @@ export default class PlayNext extends Command { if (player.queue.length > client.config.maxQueueSize) return await ctx.editMessage({ embeds: [ - embed - .setColor(this.client.color.red) - .setDescription( - ctx.locale("cmd.playnext.errors.queue_too_long", { maxQueueSize: client.config.maxQueueSize }), - ), + embed.setColor(this.client.color.red).setDescription( + ctx.locale("cmd.playnext.errors.queue_too_long", { + maxQueueSize: client.config.maxQueueSize, + }), + ), ], }); player.queue.splice(0, 0, track); await player.isPlaying(); ctx.editMessage({ embeds: [ - embed - .setColor(this.client.color.main) - .setDescription( - ctx.locale("cmd.playnext.added_to_play_next", { title: res.data.info.title, uri: res.data.info.uri }), - ), + embed.setColor(this.client.color.main).setDescription( + ctx.locale("cmd.playnext.added_to_play_next", { + title: res.data.info.title, + uri: res.data.info.uri, + }), + ), ], }); break; @@ -92,11 +94,11 @@ export default class PlayNext extends Command { if (res.data.tracks.length > client.config.maxPlaylistSize) return await ctx.editMessage({ embeds: [ - embed - .setColor(this.client.color.red) - .setDescription( - ctx.locale("cmd.playnext.errors.playlist_too_long", { maxPlaylistSize: client.config.maxPlaylistSize }), - ), + embed.setColor(this.client.color.red).setDescription( + ctx.locale("cmd.playnext.errors.playlist_too_long", { + maxPlaylistSize: client.config.maxPlaylistSize, + }), + ), ], }); for (const track of res.data.tracks) { @@ -104,11 +106,11 @@ export default class PlayNext extends Command { if (player.queue.length > client.config.maxQueueSize) return await ctx.editMessage({ embeds: [ - embed - .setColor(this.client.color.red) - .setDescription( - ctx.locale("cmd.playnext.errors.queue_too_long", { maxQueueSize: client.config.maxQueueSize }), - ), + embed.setColor(this.client.color.red).setDescription( + ctx.locale("cmd.playnext.errors.queue_too_long", { + maxQueueSize: client.config.maxQueueSize, + }), + ), ], }); player.queue.splice(0, 0, pl); @@ -128,22 +130,23 @@ export default class PlayNext extends Command { if (player.queue.length > client.config.maxQueueSize) return await ctx.editMessage({ embeds: [ - embed - .setColor(this.client.color.red) - .setDescription( - ctx.locale("cmd.playnext.errors.queue_too_long", { maxQueueSize: client.config.maxQueueSize }), - ), + embed.setColor(this.client.color.red).setDescription( + ctx.locale("cmd.playnext.errors.queue_too_long", { + maxQueueSize: client.config.maxQueueSize, + }), + ), ], }); player.queue.splice(0, 0, track1); await player.isPlaying(); ctx.editMessage({ embeds: [ - embed - .setColor(this.client.color.main) - .setDescription( - ctx.locale("cmd.playnext.added_to_play_next", { title: res.data[0].info.title, uri: res.data[0].info.uri }), - ), + embed.setColor(this.client.color.main).setDescription( + ctx.locale("cmd.playnext.added_to_play_next", { + title: res.data[0].info.title, + uri: res.data[0].info.uri, + }), + ), ], }); break; @@ -151,26 +154,27 @@ export default class PlayNext extends Command { } } - public async autocomplete(interaction) { + public async autocomplete(interaction: AutocompleteInteraction): Promise { const focusedValue = interaction.options.getFocused(); - // Search for songs based on the focused value const res = await this.client.queue.search(focusedValue); const songs = []; if (res.loadType === LoadType.SEARCH && res.data.length) { res.data.slice(0, 10).forEach((x) => { + let name = `${x.info.title} by ${x.info.author}`; + if (name.length > 100) { + name = `${name.substring(0, 97)}...`; + } songs.push({ - name: `${x.info.title} by ${x.info.author}`, + name: name, value: x.info.uri, }); }); } - // Respond with the song suggestions await interaction.respond(songs).catch(console.error); } - } /** diff --git a/src/commands/music/Queue.ts b/src/commands/music/Queue.ts index 53612466e..a6707fcc7 100644 --- a/src/commands/music/Queue.ts +++ b/src/commands/music/Queue.ts @@ -70,9 +70,17 @@ export default class Queue extends Command { return this.client .embed() .setColor(this.client.color.main) - .setAuthor({ name: ctx.locale("cmd.queue.title"), iconURL: ctx.guild.iconURL({}) }) + .setAuthor({ + name: ctx.locale("cmd.queue.title"), + iconURL: ctx.guild.iconURL({}), + }) .setDescription(chunk.join("\n")) - .setFooter({ text: ctx.locale("cmd.queue.page_info", { index: index + 1, total: chunks.length }) }); + .setFooter({ + text: ctx.locale("cmd.queue.page_info", { + index: index + 1, + total: chunks.length, + }), + }); }); return await client.utils.paginate(client, ctx, pages); } diff --git a/src/commands/music/Remove.ts b/src/commands/music/Remove.ts index bfa1f3a6b..5b1f60567 100644 --- a/src/commands/music/Remove.ts +++ b/src/commands/music/Remove.ts @@ -54,7 +54,13 @@ export default class Remove extends Command { player.remove(songNumber - 1); return await ctx.sendMessage({ - embeds: [embed.setColor(this.client.color.main).setDescription(ctx.locale("cmd.remove.messages.removed", { songNumber }))], + embeds: [ + embed.setColor(this.client.color.main).setDescription( + ctx.locale("cmd.remove.messages.removed", { + songNumber, + }), + ), + ], }); } } diff --git a/src/commands/music/Search.ts b/src/commands/music/Search.ts index 39c0510f2..a26412b72 100644 --- a/src/commands/music/Search.ts +++ b/src/commands/music/Search.ts @@ -104,7 +104,12 @@ export default class Search extends Command { player.isPlaying(); await ctx.editMessage({ embeds: [ - embed.setDescription(ctx.locale("cmd.search.messages.added_to_queue", { title: song.info.title, uri: song.info.uri })), + embed.setDescription( + ctx.locale("cmd.search.messages.added_to_queue", { + title: song.info.title, + uri: song.info.uri, + }), + ), ], components: [], }); diff --git a/src/commands/music/Seek.ts b/src/commands/music/Seek.ts index 883f32970..f17c21489 100644 --- a/src/commands/music/Seek.ts +++ b/src/commands/music/Seek.ts @@ -55,18 +55,22 @@ export default class Seek extends Command { if (duration > current.length) { return await ctx.sendMessage({ embeds: [ - embed - .setColor(this.client.color.red) - .setDescription(ctx.locale("cmd.seek.errors.beyond_duration", { length: client.utils.formatTime(current.length) })), + embed.setColor(this.client.color.red).setDescription( + ctx.locale("cmd.seek.errors.beyond_duration", { + length: client.utils.formatTime(current.length), + }), + ), ], }); } player.seek(duration); return await ctx.sendMessage({ embeds: [ - embed - .setColor(this.client.color.main) - .setDescription(ctx.locale("cmd.seek.messages.seeked_to", { duration: client.utils.formatTime(duration) })), + embed.setColor(this.client.color.main).setDescription( + ctx.locale("cmd.seek.messages.seeked_to", { + duration: client.utils.formatTime(duration), + }), + ), ], }); } diff --git a/src/commands/music/Shuffle.ts b/src/commands/music/Shuffle.ts index 636a53cd9..4328cde13 100644 --- a/src/commands/music/Shuffle.ts +++ b/src/commands/music/Shuffle.ts @@ -35,7 +35,7 @@ export default class Shuffle extends Command { const embed = this.client.embed(); if (!player.queue.length) { return await ctx.sendMessage({ - embeds: [embed.setColor(this.client.color.red).setDescription(ctx.locale("cmd.player.errors.no_songs"))], + embeds: [embed.setColor(this.client.color.red).setDescription(ctx.locale("player.errors.no_song"))], }); } player.setShuffle(); diff --git a/src/commands/music/Skip.ts b/src/commands/music/Skip.ts index 7c6a897a9..057b415a5 100644 --- a/src/commands/music/Skip.ts +++ b/src/commands/music/Skip.ts @@ -35,7 +35,7 @@ export default class Skip extends Command { const embed = this.client.embed(); if (player.queue.length === 0) { return await ctx.sendMessage({ - embeds: [embed.setColor(this.client.color.red).setDescription(ctx.locale("cmd.player.errors.no_songs"))], + embeds: [embed.setColor(this.client.color.red).setDescription(ctx.locale("player.errors.no_song"))], }); } const currentTrack = player.current.info; @@ -43,9 +43,12 @@ export default class Skip extends Command { if (ctx.isInteraction) { return await ctx.sendMessage({ embeds: [ - embed - .setColor(this.client.color.main) - .setDescription(ctx.locale("cmd.skip.messages.skipped", { title: currentTrack.title, uri: currentTrack.uri })), + embed.setColor(this.client.color.main).setDescription( + ctx.locale("cmd.skip.messages.skipped", { + title: currentTrack.title, + uri: currentTrack.uri, + }), + ), ], }); } diff --git a/src/commands/music/Skipto.ts b/src/commands/music/Skipto.ts index 402feb6ed..1ebb24623 100644 --- a/src/commands/music/Skipto.ts +++ b/src/commands/music/Skipto.ts @@ -50,7 +50,13 @@ export default class Skipto extends Command { player.skip(num); return await ctx.sendMessage({ - embeds: [embed.setColor(this.client.color.main).setDescription(ctx.locale("cmd.skipto.messages.skipped_to", { number: num }))], + embeds: [ + embed.setColor(this.client.color.main).setDescription( + ctx.locale("cmd.skipto.messages.skipped_to", { + number: num, + }), + ), + ], }); } } diff --git a/src/commands/music/Volume.ts b/src/commands/music/Volume.ts index 90076934c..36ef52acb 100644 --- a/src/commands/music/Volume.ts +++ b/src/commands/music/Volume.ts @@ -58,7 +58,11 @@ export default class Volume extends Command { return await ctx.sendMessage({ embeds: [ - embed.setColor(this.client.color.main).setDescription(ctx.locale("cmd.volume.messages.set", { volume: currentVolume })), + embed.setColor(this.client.color.main).setDescription( + ctx.locale("cmd.volume.messages.set", { + volume: currentVolume, + }), + ), ], }); } diff --git a/src/commands/playlist/AddSong.ts b/src/commands/playlist/AddSong.ts index 3519be9ec..9c3cb1334 100644 --- a/src/commands/playlist/AddSong.ts +++ b/src/commands/playlist/AddSong.ts @@ -1,3 +1,4 @@ +import type { AutocompleteInteraction } from "discord.js"; import { LoadType } from "shoukaku"; import { Command, type Context, type Lavamusic } from "../../structures/index.js"; @@ -98,26 +99,29 @@ export default class AddSong extends Command { const successMessage = this.client .embed() - .setDescription(ctx.locale("cmd.addsong.messages.added", { count, playlist: playlistData.name })) + .setDescription( + ctx.locale("cmd.addsong.messages.added", { + count, + playlist: playlistData.name, + }), + ) .setColor(this.client.color.green); await ctx.sendMessage({ embeds: [successMessage] }); } - // Add autocomplete handler - public async autocomplete(interaction) { + public async autocomplete(interaction: AutocompleteInteraction): Promise { const focusedValue = interaction.options.getFocused(); const userId = interaction.user.id; - // Fetch user playlists from the database const playlists = await this.client.db.getUserPlaylists(userId); - // Filter playlists based on the focused value and respond - const filtered = playlists.filter(playlist => - playlist.name.toLowerCase().startsWith(focusedValue.toLowerCase()) - ); + const filtered = playlists.filter((playlist) => playlist.name.toLowerCase().startsWith(focusedValue.toLowerCase())); await interaction.respond( - filtered.map(playlist => ({ name: playlist.name, value: playlist.name })) + filtered.map((playlist) => ({ + name: playlist.name, + value: playlist.name, + })), ); } } diff --git a/src/commands/playlist/Create.ts b/src/commands/playlist/Create.ts index f35487e5c..c6b80a7ea 100644 --- a/src/commands/playlist/Create.ts +++ b/src/commands/playlist/Create.ts @@ -56,7 +56,15 @@ export default class CreatePlaylist extends Command { await client.db.createPlaylist(ctx.author.id, name); return await ctx.sendMessage({ - embeds: [embed.setDescription(ctx.locale("cmd.create.messages.playlist_created", { name })).setColor(this.client.color.green)], + embeds: [ + embed + .setDescription( + ctx.locale("cmd.create.messages.playlist_created", { + name, + }), + ) + .setColor(this.client.color.green), + ], }); } } diff --git a/src/commands/playlist/Delete.ts b/src/commands/playlist/Delete.ts index 91c6aec9f..663bd4518 100644 --- a/src/commands/playlist/Delete.ts +++ b/src/commands/playlist/Delete.ts @@ -1,3 +1,4 @@ +import type { AutocompleteInteraction } from "discord.js"; import { Command, type Context, type Lavamusic } from "../../structures/index.js"; export default class DeletePlaylist extends Command { @@ -56,27 +57,29 @@ export default class DeletePlaylist extends Command { return await ctx.sendMessage({ embeds: [ embed - .setDescription(ctx.locale("cmd.delete.messages.playlist_deleted", { playlistName })) + .setDescription( + ctx.locale("cmd.delete.messages.playlist_deleted", { + playlistName, + }), + ) .setColor(this.client.color.green), ], }); } - // Add autocomplete handler - public async autocomplete(interaction) { + public async autocomplete(interaction: AutocompleteInteraction): Promise { const focusedValue = interaction.options.getFocused(); const userId = interaction.user.id; - // Fetch user playlists from the database const playlists = await this.client.db.getUserPlaylists(userId); - // Filter playlists based on the focused value and respond - const filtered = playlists.filter(playlist => - playlist.name.toLowerCase().startsWith(focusedValue.toLowerCase()) - ); + const filtered = playlists.filter((playlist) => playlist.name.toLowerCase().startsWith(focusedValue.toLowerCase())); await interaction.respond( - filtered.map(playlist => ({ name: playlist.name, value: playlist.name })) + filtered.map((playlist) => ({ + name: playlist.name, + value: playlist.name, + })), ); } } diff --git a/src/commands/playlist/List.ts b/src/commands/playlist/List.ts index d262b5441..eeba5c708 100644 --- a/src/commands/playlist/List.ts +++ b/src/commands/playlist/List.ts @@ -30,7 +30,7 @@ export default class GetPlaylists extends Command { { name: "user", description: "cmd.list.options.user", - type: 6, // USER type + type: 6, required: false, }, ], @@ -72,7 +72,11 @@ export default class GetPlaylists extends Command { const targetUsername = targetUser ? targetUser.username : ctx.locale("cmd.list.messages.your"); const successMessage = this.client .embed() - .setTitle(ctx.locale("cmd.list.messages.playlists_title", { username: targetUsername })) + .setTitle( + ctx.locale("cmd.list.messages.playlists_title", { + username: targetUsername, + }), + ) .setDescription(playlists.map((playlist: any) => playlist.name).join("\n")) .setColor(this.client.color.green); await ctx.sendMessage({ embeds: [successMessage] }); diff --git a/src/commands/playlist/Load.ts b/src/commands/playlist/Load.ts index c79851565..f23cdd3cc 100644 --- a/src/commands/playlist/Load.ts +++ b/src/commands/playlist/Load.ts @@ -1,3 +1,4 @@ +import type { AutocompleteInteraction } from "discord.js"; import { Command, type Context, type Lavamusic } from "../../structures/index.js"; export default class LoadPlaylist extends Command { @@ -94,21 +95,19 @@ export default class LoadPlaylist extends Command { }); } - // Add autocomplete handler - public async autocomplete(interaction) { + public async autocomplete(interaction: AutocompleteInteraction): Promise { const focusedValue = interaction.options.getFocused(); const userId = interaction.user.id; - // Fetch user playlists from the database const playlists = await this.client.db.getUserPlaylists(userId); - // Filter playlists based on the focused value and respond - const filtered = playlists.filter(playlist => - playlist.name.toLowerCase().startsWith(focusedValue.toLowerCase()) - ); + const filtered = playlists.filter((playlist) => playlist.name.toLowerCase().startsWith(focusedValue.toLowerCase())); await interaction.respond( - filtered.map(playlist => ({ name: playlist.name, value: playlist.name })) + filtered.map((playlist) => ({ + name: playlist.name, + value: playlist.name, + })), ); } } diff --git a/src/commands/playlist/RemoveSong.ts b/src/commands/playlist/RemoveSong.ts index 6a924394b..04c2e7201 100644 --- a/src/commands/playlist/RemoveSong.ts +++ b/src/commands/playlist/RemoveSong.ts @@ -1,3 +1,4 @@ +import type { AutocompleteInteraction } from "discord.js"; import { LoadType } from "shoukaku"; import { Command, type Context, type Lavamusic } from "../../structures/index.js"; @@ -93,7 +94,10 @@ export default class RemoveSong extends Command { const successMessage = this.client .embed() .setDescription( - ctx.locale("cmd.removesong.messages.song_removed", { song: trackToRemove.info.title, playlist: playlistData.name }), + ctx.locale("cmd.removesong.messages.song_removed", { + song: trackToRemove.info.title, + playlist: playlistData.name, + }), ) .setColor(this.client.color.green); await ctx.sendMessage({ embeds: [successMessage] }); @@ -106,21 +110,19 @@ export default class RemoveSong extends Command { return await ctx.sendMessage({ embeds: [genericError] }); } } - // Add autocomplete handler - public async autocomplete(interaction) { + public async autocomplete(interaction: AutocompleteInteraction): Promise { const focusedValue = interaction.options.getFocused(); const userId = interaction.user.id; - // Fetch user playlists from the database const playlists = await this.client.db.getUserPlaylists(userId); - // Filter playlists based on the focused value and respond - const filtered = playlists.filter(playlist => - playlist.name.toLowerCase().startsWith(focusedValue.toLowerCase()) - ); + const filtered = playlists.filter((playlist) => playlist.name.toLowerCase().startsWith(focusedValue.toLowerCase())); await interaction.respond( - filtered.map(playlist => ({ name: playlist.name, value: playlist.name })) + filtered.map((playlist) => ({ + name: playlist.name, + value: playlist.name, + })), ); } } diff --git a/src/commands/playlist/Steal.ts b/src/commands/playlist/Steal.ts index 3a4d57299..1f272e8f7 100644 --- a/src/commands/playlist/Steal.ts +++ b/src/commands/playlist/Steal.ts @@ -36,7 +36,7 @@ export default class StealPlaylist extends Command { { name: "user", description: "cmd.steal.options.user", - type: 6, // USER type + type: 6, required: true, }, ], @@ -84,7 +84,9 @@ export default class StealPlaylist extends Command { .embed() .setDescription(ctx.locale("cmd.steal.messages.playlist_not_exist")) .setColor(this.client.color.red); - return await ctx.sendMessage({ embeds: [playlistNotFoundError] }); + return await ctx.sendMessage({ + embeds: [playlistNotFoundError], + }); } const targetSongs = await client.db.getSongs(targetUserId, playlistName); @@ -92,7 +94,12 @@ export default class StealPlaylist extends Command { const successMessage = this.client .embed() - .setDescription(ctx.locale("cmd.steal.messages.playlist_stolen", { playlist: playlistName, user: targetUser.username })) + .setDescription( + ctx.locale("cmd.steal.messages.playlist_stolen", { + playlist: playlistName, + user: targetUser.username, + }), + ) .setColor(this.client.color.green); await ctx.sendMessage({ embeds: [successMessage] }); } catch (error) { @@ -108,52 +115,62 @@ export default class StealPlaylist extends Command { public async autocomplete(interaction) { try { const focusedValue = interaction.options.getFocused(); - const userOptionId = interaction.options.get('user')?.value; + const userOptionId = interaction.options.get("user")?.value; if (!userOptionId) { - await interaction.respond([ - { name: "Please specify a user to search their playlists.", value: "NoUser" } - ]).catch(console.error); + await interaction + .respond([ + { + name: "Please specify a user to search their playlists.", + value: "NoUser", + }, + ]) + .catch(console.error); return; } - // Fetch the user object using the client const user = await interaction.client.users.fetch(userOptionId); if (!user) { - await interaction.respond([ - { name: "User not found.", value: "NoUserFound" } - ]).catch(console.error); - return; // Exit early if user cannot be found + await interaction.respond([{ name: "User not found.", value: "NoUserFound" }]).catch(console.error); + return; } - // Proceed with fetching the user's playlists const playlists = await this.client.db.getUserPlaylists(user.id); - // If no playlists are found, respond accordingly if (!playlists || playlists.length === 0) { - await interaction.respond([ - { name: "No playlists found for this user.", value: "NoPlaylists" } - ]).catch(console.error); - return; // Exit early as there are no playlists + await interaction + .respond([ + { + name: "No playlists found for this user.", + value: "NoPlaylists", + }, + ]) + .catch(console.error); + return; } - // Filter playlists based on the focused value - const filtered = playlists.filter(playlist => - playlist.name.toLowerCase().startsWith(focusedValue.toLowerCase()) - ); + const filtered = playlists.filter((playlist) => playlist.name.toLowerCase().startsWith(focusedValue.toLowerCase())); - // Respond with filtered playlist names - await interaction.respond( - filtered.map(playlist => ({ name: playlist.name, value: playlist.name })) - ).catch(console.error); + await interaction + .respond( + filtered.map((playlist) => ({ + name: playlist.name, + value: playlist.name, + })), + ) + .catch(console.error); } catch (error) { console.error("Error in autocomplete interaction:", error); - await interaction.respond([ - { name: "An error occurred while fetching playlists.", value: "Error" } - ]).catch(console.error); + await interaction + .respond([ + { + name: "An error occurred while fetching playlists.", + value: "Error", + }, + ]) + .catch(console.error); } } - } /** diff --git a/src/database/server.ts b/src/database/server.ts index c068221de..547e5b8ff 100644 --- a/src/database/server.ts +++ b/src/database/server.ts @@ -194,7 +194,9 @@ export default class ServerData { public async getSongs(userId: string, name: string): Promise { const playlist = await this.getPlaylist(userId, name); if (playlist) { - return this.prisma.song.findMany({ where: { playlistId: playlist.id } }); + return this.prisma.song.findMany({ + where: { playlistId: playlist.id }, + }); } return []; } @@ -202,7 +204,9 @@ export default class ServerData { public async clearPlaylist(userId: string, name: string): Promise { const playlist = await this.getPlaylist(userId, name); if (playlist) { - await this.prisma.song.deleteMany({ where: { playlistId: playlist.id } }); + await this.prisma.song.deleteMany({ + where: { playlistId: playlist.id }, + }); } } diff --git a/src/events/client/GuildCreate.ts b/src/events/client/GuildCreate.ts index 8c5ba877f..e7b2a27e4 100644 --- a/src/events/client/GuildCreate.ts +++ b/src/events/client/GuildCreate.ts @@ -18,14 +18,33 @@ export default class GuildCreate extends Event { const embed = new EmbedBuilder() .setColor(this.client.config.color.green) - .setAuthor({ name: guild.name, iconURL: guild.iconURL({ extension: "jpeg" }) }) + .setAuthor({ + name: guild.name, + iconURL: guild.iconURL({ extension: "jpeg" }), + }) .setDescription(`**${guild.name}** has been added to my guilds!`) .setThumbnail(guild.iconURL({ extension: "jpeg" })) .addFields( - { name: "Owner", value: owner ? owner.user.tag : "Unknown#0000", inline: true }, - { name: "Members", value: guild.memberCount.toString(), inline: true }, - { name: "Created At", value: ``, inline: true }, - { name: "Joined At", value: ``, inline: true }, + { + name: "Owner", + value: owner ? owner.user.tag : "Unknown#0000", + inline: true, + }, + { + name: "Members", + value: guild.memberCount.toString(), + inline: true, + }, + { + name: "Created At", + value: ``, + inline: true, + }, + { + name: "Joined At", + value: ``, + inline: true, + }, { name: "ID", value: guild.id, inline: true }, ) .setTimestamp(); diff --git a/src/events/client/GuildDelete.ts b/src/events/client/GuildDelete.ts index 05b0b99b8..9df21f6f8 100644 --- a/src/events/client/GuildDelete.ts +++ b/src/events/client/GuildDelete.ts @@ -25,10 +25,26 @@ export default class GuildDelete extends Event { .setDescription(`**${guild.name}** has been removed from my guilds!`) .setThumbnail(guild.iconURL({ extension: "jpeg" })) .addFields( - { name: "Owner", value: owner ? owner.user.tag : "Unknown#0000", inline: true }, - { name: "Members", value: guild.memberCount?.toString() || "Unknown", inline: true }, - { name: "Created At", value: ``, inline: true }, - { name: "Removed At", value: ``, inline: true }, + { + name: "Owner", + value: owner ? owner.user.tag : "Unknown#0000", + inline: true, + }, + { + name: "Members", + value: guild.memberCount?.toString() || "Unknown", + inline: true, + }, + { + name: "Created At", + value: ``, + inline: true, + }, + { + name: "Removed At", + value: ``, + inline: true, + }, { name: "ID", value: guild.id, inline: true }, ) .setTimestamp(); diff --git a/src/events/client/InteractionCreate.ts b/src/events/client/InteractionCreate.ts index 41930bd25..8b15e0f78 100644 --- a/src/events/client/InteractionCreate.ts +++ b/src/events/client/InteractionCreate.ts @@ -12,10 +12,8 @@ import { PermissionFlagsBits, type TextChannel, } from "discord.js"; -import { LoadType } from "shoukaku"; import { T } from "../../structures/I18n.js"; import { Context, Event, type Lavamusic } from "../../structures/index.js"; -import { Language } from "../../types.js"; export default class InteractionCreate extends Event { constructor(client: Lavamusic, file: string) { @@ -196,7 +194,10 @@ export default class InteractionCreate extends Event { const timeLeft = (expirationTime - now) / 1000; if (now < expirationTime && timeLeft > 0.9) { return await interaction.reply({ - content: T(locale, "event.interaction.cooldown", { time: timeLeft.toFixed(1), command: commandName }), + content: T(locale, "event.interaction.cooldown", { + time: timeLeft.toFixed(1), + command: commandName, + }), }); } timestamps.set(interaction.user.id, now); @@ -217,7 +218,9 @@ export default class InteractionCreate extends Event { const embed = new EmbedBuilder() .setAuthor({ name: "Slash - Command Logs", - iconURL: this.client.user?.avatarURL({ size: 2048 }), + iconURL: this.client.user?.avatarURL({ + size: 2048, + }), }) .setColor(this.client.config.color.blue) .setDescription( diff --git a/src/events/client/MessageCreate.ts b/src/events/client/MessageCreate.ts index ec45ae6db..3bafa99e8 100644 --- a/src/events/client/MessageCreate.ts +++ b/src/events/client/MessageCreate.ts @@ -32,7 +32,9 @@ export default class MessageCreate extends Event { const mention = new RegExp(`^<@!?${this.client.user.id}>( |)$`); if (mention.test(message.content)) { await message.reply({ - content: T(locale, "event.message.prefix_mention", { prefix: guild.prefix }), + content: T(locale, "event.message.prefix_mention", { + prefix: guild.prefix, + }), }); return; } @@ -114,7 +116,9 @@ export default class MessageCreate extends Event { if (command.player.voice) { if (!message.member.voice.channel) { await message.reply({ - content: T(locale, "event.message.no_voice_channel", { command: command.name }), + content: T(locale, "event.message.no_voice_channel", { + command: command.name, + }), }); return; } @@ -218,7 +222,10 @@ export default class MessageCreate extends Event { const timeLeft = (expirationTime - now) / 1000; if (now < expirationTime && timeLeft > 0.9) { await message.reply({ - content: T(locale, "event.message.cooldown", { time: timeLeft.toFixed(1), command: cmd }), + content: T(locale, "event.message.cooldown", { + time: timeLeft.toFixed(1), + command: cmd, + }), }); return; } @@ -240,7 +247,9 @@ export default class MessageCreate extends Event { return command.run(this.client, ctx, ctx.args); } catch (error) { this.client.logger.error(error); - await message.reply({ content: T(locale, "event.message.error", { error }) }); + await message.reply({ + content: T(locale, "event.message.error", { error }), + }); } finally { if (logs) { const embed = new EmbedBuilder() diff --git a/src/events/client/SetupButtons.ts b/src/events/client/SetupButtons.ts index 01fbd8466..b59ba5ea2 100644 --- a/src/events/client/SetupButtons.ts +++ b/src/events/client/SetupButtons.ts @@ -23,7 +23,9 @@ export default class SetupButtons extends Event { if (clientMember.voice.channel && clientMember.voice.channelId !== interaction.member.voice.channelId) { return await buttonReply( interaction, - T(locale, "event.setupButton.different_voice_channel_button", { channel: clientMember.voice.channel }), + T(locale, "event.setupButton.different_voice_channel_button", { + channel: clientMember.voice.channel, + }), this.client.color.red, ); } @@ -35,7 +37,9 @@ export default class SetupButtons extends Event { const { title, uri, length, artworkUrl, sourceName, isStream, requester } = player.current.info; let message: Message; try { - message = await interaction.channel.messages.fetch(data.messageId, { cache: true }); + message = await interaction.channel.messages.fetch(data.messageId, { + cache: true, + }); } catch (_e) { /* empty */ } @@ -43,7 +47,10 @@ export default class SetupButtons extends Event { const iconUrl = this.client.config.icons[sourceName] || this.client.user.displayAvatarURL({ extension: "png" }); const embed = this.client .embed() - .setAuthor({ name: T(locale, "event.setupButton.now_playing"), iconURL: iconUrl }) + .setAuthor({ + name: T(locale, "event.setupButton.now_playing"), + iconURL: iconUrl, + }) .setColor(this.client.color.main) .setDescription( `[${title}](${uri}) - ${isStream ? T(locale, "event.setupButton.live") : this.client.utils.formatTime(length)} - ${T(locale, "event.setupButton.requested_by", { requester })}`, @@ -62,7 +69,10 @@ export default class SetupButtons extends Event { await message.edit({ embeds: [ embed.setFooter({ - text: T(locale, "event.setupButton.volume_footer", { vol, displayName: interaction.member.displayName }), + text: T(locale, "event.setupButton.volume_footer", { + vol, + displayName: interaction.member.displayName, + }), iconURL: interaction.member.displayAvatarURL({}), }), ], @@ -102,7 +112,9 @@ export default class SetupButtons extends Event { await message.edit({ embeds: [ embed.setFooter({ - text: T(locale, "event.setupButton.skipped_footer", { displayName: interaction.member.displayName }), + text: T(locale, "event.setupButton.skipped_footer", { + displayName: interaction.member.displayName, + }), iconURL: interaction.member.displayAvatarURL({}), }), ], @@ -115,14 +127,18 @@ export default class SetupButtons extends Event { embeds: [ embed .setFooter({ - text: T(locale, "event.setupButton.stopped_footer", { displayName: interaction.member.displayName }), + text: T(locale, "event.setupButton.stopped_footer", { + displayName: interaction.member.displayName, + }), iconURL: interaction.member.displayAvatarURL({}), }) .setDescription(T(locale, "event.setupButton.nothing_playing")) .setImage(this.client.config.links.img) .setAuthor({ name: this.client.user.username, - iconURL: this.client.user.displayAvatarURL({ extension: "png" }), + iconURL: this.client.user.displayAvatarURL({ + extension: "png", + }), }), ], }); @@ -131,7 +147,13 @@ export default class SetupButtons extends Event { const loopOptions: Array<"off" | "queue" | "repeat"> = ["off", "queue", "repeat"]; const newLoop = loopOptions[(loopOptions.indexOf(player.loop) + 1) % loopOptions.length]; player.setLoop(newLoop); - await buttonReply(interaction, T(locale, "event.setupButton.loop_set", { loop: newLoop }), this.client.color.main); + await buttonReply( + interaction, + T(locale, "event.setupButton.loop_set", { + loop: newLoop, + }), + this.client.color.main, + ); await message.edit({ embeds: [ embed.setFooter({ @@ -158,7 +180,9 @@ export default class SetupButtons extends Event { await message.edit({ embeds: [ embed.setFooter({ - text: T(locale, "event.setupButton.previous_footer", { displayName: interaction.member.displayName }), + text: T(locale, "event.setupButton.previous_footer", { + displayName: interaction.member.displayName, + }), iconURL: interaction.member.displayAvatarURL({}), }), ], @@ -174,7 +198,9 @@ export default class SetupButtons extends Event { await message.edit({ embeds: [ embed.setFooter({ - text: T(locale, "event.setupButton.rewind_footer", { displayName: interaction.member.displayName }), + text: T(locale, "event.setupButton.rewind_footer", { + displayName: interaction.member.displayName, + }), iconURL: interaction.member.displayAvatarURL({}), }), ], @@ -191,7 +217,9 @@ export default class SetupButtons extends Event { await message.edit({ embeds: [ embed.setFooter({ - text: T(locale, "event.setupButton.forward_footer", { displayName: interaction.member.displayName }), + text: T(locale, "event.setupButton.forward_footer", { + displayName: interaction.member.displayName, + }), iconURL: interaction.member.displayAvatarURL({}), }), ], diff --git a/src/events/client/SetupSystem.ts b/src/events/client/SetupSystem.ts index 5a74d75a3..72acb39fb 100644 --- a/src/events/client/SetupSystem.ts +++ b/src/events/client/SetupSystem.ts @@ -25,13 +25,23 @@ export default class SetupSystem extends Event { const clientMember = message.guild.members.cache.get(clientUser.id); if (!voiceChannel.permissionsFor(clientUser).has(PermissionsBitField.Flags.Connect | PermissionsBitField.Flags.Speak)) { - await oops(channel, T(locale, "event.message.no_permission_connect_speak", { channel: voiceChannel.id })); + await oops( + channel, + T(locale, "event.message.no_permission_connect_speak", { + channel: voiceChannel.id, + }), + ); await message.delete().catch(() => {}); return; } if (clientMember?.voice.channel && clientMember.voice.channelId !== voiceChannel.id) { - await oops(channel, T(locale, "event.message.different_voice_channel_queue", { channel: clientMember.voice.channelId })); + await oops( + channel, + T(locale, "event.message.different_voice_channel_queue", { + channel: clientMember.voice.channelId, + }), + ); await message.delete().catch(() => {}); return; } diff --git a/src/events/player/TrackStart.ts b/src/events/player/TrackStart.ts index 3fc5687b0..89eced69a 100644 --- a/src/events/player/TrackStart.ts +++ b/src/events/player/TrackStart.ts @@ -47,7 +47,9 @@ export default class TrackStart extends Event { .setColor(this.client.color.main) .setDescription(`**[${track.info.title}](${track.info.uri})**`) .setFooter({ - text: T(locale, "player.trackStart.requested_by", { user: track.info.requester.tag }), + text: T(locale, "player.trackStart.requested_by", { + user: track.info.requester.tag, + }), iconURL: track.info.requester.avatarURL({}), }) .setThumbnail(track.info.artworkUrl) @@ -57,7 +59,11 @@ export default class TrackStart extends Event { value: track.info.isStream ? "LIVE" : this.client.utils.formatTime(track.info.length), inline: true, }, - { name: T(locale, "player.trackStart.author"), value: track.info.author, inline: true }, + { + name: T(locale, "player.trackStart.author"), + value: track.info.author, + inline: true, + }, ) .setTimestamp(); @@ -136,7 +142,12 @@ function createCollector(message: any, dispatcher: Dispatcher, _track: Song, emb const editMessage = async (text: string): Promise => { if (message) { await message.edit({ - embeds: [embed.setFooter({ text, iconURL: interaction.user.avatarURL({}) })], + embeds: [ + embed.setFooter({ + text, + iconURL: interaction.user.avatarURL({}), + }), + ], components: [createButtonRow(dispatcher, client)], }); } @@ -146,7 +157,11 @@ function createCollector(message: any, dispatcher: Dispatcher, _track: Song, emb if (dispatcher.previous) { await interaction.deferUpdate(); dispatcher.previousTrack(); - await editMessage(T(locale, "player.trackStart.previous_by", { user: interaction.user.tag })); + await editMessage( + T(locale, "player.trackStart.previous_by", { + user: interaction.user.tag, + }), + ); } else { await interaction.reply({ content: T(locale, "player.trackStart.no_previous_song"), @@ -159,8 +174,12 @@ function createCollector(message: any, dispatcher: Dispatcher, _track: Song, emb await interaction.deferUpdate(); await editMessage( dispatcher.paused - ? T(locale, "player.trackStart.paused_by", { user: interaction.user.tag }) - : T(locale, "player.trackStart.resumed_by", { user: interaction.user.tag }), + ? T(locale, "player.trackStart.paused_by", { + user: interaction.user.tag, + }) + : T(locale, "player.trackStart.resumed_by", { + user: interaction.user.tag, + }), ); break; case "stop": @@ -171,7 +190,11 @@ function createCollector(message: any, dispatcher: Dispatcher, _track: Song, emb if (dispatcher.queue.length) { await interaction.deferUpdate(); dispatcher.skip(); - await editMessage(T(locale, "player.trackStart.skipped_by", { user: interaction.user.tag })); + await editMessage( + T(locale, "player.trackStart.skipped_by", { + user: interaction.user.tag, + }), + ); } else { await interaction.reply({ content: T(locale, "player.trackStart.no_more_songs_in_queue"), @@ -184,15 +207,27 @@ function createCollector(message: any, dispatcher: Dispatcher, _track: Song, emb switch (dispatcher.loop) { case "off": dispatcher.loop = "repeat"; - await editMessage(T(locale, "player.trackStart.looping_by", { user: interaction.user.tag })); + await editMessage( + T(locale, "player.trackStart.looping_by", { + user: interaction.user.tag, + }), + ); break; case "repeat": dispatcher.loop = "queue"; - await editMessage(T(locale, "player.trackStart.looping_queue_by", { user: interaction.user.tag })); + await editMessage( + T(locale, "player.trackStart.looping_queue_by", { + user: interaction.user.tag, + }), + ); break; case "queue": dispatcher.loop = "off"; - await editMessage(T(locale, "player.trackStart.looping_off_by", { user: interaction.user.tag })); + await editMessage( + T(locale, "player.trackStart.looping_off_by", { + user: interaction.user.tag, + }), + ); break; } break; diff --git a/src/index.ts b/src/index.ts index c5afa14e7..82adc7d07 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,4 +1,5 @@ // biome-ignore lint/style/noNamespaceImport: +// biome-ignore lint/correctness/noNodejsModules: import * as fs from "node:fs"; import { ShardingManager } from "discord.js"; diff --git a/src/plugin/index.ts b/src/plugin/index.ts index dd455b10f..60902b424 100644 --- a/src/plugin/index.ts +++ b/src/plugin/index.ts @@ -1,5 +1,8 @@ +// biome-ignore lint/correctness/noNodejsModules: import fs from "node:fs"; +// biome-ignore lint/correctness/noNodejsModules: import path from "node:path"; +// biome-ignore lint/correctness/noNodejsModules: import { fileURLToPath } from "node:url"; import type { Lavamusic } from "../structures/index.js"; diff --git a/src/plugin/plugins/keepAlive.ts b/src/plugin/plugins/keepAlive.ts index adf545818..2b5c1d227 100644 --- a/src/plugin/plugins/keepAlive.ts +++ b/src/plugin/plugins/keepAlive.ts @@ -1,3 +1,4 @@ +// biome-ignore lint/correctness/noNodejsModules: import http from "node:http"; import type { Lavamusic } from "../../structures/index.js"; import type { BotPlugin } from "../index.js"; diff --git a/src/structures/Lavamusic.ts b/src/structures/Lavamusic.ts index 0b64dc0dc..727cc4aec 100644 --- a/src/structures/Lavamusic.ts +++ b/src/structures/Lavamusic.ts @@ -1,5 +1,8 @@ +// biome-ignore lint/correctness/noNodejsModules: import fs from "node:fs"; +// biome-ignore lint/correctness/noNodejsModules: import path from "node:path"; +// biome-ignore lint/correctness/noNodejsModules: import { fileURLToPath } from "node:url"; import { Api } from "@top-gg/sdk"; import { @@ -35,8 +38,8 @@ export default class Lavamusic extends Client { public readonly emoji = config.emoji; public readonly color = config.color; private body: RESTPostAPIChatInputApplicationCommandsJSONBody[] = []; - public shoukaku: ShoukakuClient; - public topGG: Api; + public shoukaku!: ShoukakuClient; + public topGG!: Api; public utils = Utils; public queue = new Queue(this); @@ -56,8 +59,8 @@ export default class Lavamusic extends Client { loadPlugins(this); await this.login(token); - this.on(Events.InteractionCreate, async (interaction: Interaction<"cached">) => { - if (interaction.isButton()) { + this.on(Events.InteractionCreate, async (interaction: Interaction) => { + if (interaction.isButton() && interaction.guildId) { const setup = await this.db.getSetup(interaction.guildId); if (setup && interaction.channelId === setup.textId && interaction.message.id === setup.messageId) { this.emit("setupButtons", interaction); @@ -96,55 +99,67 @@ export default class Lavamusic extends Client { name_localizations: null, description_localizations: null, }; - // command description and name localizations + const localizations = []; i18n.getLocales().map((locale) => { localizations.push(localization(locale, command.name, command.description.content)); }); + for (const localization of localizations) { const [language, name] = localization.name; const [language2, description] = localization.description; - data.name_localizations = { ...data.name_localizations, [language]: name }; - data.description_localizations = { ...data.description_localizations, [language2]: description }; + data.name_localizations = { + ...data.name_localizations, + [language]: name, + }; + data.description_localizations = { + ...data.description_localizations, + [language2]: description, + }; } - // command options localizations if (command.options.length > 0) { command.options.map((option) => { - // command options name and description localizations const optionsLocalizations = []; i18n.getLocales().map((locale) => { optionsLocalizations.push(localization(locale, option.name, option.description)); }); + for (const localization of optionsLocalizations) { const [language, name] = localization.name; const [language2, description] = localization.description; - option.name_localizations = { ...option.name_localizations, [language]: name }; - option.description_localizations = { ...option.description_localizations, [language2]: description }; + option.name_localizations = { + ...option.name_localizations, + [language]: name, + }; + option.description_localizations = { + ...option.description_localizations, + [language2]: description, + }; } - // command options description localization option.description = T(Locale.EnglishUS, option.description); }); - // subcommand options localizations data.options.map((option) => { if ("options" in option && option.options.length > 0) { option.options.map((subOption) => { - // subcommand options name and description localizations const subOptionsLocalizations = []; i18n.getLocales().map((locale) => { subOptionsLocalizations.push(localization(locale, subOption.name, subOption.description)); }); + for (const localization of subOptionsLocalizations) { const [language, name] = localization.name; const [language2, description] = localization.description; - subOption.name_localizations = { ...subOption.name_localizations, [language]: name }; + subOption.name_localizations = { + ...subOption.name_localizations, + [language]: name, + }; subOption.description_localizations = { ...subOption.description_localizations, [language2]: description, }; } - // subcommand options description localization subOption.description = T(Locale.EnglishUS, subOption.description); }); } diff --git a/src/utils/BotLog.ts b/src/utils/BotLog.ts index 7481aa6b0..f72ae6c73 100644 --- a/src/utils/BotLog.ts +++ b/src/utils/BotLog.ts @@ -6,7 +6,7 @@ export default class BotLog { public static send(client: Lavamusic, message: string, type: "error" | "warn" | "info" | "success" = "info"): void { if (!client?.channels.cache && client.config.logChannelId) return; - const channel = client.channels.cache.get(client.config.logChannelId) as TextChannel; + const channel = client.channels.cache.get(client.config.logChannelId!) as TextChannel; if (!channel) return; const colors = { diff --git a/src/utils/Buttons.ts b/src/utils/Buttons.ts index 289156946..d9d46d3f2 100644 --- a/src/utils/Buttons.ts +++ b/src/utils/Buttons.ts @@ -3,20 +3,56 @@ import type { Dispatcher, Lavamusic } from "../structures/index.js"; function getButtons(player: Dispatcher, client: Lavamusic): ActionRowBuilder[] { const buttonData = [ - { customId: "REWIND_BUT", emoji: client.emoji.replay, style: ButtonStyle.Secondary }, - { customId: "LOW_VOL_BUT", emoji: client.emoji.voldown, style: ButtonStyle.Secondary }, - { customId: "STOP_BUT", emoji: client.emoji.stop, style: ButtonStyle.Danger }, - { customId: "HIGH_VOL_BUT", emoji: client.emoji.volup, style: ButtonStyle.Secondary }, - { customId: "FORWARD_BUT", emoji: client.emoji.forward, style: ButtonStyle.Secondary }, - { customId: "PREV_BUT", emoji: client.emoji.previous, style: ButtonStyle.Secondary }, - { customId: "LOOP_BUT", emoji: client.emoji.loop.none, style: ButtonStyle.Secondary }, + { + customId: "REWIND_BUT", + emoji: client.emoji.replay, + style: ButtonStyle.Secondary, + }, + { + customId: "LOW_VOL_BUT", + emoji: client.emoji.voldown, + style: ButtonStyle.Secondary, + }, + { + customId: "STOP_BUT", + emoji: client.emoji.stop, + style: ButtonStyle.Danger, + }, + { + customId: "HIGH_VOL_BUT", + emoji: client.emoji.volup, + style: ButtonStyle.Secondary, + }, + { + customId: "FORWARD_BUT", + emoji: client.emoji.forward, + style: ButtonStyle.Secondary, + }, + { + customId: "PREV_BUT", + emoji: client.emoji.previous, + style: ButtonStyle.Secondary, + }, + { + customId: "LOOP_BUT", + emoji: client.emoji.loop.none, + style: ButtonStyle.Secondary, + }, { customId: "PAUSE_BUT", emoji: player?.paused ? client.emoji.resume : client.emoji.pause, style: player?.paused ? ButtonStyle.Success : ButtonStyle.Secondary, }, - { customId: "SHUFFLE_BUT", emoji: client.emoji.shuffle, style: ButtonStyle.Secondary }, - { customId: "SKIP_BUT", emoji: client.emoji.skip, style: ButtonStyle.Secondary }, + { + customId: "SHUFFLE_BUT", + emoji: client.emoji.shuffle, + style: ButtonStyle.Secondary, + }, + { + customId: "SKIP_BUT", + emoji: client.emoji.skip, + style: ButtonStyle.Secondary, + }, ]; return buttonData.reduce((rows, { customId, emoji, style }, index) => { diff --git a/src/utils/SetupSystem.ts b/src/utils/SetupSystem.ts index e8ca54642..a25872dac 100644 --- a/src/utils/SetupSystem.ts +++ b/src/utils/SetupSystem.ts @@ -18,7 +18,10 @@ function neb(embed: EmbedBuilder, player: Dispatcher, client: Lavamusic, locale: requester: player.current.info.requester, }); return embed - .setAuthor({ name: T(locale, "player.setupStart.now_playing"), iconURL: iconUrl }) + .setAuthor({ + name: T(locale, "player.setupStart.now_playing"), + iconURL: iconUrl, + }) .setDescription(description) .setImage(icon) .setColor(client.color.main); @@ -31,7 +34,11 @@ async function setupStart(client: Lavamusic, query: string, player: Dispatcher, const data = await client.db.getSetup(message.guild.id); const locale = await client.db.getLanguage(message.guildId); try { - if (data) m = await message.channel.messages.fetch({ message: data.messageId, cache: true }); + if (data) + m = await message.channel.messages.fetch({ + message: data.messageId, + cache: true, + }); } catch (error) { client.logger.error(error); } @@ -59,11 +66,11 @@ async function setupStart(client: Lavamusic, query: string, player: Dispatcher, await message.channel .send({ embeds: [ - embed - .setColor(client.color.red) - .setDescription( - T(locale, "player.setupStart.queue_too_long", { maxQueueSize: client.config.maxQueueSize }), - ), + embed.setColor(client.color.red).setDescription( + T(locale, "player.setupStart.queue_too_long", { + maxQueueSize: client.config.maxQueueSize, + }), + ), ], }) .then((msg) => setTimeout(() => msg.delete(), 5000)); @@ -141,11 +148,11 @@ async function setupStart(client: Lavamusic, query: string, player: Dispatcher, await message.channel .send({ embeds: [ - embed - .setColor(client.color.red) - .setDescription( - T(locale, "player.setupStart.queue_too_long", { maxQueueSize: client.config.maxQueueSize }), - ), + embed.setColor(client.color.red).setDescription( + T(locale, "player.setupStart.queue_too_long", { + maxQueueSize: client.config.maxQueueSize, + }), + ), ], }) .then((msg) => setTimeout(() => msg.delete(), 5000)); @@ -204,7 +211,10 @@ async function trackStart( const embed = client .embed() - .setAuthor({ name: T(locale, "player.setupStart.now_playing"), iconURL: iconUrl }) + .setAuthor({ + name: T(locale, "player.setupStart.now_playing"), + iconURL: iconUrl, + }) .setColor(client.color.main) .setDescription(description) .setImage(icon); @@ -242,7 +252,10 @@ async function updateSetup(client: Lavamusic, guild: any, locale: string): Promi const textChannel = guild.channels.cache.get(setup.textId) as TextChannel; if (!textChannel) return; try { - m = await textChannel.messages.fetch({ message: setup.messageId, cache: true }); + m = await textChannel.messages.fetch({ + message: setup.messageId, + cache: true, + }); } catch (error) { client.logger.error(error); } @@ -261,7 +274,10 @@ async function updateSetup(client: Lavamusic, guild: any, locale: string): Promi const embed = client .embed() - .setAuthor({ name: T(locale, "player.setupStart.now_playing"), iconURL: iconUrl }) + .setAuthor({ + name: T(locale, "player.setupStart.now_playing"), + iconURL: iconUrl, + }) .setColor(client.color.main) .setDescription(description) .setImage(player.current.info.artworkUrl); diff --git a/src/utils/Utils.ts b/src/utils/Utils.ts index bcee891bb..67df5a200 100644 --- a/src/utils/Utils.ts +++ b/src/utils/Utils.ts @@ -17,7 +17,7 @@ export class Utils { public static updateStatus(client: Lavamusic, guildId?: string): void { const { user } = client; if (user && guildId === config.guildId) { - const player = client.queue.get(config.guildId); + const player = client.queue.get(config.guildId!); user.setPresence({ activities: [ { @@ -80,6 +80,7 @@ export class Utils { ctx.deferred ? ctx.interaction.followUp({ embeds: embed }) : ctx.interaction.reply({ embeds: embed }); return; } + (ctx.channel as TextChannel).send({ embeds: embed }); return; } @@ -117,14 +118,23 @@ export class Utils { const msgOptions = getButton(0); const msg = ctx.isInteraction ? await (ctx.deferred - ? ctx.interaction.followUp({ ...msgOptions, fetchReply: true as boolean }) - : ctx.interaction.reply({ ...msgOptions, fetchReply: true })) - : await (ctx.channel as TextChannel).send({ ...msgOptions, fetchReply: true }); + ? ctx.interaction!.followUp({ + ...msgOptions, + fetchReply: true as boolean, + }) + : ctx.interaction!.reply({ ...msgOptions, fetchReply: true })) + : await (ctx.channel as TextChannel).send({ + ...msgOptions, + fetchReply: true, + }); const author = ctx instanceof CommandInteraction ? ctx.user : ctx.author; const filter = (int: any): any => int.user.id === author.id; - const collector = msg.createMessageComponentCollector({ filter, time: 60000 }); + const collector = msg.createMessageComponentCollector({ + filter, + time: 60000, + }); collector.on("collect", async (interaction) => { if (interaction.user.id === author.id) { @@ -142,7 +152,10 @@ export class Utils { } await interaction.editReply(getButton(page)); } else { - await interaction.reply({ content: ctx.locale("buttons.errors.not_author"), ephemeral: true }); + await interaction.reply({ + content: ctx.locale("buttons.errors.not_author"), + ephemeral: true, + }); } }); diff --git a/tsconfig.json b/tsconfig.json index d90874eb4..67360f898 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -5,8 +5,8 @@ "lib": ["es2023"], "declaration": true, "sourceMap": true, - "outDir": "./dist", - "rootDir": "./src", + "outDir": "dist", + "rootDir": "src", "strict": false, "moduleResolution": "node", "esModuleInterop": true, @@ -15,6 +15,6 @@ "skipLibCheck": true, "forceConsistentCasingInFileNames": true }, - "include": ["src/**/*.ts"], - "exclude": ["dist", "node_modules"] + "include": ["src/"], + "exclude": ["dist/", "node_modules/"] }