Endxxr
Endxxr

Reputation: 37

Discord Bot leave the VC after X Seconds with Discord.js

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

Answers (1)

Zem
Zem

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

Related Questions