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

discord.py中FFmpeg播放器播放完成后自动退出的实现问题

解决Discord机器人FFmpeg Player的after参数错误与非循环状态检测问题

看起来你遇到了Discord.py音效机器人开发里的两个常见问题,我来一步步帮你梳理解决方案:

一、修复after=voice_client.disconnect()的TypeError问题

你触发错误的核心原因有两点:

  1. 你直接写了voice_client.disconnect(),这会立刻执行断开连接的操作,而不是把函数本身传递给after参数——after需要的是一个可调用的函数对象,而非函数执行后的返回值。
  2. create_ffmpeg_player的after回调会自动传入一个参数(播放出错时是错误对象,播放完成则为None),但voice_client.disconnect()不需要任何参数,因此出现了“参数数量不匹配”的报错。

正确写法有两种:

1. Lambda表达式包装(简单场景推荐)

用lambda忽略回调传递的参数,直接调用断开连接方法:

soundboard_player = voice_client.create_ffmpeg_player("doh.mp3", after=lambda error: voice_client.disconnect())
soundboard_player.start()
await client.send_message(message.channel, "Playing DOH...")

2. 自定义回调函数(适合需要错误处理的场景)

如果想捕获播放过程中的错误,可以单独写一个处理函数:

def handle_play_finish(error):
    if error:
        print(f"播放音效时出现错误: {error}")
    # 无论是否出错,播放完成后断开连接
    voice_client.disconnect()

soundboard_player = voice_client.create_ffmpeg_player("doh.mp3", after=handle_play_finish)
soundboard_player.start()
await client.send_message(message.channel, "Playing DOH...")

二、非循环式的播放状态检测与手动停止方案

你提到用is_done()会陷入循环、无法响应STOP命令——其实完全不需要用循环检测状态,我们可以结合全局变量保存播放器实例和独立的STOP命令来实现手动终止,同时用after回调处理自动断开逻辑。

示例代码:

# 全局变量保存当前正在播放的播放器实例
current_player = None

# 播放音效的命令
@client.command()
async def play_doh(ctx):
    global current_player
    # 先检查用户是否在语音频道内
    if not ctx.author.voice:
        await ctx.send("你需要先加入一个语音频道才能播放音效!")
        return
    
    voice_channel = ctx.author.voice.channel
    voice_client = await voice_channel.connect()
    
    # 创建播放器并绑定after回调
    current_player = voice_client.create_ffmpeg_player(
        "doh.mp3",
        after=lambda e: voice_client.disconnect()
    )
    current_player.start()
    await ctx.send("Playing DOH...")

# 手动停止音效的命令
@client.command()
async def stop(ctx):
    global current_player
    # 检查是否有正在播放的音效,且机器人处于连接状态
    if current_player and ctx.voice_client and ctx.voice_client.is_connected():
        current_player.stop()
        await ctx.voice_client.disconnect()
        await ctx.send("音效已停止播放!")
    else:
        await ctx.send("当前没有正在播放的音效哦!")

这样实现的优势:

  • 无需循环检测is_done(),播放完成后after回调会自动断开连接
  • 用户随时可以发送!stop命令终止播放,不会被循环阻塞
  • 全局变量current_player帮我们跟踪当前播放状态,避免重复播放冲突

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 07:55:18