微信群照片归档(macOS 版)
> ⚠️ 平台限制:本技能只适用于 macOS。
> 脚本里写死了 macOS 专属的路径与工具 —— ~/Library/Containers/com.tencent.xinWeChat 缓存目录、
> rsync 同步、openssl 解密、launchd 常驻,在 Windows 上一个都用不了。
> Windows 用户请安装 wechat-photo-archive-win,
> 那一版已完成全部平台替换(robocopy / 纯 Python AES / 计划任务 / 注册表定位微信缓存),
> 并且针对微信 4.x 的 .dat 新格式做了适配。
把工作群里刷屏的照片自动归集 → 去重 → 按群名/年月整理 → 存到电脑文件夹 + NAS 备份。
典型场景
> 群里天天有人发照片,手机内存撑不住了,但一张都不敢删。
项目群、客户群、班组群、家校群……同事每天往群里甩现场照、验收照、截图、活动照,几个月下来手机相册里塞了几千张:
- 不敢删:删了怕哪天要找,聊天记录一过期就再也翻不出来
- 不好找:想找三个月前某张现场照,只能靠记忆在聊天记录里往上翻
- 占空间:手机存储长期告急,换机迁移慢,云空间还得续费
用它之后:群里的照片自动落到你的个人电脑文件夹(并同步一份到 NAS),按「哪个群 / 哪年哪月」分好目录、同名重复图只留一份。手机这边可以放心清理腾空间,要找图直接开文件夹按时间翻,NAS 上还多一层本地备份,换手机、清缓存都不慌。
适合:项目/施工/巡检群、门店与销售群、家校与班级群、社团活动群,以及任何"照片刷屏但得留档"的群。
设计前提(重要)
个人微信没有官方开放 API,任何协议级 hook(wechaty 之类)都有封号风险且主流 puppet 已失效。本技能只用官方/本地只读手段:
| 通道 | 机制 | 能否识别群名 | 风险 |
|---|---|---|---|
| 企业微信 | 官方「接收消息」回调,群聊里 @应用 发图才推(全量群消息需付费的会话存档 API) | ✅ ChatId→群名映射 | 无(官方 API) |
| 个人微信 | 扫描微信客户端本地图片缓存 / 手机相册同步目录 | ❌ 缓存无群名 → 落 未分组 |
无(只读本地文件) |
个人微信通道的群名限制无法绕过(除非破解加密数据库,不做)。实用替代:让手机端把群图自动备份到独立目录(iOS 快捷指令 / Android Tasker / Synology Photos 备份),在配置里给该目录指定 group 别名,即可实现"按目录=按群"的变相分组。详见 references/setup-personal-wechat.md。
企业微信的 media_id 只保留 3 天,所以接收器必须常驻(后台跑),不能等手动触发再拉;手动触发的是「整理归档 + NAS 同步」这一步。
目录布局
~/Pictures/微信照片归档/
├── _staging/ # 采集缓冲(各通道原始落地)
│ ├── 企业微信/
│ └── 个人微信/
├── 库/ # 正式归档库
│ └── <通道>/<群名>/<YYYY-MM>/
└── _index/manifest.jsonl # 去重索引(sha256 + 来源 + 时间)
NAS 目标默认 ~/mnt/nas/admin/Drive/微信照片归档(本地库的 rsync 镜像)。
命令
PY=/Users/weiwu/.workbuddy/binaries/python/versions/3.13.12/bin/python3
S=~/.workbuddy/skills/wechat-photo-archive/scripts
# 手动归档主入口(采集 → 整理 → 同步 NAS)
$PY $S/archive.py ingest
# 分步
$PY $S/archive.py scan # 只采集到 _staging
$PY $S/archive.py organize # staging → 库(sha256 去重、按群/年月归类)
$PY $S/archive.py sync # 库 → NAS
$PY $S/archive.py status # 查看各目录计数、最近归档、NAS 是否可写
# 常用参数
$PY $S/archive.py ingest --since 30d # 个人微信只扫最近 30 天(默认 7d)
$PY $S/archive.py ingest --dry-run # 只打印计划,不落盘
$PY $S/archive.py ingest --prune-staging # 归档成功后清空缓存区
# 企业微信接收器(常驻后台,media 有效期 3 天,必须常驻)
nohup $PY $S/wecom_receiver.py >> ~/Library/Logs/wecom-receiver.log 2>&1 &
首次配置
编辑 config.yaml(技能根目录):
paths.*—— staging / library / nas 三个目录(默认已按你的环境填好)personal.sources—— 个人微信通道的源目录列表,每项可指定group别名wecom_api.*—— 企业微信 corpid / secret / token / encoding_aes_key(先留空也能跑个人微信通道)
企业微信回调要配公网地址,用你已有的 Cloudflare Tunnel 加一条 ingress 指向本机 127.0.0.1:8099/wecom/callback。步骤见 references/setup-wecom.md。
归档规则
- 去重:sha256 命中 manifest 则跳过,同一张图重复收发只留一份
- 命名:
YYYY-MM-DD_HHMMSS_<hash前8位><ext>,目录库/<通道>/<群名>/<YYYY-MM>/ - 时间来源:企微用消息 CreateTime;个人微信只能取文件 mtime
- 格式识别:靠 magic bytes 判定真实类型(jpg/png/gif/webp/heic/mp4),
.dat加密缓存自动尝试异或还原 - 不删源:staging 默认保留,需
--prune-staging才清
坑
- NAS(SMB)禁止 unlink 删除,sync 只用
rsync -a,不要加--delete - 企微 media 3 天过期 → 接收器挂了会丢图,
status会显示 staging 积压数量 - 个人微信缓存目录随客户端版本变,
scan找不到时按references/setup-personal-wechat.md重新定位 - 后台常驻进程可能被系统回收,企微通道建议配 launchd(references 里有 plist 样例)