Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
246 views
in Technique[技术] by (71.8m points)

javascript - Having trouble getting bot to stay in voice channel and listen for commands

Hello I am trying to build a discord bot that can perform text to speech using AWS Polly in JavaScript. This is my first time using JavaScript and I'm running into issues. I'm hoping someone with more experience with discord.js/building discord bots/writing code in JavaScript can help me and provide insight on how to fix this.

Below is my entire source code:

var AWS = require('aws-sdk');
const Discord = require('discord.js'); 
const fs = require('fs');
var auth = require('./auth.json');

var m_currentPlaying = "";
const client = new Discord.Client();
const prefix = '$'; 
const Polly = new AWS.Polly({
    region: 'us-east-1',
    accessKeyId: auth.accessKey,
    secretAccessKey: auth.secret
});

function getTTS(msg, text) {
    var params = {
        OutputFormat: "mp3",
        Text: text,
        TextType: "text", 
        VoiceId: "Brian"
    };

    console.log("processing command:" + text);

    var fileName = 'sounds/' + msg.id + '.mp3';
    Polly.synthesizeSpeech(params, (err, data) => {
        if (err) {
            console.log("Error getting from polly");
            return err;
        }
        if (data.AudioStream instanceof Buffer) {
            fs.writeFile(fileName, data.AudioStream, function (fsErr) {
                if (fsErr) {
                    console.log("Error writing " + fileName);
                    return fsErr;
                } else {
                    console.log(fileName + ' written sucessfully');
                }
            })
        }
    });

    return fileName;
}

function deleteFile(fileName) {
    fs.unlinkSync("./" + fileName, function(err){
        if (err) {
            console.log("failed to delete " + fileName);
            console.log(err);
            return;
        } 
        console.log(fileName + ' successfully deleted');                                     
    });
}

function playSound(msg, fileName) {
    var voiceChannel = msg.member.voice.channel;
    
    voiceChannel.join()
    .then(connection => {
        m_currentPlaying = fileName; 
        const dispatcher = connection.play(fileName);
        dispatcher.on("finish", end => {
            voiceChannel.leave();
            deleteFile(fileName);
            m_currentPlaying = "";
        });
    })  
}

client.on('ready', () => {
    console.log(`Logged in as ${client.user.tag}!`);
});
  
client.on('message', async msg => {
    if(!msg.content.startsWith(prefix) || msg.author.bot) return; 
 
    const args = msg.content.slice(prefix.length).split(/ +/);
    const command = args.shift().toLowerCase();

    if (command === 'tts') {
        if (msg.member.voice.channel) {
            var sentence = args.join(" ");
            try {
                var file = getTTS(msg, sentence);
                console.log(file);
                playSound(msg, file);
            }
            catch(err) {
                msg.reply("There was an error with that command, I'm sorry");
                console.log(err);
                return; 
            }
        }
    }
    else if (command === 'stop') {
        if (msg.member.voice.channel) 
        {
            console.log(m_currentPlaying);
            msg.guild.voice.connection.dispatcher.destroy();
            msg.guild.voice.connection.disconnect();
            deleteFile(m_currentPlaying);
            m_currentPlaying = "";
        }
    }
});

client.login(auth.token);



Right now the bot does the following:

  • The bot starts up and connects to the discord api with my token stored in a json file
  • It then waits for commands in the put into the discord that contain the prefix $
  • If it sees the command '$tts' it will make sure the user is in a voice channel. It then will use the AWS polly API to create a mp3 file of what the user put in their message.
  • Then it will join the discord voice channel and play the mp3 file. After the mp3 file is done playing it will leave the voice channel and delete the mp3 file with no issues.
  • The "$stop" command also works with no issues. It will destroy the dispatcher currently playing the mp3, disconnect the bot, and delete the mp3 file created

The issue:

  • Right now the bot works great and will join the voice channel, speak the tts message, delete the mp3 file. However what I want the code to do is I want the bot to join the voice channel and stay in the voice channel ready to receive commands and play mp3s.
  • I want it to work the way rhythm bot works. Rhythm bot will hangout in your voice channel and eventually disconnect due to an inactive timer. But otherwise the bot will stay in the voice channel listening for more song requests. I want my bot to act the same way.
  • I've tried writing my play function as follows:
function playSound(msg, fileName) {
    var voiceChannel = msg.member.voice.channel;
    
    if (!msg.guild.me.voice.channel) {
        voiceChannel.join()
        .then(connection => {
            m_currentPlaying = fileName; 
            const dispatcher = connection.play(fileName);
            dispatcher.on("finish", end => {
                deleteFile(fileName);
                m_currentPlaying = "";
            });
        })
    }
    else { // else already in a voice chat 
        m_currentPlaying = fileName;
        console.log(fileName);
        const dispatcher = msg.guild.voice.connection.play(fileName);
        dispatcher.on("finish", end => {
            deleteFile(fileName);
            m_currentPlaying = "";
        });
    }
   
}

When I write the play function in this way I receive this error: error message

It seems like it is getting to the play() function before the fs.writeFileSync() is called and thus the file doesn't exist yet and I'm not really sure why. I think this could be an issue with synchronous vs asynchronous but I'm having trouble solving this bug. Thanks for anyone who takes the time to look through my code and provide insight


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

If anyone finds this from google I figured it out. I ended up doing some more research into using a buffer and avoid writing mp3 files all together. That solved the issue and now the bot can hangout in the voice channel waiting for incoming commands. Hope this helps save some time for someone out there :)

New Code:

function getTTS(msg, text) {
    var params = {
        OutputFormat: "mp3",
        Text: text,
        TextType: "text", 
        VoiceId: "Brian"
    };

    console.log("processing command:" + text);

    Polly.synthesizeSpeech(params, (err, data) => {
        if (err) {
            console.log("Error getting from polly");
            return err;
        }
        if (data.AudioStream instanceof Buffer) {
            playSound(msg, data);
        }
    });
}

function playSound(msg, soundData) {
    var voiceChannel = msg.member.voice.channel;
    
    if (!msg.guild.me.voice.channel) {
        voiceChannel.join()
        .then(connection => {
            var bufferStream = new Stream.PassThrough();
            bufferStream.end(soundData.AudioStream);
            const dispatcher = connection.play(bufferStream);
            dispatcher.on("finish", end => {
                //voiceChannel.leave();
                //deleteFile(fileName);
                console.log("test2");
            });
        })
    } else { // else already in a voice chat 
        var bufferStream = new Stream.PassThrough();
        bufferStream.end(soundData.AudioStream);
        const dispatcher = msg.guild.voice.connection.play(bufferStream);
        dispatcher.on("finish", end => {
            //voiceChannel.leave();
            //deleteFile(fileName);
            console.log("test1");
        });
    }  
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...