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

+49 -18
View File
@@ -199,28 +199,29 @@ PRAGMA synchronous = NORMAL;
│ ├── migrations.py # schema_version 与迁移
│ ├── scheduler.py # 内置任务调度
│ ├── logging_json.py # 脱敏 JSON 日志
│ ├── classify.py # 标题归一化、时长解析与打分
│ ├── fav_position.py # 新视频插入位置计算
│ ├── timeutil.py # 上海时区与每日时间
│ ├── bilibili/
│ │ ├── client.py # HTTP、WBI、重试与限速
│ │ ├── client.py # 只读 HTTP、重试与限速
│ │ ├── write_client.py # deal / sort 写客户端
│ │ ├── search.py # WBI 搜索与旧接口降级
│ │ ├── provider.py # 凭据变化重建客户端
│ │ ├── auth.py # Cookie、设备指纹与请求头工具
│ │ ├── auth_flow.py # app.py auth 的扫码与原子写回流程
│ │ └── favorite.py # 加入收藏夹与排序定位
│ │ └── models.py # 接口响应模型
│ ├── services/
│ │ ├── discovery.py
│ │ ├── discovery.py # 搜索发现与候选池
│ │ ├── favorites.py # 收藏 / 忽略 / 拉黑
│ │ ├── telegram_poller.py # getUpdates 与回调分发
│ │ ├── folder_sync.py
│ │ ├── snapshot.py
│ │ ├── fans.py
│ │ ├── candidates.py
│ │ ├── rankings.py
│ │ └── maintenance.py
│ ├── notify/telegram.py
│ └── web/
│ ├── notify/telegram.py # Telegram 消息与按钮
│ └── web/ # P2 预留
│ ├── server.py
│ ├── api.py
│ └── static/
│ ├── index.html
│ ├── app.js
│ ├── styles.css
│ └── vendor/echarts.min.js
│
├── tests/
└── data/ # 本地运行期数据,默认不提交
@@ -379,6 +380,14 @@ score >= 2:发送通知
score < 0:丢弃
```
P3 实现说明:
- WBI 密钥来自 `nav.data.wbi_img`,缓存 6 小时;WBI 失败自动降级旧版 `search/type`;
- 关键词、页数和时间窗由 `discover` 配置控制;
- 同一 aid 在多个关键词/页重复出现时,候选与通知都按 aid 去重;
- 已通知但未决策的候选不会重复通知;未通知的候选会在后续发现轮次补发;
- 人工把候选加入收藏夹后,收藏夹同步会入库并删除同 aid 候选。
### 7.3 收藏夹同步
每小时对所有已配置年度夹执行:
@@ -451,6 +460,16 @@ Telegram `callback_data` 只包含短操作 ID,例如 `fav:<id>`;真实 aid
GET 页面或链接预览只能展示信息,绝不能触发任何写操作。
P3 实现说明:
- `callback_data` 使用 `fav:<aid>` / `ign:<aid>` / `blk:<aid>`,真实状态存 `fav_action`;
- `begin_fav_action` 把 `pending/failed` 原子切换为 `processing`;并发点击返回 `busy`;
- 已在目标夹时直接成功,不重复 `deal`;
- 目标夹优先同 UP 在库最早视频所在夹,其次当前自然年夹,最后最新年度夹;
- 插入位置由 `fav_position.plan_insertion` 计算;组头需要两次 `sort`;
- `deal` 或 `sort` 失败写 `fav_action.state='failed'`,保留候选,用户可再次点击重试;
- Telegram 只接受 `chat_id` 与 `from.id` 都等于配置私聊用户的回调。
---
## 9. Web API 与页面
@@ -608,18 +627,30 @@ uv run python tests/test_moves.py
- `favsort.py`:`--verify-every` 必须为正数;`sort` 使用真实资源类型,不再硬编码 `2`;
- 配置每 60 秒检查 mtime;调度参数变更需重启。
### P3:Telegram 与一键加入 ✅
- long polling、候选通知、收藏/忽略/拉黑;
- `deal`、`sort`、回读验证和失败重试;
- 对真实写入操作使用独立测试视频完成授权验证后再启用。
完成情况(2026-10-31):
- 已实现 `bilibili/search.py`:WBI 签名、密钥缓存 6 小时、旧版搜索降级;
- 已实现 `classify.py`:标题归一化、时长解析与打分;
- 已实现 `services/discovery.py`:关键词/页数/时间窗过滤、黑名单、候选池、通知批次;
- 已实现 `notify/telegram.py` 与 `services/telegram_poller.py`:消息分片、Inline Keyboard、回调授权、offset 推进;
- 已实现 `bilibili/write_client.py`、`fav_position.py`、`services/favorites.py`:目标夹选择、`deal`、`sort`、回读校验、失败保留候选;
- `app.py` 新增 `discover` / `candidates`;`run` 注册发现与候选清理任务,并启动 Telegram poller;
- 真实只读联调:4 次 WBI 搜索、168 条结果、1 条候选(score=6),Telegram 通知发送成功;
- 真实 `deal` / `sort` 尚未在收藏夹执行,等待用户点击 Telegram 按钮或授权测试视频后验证;
- 自动化测试见 `tests/test_classify.py`、`test_search.py`、`test_candidates.py`、`test_discovery.py`、`test_fav_position.py`、`test_favorites.py`、`test_telegram.py`。
### P2:本地看板
- 总览、榜单、详情、UP、粉丝、候选和系统状态页面;
- 原生前端和 ECharts;
- 本机默认绑定 `127.0.0.1:8080`。
### P3:Telegram 与一键加入
- long polling、候选通知、收藏/忽略/拉黑;
- `deal`、`sort`、回读验证和失败重试;
- 对真实写入操作使用独立测试视频完成授权验证后再启用。
### P4:可选部署
- 反向代理、TLS、远程访问鉴权;