Discord音乐bot首歌播放完成后如何自动播放queue队列内的下一首歌曲?
Discord音乐bot自动播放队列下一首实现方案
核心实现逻辑是利用VoiceClient.play()方法的after回调参数,在当前歌曲播放结束或报错时,触发下一首歌曲的加载播放流程,同时调整原play函数的执行逻辑,避免重复抢占播放资源。
核心修改点
- 新增独立的异步
play_next函数,专门负责队列下一首歌曲的加载、播放、回调绑定逻辑 - 调整原play函数逻辑:仅当当前没有正在播放的内容时触发播放,否则仅将传入的url加入队列
- 重写
after回调逻辑,播放结束后自动触发下一首播放,而非仅打印错误
完整修改后代码
import asyncio queue = [] async def play_next(ctx, voice_channel): global queue # 队列非空时播放下一首 if len(queue) > 0: player = await YTDLSource.from_url(queue[0], loop=client.loop) # 绑定播放结束回调,注意after是同步回调,需要通过事件循环触发异步函数 voice_channel.play(player, after=lambda e: ( print('Player error: %s' % e) if e else None, client.loop.call_soon_threadsafe( asyncio.run_coroutine_threadsafe, play_next(ctx, voice_channel), client.loop ) )) await ctx.send(f'**Now playing:** {player.title}') # 已播放的队首歌曲出列 del queue[0] else: # 队列为空时可按需添加自动退出语音频道的逻辑 # await voice_channel.disconnect() pass @client.command(name='play',help ='Play a song',aliases=['plays', 'p']) async def play(ctx, url): global queue server = ctx.message.guild voice_channel = server.voice_client queue.append(url) # 仅当前无播放内容时直接触发播放,否则仅入队 if not voice_channel.is_playing(): async with ctx.typing(): await play_next(ctx, voice_channel) else: await ctx.send(f"已将歌曲加入队列,当前队列长度:{len(queue)}")
优化提示
如果你的bot需要支持多服务器同时使用,不要用全局队列,建议改成按服务器ID区分的字典存储队列,示例如下:
from collections import defaultdict # 键为服务器ID,值为对应服务器的歌曲队列 queues = defaultdict(list) # 后续所有操作queue的地方,都替换为queues[ctx.guild.id]即可
内容的提问来源于stack exchange,提问作者KAOTU
相关产品推荐
相关产品推荐

