AeThex-Bot-Master/aethex-bot/commands/music.js
sirpiglr ba1d4c90da Add music player functionality and update dependencies for improved performance
Integrate discord-player and extractors, update package.json dependencies, and add music command functionality to bot.js and music.js.

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: aed2e46d-25bb-4b73-81a1-bb9e8437c261
Replit-Commit-Checkpoint-Type: intermediate_checkpoint
Replit-Commit-Event-Id: 85c6eaeb-53ee-4ce1-abcf-e58baf3f4df1
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/3bdfff67-975a-46ad-9845-fbb6b4a4c4b5/aed2e46d-25bb-4b73-81a1-bb9e8437c261/Mc7EIoi
Replit-Helium-Checkpoint-Created: true
2025-12-13 08:07:48 +00:00

332 lines
11 KiB
JavaScript

const { SlashCommandBuilder, EmbedBuilder } = require('discord.js');
const { useMainPlayer, useQueue } = require('discord-player');
module.exports = {
data: new SlashCommandBuilder()
.setName('music')
.setDescription('Music player controls')
.addSubcommand(sub =>
sub.setName('play')
.setDescription('Play a song or playlist')
.addStringOption(opt =>
opt.setName('query')
.setDescription('Song name, URL, or playlist link')
.setRequired(true)))
.addSubcommand(sub =>
sub.setName('skip')
.setDescription('Skip the current track'))
.addSubcommand(sub =>
sub.setName('stop')
.setDescription('Stop playback and clear the queue'))
.addSubcommand(sub =>
sub.setName('pause')
.setDescription('Pause the current track'))
.addSubcommand(sub =>
sub.setName('resume')
.setDescription('Resume playback'))
.addSubcommand(sub =>
sub.setName('queue')
.setDescription('View the current queue'))
.addSubcommand(sub =>
sub.setName('nowplaying')
.setDescription('Show the currently playing track'))
.addSubcommand(sub =>
sub.setName('volume')
.setDescription('Adjust the volume')
.addIntegerOption(opt =>
opt.setName('level')
.setDescription('Volume level (0-100)')
.setRequired(true)
.setMinValue(0)
.setMaxValue(100)))
.addSubcommand(sub =>
sub.setName('shuffle')
.setDescription('Shuffle the queue'))
.addSubcommand(sub =>
sub.setName('loop')
.setDescription('Set loop mode')
.addStringOption(opt =>
opt.setName('mode')
.setDescription('Loop mode')
.setRequired(true)
.addChoices(
{ name: 'Off', value: 'off' },
{ name: 'Track', value: 'track' },
{ name: 'Queue', value: 'queue' }
))),
async execute(interaction, client, supabase) {
const subcommand = interaction.options.getSubcommand();
const player = useMainPlayer();
const memberVoice = interaction.member.voice.channel;
const botVoice = interaction.guild.members.me.voice.channel;
if (subcommand === 'play') {
if (!memberVoice) {
return interaction.reply({
embeds: [new EmbedBuilder()
.setColor(0xff0000)
.setDescription('You need to be in a voice channel to play music.')],
ephemeral: true
});
}
if (botVoice && botVoice.id !== memberVoice.id) {
return interaction.reply({
embeds: [new EmbedBuilder()
.setColor(0xff0000)
.setDescription(`I'm already playing music in <#${botVoice.id}>. Join that channel or wait until I'm done.`)],
ephemeral: true
});
}
const query = interaction.options.getString('query');
await interaction.deferReply();
try {
const result = await player.search(query, {
requestedBy: interaction.user
});
if (!result.hasTracks()) {
return interaction.editReply({
embeds: [new EmbedBuilder()
.setColor(0xff0000)
.setDescription(`No results found for: **${query}**`)]
});
}
const { track, searchResult } = await player.play(memberVoice, result, {
nodeOptions: {
metadata: {
channel: interaction.channel,
client: interaction.guild.members.me,
requestedBy: interaction.user
},
volume: 50,
leaveOnEmpty: true,
leaveOnEmptyCooldown: 300000,
leaveOnEnd: true,
leaveOnEndCooldown: 300000
}
});
const embed = new EmbedBuilder()
.setColor(0x5865f2)
.setAuthor({ name: 'Added to Queue', iconURL: interaction.user.displayAvatarURL() });
if (searchResult.playlist) {
embed.setTitle(searchResult.playlist.title)
.setURL(searchResult.playlist.url)
.setDescription(`Added **${searchResult.tracks.length}** tracks from playlist`)
.setThumbnail(searchResult.playlist.thumbnail || track.thumbnail);
} else {
embed.setTitle(track.title)
.setURL(track.url)
.setDescription(`**Duration:** ${track.duration}\n**Author:** ${track.author}`)
.setThumbnail(track.thumbnail);
}
return interaction.editReply({ embeds: [embed] });
} catch (error) {
console.error('Music play error:', error);
let errorMessage = 'Something went wrong while trying to play music.';
if (error.message?.includes('Sign in')) {
errorMessage = 'This track requires age verification or is restricted.';
} else if (error.message?.includes('private')) {
errorMessage = 'This playlist or video is private.';
} else if (error.message?.includes('unavailable')) {
errorMessage = 'This content is unavailable in the current region.';
} else if (error.message?.includes('Could not extract')) {
errorMessage = 'Could not load this track. Try a different search term.';
}
return interaction.editReply({
embeds: [new EmbedBuilder()
.setColor(0xff0000)
.setDescription(errorMessage)]
});
}
}
const queue = useQueue(interaction.guildId);
if (subcommand === 'nowplaying') {
if (!queue || !queue.isPlaying()) {
return interaction.reply({
embeds: [new EmbedBuilder()
.setColor(0xff0000)
.setDescription('Nothing is currently playing.')],
ephemeral: true
});
}
const track = queue.currentTrack;
const progress = queue.node.createProgressBar();
const embed = new EmbedBuilder()
.setColor(0x5865f2)
.setTitle('Now Playing')
.setDescription(`**[${track.title}](${track.url})**\n\n${progress}`)
.setThumbnail(track.thumbnail)
.addFields(
{ name: 'Author', value: track.author, inline: true },
{ name: 'Duration', value: track.duration, inline: true },
{ name: 'Requested By', value: track.requestedBy?.username || 'Unknown', inline: true }
)
.setFooter({ text: `Volume: ${queue.node.volume}%` });
return interaction.reply({ embeds: [embed] });
}
if (subcommand === 'queue') {
if (!queue || !queue.isPlaying()) {
return interaction.reply({
embeds: [new EmbedBuilder()
.setColor(0xff0000)
.setDescription('The queue is empty.')],
ephemeral: true
});
}
const current = queue.currentTrack;
const tracks = queue.tracks.toArray().slice(0, 10);
let description = `**Now Playing:**\n[${current.title}](${current.url}) - \`${current.duration}\`\n\n`;
if (tracks.length > 0) {
description += '**Up Next:**\n';
description += tracks.map((track, i) =>
`**${i + 1}.** [${track.title}](${track.url}) - \`${track.duration}\``
).join('\n');
if (queue.tracks.size > 10) {
description += `\n\n*...and ${queue.tracks.size - 10} more tracks*`;
}
} else {
description += '*No more tracks in queue*';
}
const embed = new EmbedBuilder()
.setColor(0x5865f2)
.setTitle(`Queue for ${interaction.guild.name}`)
.setDescription(description)
.setFooter({ text: `Total: ${queue.tracks.size + 1} tracks | Volume: ${queue.node.volume}%` });
return interaction.reply({ embeds: [embed] });
}
if (!queue || !queue.isPlaying()) {
return interaction.reply({
embeds: [new EmbedBuilder()
.setColor(0xff0000)
.setDescription('No music is currently playing.')],
ephemeral: true
});
}
if (memberVoice?.id !== botVoice?.id) {
return interaction.reply({
embeds: [new EmbedBuilder()
.setColor(0xff0000)
.setDescription('You need to be in the same voice channel as the bot.')],
ephemeral: true
});
}
switch (subcommand) {
case 'skip': {
const current = queue.currentTrack;
queue.node.skip();
return interaction.reply({
embeds: [new EmbedBuilder()
.setColor(0x5865f2)
.setDescription(`Skipped **${current.title}**`)]
});
}
case 'stop': {
queue.delete();
return interaction.reply({
embeds: [new EmbedBuilder()
.setColor(0x5865f2)
.setDescription('Stopped playback and cleared the queue.')]
});
}
case 'pause': {
if (queue.node.isPaused()) {
return interaction.reply({
embeds: [new EmbedBuilder()
.setColor(0xff0000)
.setDescription('The player is already paused.')],
ephemeral: true
});
}
queue.node.pause();
return interaction.reply({
embeds: [new EmbedBuilder()
.setColor(0x5865f2)
.setDescription('Paused the player.')]
});
}
case 'resume': {
if (!queue.node.isPaused()) {
return interaction.reply({
embeds: [new EmbedBuilder()
.setColor(0xff0000)
.setDescription('The player is not paused.')],
ephemeral: true
});
}
queue.node.resume();
return interaction.reply({
embeds: [new EmbedBuilder()
.setColor(0x5865f2)
.setDescription('Resumed playback.')]
});
}
case 'volume': {
const level = interaction.options.getInteger('level');
queue.node.setVolume(level);
return interaction.reply({
embeds: [new EmbedBuilder()
.setColor(0x5865f2)
.setDescription(`Volume set to **${level}%**`)]
});
}
case 'shuffle': {
queue.tracks.shuffle();
return interaction.reply({
embeds: [new EmbedBuilder()
.setColor(0x5865f2)
.setDescription('Shuffled the queue.')]
});
}
case 'loop': {
const mode = interaction.options.getString('mode');
const { QueueRepeatMode } = require('discord-player');
const modes = {
off: QueueRepeatMode.OFF,
track: QueueRepeatMode.TRACK,
queue: QueueRepeatMode.QUEUE
};
queue.setRepeatMode(modes[mode]);
return interaction.reply({
embeds: [new EmbedBuilder()
.setColor(0x5865f2)
.setDescription(`Loop mode set to **${mode}**`)]
});
}
}
}
};