diff --git a/src/discord/MusicPlayer/Join.ts b/src/discord/MusicPlayer/Join.ts index c0e384d..e27ec62 100644 --- a/src/discord/MusicPlayer/Join.ts +++ b/src/discord/MusicPlayer/Join.ts @@ -1,56 +1,88 @@ -import DiscordModule, { HybridInteractionMessage } from "../../utils/DiscordModule"; +import DiscordModule, { HybridInteractionMessage } from '../../utils/DiscordModule'; -import { Message, CommandInteraction, Interaction, VoiceChannel, Permissions, GuildMember, DMChannel, StageChannel, MessageActionRow, MessageButton, TextChannel, VoiceBasedChannel } from "discord.js"; -import { makeSuccessEmbed, makeErrorEmbed, sendMessage, sendHybridInteractionMessageResponse, makeInfoEmbed } from "../../utils/DiscordMessage"; -import DiscordProvider from "../../providers/Discord"; -import DiscordMusicPlayer, { PlayerPlayingEvent, PlayerErrorEvent, VoiceDisconnectedEvent, ValidTracks, DiscordMusicPlayerInstance, DiscordMusicPlayerLoopMode } from "../../providers/DiscordMusicPlayer"; +import { + Message, + CommandInteraction, + Interaction, + VoiceChannel, + Permissions, + GuildMember, + DMChannel, + StageChannel, + MessageActionRow, + MessageButton, + TextChannel, + VoiceBasedChannel +} from 'discord.js'; +import { + makeSuccessEmbed, + makeErrorEmbed, + sendMessage, + sendHybridInteractionMessageResponse, + makeInfoEmbed +} from '../../utils/DiscordMessage'; +import DiscordProvider from '../../providers/Discord'; +import DiscordMusicPlayer, { + PlayerPlayingEvent, + PlayerErrorEvent, + VoiceDisconnectedEvent, + ValidTracks, + DiscordMusicPlayerInstance, + DiscordMusicPlayerLoopMode +} from '../../providers/DiscordMusicPlayer'; const EMBEDS = { VOICECHANNEL_JOINED: (data: Message | Interaction) => { return makeSuccessEmbed({ title: `Success`, description: `Joined voice channel`, - user: (data instanceof Interaction) ? data.user : data.author + user: data instanceof Interaction ? data.user : data.author }); }, VOICECHANNEL_DISCONNECTED: (data: Message | Interaction) => { return makeSuccessEmbed({ title: `Disconnected`, description: `I got disconnected from the voice channel`, - user: (data instanceof Interaction) ? data.user : data.author + user: data instanceof Interaction ? data.user : data.author }); }, VOICECHANNEL_INUSE: (data: Message | Interaction) => { - - let haveForceMove = (data instanceof Message) ? (data as Message).member!.permissions.has([Permissions.FLAGS.MOVE_MEMBERS]) : ((data as Interaction).member! as GuildMember).permissions.has([Permissions.FLAGS.MOVE_MEMBERS]); + let haveForceMove = + data instanceof Message + ? (data as Message).member!.permissions.has([Permissions.FLAGS.MOVE_MEMBERS]) + : ((data as Interaction).member! as GuildMember).permissions.has([Permissions.FLAGS.MOVE_MEMBERS]); return makeErrorEmbed({ title: `I can't open portal to parallel universe`, description: `I can't join mutiple voice channel on the same guild. I wish I had a superpower, maybe... one day I will. - There are also somebody listening to the music in the voice channel I'm currently in.${!haveForceMove ? ` Wait until I finish playing there or I'm alone there. Better yet, join them!` : " Wait until I finish playing there or I'm alone there. Better yet, join them! \n\n**Or... just (ab)use your admin permissions and move me to where you want!**"}`, - user: (data instanceof Interaction) ? data.user : data.author + There are also somebody listening to the music in the voice channel I'm currently in.${ + !haveForceMove + ? ` Wait until I finish playing there or I'm alone there. Better yet, join them!` + : " Wait until I finish playing there or I'm alone there. Better yet, join them! \n\n**Or... just (ab)use your admin permissions and move me to where you want!**" + }`, + user: data instanceof Interaction ? data.user : data.author }); }, VOICECHANNEL_ALREADY_JOINED: (data: Message | Interaction) => { return makeInfoEmbed({ title: `I'm already here`, description: `Already in the voice channel you are currently connected to`, - user: (data instanceof Interaction) ? data.user : data.author + user: data instanceof Interaction ? data.user : data.author }); }, USER_NOT_IN_VOICECHANNEL: (data: Message | Interaction) => { return makeErrorEmbed({ title: `You need to be in the voice channel first!`, - user: (data instanceof Interaction) ? data.user : data.author + user: data instanceof Interaction ? data.user : data.author }); }, MUSIC_ERROR: (data: Message | Interaction, err: Error) => { return makeErrorEmbed({ title: `Error while playing music, skipping this track`, description: `${err.message}`, - user: (data instanceof Interaction) ? data.user : data.author + user: data instanceof Interaction ? data.user : data.author }); }, NOW_PLAYING: (data: Message | Interaction, track: ValidTracks) => { @@ -61,10 +93,11 @@ const EMBEDS = { user: DiscordProvider.client.user }); - const highestResolutionThumbnail = track.thumbnails.reduce((prev, current) => (prev.height * prev.width > current.height * current.width) ? prev : current) + const highestResolutionThumbnail = track.thumbnails.reduce((prev, current) => + prev.height * prev.width > current.height * current.width ? prev : current + ); - if(highestResolutionThumbnail) - embed.setImage(highestResolutionThumbnail.url); + if (highestResolutionThumbnail) embed.setImage(highestResolutionThumbnail.url); return embed; }, @@ -76,36 +109,40 @@ const EMBEDS = { user: DiscordProvider.client.user }); - const highestResolutionThumbnail = track.thumbnails.reduce((prev, current) => (prev.height * prev.width > current.height * current.width) ? prev : current) + const highestResolutionThumbnail = track.thumbnails.reduce((prev, current) => + prev.height * prev.width > current.height * current.width ? prev : current + ); - if(highestResolutionThumbnail) - embed.setImage(highestResolutionThumbnail.url); + if (highestResolutionThumbnail) embed.setImage(highestResolutionThumbnail.url); return embed; } -} - -export async function joinVoiceChannelProcedure (data: HybridInteractionMessage, instance: (DiscordMusicPlayerInstance | null), voiceChannel: (VoiceChannel | StageChannel)) { +}; +export async function joinVoiceChannelProcedure( + data: HybridInteractionMessage, + instance: DiscordMusicPlayerInstance | null, + voiceChannel: VoiceChannel | StageChannel +) { const isSlashCommand = data.isSlashCommand(); const isAcceptableInteraction = data.isSelectMenu() || data.isButton(); const isMessage = data.isMessage(); - if ((!isSlashCommand && !isAcceptableInteraction) && !isMessage) return; + if (!isSlashCommand && !isAcceptableInteraction && !isMessage) return; const member = data.getMember(); const channel = data.getChannel(); const guild = data.getGuild(); - if(!member || !channel || !guild) return; + if (!member || !channel || !guild) return; if (channel instanceof DMChannel) return; if (!(channel instanceof TextChannel)) return; - const memberVoiceChannel = member.voice.channel;//isMessage ? member.voice.channel : DiscordProvider.client.guilds.cache.get(guild.id)!.members.cache.get((data as Interaction).user.id)?.voice.channel; + const memberVoiceChannel = member.voice.channel; //isMessage ? member.voice.channel : DiscordProvider.client.guilds.cache.get(guild.id)!.members.cache.get((data as Interaction).user.id)?.voice.channel; if (!memberVoiceChannel) return; const bot = guild.me; - if(!bot) return; + if (!bot) return; // If already in VoiceChannel if (bot.voice.channelId) { @@ -122,49 +159,54 @@ export async function joinVoiceChannelProcedure (data: HybridInteractionMessage, instance = DiscordMusicPlayer.getGuildInstance(guild.id); instance!.joinVoiceChannel(voiceChannel, channel); - if(!isAcceptableInteraction) - await sendHybridInteractionMessageResponse(data, { embeds: [EMBEDS.VOICECHANNEL_JOINED(data.getRaw())] }); + if (!isAcceptableInteraction) + await sendHybridInteractionMessageResponse(data, { + embeds: [EMBEDS.VOICECHANNEL_JOINED(data.getRaw())] + }); } // And, already have instance on the guild else { // And, User VoiceChannel is same as the instance if (channel.id === instance.voiceChannel.id) { - if(!isAcceptableInteraction) - return await sendHybridInteractionMessageResponse(data, { embeds: [EMBEDS.VOICECHANNEL_ALREADY_JOINED(data.getRaw())] }); + if (!isAcceptableInteraction) + return await sendHybridInteractionMessageResponse(data, { + embeds: [EMBEDS.VOICECHANNEL_ALREADY_JOINED(data.getRaw())] + }); else return; } // But, not the same VoiceChannel else { - let activeMembers = instance.voiceChannel.members.filter(member => member.user.bot === false); + let activeMembers = instance.voiceChannel.members.filter((member) => member.user.bot === false); // And someone else is using the bot - if(activeMembers.size > 0) { - if(!isAcceptableInteraction) - return await sendHybridInteractionMessageResponse(data, { embeds: [EMBEDS.VOICECHANNEL_INUSE(data.getRaw())] }); + if (activeMembers.size > 0) { + if (!isAcceptableInteraction) + return await sendHybridInteractionMessageResponse(data, { + embeds: [EMBEDS.VOICECHANNEL_INUSE(data.getRaw())] + }); else return; } // And alone in the VoiceChannel else { // Move to the new voice channel await bot.voice.setChannel(voiceChannel); - if(!isAcceptableInteraction) - return await sendHybridInteractionMessageResponse(data, { embeds: [EMBEDS.VOICECHANNEL_JOINED(data.getRaw())] }); + if (!isAcceptableInteraction) + return await sendHybridInteractionMessageResponse(data, { + embeds: [EMBEDS.VOICECHANNEL_JOINED(data.getRaw())] + }); else return; } } } - } // Not in any VoiceChannel else { - - if (instance) - await DiscordMusicPlayer.destoryGuildInstance(guild.id); + if (instance) await DiscordMusicPlayer.destoryGuildInstance(guild.id); DiscordMusicPlayer.createGuildInstance(guild.id, voiceChannel); instance = DiscordMusicPlayer.getGuildInstance(guild.id); instance!.joinVoiceChannel(voiceChannel, channel); - if(!isAcceptableInteraction) + if (!isAcceptableInteraction) await sendHybridInteractionMessageResponse(data, { embeds: [EMBEDS.VOICECHANNEL_JOINED(data.getRaw())] }); } @@ -175,43 +217,49 @@ export async function joinVoiceChannelProcedure (data: HybridInteractionMessage, // Register Event Listeners instance.events.on('playing', async (event: PlayerPlayingEvent) => { - - if(!event.instance.queue || !event.instance.queue.track || event.instance.queue.track.length === 0) return; + if (!event.instance.queue || !event.instance.queue.track || event.instance.queue.track.length === 0) return; previousTrack = event.instance.getPreviousTrack(); - if(event.instance.queue.track[0] !== previousTrack) - isLoopMessageSent = false; - else if(event.instance.queue.track[0] === previousTrack && isLoopMessageSent) return; + if (event.instance.queue.track[0] !== previousTrack) isLoopMessageSent = false; + else if (event.instance.queue.track[0] === previousTrack && isLoopMessageSent) return; - const row = new MessageActionRow() - .addComponents( - new MessageButton() - .setEmoji('▶️') - .setLabel(' Open on YouTube') - .setURL(encodeURI(`https://www.youtube.com/watch?v=${event.instance.queue.track[0].id}`)) - .setStyle('LINK'), - ) + const row = new MessageActionRow().addComponents( + new MessageButton() + .setEmoji('▶️') + .setLabel(' Open on YouTube') + .setURL(encodeURI(`https://www.youtube.com/watch?v=${event.instance.queue.track[0].id}`)) + .setStyle('LINK') + ); if (event.instance.textChannel) { - if(event.instance.getLoopMode() === DiscordMusicPlayerLoopMode.Current) { + if (event.instance.getLoopMode() === DiscordMusicPlayerLoopMode.Current) { isLoopMessageSent = true; - await sendMessage(event.instance.textChannel, undefined, { embeds: [EMBEDS.NOW_REPEATING(data.getRaw(), event.instance.queue.track[0])], components: [row] }); - } - else { - await sendMessage(event.instance.textChannel, undefined, { embeds: [EMBEDS.NOW_PLAYING(data.getRaw(), event.instance.queue.track[0])], components: [row] }); + await sendMessage(event.instance.textChannel, undefined, { + embeds: [EMBEDS.NOW_REPEATING(data.getRaw(), event.instance.queue.track[0])], + components: [row] + }); + } else { + await sendMessage(event.instance.textChannel, undefined, { + embeds: [EMBEDS.NOW_PLAYING(data.getRaw(), event.instance.queue.track[0])], + components: [row] + }); } } }); instance.events.on('error', async (event: PlayerErrorEvent) => { if (event.instance.textChannel) { - await sendMessage(event.instance.textChannel, undefined, { embeds: [EMBEDS.MUSIC_ERROR(data.getRaw(), event.error)] }); + await sendMessage(event.instance.textChannel, undefined, { + embeds: [EMBEDS.MUSIC_ERROR(data.getRaw(), event.error)] + }); } }); instance.events.on('disconnect', async (event: VoiceDisconnectedEvent) => { if (event.instance.textChannel) { - await sendMessage(event.instance.textChannel, undefined, { embeds: [EMBEDS.VOICECHANNEL_DISCONNECTED(data.getRaw())] }); + await sendMessage(event.instance.textChannel, undefined, { + embeds: [EMBEDS.VOICECHANNEL_DISCONNECTED(data.getRaw())] + }); } DiscordMusicPlayer.destoryGuildInstance(event.instance.voiceChannel.guildId); @@ -219,33 +267,33 @@ export async function joinVoiceChannelProcedure (data: HybridInteractionMessage, } export default class Join extends DiscordModule { - - public id = "Discord_MusicPlayer_Join"; - public commands = ["join"]; - public commandInteractionName = "join"; + public id = 'Discord_MusicPlayer_Join'; + public commands = ['join']; + public commandInteractionName = 'join'; async GuildOnModuleCommand(args: any, message: Message) { await this.run(new HybridInteractionMessage(message), args); } - async GuildModuleCommandInteractionCreate(interaction: CommandInteraction) { + async GuildModuleCommandInteractionCreate(interaction: CommandInteraction) { await this.run(new HybridInteractionMessage(interaction), interaction.options); } async run(data: HybridInteractionMessage, args: any) { - const guild = data.getGuild(); const member = data.getMember(); - if(!guild || !member) return; + if (!guild || !member) return; const voiceChannel = member.voice.channel; if (!voiceChannel) - return await sendHybridInteractionMessageResponse(data, { embeds: [EMBEDS.USER_NOT_IN_VOICECHANNEL(data.getRaw())] }); - + return await sendHybridInteractionMessageResponse(data, { + embeds: [EMBEDS.USER_NOT_IN_VOICECHANNEL(data.getRaw())] + }); + const instance = DiscordMusicPlayer.getGuildInstance(guild.id); - console.log(data.isButton) + console.log(data.isButton); await joinVoiceChannelProcedure(data, instance, voiceChannel); } -} \ No newline at end of file +} diff --git a/src/utils/DiscordMessage.ts b/src/utils/DiscordMessage.ts index cd8d36c..04a02f5 100644 --- a/src/utils/DiscordMessage.ts +++ b/src/utils/DiscordMessage.ts @@ -33,6 +33,16 @@ interface EmbedData { setTimestamp: boolean; } +interface EmbedDataPresets { + icon?: string; + title: string; + description?: any; + color?: ColorResolvable; + fields?: any; + user?: User; + setTimestamp?: boolean; +} + export function makeEmbed(data: EmbedData) { const embed = new MessageEmbed(); embed.setColor(data.color || '#FFFFFF'); @@ -59,19 +69,19 @@ export function makeEmbed(data: EmbedData) { return embed; } -export function makeInfoEmbed(options: any) { +export function makeInfoEmbed(data: EmbedDataPresets) { return makeEmbed({ - icon: !options.icon ? '🔮' : options.icon, - title: options.title, - description: options.description, + icon: !data.icon ? '🔮' : data.icon, + title: data.title, + description: data.description, color: '#C7CEEA', - fields: options.fields, - user: options.user, - setTimestamp: options.setTimestamp || true + fields: data.fields, + user: data.user, + setTimestamp: data.setTimestamp || true }); } -export function makeSuccessEmbed(options: any) { +export function makeSuccessEmbed(options: EmbedDataPresets) { return makeEmbed({ icon: !options.icon ? '✅' : options.icon, title: options.title, @@ -83,39 +93,39 @@ export function makeSuccessEmbed(options: any) { }); } -export function makeWarningEmbed(options: any) { +export function makeWarningEmbed(data: EmbedDataPresets) { return makeEmbed({ - icon: !options.icon ? '⚠️' : options.icon, - title: options.title, - description: options.description, + icon: !data.icon ? '⚠️' : data.icon, + title: data.title, + description: data.description, color: '#FFEEAD', - fields: options.fields, - user: options.user, - setTimestamp: options.setTimestamp || true + fields: data.fields, + user: data.user, + setTimestamp: data.setTimestamp || true }); } -export function makeErrorEmbed(options: any) { +export function makeErrorEmbed(data: EmbedDataPresets) { return makeEmbed({ - icon: !options.icon ? '❌' : options.icon, - title: options.title, - description: options.description, + icon: !data.icon ? '❌' : data.icon, + title: data.title, + description: data.description, color: '#FF9AA2', - fields: options.fields, - user: options.user, - setTimestamp: options.setTimestamp || true + fields: data.fields, + user: data.user, + setTimestamp: data.setTimestamp || true }); } -export function makeProcessingEmbed(options: any) { +export function makeProcessingEmbed(data: EmbedDataPresets) { return makeEmbed({ - icon: !options.icon ? getEmotes().yumiloading : options.icon, - title: options.title, - description: options.description, + icon: !data.icon ? getEmotes().yumiloading : data.icon, + title: data.title, + description: data.description, color: '#E2F0CB', - fields: options.fields, - user: options.user, - setTimestamp: options.setTimestamp || true + fields: data.fields, + user: data.user, + setTimestamp: data.setTimestamp || true }); } @@ -147,25 +157,6 @@ export async function sendMessage( } } -export async function sendReply(rMessage: Message, options: string | MessagePayload | MessageOptions) { - let message; - - try { - message = await rMessage.reply(options); - } catch (error) { - try { - message = await rMessage.author.send(options); - } catch (errorDM) { - Logger.error( - `Cannot find available destinations to reply the message to. MID: ${rMessage.id} CID: ${rMessage.channel.id} UID: ${rMessage.author.id} C_ERR: ${error} DM_ERR: ${errorDM}` - ); - return; - } - } finally { - return message; - } -} - export async function sendHybridInteractionMessageResponse( data: HybridInteractionMessage, payload: MessageOptions | InteractionReplyOptions, @@ -216,3 +207,23 @@ export async function sendHybridInteractionMessageResponse( export function getEmotes() { return emotes; } + + +async function sendReply(rMessage: Message, options: string | MessagePayload | MessageOptions) { + let message; + + try { + message = await rMessage.reply(options); + } catch (error) { + try { + message = await rMessage.author.send(options); + } catch (errorDM) { + Logger.error( + `Cannot find available destinations to reply the message to. MID: ${rMessage.id} CID: ${rMessage.channel.id} UID: ${rMessage.author.id} C_ERR: ${error} DM_ERR: ${errorDM}` + ); + return; + } + } finally { + return message; + } +} \ No newline at end of file