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

Discord.js v13音乐机器人报错ReferenceError: channel is not defined求助

问题修复方案

错误根因

  1. 代码第17行调用joinVoiceChannel时使用的channel变量从未定义,直接触发ReferenceError
  2. 连接语音频道的逻辑放在了用户语音频道权限校验之前,即使修复变量问题,也会出现用户未进入语音频道但机器人尝试连接的逻辑错误
  3. 播放逻辑仍使用discord.js v12的旧API,和v13配套的@discordjs/voice不兼容,修复变量后仍会出现播放报错

修复步骤

  • 把joinVoiceChannel的调用移到权限校验通过后的队列初始化try代码块中,参数替换为已定义的voice_channel变量
  • 新增音频播放器、音频资源的创建逻辑,适配@discordjs/voice的API要求
  • 调整skip、stop方法的停止逻辑,适配新的播放器实例

修改后的完整代码

const ytdl = require('ytdl-core');
const ytSearch = require('yt-search');
const { joinVoiceChannel, createAudioPlayer, createAudioResource, AudioPlayerStatus } = require('@discordjs/voice');

// 全局队列,每个服务器对应一个队列实例
const queue = new Map();

module.exports = {
    name: 'play',
    aliases: ['skip', 'stop'],
    cooldown: 0,
    description: 'Advanced music bot',
    async execute(message, args, cmd, client, Discord){
        // 先校验用户语音频道和权限
        const voice_channel = message.member.voice.channel;
        if (!voice_channel) return message.channel.send('You need to be in a channel to execute this command!');
        const permissions = voice_channel.permissionsFor(message.client.user);
        if (!permissions.has('CONNECT')) return message.channel.send('You dont have the correct permissions');
        if (!permissions.has('SPEAK')) return message.channel.send('You dont have the correct permissions');

        const server_queue = queue.get(message.guild.id);

        if (cmd === 'play'){
            if (!args.length) return message.channel.send('You need to send the second argument!');
            let song = {};

            // 链接解析逻辑
            if (ytdl.validateURL(args[0])) {
                const song_info = await ytdl.getInfo(args[0]);
                song = { title: song_info.videoDetails.title, url: song_info.videoDetails.video_url }
            } else {
                // 关键词搜索逻辑
                const video_finder = async (query) =>{
                    const video_result = await ytSearch(query);
                    return (video_result.videos.length > 1) ? video_result.videos[0] : null;
                }

                const video = await video_finder(args.join(' '));
                if (video){
                    song = { title: video.title, url: video.url }
                } else {
                     return message.channel.send('Error finding video.');
                }
            }

            // 队列为空时新建队列
            if (!server_queue){
                const queue_constructor = {
                    voice_channel: voice_channel,
                    text_channel: message.channel,
                    connection: null,
                    player: null,
                    songs: []
                }
                
                queue.set(message.guild.id, queue_constructor);
                queue_constructor.songs.push(song);
    
                try {
                    // 这里才初始化语音连接,用已经校验过的voice_channel
                    const connection = joinVoiceChannel({
                        channelId: voice_channel.id,
                        guildId: voice_channel.guild.id,
                        adapterCreator: voice_channel.guild.voiceAdapterCreator,
                    });
                    // 创建音频播放器
                    const player = createAudioPlayer();
                    connection.subscribe(player);
                    
                    queue_constructor.connection = connection;
                    queue_constructor.player = player;
                    video_player(message.guild, queue_constructor.songs[0]);
                } catch (err) {
                    queue.delete(message.guild.id);
                    message.channel.send('There was an error connecting!');
                    throw err;
                }
            } else{
                server_queue.songs.push(song);
                return message.channel.send(`👍 **${song.title}** added to queue!`);
            }
        }

        else if(cmd === 'skip') skip_song(message, server_queue);
        else if(cmd === 'stop') stop_song(message, server_queue);
    }
    
}

const video_player = async (guild, song) => {
    const song_queue = queue.get(guild.id);

    if (!song) {
        song_queue.connection.destroy();
        queue.delete(guild.id);
        return;
    }
    const stream = ytdl(song.url, { filter: 'audioonly', highWaterMark: 1<<25 });
    // 创建音频资源
    const resource = createAudioResource(stream, { inlineVolume: true });
    resource.volume.setVolume(0.5);
    // 播放音频
    song_queue.player.play(resource);
    // 监听播放结束事件
    song_queue.player.on(AudioPlayerStatus.Idle, () => {
        song_queue.songs.shift();
        video_player(guild, song_queue.songs[0]);
    });
    await song_queue.text_channel.send(`🎶 Now playing **${song.title}**`)
}

const skip_song = (message, server_queue) => {
    if (!message.member.voice.channel) return message.channel.send('You need to be in a channel to execute this command!');
    if(!server_queue){
        return message.channel.send(`There are no songs in queue 😔`);
    }
    server_queue.player.stop();
}

const stop_song = (message, server_queue) => {
    if (!message.member.voice.channel) return message.channel.send('You need to be in a channel to execute this command!');
    server_queue.songs = [];
    server_queue.player.stop();
}

额外注意事项

  • 启动机器人时需要在Client配置中开启GUILD_VOICE_STATES意图,否则无法正常连接语音频道
  • 确保已经安装了libsodium-wrappers(或sodium)依赖,否则语音功能无法正常运行

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.26 05:36:06