Repository navigation
fix: 回流社区 Fork 中的 13 项修复与增强(基于当前 main 重写) - #180
Merged
2977094657 merged 13 commits intoOct 7, 2026
Merged
2977094657 merged 13 commits into
2977094657 merged 13 commits into
Conversation
start_chat_search_index_build 在持有不可重入的 _BUILD_LOCK 时,若该账号已处于 building,会直接调用 get_chat_search_index_status,后者再次获取同一把锁, 调用线程永久挂起且锁不再释放;/api/chat/search-index/build 是 async 路由, 事件循环会被一并卡住。 现在锁内只判断并登记构建状态,状态查询挪到锁外执行(未改用 RLock:状态查询要读库,不该占着构建线程也要用的锁)。 新增带超时的线程回归测试,使用独立的锁与状态,回归时不会占住模块级的锁; 另补一个测试,确认全新构建只登记一次状态、只启动一个 worker。 回流自 dsdffgh/WeChatDataAnalysis@91c060a(已基于当前 main 重写)。 Co-authored-by: dsdffgh <94230177+dsdffgh@users.noreply.github.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
GET /api/account/archive_export/download?path= 只校验后缀,后端进程可读的任意 .zip/.wec 都能被取走。
现与聊天、朋友圈导出保持一致,改为 GET /api/account/archive_export/{export_id}/download:
文件路径只取自服务端任务的 zip_path,任务不存在返回 404,未完成返回 409,?path= 不再生效。
zip_path 在任务开始时就已写入,所以显式要求 status 为 done,避免取到同名旧文件或未写完的文件。
前端 GlobalExportDialog 同步改用 export_id,仓库内没有其他调用方。
回流自 ruiyang-xu/WeChatDataAnalysis@9385026(已基于当前 main 重写)。
Co-authored-by: ruiyang-xu <44563622+ruiyang-xu@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
导出面板的消息类型里没有“位置”,而面板总是提交勾选清单、服务端按清单过滤, 位置消息因此永远导不出来;接口的 MessageType 也不接受 location,直接 422。 现在面板(默认勾选,顺序与导出页的类型筛选一致)和接口都补上 location。 增量目录把消息类型计入配置指纹,此前用面板建立的目录基线里都没有位置,默认多勾这一项 就会被判成 incremental_config_mismatch。基线只差“位置”一项时改为沿用基线的类型清单 继续更新,并在任务结果里提示本次未导出位置消息;重置基线后按新清单重建,其它勾选变化 照旧拒绝。 回流自 dsdffgh/WeChatDataAnalysis@92de4cd(已基于当前 main 重写)。 Co-authored-by: dsdffgh <94230177+dsdffgh@users.noreply.github.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
扫描循环末尾的 macOS 兜底会把任何直接子目录形似账号目录的扫描路径加入结果, 而扫描路径包含用户主目录、Documents、Desktop、Downloads,账号目录的判定又只要求 目录下直接有 *.db,于是 ~/.hermes/state.db 这类无关目录会被列为微信账号。 删除该兜底。macOS 的其余扫描路径(com.tencent.xinWeChat、版本号目录、 xwechat_files)都按名称匹配,而名称匹配分支的 _contains_wechat_accounts_within(depth=2) 第一步就是兜底所用的 _contains_wechat_account_dirs,兜底对它们不会再多加任何结果;名称不认识的版本 目录本来就不会成为扫描路径,由 com.tencent.xinWeChat 根目录的 depth=2 查找覆盖。 所以该兜底唯一的可见效果就是把上述四个通用目录加进结果。 行为变化:直接放在这四个目录下的账号目录(如 ~/Desktop/wxid_xxx/db_storage) 在 macOS 上不再被自动检测,需要放进名称含 WeChat/微信 的父目录,或手动填写 数据目录,与 Windows 一直以来的行为一致。通用目录下名称匹配的子目录照常识别, 账号目录的判定规则未改;该兜底仅 darwin 进入,Windows 行为不变。 回流自 denghy46-cloud/WeChatDataAnalysis@05bb180(已基于当前 main 重写)。 Co-authored-by: denghy46-cloud <230619540+denghy46-cloud@users.noreply.github.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
fix_sns_cdn_url() 会把朋友圈 CDN 地址强制升级为 https,但 vweixinthumb.tc.qq.com 与 vweixinf.tc.qq.com 返回的是 *.video.qq.com 证书,后端代理校验证书失败, 视频封面、实况缩略图走到远程下载时 /api/sns/media 与 /api/sns/video_remote 返回 502。 这两个主机都是 socwxsns.video.qq.com 的 CNAME,现在升级 https 时一并换成该主机名。 别名仍在主机白名单内;远程缓存键随改写后的主机名变化,读写两侧保持一致。 只取 fork 提交中主机别名的部分,并补上同样证书不匹配的 vweixinf.tc.qq.com。 vweixinf.tc.qq.com 的依据是实测的 CNAME 与证书不匹配,尚未用真实媒体地址验证过取回内容; 这两个主机此前在 TLS 握手阶段必然失败,改写不会让原本可用的地址变差。 回流自 dsdffgh/WeChatDataAnalysis@242c481(已基于当前 main 重写)。 Co-authored-by: dsdffgh <94230177+dsdffgh@users.noreply.github.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
.dat 图片的 XOR 解码有 5 处用 bytes(b ^ key for b in data) 逐字节循环, 按魔数猜 key 的 256 轮预览穷举也走解释器循环。新增 _xor_bytes:按 key 缓存 256 字节映射表后交给 bytes.translate,只用标准库,不引入 numpy。 本机 4 MiB 输入下,v3 整文件、v4 XOR 尾段、猜 key 命中从约 100 ms 降到 1–2 ms,256 轮预览全部落空从约 60 ms 降到约 12 ms。 非空输入遇到越界 key 与原实现一样抛 ValueError(空输入原先返回 b"", 现在同样报错);其他模块里 16 字节 salt 的 XOR 不在热路径,未改。 回流自 DYY-Studio/WeChatDataAnalysis@5ce5d67(已基于当前 main 重写)。 Co-authored-by: DYY-Studio <48157880+DYY-Studio@users.noreply.github.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
_get_wxam_decoder() 在非 Windows 上恒为 None,macOS/Linux 上的 wxgf 图片 全部解不出来。现在没有 WxAM 解码器时,把容器里的 HEVC 码流经 stdin 交给 ffmpeg(桌面端已打包并通过 WECHAT_TOOL_FFMPEG 传入),从 stdout 取回 JPEG: 不落临时文件、一份文件总计 20 秒超时、任何失败都返回 None、Windows 下不弹控制台窗口。 WxAM 解码器存在时行为不变。 分区按「起始码 + VPS」定位,并按它前面的 4 字节长度截断,长度对不上 (文件被截断)就放弃。只转换单帧 JPEG 能如实表示的图片:多帧动图,或 [alpha, 画面] 两个分区里 alpha 不是全不透明时返回 None,调用方照旧走 原有回退(表情仍取远程 GIF),不缓存降级后的画面。ffmpeg 以 -xerror -err_detect explode 运行,解码报错即失败,但只能拦住一部分码流损坏。 数据可能来自远程地址,所以分区数(至多两个)、NAL 数量和画面像素数 (-max_pixels)都设了上限,超出即放弃,不启动或提前终止解码。 转换结果(含失败)按内容缓存,上限 16 MiB:一次读取里的重试、图片请求 重新比较各变体时不再重复启动进程;失败日志只保留 stderr 结尾。表情接口 读本地文件、解码远程表情都改到线程里执行。输出 -q:v 3、不带容器里的 ICC,边长为奇数时 按 HEVC 编码尺寸多出 1 像素。 回流自 dohard-ma/WeChatDataAnalysis@a06f9ad(已基于当前 main 重写)。 Co-authored-by: dohard-ma <31983261+dohard-ma@users.noreply.github.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
account_keys.json(数据库密钥、图片密钥)和账号目录下的 _media_keys.json 按默认 umask 写出,通常是 0644。现在写入密钥前先把文件(原子写入时是 临时文件)建成 0600,已存在的更宽权限也先收紧,密钥不会以更宽的权限 落盘;收紧失败时静默忽略;只在 POSIX 上执行,Windows 上没有行为变化。 POSIX 上只读的 _media_keys.json 会被改成 0600 并更新,此前这种情况下写入会静默失败。 这是纵深防御:macOS 桌面端默认数据目录在 ~/Library(0700)下,本来就 只有属主能进,受益的是自定义或共享的输出目录和源码运行。已存在的 0644 文件要到下一次写入才收紧;导入账号时复制过来的 _media_keys.json、解密后 的数据库和目录本身的权限不在本次范围内。 回流自 ruiyang-xu/WeChatDataAnalysis@9385026(已基于当前 main 重写)。 Co-authored-by: ruiyang-xu <44563622+ruiyang-xu@users.noreply.github.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
_resolve_contact 把候选字段转成小写后仍用原始大小写的 query 做子串判断, query 含大写字母时拿不到子串分:"Alice" 命中备注 Alice 的联系人也只有保底 20 分。 _mobile_resolve_target 对不带 confidence 的候选(朋友圈用户)按返回位置给 max(20, 80 - idx*8),发圈最多的用户固定 80 分,会排到真正命中的联系人前面。 现把联系人打分提取为 _match_confidence,子串判断改用小写 query(精确用户名加分 仍区分大小写,未改),无 confidence 的候选复用这套规则。只按名称子串命中的联系人 和朋友圈用户同为 60 分,联系人靠查询顺序和稳定排序排在前面;会话仍用 _resolve_session 自己的规则。同一个人同时作为联系人和朋友圈用户返回时分数相同, ambiguous 因此改为只和 id 不同的候选比较。 公众号结果在 main 上进不了候选列表(接口把列表放在 data 下),本次未处理。 原提交的其它改动(紧凑 JSON、拼音、并行化等)未带入。 回流自 C-Li/WeChatDataAnalysis@8e95b7c(已基于当前 main 重写)。 Co-authored-by: C-Li <20661667+C-Li@users.noreply.github.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
moments.get_media_url / get_remote_video_url、media.get_chat_emoji_url / get_chat_video_thumb_url / get_chat_video_url / get_chat_voice_url、mobile.get_media_links / get_message_media_bundle 注册时 properties 为空,LLM 客户端无从得知可传哪些参数。现按 get_chat_image_url 的写法声明处理函数 实际读取的参数(含 tid、msg_svr_id、session_id、link_url 等兼容别名),工具描述一并改为中文, 保留 additionalProperties=true 且不加 required;重复的 server_id、表情远程地址两组提成常量。 mobile.get_media_links 把参数原样转给各专用处理函数,门面上只声明常用参数:fetch_remote 等 聊天图片选项和朋友圈缓存定位项不公布(仍可传入),需要时按描述改用带额度提示的专用工具。 server_id / msg_svr_id 可能超过 2^53,按 resolve_app_message 的做法声明为十进制字符串; get_chat_image_url 仍声明为 integer,本次未改,留待后续统一。 新增测试核对八个工具声明的参数集合,并逐个探测已声明的参数确实会改变返回结果。 回流自 C-Li/WeChatDataAnalysis@f502c55(已基于当前 main 重写)。 Co-authored-by: C-Li <20661667+C-Li@users.noreply.github.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
_matches_keyword 只做 username/显示名/备注/昵称等字段的子串匹配,联系人页搜索框、 联系人导出和 MCP 联系人工具输入 "zw"、"zhangwei" 都找不到“张伟”。 现在关键词为纯 ASCII 字母时,再对含汉字的显示名/备注/昵称做拼音匹配:逐字首字母串按子串匹配; 全拼只允许从音节边界起做前缀匹配("zhangw"、"wei" 命中,"an"、"hang" 不命中)。 词语读音沿用 pypinyin 消歧,首字是多音字姓氏时同时接受姓氏读音与默认读音,lüe/nüe 兼收 lue/nue。 字段子串命中的联系人排在仅拼音命中的之前,MCP resolve_contact 这类只取前 N 条的调用方 不会因为新增的拼音命中丢掉原有结果。 仅拼音命中的联系人在 MCP 里按现有打分规则得到最低置信度 20,没有单独加分。 名称转换结果用 lru_cache 缓存;非字母关键词和不含汉字的名称不做拼音匹配,原有子串匹配不变。 聊天页会话列表的搜索是前端本地过滤,不在本次范围内。 回流自 C-Li/WeChatDataAnalysis@8e95b7c(已基于当前 main 重写)。 Co-authored-by: C-Li <20661667+C-Li@users.noreply.github.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
validate_url 只对 localhost/127.0.0.1/::1 放行 http,局域网内其他机器上的 Ollama、 LM Studio、vLLM 既不能保存配置,也不能获取模型列表。 现额外放行 RFC 1918(10/8、172.16/12、192.168/16)与 IPv6 唯一本地地址(fc00::/7) 的 IP 字面量。网段显式列出,不用 is_private(它还含 0.0.0.0/8、169.254/16 等)。 不解析域名;域名、公网 IP、链路本地、CGNAT、IPv4 映射地址和其他回环写法仍必须使用 HTTPS,报错文案改为说明该规则。 设置页原先只把回环地址上的 Ollama / LM Studio 视为免密钥的本地服务,改填局域网 IP 后 会提示先填写密钥,也不自动获取模型。现改为按协议判断(后端只对本机和局域网 IP 放行 http),不在前端重复网段规则;非本机的 http 地址另外提示明文传输。 这是对原有限制的放宽:保存后的局域网 http 配置会被自动任务和关注提醒持续使用,聊天 内容和密钥以明文发往该 IP,且无法校验对端身份。文档已补充规则与风险。 回流自 GTBABC/WeChatDataAnalysis@25c51b9(已基于当前 main 重写)。 Co-authored-by: GTBABC <30303859+GTBABC@users.noreply.github.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
README 写明 main.py 会在导入项目包前优先加入当前仓库的 src 并打印代码来源, 但 LifeArchiveProject#84 只合入了这段文档,main.py 里并没有对应逻辑:按 README 执行 `uv sync --no-editable` 后,`uv run --no-sync main.py` 运行的是 site-packages 里的旧副本,改代码或拉取更新都不会生效。 现在 main.py 在任何项目包导入之前把 <repo>/src 放到 sys.path 最前(仅当该目录存在), 并在启动横幅里打印 wechat_decrypt_tool 的代码来源;打包入口 backend_entry.py 未改动。 非 editable 安装下,包内按 __file__ 定位的资源(native 目录、前端静态产物)也随之改从仓库读取。 回流自 Leslie0Han/WeChatDataAnalysis@54a4fb6 与 shierqi/WeChatDataAnalysis@c4f3053(已基于当前 main 重写)。 Co-authored-by: Leslie0Han <98613843+Leslie0Han@users.noreply.github.com> Co-authored-by: shierqi <129961263+shierqi@users.noreply.github.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
这个 PR 是什么
把社区 Fork 里只存在于 Fork、上游至今仍缺的 13 项修复与小增强回流到
main。每一项都没有直接 cherry-pick,而是对照当前main(5d489aa,2.8.0 之后)重新实现、补回归测试,并在提交里署了原 Fork 作者(Co-authored-by)。筛选范围:上游全部 1166 个可见 Fork(1293 个分支头)→ 43 个带 Fork 作者自有提交的分支 → 拆出 113 项改动逐项对照
main与历史 PR → 选出这 13 项。没选的见文末。一项一个提交,可以单独审、单独回退;不想要的提交直接 drop 即可,彼此没有依赖(
media_helpers.py的三个提交按顺序排列)。提交清单
fix(search-index)索引构建自死锁async,整个后端事件循环被卡住91c060afix(export)账号归档下载按 export_id 取文件GET /api/account/archive_export/download?path=只校验后缀,后端进程可读的任意.zip/.wec都能被取走(无鉴权、CORS*)9385026fix(chat-export)导出面板补上「位置」MessageType都缺location,位置消息永远导不出来92de4cdfix(detection)macOS 自动检测误报~、~/Documents、~/Desktop、~/Downloads下任何直接含*.db的目录都被当成微信账号05bb180fix(sns)朋友圈视频封面 TLS 主机别名vweixinthumb.tc.qq.com/vweixinf.tc.qq.com返回的是*.video.qq.com证书,强制升级 https 后校验必然失败,接口返回 502242c481perf(media)单字节 XOR 改查表.dat解码用bytes(b ^ key for b in data)逐字节跑 Python 循环;4 MiB 实测约 100 ms → 约 1.5 ms(纯标准库,无新依赖)5ce5d67fix(media)非 Windows 下用 ffmpeg 解码 wxgfa06f9adfix(keys)密钥文件 0600account_keys.json、_media_keys.json按默认 umask 写出(通常 0644)9385026fix(mcp)联系人/目标解析打分8e95b7cfix(mcp)八个媒体工具补全入参 schemaget_chat_image_url的做法)f502c55feat(contacts)联系人搜索支持拼音zw/zhangwei找不到「张伟」;现支持首字母与按音节边界的全拼前缀8e95b7cfix(ai)局域网 IP 的模型服务允许 HTTP25c51b9fix(dev)源码启动优先加载仓库srcmain.py会这么做,但对应代码从未合入(#84 只带进了文档),uv sync --no-editable后实际跑的是 site-packages 里的旧副本54a4fb6、shierqic4f3053需要你拿主意的地方
第 12 项是对一条刻意设置的限制的放宽,请单独判断要不要:
10/8、172.16/12、192.168/16)和 IPv6 ULA(fc00::/7)。不解析域名(nas.local仍须 HTTPS),链路本地(含169.254.169.254)、0.0.0.0/8、CGNAT100.64/10、IPv4 映射地址都仍然拒绝。docs/chat-ai.md加了提示,但没有做代码层面的限制。ChatOpenAI/ChatAnthropic/AsyncOpenAI)用的是 SDK 默认 httpx 客户端,会跟随重定向(HTTPS 地址本来也如此;catalog()已是follow_redirects=False)。改这三处客户端构造牵涉面较大,没放进这个 PR。行为变化
/api/account/archive_export/download?path=不再存在,改为/api/account/archive_export/{export_id}/download,与聊天、朋友圈导出一致。仓库内唯一调用方GlobalExportDialog.vue已同步;仓库外若有人直接调旧地址会得到 404。incremental_config_mismatch:请求去掉「位置」后若与基线指纹一致,该目录继续按基线类型更新(不导位置消息),并在任务结果里多显示一行说明;重置基线或换新目录后才包含位置。~、~/Documents、~/Desktop、~/Downloads下的账号目录(没有名称含 WeChat/微信 的父目录)在 macOS 上不再被自动检测,需手动填数据目录。实现上是删掉了那段 darwin 专属兜底——对其余扫描路径它本来就不会多加任何结果。Windows 不受影响。名称匹配的目录下含*.db仍会被识别,这个既有问题没动。_media_keys.json现在会被改成 0600 并更新(此前写入静默失败)。ambiguous只和「另一个目标」比,同一个人同时以联系人和朋友圈用户出现时不再被判为歧义。additionalProperties仍为 true,原先能用的参数都还能用。get_chat_image_url仍声明为整数,没动。li会命中所有 李/丽/黎…);字段子串命中的排在仅拼音命中的之前,原有结果是新结果的前缀。作用于联系人页、联系人导出和 MCP;聊天页会话列表是前端本地过滤,不受影响。仅拼音命中的联系人在 MCP 里是最低置信度 20。__file__定位的资源(native/、前端静态产物)也改从仓库读取。打包入口backend_entry.py没动。验证
全部在 macOS(Apple Silicon,Python 3.11.15)上完成,没有任何东西在 Windows 上运行过。
tests/test_native_core_voice_asr.py会触发 pytest 内部错误,上游现状),所以对main和本分支各自逐文件运行并比对。main:2362 通过 / 168 失败 / 9 错误(均为main在这台机器上自身的结果);本分支:2509 通过 / 170 失败 / 9 错误。原有用例没有任何一个由通过变为失败;多出的 2 个失败是下文所说第 3 项里依赖wce_integrity的两个新测试。chat-export-model-options.test.js、ai-presets.test.js共 41 个用例通过。vweixinf.tc.qq.com是在 Fork 基础上按同样证据补的,如果只想要 Fork 验证过的那个主机,删掉表里那一行即可。尚未验证、合并前建议看一眼
wce_integrity,仓库里只有 Windows 的.pyd,在 macOS 上和上游同文件的其他用例一样无法运行,只在本地用桩验证过。需要在 Windows 上跑一次tests/test_chat_incremental_export.py和tests/test_chat_export_message_types_semantics.py。chat-image-quality.yml,会在 windows-2022 上首次运行。没有回流的内容
🤖 Generated with Claude Code