From e86c2eff74b540c6d84498e5eb458b891bac648f Mon Sep 17 00:00:00 2001 From: JustEvil <71156616+EvilG-MC@users.noreply.github.com> Date: Thu, 26 Dec 2024 11:04:12 -0600 Subject: [PATCH 1/3] refactor: moved middlewares into separated files, and more stuff. --- pnpm-lock.yaml | 8 +- seyfert.config.js | 6 +- src/commands/music/autoplay.ts | 8 +- src/commands/music/loop.ts | 5 +- src/commands/music/move.ts | 9 +- src/commands/music/nowplaying.ts | 5 +- src/commands/music/play.ts | 4 +- src/commands/music/queue.ts | 21 ++-- src/commands/music/seek.ts | 5 +- src/commands/music/shuffle.ts | 8 +- src/commands/music/skip.ts | 8 +- src/commands/music/stop.ts | 5 +- src/commands/music/volume.ts | 5 +- src/components/autoplay.ts | 6 +- src/components/loop.ts | 5 +- src/components/pause.ts | 5 +- src/components/previous.ts | 5 +- src/components/queue.ts | 16 +-- src/components/skip.ts | 5 +- src/components/stop.ts | 5 +- src/lavalink/player/destroy.ts | 6 +- src/locales/en-US.ts | 6 +- src/locales/es-419.ts | 4 + src/middlewares/commands/manager.ts | 113 ++++++++++++++++++ src/middlewares/commands/verifications.ts | 93 +------------- src/middlewares/commands/voice.ts | 102 ++++++++++++++++ src/middlewares/index.ts | 17 +++ src/structures/client/Stelle.ts | 1 - src/structures/utils/data/Configuration.ts | 4 + src/structures/utils/functions/autoplay.ts | 67 +++++++---- .../utils/types/client/StelleConfiguration.ts | 16 +++ src/structures/utils/types/index.ts | 36 ------ 32 files changed, 374 insertions(+), 235 deletions(-) create mode 100644 src/middlewares/commands/manager.ts create mode 100644 src/middlewares/commands/voice.ts diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4594d25..923c1a7 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -19,7 +19,7 @@ importers: version: 2.2.3 seyfert: specifier: github:tiramisulabs/seyfert - version: https://codeload.github.com/tiramisulabs/seyfert/tar.gz/85f77f963d0309315c9548422ecbaa08fa5dd705 + version: https://codeload.github.com/tiramisulabs/seyfert/tar.gz/62aa27bb837253687e03422ff2a9914b769f6ab8 yunaforseyfert: specifier: ^1.1.0 version: 1.1.0 @@ -473,8 +473,8 @@ packages: rfdc@1.4.1: resolution: {integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==} - seyfert@https://codeload.github.com/tiramisulabs/seyfert/tar.gz/85f77f963d0309315c9548422ecbaa08fa5dd705: - resolution: {tarball: https://codeload.github.com/tiramisulabs/seyfert/tar.gz/85f77f963d0309315c9548422ecbaa08fa5dd705} + seyfert@https://codeload.github.com/tiramisulabs/seyfert/tar.gz/62aa27bb837253687e03422ff2a9914b769f6ab8: + resolution: {tarball: https://codeload.github.com/tiramisulabs/seyfert/tar.gz/62aa27bb837253687e03422ff2a9914b769f6ab8} version: 2.1.0 shebang-command@2.0.0: @@ -905,7 +905,7 @@ snapshots: rfdc@1.4.1: {} - seyfert@https://codeload.github.com/tiramisulabs/seyfert/tar.gz/85f77f963d0309315c9548422ecbaa08fa5dd705: {} + seyfert@https://codeload.github.com/tiramisulabs/seyfert/tar.gz/62aa27bb837253687e03422ff2a9914b769f6ab8: {} shebang-command@2.0.0: dependencies: diff --git a/seyfert.config.js b/seyfert.config.js index e9846f4..65b6992 100644 --- a/seyfert.config.js +++ b/seyfert.config.js @@ -5,7 +5,7 @@ import { config } from "seyfert"; import { DEV_MODE, DEBUG_MODE } from "#stelle/data/Constants.js"; -const output = DEV_MODE ? "src" : "dist"; +const base = DEV_MODE ? "src" : "dist"; export default config.bot({ token: process.env.TOKEN ?? "Trailblazer", @@ -22,8 +22,8 @@ export default config.bot({ * @type {import("seyfert").RuntimeConfig["locations"] & { lavalink: string }} */ locations: { - output, - base: "src", + base, + output: base, lavalink: "lavalink", commands: "commands", components: "components", diff --git a/src/commands/music/autoplay.ts b/src/commands/music/autoplay.ts index ac8f574..94c4d19 100644 --- a/src/commands/music/autoplay.ts +++ b/src/commands/music/autoplay.ts @@ -1,4 +1,4 @@ -import { Command, type CommandContext, Declare, LocalesT } from "seyfert"; +import { Command, type CommandContext, Declare, LocalesT, Middlewares } from "seyfert"; import { StelleOptions } from "#stelle/decorators"; import { StelleCategory } from "#stelle/types"; @@ -14,13 +14,9 @@ import { getAutoplayState } from "#stelle/utils/functions/utils.js"; @StelleOptions({ cooldown: 5, category: StelleCategory.Music, - checkPlayer: true, - inVoice: true, - sameVoice: true, - moreTracks: true, - checkNodes: true, }) @LocalesT("locales.autoplay.name", "locales.autoplay.description") +@Middlewares(["checkNodes", "checkVoiceChannel", "checkBotVoiceChannel", "checkPlayer", "checkTracks"]) export default class AutoplayCommand extends Command { public override async run(ctx: CommandContext) { const { client, guildId } = ctx; diff --git a/src/commands/music/loop.ts b/src/commands/music/loop.ts index 1e8e606..f8aee23 100644 --- a/src/commands/music/loop.ts +++ b/src/commands/music/loop.ts @@ -1,4 +1,4 @@ -import { Command, type CommandContext, Declare, LocalesT, Options, createStringOption } from "seyfert"; +import { Command, type CommandContext, Declare, LocalesT, Middlewares, Options, createStringOption } from "seyfert"; import { StelleOptions } from "#stelle/decorators"; import type { RepeatMode } from "lavalink-client"; @@ -38,9 +38,10 @@ const options = { contexts: ["Guild"], aliases: ["l"], }) -@StelleOptions({ cooldown: 5, category: StelleCategory.Music, checkPlayer: true, inVoice: true, sameVoice: true, checkNodes: true }) +@StelleOptions({ cooldown: 5, category: StelleCategory.Music }) @Options(options) @LocalesT("locales.loop.name", "locales.loop.description") +@Middlewares(["checkNodes", "checkVoiceChannel", "checkBotVoiceChannel", "checkPlayer"]) export default class LoopCommand extends Command { public override async run(ctx: CommandContext) { const { client, options, guildId } = ctx; diff --git a/src/commands/music/move.ts b/src/commands/music/move.ts index e548472..b2218a5 100644 --- a/src/commands/music/move.ts +++ b/src/commands/music/move.ts @@ -1,4 +1,4 @@ -import { Command, type CommandContext, Declare, LocalesT, Options, createChannelOption } from "seyfert"; +import { Command, type CommandContext, Declare, LocalesT, Middlewares, Options, createChannelOption } from "seyfert"; import { StelleOptions } from "#stelle/decorators"; import { StelleCategory } from "#stelle/types"; @@ -31,9 +31,10 @@ const options = { contexts: ["Guild"], aliases: ["mov", "m"], }) -@StelleOptions({ cooldown: 5, category: StelleCategory.Music, checkPlayer: true, inVoice: true, checkNodes: true }) +@StelleOptions({ cooldown: 5, category: StelleCategory.Music }) @Options(options) @LocalesT("locales.move.name", "locales.move.description") +@Middlewares(["checkNodes", "checkVoiceChannel", "checkPlayer"]) export default class MoveCommand extends Command { public override async run(ctx: CommandContext) { const { client, options, guildId } = ctx; @@ -54,6 +55,8 @@ export default class MoveCommand extends Command { player.options.voiceChannelId = voice.id; player.voiceChannelId = voice.id; + const channel = await ctx.channel(); + await player.connect(); await ctx.editOrReply({ embeds: [ @@ -61,7 +64,7 @@ export default class MoveCommand extends Command { color: client.config.color.success, description: messages.commands.move({ voiceId: voice.id, - textId: text?.id ?? ctx.channel()?.id ?? "1143606303850483280", + textId: text?.id ?? channel?.id ?? "1143606303850483280", }), }, ], diff --git a/src/commands/music/nowplaying.ts b/src/commands/music/nowplaying.ts index 7f5afaf..e7d5efd 100644 --- a/src/commands/music/nowplaying.ts +++ b/src/commands/music/nowplaying.ts @@ -1,4 +1,4 @@ -import { Command, type CommandContext, Declare, LocalesT, type User } from "seyfert"; +import { Command, type CommandContext, Declare, LocalesT, Middlewares, type User } from "seyfert"; import { StelleOptions } from "#stelle/decorators"; import { StelleCategory } from "#stelle/types"; @@ -13,8 +13,9 @@ import { createBar } from "#stelle/utils/functions/utils.js"; contexts: ["Guild"], aliases: ["np"], }) -@StelleOptions({ cooldown: 5, category: StelleCategory.Music, checkNodes: true, checkPlayer: true }) +@StelleOptions({ cooldown: 5, category: StelleCategory.Music }) @LocalesT("locales.nowplaying.name", "locales.nowplaying.description") +@Middlewares(["checkNodes", "checkPlayer"]) export default class NowPlayingCommand extends Command { public override async run(ctx: CommandContext) { const { client, guildId } = ctx; diff --git a/src/commands/music/play.ts b/src/commands/music/play.ts index 579e171..af35864 100644 --- a/src/commands/music/play.ts +++ b/src/commands/music/play.ts @@ -5,6 +5,7 @@ import { Embed, LocalesT, type Message, + Middlewares, Options, type User, type WebhookMessage, @@ -73,9 +74,10 @@ const options = { integrationTypes: ["GuildInstall"], contexts: ["Guild"], }) -@StelleOptions({ cooldown: 5, category: StelleCategory.Music, inVoice: true, sameVoice: true, checkNodes: true }) +@StelleOptions({ cooldown: 5, category: StelleCategory.Music }) @Options(options) @LocalesT("locales.play.name", "locales.play.description") +@Middlewares(["checkNodes", "checkVoiceChannel", "checkVoicePermissions", "checkBotVoiceChannel"]) export default class PlayCommand extends Command { public override async run(ctx: CommandContext): Promise { const { options, client, guildId, channelId, member } = ctx; diff --git a/src/commands/music/queue.ts b/src/commands/music/queue.ts index 1380d69..f5d336f 100644 --- a/src/commands/music/queue.ts +++ b/src/commands/music/queue.ts @@ -1,4 +1,4 @@ -import { Command, type CommandContext, Declare, Embed, LocalesT, type User } from "seyfert"; +import { Command, type CommandContext, Declare, Embed, LocalesT, Middlewares, type User } from "seyfert"; import { StelleOptions } from "#stelle/decorators"; import { StelleCategory } from "#stelle/types"; @@ -13,22 +13,19 @@ import { EmbedPaginator } from "#stelle/utils/Paginator.js"; @StelleOptions({ cooldown: 5, category: StelleCategory.Music, - checkPlayer: true, - inVoice: true, - sameVoice: true, - checkNodes: true, - checkQueue: true, }) @LocalesT("locales.queue.name", "locales.queue.description") +@Middlewares(["checkNodes", "checkVoiceChannel", "checkBotVoiceChannel", "checkPlayer", "checkQueue"]) export default class QueueCommand extends Command { public override async run(ctx: CommandContext) { - const { client, guildId, author } = ctx; - - if (!guildId) return; + const { client, author } = ctx; const { messages } = await ctx.getLocale(); - const player = client.manager.getPlayer(guildId); + const guild = await ctx.guild(); + if (!guild) return; + + const player = client.manager.getPlayer(guild.id); if (!player) return; const tracksPerPage = 20; @@ -42,7 +39,7 @@ export default class QueueCommand extends Command { new Embed() .setDescription(messages.events.playerQueue({ tracks: tracks.slice(0, tracksPerPage).join("\n") })) .setColor(client.config.color.extra) - .setThumbnail(ctx.guild()!.iconURL()) + .setThumbnail(guild.iconURL()) .setTimestamp() .setAuthor({ name: author.tag, iconUrl: author.avatarURL() }), ], @@ -55,7 +52,7 @@ export default class QueueCommand extends Command { new Embed() .setDescription(messages.events.playerQueue({ tracks: tracks.slice(i, i + tracksPerPage).join("\n") })) .setColor(client.config.color.extra) - .setThumbnail(ctx.guild()!.iconURL()) + .setThumbnail(guild.iconURL()) .setTimestamp() .setAuthor({ name: author.tag, iconUrl: author.avatarURL() }), ); diff --git a/src/commands/music/seek.ts b/src/commands/music/seek.ts index 6694786..ea4b7a2 100644 --- a/src/commands/music/seek.ts +++ b/src/commands/music/seek.ts @@ -1,4 +1,4 @@ -import { Command, type CommandContext, Declare, LocalesT, type OKFunction, Options, createStringOption } from "seyfert"; +import { Command, type CommandContext, Declare, LocalesT, Middlewares, type OKFunction, Options, createStringOption } from "seyfert"; import { StelleOptions } from "#stelle/decorators"; import { EmbedColors } from "seyfert/lib/common/index.js"; @@ -33,9 +33,10 @@ const options = { contexts: ["Guild"], aliases: ["sk"], }) -@StelleOptions({ cooldown: 5, category: StelleCategory.Music, checkPlayer: true, inVoice: true, sameVoice: true, checkNodes: true }) +@StelleOptions({ cooldown: 5, category: StelleCategory.Music }) @Options(options) @LocalesT("locales.seek.name", "locales.seek.description") +@Middlewares(["checkNodes", "checkVoiceChannel", "checkBotVoiceChannel", "checkPlayer"]) export default class SeekCommand extends Command { public override async run(ctx: CommandContext) { const { client, options, guildId } = ctx; diff --git a/src/commands/music/shuffle.ts b/src/commands/music/shuffle.ts index a9920ed..349ce66 100644 --- a/src/commands/music/shuffle.ts +++ b/src/commands/music/shuffle.ts @@ -1,4 +1,4 @@ -import { Command, type CommandContext, Declare } from "seyfert"; +import { Command, type CommandContext, Declare, Middlewares } from "seyfert"; import { StelleOptions } from "#stelle/decorators"; import { StelleCategory } from "#stelle/types"; @@ -12,12 +12,8 @@ import { StelleCategory } from "#stelle/types"; @StelleOptions({ cooldown: 5, category: StelleCategory.Music, - checkNodes: true, - checkPlayer: true, - checkQueue: true, - inVoice: true, - sameVoice: true, }) +@Middlewares(["checkNodes", "checkVoiceChannel", "checkBotVoiceChannel", "checkPlayer", "checkQueue"]) export default class ShuffleCommand extends Command { public override async run(ctx: CommandContext) { const { client } = ctx; diff --git a/src/commands/music/skip.ts b/src/commands/music/skip.ts index 84749d8..cc95563 100644 --- a/src/commands/music/skip.ts +++ b/src/commands/music/skip.ts @@ -1,4 +1,4 @@ -import { Command, type CommandContext, Declare, LocalesT, Options, createIntegerOption } from "seyfert"; +import { Command, type CommandContext, Declare, LocalesT, Middlewares, Options, createIntegerOption } from "seyfert"; import { StelleOptions } from "#stelle/decorators"; import { StelleCategory } from "#stelle/types"; @@ -22,14 +22,10 @@ const options = { @StelleOptions({ cooldown: 5, category: StelleCategory.Music, - checkPlayer: true, - inVoice: true, - sameVoice: true, - checkNodes: true, - checkQueue: true, }) @Options(options) @LocalesT("locales.skip.name", "locales.skip.description") +@Middlewares(["checkNodes", "checkVoiceChannel", "checkBotVoiceChannel", "checkPlayer", "checkQueue"]) export default class SkipCommand extends Command { public override async run(ctx: CommandContext) { const { client, options, guildId } = ctx; diff --git a/src/commands/music/stop.ts b/src/commands/music/stop.ts index d2b11e0..7476137 100644 --- a/src/commands/music/stop.ts +++ b/src/commands/music/stop.ts @@ -1,4 +1,4 @@ -import { Command, type CommandContext, Declare, LocalesT } from "seyfert"; +import { Command, type CommandContext, Declare, LocalesT, Middlewares } from "seyfert"; import { StelleOptions } from "#stelle/decorators"; import { StelleCategory } from "#stelle/types"; @@ -9,8 +9,9 @@ import { StelleCategory } from "#stelle/types"; contexts: ["Guild"], aliases: ["sp"], }) -@StelleOptions({ cooldown: 5, category: StelleCategory.Music, checkPlayer: true, inVoice: true, sameVoice: true, checkNodes: true }) +@StelleOptions({ cooldown: 5, category: StelleCategory.Music }) @LocalesT("locales.stop.name", "locales.stop.description") +@Middlewares(["checkNodes", "checkVoiceChannel", "checkBotVoiceChannel", "checkPlayer"]) export default class StopCommand extends Command { public override async run(ctx: CommandContext) { const { client, guildId } = ctx; diff --git a/src/commands/music/volume.ts b/src/commands/music/volume.ts index c093ed3..b95d073 100644 --- a/src/commands/music/volume.ts +++ b/src/commands/music/volume.ts @@ -1,4 +1,4 @@ -import { Command, type CommandContext, Declare, LocalesT, Options, createIntegerOption } from "seyfert"; +import { Command, type CommandContext, Declare, LocalesT, Middlewares, Options, createIntegerOption } from "seyfert"; import { StelleOptions } from "#stelle/decorators"; import { StelleCategory } from "#stelle/types"; @@ -22,9 +22,10 @@ const options = { contexts: ["Guild"], aliases: ["v", "vol"], }) -@StelleOptions({ cooldown: 5, category: StelleCategory.Music, checkPlayer: true, inVoice: true, sameVoice: true, checkNodes: true }) +@StelleOptions({ cooldown: 5, category: StelleCategory.Music }) @Options(options) @LocalesT("locales.volume.name", "locales.volume.description") +@Middlewares(["checkNodes", "checkVoiceChannel", "checkBotVoiceChannel", "checkPlayer"]) export default class VolumeCommand extends Command { public override async run(ctx: CommandContext) { const { client, options, guildId } = ctx; diff --git a/src/components/autoplay.ts b/src/components/autoplay.ts index f1efe45..0e8b082 100644 --- a/src/components/autoplay.ts +++ b/src/components/autoplay.ts @@ -1,11 +1,9 @@ -import { ActionRow, Button, ComponentCommand, type ComponentContext } from "seyfert"; -import { StelleOptions } from "#stelle/decorators"; - +import { ActionRow, Button, ComponentCommand, type ComponentContext, Middlewares } from "seyfert"; import { type APIButtonComponentWithCustomId, ButtonStyle, ComponentType } from "seyfert/lib/types/index.js"; import { getAutoplayState } from "#stelle/utils/functions/utils.js"; -@StelleOptions({ inVoice: true, sameVoice: true, checkPlayer: true, moreTracks: true, checkNodes: true }) +@Middlewares(["checkNodes", "checkVoiceChannel", "checkBotVoiceChannel", "checkPlayer", "checkTracks"]) export default class AutoplayComponent extends ComponentCommand { componentType = "Button" as const; diff --git a/src/components/loop.ts b/src/components/loop.ts index eca0294..24a020d 100644 --- a/src/components/loop.ts +++ b/src/components/loop.ts @@ -1,10 +1,9 @@ -import { ActionRow, Button, ComponentCommand, type ComponentContext } from "seyfert"; -import { StelleOptions } from "#stelle/decorators"; +import { ActionRow, Button, ComponentCommand, type ComponentContext, Middlewares } from "seyfert"; import { type APIButtonComponentWithCustomId, ButtonStyle, ComponentType } from "seyfert/lib/types/index.js"; import { getLoopState } from "#stelle/utils/functions/utils.js"; -@StelleOptions({ inVoice: true, sameVoice: true, checkPlayer: true, checkNodes: true }) +@Middlewares(["checkNodes", "checkVoiceChannel", "checkBotVoiceChannel", "checkPlayer"]) export default class ToggleLoopComponent extends ComponentCommand { componentType = "Button" as const; diff --git a/src/components/pause.ts b/src/components/pause.ts index 82d9e18..256dd9c 100644 --- a/src/components/pause.ts +++ b/src/components/pause.ts @@ -1,10 +1,9 @@ -import { ActionRow, Button, ComponentCommand, type ComponentContext } from "seyfert"; -import { StelleOptions } from "#stelle/decorators"; +import { ActionRow, Button, ComponentCommand, type ComponentContext, Middlewares } from "seyfert"; import { type APIButtonComponentWithCustomId, ButtonStyle, ComponentType } from "seyfert/lib/types/index.js"; import { getPauseState } from "#stelle/utils/functions/utils.js"; -@StelleOptions({ inVoice: true, sameVoice: true, checkPlayer: true, checkNodes: true }) +@Middlewares(["checkNodes", "checkVoiceChannel", "checkBotVoiceChannel", "checkPlayer"]) export default class PauseTrackComponent extends ComponentCommand { componentType = "Button" as const; diff --git a/src/components/previous.ts b/src/components/previous.ts index babc037..e6b6688 100644 --- a/src/components/previous.ts +++ b/src/components/previous.ts @@ -1,10 +1,9 @@ -import { ComponentCommand, type ComponentContext } from "seyfert"; -import { StelleOptions } from "#stelle/decorators"; +import { ComponentCommand, type ComponentContext, Middlewares } from "seyfert"; import { EmbedColors } from "seyfert/lib/common/index.js"; import { MessageFlags } from "seyfert/lib/types/index.js"; -@StelleOptions({ inVoice: true, sameVoice: true, checkPlayer: true, checkNodes: true }) +@Middlewares(["checkNodes", "checkVoiceChannel", "checkBotVoiceChannel", "checkPlayer"]) export default class PreviousTrackComponent extends ComponentCommand { componentType = "Button" as const; diff --git a/src/components/queue.ts b/src/components/queue.ts index 613c1a6..8c4a60d 100644 --- a/src/components/queue.ts +++ b/src/components/queue.ts @@ -1,9 +1,8 @@ -import { ComponentCommand, type ComponentContext, Embed, type User } from "seyfert"; +import { ComponentCommand, type ComponentContext, Embed, Middlewares, type User } from "seyfert"; import { MessageFlags } from "seyfert/lib/types/index.js"; -import { StelleOptions } from "#stelle/decorators"; import { EmbedPaginator } from "#stelle/utils/Paginator.js"; -@StelleOptions({ inVoice: true, sameVoice: true, checkPlayer: true, checkQueue: true, checkNodes: true }) +@Middlewares(["checkNodes", "checkVoiceChannel", "checkBotVoiceChannel", "checkPlayer", "checkQueue"]) export default class QueueComponent extends ComponentCommand { componentType = "Button" as const; @@ -12,13 +11,14 @@ export default class QueueComponent extends ComponentCommand { } async run(ctx: ComponentContext): Promise { - const { client, guildId, author } = ctx; + const { client, author } = ctx; - if (!guildId) return; + const guild = await ctx.guild(); + if (!guild) return; const { messages } = await ctx.getLocale(); - const player = client.manager.getPlayer(guildId); + const player = client.manager.getPlayer(guild.id); if (!player) return; const tracksPerPage = 20; @@ -33,7 +33,7 @@ export default class QueueComponent extends ComponentCommand { new Embed() .setDescription(messages.events.playerQueue({ tracks: tracks.slice(0, tracksPerPage).join("\n") })) .setColor(client.config.color.extra) - .setThumbnail(ctx.guild()!.iconURL()) + .setThumbnail(guild.iconURL()) .setTimestamp() .setAuthor({ name: author.tag, iconUrl: author.avatarURL() }), ], @@ -46,7 +46,7 @@ export default class QueueComponent extends ComponentCommand { new Embed() .setDescription(messages.events.playerQueue({ tracks: tracks.slice(i, i + tracksPerPage).join("\n") })) .setColor(client.config.color.extra) - .setThumbnail(ctx.guild()!.iconURL()) + .setThumbnail(guild.iconURL()) .setTimestamp() .setAuthor({ name: author.tag, iconUrl: author.avatarURL() }), ); diff --git a/src/components/skip.ts b/src/components/skip.ts index 743a527..81f0bd0 100644 --- a/src/components/skip.ts +++ b/src/components/skip.ts @@ -1,7 +1,6 @@ -import { ComponentCommand, type ComponentContext } from "seyfert"; -import { StelleOptions } from "#stelle/decorators"; +import { ComponentCommand, type ComponentContext, Middlewares } from "seyfert"; -@StelleOptions({ inVoice: true, sameVoice: true, checkPlayer: true, checkQueue: true, checkNodes: true }) +@Middlewares(["checkNodes", "checkVoiceChannel", "checkBotVoiceChannel", "checkPlayer", "checkQueue"]) export default class SkipTrackComponent extends ComponentCommand { componentType = "Button" as const; diff --git a/src/components/stop.ts b/src/components/stop.ts index 7dca7b9..5d0e217 100644 --- a/src/components/stop.ts +++ b/src/components/stop.ts @@ -1,7 +1,6 @@ -import { ComponentCommand, type ComponentContext } from "seyfert"; -import { StelleOptions } from "#stelle/decorators"; +import { ComponentCommand, type ComponentContext, Middlewares } from "seyfert"; -@StelleOptions({ inVoice: true, sameVoice: true, checkPlayer: true, checkNodes: true }) +@Middlewares(["checkNodes", "checkVoiceChannel", "checkBotVoiceChannel", "checkPlayer"]) export default class StopComponent extends ComponentCommand { componentType = "Button" as const; diff --git a/src/lavalink/player/destroy.ts b/src/lavalink/player/destroy.ts index ef78962..1618920 100644 --- a/src/lavalink/player/destroy.ts +++ b/src/lavalink/player/destroy.ts @@ -7,10 +7,8 @@ export default new Lavalink({ run: async (client, player) => { sessions.delete(player.guildId); - if (player.voiceChannelId) { - const voice = await client.channels.fetch(player.voiceChannelId); - if (voice.is(["GuildVoice"])) await voice.setVoiceStatus(null).catch(() => null); - } + const voice = await client.channels.fetch(player.voiceChannelId ?? player.options.voiceChannelId); + if (voice.is(["GuildVoice"])) await voice.setVoiceStatus(null).catch(() => null); return DEBUG_MODE && client.logger.debug(`[Lavalink PlayerDestroy] Destroyed player for guild ${player.guildId}`); }, diff --git a/src/locales/en-US.ts b/src/locales/en-US.ts index 4da267c..3fe2838 100644 --- a/src/locales/en-US.ts +++ b/src/locales/en-US.ts @@ -118,7 +118,7 @@ export default { noSameVoice: ({ channelId }: IChannel) => `\`โŒ\` You are not in the **same voice channel** as me. (<#${channelId}>)`, noCollector: ({ userId }: IUser) => `\`โŒ\` Only the user: <@${userId}> can use this.`, invalidOptions: ({ options, list }: IOptions) => - `\`โŒ\` Invalid command options or arguments.\n- **Required**: \`<>\`\n- **Optional**: \`[]\`\n\n\`๐Ÿ“‹\` **Usage**:\n ${options}\n\`๐Ÿ“ข\` **Options Available**:\n${list}`, + `\`โŒ\` Invalid command options or arguments.\n-# - **Required**: \`<>\`\n-# - **Optional**: \`[]\`\n\n\`๐Ÿ“‹\` **Usage**:\n ${options}\n\`๐Ÿ“ข\` **Options Available**:\n${list}`, playerQueue: ({ tracks }: ITracks) => `\`๐Ÿ“‹\` Here is the full server queue: \n\n${tracks}`, channelEmpty: ({ type }: IType) => `\`๐ŸŽง\` Stelle is alone in the **voice channel**... Pausing and waiting **${type}**.`, mention: ({ clientName, defaultPrefix, commandName }: IMention) => @@ -228,6 +228,10 @@ export default { }, bot: { description: "`๐Ÿ“ข` Hey! I'm missing some permissions to do this.", + field: "`๐Ÿ“‹` Permissions", + }, + channel: { + description: ({ channelId }: IChannel) => `\`๐Ÿ“ข\` Hey! I'm missing some permissions in the channel. <#${channelId}>`, field: "`๐Ÿ“‹` Missing Permissions", }, }, diff --git a/src/locales/es-419.ts b/src/locales/es-419.ts index 3f4b453..864f08e 100644 --- a/src/locales/es-419.ts +++ b/src/locales/es-419.ts @@ -231,6 +231,10 @@ export default { description: "`๐Ÿ“ข` ยกOye! Me faltan algunos permisos para hacer esto.", field: "`๐Ÿ“‹` Permisos Faltantes", }, + channel: { + description: ({ channelId }) => `\`๐Ÿ“ข\` ยกOye! Me faltan algunos permisos en el canal: <#${channelId}>`, + field: "`๐Ÿ“‹` Permisos Faltantes", + }, }, }, }, diff --git a/src/middlewares/commands/manager.ts b/src/middlewares/commands/manager.ts new file mode 100644 index 0000000..507e49d --- /dev/null +++ b/src/middlewares/commands/manager.ts @@ -0,0 +1,113 @@ +import { createMiddleware } from "seyfert"; +import { EmbedColors } from "seyfert/lib/common/index.js"; +import { MessageFlags } from "seyfert/lib/types/index.js"; + +/** + * Check if the bot is connected to any lavalink node. + */ +export const checkNodes = createMiddleware(async ({ context, pass, next }) => { + const { messages } = await context.getLocale(); + const { client } = context; + + if (!client.manager.useable) { + await context.editOrReply({ + flags: MessageFlags.Ephemeral, + embeds: [ + { + description: messages.events.noNodes, + color: EmbedColors.Red, + }, + ], + }); + + return pass(); + } + + return next(); +}); + +/** + * Check if the player exists. + */ +export const checkPlayer = createMiddleware(async ({ context, pass, next }) => { + const { client } = context; + const { messages } = await context.getLocale(); + + if (!context.guildId) return pass(); + + const player = client.manager.getPlayer(context.guildId); + if (!player) { + await context.editOrReply({ + flags: MessageFlags.Ephemeral, + embeds: [ + { + description: messages.events.noPlayer, + color: EmbedColors.Red, + }, + ], + }); + + return pass(); + } + + return next(); +}); + +/** + * Check if the queue has tracks. + */ +export const checkQueue = createMiddleware(async ({ context, pass, next }) => { + const { client } = context; + const { messages } = await context.getLocale(); + + if (!context.guildId) return pass(); + + const player = client.manager.getPlayer(context.guildId); + if (!player) return pass(); + + const isAutoplay = !!player.get("enabledAutoplay"); + if (!(isAutoplay || player!.queue.tracks.length)) { + await context.editOrReply({ + flags: MessageFlags.Ephemeral, + embeds: [ + { + description: messages.events.noTracks, + color: EmbedColors.Red, + }, + ], + }); + + return pass(); + } + + return next(); +}); + +/** + * Check if the queue has more than one track. + */ +export const checkTracks = createMiddleware(async ({ context, pass, next }) => { + const { client } = context; + const { messages } = await context.getLocale(); + + if (!context.guildId) return pass(); + + const player = client.manager.getPlayer(context.guildId); + if (!player) return pass(); + + if (!(player.queue.tracks.length + Number(!!player.queue.current) >= 1)) { + await context.editOrReply({ + flags: MessageFlags.Ephemeral, + embeds: [ + { + description: messages.events.moreTracks, + color: EmbedColors.Red, + }, + ], + }); + + return pass(); + } + + return next(); +}); diff --git a/src/middlewares/commands/verifications.ts b/src/middlewares/commands/verifications.ts index 159acd9..6aae6d1 100644 --- a/src/middlewares/commands/verifications.ts +++ b/src/middlewares/commands/verifications.ts @@ -7,17 +7,12 @@ export const checkVerifications = createMiddleware(async ({ context, next, const { client, author, member, command } = context; const { developerIds } = client.config; - const guild = context.guild(); + const guild = await context.guild(); if (!(member && command && guild)) return pass(); const { messages } = await context.getLocale(); - const voice = await client.cache.voiceStates?.get(member!.id, guild.id)?.channel(); - const bot = client.cache.voiceStates?.get(client.me.id, guild.id); - const player = client.manager.getPlayer(guild.id); - const isAutoplay = !!player?.get("enabledAutoplay"); - if (command.onlyDeveloper && !developerIds.includes(author.id)) { await context.editOrReply({ flags: MessageFlags.Ephemeral, @@ -32,7 +27,7 @@ export const checkVerifications = createMiddleware(async ({ context, next, return pass(); } - if (command.onlyGuildOwner && author.id !== guild.ownerId) { + if (command.onlyGuildOwner && member.id !== guild.ownerId) { await context.editOrReply({ flags: MessageFlags.Ephemeral, embeds: [ @@ -46,89 +41,5 @@ export const checkVerifications = createMiddleware(async ({ context, next, return pass(); } - if (command.checkNodes && !client.manager.useable) { - await context.editOrReply({ - flags: MessageFlags.Ephemeral, - embeds: [ - { - description: messages.events.noNodes, - color: EmbedColors.Red, - }, - ], - }); - - return pass(); - } - - if (command.inVoice && !voice?.is(["GuildVoice", "GuildStageVoice"])) { - await context.editOrReply({ - flags: MessageFlags.Ephemeral, - embeds: [ - { - description: messages.events.noVoiceChannel, - color: EmbedColors.Red, - }, - ], - }); - - return pass(); - } - - if (command.sameVoice && bot && bot.channelId !== voice!.id) { - await context.editOrReply({ - flags: MessageFlags.Ephemeral, - embeds: [ - { - description: messages.events.noSameVoice({ channelId: bot.channelId! }), - color: EmbedColors.Red, - }, - ], - }); - - return pass(); - } - - if (command.checkPlayer && !player) { - await context.editOrReply({ - flags: MessageFlags.Ephemeral, - embeds: [ - { - description: messages.events.noPlayer, - color: EmbedColors.Red, - }, - ], - }); - - return pass(); - } - - if (command.checkQueue && !isAutoplay && !player!.queue.tracks.length) { - await context.editOrReply({ - flags: MessageFlags.Ephemeral, - embeds: [ - { - description: messages.events.noTracks, - color: EmbedColors.Red, - }, - ], - }); - - return pass(); - } - - if (command.moreTracks && !(player!.queue.tracks.length + Number(!!player?.queue.current) >= 1)) { - await context.editOrReply({ - flags: MessageFlags.Ephemeral, - embeds: [ - { - description: messages.events.moreTracks, - color: EmbedColors.Red, - }, - ], - }); - - return pass(); - } - return next(); }); diff --git a/src/middlewares/commands/voice.ts b/src/middlewares/commands/voice.ts new file mode 100644 index 0000000..af0f4bc --- /dev/null +++ b/src/middlewares/commands/voice.ts @@ -0,0 +1,102 @@ +import { createMiddleware } from "seyfert"; +import { EmbedColors } from "seyfert/lib/common/index.js"; +import { MessageFlags } from "seyfert/lib/types/index.js"; + +/** + * Check if the bot is in a voice channel and if is the same as the author. + */ +export const checkBotVoiceChannel = createMiddleware(async ({ context, pass, next }) => { + const { messages } = await context.getLocale(); + + const me = await context.me(); + + const state = context.client.cache.voiceStates!.get(context.author.id, context.guildId!); + if (!state) return pass(); + + const bot = context.client.cache.voiceStates!.get(me.id, context.guildId!); + + if (bot && bot.channelId !== state.channelId) { + await context.editOrReply({ + flags: MessageFlags.Ephemeral, + embeds: [ + { + description: messages.events.noSameVoice({ channelId: bot.channelId! }), + color: EmbedColors.Red, + }, + ], + }); + + return pass(); + } + + return next(); +}); + +/** + * Check if the author is in a voice channel. + */ +export const checkVoiceChannel = createMiddleware(async ({ context, pass, next }) => { + const { messages } = await context.getLocale(); + + const state = context.client.cache.voiceStates!.get(context.author.id, context.guildId!); + const channel = await state?.channel().catch(() => null); + + if (!channel?.is(["GuildVoice", "GuildStageVoice"])) { + await context.editOrReply({ + flags: MessageFlags.Ephemeral, + embeds: [ + { + description: messages.events.noVoiceChannel, + color: EmbedColors.Red, + }, + ], + }); + + return pass(); + } + + return next(); +}); + +/** + * Check if the bot has permissions to join the voice channel. + */ +export const checkVoicePermissions = createMiddleware(async ({ context, pass, next }) => { + const state = context.client.cache.voiceStates!.get(context.author.id, context.guildId!); + if (!state) return pass(); + + const channel = await state.channel().catch(() => null); + if (!channel?.is(["GuildVoice", "GuildStageVoice"])) return pass(); + + const { stagePermissions, voicePermissions } = context.client.config.permissions; + const { messages } = await context.getLocale(); + + const me = await context.me(); + const permissions = await context.client.channels.memberPermissions(channel.id, me); + const missings = permissions.keys(permissions.missings(channel.isStage() ? stagePermissions : voicePermissions)); + + if (missings.length) { + await context.editOrReply({ + content: "", + flags: MessageFlags.Ephemeral, + embeds: [ + { + description: messages.events.permissions.channel.description({ + channelId: channel.id, + }), + color: EmbedColors.Red, + fields: [ + { + name: messages.events.permissions.user.field, + value: missings.map((p) => `- ${messages.events.permissions.list[p]}`).join("\n"), + }, + ], + }, + ], + }); + + return pass(); + } + + return next(); +}); diff --git a/src/middlewares/index.ts b/src/middlewares/index.ts index 9c92b5d..174a57a 100644 --- a/src/middlewares/index.ts +++ b/src/middlewares/index.ts @@ -1,7 +1,24 @@ import { checkCooldown } from "./commands/cooldown.js"; import { checkVerifications } from "./commands/verifications.js"; +import { checkNodes, checkPlayer, checkQueue, checkTracks } from "./commands/manager.js"; +import { checkBotVoiceChannel, checkVoiceChannel, checkVoicePermissions } from "./commands/voice.js"; + export const StelleMiddlewares = { + // Main middlewares checkCooldown, checkVerifications, + + // Voice middlewares + checkBotVoiceChannel, + checkVoiceChannel, + + // Manager middlewares + checkQueue, + checkNodes, + checkPlayer, + checkTracks, + + // Permissions middlewares + checkVoicePermissions, } as const; diff --git a/src/structures/client/Stelle.ts b/src/structures/client/Stelle.ts index b3535b7..9ad8b0e 100644 --- a/src/structures/client/Stelle.ts +++ b/src/structures/client/Stelle.ts @@ -118,7 +118,6 @@ export class Stelle extends Client { disabledCache: { bans: true, emojis: true, - overwrites: true, stickers: true, roles: true, presences: true, diff --git a/src/structures/utils/data/Configuration.ts b/src/structures/utils/data/Configuration.ts index ae0f57a..c56c1b7 100644 --- a/src/structures/utils/data/Configuration.ts +++ b/src/structures/utils/data/Configuration.ts @@ -49,4 +49,8 @@ export const Configuration: StelleConfiguration = { resumeTime: ms("1min"), resumePlayers: true, }, + permissions: { + stagePermissions: ["MuteMembers"], + voicePermissions: ["ViewChannel", "Connect", "Speak"], + }, }; diff --git a/src/structures/utils/functions/autoplay.ts b/src/structures/utils/functions/autoplay.ts index 620172f..c2a7f25 100644 --- a/src/structures/utils/functions/autoplay.ts +++ b/src/structures/utils/functions/autoplay.ts @@ -1,4 +1,4 @@ -import type { Player, SourceNames, Track, UnresolvedTrack } from "lavalink-client"; +import type { Player, Track, UnresolvedTrack } from "lavalink-client"; import type { ClientUser } from "seyfert"; type ResolvableTrack = UnresolvedTrack | Track; @@ -12,6 +12,23 @@ const maxTracks = 10; * Modified by: https://github.com/NoBody-UU/ */ +/** + * + * Filter tracks. + * @param player The player. + * @param lastTrack The last track. + * @param tracks The tracks. + * @returns + */ +const filterTracks = (player: Player, lastTrack: Track, tracks: ResolvableTrack[]) => + tracks.filter( + (track) => + !( + player.queue.previous.some((t) => t.info.identifier === track.info.identifier) || + lastTrack.info.identifier === track.info.identifier + ), + ); + /** * * An autoplay function, that's all. @@ -32,34 +49,36 @@ export async function autoPlayFunction(player: Player, lastTrack?: Track): Promi const me = player.get("me"); if (!me) return; - const filterTracks = (tracks: ResolvableTrack[]) => - tracks.filter( - (track) => - !( - player.queue.previous.some((t) => t.info.identifier === track.info.identifier) || - lastTrack.info.identifier === track.info.identifier - ), - ); + switch (lastTrack.info.sourceName) { + case "spotify": { + const filtered = player.queue.previous.filter(({ info }) => info.sourceName === "spotify").slice(0, 1); + if (!filtered.length) filtered.push(lastTrack); - if (lastTrack.info.sourceName === "spotify") { - const filtered = player.queue.previous.filter(({ info }) => info.sourceName === "spotify").slice(0, 1); - if (!filtered.length) filtered.push(lastTrack); + const ids = filtered.map( + ({ info }) => info.identifier ?? info.uri.split("/").reverse()?.[0] ?? info.uri.split("/").reverse()?.[1], + ); + const res = await player.search({ query: `seed_tracks=${ids.join(",")}`, source: "sprec" }, me); - const ids = filtered.map(({ info }) => info.identifier ?? info.uri.split("/").reverse()?.[0] ?? info.uri.split("/").reverse()?.[1]); - const res = await player.search({ query: `seed_tracks=${ids.join(",")}`, source: "sprec" }, me); + if (res.tracks.length) { + const track = filterTracks(player, lastTrack, res.tracks)[Math.floor(Math.random() * res.tracks.length)] as Track; + await player.queue.add(track); + } - if (res.tracks.length) { - const track = filterTracks(res.tracks)[Math.floor(Math.random() * res.tracks.length)] as Track; - await player.queue.add(track); + break; } - } else if ((["youtube", "youtubemusic"] as SourceNames[]).includes(lastTrack.info.sourceName)) { - const search = `https://www.youtube.com/watch?v=${lastTrack.info.identifier}&list=RD${lastTrack.info.identifier}`; - const res = await player.search({ query: search }, me); - if (res.tracks.length) { - const random = Math.floor(Math.random() * res.tracks.length); - const tracks = filterTracks(res.tracks).slice(random, random + maxTracks) as Track[]; - await player.queue.add(tracks); + case "youtube": + case "youtubemusic": { + const search = `https://www.youtube.com/watch?v=${lastTrack.info.identifier}&list=RD${lastTrack.info.identifier}`; + const res = await player.search({ query: search }, me); + + if (res.tracks.length) { + const random = Math.floor(Math.random() * res.tracks.length); + const tracks = filterTracks(player, lastTrack, res.tracks).slice(random, random + maxTracks) as Track[]; + await player.queue.add(tracks); + } + + break; } } } diff --git a/src/structures/utils/types/client/StelleConfiguration.ts b/src/structures/utils/types/client/StelleConfiguration.ts index 8adf8bd..0a01915 100644 --- a/src/structures/utils/types/client/StelleConfiguration.ts +++ b/src/structures/utils/types/client/StelleConfiguration.ts @@ -1,4 +1,5 @@ import type { LavalinkNodeOptions, SearchPlatform } from "lavalink-client"; +import type { PermissionStrings } from "seyfert"; interface StelleColors { /** The success color. */ @@ -45,6 +46,19 @@ interface StelleSessions { resumePlayers: boolean; } +interface StellePermissions { + /** + * Stelle voice channel permissions. + * @default ["ViewChannel", "Connect", "Speak"] + */ + voicePermissions: PermissionStrings; + /** + * Stelle stage channel permissions. + * @default ["MuteMembers"] + */ + stagePermissions: PermissionStrings; +} + export interface StelleConfiguration { /** * Stelle default prefix. @@ -90,4 +104,6 @@ export interface StelleConfiguration { cache: StelleCache; /** Stelle sessions. */ sessions: StelleSessions; + /** Stelle permissions. */ + permissions: StellePermissions; } diff --git a/src/structures/utils/types/index.ts b/src/structures/utils/types/index.ts index 4fb811f..ece8cf1 100644 --- a/src/structures/utils/types/index.ts +++ b/src/structures/utils/types/index.ts @@ -40,42 +40,6 @@ export interface Options { * @default false */ onlyGuildOwner?: boolean; - /** - * - * Only a member in a voice channel can use the command. - * @default false - */ - inVoice?: boolean; - /** - * - * Only a member on the same voice channel with Stelle will be able to use the command. - * @default false - */ - sameVoice?: boolean; - /** - * - * Check if Stelle is connected atleast in one node. - * @default false - */ - checkNodes?: boolean; - /** - * - * Check if a player exists in a guild. - * @default false - */ - checkPlayer?: boolean; - /** - * - * Check if the player queue has more than one track. - * @default false - */ - checkQueue?: boolean; - /** - * - * Check if the queue has two or more tracks. - * @default false - */ - moreTracks?: boolean; /** * * The command category. From 09df9b9f20f99f72423c2fd46c6afc078c23adf8 Mon Sep 17 00:00:00 2001 From: JustEvil <71156616+EvilG-MC@users.noreply.github.com> Date: Thu, 26 Dec 2024 11:05:25 -0600 Subject: [PATCH 2/3] :zap: chore (version :memo:): bot version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 3d4600b..63128db 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "stelle-music", - "version": "0.3.2.5-BLAZER", + "version": "0.3.3.0-BLAZER", "description": "A music bot.", "main": "./dist/index.js", "type": "module", From 03b925a1a29dda1a6709d8b1f3edb4644e54378d Mon Sep 17 00:00:00 2001 From: JustEvil <71156616+EvilG-MC@users.noreply.github.com> Date: Thu, 26 Dec 2024 11:06:24 -0600 Subject: [PATCH 3/3] lol --- seyfert.config.js | 1 - 1 file changed, 1 deletion(-) diff --git a/seyfert.config.js b/seyfert.config.js index 65b6992..e3481ff 100644 --- a/seyfert.config.js +++ b/seyfert.config.js @@ -23,7 +23,6 @@ export default config.bot({ */ locations: { base, - output: base, lavalink: "lavalink", commands: "commands", components: "components",