2022-03-03 20:56:49 +07:00
import DiscordModule , { HybridInteractionMessage } from "../../utils/DiscordModule" ;
2022-06-06 21:33:02 +07:00
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" ;
2022-01-30 20:10:52 +07:00
import DiscordProvider from "../../providers/Discord" ;
2022-05-01 16:56:37 +07:00
import DiscordMusicPlayer , { PlayerPlayingEvent , PlayerErrorEvent , VoiceDisconnectedEvent , ValidTracks , DiscordMusicPlayerInstance , DiscordMusicPlayerLoopMode } from "../../providers/DiscordMusicPlayer" ;
2022-01-30 20:10:52 +07:00
const EMBEDS = {
VOICECHANNEL_JOINED : ( data : Message | Interaction ) => {
return makeSuccessEmbed ({
title : `Success` ,
description : `Joined voice channel` ,
user : ( data instanceof Interaction ) ? data.user : data.author
});
},
2022-02-27 17:15:20 +07:00
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
});
},
2022-01-30 20:10:52 +07:00
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 ]);
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.
2022-01-30 22:42:00 +07:00
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!**" } ` ,
2022-01-30 20:10:52 +07:00
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
});
},
2022-01-30 22:42:00 +07:00
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
});
},
2022-02-27 17:15:20 +07:00
MUSIC_ERROR : ( data : Message | Interaction , err : Error ) => {
return makeErrorEmbed ({
2022-03-03 22:18:09 +07:00
title : `Error while playing music, skipping this track` ,
2022-02-27 17:15:20 +07:00
description : ` ${ err . message } ` ,
user : ( data instanceof Interaction ) ? data.user : data.author
});
},
2022-01-30 20:10:52 +07:00
NOW_PLAYING : ( data : Message | Interaction , track : ValidTracks ) => {
const embed = makeInfoEmbed ({
title : ' Now playing' ,
icon : '🎵' ,
2022-02-05 00:23:53 +07:00
description : ` ${ track . title } ` ,
2022-01-30 20:10:52 +07:00
user : DiscordProvider.client.user
});
2022-03-04 00:29:50 +07:00
const highestResolutionThumbnail = track . thumbnails . reduce (( prev , current ) => ( prev . height * prev . width > current . height * current . width ) ? prev : current )
2022-05-01 16:56:37 +07:00
if ( highestResolutionThumbnail )
embed . setImage ( highestResolutionThumbnail . url );
return embed ;
},
NOW_REPEATING : ( data : Message | Interaction , track : ValidTracks ) => {
const embed = makeInfoEmbed ({
title : ' Now playing (Repeating)' ,
icon : '🎵' ,
description : ` ${ track . title } ` ,
user : DiscordProvider.client.user
});
const highestResolutionThumbnail = track . thumbnails . reduce (( prev , current ) => ( prev . height * prev . width > current . height * current . width ) ? prev : current )
2022-03-04 00:29:50 +07:00
if ( highestResolutionThumbnail )
embed . setImage ( highestResolutionThumbnail . url );
2022-01-30 20:10:52 +07:00
return embed ;
}
}
2022-06-06 21:33:02 +07:00
export async function joinVoiceChannelProcedure ( data : HybridInteractionMessage , instance : ( DiscordMusicPlayerInstance | null ), voiceChannel : ( VoiceChannel | StageChannel )) {
2022-01-30 20:10:52 +07:00
2022-06-06 21:33:02 +07:00
const isSlashCommand = data . isSlashCommand ();
const isAcceptableInteraction = data . isSelectMenu () || data . isButton ();
const isMessage = data . isMessage ();
2022-01-30 20:10:52 +07:00
if (( ! isSlashCommand && ! isAcceptableInteraction ) && ! isMessage ) return ;
2022-06-06 21:33:02 +07:00
const member = data . getMember ();
const channel = data . getChannel ();
const guild = data . getGuild ();
2022-01-30 20:10:52 +07:00
2022-06-06 21:33:02 +07:00
if ( ! member || ! channel || ! guild ) return ;
2022-01-30 20:10:52 +07:00
2022-06-06 21:33:02 +07:00
if ( channel instanceof DMChannel ) return ;
if ( ! ( channel instanceof TextChannel )) return ;
2022-01-30 20:10:52 +07:00
2022-06-06 21:33:02 +07:00
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 ;
2022-01-30 20:10:52 +07:00
// If already in VoiceChannel
2022-06-06 21:33:02 +07:00
if ( bot . voice . channelId ) {
2022-01-30 20:10:52 +07:00
// But, no music instance yet (The bot might just restarted)
if ( ! instance ) {
// User is in different VoiceChannel
2022-06-06 21:33:02 +07:00
if ( memberVoiceChannel . id !== bot . voice . channelId ) {
2022-01-30 20:10:52 +07:00
//Disconnect it
2022-06-06 21:33:02 +07:00
await bot . voice . disconnect ();
2022-01-30 20:10:52 +07:00
}
//Create instance for a new one
2022-06-06 21:33:02 +07:00
DiscordMusicPlayer . createGuildInstance ( guild . id , voiceChannel );
instance = DiscordMusicPlayer . getGuildInstance ( guild . id );
2022-01-30 20:10:52 +07:00
2022-06-06 21:33:02 +07:00
instance ! . joinVoiceChannel ( voiceChannel , channel );
2022-01-30 20:10:52 +07:00
if ( ! isAcceptableInteraction )
2022-06-06 21:33:02 +07:00
await sendHybridInteractionMessageResponse ( data , { embeds : [ EMBEDS . VOICECHANNEL_JOINED ( data . getRaw ())] });
2022-01-30 20:10:52 +07:00
}
// And, already have instance on the guild
else {
// And, User VoiceChannel is same as the instance
if ( channel . id === instance . voiceChannel . id ) {
if ( ! isAcceptableInteraction )
2022-06-06 21:33:02 +07:00
return await sendHybridInteractionMessageResponse ( data , { embeds : [ EMBEDS . VOICECHANNEL_ALREADY_JOINED ( data . getRaw ())] });
2022-01-30 20:10:52 +07:00
else return ;
}
// But, not the same VoiceChannel
else {
let activeMembers = instance . voiceChannel . members . filter ( member => member . user . bot === false );
// And someone else is using the bot
if ( activeMembers . size > 0 ) {
if ( ! isAcceptableInteraction )
2022-06-06 21:33:02 +07:00
return await sendHybridInteractionMessageResponse ( data , { embeds : [ EMBEDS . VOICECHANNEL_INUSE ( data . getRaw ())] });
2022-01-30 20:10:52 +07:00
else return ;
}
// And alone in the VoiceChannel
else {
// Move to the new voice channel
2022-06-06 21:33:02 +07:00
await bot . voice . setChannel ( voiceChannel );
2022-01-30 20:10:52 +07:00
if ( ! isAcceptableInteraction )
2022-06-06 21:33:02 +07:00
return await sendHybridInteractionMessageResponse ( data , { embeds : [ EMBEDS . VOICECHANNEL_JOINED ( data . getRaw ())] });
2022-01-30 20:10:52 +07:00
else return ;
}
}
}
}
// Not in any VoiceChannel
else {
if ( instance )
2022-06-06 21:33:02 +07:00
await DiscordMusicPlayer . destoryGuildInstance ( guild . id );
2022-01-30 20:10:52 +07:00
2022-06-06 21:33:02 +07:00
DiscordMusicPlayer . createGuildInstance ( guild . id , voiceChannel );
instance = DiscordMusicPlayer . getGuildInstance ( guild . id );
2022-01-30 20:10:52 +07:00
2022-06-06 21:33:02 +07:00
instance ! . joinVoiceChannel ( voiceChannel , channel );
2022-01-30 20:25:34 +07:00
if ( ! isAcceptableInteraction )
2022-06-06 21:33:02 +07:00
await sendHybridInteractionMessageResponse ( data , { embeds : [ EMBEDS . VOICECHANNEL_JOINED ( data . getRaw ())] });
2022-01-30 20:10:52 +07:00
}
if ( ! instance ) return ;
2022-05-01 16:56:37 +07:00
let previousTrack : ValidTracks | undefined ;
let isLoopMessageSent = false ;
2022-01-30 20:10:52 +07:00
// Register Event Listeners
instance . events . on ( 'playing' , async ( event : PlayerPlayingEvent ) => {
2022-03-03 22:18:09 +07:00
if ( ! event . instance . queue || ! event . instance . queue . track || event . instance . queue . track . length === 0 ) return ;
2022-05-01 16:56:37 +07:00
previousTrack = event . instance . getPreviousTrack ();
if ( event . instance . queue . track [ 0 ] !== previousTrack )
isLoopMessageSent = false ;
else if ( event . instance . queue . track [ 0 ] === previousTrack && isLoopMessageSent ) return ;
2022-03-03 22:18:09 +07:00
2022-01-30 20:10:52 +07:00
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 ) {
2022-05-01 16:56:37 +07:00
if ( event . instance . getLoopMode () === DiscordMusicPlayerLoopMode . Current ) {
isLoopMessageSent = true ;
2022-06-06 21:33:02 +07:00
await sendMessage ( event . instance . textChannel , undefined , { embeds : [ EMBEDS . NOW_REPEATING ( data . getRaw (), event . instance . queue . track [ 0 ])], components : [ row ] });
2022-05-01 16:56:37 +07:00
}
else {
2022-06-06 21:33:02 +07:00
await sendMessage ( event . instance . textChannel , undefined , { embeds : [ EMBEDS . NOW_PLAYING ( data . getRaw (), event . instance . queue . track [ 0 ])], components : [ row ] });
2022-05-01 16:56:37 +07:00
}
2022-01-30 20:10:52 +07:00
}
2022-02-27 17:15:20 +07:00
});
instance . events . on ( 'error' , async ( event : PlayerErrorEvent ) => {
if ( event . instance . textChannel ) {
2022-06-06 21:33:02 +07:00
await sendMessage ( event . instance . textChannel , undefined , { embeds : [ EMBEDS . MUSIC_ERROR ( data . getRaw (), event . error )] });
2022-02-27 17:15:20 +07:00
}
});
instance . events . on ( 'disconnect' , async ( event : VoiceDisconnectedEvent ) => {
if ( event . instance . textChannel ) {
2022-06-06 21:33:02 +07:00
await sendMessage ( event . instance . textChannel , undefined , { embeds : [ EMBEDS . VOICECHANNEL_DISCONNECTED ( data . getRaw ())] });
2022-02-27 17:15:20 +07:00
}
2022-03-03 22:48:23 +07:00
DiscordMusicPlayer . destoryGuildInstance ( event . instance . voiceChannel . guildId );
2022-02-27 17:15:20 +07:00
});
2022-01-30 20:10:52 +07:00
}
2022-03-03 20:56:49 +07:00
export default class Join extends DiscordModule {
2022-01-30 20:10:52 +07:00
2022-03-03 20:56:49 +07:00
public id = "Discord_MusicPlayer_Join" ;
public commands = [ "join" ];
public commandInteractionName = "join" ;
2022-01-30 20:10:52 +07:00
2022-03-03 20:56:49 +07:00
async GuildOnModuleCommand ( args : any , message : Message ) {
await this . run ( new HybridInteractionMessage ( message ), args );
2022-01-30 20:10:52 +07:00
}
2022-03-03 20:56:49 +07:00
async GuildModuleCommandInteractionCreate ( interaction : CommandInteraction ) {
await this . run ( new HybridInteractionMessage ( interaction ), interaction . options );
2022-01-30 20:10:52 +07:00
}
2022-03-03 20:56:49 +07:00
async run ( data : HybridInteractionMessage , args : any ) {
2022-01-30 20:10:52 +07:00
2022-03-03 20:56:49 +07:00
const guild = data . getGuild ();
const member = data . getMember ();
2022-01-30 20:10:52 +07:00
2022-03-03 20:56:49 +07:00
if ( ! guild || ! member ) return ;
2022-01-30 20:10:52 +07:00
2022-03-03 20:56:49 +07:00
const voiceChannel = member . voice . channel ;
2022-01-30 20:10:52 +07:00
2022-03-03 20:56:49 +07:00
if ( ! voiceChannel )
return await sendHybridInteractionMessageResponse ( data , { embeds : [ EMBEDS . USER_NOT_IN_VOICECHANNEL ( data . getRaw ())] });
2022-01-30 22:42:00 +07:00
2022-03-03 20:56:49 +07:00
const instance = DiscordMusicPlayer . getGuildInstance ( guild . id );
2022-06-06 21:33:02 +07:00
console . log ( data . isButton )
await joinVoiceChannelProcedure ( data , instance , voiceChannel );
2022-01-30 20:10:52 +07:00
}
}