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

如何检测Discord机器人是否在语音频道,实现无重连歌曲续播

代码缺陷定位
  • 无差别执行频道连接逻辑:原代码无论机器人当前是否已经接入对应服务器的语音频道,都会强制执行await channel.connect()。当机器人已存在有效连接时,重复触发连接动作会直接抛出框架异常,阻断后续播放流程,这也是必须手动断开重连才能正常点歌的核心诱因
  • 播放触发逻辑无状态校验:discord.py框架的音频播放器不支持在有正在播放/已暂停的音频时,直接调用play()方法加载新音源。原代码没有判断播放器状态就直接触发播放,就算解决了连接问题,也会因为播放器资源占用无法正常加载新歌曲
  • 无连续播放支撑逻辑:缺少基础的请求排队机制,连续发送点歌指令时,要么触发播放器占用报错,要么直接打断当前正在播放的音频,无法实现自动接续播放
适配需求的代码修正
import asyncio
from discord.ext import commands

# 按服务器维度维护独立播放队列,避免不同服务器的点歌请求互相干扰
guild_queues = {}

@bot.command()
async def hraj(ctx, url):
    # 校验指令发送者是否在语音频道
    if not ctx.author.voice:
        await ctx.send("Musíš být ve voicu ty pepego!")
        return
    user_channel = ctx.author.voice.channel
    current_guild = ctx.guild
    guild_id = current_guild.id

    # 复用现有语音连接,移除强制重连逻辑
    voice_client = current_guild.voice_client
    if not voice_client:
        # 不存在连接时才执行频道接入
        voice_client = await user_channel.connect()
    else:
        # 已存在连接时,自动切换到用户当前所在的频道
        if voice_client.channel != user_channel:
            await voice_client.move_to(user_channel)

    # 初始化当前服务器的播放队列
    if guild_id not in guild_queues:
        guild_queues[guild_id] = asyncio.Queue()

    async with ctx.typing():
        # 加载音频源
        player = await YTDLSource.from_url(url, loop=bot.loop)
        # 将新音频源加入队列等待播放
        await guild_queues[guild_id].put(player)

    # 播放器处于空闲状态时,启动循环播放流程
    if not voice_client.is_playing() and not voice_client.is_paused():
        async def queue_player():
            while not guild_queues[guild_id].empty():
                # 取出队列中的下一首音频
                current_player = await guild_queues[guild_id].get()
                # 触发播放,播放结束后自动回到队列取新音频
                done_event = asyncio.Event()
                def after_play(err):
                    if err:
                        print(f"播放异常: {err}")
                    bot.loop.call_soon_threadsafe(done_event.set)
                
                voice_client.play(current_player, after=after_play)
                # 发送当前播放提示
                embed = discord.Embed(
                    title="Právě hraje:",
                    description=f"[{current_player.title}]({url})",
                    color=0x0091ff
                )
                embed.set_footer(text="Lets go jdem vibovat <333")
                await ctx.send(embed=embed)
                # 等待当前歌曲播放完成,再处理下一首
                await done_event.wait()

        bot.loop.create_task(queue_player())
修正后的核心效果
  • 机器人已在语音频道时,直接复用现有连接处理点歌请求,完全不需要手动断开重连
  • 连续发送的点歌请求会自动进入队列排队,当前歌曲播放结束后自动接续下一首,不会出现播放器占用报错
  • 支持自动频道切换:如果机器人当前在其他语音频道,收到用户的点歌指令后会自动移动到用户所在的频道

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.22 17:06:03