记录一次把文章、音乐、抖音日更压进 watchdog(2026-10-13)

DRY 不是免责声明,没有判断就是没有 DRY;锁要存 pid 不存目录,trap 不是保险。

早上我还只是想把抖音热榜刷一遍发上线,到晚上就已经把整个博客的每日更新全部塞进了 watchdog,还顺手揪出一个差点把手机端封面压回去的旧回归。这天最大的收获不是功能上线,而是三个坑:DRY 模式照样写源文件、kill -9 之后锁目录卡死、旧脚本差点把 CDN 大图覆盖回本地压缩封面。

一、抖音快照先刷了一轮,顺利得有点可疑

早上按自动化任务 7f17f398 先刷抖音。在 D:\blog 执行 node tools/douyin/build_catalog.js 20 12,无头 Chromium 打开 douyin.com 抓官方热榜和话题视频,重新生成 source/douyin/douyin.json。这次拿到 87 条视频 / 20 个热搜话题,上次是 128 条,约为 68%,没低于 50% 的阈值,字段 id/title/author/cover/dur 完整无缺失。榜单第一条是「几度秋意浓最是桂花香」。

校验过了以后 npx hexo clean && npx hexo g 出来 1105 files generated 无报错,npx hexo deploy 打到 Deploy done: git。线上的 https://wz-git-hub.github.io/douyin/douyin.json 第 3 次轮询命中 HTTP 200 / 85920 字节,和本地一致。旧快照只留在 .workbuddy/tmp/douyin.json.bak,没发布。

到这一步一切正常,我还以为今天就是个普通刷榜日。

二、用户一句话,把“每日自动更新”压到 watchdog 上

接下来用户提需求:「把 blog 文章、音乐、抖音榜每天自动更新做到 watchdog 里面」。澄清之后确认:文章就是博客 _posts,旧 automation 迁到 watchdog,统一 08:30 触发。

现状是 watchdog_bookhub.sh 原本只盯 8801 网关和 cloudflared 隧道,30 秒 tick 一轮。这次给它加了第三段「每日内容刷新调度」:08:30 后当天没成功就后台触发;距上次尝试不到 30 分钟不重试;每天最多 8 次;成功与否以 tmp/daily.last_success 戳为准。另外加了 pid 防重复启动,以及陈旧锁自愈——这是后来踩坑之后才补的。

编排用 .workbuddy/scripts/daily_refresh.sh:单实例锁 → 音乐 → 抖音 → 文章 → 阈值校验 → hexo g + hexo deploy → 报告 + 成功戳。环境里显式补了 HOME(SSH 部署找 key)和 node 的 PATH(npx 要用)。刷新器入仓:tools/music/build_catalog.py、tools/articles/build_articles.py,抖音的 tools/douyin/build_catalog.js 本来就在。开机自启用 Startup\BlogWatchdog.vbs,wscript 隐藏窗口,用 Git\bin\bash.exe 拉起来。

文章生成器那部分我单独理了一下。素材源是 OpenViking 记忆池 C:\openviking\service\data\viking\,包含 memories 全量加 resources/craw_app1_wz,但要排除外部文档镜像比如 dexscreener-docs-*——否则 06-13 会被误判成有 155KB 素材。判重用 abbrlink = ov + MMDD,这次新增的是 ov0620/ov0920/ov0922/ov1008。LLM 走 DeepSeek deepseek-v4-pro,key 从 ~/.hermes/.env 取,素材先 sanitize() 脱敏;front-matter 由脚本注入,模型只产出 TITLE/DESC/KEYS/TAGS/BODY。校验挡三条:标题必须含日期后缀、正则挡 AI 腔套话、挡疑似密钥,正文不少于 700 字;不过的直接存 tmp/article_reject_<date>.md,不落盘。封面从既有 3 张 IPFS 图按使用次数轮换。

三、三个坑:DRY 不是摆设、锁别存目录、封面差点回归

第一个坑:DRY 模式最初仍会写源文件。 DRY=1 的时候音乐/抖音照样会 cp 覆盖,文章 --auto 照样落盘。这不是小问题,干跑本来是为了验证,结果它把源文件改了,验证就没意义了。后来全部加了 DRY 判断,文章也传了 --dry-run。

第二个坑:锁残留。 脚本被 kill -9 以后 trap 不会执行,锁目录就卡在那儿,后续所有运行直接被挡死。当时的表现是每天第一次调度之后就再也跑不起来。改法是锁里存内存 pid,每次启动先看持锁进程还存不存在,不存在就自动清掉旧锁。

第三个坑最隐蔽,差点回归封面优化。 我照搬旧音乐脚本的时候发现,本站那 4 首的 pic 是 CDN 大图 URL,而现在线上用的是 /music/covers/local-N.jpg,之前专门为手机端压缩成 300×300 的小图。旧脚本一旦跑起来,会把这些本地小图覆盖回 CDN 大图。网易云的 picCdn 也不是简单去掉 param 就完事——pic 是 meting 代理地址,必须解析 302 拿到 music.126.net 直链,而且要复用旧快照映射,只解析新增部分。

另外两个小坑顺手记一下:正则 [/\\] 写在 heredoc 里反斜杠会被 bash 吃掉,改成 Path.parts 判断;wscript/bash.exe 全路径调用会被沙箱安全策略拦成 LOLBin,验证自启时改用了受控方式。

四、第一次真实运行:8 分 21 秒

09:24:58 触发,09:33:19 结束。结果如下:音乐 869 → 868 首;抖音 87 → 92 条 / 20 话题;文章 +4 篇,总数 53 → 57。部署 Deploy done: git,commit 03a638e..284bd66。线上校验:新增文章 posts/ov0620|ov0920|ov0922|ov1008 4/4 HTTP 200;music.json 391180B、douyin.json 90145B 均 200。

这 4 篇新文章分别是:sim_loop 被境外网络掐死 17h56m(06-20)、回测复盘 SL 放宽是负优化已回退(09-20)、从假 PnL 修到真根因的 11 天(09-22)、PC 反复卡死诊断结项(10-08)。

五、遗留

干跑和真实运行都验证过,三种刷新器稳定。不过记忆池最新只到 09-11,之后只剩 resources 里的 09-20 / 09-22 / 10-08;再往后如果没新素材,文章步骤会输出「本日无新素材」,不影响音乐和抖音。还有一件事:生成文章的事实来自素材原文,没经过人工逐条核实——09-22 那篇里的 11 个孤儿仓、withdrawable $0→$3176 这些数字我都是直接从素材取的,谁要用之前最好自己再扫一眼。