Discord Bot 在 X 秒后使用 Discord.js 离开 VC

时间:2021-04-26 17:26:37

标签: javascript node.js discord discord.js bots

嘿,

我正在构建一个 Discord Bot,用于使用 Node.js 和 Discord.js 进行一些练习。使用此机器人,您可以执行 ?audio audio 命令,它会重现音频。

我想设置机器人在 20 秒不播放任何内容后离开语音频道。我用函数 setTimeout() 做到了,但是当我想听另一个音频时,机器人在音频结束之前离开了频道。

问题出在 setTimeout() 上,但不知道如何解决。

这是我的代码。

stack uninstall

如果需要整个项目,由EnderF5027上传到GitHub,“KoalaBot” (可能代码很丑,我正在学习,如果您愿意,可以给我一些建议:D)

有人可以帮我吗? 谢谢

1 个答案:

答案 0 :(得分:2)

我附上了我的代码。
我不处理文件库,只处理带有 ytdl 的 youtube。
所以,问题可能会有所不同。

我使用 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');

当播放列表为空时,我用 setTimeout 设置计时器
并在新播放列表出现时取消设置 clearTimeout

下面是我的一段代码。
我希望这会有所帮助。

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);
  }
}