Discord bot开发:on_message_delete事件中如何准确获取消息删除者?
修复方案
核心逻辑优化
- 新增全局缓存存储批量删除的审计日志记录,避免重复拉取审计日志,同时匹配批量删除场景下的多条消息删除事件
- 扩大审计日志时间窗口到3秒,规避Discord API延迟导致的漏匹配问题
- 优先匹配缓存中的批量删除记录,再拉取新的审计日志,解决单条审计日志对应多条删除事件的问题
- 修复原代码中存在的语法错误和逻辑漏洞
修复后的完整代码
import pytz import datetime from discord import Color # 全局批量删除记录缓存,结构:(操作人ID, 被删消息作者ID): [剩余待匹配消息数, 过期时间戳] bulk_delete_cache = {} CACHE_EXPIRE_SECONDS = 5 AUDIT_LOG_WINDOW_SECONDS = 3 @client.event async def on_message_delete(message): pst = pytz.timezone('US/Pacific') psttime = datetime.datetime.now(pst) current_pst_date = psttime.strftime('%Y/%m/%d, %I:%M %p PST.') delete_channel = message.channel.mention nsfw_tag = '' spoiler_tag = '' in_nsfw = False log_channel = client.get_channel(863957409293664266) message_author = message.author if message.content.startswith("^"): return delete_author = None now_utc = datetime.datetime.utcnow() # 先清理过期的缓存记录 expired_keys = [] for key, val in bulk_delete_cache.items(): if val[1] < now_utc: expired_keys.append(key) for key in expired_keys: del bulk_delete_cache[key] # 先匹配缓存中的批量删除记录 cache_key = None for key in bulk_delete_cache.keys(): # key的第二个元素是被删消息作者ID if key[1] == message_author.id: cache_key = key break if cache_key: delete_author = await message.guild.fetch_member(cache_key[0]) bulk_delete_cache[cache_key][0] -= 1 if bulk_delete_cache[cache_key][0] <= 0: del bulk_delete_cache[cache_key] else: # 缓存没命中,拉取审计日志 delta = now_utc - datetime.timedelta(seconds=AUDIT_LOG_WINDOW_SECONDS) async for entry in message.guild.audit_logs(action=discord.AuditLogAction.message_delete, limit=10): # 匹配时间窗口、且被删消息作者和审计日志目标一致的记录 if entry.created_at > delta and entry.target.id == message_author.id: delete_author = entry.user # 把批量记录加入缓存,count减1是因为当前这条消息已经匹配上了 expire_time = now_utc + datetime.timedelta(seconds=CACHE_EXPIRE_SECONDS) bulk_delete_cache[(entry.user.id, entry.target.id)] = [entry.extra.count - 1, expire_time] break # 还是没找到,判定为自删 if not delete_author: delete_author = message_author # 修复原代码nsfw判断逻辑 if message.channel.nsfw: nsfw_tag = '**:warning: NSFW :warning:**' in_nsfw = True spoiler_tag = '||' e = discord.Embed(title='', description=f"{nsfw_tag}\n{delete_author.mention} Deleted a Message by {message_author.name} in {spoiler_tag}{delete_channel}{spoiler_tag}") if in_nsfw: e.color = Color.red() else: e.color = Color.gold() e.set_author(name=f"{message_author}", icon_url=f"{message_author.avatar_url}") e.set_footer(text=f"• {current_pst_date}") await log_channel.send(embed=e)
注意点
- 缓存的过期时间和审计日志时间窗口可以根据你的服务器实际延迟情况调整,避免漏匹配
- 如果服务器删除消息频率很高,可以把审计日志拉取的limit值适当调大,避免漏匹配多组同时发生的批量删除操作
- 已删除原代码中不存在ctx变量导致的错误逻辑,同时修复了delete_author被赋值为字符串导致无法调用mention属性的问题
内容的提问来源于stack exchange,提问作者Broso56
相关产品推荐
相关产品推荐

