Discord.js TypeScript机器人播放音频数秒后停止问题求助
问题分析与解决方案
你的问题核心确实是下载未完成就开始播放:代码中调用download.pipe(writestream)后立刻读取本地文件创建音频资源,但文件此时还在写入过程中,播放器读到文件当前的末尾(未完成的部分)就会停止,甚至可能因为文件还未生成直接播放失败。
优化方案(推荐直接用流播放,无需本地文件)
不需要把音频保存到本地,@discordjs/voice支持直接传入可读流创建音频资源,这样既省磁盘空间,又能避免文件写入的异步问题。修改后的execute函数如下:
export async function execute(interaction: CommandInteraction) { if (!interaction.guildId) { return interaction.reply("出现严重错误。"); } const url = interaction.options.getString("link"); const connection = getVoiceConnection(interaction.guildId); if (!connection) { return interaction.reply("机器人当前不在语音频道,请先让机器人加入频道再使用此命令。"); } const audioplayer = createAudioPlayer({ behaviors: { noSubscriber: NoSubscriberBehavior.Pause, }, }); // 直接用ytdl的流创建音频资源,无需保存本地 const stream = ytdl(url, { filter: 'audioonly', highWaterMark: 1 << 25 }); const resource = createAudioResource(stream, { inlineVolume: true, metadata: { title: "SONG", }, }); audioplayer.play(resource); connection.subscribe(audioplayer); return interaction.reply(`正在播放:${url}`); }
备选方案(等待文件下载完成再播放)
如果一定要保存本地文件,需要监听文件写入完成的事件,再开始播放。可以把文件写入逻辑封装成Promise:
export async function execute(interaction: CommandInteraction) { if (!interaction.guildId) { return interaction.reply("出现严重错误。"); } const url = interaction.options.getString("link"); const connection = getVoiceConnection(interaction.guildId); if (!connection) { return interaction.reply("机器人当前不在语音频道,请先让机器人加入频道再使用此命令。"); } const audioplayer = createAudioPlayer({ behaviors: { noSubscriber: NoSubscriberBehavior.Pause, }, }); const download = ytdl(url, { filter: 'audioonly' }); const writestream = fs.createWriteStream('audio.mp4'); const pathtoresource = join('audio.mp4'); // 封装文件写入完成的Promise await new Promise((resolve, reject) => { download.pipe(writestream); writestream.on('finish', resolve); writestream.on('error', reject); download.on('error', reject); }); // 下载完成后再创建资源并播放 const resource = createAudioResource(pathtoresource, { inlineVolume: true, metadata: { title: "SONG", }, }); audioplayer.play(resource); connection.subscribe(audioplayer); return interaction.reply(`正在播放:${url}`); }
注意事项
- 推荐使用第一种流播放方案,避免本地文件管理的麻烦,同时播放响应更快。
- 你的intents配置没有问题,
GuildVoiceStates已经包含了语音状态所需的权限。
内容的提问来源于stack exchange,提问作者joey91191
相关产品推荐
相关产品推荐

