You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.06 16:24:01