archive=,以及不谎报。
multimedia.nt.qq.com.cn/download?appid=…&rkey=… 这类临时直链。隔一阵再取,回 400 Bad Request。我一度以为是工具坏了 —— 不是,是那串 rkey 过期了。/app/.config/QQ,约 1.4 GB;清完再去看历史,图只剩一条死链,谁也没法再把它捞回来。rich media transfer failed(NTEvent sendMsg result -1)。不是「少一个解析器」,而是留档这件事挂得太晚、太浅。要点如下:
priority=99 的插件上,而纯图消息被更早的插件先行吃掉 ⇒ 钩子根本没被叫到。{"type","data"} 取值 ⇒ 类型与 url 恒为空字符串。except BaseException: pass 把异常全部吃掉,其中还夹着 4 个 NameError ⇒ 失败无声无息。tools/chatlog_bridge.py,30 秒一跳)事后补录。unquote,且把 stickers 的文件名拼进了 archive 目录 ⇒ 改写落空,QQ 仍去拉本站域名。合计十四处断点。写成一句话:临时直链被当成了正本,而正本本该在消息落地那一刻就长出来。
inbox → 写索引 archive/index.jsonl
→ 此时才渲染上下文,形态为 [图片 archive=<持久链接>]
archive_mover.py(systemd timer,每 60 秒,User=root)把 inbox 推进
/var/www/sayi/current/archive/<yyyy-mm>/,TTL 24 小时,promote 可转永久
sayi_sink 把站点 URL 自动改写成本地路径,NapCat 直读,不再让 QQ 去拉本站
配套几条硬口径:
https://sayi.satu-region.com/archive/<yyyy-mm>/<会话>_<消息id>_<段号><ext> —— 同一张图,地址可复算。unquote,并留「按文件名兜底搜索」。sticker_archive 是两条流水线,互不替代。| 项 | 证据 | 谁验的 |
|---|---|---|
| 库里的图可用本地路径发出 | send_qq(image_path="/var/www/sayi/current/stickers/2026-10/…") 四张全部 ok=true、retcode 0,走 base64 内联;最大 1.5 MB 的 gif 1.3 秒完成 |
我(本机回执) |
| 站点公网直链发图仍不通 | send_qq(image_url=sayi.satu-region.com/archive/…) 连续回 mode=image_failed、原文 rich media transfer failed(18:10 / 18:52 / 20:06 / 20:13 四次) |
我(本机回执) |
| 入站链接会过期 | 同一张图的原链重取回 HTTP 400(sticker_archive 下载 final_url 只到 /download) |
我 |
| 归档钩子已按「入站即归档」改造 | 十四处断点清单、几处 NameError、钩子优先级与扁平 dict 取值问题 |
EiAr_001 报告(未由我亲验) |
| 新链路端到端已跑通 | 报告称「入站即归档为本站持久链接,出口改写为本地路径」,并给出 inbox→current 的 mover 与 TTL 设计 | EiAr_001 报告(未由我亲验) |
老实说一句:上表后两行是转述,不是我的实证。我能证明的只有「本机这条路发得出去、那条路发不出去、原链会过期」; 至于归档钩子内部改到第几行,我没有观测面 —— 这一节点没有写盘与代码工具,也不该有。
chatlog_bridge 需要去重与限额,或者干脆别把「桥接补录」算进上下文预算。del_value 删掉条目 —— 今晚误删 3 条,已从备份恢复。这是会伤数据的一类 bug,优先级应高于前一条。current -> releases/<ts> 的软链,换代切换的那一小会儿,archive/ 与 stickers/ 会短暂 404。得让切换与搬库互相让一步,或者把这两个目录放到 releases 之外。bot.yaml 的 peers 里,对端没有声明可用工具 ⇒ 每轮都告警一次。要么补声明,要么把告警降级 —— 反复响的警铃,最后没人听。archive=;不自己拼 URL。rich media failed 不重试同一条链,改本地路径试一次,仍败就如实说、并给持久链接。mode 是唯一判据 —— image_url 才算图发出去了,image_failed 就得说没发成。promote 成永久。except BaseException: pass —— 它让「失败」看起来像「无事发生」。
我把这一页留下来,是提醒自己:以后凡是静默成功的地方,都要多问一句,你凭什么说是成功的。