javascript 使用 discord.js 和 ytdl-core 播放音频文件

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/47045805/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-29 07:08:46  来源:igfitidea点击:

Playing an audio file using discord.js and ytdl-core

javascriptnode.jsdiscord.js

提问by Oliver

I'm trying to download and play an audio file fetched from youtube using ytdl and discord.js:

我正在尝试使用 ytdl 和 discord.js 下载并播放从 youtube 获取的音频文件:

        ytdl(url)
            .pipe(fs.createWriteStream('./music/downloads/music.mp3'));

        var voiceChannel = message.member.voiceChannel;
        voiceChannel.join().then(connection => {
            console.log("joined channel");
            const dispatcher = connection.playFile('./music/downloads/music.mp3');
            dispatcher.on("end", end => {
                console.log("left channel");
                voiceChannel.leave();
            });
        }).catch(err => console.log(err));
        isReady = true

I successfully manage to play the mp3 file in ./music/downloads/ without the ytdl part (ytdl(url).pipe(fs.createWriteStream('./music/downloads/music.mp3'));). But when that part is in the code, the bot just joins and leaves.

我成功地在 ./music/downloads/ 中播放了 mp3 文件而没有 ytdl 部分 ( ytdl(url).pipe(fs.createWriteStream('./music/downloads/music.mp3'));)。但是当那部分在代码中时,机器人就会加入然后离开。

Here is the output with the ytdl part:

这是带有 ytdl 部分的输出:

Bot has started, with 107 users, in 43 channels of 3 guilds.
joined channel
left channel

And here is the output without the ytdl part:

这是没有 ytdl 部分的输出:

Bot has started, with 107 users, in 43 channels of 3 guilds.
joined channel
[plays mp3 file]
left channel

Why is that and how can i solve it?

为什么会这样,我该如何解决?

回答by ufxmeng

Use playStreaminstead of playFile when you need to play a audio stream.

当您需要播放音频流时,请使用playStream而不是 playFile。

const streamOptions = { seek: 0, volume: 1 };
var voiceChannel = message.member.voiceChannel;
        voiceChannel.join().then(connection => {
            console.log("joined channel");
            const stream = ytdl('https://www.youtube.com/watch?v=gOMhN-hfMtY', { filter : 'audioonly' });
            const dispatcher = connection.playStream(stream, streamOptions);
            dispatcher.on("end", end => {
                console.log("left channel");
                voiceChannel.leave();
            });
        }).catch(err => console.log(err));

回答by ufxmeng

You're doing it in an inefficient way. There's no synchronization between reading and writing.
Wait for the file to be written to the filesystem, then read it!

你正在以一种低效的方式做这件事。读和写之间没有同步。
等待文件写入文件系统,然后读取它!

Directly stream it

直接流式传输

Redirect YTDL's video output to dispatcher, which would be converted to opusaudio data packets first, then streamed from your computer to Discord.

YTDL的视频输出重定向到调度器,它会首先转换为opus音频数据包,然后从您的计算机流式传输到 Discord。

message.member.voiceChannel.join()
.then(connection => {
    console.log('joined channel');

    connection.playStream(ytdl(url))
    // When no packets left to send, leave the channel.
    .on('end', () => {
        console.log('left channel');
        connection.channel.leave();
    })
    // Handle error without crashing the app.
    .catch(console.error);
})
.catch(console.error);

FWTR (First write, then read)

FWTR(先写,后读)

The approach you used wass pretty close to success, but the failure is when you don't synchronize read/write.

您使用的方法非常接近成功,但失败是当您不同步读/写时。

var stream = ytdl(url);

// Wait until writing is finished
stream.pipe(fs.createWriteStream('tmp_buf_audio.mp3'))
.on('end', () => {
    message.member.voiceChannel.join()
    .then(connection => {
        console.log('joined channel');

        connection.playStream(fs.createReadStream('tmp_buf_audio.mp3'))
        // When no packets left to send, leave the channel.
        .on('end', () => {
            console.log('left channel');
            connection.channel.leave();
        })
        // Handle error without crashing the app.
        .catch(console.error);
    })
    .catch(console.error);
});