Discord机器人封禁/踢出日志重复发送问题的修复需求
Discord机器人封禁与踢出日志区分修复
问题描述
我编写了Discord机器人的封禁(ban)、解封(unban)和踢出(kick)日志脚本,目前脚本可正常运行,但存在异常:当用户被封禁时,机器人会同时发送封禁日志和踢出日志。需要实现:仅在用户被封禁时发送封禁日志,仅在用户被踢出时发送踢出日志。当前相关代码如下:
client.on(Events.GuildBanRemove, async (ban) => { const fetchedLogs = await ban.guild.fetchAuditLogs({ limit: 1, type: AuditLogEvent.MemberBanRemove, }); const unbanLog = fetchedLogs.entries.first(); const { executor, target } = unbanLog; if (target.id === ban.user.id) { const channel2 = client.channels.cache.get("1026979529387950132"); const embed2 = new Discord.EmbedBuilder() .setColor("#10fee4") .setThumbnail(`${client.user.displayAvatarURL({ size: 2048 })}`) .setTitle(`Log | Usuario Desbanido.`) .setDescription(`**Informações do usuario:**\n > Membro:${ban.user}\n > ID:\`${ban.user.id}\`\n\n**Informações do unban**:\n > Desbanido por: ${executor}\n> ID:\`${executor.id}\``) .setFooter({ text: `© ${client.user.username} 2023` }) .setTimestamp(new Date()); channel2.send({ embeds: [embed2] }); } }); client.on(Events.GuildMemberRemove, async (member) => { const fetchedLogs2 = await member.guild.fetchAuditLogs({ limit: 1, type: AuditLogEvent.MemberKick, }); const kickLog = fetchedLogs2.entries.first(); const { executor, target } = kickLog; if (target.id === member.id) { const channel3 = client.channels.cache.get("1026979529387950132"); const embed3 = new Discord.EmbedBuilder() .setColor("#10fee4") .setThumbnail(`${client.user.displayAvatarURL({ size: 2048 })}`) .setTitle(`Log | Usuario Expulso.`) .setDescription(`**Informações do usuario:**\n > Membro:${member.user}\n > ID:\`${member.user.id}\`\n\n**Informações da expulsão:**\n > Expulso por: ${executor}\n> ID:\`${executor.id}\``) .setFooter({ text: `© ${client.user.username} 2023` }) .setTimestamp(new Date()); channel3.send({ embeds: [embed3] }); } });
问题原因
用户被封禁时,Discord会先将用户从服务器移除(触发GuildMemberRemove事件),再添加封禁记录。当前的GuildMemberRemove事件直接查询踢出类型的审计日志,会误把封禁导致的成员离开判定为踢出,从而重复发送日志。
解决方案
在GuildMemberRemove事件中,先检查该用户是否已被服务器封禁。如果用户处于封禁状态,说明是封禁操作导致的离开,不发送踢出日志;只有当用户未被封禁时,才判定为踢出操作,发送对应日志。
修改后的完整代码
client.on(Events.GuildBanRemove, async (ban) => { const fetchedLogs = await ban.guild.fetchAuditLogs({ limit: 1, type: AuditLogEvent.MemberBanRemove, }); const unbanLog = fetchedLogs.entries.first(); const { executor, target } = unbanLog; if (target.id === ban.user.id) { const channel2 = client.channels.cache.get("1026979529387950132"); const embed2 = new Discord.EmbedBuilder() .setColor("#10fee4") .setThumbnail(`${client.user.displayAvatarURL({ size: 2048 })}`) .setTitle(`Log | Usuario Desbanido.`) .setDescription(`**Informações do usuario:**\n > Membro:${ban.user}\n > ID:\`${ban.user.id}\`\n\n**Informações do unban**:\n > Desbanido por: ${executor}\n> ID:\`${executor.id}\``) .setFooter({ text: `© ${client.user.username} 2023` }) .setTimestamp(new Date()); channel2.send({ embeds: [embed2] }); } }); client.on(Events.GuildMemberRemove, async (member) => { // 检查用户是否被封禁,区分封禁/踢出导致的离开 const isBanned = await member.guild.bans.fetch(member.id).catch(() => false); if (isBanned) return; // 封禁导致的离开,直接返回不发踢出日志 const fetchedLogs2 = await member.guild.fetchAuditLogs({ limit: 1, type: AuditLogEvent.MemberKick, }); const kickLog = fetchedLogs2.entries.first(); if (!kickLog) return; // 无踢出审计日志,直接返回 const { executor, target } = kickLog; if (target.id === member.id) { const channel3 = client.channels.cache.get("1026979529387950132"); const embed3 = new Discord.EmbedBuilder() .setColor("#10fee4") .setThumbnail(`${client.user.displayAvatarURL({ size: 2048 })}`) .setTitle(`Log | Usuario Expulso.`) .setDescription(`**Informações do usuario:**\n > Membro:${member.user}\n > ID:\`${member.user.id}\`\n\n**Informações da expulsão:**\n > Expulso por: ${executor}\n> ID:\`${executor.id}\``) .setFooter({ text: `© ${client.user.username} 2023` }) .setTimestamp(new Date()); channel3.send({ embeds: [embed3] }); } });
关键修改说明
- 在
GuildMemberRemove事件开头添加member.guild.bans.fetch(member.id)判断,若用户已被封禁则直接退出函数,跳过踢出日志发送逻辑 - 增加
if (!kickLog) return判断,避免因无有效审计日志导致的报错
内容的提问来源于stack exchange,提问作者zxszin
相关产品推荐
相关产品推荐

