Reputation: 37
Heyy,
Im building a Discord Bot for do some practice with Node.js and Discord.js. With this bot you can do the command ?audio audio and it will reproduce a audio.
I want to set that the bot after 20 seconds of not playing anything leave the Voice Channel. I did it with the function setTimeout() but when I want to listen another audio the bot leave the channel before the audio finish.
The problem is obv the setTimeout() but idk how to fix it.
Here's my code.
execute(message, args, CanaleVocale, AudioFiles) {
let inactive
let name = args[1] + ".mp3";
console.log("[Command] ?audio " + message.author.id)
if (!CanaleVocale) {
message.channel.send("Il Koala e' confuso, non ti vede in nessun canale vocale :( ")
console.log(`[Voice] The user ${message.author.id} isn't in a voice channel` )
} else {
if (AudioFiles.includes(name)) {
CanaleVocale.join()
.then(connection => {
clearTimeout(inactive)
inactive = undefined
connection.voice.setSelfDeaf(true);
connection.play(`./audio/${name}`)
console.log(`[Voice] Played the sound ${name} for the user ${message.author} `)
inactive = setTimeout(function(){
CanaleVocale.leave()
console.log(`[Voice] Left from the channel of ${message.author.id}`)
message.channel.send("Il Koala e' annoiato e quindi esce dalla chat vocale")
}, 20*1000)
})
} else {
message.channel.send(`L'audio ${name} non esiste!`)
console.log(`[Voice] The user ${message.author} tried to play ${name} but it doesn't exist!`)
}
}
}
}
If you need the entire project, it is uploaded on GitHub, "KoalaBot" by EnderF5027 (Probably the code is ugly, im learning and if you want to, you can give me some suggestions :D )
Can someone help me ? Thank you
Upvotes: 1
Views: 2702
Reputation: 474
I attach my code for example.
I handle not file base, only youtube with ytdl.
So, It could be differect with questions.
I handle joined channels with Map()
Object.
// message.guild.id = '1234567812345678'
const queue = new Map();
// 1. set new queue
const queueContruct = {
textChannel: message.channel,
voiceChannel: voiceChannel,
connection: null,
songs: [],
search: [],
volume: 5,
playing: true,
leaveTimer: null /* 20 seconds in question */
};
queue.set('1234567812345678', queueContruct);
// 2. get queueContruct from queue
const serverQueue = queue.get('1234567812345678');
if(!serverQueue) { /* not exist */ }
// 3. delete from queue
queue.delete('1234567812345678');
I set timer with setTimeout
when play-list is empty
and unset with clearTimeout
when new play-list is come in.
Under is a piece of my code.
I wish this will be helpful.
const Discord = require('discord.js');
const bot = new Discord.Client();
const queue = new Map();
const prefix = "?"; // this prefix is in Question.
bot.on("message", async message => {
// if direct-message received, message.guild could be null
// Not handle that case.
const serverQueue = queue.get(message.guild.id);
if(message.content.startsWith(`${prefix}audio`)) {
execute(message, serverQueue);
}
});
// I assume user message is "?audio audioName"
function execute(message, serverQueue) {
const audioName = message.content.split(' ')[1]; // "audioName"
// check user who send message is in voiceChannel
const voiceChannel = message.member.voice.channel;
if(!voiceChannel) {
return message.channel.send("YOU ARE NOT IN VOICE CHANNEL");
}
// check permission
const permissions = voiceChannel.permissionsFor(message.client.user);
if (!permissions.has("CONNECT") || !permissions.has("SPEAK")) {
return message.channel.send("PERMISSION ERROR");
}
/*
I handle only songs with google youtube api
So, I skip how to get & push song information
*/
if(!serverQueue) {
// create new serverQueue
const queueContruct = {
textChannel: message.channel,
voiceChannel: voiceChannel,
connection: null,
songs: [],
search: [],
volume: 5,
playing: true
};
queue.set(message.guild.id, queueContruct);
// "song" value is one of play list in my case
// var song = {title: 'audioName', url: 'youtube-url'};
queueContruct.songs.push(song);
try {
var connection = await voiceChannel.join();
queueContruct.connection = connection;
playStart(message.guild, queueContruct.songs[0]);
} catch (err) {
queue.delete(message.guild.id);
return message.channel.send(err);
}
}
else { // exist serverQueue
// "song" value is one of play list in my case
// var song = {title: 'audioName', url: 'youtube-url'};
serverQueue.songs.push(song);
if(serverQueue.songs.length == 1) {
playStart(message.guild, serverQueue.songs[0]);
}
}
}
function play(guild, song) {
const serverQueue = queue.get(guild.id);
if(!song) {
if(serverQueue.songs.length == 0) {
serverQueue.leaveTimer = setTimeout(function() {
leave_with_timeout(guild.id);
}, 20 * 1000); // 20 seconds is for follow question
}
return;
}
// clear timer before set
try {
clearTimeout(serverQueue.leaveTimer);
} catch(e) {
// there's no leaveTimer
}
const dispatcher = serverQueue.connection
.play(ytdl(song.url))
.on('finish', () => {
serverQueue.songs.shift(); // pop front
play(guild, serverQueue.songs[0]); // play next
})
.on('error' error => console.log(error));
dispatcher.setVolumeLogarithmic( 1 );
serverQueue.textChannel.send(`Play Start ${song.title}`);
}
function leave_with_timeout(guild_id) {
const serverQueue = queue.get(guild_id);
if(serverQueue) {
serverQueue.textChannel.send(`20 seconds left. Bye!`);
serverQueue.voiceChannel.leave();
queue.delete(guild_id);
}
}
Upvotes: 2