如何在Discord.py中实现歌曲播放结束后自动续播
Discord机器人自动续播放队列歌曲的实现方案
你不需要用while循环检测播放状态,Discord.py提供了音频播放结束的回调机制——这就是你要的“音频结束事件”,通过voice.play()的after参数就能实现,完全适配异步事件循环,不会导致机器人卡死。
核心实现逻辑
每次调用voice.play()时,传入一个after回调函数,当前音频播放完毕后,这个函数会自动触发。在回调里检查队列是否有剩余歌曲,有就继续播放下一首即可。
你现有代码的问题
- while循环会阻塞Discord机器人的事件循环,导致机器人无法响应任何指令,这是它失效的核心原因
queue.remove(source)逻辑错误:你创建的source是全新的FFmpegPCMAudio实例,并不在队列中,应该移除队列的第一个待播放项next(next_song)的写法不规范,直接从队列取首项即可
正确的代码示例
# 假设你已定义全局/指令上下文内的队列,示例中存歌曲文件路径 queue = [] def play_next(ctx, client): # 检查队列是否为空 if not queue: return # 取出队列首项的歌曲路径 next_song_path = queue.pop(0) # 获取当前服务器的语音客户端 voice = discord.utils.get(client.voice_clients, guild=ctx.guild) if not voice or not voice.is_connected(): return # 创建音频源 source = FFmpegPCMAudio(next_song_path) # 播放音频,同时传入after回调,播放结束后自动触发下一首 voice.play(source, after=lambda e: play_next(ctx, client)) # 异步发送播放通知(回调是同步函数,需用事件循环包装) client.loop.create_task(ctx.send(f"正在播放下一首: {next_song_path.split('/')[-1]}")) # 示例:触发播放的指令(比如!play) @client.command() async def play(ctx, song_path): queue.append(song_path) # 如果当前没有在播放,启动队列的第一首 voice = discord.utils.get(client.voice_clients, guild=ctx.guild) if not voice or not voice.is_playing(): play_next(ctx, client)
关键细节
after参数接收带错误参数的lambda函数(lambda e: ...),e是播放时可能出现的异常,可按需添加异常处理- 队列建议存储歌曲路径/唯一标识,不要直接存FFmpegPCMAudio对象,避免不必要的资源占用
内容的提问来源于stack exchange,提问作者RRTropical
相关产品推荐
相关产品推荐

