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

使用Pycord实现星标板Cog:编辑Embed添加新增反应用户

问题诊断与修复方案

核心问题

你的代码存在两个致命逻辑错误,直接导致更新功能失效:

  1. 嵌套判断矛盾:if reactions and reactions.count > 1被放在if reactions and reactions.count == 1的分支内部——这种逻辑下只有当反应数同时等于1和大于1时才会执行,完全不可能触发,所以更新代码永远不会运行。
  2. 无消息关联存储:首次发送星标消息后,你没有记录该消息与原消息的对应关系,后续添加反应时根本找不到需要编辑的目标消息。

另外还有两处细节瑕疵:

  • 用payload.emoji.name匹配表情不如str(payload.emoji)准确,部分表情的名称与字符串表现存在差异;
  • 第二次触发on_raw_reaction_add时,代码不会进入count == 1的分支,自然不会执行任何更新操作。

修复后的完整代码

from discord.ext import commands
import discord

class Starboard(commands.Cog):
    def __init__(self, bot):
        self.bot = bot
        # 内存字典存储原消息ID与星标消息ID的映射,重启会丢失,生产环境建议用数据库持久化
        self.starboard_map = {}  

    @commands.Cog.listener()
    async def on_raw_reaction_add(self, payload):
        # 仅处理⭐表情
        if str(payload.emoji) != "⭐":
            return
        
        # 跳过机器人的反应
        user = self.bot.get_user(payload.user_id)
        if user.bot:
            return
        
        # 获取原消息所在频道
        channel = self.bot.get_channel(payload.channel_id)
        if not channel:
            return
        
        # 获取原消息,处理消息已被删除的情况
        try:
            message = await channel.fetch_message(payload.message_id)
        except discord.NotFound:
            return
        
        # 获取该消息的⭐反应数据
        star_reaction = discord.utils.get(message.reactions, emoji="⭐")
        if not star_reaction:
            return
        
        starboard_channel_id = 1141847109528735866
        starboard_channel = self.bot.get_channel(starboard_channel_id)
        if not starboard_channel:
            return
        
        # 提取所有非机器人打星用户的提及字符串
        reacted_users = await star_reaction.users().flatten()
        mentions = ' '.join([u.mention for u in reacted_users if not u.bot])
        
        # 复用Embed构建逻辑,避免重复代码
        def build_star_embed():
            embed = discord.Embed(description=message.content, color=discord.Color.blurple())
            embed.set_author(
                name=message.author.display_name,
                icon_url=message.author.avatar.url if message.author.avatar else None
            )
            embed.add_field(name="打星用户", value=mentions if mentions else "无", inline=True)
            embed.add_field(name="来源频道", value=channel.mention, inline=True)
            embed.add_field(name="跳转原消息", value=f"[点击这里]({message.jump_url})", inline=True)
            if message.author.avatar:
                embed.set_thumbnail(url=message.author.avatar.url)
            return embed

        # 分场景处理:首次打星发送新消息,后续打星编辑已有消息
        if payload.message_id not in self.starboard_map:
            # 首次打星,发送星标消息并记录映射
            if star_reaction.count == 1:
                star_msg = await starboard_channel.send(embed=build_star_embed())
                self.starboard_map[payload.message_id] = star_msg.id
        else:
            # 已有星标消息,找到并更新
            star_msg_id = self.starboard_map[payload.message_id]
            try:
                star_msg = await starboard_channel.fetch_message(star_msg_id)
                await star_msg.edit(embed=build_star_embed())
                print(f"已更新星标消息,当前打星用户:{mentions}")
            except discord.NotFound:
                # 星标消息已被删除,移除无效映射
                del self.starboard_map[payload.message_id]

关键修复点说明

  1. 拆分逻辑分支:将首次发送与后续更新逻辑分离,通过starboard_map判断原消息是否已有对应星标消息。
  2. 存储消息映射:用字典记录原消息ID到星标消息ID的关联,确保后续能准确找到需要编辑的消息。
  3. 复用Embed构建:把Embed生成逻辑封装成函数,保证首次发送与更新的格式完全一致,减少冗余代码。
  4. 排除机器人用户:过滤掉机器人的反应,避免无效用户被计入打星列表。
  5. 异常处理:增加原消息或星标消息不存在时的容错逻辑,防止程序崩溃。
  6. 表情判断优化:用str(payload.emoji)匹配⭐,避免表情名称匹配的误差。

注意事项

  • 内存字典starboard_map在机器人重启后会丢失所有映射,生产环境建议使用SQLite、MySQL等数据库持久化存储该关联关系;
  • 若星标频道的消息被手动删除,代码会自动移除对应的映射,下次打星时会重新发送新的星标消息。

内容的提问来源于stack exchange,提问作者Ramo A.

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 08:36:11