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

如何在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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 11:06:44