如何修改Discord bot代码实现snipe捕获clear命令删除的前2条消息
问题根因
你当前的代码存在两个核心问题导致无法捕获clear指令删除的消息:
- 批量删除消息时(discord.py中
purge类方法执行的删除操作)默认触发on_bulk_message_delete事件,不会触发单条删除的on_message_delete,你的代码没有监听该事件 - 每个频道仅存储最后一条被删消息,clear指令执行时最后删除的是
$clear 2这条指令消息,直接覆盖了前面被删的普通用户消息,所以snipe只能拿到已经被删的指令内容,没有有效信息 - 用
await sleep(60)后删除存储条目的逻辑存在协程堆积、覆盖后删除异常的问题,稳定性差
注意:需要在Discord开发者后台开启Bot的
Message Content Intent权限,否则无法正常读取消息内容。
修改后的完整代码
import discord from discord.ext import commands import time from collections import defaultdict # 存储结构改为每个频道存一个列表,每个元素是(作者, 内容, 删除时间戳, 是否是bot指令消息) snipe_store = defaultdict(list) # 最多存每个频道最近10条被删消息,可自行调整 MAX_SNIPE_PER_CHANNEL = 10 # 被删消息保留时间,单位秒 SNIPE_EXPIRE_TIME = 60 ult = commands.Bot(command_prefix='$', intents=discord.Intents.all()) # 清理过期消息的工具函数 def clean_expired(channel_id): now = time.time() snipe_store[channel_id] = [ item for item in snipe_store[channel_id] if now - item[2] < SNIPE_EXPIRE_TIME ] @ult.event async def on_message_delete(message): # 忽略自己发的snipe返回消息,可根据需求调整 if message.author == ult.user: return channel_id = message.channel.id # 存入存储,标记是不是指令消息 is_command = message.content.startswith(ult.command_prefix) snipe_store[channel_id].append( (message.author, message.content, time.time(), is_command) ) # 超过最大存储量就删掉最早的 if len(snipe_store[channel_id]) > MAX_SNIPE_PER_CHANNEL: snipe_store[channel_id].pop(0) @ult.event async def on_bulk_message_delete(messages): # 批量删除事件触发时,逐个处理被删消息 for message in messages: await on_message_delete(message) @ult.command() async def snipe(ctx, index: int = 0): channel = ctx.channel channel_id = channel.id # 先清过期消息 clean_expired(channel_id) # 过滤掉指令消息,取有效用户消息 valid_messages = [item for item in snipe_store[channel_id] if not item[3]] if not valid_messages: await ctx.send(f"There are no deleted messages in #{channel.name}") return # 支持指定索引取更早的消息,默认0是最新一条 if index < 0 or index >= len(valid_messages): await ctx.send(f"仅存{len(valid_messages)}条可 snipe 的消息,索引范围为0到{len(valid_messages)-1}") return author, content, _, _ = valid_messages[-(index+1)] snipeEmbed = discord.Embed(title=f"Last deleted message in #{channel.name}", description = content) snipeEmbed.set_footer(text=f"Deleted by {author}") await ctx.send(embed = snipeEmbed)
核心修改说明
- 新增
on_bulk_message_delete事件监听,处理clear指令批量删除的消息 - 存储结构改为每个频道存多条被删消息,不会因为最后删除的指令消息覆盖普通用户消息
- 增加过期消息自动清理逻辑,替代原有不稳定的sleep协程方案
- 新增过滤规则自动排除指令类消息,snipe默认返回最新的普通用户被删消息,也支持传入索引参数获取更早的被删消息,比如
$snipe 1返回倒数第二条被删的普通消息
内容的提问来源于stack exchange,提问作者user16186190
相关产品推荐
相关产品推荐

