Discord.js v14:如何让机器人播放完MP3后退出语音频道?
问题:Discord.js v14 机器人播放MP3后无法自动退出语音频道
使用斜杠命令调用机器人进入语音频道播放MP3文件后,无法实现播放完毕自动退出。目前通过setTimeout临时实现需求,但希望找到Discord.js v14官方推荐的正确实现方式。
原代码中尝试通过if (player.pause(), () => voiceConnection.disconnect())实现退出,但该逻辑无效。
解决方案
在Discord.js v14配合@discordjs/voice库时,正确的做法是监听音频播放器的**Idle事件**——当音频资源播放完成后,播放器会自动触发该事件,此时即可执行断开语音连接的操作。
修改要点:
- 移除原代码中无效的
if (player.pause(), () => voiceConnection.disconnect())语句 - 为
player添加Idle事件监听器,在回调内调用voiceConnection.disconnect()或voiceConnection.destroy()(后者会彻底销毁连接,适合单次播放场景)
修改后的完整代码:
const { SlashCommandBuilder, ChannelType } = require('discord.js'); const { getVoiceConnection, entersState, joinVoiceChannel, createAudioPlayer, createAudioResource, VoiceConnectionStatus } = require('@discordjs/voice'); const { join } = require('node:path'); module.exports = { data: new SlashCommandBuilder() .setName('padoru') .setDescription('Elle est partout.....fuyez..') .addChannelOption(option => option.setName('channel').setDescription('Le channel vocal à rejoindre.').setRequired(true).addChannelTypes(ChannelType.GuildVoice)), async execute(interaction) { if (interaction.isChatInputCommand() && interaction.commandName === 'padoru') { const voiceChannel = interaction.options.getChannel('channel'); const voiceConnection = joinVoiceChannel({ channelId: voiceChannel.id, guildId: interaction.guild.id, adapterCreator: interaction.guild.voiceAdapterCreator, selfDeaf: false, }); const player = createAudioPlayer(); const resource = createAudioResource(join(__dirname, '../../medias/sound_effect/padorupadoru.mp3')); try { await entersState(voiceConnection, VoiceConnectionStatus.Ready, 5000); console.log("Connected: " + voiceChannel.guild.name); } catch (error) { console.log("Voice Connection not ready within 5s.", error); voiceConnection.destroy(); // 连接失败时销毁连接 return; } // 监听播放完成事件 player.on('idle', () => { voiceConnection.disconnect(); // 断开连接 // 若需要彻底销毁连接,可改用 voiceConnection.destroy(); console.log("Playback finished, disconnected from voice channel."); }); voiceConnection.subscribe(player); player.play(resource); // 回复交互,避免超时 await interaction.reply({ content: `正在播放Padoru在${voiceChannel.name}`, ephemeral: true }); } } };
补充说明:
Idle事件仅在播放器没有待播放的资源且处于空闲状态时触发,刚好对应单音频播放完成的场景- 记得在交互中调用
interaction.reply(),否则Discord会判定命令超时失败 - 连接失败时调用
voiceConnection.destroy()可以避免残留无效连接
内容的提问来源于stack exchange,提问作者Cyber Moika
相关产品推荐
相关产品推荐

