【问题标题】:Queuing audio to play via Discord Bot排队通过 Discord Bot 播放音频
【发布时间】:2017-03-05 04:40:40
【问题描述】:

目前,我一直在为 Discord 编写一个机器人。

我已经设法让它根据给定的搜索字词查询 YouTube,然后从顶部结果中播放音频,但是当我尝试在列表中对音轨进行排队并播放一次音频时遇到了一个问题流已完成。

const API_KEY = "<my API Key>";

var discord = require("discord.js");
var ytdl = require('ytdl-core');
var request = require('superagent');

var bot = new discord.Client();
var voiceChannel = null;
var ytAudioQueue = [];

bot.on('ready', function() {
    console.log('I am ready');
});

bot.on('message', function(message) {
    var messageParts = message.content.split(' ');

    var command = messageParts[0].toLowerCase();
    var parameters = messageParts.splice(1, messageParts.length);

    console.log("command: " + command);
    console.log("parameters: " + parameters);

    switch (command) {
        case "hi":
            message.reply("Hey there!");
            break;
        case "*help":
            HelpCommand(message);
            break;
        case "*join":
            message.reply("Attempting to join channel: " + parameters[0]);
            JoinCommand(parameters[0], message);
            break;
        case "*play":
            PlayCommand(parameters.join(" "), message);
            break;
    }
});

voiceChannel.on('speaking', (user, speaking) => {

    // the audio has finished playing, so remove it from the queue and start playing the next song
    if (!speaking && ytAudioQueue.length > 1) {
        ytAudioQueue.pop();

        if (voiceChannel == null) {
            JoinCommand(bot.channels.find(val => val.type === 'voice').name).then(function() {
                PlayStream(ytAudioQueue.first);
            });
        }
        else {
            PlayStream(ytAudioQueue.first);
        }
    }
});

/* COMMAND HANDLERS */

/// lists out all of the bot commands
function HelpCommand(originalMessage) {
    originalMessage.reply("*join <channel-to-join> - Connects to bot to a channel by channel name");
    originalMessage.reply("*play <YouTube search term> - Plays audio from YouTube based on the search term");
}

/// plays audio based on results from youtube search
function PlayCommand(searchTerm) {
    //bot.sendMessage("Searching Youtube for audio...");
    YoutubeSearch(searchTerm);
}

/// joins the bot to the specified voice channel
function JoinCommand(channelName) {

    if (voiceChannel) {
        voiceChannel.disconnet();
    }

    var voiceChannel = GetChannelByName(channelName);
    return voiceChannel.join();
}

/* END COMMAND HANDLERS */

/* HELPER METHODS */

/// returns the channel that matches the name provided
function GetChannelByName(name) {
    var channel = bot.channels.find(val => val.name === name);

    return channel;
}

function YoutubeSearch(searchKeywords) {
    var requestUrl = 'https://www.googleapis.com/youtube/v3/search' + `?part=snippet&q=${escape(searchKeywords)}&key=${API_KEY}`;

    request(requestUrl, (error, response) => {
        if (!error && response.statusCode == 200) {

            var body = response.body;
            if (body.items.length == 0) {
                console.log("Your search gave 0 results");
                return videoId;
            }

            for (var item of body.items) {
                if (item.id.kind === 'youtube#video') {
                    QueueYtAudioStream(item.id.videoId);
                }
            }
        }
        else {
            console.log("Unexpected error when searching YouTube");
            return null;
        }
    });

    return null;
}

/// Queues result of Youtube search into stream
function QueueYtAudioStream(videoId) {
    var streamUrl = `https://www.youtube.com/watch?v=${videoId}`;
    ytAudioQueue.push(streamUrl);
}

// plays a given stream
function PlayStream(streamUrl) {

    const streamOptions = {seek: 0, volume: 1};
    console.log("Streaming audio from " + streamUrl);

    if (streamUrl) {
        const stream = ytdl(streamUrl, {filter: 'audioonly'});
        const dispatcher = bot.voiceConnections.first().playStream(stream, streamOptions);
    }
}

/* END HELPER METHODS */

bot.login("<BOT LOGIN ID HERE>");

https://jsfiddle.net/o3Lvqt94/

我的想法是,一旦 voiceChannel 停止讲话,我就可以开始播放下一个 audioStream,但是由于未在启动时设置,因此事件失败,虽然我可以这样做,但我认为它不适合我的需要,因为语音通道可以用另一个命令来改变。

【问题讨论】:

    标签: javascript audio youtube-api bots discord


    【解决方案1】:

    我使用您的代码作为我自己的 Discord 机器人的基础,并解决了您提到的错误。我只是改变了

    dispatcher.on('end', () => {                        
      PlayNextStreamInQueue();
    });
    

     dispatcher.on('end', () => {                       
       dispatcher = null;                 
       PlayNextStreamInQueue();
     });
    

    【讨论】:

    • 很高兴听到我的代码得到了很好的利用 :) 我会尝试解决这个问题!
    【解决方案2】:

    我的解决方案。

    index.js

    var discord = require("discord.js");        // discord library
    var ytdl = require('ytdl-core');            // youtube download library
    var youtube = require('./youtube.js');      // performs youtube API requests
    
    var bot = new discord.Client();
    var ytAudioQueue = [];
    var dispatcher = null;
    
    bot.on('ready', function () {
        console.log('I am ready');
    });
    
    bot.on('message', function (message) {
        var messageParts = message.content.split(' ');
    
        var command = messageParts[0].toLowerCase();
        var parameters = messageParts.splice(1, messageParts.length);
    
        console.log("command: " + command);
        console.log("parameters: " + parameters);
    
        switch (command) {
            case "hi":
                message.reply("Hey there!");
                break;
            case "*help":
                HelpCommand(message);
                break;
            case "*join":
                message.reply("Attempting to join channel: " + parameters[0]);
                JoinCommand(parameters[0]);
                break;
            case "*play":
                PlayCommand(parameters.join(" "), message);
                break;
            case "*playqueue":
                PlayQueueCommand(message);
                break;
        }
    });
    
    /* COMMAND HANDLERS */
    
    /// lists out all of the bot commands
    function HelpCommand(originalMessage) {
        originalMessage.reply("*join <channel-to-join> - Connects to bot to a channel by channel name");
        originalMessage.reply("*play <YouTube search term> - Plays audio from YouTube based on the search term");
        originalMessage.reply("*playqueue - Lists the audio remaining in the play queue");
    }
    
    /// plays audio based on results from youtube search
    function PlayCommand(searchTerm) {
    
        // if not connected to a voice channel then connect to first one
        if (bot.voiceConnections.array().length == 0) {
            var defaultVoiceChannel = bot.channels.find(val => val.type === 'voice').name;
            JoinCommand(defaultVoiceChannel);
        }
    
        // search youtube using the given search search term and perform callback action if video is found
        youtube.search(searchTerm, QueueYtAudioStream);
    }
    
    /// lists out all music queued to play
    function PlayQueueCommand(message) {
        var queueString = "";
    
        for(var x = 0; x < ytAudioQueue.length; x++) {
            queueString += ytAudioQueue[x].videoName + ", ";
        }
    
        queueString = queueString.substring(0, queueString.length - 2);
        message.reply(queueString);
    }
    
    /// joins the bot to the specified voice channel
    function JoinCommand(channelName) {
        var voiceChannel = GetChannelByName(channelName);
    
        if (voiceChannel) {
            voiceChannel.join();
            console.log("Joined " + voiceChannel.name);
        }
    
        return voiceChannel;
    }
    
    /* END COMMAND HANDLERS */
    /*----------------------------------------------------------------------*/
    /* HELPER METHODS */
    
    /// returns the channel that matches the name provided
    function GetChannelByName(name) {
        var channel = bot.channels.find(val => val.name === name);
        return channel;
    }
    
    /// Queues result of Youtube search into stream
    function QueueYtAudioStream(videoId, videoName) {
        var streamUrl = `${youtube.watchVideoUrl}${videoId}`;
    
        if (!ytAudioQueue.length) {
            ytAudioQueue.push(
                {
                    'streamUrl': streamUrl,
                    'videoName': videoName
                }
            );
    
            console.log("Queued audio " + videoName);
            PlayStream(ytAudioQueue[0].streamUrl);
        }
        else {
            ytAudioQueue.push(
                {
                    'streamUrl': streamUrl,
                    'videoName': videoName
                }
            );
    
            console.log("Queued audio " + videoName);
        }
    
    }
    
    /// Plays a given stream
    function PlayStream(streamUrl) {
    
        const streamOptions = {seek: 0, volume: 1};
    
        if (streamUrl) {
            const stream = ytdl(streamUrl, {filter: 'audioonly'});
    
            if (dispatcher == null) {
    
                var voiceConnection = bot.voiceConnections.first();
                //console.log(voiceConnection);
    
                if (voiceConnection) {
    
                    console.log("Now Playing " + ytAudioQueue[0].videoName);
                    dispatcher = bot.voiceConnections.first().playStream(stream, streamOptions);
    
                    dispatcher.on('end', () => {
                        PlayNextStreamInQueue();
                    });
    
                    dispatcher.on('error', (err) => {
                        console.log(err);
                    });
                }
            }
            else {
                dispatcher = bot.voiceConnections.first().playStream(stream, streamOptions);
            }
        }
    }
    
    /// Plays the next stream in the queue
    function PlayNextStreamInQueue() {
    
        ytAudioQueue.splice(0, 1);
    
        // if there are streams remaining in the queue then try to play
        if (ytAudioQueue.length != 0) {
            console.log("Now Playing " + ytAudioQueue[0].videoName);
            PlayStream(ytAudioQueue[0].streamUrl);
        }
    }
    /* END HELPER METHODS */
    
    bot.login("redacted");
    

    youtube.js

    var request = require('superagent');
    
    const API_KEY = "redacted";
    const WATCH_VIDEO_URL = "https://www.youtube.com/watch?v=";
    
    exports.watchVideoUrl = WATCH_VIDEO_URL;
    
    exports.search = function search(searchKeywords, callback) {
        var requestUrl = 'https://www.googleapis.com/youtube/v3/search' + `?part=snippet&q=${escape(searchKeywords)}&key=${API_KEY}`;
    
        request(requestUrl, (error, response) => {
            if (!error && response.statusCode == 200) {
    
                var body = response.body;
                if (body.items.length == 0) {
                    console.log("Your search gave 0 results");
                    return;
                }
    
                for (var item of body.items) {
                    if (item.id.kind === 'youtube#video') {
                        callback(item.id.videoId, item.snippet.title);
                        return; // prevent adding entire list of youtube videos
                    }
                }
            }
            else {
                console.log("Unexpected error when searching YouTube");
                return;
            }
        });
    
        return;
    };
    

    【讨论】:

    • 此解决方案仍有一些错误,有时排队的音频播放,有时不播放。我不确定逻辑有什么问题。
    【解决方案3】:

    我会说将队列保存在数组中

    var que = {
      0 = "LINK";
    };
    

    然后你使用

    que[0]
    

    自动排队

    function skip() {
      for (var i = 0; var length = que.length; i < length; i++) {
        if (i != length) {
          que[i] = que[(i+1)];
        } else {
          que[i] = null;
        }
      }
    }
    

    显示队列

    function showque() {
      var queText = "";
      for (var i = 0; var length = que.length; i < length; i++) {
        queText = queText + "[" + i + "] " + que[i] + "\n";
      }
      return queText;
    }
    

    要发送的消息片段

    message("ANYTHING BEFORE THE QUE\n" + showque() + "ANYTHING AFTER");
    

    希望应该可以工作。

    【讨论】:

      猜你喜欢
      • 2021-11-18
      • 2018-05-17
      • 2021-10-29
      • 1970-01-01
      • 2021-11-07
      • 2017-12-30
      • 2020-11-26
      • 2022-12-11
      • 2019-09-06
      相关资源
      最近更新 更多