Give getUpdates a wider HTTP timeout than the long-poll window, log transient SSL/network disconnects as warnings, apply exponential backoff with recovery logging, and only escalate to error after five consecutive failures.
bili-fav
咻咻满 Reaction 视频数据看板与收藏夹管理工具。
项目以 B 站年度收藏夹为可信视频来源,补充关键词发现和 Telegram 人工确认,持续采集 reaction 视频的七项数据与咻咻满粉丝数,并提供本地数据看板。现有的收藏夹排序工具仍保留并作为一键加入后的排序能力基础。
当前状态:P0(数据底座与收藏夹同步)、P1(快照与粉丝追踪)、P3(Telegram 与一键加入)已实施;P2 待开始。
当前已可用:扫码授权、收藏夹读取、排序计划生成、执行与校验;SQLite 建库迁移、收藏夹首次导入与增量同步、失效识别、黑名单种子;每日七项视频快照、粉丝数快照、失败占位、断点续跑与日备份;搜索发现、候选池、Telegram 通知与收藏/忽略/拉黑回调。
详细业务口径、接口验证和风险记录见 project.md;开发架构与实施计划见 DEVELOPMENT.md。
功能概览
| 功能 | 状态 | 说明 |
|---|---|---|
| 收藏夹排序 | 可用 | 同一 UP 连续,组内按发布时间倒序,组间按该 UP 最早视频发布时间倒序。 |
| 扫码授权与 Cookie 续期 | 可用 | 本地生成二维码;更新身份 Cookie 时保留设备指纹。 |
| 收藏夹同步与首次导入 | 可用(P0) | 监控已配置年度夹,自动发现人工新收藏的视频与失效资源。 |
| 视频日快照 | 可用(P1) | 逐条采集播放、点赞、投币、收藏、转发、评论、弹幕。 |
| 粉丝追踪 | 可用(P1) | 每日记录咻咻满等配置 UP 的粉丝数。 |
| 搜索发现与候选池 | 可用(P3) | 每小时搜索前 2 页,分类打分后写入候选池。 |
| Telegram 通知与一键加入 | 可用(P3) | 收藏 / 忽略 / 拉黑按钮,deal + sort 回读校验。 |
| 本地数据看板 | 规划(P2) | 总览、榜单、视频/UP 详情、粉丝曲线、候选池和系统状态。 |
核心工作流
关键词搜索(补漏) ──► 候选池 / Telegram 人工确认 ──► 收藏夹 + 视频库
│
人工加入年度收藏夹 ──► 收藏夹同步(真相源)───────────┤
▼
每日指标与粉丝快照
▼
本地看板
- 收录范围:只收录他人观看、试听或点评咻咻满内容的 reaction 视频;最终是否收录由人工确认。
- 收藏夹是真相源:手工加入已配置年度夹的视频自动入库;关键词搜索仅负责发现候选。
- 黑名单仅作用于发现:已收藏或已入库的黑名单 UP 视频不会被清理,也会继续追踪。
- 年度夹不自动创建或切换:同一 UP 的新视频优先进入该 UP 最早视频所在的收藏夹;容量接近上限时预警,失败时告警,不擅自改夹。
- 数据不回填:B 站不提供任意日期的历史指标;新视频从首次入库日起开始积累快照。
本地开发环境
项目默认使用 Python 3.14 和 uv。本地开发、测试和现有排序工具的运行均不依赖 Docker、Node.js、数据库服务或宿主机 cron。
# 在项目根目录初始化或同步环境
uv sync --all-groups
# 确认锁定的解释器版本
uv run python --version
# 查看现有 CLI 帮助
uv run bili-fav help
完整的 uv 使用方式、依赖规范、架构与开发约定见 DEVELOPMENT.md。
P0:数据底座与收藏夹同步
P0 已实现 SQLite 迁移、配置热加载、B 站只读客户端、收藏夹首次导入与增量同步、infos 全量元数据刷新、失效识别、容量预警和黑名单种子。所有请求均为只读,不会修改收藏夹。
# 建库、执行迁移、写入配置文件夹与黑名单种子(离线)
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 日备份。
# 采集当日快照与粉丝数(只读联网,约 18~20 分钟 / 795 条)
uv run python app.py snapshot
# 忽略当日完成标记,重新采集
uv run python app.py snapshot --force
# 分别为只读和写入账号扫码授权(默认 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 加入流程。
# 执行一次发现;--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 站账号信息:
Copy-Item config.example.json config.json
config.json 已被 .gitignore 忽略,不得提交。配置必须使用双账号格式:
{
"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 和 DEVELOPMENT.md 为准。
当前可用:收藏夹排序 CLI
所有命令建议通过 uv run 执行:
# 查看全部命令;无需 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 离线重算。
排序规则
- 同一 UP 必须连续:按
upper.mid分组,组内按发布时间倒序;发布时间相同则按avid升序。 - 组间按最早投稿倒序:取该 UP 在当前收藏夹中最早视频的发布时间作为组键,按组键倒序;并列时按组内最小
avid升序。 - 失效或异常资源置底:保持它们原有的相对顺序。
- 可配置归属修正:
config.json的overrides可为指定视频指定实际归属 UP。
组间规则是有意设计:某个 UP 只要存在较老视频,即使近期继续投稿,整个分组也会靠后。
扫码授权
当接口返回 -101 或 Cookie 即将过期时,使用统一认证入口:
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验证新登录态,失败时自动回滚;不会修改另一个账号。
常用选项:
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。
x/v3/fav/resource/sort 的实测语义为:
sort=A:2:B:2 → 将 B 插到 A 之后
运行排序时会重新读取实际顺序、逐步回读校验,并在收藏夹内容于执行期间变动时中止,避免用过期计划强制排序。写操作存在风险,请确认计划后再执行;中断后可直接再次运行 run 继续收敛。
测试
测试全部离线运行,外部接口只在 transport 边界用真实响应形状的 Mock 替换:
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_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_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 离线路径
运行期文件
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:完整可行性分析、业务口径、接口验证、数据模型草案和风险清单。
- DEVELOPMENT.md:开发架构、数据库迁移、API、调度、Telegram 与分阶段实施计划。