基于Discord.js优化禁言检测:如何获取用户被禁言的频道?
优化方案:检测用户被禁言的频道
原代码通过guildMemberUpdate事件只能捕获用户角色变化,但没法直接得知操作发生的频道——毕竟给用户添加muted角色的操作,可能是频道内命令触发,也可能是服务器后台设置操作的。要解决这个问题,最可靠的方式是查询服务器审计日志,结合角色变更事件定位操作上下文。
优化后的代码
const MUTED_ROLE_ID = "949798282442473582"; const GENERAL_CHANNEL_ID = "791388060683862066"; client.on("guildMemberUpdate", async (oldMember, newMember) => { // 判断是否为刚添加muted角色的操作 const hadMutedRole = oldMember.roles.cache.has(MUTED_ROLE_ID); const hasMutedRole = newMember.roles.cache.has(MUTED_ROLE_ID); if (!hadMutedRole && hasMutedRole) { try { // 拉取最近5条成员角色更新的审计日志 const auditLogs = await newMember.guild.fetchAuditLogs({ type: "MEMBER_ROLE_UPDATE", limit: 5 }); // 筛选出给目标用户添加muted角色的操作记录 const muteAction = auditLogs.entries.find(entry => { return ( entry.target.id === newMember.id && entry.changes.some(change => change.key === "$add" && change.new.includes(MUTED_ROLE_ID) ) ); }); // 获取操作频道信息 const actionChannel = muteAction?.extra.channel; let channelInfo = actionChannel ? `在频道 ${actionChannel} 被禁言` : "被禁言(无法定位操作频道,可能是通过服务器设置/批量操作触发)"; // 发送消息到#general频道 const generalChannel = client.channels.cache.get(GENERAL_CHANNEL_ID); if (generalChannel) { await generalChannel.send({ content: `<@${newMember.id}> ${channelInfo}`, files: [{ attachment: "screenshot/muted.mp4", name: "muted.mp4" }] }); } } catch (error) { console.error("查询审计日志失败:", error); // 日志查询失败时,发送基础提示消息 const generalChannel = client.channels.cache.get(GENERAL_CHANNEL_ID); generalChannel?.send({ content: `<@${newMember.id}> 被禁言`, files: [{ attachment: "screenshot/muted.mp4", name: "muted.mp4" }] }); } } });
关键细节说明
- 使用
fetchAuditLogs获取服务器审计日志,指定类型为MEMBER_ROLE_UPDATE,精准筛选角色变更操作。 - 通过匹配日志条目,找到对应给目标用户添加muted角色的记录,从
extra.channel字段提取操作频道。 - 增加错误处理逻辑,避免因权限不足或日志查询失败导致机器人崩溃。
- 将固定ID提取为常量,提升代码维护性。
注意事项
- 机器人必须拥有
VIEW_AUDIT_LOGS权限,否则无法查询审计日志。 - 如果禁言操作是通过服务器后台批量设置、第三方工具触发,可能没有关联频道,此时会显示无法定位的提示。
内容的提问来源于stack exchange,提问作者Toffi
相关产品推荐
相关产品推荐

