diff --git a/Lavalink/example.application.yml b/Lavalink/example.application.yml index 2a189eae2..ef4f899c4 100644 --- a/Lavalink/example.application.yml +++ b/Lavalink/example.application.yml @@ -4,6 +4,8 @@ server: # REST and WS server http2: enabled: false # Whether to enable HTTP/2 support plugins: + jiosaavn: + apiURL: "https://saavn.dev/api" # The API URL for JioSaavn dunctebot: ttsLanguage: 'en-US' # language of the TTS engine sources: @@ -18,8 +20,6 @@ plugins: mixcloud: true # mixcloud.com soundgasm: true # soundgasm.net pixeldrain: true # pixeldrain.com - jiosaavn: - apiURL: "https://saavn.dev/api" # The API URL for JioSaavn lavasrc: providers: # Custom providers for track loading. This is the default # - "dzisrc:%ISRC%" # Deezer ISRC provider @@ -33,19 +33,22 @@ plugins: deezer: false # Enable Deezer source yandexmusic: false # Enable Yandex Music source flowerytts: false # Enable Flowery TTS source + vkmusic: false # Enable Vk Music source youtube: true # Enable YouTube search source (https://github.com/topi314/LavaSearch) lyrics-sources: spotify: false # Enable Spotify lyrics source deezer: false # Enable Deezer lyrics source youtube: false # Enable YouTube lyrics source yandexmusic: false # Enable Yandex Music lyrics source + vkmusic: false # Enable Vk Music lyrics source spotify: clientId: "your client id" clientSecret: "your client secret" - spDc: "your sp dc cookie" # the sp dc cookie used for accessing the spotify lyrics api + # spDc: "your sp dc cookie" # the sp dc cookie used for accessing the spotify lyrics api countryCode: "US" # the country code you want to use for filtering the artists top tracks. See https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2 playlistLoadLimit: 6 # The number of pages at 100 tracks each albumLoadLimit: 6 # The number of pages at 50 tracks each + resolveArtistsInSearch: true # Whether to resolve artists in track search results (can be slow) localFiles: false # Enable local files support with Spotify playlists. Please note `uri` & `isrc` will be `null` & `identifier` will be `"local"` applemusic: countryCode: "US" # the country code you want to use for filtering the artists top tracks and language. See https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2 @@ -61,6 +64,8 @@ plugins: albumLoadLimit: 6 # The number of pages at 300 tracks each deezer: masterDecryptionKey: "your master decryption key" # the master key used for decrypting the deezer tracks. (yes this is not here you need to get it from somewhere else) + # arl: "your deezer arl" # the arl cookie used for accessing the deezer api this is optional but required for formats above MP3_128 + formats: [ "FLAC", "MP3_320", "MP3_256", "MP3_128", "MP3_64", "AAC_64" ] # the formats you want to use for the deezer tracks. "FLAC", "MP3_320", "MP3_256" & "AAC_64" are only available for premium users and require a valid arl yandexmusic: accessToken: "your access token" # the token used for accessing the yandex music api. See https://github.com/TopiSenpai/LavaSrc#yandex-music playlistLoadLimit: 1 # The number of pages at 100 tracks each @@ -74,6 +79,11 @@ plugins: audioFormat: "mp3" # supported formats are: mp3, ogg_opus, ogg_vorbis, aac, wav, and flac. Default format is mp3 youtube: countryCode: "US" # the country code you want to use for searching lyrics via ISRC. See https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2 + vkmusic: + userToken: "your user token" # This token is needed for authorization in the api. Guide: https://github.com/topi314/LavaSrc#vk-music + playlistLoadLimit: 1 # The number of pages at 50 tracks each + artistLoadLimit: 1 # The number of pages at 10 tracks each + recommendationsLoadLimit: 10 # Number of tracks youtube: enabled: true # Whether this source can be used. allowSearch: true # Whether "ytsearch:" and "ytmsearch:" can be used. @@ -83,9 +93,9 @@ plugins: # Clients are queried in the order they are given (so the first client is queried first and so on...) clients: - MUSIC - - WEB - ANDROID_TESTSUITE - ANDROID_MUSIC + - WEB - TVHTML5EMBEDDED - ANDROID_LITE - MEDIA_CONNECT diff --git a/package.json b/package.json index 059f9c4f5..43ea986fd 100644 --- a/package.json +++ b/package.json @@ -36,15 +36,15 @@ "devDependencies": { "@biomejs/biome": "^1.8.3", "@types/i18n": "^0.13.12", - "@types/node": "^22.5.1", + "@types/node": "^22.5.3", "@types/signale": "^1.4.7", - "prisma": "^5.19.0", + "prisma": "^5.19.1", "typescript": "^5.5.4" }, "dependencies": { - "@prisma/client": "^5.19.0", + "@prisma/client": "^5.19.1", "@top-gg/sdk": "^3.1.6", - "discord.js": "^14.15.3", + "discord.js": "^14.16.1", "dotenv": "^16.4.5", "i18n": "^0.15.1", "node-system-stats": "^1.3.0", diff --git a/src/structures/Context.ts b/src/structures/Context.ts index 640427750..074eaa1ee 100644 --- a/src/structures/Context.ts +++ b/src/structures/Context.ts @@ -16,6 +16,7 @@ import { type PartialDMChannel, type TextChannel, type User, + ChannelType, } from "discord.js"; import { T } from "./I18n.js"; import type { Lavamusic } from "./index.js"; @@ -36,11 +37,18 @@ export default class Context { public args: any[]; public msg: any; public guildLocale: string; + constructor(ctx: ChatInputCommandInteraction | Message, args: any[]) { this.ctx = ctx; this.interaction = ctx instanceof ChatInputCommandInteraction ? ctx : null; this.message = ctx instanceof Message ? ctx : null; - this.channel = ctx.channel; + + if (ctx.channel && ctx.channel.type !== ChannelType.GroupDM) { + this.channel = ctx.channel + } else { + this.channel = null; + } + this.id = ctx.id; this.channelId = ctx.channelId; this.client = ctx.client as Lavamusic; @@ -53,6 +61,7 @@ export default class Context { this.setArgs(args); this.setUpLocale(); } + private async setUpLocale(): Promise { this.guildLocale = this.guild ? await this.client.db.getLanguage(this.guild.id) : "en"; } @@ -64,6 +73,7 @@ export default class Context { public setArgs(args: any[]): void { this.args = this.isInteraction ? args.map((arg: { value: any }) => arg.value) : args; } + public async sendMessage(content: string | MessagePayload | MessageCreateOptions | InteractionReplyOptions): Promise { if (this.isInteraction) { if (typeof content === "string" || isInteractionReplyOptions(content)) { @@ -98,9 +108,11 @@ export default class Context { this.msg = await (this.message.channel as TextChannel).send(content); return this.msg; } + public locale(key: string, ...args: any) { return T(this.guildLocale, key, ...args); } + public async sendFollowUp(content: string | MessagePayload | MessageCreateOptions | InteractionReplyOptions): Promise { if (this.isInteraction) { if (typeof content === "string" || isInteractionReplyOptions(content)) { diff --git a/src/utils/SetupSystem.ts b/src/utils/SetupSystem.ts index a25872dac..452d2d0d4 100644 --- a/src/utils/SetupSystem.ts +++ b/src/utils/SetupSystem.ts @@ -44,73 +44,107 @@ async function setupStart(client: Lavamusic, query: string, player: Dispatcher, } if (m) { try { - const res = await client.queue.search(query); - switch (res.loadType) { - case LoadType.ERROR: - await message.channel - .send({ - embeds: [embed.setColor(client.color.red).setDescription(T(locale, "player.setupStart.error_searching"))], - }) - .then((msg) => setTimeout(() => msg.delete(), 5000)); - break; - case LoadType.EMPTY: - await message.channel - .send({ - embeds: [embed.setColor(client.color.red).setDescription(T(locale, "player.setupStart.no_results"))], - }) - .then((msg) => setTimeout(() => msg.delete(), 5000)); - break; - case LoadType.TRACK: { - const track = player.buildTrack(res.data, message.author); - if (player.queue.length > client.config.maxQueueSize) { + if (message.inGuild()) { + const res = await client.queue.search(query); + switch (res.loadType) { + case LoadType.ERROR: + await message.channel + .send({ + embeds: [embed.setColor(client.color.red).setDescription(T(locale, "player.setupStart.error_searching"))], + }) + .then((msg) => setTimeout(() => msg.delete(), 5000)); + break; + case LoadType.EMPTY: + await message.channel + .send({ + embeds: [embed.setColor(client.color.red).setDescription(T(locale, "player.setupStart.no_results"))], + }) + .then((msg) => setTimeout(() => msg.delete(), 5000)); + break; + case LoadType.TRACK: { + const track = player.buildTrack(res.data, message.author); + if (player.queue.length > client.config.maxQueueSize) { + await message.channel + .send({ + embeds: [ + embed.setColor(client.color.red).setDescription( + T(locale, "player.setupStart.queue_too_long", { + maxQueueSize: client.config.maxQueueSize, + }), + ), + ], + }) + .then((msg) => setTimeout(() => msg.delete(), 5000)); + return; + } + player.queue.push(track); + await player.isPlaying(); 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.main).setDescription( + T(locale, "player.setupStart.added_to_queue", { + title: res.data.info.title, + uri: res.data.info.uri, }), ), ], }) .then((msg) => setTimeout(() => msg.delete(), 5000)); - return; + neb(n, player, client, locale); + await m.edit({ embeds: [n] }).catch(() => {}); + break; } - player.queue.push(track); - await player.isPlaying(); - await message.channel - .send({ - embeds: [ - embed.setColor(client.color.main).setDescription( - T(locale, "player.setupStart.added_to_queue", { - title: res.data.info.title, - uri: res.data.info.uri, - }), - ), - ], - }) - .then((msg) => setTimeout(() => msg.delete(), 5000)); - neb(n, player, client, locale); - await m.edit({ embeds: [n] }).catch(() => {}); - break; - } - case LoadType.PLAYLIST: - if (res.data.tracks.length > client.config.maxPlaylistSize) { + case LoadType.PLAYLIST: + if (res.data.tracks.length > client.config.maxPlaylistSize) { + await message.channel + .send({ + embeds: [ + embed.setColor(client.color.red).setDescription( + T(locale, "player.setupStart.playlist_too_long", { + maxPlaylistSize: client.config.maxPlaylistSize, + }), + ), + ], + }) + .then((msg) => setTimeout(() => msg.delete(), 5000)); + return; + } + for (const track of res.data.tracks) { + const pl = player.buildTrack(track, message.author); + if (player.queue.length > client.config.maxQueueSize) { + await message.channel + .send({ + embeds: [ + embed.setColor(client.color.red).setDescription( + T(locale, "player.setupStart.queue_too_long", { + maxQueueSize: client.config.maxQueueSize, + }), + ), + ], + }) + .then((msg) => setTimeout(() => msg.delete(), 5000)); + return; + } + player.queue.push(pl); + } + await player.isPlaying(); await message.channel .send({ embeds: [ - embed.setColor(client.color.red).setDescription( - T(locale, "player.setupStart.playlist_too_long", { - maxPlaylistSize: client.config.maxPlaylistSize, - }), - ), + embed + .setColor(client.color.main) + .setDescription( + T(locale, "player.setupStart.added_playlist_to_queue", { length: res.data.tracks.length }), + ), ], }) .then((msg) => setTimeout(() => msg.delete(), 5000)); - return; - } - for (const track of res.data.tracks) { - const pl = player.buildTrack(track, message.author); + neb(n, player, client, locale); + await m.edit({ embeds: [n] }).catch(() => {}); + break; + case LoadType.SEARCH: { + const track = player.buildTrack(res.data[0], message.author); if (player.queue.length > client.config.maxQueueSize) { await message.channel .send({ @@ -125,56 +159,24 @@ async function setupStart(client: Lavamusic, query: string, player: Dispatcher, .then((msg) => setTimeout(() => msg.delete(), 5000)); return; } - player.queue.push(pl); - } - await player.isPlaying(); - await message.channel - .send({ - embeds: [ - embed - .setColor(client.color.main) - .setDescription( - T(locale, "player.setupStart.added_playlist_to_queue", { length: res.data.tracks.length }), - ), - ], - }) - .then((msg) => setTimeout(() => msg.delete(), 5000)); - neb(n, player, client, locale); - await m.edit({ embeds: [n] }).catch(() => {}); - break; - case LoadType.SEARCH: { - const track = player.buildTrack(res.data[0], message.author); - if (player.queue.length > client.config.maxQueueSize) { + player.queue.push(track); + await player.isPlaying(); 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.main).setDescription( + T(locale, "player.setupStart.added_to_queue", { + title: res.data[0].info.title, + uri: res.data[0].info.uri, }), ), ], }) .then((msg) => setTimeout(() => msg.delete(), 5000)); - return; + neb(n, player, client, locale); + await m.edit({ embeds: [n] }).catch(() => {}); + break; } - player.queue.push(track); - await player.isPlaying(); - await message.channel - .send({ - embeds: [ - embed.setColor(client.color.main).setDescription( - T(locale, "player.setupStart.added_to_queue", { - title: res.data[0].info.title, - uri: res.data[0].info.uri, - }), - ), - ], - }) - .then((msg) => setTimeout(() => msg.delete(), 5000)); - neb(n, player, client, locale); - await m.edit({ embeds: [n] }).catch(() => {}); - break; } } } catch (error) {