diff --git a/monitor_web.py b/monitor_web.py index ec5f275..83f3cda 100644 --- a/monitor_web.py +++ b/monitor_web.py @@ -627,6 +627,10 @@ def _convert_hevc_to_jpeg(hevc_path, jpeg_path): # ============ 监听器 ============ class SessionMonitor: + # 改名/备注变更场景的刷新最小间隔(秒)。低于此间隔的 mtime 变化不触发 + # 全量 reload,避免微信高频写 contact.db 时 CPU 抖动。30s 是经验值。 + CONTACT_REFRESH_COOLDOWN = 30 + def __init__(self, enc_key, session_db, contact_names, db_cache=None, username_db_map=None): self.enc_key = enc_key self.session_db = session_db @@ -639,6 +643,43 @@ class SessionMonitor: self.patched_pages = 0 # 已显示消息去重: {(username, timestamp, base_msg_type), ...} self._shown_keys = set() + # contact.db mtime + 上次刷新时间,用于检测改名/备注变更 + self._contact_db_mtime = 0 + self._last_contact_refresh = 0 + + def _maybe_refresh_contacts(self): + """检测 contact.db mtime 变化时全量 reload 联系人缓存。 + + 覆盖三种变更场景: + - 新增联系人(之前 commit e86e00d 只覆盖了这种) + - 修改备注名(issue #67) + - 修改群名 + + 受 CONTACT_REFRESH_COOLDOWN 节流,避免 contact.db 高频变更时反复 reload。 + """ + if not self.db_cache: + return + try: + contact_path = self.db_cache.get(os.path.join("contact", "contact.db")) + except Exception as e: + print(f" [contact] 实时解密 contact.db 失败: {e}", flush=True) + return + if not contact_path: + return + try: + curr_mtime = os.path.getmtime(contact_path) + except OSError: + return + now = time.time() + if curr_mtime <= self._contact_db_mtime: + return # mtime 没变,跳过 + if now - self._last_contact_refresh < self.CONTACT_REFRESH_COOLDOWN: + return # cooldown 中,等下次 + refreshed = load_contact_names(contact_path) + if refreshed: + self.contact_names.update(refreshed) + self._contact_db_mtime = curr_mtime + self._last_contact_refresh = now def resolve_image(self, username, timestamp): """解密图片: username+timestamp → 解密后的图片文件名,失败返回 None""" @@ -1369,22 +1410,11 @@ class SessionMonitor: is_new = prev and (curr['timestamp'] > prev['timestamp'] or (curr['timestamp'] == prev['timestamp'] and curr['msg_type'] != prev.get('msg_type'))) if is_new: + # contact.db mtime 变化时刷新缓存:覆盖新增联系人、改名、改备注、群名 + # 修改等场景(issue #46, #67)。受 cooldown 节流。 + self._maybe_refresh_contacts() display = self.contact_names.get(username, username) is_group = '@chatroom' in username - # 新群/新联系人不在缓存中时,通过 db_cache 实时解密 contact.db 后重新加载 - # (load_contact_names 默认读静态快照,新加的联系人不在里面,这里必须走实时解密) - if username not in self.contact_names: - fresh_contact_db = None - if self.db_cache: - try: - fresh_contact_db = self.db_cache.get(os.path.join("contact", "contact.db")) - except Exception as e: - print(f" [contact] 实时解密 contact.db 失败: {e}", flush=True) - refreshed = load_contact_names(fresh_contact_db) - self.contact_names.update(refreshed) - display = self.contact_names.get(username, username) - if username in refreshed: - print(f" [contact] 新增: {username} -> {display}", flush=True) sender = '' if is_group: sender = self.contact_names.get(curr['sender'], curr['sender_name'] or curr['sender'])