如何使用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
相关产品推荐
相关产品推荐

