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

如何让discord.py中的wait_for方法在单次运行中多次触发?

问题根源
  • wait_for检查逻辑缺失必要过滤条件:未限制反应绑定的消息对象,未过滤机器人自身触发的反应事件,会导致非目标操作触发逻辑异常
  • 反应移除逻辑错误:固定移除命令发起者ctx.author的反应,实际触发操作的用户与ctx.author不一致时,移除操作会抛出异常,直接终止监听循环
  • 未处理切歌场景:切换下一首时没有终止旧播放消息的监听循环,也没有为新播放消息启动新的监听逻辑,导致新消息的反应无响应
  • 无异常捕获机制:移除反应、调用语音客户端方法时出现的错误会直接打断循环,导致后续操作无响应
修复步骤
  1. 完善检查函数,过滤条件新增:反应对应的消息是当前播放控制消息、触发用户不是机器人
  2. 调整反应移除逻辑,删除实际触发操作的用户的对应反应
  3. 封装控制监听逻辑为独立协程,切歌时先终止上一首的监听任务、清除旧消息的反应,再为新消息启动新的监听
  4. 新增异常捕获,避免非核心错误打断监听循环
修正后代码示例
import asyncio

# 全局/服务器级变量,存储当前正在运行的控制监听任务,多服务器场景可按服务器id分组存储避免冲突
current_control_task = None
current_control_msg = None

# 以下为播放命令内的逻辑
msg = await ctx.channel.send(f"`Now playing: {var3}`\n{url}")
await msg.add_reaction("⏸")
await msg.add_reaction("▶")

# 先终止旧的监听任务,清理旧消息反应
if current_control_task and not current_control_task.done():
    current_control_task.cancel()
if current_control_msg:
    try:
        await current_control_msg.clear_reactions()
    except:
        pass

# 定义独立的反应监听协程
async def control_listen():
    while True:
        try:
            reaction, user = await client.wait_for(
                "reaction_add",
                check=lambda r, u: r.message.id == msg.id and not u.bot and str(r.emoji) in ["⏸", "▶"],
                timeout=90.0
            )
        except asyncio.TimeoutError:
            await msg.clear_reactions()
            break
        except asyncio.CancelledError:
            # 切歌时主动取消任务的异常,直接退出即可
            break
        
        try:
            # 移除实际触发用户的对应反应
            await msg.remove_reaction(reaction.emoji, user)
            # 校验语音客户端状态,避免断开连接后调用方法报错
            if not ctx.voice_client or not ctx.voice_client.is_connected():
                break
            if str(reaction.emoji) == "⏸":
                if ctx.voice_client.is_playing():
                    await ctx.voice_client.pause()
            elif str(reaction.emoji) == "▶":
                if ctx.voice_client.is_paused():
                    await ctx.voice_client.resume()
        except:
            # 忽略权限不足、反应已被删除等非致命错误,继续监听后续操作
            continue

# 启动新的监听任务,更新全局存储变量
current_control_msg = msg
current_control_task = client.loop.create_task(control_listen())

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.28 09:24:01