448 lines
24 KiB
Markdown
448 lines
24 KiB
Markdown
# bili-fav
|
||
|
||
**咻咻满 Reaction 视频数据看板与收藏夹管理工具。**
|
||
|
||
项目以 B 站年度收藏夹为可信视频来源,补充关键词发现和 Telegram 人工确认,持续采集 reaction 视频的七项数据与咻咻满粉丝数,并提供本地数据看板。现有的收藏夹排序工具仍保留并作为一键加入后的排序能力基础。
|
||
|
||
> 当前状态:**P0(数据底座与收藏夹同步)、P1(快照与粉丝追踪)、P2(只读本地看板)、P3(Telegram 与一键加入)已实施。**
|
||
>
|
||
> 当前已可用:扫码授权、收藏夹读取、排序计划生成、执行与校验;SQLite 建库迁移、收藏夹首次导入与增量同步、失效识别、黑名单种子;每日七项视频快照、粉丝数快照、失败占位、断点续跑与日备份;搜索发现、候选池、Telegram 通知与收藏/忽略/拉黑回调;只读本地看板与可重复生成的预览数据。
|
||
>
|
||
> 详细业务口径、接口验证和风险记录见 [project.md](project.md);开发架构与实施计划见 [DEVELOPMENT.md](DEVELOPMENT.md)。
|
||
|
||
## 功能概览
|
||
|
||
| 功能 | 状态 | 说明 |
|
||
|---|---|---|
|
||
| 收藏夹排序 | 可用 | 同一 UP 连续,组内按发布时间倒序,组间按该 UP 最早视频发布时间倒序。 |
|
||
| 扫码授权与 Cookie 续期 | 可用 | 本地生成二维码;更新身份 Cookie 时保留设备指纹。 |
|
||
| 收藏夹同步与首次导入 | 可用(P0) | 监控已配置年度夹,自动发现人工新收藏的视频与失效资源。 |
|
||
| 视频日快照 | 可用(P1) | 逐条采集播放、点赞、投币、收藏、转发、评论、弹幕。 |
|
||
| 粉丝追踪 | 可用(P1) | 每日记录咻咻满等配置 UP 的粉丝数。 |
|
||
| 搜索发现与候选池 | 可用(P3) | 每小时搜索前 2 页,分类打分后写入候选池。 |
|
||
| Telegram 通知与一键加入 | 可用(P3) | 收藏 / 忽略 / 拉黑按钮,`deal` + `sort` 回读校验。 |
|
||
| 本地数据看板 | 可用(P2/P9) | 只读总览、视频榜、UP 主榜、内容效率、视频/UP 详情、粉丝曲线、数据说明、候选池和系统状态。 |
|
||
|
||
## 核心工作流
|
||
|
||
```text
|
||
关键词搜索(补漏) ──► 候选池 / Telegram 人工确认 ──► 收藏夹 + 视频库
|
||
│
|
||
人工加入年度收藏夹 ──► 收藏夹同步(真相源)───────────┤
|
||
▼
|
||
每日指标与粉丝快照
|
||
▼
|
||
本地看板
|
||
```
|
||
|
||
- **收录范围**:只收录他人观看、试听或点评咻咻满内容的 reaction 视频;最终是否收录由人工确认。
|
||
- **收藏夹是真相源**:手工加入已配置年度夹的视频自动入库;关键词搜索仅负责发现候选。
|
||
- **黑名单仅作用于发现**:已收藏或已入库的黑名单 UP 视频不会被清理,也会继续追踪。
|
||
- **年度夹不自动创建或切换**:同一 UP 的新视频优先进入该 UP 最早视频所在的收藏夹;容量接近上限时预警,失败时告警,不擅自改夹。
|
||
- **数据不回填**:B 站不提供任意日期的历史指标;新视频从首次入库日起开始积累快照。
|
||
|
||
## 本地开发环境
|
||
|
||
项目默认使用 **Python 3.14** 和 [uv](https://docs.astral.sh/uv/)。本地开发、测试和现有排序工具的运行均不依赖 Docker、Node.js、数据库服务或宿主机 cron。
|
||
|
||
```powershell
|
||
# 在项目根目录初始化或同步环境
|
||
uv sync --all-groups
|
||
|
||
# 确认锁定的解释器版本
|
||
uv run python --version
|
||
|
||
# 查看现有 CLI 帮助
|
||
uv run bili-fav help
|
||
```
|
||
|
||
完整的 `uv` 使用方式、依赖规范、架构与开发约定见 [DEVELOPMENT.md](DEVELOPMENT.md)。
|
||
|
||
## P0:数据底座与收藏夹同步
|
||
|
||
P0 已实现 SQLite 迁移、配置热加载、B 站只读客户端、收藏夹首次导入与增量同步、`infos` 全量元数据刷新、失效识别、容量预警和黑名单种子。所有请求均为只读,不会修改收藏夹。
|
||
|
||
```powershell
|
||
# 建库、执行迁移、写入配置文件夹与黑名单种子(离线)
|
||
uv run python app.py init
|
||
|
||
# 首次导入或增量同步配置中的年度收藏夹(只读联网)
|
||
uv run python app.py sync
|
||
|
||
# 按配置周期常驻运行收藏夹同步 + 每日快照;--once 只跑一次到期任务
|
||
uv run python app.py run
|
||
uv run python app.py run --once
|
||
|
||
# 强制全量刷新元数据(每 6 小时自动执行一次)
|
||
uv run python app.py sync --full
|
||
|
||
# 查看库内状态(离线)
|
||
uv run python app.py status
|
||
```
|
||
|
||
- 数据写入 `data/app.db`(SQLite WAL);升级已有数据库前会自动备份到 `data/backup/`;
|
||
- 内置调度器按 `schedule.folder_sync_minutes` 周期运行,`run` 常驻、`sync` 单次;
|
||
- `infos` 静默缺失或 `attr=9` 的资源标记为 `removed`,保留历史;
|
||
- 从收藏夹移除的资源标记为 `unfaved`,仍保留数据;
|
||
- 黑名单只作为发现阶段的种子写入,**不会过滤收藏夹同步**;
|
||
- 收藏夹达到 950 条时预警,系统绝不自动换夹;
|
||
- 远端返回 0 条但本地仍有记录时默认按异常跳过差集,确认收藏夹确实被清空后才使用 `--allow-empty-folder`。
|
||
|
||
## P1:每日快照与粉丝追踪
|
||
|
||
P1 已实现每日七项视频指标快照、咻咻满粉丝数快照、失败占位、断点续跑、Cookie 失效告警和 SQLite 日备份。
|
||
|
||
```powershell
|
||
# 采集当日快照与粉丝数(只读联网,约 18~20 分钟 / 795 条)
|
||
uv run python app.py snapshot
|
||
|
||
# 忽略当日完成标记,重新采集
|
||
uv run python app.py snapshot --force
|
||
|
||
# 回填历史视频的 UP 粉丝数快照(第 9 轮,只补空值)
|
||
uv run python app.py backfill-followers
|
||
uv run python app.py backfill-followers --dry-run
|
||
|
||
# 分别为只读和写入账号扫码授权(默认 read)
|
||
uv run python app.py auth
|
||
uv run python app.py auth --account write
|
||
|
||
# 检查指定账号或两套账号的登录态
|
||
uv run python app.py auth-check --account read
|
||
uv run python app.py auth-check --account all
|
||
```
|
||
|
||
- `snapshot` 对 `active` / `unfaved` 视频逐条请求 `view`,每条请求间隔 1.0~1.6 秒;
|
||
- 成功写入 `snapshot` 的七项指标;同日 `ok=1` 的记录直接跳过,可断点续跑;
|
||
- 当天已完成后新入库或从 `dropped` 恢复的视频会立即补采当天快照,不必等到次日;
|
||
- 视频不可访问(`-404` / `62002` / `62012`)标记为 `removed`;
|
||
- 其他错误重试 3 次,仍失败写入 `ok=0` 和错误信息,不写伪造的零值;
|
||
- 粉丝数写入 `up_stat`,失败同样写 `ok=0`;续跑时已成功的 `(stat_date, mid)` 会跳过,不会被失败结果覆盖;
|
||
- 当日全部视频与粉丝采集成功后写入完成标记;服务启动时若当天未完成会自动补跑;
|
||
- 每次采集后生成 `data/backup/app-YYYYMMDD.db`,按 `storage.backup_keep_days` 清理旧日备份;
|
||
- 备份失败时 `snapshot` 返回 1 便于任务告警;再次执行只重试备份,不重复请求 B 站;
|
||
- Cookie 失效只告警,不阻塞匿名 `view` 采集;P0/P1 只使用 `bilibili.read`。
|
||
|
||
首次真实全量采集结果: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 覆盖。
|
||
|
||
## P2:只读本地看板
|
||
|
||
P2 提供移动端优先的只读看板,默认绑定 `127.0.0.1:8080`。Web 页面不提供收藏、忽略、拉黑、移出库等写操作;数据管理仍通过 Telegram、CLI 或数据库完成。
|
||
|
||
```powershell
|
||
# 只启动只读 Web(不运行调度、不连 B 站)
|
||
uv run python app.py serve
|
||
|
||
# 无子命令启动完整服务:只读 Web + 调度 + Telegram
|
||
uv run python app.py
|
||
|
||
# 生成 7 天预览库并启动预览
|
||
uv run python tools/seed_preview_db.py --days 7
|
||
uv run python app.py serve --preview --config data/preview/config.json
|
||
```
|
||
|
||
- 首页默认“最新动态”:今日增量、最新入库、最近发布、增长动态、热度速览、收藏夹容量与采集状态;
|
||
- 「视频」与「UP主」是两个独立入口:视频榜支持内容效率(默认)、综合热度、播放/投币/收藏/评论、互动率、播放增量/播放增速;UP 榜展示视频数、总时长、总播放、播放·小时、互动·小时等,可分别排序;
|
||
- 内容效率 = 播放 / 内容小时,只统计时长 ≥ 600 秒且发布满 14 天的视频;UP 内容效率用经验贝叶斯收缩,避免极小样本冲榜;
|
||
- 「数据说明」(`/about`)说明数据来源、发布时间/入库时间/快照日期、指标公式、筛选口径与已知局限,数值由 `/api/about` 动态读取;
|
||
- 视频详情提供分 P 数、七项指标、内容/互动效率、入库时粉丝数、单指标趋势、快照表和同 UP 对比;UP 页提供聚合趋势、单视频对比与入库时/当前粉丝数;
|
||
- 粉丝页只绘制粉丝曲线,不叠加视频数据;支持 7/30/90/全部与自选日期,范围超过一年时按每月峰值日期聚合;最近记录默认 14 天并显示较上一成功日的增量;
|
||
- 前端使用 History API 的干净路径路由(`/videos`、`/ups`、`/video/{aid}`、`/up/{mid}`、`/about`),不使用 `#/` hash;旧 `/rank` 链接仍可用;
|
||
- 候选池和系统状态只读展示,操作入口指向 Telegram/CLI;
|
||
- 首页、视频榜、UP 主榜、视频/UP 详情、粉丝页和数据说明页对访客可见;
|
||
- 配置 `web.auth_token` 后,“候选”和“系统”页面及其接口需要登录,启用登录页和 HttpOnly Cookie;访客的底部导航只显示公开页面;
|
||
- 本地回环地址且未配置 token 时视为无鉴权,全部页面可见;非回环地址且未配置 token 时拒绝启动;
|
||
- 所有业务接口只接受 GET,写方法返回 `405`;
|
||
- 首页/榜单聚合结果缓存 1 小时,粉丝结果缓存 24 小时;快照、收藏夹同步、发现、收藏操作和粉丝 CSV 导入会立即让对应缓存失效。
|
||
|
||
### 预览数据
|
||
|
||
`tools/seed_preview_db.py` 通过 SQLite backup API 复制真实库到 `data/preview/app.db`,再回填 7 天合成快照:
|
||
|
||
- 合成行标记 `src='preview'`,并写入 `kv preview:seeded=1`;
|
||
- 真实库只读,预览库与真实库完全分离;
|
||
- 默认包含少量缺失日、3 条失败快照、4 条预览候选和 1 条预览黑名单;
|
||
- `--profile first-day` 可生成保持“首次导入”状态的冷启动库;
|
||
- 预览配置不包含真实 Cookie,端口 8081,Telegram 关闭;
|
||
- 重新生成前必须先停止预览服务,否则 Windows 会因数据库被占用而拒绝覆盖;
|
||
- 第 9 轮起本地不再保留 `data/app.db` 真实副本,重新生成请加 `--source data/backup/<真实库备份>`;预览库会自动升级到当前 schema(含 `up_profile` / `pages`)。
|
||
|
||
### 粉丝历史回填(CSV)
|
||
|
||
B 站粉丝历史 CSV 形如:
|
||
|
||
```csv
|
||
时间,粉丝,7日变化,1日变化
|
||
2026-10-31 22:42,2767269,139,-33
|
||
2026-10-29 23:53,2767334,496,15
|
||
```
|
||
|
||
导入命令:
|
||
|
||
```powershell
|
||
# 先预览将要写入的内容
|
||
uv run python tools/import_fans_csv.py --csv E:\Downloads\history.csv --dry-run
|
||
|
||
# 实际写入;默认跳过已有成功记录,--force 才覆盖同日期记录
|
||
uv run python tools/import_fans_csv.py --csv E:\Downloads\history.csv
|
||
|
||
# 用完整 CSV 替换该 mid 的全部粉丝历史(推荐首次导入完整历史时使用)
|
||
uv run python tools/import_fans_csv.py --csv E:\Downloads\history.csv --replace
|
||
```
|
||
|
||
- 只写 `up_stat`,不修改视频快照、收藏夹或黑名单;
|
||
- 同一天出现多行时保留时间最晚的一条;
|
||
- 缺失日期不插值,粉丝曲线会断开;
|
||
- 默认跳过已有 `ok=1` 记录;`ok=0` 的历史记录会被修复;
|
||
- `--replace` 会先删除该 mid 的全部 `up_stat`,再按 CSV 重建,适合用完整历史覆盖旧数据;
|
||
- 如果数据库里已有晚于 CSV 末尾的记录,`--replace` 会拒绝执行;确认要删除时才加 `--allow-lossy-replace`;只想补齐 CSV 日期并保留后续采集时用 `--force`;
|
||
- 页面的“日增”只在存在前一天数据时计算,跨多天不会标成日增;
|
||
- 写入前建议先备份 `data/app.db`,例如 `data/backup/app-pre-fans-YYYYMMDD.db`;
|
||
- 容器内运行时用 `--db /data/app.db` 或 `--config /config/config.json`,避免默认去找 `/app/config.json`。
|
||
|
||
## 快速部署(Docker)
|
||
|
||
仓库根目录已包含 `Dockerfile`、`compose.example.yml`、`.dockerignore` 和 `config.docker.example.json`。Compose 文件是示例,需要显式指定:
|
||
|
||
```powershell
|
||
# 1. 准备服务器配置;至少填写 B 站 Cookie / Telegram,并保留 /data 绝对路径
|
||
Copy-Item config.docker.example.json config.json
|
||
|
||
# 2. 构建并后台启动
|
||
docker compose -f compose.example.yml up -d --build
|
||
|
||
# 3. 查看日志与健康状态
|
||
docker compose -f compose.example.yml logs -f
|
||
curl http://127.0.0.1:8080/api/health
|
||
```
|
||
|
||
如果希望省略 `-f`,可以复制为 `compose.yml`(该文件不提交):
|
||
|
||
```powershell
|
||
Copy-Item compose.example.yml compose.yml
|
||
docker compose up -d --build
|
||
```
|
||
|
||
- 容器执行 `python app.py --config /config/config.json`,同时运行只读 Web、调度和 Telegram;
|
||
- `config.json` 挂载到 `/config/config.json`,`data/` 挂载到 `/data/`;
|
||
- 服务器配置需使用 `web.host = 0.0.0.0` 并设置 `web.auth_token`,否则服务拒绝启动;
|
||
- `storage.database_path` 使用 `/data/app.db`,`storage.backup_dir` 使用 `/data/backup`;
|
||
- 首次部署可先在本地执行 `uv run python app.py auth --account read` 扫码,再把生成好的 `config.json` 放到服务器;
|
||
- 也可在容器内扫码:`docker compose -f compose.example.yml run --rm board python app.py auth --account read --no-browser`,二维码会打印在临时文件路径,可用 `docker cp` 取出;
|
||
- 镜像包含 `tools/`,可直接在容器内执行 `python tools/import_fans_csv.py ...` 回填粉丝历史;
|
||
- 数据卷包含数据库、备份与预览库,建议定期备份 `/data`。
|
||
|
||
不使用 Compose 时:
|
||
|
||
```powershell
|
||
docker build -t reaction-board .
|
||
docker run -d --name reaction-board --restart unless-stopped `
|
||
-p 8080:8080 `
|
||
-v ${PWD}/config.json:/config/config.json `
|
||
-v ${PWD}/data:/data `
|
||
reaction-board
|
||
```
|
||
|
||
## 配置
|
||
|
||
复制样例配置,并填写 B 站账号信息:
|
||
|
||
```powershell
|
||
Copy-Item config.example.json config.json
|
||
```
|
||
|
||
`config.json` 已被 `.gitignore` 忽略,**不得提交**。配置必须使用双账号格式:
|
||
|
||
```json
|
||
{
|
||
"bilibili": {
|
||
"read": { "mid": 0, "cookie": "...", "csrf": "..." },
|
||
"write": { "mid": 0, "cookie": "...", "csrf": "..." }
|
||
}
|
||
}
|
||
```
|
||
|
||
- `bilibili.read`:年度收藏夹同步、视频数据快照、粉丝数与其他只读查询使用;
|
||
- `bilibili.write`:后续加入目标收藏夹、回读验证与现有 `favsort.py` 排序使用;
|
||
- 两个账号的 Cookie、CSRF 与设备指纹严格隔离;顶层 `mid` / `cookie` / `csrf` **不再支持**;
|
||
- `overrides`:可选,为代发或联合投稿视频指定归属 UP;
|
||
- `folders`:年度收藏夹配置(`year` + `media_id` + `title`),系统不自动建夹;
|
||
- `up_blacklist_seed`:首次启动写入数据库的 UP 黑名单种子;
|
||
- `track_fans`:需要每日追踪粉丝数的 UP mid;
|
||
- `discover`:搜索关键词、页数与时间窗(`keywords` / `pages` / `window_days`);
|
||
- `storage`:数据库与备份目录;
|
||
- `schedule` / `notify` / `classify` / `heat_weights`:任务节奏、通知阈值、分类规则和热度权重。
|
||
|
||
配置每 60 秒检查一次 mtime,凭据、收藏夹、分类规则等变更无需重启即可在下次任务读取;但 `schedule.folder_sync_minutes` 与 `schedule.snapshot_at` 在启动时固化,修改后需重启 `run` 进程。
|
||
|
||
完整配置口径以 [project.md](project.md) 和 [DEVELOPMENT.md](DEVELOPMENT.md) 为准。
|
||
|
||
## 当前可用:收藏夹排序 CLI
|
||
|
||
所有命令建议通过 `uv run` 执行:
|
||
|
||
```powershell
|
||
# 查看全部命令;无需 config.json
|
||
uv run bili-fav help
|
||
|
||
# 为写账号扫码登录与检查状态(认证入口统一在 app.py)
|
||
uv run python app.py auth --account write
|
||
uv run python app.py auth-check --account write
|
||
|
||
# 列出本人创建的收藏夹
|
||
uv run bili-fav folders
|
||
|
||
# 只读:拉取收藏夹,生成排序计划
|
||
uv run bili-fav plan <media_id> -v
|
||
|
||
# 查看或离线重算已有计划
|
||
uv run bili-fav show <media_id>
|
||
uv run bili-fav replan <media_id>
|
||
|
||
# 写操作:按计划逐步排序;完成后校验
|
||
uv run bili-fav run <media_id>
|
||
uv run bili-fav verify <media_id>
|
||
```
|
||
|
||
`plan` 会生成 `data/plan-<media_id>.json`,其中含原始顺序、目标顺序、移动脚本及视频元数据缓存。`run` 直接使用该计划,不会重复请求 `infos`;如排序算法变更,可用 `replan` 离线重算。
|
||
|
||
### 排序规则
|
||
|
||
1. **同一 UP 必须连续**:按 `upper.mid` 分组,组内按发布时间倒序;发布时间相同则按 `avid` 升序。
|
||
2. **组间按最早投稿倒序**:取该 UP 在当前收藏夹中最早视频的发布时间作为组键,按组键倒序;并列时按组内最小 `avid` 升序。
|
||
3. **失效或异常资源置底**:保持它们原有的相对顺序。
|
||
4. **可配置归属修正**:`config.json` 的 `overrides` 可为指定视频指定实际归属 UP。
|
||
|
||
> 组间规则是有意设计:某个 UP 只要存在较老视频,即使近期继续投稿,整个分组也会靠后。
|
||
|
||
## 扫码授权
|
||
|
||
当接口返回 `-101` 或 Cookie 即将过期时,使用统一认证入口:
|
||
|
||
```powershell
|
||
uv run python app.py auth --account read
|
||
uv run python app.py auth --account write
|
||
uv run python app.py auth-check --account all
|
||
```
|
||
|
||
授权流程在本地生成二维码图片并等待手机客户端扫码确认。成功后:
|
||
|
||
- 更新 `SESSDATA`、`bili_jct`、`DedeUserID`、`sid` 等身份字段;
|
||
- 保留 `buvid3`、`buvid4`、`_uuid`、`buvid_fp` 等设备指纹;
|
||
- 将选中账号的 `csrf` 同步为新的 `bili_jct`,并从 `nav` 回写该账号实际 mid;
|
||
- 原子写入 `config.json`,并保留 `config.json.bak`;
|
||
- 通过 `x/web-interface/nav` 验证新登录态,失败时自动回滚;不会修改另一个账号。
|
||
|
||
常用选项:
|
||
|
||
```powershell
|
||
uv run python app.py auth --account write --no-browser
|
||
uv run python app.py auth --account read --timeout 180
|
||
```
|
||
|
||
## B 站访问与安全约束
|
||
|
||
| 接口 | 当前用途 | 身份 Cookie |
|
||
|---|---|---|
|
||
| `fav/resource/ids` / `infos` | 年度收藏夹同步与排序计划 | `read` 用于 P0;`favsort.py` 计划使用 `write`。 |
|
||
| `view` / `relation/stat` / `nav` | P1 快照与 read 登录态 | `read`。 |
|
||
| `fav/folder/created/list-all` | 列出目标自建收藏夹 | `write`。 |
|
||
| `fav/resource/deal` / `sort` | 加入收藏夹、收藏夹排序 | `write`,需要完整 Cookie 和 CSRF。 |
|
||
|
||
只读客户端对 `ids` / `infos` 默认剥离 `read` 身份 Cookie,仅保留该账号设备指纹;如果失败才使用完整 `read` Cookie 重试。写操作一律使用完整 `write` Cookie 与 CSRF。
|
||
|
||
B 站请求通过 `httpx` 连接池发送,并按 `data/raw-request.txt` 对齐 Chrome 155 的 UA、`sec-ch-ua`、`origin`、`referer` 和 `priority` 等请求头;收藏夹请求的 `referer` 会带上目标 `media_id`。
|
||
|
||
`x/v3/fav/resource/sort` 的实测语义为:
|
||
|
||
```text
|
||
sort=A:2:B:2 → 将 B 插到 A 之后
|
||
```
|
||
|
||
运行排序时会重新读取实际顺序、逐步回读校验,并在收藏夹内容于执行期间变动时中止,避免用过期计划强制排序。写操作存在风险,请确认计划后再执行;中断后可直接再次运行 `run` 继续收敛。
|
||
|
||
## 测试
|
||
|
||
测试全部离线运行,外部接口只在 transport 边界用真实响应形状的 Mock 替换:
|
||
|
||
```powershell
|
||
uv run python tests/test_auth.py # Cookie 合并、设备指纹、Set-Cookie 解析
|
||
uv run python tests/test_moves.py # 排序移动脚本:随机排列与头部用例
|
||
uv run python tests/test_favsort_http.py # favsort httpx 请求头与匿名回退
|
||
uv run python tests/test_config.py # 配置加载、校验、ENV 覆盖与热加载
|
||
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_httpx_transport.py # httpx B 站/Telegram 传输层
|
||
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 # 日备份与保留期
|
||
uv run python tests/test_timeutil.py # 上海时区与每日任务时间
|
||
uv run python tests/test_analytics.py # 热度、互动率、增长与封面
|
||
uv run python tests/test_preview_seed.py # 预览库回填、确定性与安全边界
|
||
uv run python tests/test_fans_csv.py # 粉丝 CSV 解析、替换与幂等回填
|
||
uv run python tests/test_web_queries.py # 看板查询层与冷启动
|
||
uv run python tests/test_web_server.py # 只读路由、鉴权、静态资源与预览模式
|
||
uv run python tests/test_scheduler.py # 内置调度器到期/失败隔离
|
||
uv run python tests/test_provider.py # 凭据变化重建客户端与配置 revision
|
||
uv run python tests/test_favsort_run.py # 排序参数校验与混合资源类型
|
||
uv run python tests/test_logging.py # JSON 日志脱敏
|
||
uv run python tests/test_cli.py # CLI 离线路径
|
||
```
|
||
|
||
## 运行期文件
|
||
|
||
```text
|
||
config.json.bak 最近一次 auth 更新前的配置备份
|
||
data/plan-<media_id>.json 排序计划、顺序快照和元数据缓存
|
||
data/journal-<media_id>.jsonl 排序执行日志
|
||
data/app.db SQLite 数据库(收藏夹、视频、快照、粉丝、黑名单)
|
||
data/backup/app-YYYYMMDD.db 每日快照后的 SQLite 备份
|
||
data/backup/app-pre-v*.db 数据库迁移前的自动备份
|
||
data/backup/app-pre-fans-*.db 粉丝历史回填前的手动备份
|
||
data/preview/app.db 合成预览数据库(不提交)
|
||
data/preview/config.json 无凭据的预览配置(不提交)
|
||
```
|
||
|
||
## 文档索引
|
||
|
||
- [project.md](project.md):完整可行性分析、业务口径、接口验证、数据模型草案和风险清单。
|
||
- [DEVELOPMENT.md](DEVELOPMENT.md):开发架构、数据库迁移、API、调度、Telegram 与分阶段实施计划。
|