如何在discord.py中结合反应监听与!info消息触发输出功能?
解决discord.py中反应监听与!info命令结合的问题
核心思路是用一个全局存储结构(比如字典)来跨事件共享反应数据,把on_reaction_add中捕获的反应信息存起来,在on_message处理!info命令时读取这些数据。
完整代码示例
import discord from discord.ext import commands intents = discord.Intents.default() intents.messages = True intents.reactions = True intents.message_content = True bot = commands.Bot(command_prefix="!", intents=intents) # 用字典存储反应数据:键是消息ID,值是{"emoji": 表情对象, "users": 用户ID列表} bot.reaction_data = {} @bot.event async def on_reaction_add(reaction, user): # 忽略机器人自己的反应,避免循环触发 if user.bot: return # 存储当前消息的反应信息,覆盖旧数据(如果需要保留多个表情,可改成嵌套字典) bot.reaction_data[reaction.message.id] = { "emoji": str(reaction.emoji), "users": [str(u) for u in await reaction.users().flatten()] } @bot.event async def on_message(message): # 先让bot处理自带的命令逻辑,避免冲突 await bot.process_commands(message) # 过滤机器人消息,避免自触发 if message.author.bot: return if message.content.startswith("!info"): # 拆分命令,支持指定消息ID(比如!info 123456789) parts = message.content.split() if len(parts) == 2: try: msg_id = int(parts[1]) data = bot.reaction_data.get(msg_id) except ValueError: await message.channel.send("请输入有效的消息ID") return else: # 如果没指定ID,取最近一条有反应的消息数据 if not bot.reaction_data: await message.channel.send("暂无反应记录") return msg_id = next(reversed(bot.reaction_data.keys())) data = bot.reaction_data[msg_id] if not data: await message.channel.send("该消息没有反应记录") return # 格式化输出信息 response = ( f"📝 目标消息ID: {msg_id}\n" f"😀 反应表情: {data['emoji']}\n" f"👥 反应用户列表:\n" + "\n".join([f"- {user}" for user in data['users']]) ) await message.channel.send(response) bot.run("你的机器人TOKEN")
关键说明
- 跨事件数据共享:通过给
bot对象添加reaction_data属性,实现on_reaction_add和on_message事件之间的数据传递,避免了局部变量无法跨事件访问的问题。 - 消息ID关联:用消息ID作为字典的键,确保每条消息的反应数据可以被精准定位。
- 命令扩展性:支持两种使用方式:
- 直接输入
!info:输出最近一条有反应的消息的信息 - 输入
!info 消息ID:输出指定消息的反应信息
- 直接输入
- 边界处理:加入了忽略机器人消息、无效ID提示、无数据提示等逻辑,避免报错。
可选优化
- 如果需要支持同一消息的多个表情反应,可以把
bot.reaction_data改成嵌套字典,结构为{消息ID: {表情字符串: [用户列表]}} - 添加
on_reaction_remove事件,实时更新用户列表,确保数据准确
内容的提问来源于stack exchange,提问作者lucy
相关产品推荐
相关产品推荐

