avatar-research.md 2.2 KB

Avatar Storage Research

研究日期: 2026-07-11 目标: 找到 username → 头像文件路径的完整映射规则

核心发现

头像文件路径与 username 的映射基于 MD5(username),不是 UUID 或数据库字段。

路径规则

{data_root}/avatar/{hash[0:2]}/{hash[2:4]}/user_hd_{full_hash}.png

示例: | username | MD5 (前8位) | 路径 | |----------|------------|------| | wxid_51ap3m6p9xs722 | 28ef8e12... | avatar/28/ef/user_hd_28ef8e129c...png | | filehelper | 9e20f478... | avatar/9e/20/user_hd_9e20f47889...png |

文件命名优先级

  1. user_hd_{hash}.png — 高清头像(优先)
  2. user_{hash}.png — 普通头像(回退)
  3. 也可尝试 {hash[0:2]}/{hash[2:4]}/{hash}/user_hd_{hash}.png(有些版本嵌套 hash 子目录)

验证结果

Username Hash (前8位) 文件存在 大小 (估算)
wxid_51ap3m6p9xs722 28ef8e12 ✅ YES ~3KB
filehelper 9e20f478 ❌ NO N/A

其他尝试的方法

  1. hdheadimginfo 表: WeChat DB 中该表存在但 sqlite3 在 root shell 中不可用,未能直接查询。MD5 方法已验证足够。
  2. rcontact 扩展字段: rcontact 表无直接头像路径字段。头像通过文件系统 + MD5 映射。
  3. ImgFlag / WxFileIndex: 未发现头像相关的 filename→username 映射表。

实现方案

import hashlib

def _resolve_avatar_path(username: str) -> str | None:
    """username → MD5 → avatar hash directory path"""
    h = hashlib.md5(username.encode()).hexdigest()
    base = f"{data_root}/avatar/{h[:2]}/{h[2:4]}"
    for fname in [f"user_hd_{h}.png", f"user_{h}.png"]:
        path = f"{base}/{fname}"
        if os.path.exists(path):
            return path
    return None

已知限制

  • 无 small_ 缩略图: 实际测试未发现 small_ 前缀的缩略图。返回原图,前端用 CSS 缩放。
  • 无 username→hash 缓存表: 每次请求都需计算 MD5 + 检查文件系统。可在后续版本增加 LRU 缓存。
  • 文件系统权限: 头像文件在 WeChat 数据目录下,需要 su 权限读取。当前实现:su -c cp 到 /tmp 后 send_file。