I am working on a Discord bot that can search and play music from YouTube. The basic functionality works fine - I can search for songs and play them in voice channels. However, I need help setting up a proper queue system that automatically plays the next song when the current one finishes.
Here’s my current implementation:
const CLIENT_KEY = "<your-api-key>";
var discordjs = require("discord.js");
var ytdlcore = require('ytdl-core');
var httprequest = require('superagent');
var client = new discordjs.Client();
var activeVoiceChannel = null;
var musicQueue = [];
client.on('ready', function() {
console.log('Bot is online');
});
client.on('message', function(msg) {
var cmdParts = msg.content.split(' ');
var cmd = cmdParts[0].toLowerCase();
var args = cmdParts.splice(1, cmdParts.length);
switch (cmd) {
case "hello":
msg.reply("Hi there!");
break;
case "!commands":
ShowHelp(msg);
break;
case "!connect":
ConnectToVoice(args[0], msg);
break;
case "!music":
SearchAndPlay(args.join(" "), msg);
break;
}
});
function ShowHelp(message) {
message.reply("!connect <voice-channel> - Bot joins specified voice channel");
message.reply("!music <search-query> - Searches and queues music from YouTube");
}
function SearchAndPlay(query) {
FindYouTubeVideo(query);
}
function ConnectToVoice(channelName) {
if (activeVoiceChannel) {
activeVoiceChannel.disconnect();
}
var targetChannel = FindVoiceChannel(channelName);
return targetChannel.join();
}
function FindVoiceChannel(channelName) {
return client.channels.find(ch => ch.name === channelName);
}
function FindYouTubeVideo(searchQuery) {
var apiUrl = 'https://www.googleapis.com/youtube/v3/search' + `?part=snippet&q=${escape(searchQuery)}&key=${CLIENT_KEY}`;
httprequest(apiUrl, (err, resp) => {
if (!err && resp.statusCode == 200) {
var data = resp.body;
for (var result of data.items) {
if (result.id.kind === 'youtube#video') {
AddToQueue(result.id.videoId);
}
}
}
});
}
function AddToQueue(videoId) {
var videoUrl = `https://www.youtube.com/watch?v=${videoId}`;
musicQueue.push(videoUrl);
}
function StartPlayback(url) {
const playOptions = {seek: 0, volume: 0.8};
if (url) {
const audioStream = ytdlcore(url, {filter: 'audioonly'});
const playDispatcher = client.voiceConnections.first().playStream(audioStream, playOptions);
}
}
client.login("<bot-token>");
The main problem is detecting when a song ends so I can automatically start the next one in the queue. I tried using the ‘speaking’ event but it doesn’t work properly since the voice channel isn’t set up when the bot starts. Any suggestions on how to properly handle this queue system?