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

Discord.js V13 队列存在时player.getQueue()返回undefined

问题原因

player.getQueue()返回undefined的核心原因是你在每一个命令文件执行时都重新创建了全新的Player实例:

  • play.js执行时new Player()生成的实例A,队列是存在实例A的内部存储里的
  • skip.js执行时又new Player()生成了全新的实例B,实例B的内部存储是空的,自然找不到之前创建的队列
    不同Player实例之间的队列数据完全不互通,这是最根本的问题。

另外你的代码里还有两个会导致异常的小问题:

  • 语音频道权限校验的两个分支没有加return,校验不通过时代码还会继续往下执行创建队列、搜索歌曲的逻辑
  • 手动给queue.playing赋值的写法是错的,这个状态由discord-player内部自动维护,手动修改会导致状态判断异常
修复方法

1. 全局初始化唯一Player实例

在你的机器人入口文件(通常是index.js/bot.js,也就是你初始化Discord Client、注册命令的文件)中,只初始化一次Player,并且挂载到client上供所有命令复用:

// 入口文件示例
const { Client, Intents } = require('discord.js');
const { Player } = require('discord-player');

// 初始化Discord客户端
const client = new Client({
    intents: [
        Intents.FLAGS.GUILDS,
        Intents.FLAGS.GUILD_VOICE_STATES,
        // 你其他需要的intents配置
    ]
});

// 全局只初始化一次Player
const player = new Player(client);
// 挂载到client上,所有命令都能拿到同一个实例
client.player = player;

// 注册discord-player必要的事件监听(可选但推荐)
player.on('trackStart', (queue, track) => {
    queue.metadata?.send(`🎶 正在播放:${track.title}`);
});
player.on('error', (queue, error) => {
    console.log(`播放队列错误:${error.message}`);
});

// 后面保留你原本的client.login、命令注册等逻辑即可

2. 修改play.js代码

把play.js里const player = new Player(interaction.client);这行删掉,替换成从client上取全局实例,同时修复之前提到的两个逻辑问题:

const { SlashCommandBuilder } = require('@discordjs/builders');
const { QueryType } = require('discord-player');

module.exports = {
    data: new SlashCommandBuilder()
        .setName('play')
        .setDescription('播放音乐')
        .addStringOption(option => option
            .setName("song")
            .setDescription("要播放的歌曲名称或链接")
            .setRequired(true)),
    async execute(interaction, Discord) {
        const voice_channel = interaction.member.voice.channel;
        const bot_channel = interaction.guild.me.voice.channel;

        if (!voice_channel) {
            await interaction.reply({
                embeds: [new Discord.MessageEmbed()
                    .setColor('#FFDAB9')
                    .setDescription('你需要先进入语音频道才能播放音乐!')],
                ephemeral: true
            });
            // 加return阻止后续代码执行
            return;
        }

        if (bot_channel && bot_channel.id != voice_channel.id) {
            await interaction.reply({
                embeds: [new Discord.MessageEmbed()
                    .setColor('#FFDAB9')
                    .setDescription(`我已经在${bot_channel.toString()}频道连接了`)] ,
                ephemeral: true
            });
            // 加return阻止后续代码执行
            return;
        }

        const song = interaction.options.getString("song");
        // 直接取全局唯一的player实例,不要重新创建
        const player = interaction.client.player;

        const searchResult = await player.search(song, {
            requestedBy: interaction.user,
            searchEngine: QueryType.AUTO
        }).catch(() => { });

        if (!searchResult || !searchResult.tracks.length) {
            return interaction.reply({ content: '没有找到对应音乐!', ephemeral: true });
        }

        // 创建队列时传入interaction.channel作为metadata,方便后续事件发送消息
        const queue = player.createQueue(interaction.guild, {
            metadata: interaction.channel
        });
        queue.options.initialVolume = 50;
        queue.options.leaveOnEmptyCooldown = 5000;

        try {
            if (!queue.connection) await queue.connect(voice_channel);
        } catch {
            void player.deleteQueue(interaction.guildId);
            return void interaction.reply({ content: "无法加入你的语音频道!", ephemeral: true });
        }

        searchResult.playlist ? queue.addTracks(searchResult.tracks) : queue.addTrack(searchResult.tracks[0]);
        // 删掉手动给queue.playing赋值的错误写法,内部会自动维护状态
        if (!queue.playing) {
            await queue.play();
        }

        const row = new Discord.MessageActionRow()
            .addComponents(
                new Discord.MessageButton()
                    .setCustomId('pause')
                    .setLabel('⏸')
                    .setStyle('PRIMARY'),
                new Discord.MessageButton()
                    .setCustomId('resume')
                    .setLabel('▶')
                    .setStyle('PRIMARY'),
            );

        const play_embed = await interaction.reply({
            embeds: [new Discord.MessageEmbed()
                .setColor('#FFDAB9')
                .setTitle(`${queue.nowPlaying().title}`)
                .setURL(`${queue.nowPlaying().url}`)
                .setThumbnail(`${queue.nowPlaying().thumbnail}`)
                .setAuthor({ name: ` | 正在播放`, iconURL: `https://imgur.com/krzRxsN.png` })
                .addField('时长:', `\`${queue.nowPlaying().duration}\``, true)
                .addField('作者:', `\`${queue.nowPlaying().author}\``, true)
                .setTimestamp()
                .setFooter({ text: `点播者:${interaction.user.username}`, iconURL: `${interaction.user.displayAvatarURL()}` })
            ],
            // components: [row]
        });
    }
}

3. 修改skip.js代码

同样替换player实例的获取方式,不要重新创建:

const { SlashCommandBuilder } = require('@discordjs/builders');

module.exports = {
    data: new SlashCommandBuilder()
        .setName('skip')
        .setDescription('跳过队列中当前播放的音乐'),
    async execute(interaction, Discord) {
        await interaction.deferReply();
        // 取全局唯一的player实例
        const player = interaction.client.player;
        const queue = player.getQueue(interaction.guildId);

        if (!queue || !queue.playing) return void interaction.followUp({ content: "❌ | 当前没有正在播放的音乐!" });
        const currentTrack = queue.current;
        const success = queue.skip();
        return void interaction.followUp({
            content: success ? `✅ | 已跳过 **${currentTrack}**!` : "❌ | 跳过操作失败!"
        });
    }
}

改完之后重启机器人,所有命令复用同一个Player实例,队列就能正常获取了。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 14:18:17