Files
re-xxm/README.md
T
kairee 5c2ab7b187 feat(p1): add daily snapshots and fan tracking
Implement P1: seven-metric view snapshots, relation/stat fan snapshots, failure placeholders, resume by daily completion markers, Cookie login warnings, daily SQLite backups, Shanghai daily scheduling, and CLI snapshot/auth-check commands. Real read-only run captured 795/795 videos successfully over 1124s with a verified daily backup.
2026-10-31 19:19:24 +08:00

252 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# bili-fav
**咻咻满 Reaction 视频数据看板与收藏夹管理工具。**
项目以 B 站年度收藏夹为可信视频来源,补充关键词发现和 Telegram 人工确认,持续采集 reaction 视频的七项数据与咻咻满粉丝数,并提供本地数据看板。现有的收藏夹排序工具仍保留并作为一键加入后的排序能力基础。
> 当前状态:**P0(数据底座与收藏夹同步)、P1(快照与粉丝追踪)已实施;P2 待开始。**
>
> 当前已可用:扫码授权、收藏夹读取、排序计划生成、执行与校验;SQLite 建库迁移、收藏夹首次导入与增量同步、失效识别、黑名单种子;每日七项视频快照、粉丝数快照、失败占位、断点续跑与日备份。
>
> 详细业务口径、接口验证和风险记录见 [project.md](project.md);开发架构与实施计划见 [DEVELOPMENT.md](DEVELOPMENT.md)。
## 功能概览
| 功能 | 状态 | 说明 |
|---|---|---|
| 收藏夹排序 | 可用 | 同一 UP 连续,组内按发布时间倒序,组间按该 UP 最早视频发布时间倒序。 |
| 扫码授权与 Cookie 续期 | 可用 | 本地生成二维码;更新身份 Cookie 时保留设备指纹。 |
| 收藏夹同步与首次导入 | 可用(P0) | 监控已配置年度夹,自动发现人工新收藏的视频与失效资源。 |
| 视频日快照 | 可用(P1) | 逐条采集播放、点赞、投币、收藏、转发、评论、弹幕。 |
| 粉丝追踪 | 可用(P1) | 每日记录咻咻满等配置 UP 的粉丝数。 |
| 本地数据看板 | 规划(P2) | 总览、榜单、视频/UP 详情、粉丝曲线、候选池和系统状态。 |
| Telegram 发现与一键加入 | 规划(P3) | 每小时发现候选,支持收藏、忽略、拉黑和收藏夹内定位。 |
## 核心工作流
```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 条时预警,系统绝不自动换夹。
## P1:每日快照与粉丝追踪
P1 已实现每日七项视频指标快照、咻咻满粉丝数快照、失败占位、断点续跑、Cookie 失效告警和 SQLite 日备份。
```powershell
# 采集当日快照与粉丝数(只读联网,约 18~20 分钟 / 795 条)
uv run python app.py snapshot
# 忽略当日完成标记,重新采集
uv run python app.py snapshot --force
# 检查 Cookie 登录态
uv run python app.py auth-check
```
- `snapshot` 对 `active` / `unfaved` 视频逐条请求 `view`,每条请求间隔 1.0~1.6 秒;
- 成功写入 `snapshot` 的七项指标;同日 `ok=1` 的记录直接跳过,可断点续跑;
- 视频不可访问(`-404` / `62002` / `62012`)标记为 `removed`;
- 其他错误重试 3 次,仍失败写入 `ok=0` 和错误信息,不写伪造的零值;
- 粉丝数写入 `up_stat`,失败同样写 `ok=0`;
- 当日全部视频与粉丝采集成功后写入完成标记;服务启动时若当天未完成会自动补跑;
- 每次采集后生成 `data/backup/app-YYYYMMDD.db`,按 `storage.backup_keep_days` 清理旧日备份;
- Cookie 失效只告警,不阻塞匿名 `view` 采集;`auth-check` 可单独检查。
首次真实全量采集结果:795 条视频全部成功、0 失败、0 移除,耗时约 19 分钟;粉丝 `follower=2767270`;日备份为 `data/backup/app-20261031.db`。
## 配置
复制样例配置,并填写 B 站账号信息:
```powershell
Copy-Item config.example.json config.json
```
`config.json` 已被 `.gitignore` 忽略,**不得提交**。其中:
- `mid` / `cookie` / `csrf`:B 站账号 UID、完整 Cookie 与 `bili_jct`(兼容 `favsort.py` 的扁平写法;也支持 `bilibili` 嵌套对象);
- `overrides`:可选,为代发或联合投稿视频指定归属 UP;
- `folders`:年度收藏夹配置(`year` + `media_id` + `title`),系统不自动建夹;
- `up_blacklist_seed`:首次启动写入数据库的 UP 黑名单种子;
- `track_fans`:需要每日追踪粉丝数的 UP mid;
- `storage`:数据库与备份目录;
- `schedule` / `notify` / `classify` / `heat_weights`:任务节奏、通知阈值、分类规则和热度权重。
完整配置口径以 [project.md](project.md) 和 [DEVELOPMENT.md](DEVELOPMENT.md) 为准。
## 当前可用:收藏夹排序 CLI
所有命令建议通过 `uv run` 执行:
```powershell
# 查看全部命令;无需 config.json
uv run bili-fav help
# 扫码登录,更新 config.json 中失效的身份 Cookie
uv run bili-fav auth
uv run bili-fav auth --check
# 列出本人创建的收藏夹
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 bili-fav auth
uv run bili-fav auth --check
```
授权流程在本地生成二维码图片并等待手机客户端扫码确认。成功后:
- 更新 `SESSDATA`、`bili_jct`、`DedeUserID`、`sid` 等身份字段;
- 保留 `buvid3`、`buvid4`、`_uuid`、`buvid_fp` 等设备指纹;
- 将 `csrf` 同步为新的 `bili_jct`;
- 原子写入 `config.json`,并保留 `config.json.bak`;
- 通过 `x/web-interface/nav` 验证新登录态,失败时自动回滚。
常用选项:
```powershell
uv run bili-fav auth --no-browser # 只生成二维码图片并输出路径
uv run bili-fav auth --timeout 180 # 修改扫码等待时间(秒)
```
## B 站访问与安全约束
| 接口 | 当前用途 | 身份 Cookie |
|---|---|---|
| `fav/resource/ids` | 收藏夹资源 ID | 不需要账号身份;可匿名读取。 |
| `fav/resource/infos` | 收藏夹元数据 | 不需要账号身份,但需要设备指纹,完全无 Cookie 时可能返回 HTTP 412。 |
| `fav/folder/created/list-all` | 列出自建收藏夹 | 需要完整登录 Cookie。 |
| `fav/resource/sort` | 收藏夹排序 | 写操作;需要完整 Cookie 和 `csrf`。 |
现有工具对 `ids` / `infos` 默认剥离账号身份 Cookie,仅保留设备指纹;如果只读请求失败,才使用完整 Cookie 重试。所有写操作使用完整 Cookie 与 CSRF。
`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_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_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_scheduler.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 数据库迁移前的自动备份
```
## 文档索引
- [project.md](project.md):完整可行性分析、业务口径、接口验证、数据模型草案和风险清单。
- [DEVELOPMENT.md](DEVELOPMENT.md):开发架构、数据库迁移、API、调度、Telegram 与分阶段实施计划。