I'm trying to create a Discord Music Bot with discord.js and the Distube Framework, the code is fine and I don't have any errors, but as soon as I try to play a music with my command ("/play song"), the bot joins the channel and sends the embed, but instantly state the music as finished and never plays it.
Here is my code:
App.js
const Distube = require("distube")
const { SoundCloudPlugin } = require("@distube/soundcloud")
const { SpotifyPlugin } = require("@distube/spotify")
/* eslint new-cap: ["error", { "properties": false }] */
client.distube = new Distube.default(client, {
leaveOnEmpty: true,
emptyCooldown: 30,
leaveOnFinish: false,
emitNewSongOnly: true,
updateYouTubeDL: true,
nsfw: true,
youtubeCookie: process.env.ytcookie,
plugins: [new SoundCloudPlugin(), new SpotifyPlugin()]
})
const status = (queue) => `Volume: \`${queue.volume}%\` | Loop: \`${queue.repeatMode ? queue.repeatMode === 2 ? "All Queue" : "This Song" : "Off"}\` | Autoplay: \`${queue.autoplay ? "On" : "Off"}\` | Filter: \`${queue.filters.join(", ") || "Off"}\``
client.distube
.on("playSong", (queue, song) => { //command to play a song
const embed = new MessageEmbed()
.setColor("RANDOM")
.setAuthor("Started Playing", "https://raw.githubusercontent.com/HELLSNAKES/Music-Slash-Bot/main/assets/music.gif")
.setThumbnail(song.thumbnail)
.setDescription(`[${song.name}](${song.url})`)
.addField("**Views:**", song.views.toString(), true)
.addField("**Like:**", song.likes.toString(), true)
.addField("**Duration:**", song.formattedDuration.toString(), true)
.addField("**Status**", status(queue).toString())
.setFooter(`Requested by ${song.user.username}`, song.user.avatarURL())
.setTimestamp()
queue.textChannel.send({ embeds: [embed] })
})
play.js
module.exports = {
name: "play",
description: "Playing music",
options: [
{
name: "query",
type: 3,
description: "The song you want to play | Supported url: youtube,soundcloud,spotify",
required: true
}
],
timeout: 5000,
run: async (interaction, client) => {
const voiceChannel = interaction.member.voice.channel
const queue = await client.distube.getQueue(interaction)
const query = interaction.options.get("query").value
if (!voiceChannel) {
return interaction.reply({ content: "Please join a voice channel!", ephemeral: true })
}
if (queue) {
if (interaction.member.guild.me.voice.channelId !== interaction.member.voice.channelId) {
return interaction.reply({ content: "You are not on the same voice channel as me!", ephemeral: true })
}
}
await interaction.reply("**Searching and attempting...**")
await interaction.editReply("Searching done :ok_hand: ")
client.distube.play(voiceChannel, query, { //Should play the song
textChannel: interaction.channel,
member: interaction.member
})
}
}
This is an issue caused by the delay between calling a song and actually starting to play it if leaveOnFinish
is toggled on. It can be fixed by setting leaveOnFinish
to false and then waiting a bit after the queue has ended to disconnect the bot. Here's how I have setup my bot to leave 2 minutes after the final song is played.
setTimeout(async () => {
if (!queue.textChannel.guild.me.voice.channelId) {
return clearTimeout();
}
let queue_music = await client.distube.getQueue(queue.voiceChannel);
if (queue_music !== undefined && queue_music.playing) {
clearTimeout();
} else if (queue_music == undefined || queue_music.songs.length === 0) {
queue.textChannel
.send({
embeds: [
new MessageEmbed()
.setDescription("Finished!")
],
})
.catch(() => { })
queue.stop(client.voice.channel)
}
}, 120000)