const { Client, Interaction, Member } = require("discord.js"); const { joinVoiceChannel, createAudioPlayer, createAudioResource, NoSubscriberBehavior, AudioPlayerStatus, } = require("@discordjs/voice"); const ytdl = require("@distube/ytdl-core"); const { nowPlayingEmbed } = require("./embeds/nowPlaying"); const queue = []; const activeChannels = {}; let stopped = false; let timeout; /** * * @param {Client} client * @param {Interaction} interaction */ function resetAll(guildId) { //console.log(`Resetting all: ${guildId}`) queue.length = 0; cancelTimer() const connection = activeChannels[guildId] if (connection) { connection.destroy() // console.log('Conection Destroyed') } delete activeChannels[guildId] stopped = false //console.log('All States reset') } function startTimer(connection) { console.log(`Disconnect timer started `); timeout = setTimeout(() => { connection.destroy(); }, 30_000); } function cancelTimer() { if (timeout) { clearTimeout(timeout); console.log("Disconnect timer stopped"); timeout = null; } } async function playFromQueue( voiceChannel, textChannel, getMemeber, videoUrl, videoTitle ) { if (queue.length === 0) { if (textChannel && activeChannels[voiceChannel.id] === textChannel.id) { textChannel.send("Queue has finished playing."); delete activeChannels[voiceChannel.id]; } return; } //console.log("Current queue: ", queue) const { interaction, link, songName } = queue[0]; try { let connection = activeChannels[interaction.guild.id]; // Join the voice channel if (!connection) { connection = joinVoiceChannel({ channelId: voiceChannel.id, guildId: interaction.guild.id, adapterCreator: interaction.guild.voiceAdapterCreator, }); activeChannels[interaction.guild.id] = connection; } // Stream audio using ytdl-core const stream = ytdl(videoUrl, { filter: "audioonly", highWaterMark: 1 << 25, // Larger buffer size quality: "highestaudio", requestOptions: { headers: { Connection: "keep-alive" }, }, }); const resource = createAudioResource(stream, { inlineVolume: true }); resource.volume.setVolume(1); // Set volume to 1 (max) const player = createAudioPlayer({ behaviors: { noSubscriber: NoSubscriberBehavior.Play, }, }); player.play(resource); connection.subscribe(player); player.on(AudioPlayerStatus.Playing, () => { if (startTimer) { cancelTimer() } else { console.log('No timer running') } }) player.on(AudioPlayerStatus.Idle, () => { //console.log('The audio player is idle.'); if (stopped) { console.log("Playback was stopped by user"); return; } queue.shift(); if (queue.length > 0) { const nextsong = queue[0]; playFromQueue( voiceChannel, textChannel, nextsong.getMember, nextsong.link, nextsong.songName ); } else { textChannel.send("The queue is empty."); if (connection) { startTimer(connection); } else { return; } } }); if (interaction.replied || interaction.deferred) { const embed = nowPlayingEmbed(queue); await interaction.followUp({ embeds: [embed] }); } else { const embed = nowPlayingEmbed(queue); await interaction.reply({ embeds: [embed] }); } // Handle errors player.on("error", (error) => { console.error("Error with the audio player:", error); interaction.followUp({ content: "There was an error playing the music.", ephemeral: true, }); }); } catch (error) { console.error("Error in playback.js: ", error); } } module.exports = { playFromQueue, queue, cancelTimer, setStopped: (value) => { stopped = value; }, getConnection: (guildId) => activeChannels[guildId], // Helper to get connection resetAll, };