"""Conversation id helpers for Douyin IM.""" def parse_conversation_parts(conversation_id: str) -> tuple[int, int] | None: parts = (conversation_id or "").split(":") if len(parts) >= 4 and parts[0] == "0" and parts[1] == "1": try: return int(parts[2]), int(parts[3]) except (TypeError, ValueError): return None return None def resolve_peer_uid(conversation_id: str, my_uid: int) -> int | None: """Resolve peer user id from conversation id or bare numeric id.""" raw = (conversation_id or "").strip() if not raw: return None parts = parse_conversation_parts(raw) if parts: uid1, uid2 = parts if my_uid and uid1 == my_uid: return uid2 if my_uid and uid2 == my_uid: return uid1 # 0:1:{my}:{peer} — 若 my_uid 与首段不一致,仍取末段为对方 return uid2 if raw.isdigit(): peer = int(raw) if my_uid and peer == my_uid: return None return peer return None def build_conversation_id(my_uid: int, peer_uid: int) -> str: return f"0:1:{int(my_uid)}:{int(peer_uid)}" def normalize_conversation_id(conversation_id: str, my_uid: int) -> str: """Ensure conversation id uses current account uid as first participant.""" peer_uid = resolve_peer_uid(conversation_id, my_uid) if peer_uid and my_uid: return build_conversation_id(my_uid, peer_uid) return (conversation_id or "").strip() def conversation_belongs_to(conversation_id: str, my_uid: int) -> bool: """判断单聊会话是否属于 my_uid 本人。 托管多个账号时,一条属于别的账号的会话(例如 frontier 长连接按设备号寻址 造成的跨账号推送)一旦流进本账号的处理链路,resolve_peer_uid 会把末段当成 「对方」、normalize_conversation_id 再拼成 0:1:{本账号}:{别人的好友},于是 本账号就把消息发给了另一个账号的好友。这里给出唯一的归属判据。 无法判定时一律返回 True(保守放行):缺 my_uid、群聊、裸 UID 等形态本来就 不带参与方信息。只有两个参与方都已知、且都不是本账号时才判定为不属于本账号。 """ try: uid = int(my_uid or 0) except (TypeError, ValueError): return True if not uid: return True parts = parse_conversation_parts(conversation_id) if not parts: return True return uid in parts