如何解决Discord中fetchAuditLogs语音操作日志合并计数问题
解决Discord审计日志合并导致的用户断开/移动操作跟踪问题
问题分析
Discord会在5分钟内合并同一管理员的重复断开/移动操作,仅显示累计计数,这导致仅通过fetchAuditLogs({limit:1})只能获取合并后的条目,无法捕捉每一次单独操作。以下是两种可行的解决思路:
方法1:跟踪审计日志条目的计数变化
通过缓存最近的审计日志条目,每次触发voiceStateUpdate时对比最新条目与缓存的计数差异,以此识别合并操作的次数。
代码示例:
// 缓存每个服务器的最近审计日志信息(键:guildId,值:{entryId, count, timestamp}) const auditLogCache = new Map(); client.on('voiceStateUpdate', async (voiceOld, voiceNew) => { // 跳过无意义的状态变更(如静音/取消静音) if (!voiceOld.channel || (voiceNew.channel && voiceOld.channel.id === voiceNew.channel.id)) return; const guild = voiceOld.guild; // 获取最新的断开操作审计日志 const auditLogs = await guild.fetchAuditLogs({ limit: 1, type: "MEMBER_DISCONNECT" }); const latestEntry = auditLogs.entries.first(); if (!latestEntry) return; const cacheKey = guild.id; const cachedEntry = auditLogCache.get(cacheKey); if (cachedEntry && cachedEntry.entryId === latestEntry.id) { // 同一合并条目,计数有新增 const countDiff = latestEntry.extra.count - cachedEntry.count; if (countDiff > 0) { console.log(`管理员 ${latestEntry.executor.tag} 新增断开了 ${countDiff} 位用户,累计:${latestEntry.extra.count}`); } } else { // 新的操作条目 console.log(`管理员 ${latestEntry.executor.tag} 断开了 ${latestEntry.extra.count} 位用户`); } // 更新缓存并设置5分钟过期(匹配Discord的合并窗口) auditLogCache.set(cacheKey, { entryId: latestEntry.id, count: latestEntry.extra.count, timestamp: Date.now() }); setTimeout(() => auditLogCache.delete(cacheKey), 5 * 60 * 1000); });
方法2:结合voiceStateUpdate事件本身统计操作
每次用户断开或移动频道都会触发voiceStateUpdate,可以直接在事件中判断状态变化,再通过审计日志验证操作是否由管理员发起,以此统计每一次操作。
代码示例:
client.on('voiceStateUpdate', async (voiceOld, voiceNew) => { let actionType = null; // 判断操作类型:断开或移动 if (voiceOld.channel && !voiceNew.channel) { actionType = "MEMBER_DISCONNECT"; } else if (voiceOld.channel && voiceNew.channel && voiceOld.channel.id !== voiceNew.channel.id) { actionType = "MEMBER_MOVE"; } if (!actionType) return; const guild = voiceOld.guild; const auditLogs = await guild.fetchAuditLogs({ limit: 1, type: actionType }); const latestEntry = auditLogs.entries.first(); if (!latestEntry) return; // 验证操作是否为管理员发起(时间差判断避免误匹配) const timeDiff = Date.now() - latestEntry.createdTimestamp; if (timeDiff < 5000) { console.log(`管理员 ${latestEntry.executor.tag} 对用户 ${voiceOld.member.tag} 执行了${actionType === "MEMBER_DISCONNECT" ? "断开语音" : "移动频道"}操作`); } });
注意事项
- 确保机器人拥有
VIEW_AUDIT_LOGS权限,否则无法获取审计日志。 - 方法1中的缓存过期时间建议设置为5分钟,与Discord的日志合并窗口一致,避免无效缓存干扰判断。
- 方法2中的时间差判断可根据实际情况调整,避免因网络延迟导致的误匹配。
内容的提问来源于stack exchange,提问作者Modee.
相关产品推荐
相关产品推荐

