B站上有很多高质量的课程,但它自带的「学习记录」功能只能看到单集进度,看到一半合集视频时根本不知道整体学了多少。于是我做了一个自己用的工具:Bili Progress。
它能做什么
- 追踪 B站收藏夹里每个视频的整体进度(不是单集,是整个合集的百分比)
- 每天凌晨自动同步一次,也可以手动触发
- 进度达到 100% 自动标记完成
- 手机可以安装成 PWA,像 App 一样使用
怎么用
首先在设置页填入 B站账号的 SESSDATA(登录凭证)。
找 SESSDATA:
- 登录 B站,打开任意页面
- 按 F12 → Application → Cookies →
https://www.bilibili.com - 找到
SESSDATA这一行,复制值
添加要追踪的视频:
点击主页右上角的「+」按钮,会拉取 B站最近的历史观看记录,点击列表里的视频即可加入追踪。
有两点需要注意:历史记录只显示固定数量,所以需要追踪哪个视频,最好先去 B站看一下,确保它出现在列表里;另外历史记录里的视频封面目前无法加载,只能靠标题识别。
填好 SESSDATA 之后点「立即同步」,工具会拉取所有已追踪视频的观看进度并更新圆柱体高度。之后每天凌晨自动同步,也可以随时手动触发。
手机上在浏览器菜单里选「添加到主屏幕」可以装成 PWA,图标直接放桌面,用起来和原生 App 差不多。
技术栈
- 前端:Vue 3 + Vite,部署后是纯静态文件
- 后端:Node.js + Express,调用 B站 API 拉取历史记录
- 数据库:SQLite,轻量够用
- 部署:运行在自己的服务器上,通过 Cloudflare Tunnel 对外暴露
最难的一个问题:多 P 进度计算
B站 API 返回的是每一集(分 P)的观看进度,但我需要的是整个合集的整体进度。
比如一个 70 小时的课程,第一集看了 1 小时,如果直接用第一集的进度(100%)来展示,显然不对。
正确的算法:
整体进度 = (前面所有集的总时长 + 当前集已看时长) / 合集总时长 × 100%
听起来简单,但实现时需要把所有分 P 的时长都拿到,B站 API 不会一次返回这些数据,要额外请求并缓存。
缓存设计
每次同步都要查视频信息(分 P 列表、每集时长),如果每次都请求 B站 API 会很慢,也容易被限流。
所以做了三层缓存:
- 内存缓存:同一次同步里如果多个视频属于同一合集,只请求一次
- SQLite 缓存:7 天有效期,大部分视频信息不会变
- B站 API:只有缓存过期才真正请求
安全方面踩的坑
做完第一版后做了一次完整的安全审查,发现了不少问题,挑几个典型的说:
密码比较时序泄露
原来的代码在比较密码前先判断长度是否相等,这会泄露密码长度信息。正确做法是不管长度,直接用 crypto.timingSafeEqual 做常数时间比较。
错误信息泄露
B站 API 返回的错误码被直接拼进了响应里,攻击者可以通过错误信息推断内部状态。改成统一返回「未知错误」,错误码只写到服务端日志。
默认密钥
JWT_SECRET || 'dev-secret-change-me' 这种写法很危险——如果忘了设置环境变量,系统会用一个公开的默认值。改成启动时检查,没设置直接报错退出。
数据库文件权限
SQLite 文件默认权限是 644(所有用户可读),而里面存着加密后的 B站 Cookie。改成 600,只有运行服务的用户可以读。
SESSDATA 加密存储
B站的登录凭证(SESSDATA)是最敏感的数据,存到数据库前用 AES-256-GCM 加密,密钥从 JWT_SECRET 派生。即使数据库文件被拿走,没有密钥也解不开。
总结
做这个项目最大的收获不是功能本身,而是第一次认真地把安全当成需求来做——不只是让功能跑起来,还要考虑每个数据的存储方式、每个接口的边界情况、每个错误信息会不会暴露内部信息。
工具本身只供自己使用,但安全意识是可以迁移的。
项目页面和截图:Bili Progress →