discord.js实现语音频道无人停播、有人加入自动播放的开发问题
解决方案
前置错误修复
首先修复原代码中两处明显的运行错误:
- 删除开头重复的登录语句:
client.login(process.env.TOKEN);,末尾已经存在调用config内TOKEN的登录逻辑,重复调用会导致登录失败 - 删除无效报错语句:
const GuildMember = new Discord.GuildMember();,该行无实际功能,且你引入的discord变量为小写,调用大写Discord会直接抛出未定义错误
功能实现说明
新增的voiceStateUpdate事件需要同时覆盖两种场景:
- 用户离开语音频道后,频道内仅剩余bot自身时,停止播放流
- 新用户加入bot所在的语音频道时,立刻恢复播放流
完整可运行代码
const { Client } = require("discord.js"); const keepAlive = require('./server.js'); const client = new Client({ disableEveryone: true }); keepAlive(); const { TOKEN, CHANNEL, STATUS, LIVE } = require("./config.json"); const discord = require("discord.js"); const ytdl = require('ytdl-core'); let broadcast = null; let interval = null; let currentConnection = null; // 存储当前语音连接 let isPlaying = false; // 存储播放状态 if (!TOKEN) { console.error("请提供有效的Discord Bot Token"); return process.exit(1); } else if (!CHANNEL || isNaN(Number(CHANNEL))) { console.log("请提供有效的频道ID"); return process.exit(1); } else if (!LIVE) { console.log("请提供有效的Youtube链接"); return process.exit(1); } // 封装播放方法 async function startPlay(channel) { if (isPlaying) return; if (!broadcast) { broadcast = client.voice.createBroadcast(); } try { stream = await ytdl(LIVE); stream.on('error', console.error); broadcast.play(stream); if (!interval) { interval = setInterval(async function() { try { stream = await ytdl(LIVE, { highWaterMark: 100 << 150 }); stream.on('error', console.error); broadcast.play(stream); } catch (e) { return } }, 1800000) } currentConnection = await channel.join(); currentConnection.play(broadcast); isPlaying = true; } catch (error) { console.error(error); } } // 封装停止播放方法 function stopPlay() { if (!isPlaying) return; if (currentConnection) { currentConnection.disconnect(); currentConnection = null; } if (broadcast) { broadcast.destroy(); broadcast = null; } if (interval) { clearInterval(interval); interval = null; } isPlaying = false; } client.on('ready', async () => { client.user.setActivity(STATUS, { type: "STREAMING", url:"https://www.youtube.com/watch?v=Igipt9XegCs"}); let channel = client.channels.cache.get(CHANNEL) || await client.channels.fetch(CHANNEL) if (!channel) { console.error("提供的频道ID不存在,或Bot无权限访问该频道,程序已退出"); return process.exit(1); } else if (channel.type !== "voice") { console.error("提供的频道ID不是语音频道,程序已退出"); return process.exit(1); } // 启动时如果频道内有人就直接播放 if (channel.members.size > 1) { await startPlay(channel); } }); setInterval(async function() { let channel = client.channels.cache.get(CHANNEL) || await client.channels.fetch(CHANNEL); if(!channel) return; // 频道内有人才检查重连 if (channel.members.size > 1 && !client.voice.connections.size) { await startPlay(channel); } }, 20000); // 语音状态更新事件处理 client.on('voiceStateUpdate', async (oldState, newState) => { const targetChannel = client.channels.cache.get(CHANNEL) || await client.channels.fetch(CHANNEL); if (!targetChannel) return; const botVoiceId = targetChannel.guild.me.voice.channelID; // 处理用户离开场景 if (oldState.channelID === botVoiceId && !newState.channelID) { // 离开后频道仅剩bot自己 if (targetChannel.members.size === 1) { setTimeout(() => { // 5秒后确认还是没人再停止 if (targetChannel.members.size === 1) { stopPlay(); } }, 5000); } } // 处理用户加入场景 if (newState.channelID === targetChannel.id && newState.member.id !== client.user.id) { // 加入的是目标频道且不是bot自己,并且当前没在播放 if (!isPlaying) { await startPlay(targetChannel); } } }); client.login(TOKEN); process.on('unhandledRejection', console.error);
内容的提问来源于stack exchange,提问作者Creesch 2.0
相关产品推荐
相关产品推荐

