import { Client, TextChannel, CommandInteraction, Guild, GuildChannel, TextBasedChannel, VoiceChannel, EmbedBuilder, ButtonBuilder, ActionRowBuilder, ButtonInteraction } from 'discord.js' import { useMainPlayer, useQueue } from 'discord-player' import { Document } from 'mongoose' import getUptime from './getUptime' type ChannelInferrable = { channel: TextBasedChannel | VoiceChannel guild?: Guild } export class PlayerMetadata { public constructor(public data: ChannelInferrable) { if (data.channel.isDMBased()) { throw new Error('PlayerMetadata cannot be created from a DM') } if (!data.channel) { throw new Error('PlayerMetadata can only be created from a channel') } } public get channel() { return this.data.channel! } public get guild() { return this.data.guild || (this.data.channel as GuildChannel).guild } public static create(data: ChannelInferrable | CommandInteraction) { if (data instanceof CommandInteraction) { if (!data.inGuild()) { throw new Error('PlayerMetadata cannot be created from a DM') } return new PlayerMetadata({ channel: data.channel!, guild: data.guild! }) } return new PlayerMetadata(data); } } export const bots = ['1065047326860783636', '1119343522059927684', '1119344050412204032', '1210714000321548329', '660961595006124052'] export const playerButtons = ['loop', 'pause', 'previous', 'resume', 'shuffle', 'skip', 'stop', 'volume_down', 'volume_up'] export async function playerDisco (client: Client, guildProfile: Document) { try { let guild = client.guilds.cache.get(guildProfile.get('guildId')) if (!guild) { clearInterval(client.disco.interval) return 'clear' } let dbData = guildProfile.get('guildPlayer.disco') let queue = useQueue(guild.id) if (queue) if (queue.isPlaying()) { dbData['progress'] = queue.node.playbackTime.toString() guildProfile.set('guildPlayer.disco', dbData) guildProfile.markModified('guildPlayer.disco') await guildProfile.save().catch(console.error) } let channel = client.channels.cache.get(dbData.channelId) as TextChannel if (!channel) { console.log(`Aucun channel trouvé avec l'id \`${dbData.channelId}\`, veuillez utiliser la commande \`/database edit 'value': guildPlayer.disco.channelId\` !`) clearInterval(client.disco.interval) return 'clear' } let { embed, components } = await playerGenerate(guild) if (components && embed.data.footer) embed.setFooter({ text: `Uptime: ${getUptime(client.uptime)} \n ${embed.data.footer.text}` }) else embed.setFooter({ text: `Uptime: ${getUptime(client.uptime)}` }) let messages = await channel.messages.fetch() messages.forEach(msg => { if (!bots.includes(msg.author.id)) msg.delete() }) let botMessage = messages.find(msg => client.user && msg.author.id === client.user.id) if (botMessage) { if (!components && botMessage.components.length > 0) { await botMessage.delete() return channel.send({ embeds: [embed] }) } else if (components) return botMessage.edit({ embeds: [embed], components }) else return botMessage.edit({ embeds: [embed] }) } else return channel.send({ embeds: [embed] }) } catch (error) { console.error(error); return 'clear' } } export async function playerEdit (interaction: ButtonInteraction) { let guild = interaction.guild if (!guild) return await interaction.reply({ content: 'Cette commande n\'est pas disponible en message privé.', ephemeral: true }) let { components } = await playerGenerate(guild) if (!components) return components.forEach((actionRow) => actionRow.components.forEach((button) => button.setDisabled(true))) await interaction.update({ components }) } export async function playerGenerate (guild: Guild) { let embed = new EmbedBuilder().setColor('#ffc370') let queue = useQueue(guild.id) if (!queue) { embed.setTitle('Aucune session d\'écoute en cours !') return ({ embed, components: null }) } let track = queue.currentTrack if (!track) { embed.setTitle('Aucune musique en cours de lecture !') return ({ embed, components: null }) } embed.setTitle(track.title) .setAuthor({ name: track.author }) .setURL(track.url) .setImage(track.thumbnail) .addFields( { name: 'Durée', value: track.duration, inline: true }, { name: 'Source', value: track.source === 'youtube' ? 'Youtube' : track.source === 'spotify' ? 'Spotify' : 'Inconnu', inline: true }, { name: 'Volume', value: `${queue.node.volume}%`, inline: true }, { name: queue.node.isPaused() ? 'Progression (en pause)' : 'Progression', value: queue.node.createProgressBar() || 'Aucune' }, { name: 'Loop', value: queue.repeatMode === 3 ? 'Autoplay' : queue.repeatMode === 2 ? 'File d\'Attente' : queue.repeatMode === 1 ? 'Titre' : 'Off', inline: true } ) .setDescription(`**Musique suivante :** ${queue.tracks.data[0] ? queue.tracks.data[0].title : 'Aucune'}`) .setFooter({ text: `Demandé par ${track.requestedBy ? track.requestedBy.tag : 'Inconnu'}` }) let components = [ new ActionRowBuilder().addComponents( new ButtonBuilder() .setLabel(queue.node.isPaused() ? '▶️' : '⏸️') .setStyle(2) .setCustomId(queue.node.isPaused() ? 'resume' : 'pause'), new ButtonBuilder() .setLabel('⏹️') .setStyle(2) .setCustomId('stop'), new ButtonBuilder() .setLabel('⏭️') .setStyle(2) .setCustomId('skip') .setDisabled(queue.tracks.data.length !== 0), new ButtonBuilder() .setLabel('🔉') .setStyle(2) .setCustomId('volume_down') .setDisabled(queue.node.volume === 0), new ButtonBuilder() .setLabel('🔊') .setStyle(2) .setCustomId('volume_up') .setDisabled(queue.node.volume === 100) ), new ActionRowBuilder().addComponents( new ButtonBuilder() .setLabel('🔀') .setStyle(2) .setCustomId('shuffle'), new ButtonBuilder() .setLabel('🔁') .setStyle(2) .setCustomId('loop'), new ButtonBuilder() .setLabel('⏮️') .setStyle(2) .setCustomId('previous') .setDisabled(queue.history.previousTrack ? false : true) ) ] return ({ embed, components }) } export async function playerReplay (client: Client, guildProfile: Document) { let dbData = guildProfile.get('guildPlayer.replay') let textChannel = client.channels.cache.get(dbData.textChannelId) as TextChannel if (!textChannel) return console.log(`Aucun channel trouvé avec l'id \`${dbData.textChannelId}\`, veuillez utiliser la commande \`/setchannel\` !`) let voiceChannel = client.channels.cache.get(dbData.voiceChannelId) as VoiceChannel if (!voiceChannel) return console.log(`Aucun channel trouvé avec l'id \`${dbData.voiceChannelId}\`, veuillez utiliser la commande \`/setchannel\` !`) let player = useMainPlayer() let queue = player.nodes.create(textChannel.guild, { metadata: { channel: textChannel, client: textChannel.guild.members.me, requestedBy: client.user }, selfDeaf: true, volume: 20, leaveOnEmpty: true, leaveOnEmptyCooldown: 30000, leaveOnEnd: true, leaveOnEndCooldown: 300000 }) try { if (!queue.connection) await queue.connect(voiceChannel) } catch (error) { console.error(error) } let result = await player.search(dbData.trackUrl as string, { requestedBy: client.user || undefined }) if (!result.hasTracks()) await textChannel.send(`Aucune musique trouvée pour **${dbData.trackUrl}** !`) let track = result.tracks[0] let entry = queue.tasksQueue.acquire() await entry.getTask() queue.addTrack(track) try { await queue.node.play() await queue.node.seek(Number(dbData.progress) / 1000) await textChannel.send(`Relancement de la musique suite à mon redémarrage...`) } catch (error) { console.error(error) } finally { queue.tasksQueue.release() } }