fix: close data integrity and hot-reload review findings

Backfill same-day snapshots for newly added or restored videos, preserve successful fan snapshots on resume, persist incomplete state before forced re-runs, and split collection completion from backup completion so failed backups can retry without API calls. Reject missing data payloads instead of treating them as empty folders, guard against mass-unfav on suspicious empty remote folders, rebuild Bilibili clients when credentials change, recompute primary folder ownership from active relations with per-folder fav_time, preserve original titles for dropped invalid videos, poll config every 60 seconds, and fix favsort verify interval and mixed resource types.
This commit is contained in:
kairee committed 2026-10-31 20:58:36 +08:00
1 parent 178ab64b18
commit 6a21b5d905
21 files changed
+895 -82

No files matched your search

+23 -4
View File
@@ -281,8 +281,9 @@ PRAGMA synchronous = NORMAL;
- P0 已实现的命令行:`python app.py init`、`python app.py sync [--full]`、`python app.py status`。
### 5.2 安全规则- Windows 本地开发时应限制 `config.json` 的文件访问权限;部署到 Linux 时权限必须为 `600`;
- 配置文件每 60 秒检查一次 mtime,收藏夹、分类规则和权重变更后无需重启;
- Cookie 或 CSRF 改变时重建 B 站请求客户端;
- 配置文件每 60 秒检查一次 mtime,凭据、收藏夹、分类规则和权重变更后无需重启;
- Cookie / CSRF 变化时由 `ClientProvider` 重建 B 站请求客户端,并保留该角色的限速与重试策略;
- `schedule.folder_sync_minutes` 与 `schedule.snapshot_at` 在启动时固化,修改后需重启 `run`;
- Telegram 操作必须同时验证 `from.id` 和 `chat.id` 是否为配置的私聊用户;
- 仅允许环境变量临时覆盖敏感配置,不能将真实凭据硬编码进源代码;
- `GET` 路由绝不进行收藏、忽略、拉黑等写操作。
@@ -310,7 +311,8 @@ PRAGMA synchronous = NORMAL;
- `snapshot` 主键为 `(stat_date, aid)`,保证同日幂等;
- `up_stat` 主键为 `(stat_date, mid)`;
- `folder_resource(media_id, aid)` 记录每个收藏夹实际拥有的资源,不能仅依赖 `video.folder_id`;
- `video.folder_id` 表示视频的主归属夹,用于新视频同 UP 归属和排序;
- `folder_resource.fav_time` 记录该视频在该夹的加入时间,用于跨夹主归属选择;
- `video.folder_id` 表示视频的主归属夹,按有效收藏关系重算,不依赖收藏夹遍历顺序;
- `up_blacklist` 只在发现任务中生效,收藏夹同步不得用它过滤既有视频;
- `seen_aid` 永久保留搜索去重标记,候选过期删除后也不重复通知;
- `fav_action` 保存 Telegram 或签名链接的动作状态,防止重复点击造成重复写入。
@@ -409,8 +411,11 @@ P1 实现说明:
- 时区使用固定 UTC+8(中国无夏令时),避免 Windows 缺少 `tzdata`;
- 当日全部视频与粉丝采集成功后在 `kv` 写入 `snapshot:completed:<date>=1`;启动时未完成会补跑;
- `ok=0` 的当日记录会在下次补跑时重试;`ok=1` 直接跳过;
- 完成标记不是唯一门槛:每次检查 `pending_snapshot_aids(date)`,新入库或从 `dropped` 恢复的视频会立即补采当天快照;
- `ok=0` 的当日记录会在下次补跑时重试;`ok=1` 直接跳过;粉丝同样跳过已成功的 `(stat_date, mid)`;
- 开始采集前先写 `snapshot:completed:<date>=0`,强制重采中断后不会残留旧的完成标记;
- 每次采集后生成 `data/backup/app-YYYYMMDD.db` 并清理超过 `storage.backup_keep_days` 的日备份;
- 采集完成与备份完成分开记录;备份失败时 `snapshot` 返回 1,下次执行只重试备份、不重复请求 B 站;
- Cookie 登录态通过 `x/web-interface/nav` 检查,失效只告警,不阻塞匿名 `view`;
- Telegram 摘要推迟到 P3,P1 先写结构化 JSON 日志和 `kv` 状态。
@@ -589,6 +594,20 @@ uv run python tests/test_moves.py
- 真实全量联调:795 条视频全部 `ok=1`,0 失败、0 移除,耗时 1124 秒;粉丝 `follower=2767270`;日备份 `data/backup/app-20261031.db` 含 795 条快照;二次执行正确命中完成标记并跳过;
- 自动化测试见 `tests/test_snapshot.py`、`test_maintenance.py`、`test_timeutil.py`,并扩展了 `test_bilibili_client.py` 与 `test_scheduler.py`。
### P1 补丁:数据完整性与热更新修复 ✅
- 新入库/恢复视频当天补采:`pending_snapshot_aids()` + 同步后立即触发快照;
- 凭据热更新:`ClientProvider` 检测 `mid/cookie/csrf` 变化后重建客户端;
- 协议防御:`ids` / `infos` 缺失 `data` 或 `data=null` 时中止,不再当作空结果;
- 空远端保护:远端 0 条而本地非空时跳过差集,需 `--allow-empty-folder` 才执行清空;
- 粉丝续跑:非强制模式跳过已成功的 `(stat_date, mid)`;
- 强制重采:开始前先写未完成标记,中断后可续跑;
- 备份恢复:采集完成与备份完成分离,备份失败返回 1 并支持无请求重试;
- 跨夹主归属:迁移 v2 增加 `folder_resource.fav_time`,按有效关系重算 `video.folder_id`;
- `dropped` 视频失效时保留原始标题;
- `favsort.py`:`--verify-every` 必须为正数;`sort` 使用真实资源类型,不再硬编码 `2`;
- 配置每 60 秒检查 mtime;调度参数变更需重启。
### P2:本地看板
- 总览、榜单、详情、UP、粉丝、候选和系统状态页面;