机器人加入公会的所有语音频道并播放文件

Posted

技术标签:

【中文标题】机器人加入公会的所有语音频道并播放文件【英文标题】:Bot join and play file across all voice channels in a guild 【发布时间】:2019-06-18 01:10:00 【问题描述】:

我最近一直在制作我的第一个不和谐机器人,今天我遇到了一个小要求的问题。 我需要我的机器人连接到服务器的所有语音通道并播放 mp3 文件。这是一条警报消息。

我首先用这个代码做了一个基本的测试,在启动命令的用户连接的频道中播放 mp3:

exports.run = async (client, message, args, level) => 
  if (message.member.voiceChannel) 
    message.member.voiceChannel.join()
    .then(connection => 
        const dispatcher = connection.playFile('/home/pi/.discordbots/TARVIS/1.mp3');
        dispatcher.on("end", end => message.member.voiceChannel.leave());
    )
    .catch(console.error);
  
;

上面的代码运行良好

所以我尝试为所有语音频道制作它:

  let voiceChannels = message.guild.channels.filter(channel => channel.type == 'voice');

  voiceChannels.forEach(channel =>
    channel.join()
      .then(connection => 
        const dispatcher = connection.playFile('/home/pi/.discordbots/TARVIS/1.mp3');
        dispatcher.on("end", end =>  channel.leave() );
      )
      .catch(console.error)
  );

问题是机器人连接到第一个通道,然后直接连接到第二个,而没有时间播放第一个通道中的文件。

我想我必须看看client.createVoiceBroadcast(); 方法。我尝试使用它,但找不到一个很好的例子。这是我尝试过的,但它也不起作用:

exports.run = (client, message, args, level) => 
  let voiceChannels = message.guild.channels.filter(channel => channel.type == 'voice');
  const broadcast = client.createVoiceBroadcast();
  broadcast.playFile('/home/pi/.discordbots/TARVIS/1.mp3');

  voiceChannels.forEach(channel =>
    channel.join()
      .then(connection => 
        const dispatcher = connection.playBroadcast(broadcast);
        dispatcher.on("end", end =>  channel.leave() );
      )
      .catch(console.error)
  );

预期的结果是机器人在每个语音通道中一个接一个地连接并播放 mp3 文件。

提前感谢您的帮助

编辑

我尝试创建一个异步函数并在 connection.playFile() 上使用 await,但我仍然遇到同样的问题。 Bot 连接到所有语音通道,但不等待文件播放。

这是我试过的代码:

exports.run = async (client, message, args, level) => 

  async function play(voiceChannel) 
    console.log(voiceChannel.name + ` Type:` + voiceChannel.type + ` (` + voiceChannel.id + `)`);
    voiceChannel.join().then(async function (connection) 
      dispatcher = await connection.playFile('/home/pi/.discordbots/TARVIS/sncf.mp3');
      dispatcher.on('end', function () 
        voiceChannel.leave()
      );
    );
  
  let voiceChannels = message.guild.channels.filter(channel => channel.type == 'voice');

  voiceChannels.map(vc => play(vc));

;

我很确定解决方案就在附近……但我被困住了……有人可以帮我找到正确的语法吗?

编辑 2

这是我对您的解决方案的尝试:

exports.run = async (client, message, args, level) => 

  async function play(voiceChannels) 
    for (let channel of voiceChannels) 
      console.log('Joining channel ' + channel.name);

      await channel.join().then(async (connection) => 
        console.log('Joined channel');

        let dispatcher = connection.playFile('/home/pi/.discordbots/TARVIS/sncf.mp3');
        await dispatcher.on('end', function () 
          channel.leave();
        );
      );
    
  

  let channels = message.guild.channels.filter(channel => channel.type == 'voice');
  console.log(channels);
  play(channels);

;

【问题讨论】:

也许this answer 可能有助于检查 谢谢@T.Dirks 我看了看,是的,我认为它与 async/await 有关,但找不到正确的语法。我会尝试用这个答案来调整我的代码 我仍在努力让它工作我看到p-iteration 可能会帮助我。我会试试看,但我很想知道如何在本机中做到这一点 【参考方案1】:

我可能已经(在某种程度上)找到了解决方案。我尝试在 JSFiddle 中重新创建此问题,以便更轻松地对其进行测试。 Here is my solution.

核心代码在函数joinChannels中,也可以在下面看到

async function joinChannels () 
  for (let channel of channels) 
    await new Promise((resolve) => 
      console.log('Joining channel ' + channel.name);

      resolve(new Promise((resolve) => 
        setTimeout(() => 
          console.log('Done with channel ' + channel.name);
          resolve();
        , 1000);
      ));
    );
  

 

现在要根据您的上下文将其重写为解决方案,这是我的尝试(未经测试,因此可能需要一些调整)

async function play(voiceChannels) 
  for (let channel of voiceChannels) 
    console.log('Joining channel ' + channel.name);

    await channel.join().then(async (connection) => 
      console.log('Joined channel');

      let dispatcher = connection.playFile('/home/pi/.discordbots/TARVIS/sncf.mp3');
      await dispatcher.on('end', function () 
        voiceChannel.leave();
      );
    );
  

试一试,让我知道结果如何。如果您有任何问题,我很乐意为您提供帮助

【讨论】:

我对你的代码做了一些修改。我用新代码更新了我的第一篇文章。我现在得到这个错误:TypeError: channel.join(...).then is not a function 在调用play()之前,我登录了channels,它是公会的集合,我还在for()之前登录了voiceChannels,它还包含频道的集合。现在看来问题出在循环上 我在函数参数中添加了voiceChannels...因为我认为它来自这里,也许这是一个坏主意...我仍在尝试使用此代码。有了你的帮助,我现在更有信心了 抱歉,我没能做到async...但我找到了一个解决方法(我的解决方案将作为答案发布)我花了几个小时试图让它工作,但我的主要问题是在for (let channel of voiceChannels) channel 内是undefined。我试图从函数中提取 for 并为每个通道调用函数,但我尝试的一切都不起作用......在总是未定义的范围内......我找到了 setTimeout【参考方案2】:

这是我的解决方法。 我使用setTimeout将频道语音排入队列,计时器为 10 秒 我知道有点脏,但它可以工作

exports.run = async (client, message, args, level) => 

  async function play(channel) 
    await channel.join().then(async (connection) => 
      let dispatcher = await connection.playFile('/home/pi/.discordbots/TARVIS/offline.m4a');
      await dispatcher.on('end', function () 
        channel.leave();
      );
    );
  

  let timer = 1000;
  client.ShowSuccess('Démarrage des annonces vocales');
  message.guild.channels.forEach(async (channel) => 
    if (channel.type == 'voice' && channel.members.size > 0) 
      client.ShowSuccess('Annonce dans le salon ' + channel.name + ' pour ' + channel.members.size + ' membre(s)', message.channel);
      client.logger.log('Annonce dans le salon ' + channel.name + ' pour ' + channel.members.size + ' membre(s)');
      setTimeout(function () 
        play(channel);
      , timer);
      timer = timer + 10000;
    
  );
  setTimeout(function () 
    client.ShowSuccess('Annonces vocales terminées');
  , timer);
;

【讨论】:

以上是关于机器人加入公会的所有语音频道并播放文件的主要内容,如果未能解决你的问题,请参考以下文章

Discord.js 机器人无法离开语音频道

Discord.py music_cog,机器人加入频道但不播放声音

如何让我的 discord.py 机器人在语音频道中播放 mp3?

Bot 在离开前未完成播放音频

需要一个关于将播放器保存在列表 discord.py 机器人上的问题的想法

客户端连接但不会在 Discord 语音频道中播放音乐