diff options
Diffstat (limited to 'src/commands')
| -rw-r--r-- | src/commands/index.ts | 8 | ||||
| -rw-r--r-- | src/commands/play.ts | 1 | ||||
| -rw-r--r-- | src/commands/queue.ts | 106 |
3 files changed, 58 insertions, 57 deletions
diff --git a/src/commands/index.ts b/src/commands/index.ts index 91b76c5..1cd927b 100644 --- a/src/commands/index.ts +++ b/src/commands/index.ts @@ -1,12 +1,14 @@ import {SlashCommandBuilder} from '@discordjs/builders'; -import {CommandInteraction} from 'discord.js'; +import {ButtonInteraction, CommandInteraction} from 'discord.js'; -export default interface Command { +export default class Command { // TODO: remove name?: string; aliases?: string[]; examples?: string[][]; readonly slashCommand?: Partial<SlashCommandBuilder> & Pick<SlashCommandBuilder, 'toJSON'>; - requiresVC?: boolean; + readonly handledButtonIds?: readonly string[]; + readonly requiresVC?: boolean; executeFromInteraction?: (interaction: CommandInteraction) => Promise<void>; + handleButtonInteraction?: (interaction: ButtonInteraction) => Promise<void>; } diff --git a/src/commands/play.ts b/src/commands/play.ts index 6e76e37..7dc5e41 100644 --- a/src/commands/play.ts +++ b/src/commands/play.ts @@ -15,6 +15,7 @@ import GetSongs from '../services/get-songs.js'; export default class implements Command { public readonly slashCommand = new SlashCommandBuilder() .setName('play') + // TODO: make sure verb tense is consistent between all command descriptions .setDescription('play a song or resume playback') .addStringOption(option => option .setName('query') diff --git a/src/commands/queue.ts b/src/commands/queue.ts index 1c0735c..479bc33 100644 --- a/src/commands/queue.ts +++ b/src/commands/queue.ts @@ -1,82 +1,80 @@ -import {Message, MessageEmbed} from 'discord.js'; -import getYouTubeID from 'get-youtube-id'; +import {ButtonInteraction, CommandInteraction} from 'discord.js'; +import {SlashCommandBuilder} from '@discordjs/builders'; import {inject, injectable} from 'inversify'; import {TYPES} from '../types.js'; import PlayerManager from '../managers/player.js'; -import {STATUS} from '../services/player.js'; +import UpdatingQueueEmbedManager from '../managers/updating-queue-embed.js'; +import {BUTTON_IDS} from '../services/updating-queue-embed.js'; import Command from '.'; -import getProgressBar from '../utils/get-progress-bar.js'; -import errorMsg from '../utils/error-msg.js'; -import {prettyTime} from '../utils/time.js'; - -const PAGE_SIZE = 10; @injectable() export default class implements Command { - public name = 'queue'; - public aliases = ['q']; - public examples = [ - ['queue', 'shows current queue'], - ['queue 2', 'shows second page of queue'], - ]; + public readonly slashCommand = new SlashCommandBuilder() + .setName('queue') + .setDescription('show the current queue'); + + public readonly handledButtonIds = Object.values(BUTTON_IDS); private readonly playerManager: PlayerManager; + private readonly updatingQueueEmbedManager: UpdatingQueueEmbedManager; - constructor(@inject(TYPES.Managers.Player) playerManager: PlayerManager) { + constructor(@inject(TYPES.Managers.Player) playerManager: PlayerManager, @inject(TYPES.Managers.UpdatingQueueEmbed) updatingQueueEmbedManager: UpdatingQueueEmbedManager) { this.playerManager = playerManager; + this.updatingQueueEmbedManager = updatingQueueEmbedManager; } - public async execute(msg: Message, args: string []): Promise<void> { - const player = this.playerManager.get(msg.guild!.id); - - const currentlyPlaying = player.getCurrent(); - - if (currentlyPlaying) { - const queueSize = player.queueSize(); - const queuePage = args[0] ? parseInt(args[0], 10) : 1; - - const maxQueuePage = Math.ceil((queueSize + 1) / PAGE_SIZE); + public async executeFromInteraction(interaction: CommandInteraction) { + const embed = this.updatingQueueEmbedManager.get(interaction.guild!.id); - if (queuePage > maxQueuePage) { - await msg.channel.send(errorMsg('the queue isn\'t that big')); - return; - } + await embed.createFromInteraction(interaction); + } - const embed = new MessageEmbed(); + public async handleButtonInteraction(interaction: ButtonInteraction) { + const player = this.playerManager.get(interaction.guild!.id); + const embed = this.updatingQueueEmbedManager.get(interaction.guild!.id); - embed.setTitle(currentlyPlaying.title); - embed.setURL(`https://www.youtube.com/watch?v=${currentlyPlaying.url.length === 11 ? currentlyPlaying.url : getYouTubeID(currentlyPlaying.url) ?? ''}`); + const buttonId = interaction.customId as keyof typeof this.handledButtonIds; - let description = player.status === STATUS.PLAYING ? 'âšī¸' : 'âļī¸'; - description += ' '; - description += getProgressBar(20, player.getPosition() / currentlyPlaying.length); - description += ' '; - description += `\`[${prettyTime(player.getPosition())}/${currentlyPlaying.isLive ? 'live' : prettyTime(currentlyPlaying.length)}]\``; - description += ' đ'; - description += player.isQueueEmpty() ? '' : '\n\n**Next up:**'; + // Not entirely sure why this is necessary. + // We don't wait for the Promise to resolve here to avoid blocking the + // main logic. However, we need to wait for the Promise to be resolved before + // throwing as otherwise a race condition pops up when bot.ts tries updating + // the interaction. + const deferedUpdatePromise = interaction.deferUpdate(); - embed.setDescription(description); + try { + switch (buttonId) { + case BUTTON_IDS.TRACK_BACK: + await player.back(); + break; - let footer = `Source: ${currentlyPlaying.artist}`; + case BUTTON_IDS.TRACK_FORWARD: + await player.forward(1); + break; - if (currentlyPlaying.playlist) { - footer += ` (${currentlyPlaying.playlist.title})`; - } + case BUTTON_IDS.PAUSE: + player.pause(); + break; - embed.setFooter(footer); + case BUTTON_IDS.PLAY: + await player.play(); + break; - const queuePageBegin = (queuePage - 1) * PAGE_SIZE; - const queuePageEnd = queuePageBegin + PAGE_SIZE; + case BUTTON_IDS.PAGE_BACK: + await embed.pageBack(); + break; - player.getQueue().slice(queuePageBegin, queuePageEnd).forEach((song, i) => { - embed.addField(`${(i + 1 + queuePageBegin).toString()}/${queueSize.toString()}`, song.title, false); - }); + case BUTTON_IDS.PAGE_FORWARD: + await embed.pageForward(); + break; - embed.addField('Page', `${queuePage} out of ${maxQueuePage}`, false); + default: + throw new Error('unknown customId'); + } + } catch (error: unknown) { + await deferedUpdatePromise; - await msg.channel.send({embeds: [embed]}); - } else { - await msg.channel.send('queue empty'); + throw error; } } } |
