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

如何使用YTDL与discordjs/voice包在移除内置语音API库的最新版Discord中实现音乐流式播放

用@discordjs/voice + yt-dlp实现Discord语音频道音乐播放

嘿,我之前也踩过这个坑!新版Discord移除内置语音API后,确实得用@discordjs/voice来单独处理语音逻辑,配合yt-dlp(别用yt-dl了,它已经停更,很多站点支持不了)来拉取音频,完全能搞定音乐播放,我给你一步步说清楚:

1. 先装必要的依赖

先打开终端,把需要的包都装上:

npm install @discordjs/voice yt-dlp-exec prism-media
  • @discordjs/voice:这是处理语音连接、播放的核心库,Discord官方维护的
  • yt-dlp-exec:替代yt-dl的音频/视频下载工具,支持超多站点,更新也勤
  • prism-media:@discordjs/voice用来转码音频的依赖,必须装

另外一定要确保你的系统有ffmpeg:

  • Windows:去ffmpeg官网下二进制包,加到系统PATH里
  • Mac:直接用brew install ffmpeg
  • Linux:Debian/Ubuntu系用sudo apt install ffmpeg,其他发行版用对应的包管理器

2. 先搞定语音连接

假设你已经有了Discord.js的客户端实例,也能拿到用户所在的语音频道对象,先写个基础的连接代码:

const { joinVoiceChannel } = require('@discordjs/voice');

// 比如通过消息获取用户的语音频道
const voiceChannel = message.member?.voice.channel;
if (!voiceChannel) {
  return message.reply('你得先加入一个语音频道啊老弟!');
}

// 建立语音连接
const connection = joinVoiceChannel({
  channelId: voiceChannel.id,
  guildId: voiceChannel.guild.id,
  adapterCreator: voiceChannel.guild.voiceAdapterCreator,
});

这段代码能让机器人成功加入你所在的语音频道,先确保这一步没问题。

3. 拉取音频并播放(流媒体方式,推荐)

不用下载本地文件,直接拉YouTube的音频流来播放,效率更高:

const ytdlp = require('yt-dlp-exec');
const { createAudioPlayer, createAudioResource, AudioPlayerStatus } = require('@discordjs/voice');

async function playStream(voiceChannel, urlOrKeyword) {
  try {
    // 用yt-dlp获取音频的信息和流媒体地址
    const audioInfo = await ytdlp(urlOrKeyword, {
      dumpSingleJson: true,
      noCheckCertificates: true,
      noWarnings: true,
      preferFreeFormats: true,
      audioFormat: 'mp3',
    });

    // 创建音频资源,支持调整音量
    const audioResource = createAudioResource(audioInfo.url, {
      inlineVolume: true,
    });

    // 创建音频播放器
    const player = createAudioPlayer();

    // 把播放器绑定到语音连接上
    connection.subscribe(player);

    // 开始播放
    player.play(audioResource);

    // 监听播放状态
    player.on(AudioPlayerStatus.Playing, () => {
      message.reply(`🎵 开始播放:${audioInfo.title}`);
      console.log(`正在播放:${audioInfo.title}`);
    });

    // 播放结束后的处理
    player.on(AudioPlayerStatus.Idle, () => {
      console.log('播放完毕');
      // 可以选择断开连接,或者留着等下一首
      // connection.destroy();
    });

    // 处理播放错误
    player.on('error', (err) => {
      console.error('播放出错:', err);
      message.reply(`播放出错了:${err.message}`);
    });
  } catch (err) {
    console.error('获取音频出错:', err);
    message.reply(`找不到音频资源:${err.message}`);
  }
}

// 调用示例:比如用户发!play https://youtube.com/watch?v=xxx 或者!play 周杰伦晴天
if (message.content.startsWith('!play')) {
  const input = message.content.slice(6).trim();
  if (!input) {
    return message.reply('请给个YouTube链接或者歌曲关键词呀!');
  }
  playStream(voiceChannel, input);
}

4. 要是想下载本地文件再播放(可选)

如果你偏好先把音频存到本地再播放,也可以这么写:

const fs = require('fs');

async function downloadAndPlay(voiceChannel, urlOrKeyword) {
  try {
    // 先获取音频信息,拿到标题用来生成文件名
    const audioInfo = await ytdlp(urlOrKeyword, {
      dumpSingleJson: true,
    });
    
    // 下载音频到本地,转成mp3格式
    await ytdlp(urlOrKeyword, {
      output: `./temp-audio/${audioInfo.title}.%(ext)s`,
      format: 'bestaudio/best',
      postprocessors: [{
        key: 'FFmpegExtractAudio',
        preferredcodec: 'mp3',
      }],
    });

    const audioPath = `./temp-audio/${audioInfo.title}.mp3`;
    const audioResource = createAudioResource(fs.createReadStream(audioPath), {
      inlineVolume: true,
    });

    const player = createAudioPlayer();
    connection.subscribe(player);
    player.play(audioResource);
  } catch (err) {
    console.error('下载或播放出错:', err);
    message.reply('出错啦!');
  }
}

常见坑要避开

  • 没声音:检查ffmpeg是不是真的装好了,PATH配置对不对;机器人有没有语音频道的「连接」和「说话」权限;音频格式是不是mp3这类支持的格式。
  • yt-dlp报错:如果是关键词搜索失败,试试直接用YouTube链接;要是访问不了YouTube,可能需要配置代理。
  • 连接断开:可以给connection加个监听事件,断开时自动重连,或者提示用户。

内容的提问来源于stack exchange,提问作者ProfitableMoon

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.30 15:27:38