feat(p3): add discovery, telegram notifications, and one-click favorites

Implement WBI video search with legacy fallback, classification scoring, candidate pool, permanent seen-aid dedupe, blacklist filtering, and batched Telegram notifications. Add write client for fav deal/sort, target-folder selection, insertion position calculation, read-back verification, fav_action locking, retry on failure, ignore and blacklist actions. Wire discovery, candidate cleanup, Telegram long polling, and new discover/candidates CLI commands into the scheduler. Add migration v3 for candidate duration and index stats.
This commit is contained in:
kairee committed 2026-10-31 21:23:12 +08:00
1 parent 6a21b5d905
commit d971e718e9
31 files changed
+2886 -55

No files matched your search

+41 -3
View File
@@ -4,9 +4,9 @@
项目以 B 站年度收藏夹为可信视频来源,补充关键词发现和 Telegram 人工确认,持续采集 reaction 视频的七项数据与咻咻满粉丝数,并提供本地数据看板。现有的收藏夹排序工具仍保留并作为一键加入后的排序能力基础。
> 当前状态:**P0(数据底座与收藏夹同步)、P1(快照与粉丝追踪)已实施;P2 待开始。**
> 当前状态:**P0(数据底座与收藏夹同步)、P1(快照与粉丝追踪)、P3(Telegram 与一键加入)已实施;P2 待开始。**
>
> 当前已可用:扫码授权、收藏夹读取、排序计划生成、执行与校验;SQLite 建库迁移、收藏夹首次导入与增量同步、失效识别、黑名单种子;每日七项视频快照、粉丝数快照、失败占位、断点续跑与日备份。
> 当前已可用:扫码授权、收藏夹读取、排序计划生成、执行与校验;SQLite 建库迁移、收藏夹首次导入与增量同步、失效识别、黑名单种子;每日七项视频快照、粉丝数快照、失败占位、断点续跑与日备份;搜索发现、候选池、Telegram 通知与收藏/忽略/拉黑回调。
>
> 详细业务口径、接口验证和风险记录见 [project.md](project.md);开发架构与实施计划见 [DEVELOPMENT.md](DEVELOPMENT.md)。
@@ -19,8 +19,9 @@
| 收藏夹同步与首次导入 | 可用(P0) | 监控已配置年度夹,自动发现人工新收藏的视频与失效资源。 |
| 视频日快照 | 可用(P1) | 逐条采集播放、点赞、投币、收藏、转发、评论、弹幕。 |
| 粉丝追踪 | 可用(P1) | 每日记录咻咻满等配置 UP 的粉丝数。 |
| 搜索发现与候选池 | 可用(P3) | 每小时搜索前 2 页,分类打分后写入候选池。 |
| Telegram 通知与一键加入 | 可用(P3) | 收藏 / 忽略 / 拉黑按钮,`deal` + `sort` 回读校验。 |
| 本地数据看板 | 规划(P2) | 总览、榜单、视频/UP 详情、粉丝曲线、候选池和系统状态。 |
| Telegram 发现与一键加入 | 规划(P3) | 每小时发现候选,支持收藏、忽略、拉黑和收藏夹内定位。 |
## 核心工作流
@@ -120,6 +121,35 @@ uv run python app.py auth-check --account all
首次真实全量采集结果:795 条视频全部成功、0 失败、0 移除,耗时约 19 分钟;粉丝 `follower=2767270`;日备份为 `data/backup/app-20261031.db`。
## P3:搜索发现与 Telegram 一键加入
P3 已实现 WBI 搜索发现、候选池、Telegram 通知与按钮回调,以及使用写账号完成的 `deal` / `sort` 加入流程。
```powershell
# 执行一次发现;--no-notify 只写候选池,不发 Telegram
uv run python app.py discover
uv run python app.py discover --no-notify
# 查看候选池(离线)
uv run python app.py candidates
uv run python app.py candidates --decision rejected
# 常驻运行:同步 + 快照 + 发现 + Telegram long polling
uv run python app.py run
```
- 搜索使用 `x/web-interface/wbi/search/type`,WBI 密钥缓存 6 小时,失败时降级旧版 `search/type`;
- 每轮按 `discover.keywords` 搜索前 `discover.pages` 页,过滤已入库/已见/超时间窗/黑名单/标题不含要求词的结果;
- 分数规则与 `classify` 配置一致;`score >= notify.min_score` 才发送 Telegram;
- 通知按钮:**收藏**、**忽略**、**拉黑**;回调只接受 `telegram.chat_id` 对应的私聊用户;
- 收藏使用 `bilibili.write`:先查目标夹是否已存在,再 `deal` 加入、`sort` 插入同 UP 组头、回读校验位置;
- 失败保留候选并写 `fav_action.state='failed'`,可直接重试;不自动换夹;
- 忽略写 `candidate.decision='rejected'`;拉黑写 `up_blacklist` 并拒绝该 UP 的其他待决策候选;
- 候选超过 `schedule.candidate_ttl_days` 且未决策时自动删除,`seen_aid` 防止重复通知;
- 人工把候选加入收藏夹后,收藏夹同步会入库并删除同 aid 候选。
> 真实 `deal` / `sort` 需要用户点击 Telegram 按钮才会触发;离线测试使用契约一致的 Mock 覆盖。
## 配置
复制样例配置,并填写 B 站账号信息:
@@ -146,6 +176,7 @@ Copy-Item config.example.json config.json
- `folders`:年度收藏夹配置(`year` + `media_id` + `title`),系统不自动建夹;
- `up_blacklist_seed`:首次启动写入数据库的 UP 黑名单种子;
- `track_fans`:需要每日追踪粉丝数的 UP mid;
- `discover`:搜索关键词、页数与时间窗(`keywords` / `pages` / `window_days`);
- `storage`:数据库与备份目录;
- `schedule` / `notify` / `classify` / `heat_weights`:任务节奏、通知阈值、分类规则和热度权重。
@@ -247,6 +278,13 @@ uv run python tests/test_migrations.py # 迁移、备份、回滚与保留
uv run python tests/test_database.py # 单写队列、事务与并发
uv run python tests/test_repository.py # 收藏夹/视频状态机与黑名单
uv run python tests/test_bilibili_client.py # ids/infos/view/fans/nav 契约与重试
uv run python tests/test_classify.py # 标题归一化、时长解析与打分
uv run python tests/test_search.py # WBI 签名、搜索解析与降级
uv run python tests/test_candidates.py # 候选池、去重、通知与 fav_action
uv run python tests/test_discovery.py # 发现过滤、候选池与通知批次
uv run python tests/test_fav_position.py # 新视频插入位置
uv run python tests/test_favorites.py # 收藏/忽略/拉黑与失败重试
uv run python tests/test_telegram.py # 消息、分片、长轮询与回调授权
uv run python tests/test_folder_sync.py # 首次导入、差集、失效识别、容量预警
uv run python tests/test_snapshot.py # 七项快照、补采、断点续跑、粉丝、备份重试
uv run python tests/test_maintenance.py # 日备份与保留期