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

