Discord.js音乐机器人运行报错connection.play() is not a function问题咨询
问题原因
- 缺少必要的语音状态意图:Discord.js v14及以上版本要求必须显式声明
GUILD_VOICE_STATES意图才能正常处理语音相关操作,你当前配置的客户端意图仅包含服务器、消息相关权限,没有语音状态权限,导致音频流无法正常传输。 - 播放API使用错误:你调用的
connection.play()是Discord.js v12及更早版本的旧API,@discordjs/voice独立包发布后早已弃用该方法,必须使用独立的音频播放器实例处理播放逻辑。 - 音频流未正确封装:ytdl返回的原始流不能直接传入语音连接,需要封装为标准的
AudioResource实例才能被播放器识别。 joinVoiceChannel本身是同步方法,你查到的加await的方案是旧版本的用法,自然不会生效。
解决方案
1. 补充依赖导入并修正客户端意图
从@discordjs/voice导入缺失的播放相关工具,同时给客户端添加语音状态意图。
2. 重构播放逻辑
统一封装播放流程:先创建音频播放器,将播放器订阅到语音连接,再将ytdl流封装为音频资源后交给播放器播放。
3. 可选优化
如果修复后仍存在拉流失败的问题,可以将官方的ytdl-core替换为第三方维护的@distube/ytdl-core,官方包经常因为YouTube接口更新导致拉流异常。
修正后的完整代码
const ytdl = require('ytdl-core'); const ytSearch = require('yt-search'); const Discord = require('discord.js') // 导入新增的播放相关工具 const { joinVoiceChannel, getVoiceConnection, createAudioPlayer, createAudioResource, StreamType } = require('@discordjs/voice'); // 补充GUILD_VOICE_STATES意图 const client = new Discord.Client({ intents: ["GUILDS","GUILD_MESSAGES","GUILD_VOICE_STATES"] }) module.exports = { name: 'play', description: 'Joins and plays a video from youtube', async execute(message, args) { const voiceChannel = message.member.voice.channel; if (!voiceChannel) return message.channel.send('You need to be in a channel to execute this command!'); const permissions = voiceChannel.permissionsFor(message.client.user); if (!permissions.has('CONNECT')) return message.channel.send('You dont have the correct permissins'); if (!permissions.has('SPEAK')) return message.channel.send('You dont have the correct permissins'); if (!args.length) return message.channel.send('You need to send the second argument!'); const validURL = (str) =>{ var regex = /(http|https):\/(\w+:{0,1}\w*)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%!\-\/]))?/; return regex.test(str); } // 封装通用播放逻辑,避免重复代码 const playStream = (connection, stream, onFinish) => { const player = createAudioPlayer(); const resource = createAudioResource(stream, { inputType: StreamType.Arbitrary, inlineVolume: true }); resource.volume.setVolume(1); player.play(resource); connection.subscribe(player); player.on('finish', () => { player.stop(); connection.destroy(); onFinish?.(); }); } if(validURL(args[0])){ const connection = joinVoiceChannel({ channelId: message.member.voice.channel.id, guildId: message.guild.id, adapterCreator: message.guild.voiceAdapterCreator }) const stream = ytdl(args[0], {filter: 'audioonly'}); playStream(connection, stream, () => { message.channel.send('leaving channel'); }); await message.reply(`:thumbsup: Now Playing ***Your Link!***`) return } const connection = joinVoiceChannel({ channelId: message.member.voice.channel.id, guildId: message.guild.id, adapterCreator: message.guild.voiceAdapterCreator }) const videoFinder = async (query) => { const videoResult = await ytSearch(query); return (videoResult.videos.length > 1) ? videoResult.videos[0] : null; } const video = await videoFinder(args.join(' ')); if(video){ const stream = ytdl(video.url, {filter: 'audioonly'}); playStream(connection, stream); await message.reply(`:thumbsup: Now Playing ***${video.title}***`) } else { message.channel.send('No video results found'); } } }
内容的提问来源于stack exchange,提问作者Teodor Kovachev
相关产品推荐
相关产品推荐

