const { SlashCommandBuilder, EmbedBuilder } = require('discord.js'); module.exports = { data: new SlashCommandBuilder() .setName('play') .setDescription('Joue une musique dans le salon vocal') .addStringOption(option => option .setName('requete') .setDescription('Nom ou URL de la musique à jouer') .setRequired(true) .setAutocomplete(true) ), async autocomplete(interaction) { const focusedValue = interaction.options.getFocused(); try { const node = interaction.client.lavalink.nodeManager.leastUsedNodes()[0]; if (!node) { return interaction.respond([ { name: '❌ Système musical indisponible', value: 'error' } ]); } let searchQuery = focusedValue.trim(); if (!searchQuery || searchQuery.length < 1) { searchQuery = 'top songs 2024'; } const res = await node.search( { query: `ytmsearch:${searchQuery}` }, interaction.user ); if (!res || !res.tracks || res.tracks.length === 0) { return interaction.respond([ { name: `🔍 Aucun résultat pour "${searchQuery}" - Essayez autre chose`, value: searchQuery } ]); } const choices = res.tracks.slice(0, 25).map(track => { let name = track.info.title; if (track.info.author && track.info.author !== 'Unknown artist') { name += ` - ${track.info.author}`; } const duration = formatDuration(track.info.duration); name += ` [${duration}]`; if (name.length > 100) { name = name.substring(0, 97) + '...'; } return { name: name, value: track.info.uri || `https://www.youtube.com/watch?v=${track.info.identifier}` }; }); await interaction.respond(choices); } catch (error) { console.error('❌ Erreur autocomplétion:', error); await interaction.respond([ { name: '❌ Erreur de recherche - Réessayez', value: 'error' } ]); } }, async execute(interaction) { const query = interaction.options.getString('requete'); const memberVoiceChannel = interaction.member.voice.channel; if (!memberVoiceChannel) { return interaction.reply({ content: '❌ Vous devez être dans un salon vocal !', ephemeral: true }); } if (query === 'error') { return interaction.reply({ content: '❌ Veuillez réessayer votre recherche.', ephemeral: true }); } const nodes = interaction.client.lavalink.nodeManager.nodes; if (!nodes || nodes.size === 0) { return interaction.reply({ content: '❌ Le système de musique n\'est pas disponible. Veuillez réessayer plus tard.', ephemeral: true }); } await interaction.deferReply(); try { let player = interaction.client.lavalink.getPlayer(interaction.guildId); if (!player) { player = await interaction.client.lavalink.createPlayer({ guildId: interaction.guildId, voiceChannelId: memberVoiceChannel.id, textChannelId: interaction.channelId, selfDeaf: true, selfMute: false, volume: 100 }); } // ✅ CORRECTION : Toujours vérifier et reconnecter si nécessaire const botVoiceState = interaction.guild.members.me.voice; if (!botVoiceState.channelId || botVoiceState.channelId !== memberVoiceChannel.id) { console.log('🔌 Connexion au salon vocal...'); console.log('📊 État actuel:', { botChannel: botVoiceState.channelId, targetChannel: memberVoiceChannel.id, playerVoiceId: player.voiceChannelId }); await player.connect(); // Attendre que Discord établisse la connexion let attempts = 0; while (attempts < 10) { await new Promise(resolve => setTimeout(resolve, 500)); const newVoiceState = interaction.guild.members.me.voice; if (newVoiceState.channelId === memberVoiceChannel.id) { console.log('✅ Bot connecté au salon vocal !'); break; } attempts++; console.log(`⏳ Attente connexion... (${attempts}/10)`); } if (!interaction.guild.members.me.voice.channelId) { console.error('❌ Le bot n\'a pas pu se connecter au salon vocal'); return interaction.editReply('❌ Impossible de se connecter au salon vocal. Vérifiez mes permissions.'); } console.log('📊 État après connexion:', { botChannel: interaction.guild.members.me.voice.channelId, playerVoiceId: player.voiceChannelId, sessionId: interaction.guild.members.me.voice.sessionId }); } else { console.log('✅ Bot déjà connecté au salon vocal'); } const isUrl = /^https?:\/\//.test(query); console.log('🔍 Recherche:', query); console.log('📌 Type:', isUrl ? 'URL' : 'Recherche'); let res; if (isUrl) { res = await player.search({ query }, interaction.user); if (res.loadType === 'error' || !res.tracks || res.tracks.length === 0) { console.log('⚠️ Échec avec URL directe, essai avec ytsearch...'); res = await player.search({ query: `ytsearch:${query}` }, interaction.user); } } else { const searchQuery = `ytmsearch:${query}`; res = await player.search({ query: searchQuery }, interaction.user); } console.log('📊 Résultats:', { loadType: res.loadType, tracks: res.tracks?.length || 0, playlist: res.playlist?.name || 'N/A', exception: res.exception || 'N/A' }); if (res.loadType === 'error') { console.error('❌ Erreur Lavalink:', res.exception); return interaction.editReply( `❌ Erreur lors de la recherche de la musique.\n` + `**Détails:** ${res.exception?.message || 'Erreur inconnue'}\n\n` + `💡 **Solutions possibles:**\n` + `• Vérifiez que Lavalink est bien démarré\n` + `• Vérifiez que le plugin YouTube est installé\n` + `• Essayez avec une autre musique` ); } if (!res || !res.tracks || res.tracks.length === 0) { console.log('❌ Aucune piste trouvée'); return interaction.editReply('❌ Aucune musique trouvée ! Essayez une autre recherche.'); } if (res.loadType === 'playlist') { for (const track of res.tracks) { track.requester = interaction.user; player.queue.add(track); } const playlistEmbed = new EmbedBuilder() .setColor('#00FF00') .setTitle('📋 Playlist ajoutée') .setDescription(`**${res.playlist.name}**`) .addFields( { name: '🎵 Pistes', value: `${res.tracks.length}`, inline: true }, { name: '👤 Demandé par', value: `${interaction.user}`, inline: true } ) .setTimestamp(); if (!player.playing && !player.paused) { await player.play(); } return interaction.editReply({ embeds: [playlistEmbed] }); } const track = res.tracks[0]; track.requester = interaction.user; console.log('🎵 Piste sélectionnée:', { title: track.info.title, author: track.info.author, uri: track.info.uri, identifier: track.info.identifier, isSeekable: track.info.isSeekable, isStream: track.info.isStream }); player.queue.add(track); console.log('✅ Piste ajoutée à la queue'); console.log('📊 État du player avant play:', { playing: player.playing, paused: player.paused, voiceChannelId: player.voiceChannelId, queueSize: player.queue.tracks.length }); const trackEmbed = new EmbedBuilder() .setColor('#9b59b6') .setTitle(player.playing ? '✅ Ajouté à la file' : '🎵 Lecture en cours') .setDescription(`**[${track.info.title}](${track.info.uri})**`) .addFields( { name: '🎤 Artiste', value: track.info.author || 'Inconnu', inline: true }, { name: '⏱️ Durée', value: formatDuration(track.info.duration), inline: true }, { name: '👤 Demandé par', value: `${interaction.user}`, inline: true } ) .setThumbnail(track.info.artworkUrl || `https://img.youtube.com/vi/${track.info.identifier}/maxresdefault.jpg`) .setTimestamp(); if (player.playing) { trackEmbed.addFields( { name: '📊 Position dans la file', value: `${player.queue.tracks.length}`, inline: true } ); } if (!player.playing && !player.paused) { console.log('▶️ Tentative de démarrage de la lecture...'); try { await player.play(); console.log('✅ player.play() exécuté avec succès'); console.log('📊 État du player après play:', { playing: player.playing, paused: player.paused, voiceChannelId: player.voiceChannelId, position: player.position, volume: player.volume }); } catch (playError) { console.error('❌ Erreur lors de player.play():', playError); return interaction.editReply('❌ Erreur lors du démarrage de la lecture.'); } } return interaction.editReply({ embeds: [trackEmbed] }); } catch (error) { console.error('❌ Erreur lors de la lecture:', error); return interaction.editReply( '❌ Une erreur est survenue lors de la lecture de la musique.\n' + `**Détails:** ${error.message}` ); } } }; function formatDuration(ms) { const seconds = Math.floor((ms / 1000) % 60); const minutes = Math.floor((ms / (1000 * 60)) % 60); const hours = Math.floor(ms / (1000 * 60 * 60)); if (hours > 0) { return `${hours}:${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`; } return `${minutes}:${seconds.toString().padStart(2, '0')}`; }