diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md index 3498e6c..4769543 100644 --- a/DEVELOPMENT.md +++ b/DEVELOPMENT.md @@ -1,6 +1,6 @@ # 咻咻满 Reaction 视频数据看板开发文档 -> **状态:** P0(数据底座与收藏夹同步)、P1(每日快照与粉丝追踪)已实施并通过只读联调;P2 待开始 +> **状态:** P0(数据底座与收藏夹同步)、P1(每日快照与粉丝追踪)、P2(只读本地看板)、P3(Telegram 与一键加入)已实施 > > **技术基线:** Python 3.14、Python 标准库、SQLite、原生 HTML/CSS/JavaScript、`uv` > @@ -107,8 +107,15 @@ uv run python app.py auth-check uv run python app.py status # P2 起启动本地看板服务 +uv run python app.py serve +uv run python app.py serve --config .\config.json + +# 无子命令启动完整服务:只读 Web + 调度 + Telegram uv run python app.py -uv run python app.py --config .\config.json + +# 生成 7 天预览库并启动预览 +uv run python tools/seed_preview_db.py --days 7 +uv run python app.py serve --preview --config data/preview/config.json ``` 不建议直接激活 `.venv`;优先使用 `uv run ...`,这样命令总是运行在项目锁定的解释器和环境中。 @@ -218,10 +225,10 @@ PRAGMA synchronous = NORMAL; │ │ ├── snapshot.py │ │ └── maintenance.py │ ├── notify/telegram.py # Telegram 消息与按钮 -│ └── web/ # P2 预留 -│ ├── server.py -│ ├── api.py -│ └── static/ +│ └── web/ # P2 只读看板 +│ ├── server.py # HTTP、路由、鉴权、静态资源 +│ ├── queries.py # 看板 SQL 与数据整形 +│ └── static/ # 原生 JS/CSS、ECharts、预览页面 │ ├── tests/ └── data/ # 本地运行期数据,默认不提交 @@ -487,9 +494,10 @@ P3 实现说明: ### 9.1 API 原则 -- `/api/health` 可匿名,仅返回健康状态; -- 其他 `/api/*` 默认要求 `Authorization: Bearer `; -- 写操作额外要求 CSRF 防护与 Origin/Referer 校验; +- P2 看板**只读**:业务接口只注册 GET,写方法统一返回 `405`; +- 数据管理(收藏、忽略、拉黑、移出库、移除黑名单)继续通过 Telegram、CLI 或数据库完成; +- `/api/health` 可匿名;配置 `web.auth_token` 后其他 `/api/*` 要求 Cookie 或 `Authorization: Bearer `; +- 只读接口不需要 CSRF;登录 POST 只建立会话,不修改业务数据; - API 返回 JSON;前端不复制热度、状态机或收藏夹归属判断; - CSV 导出由后端根据当前筛选条件生成。 @@ -497,32 +505,38 @@ P3 实现说明: | 方法 | 路径 | 用途 | |---|---|---| -| `GET` | `/api/overview` | 总览指标、容量、采集状态 | -| `GET` | `/api/videos` | 视频分页、筛选和排序 | +| `GET` | `/api/overview` | 首页动态、总览指标、容量、采集状态 | +| `GET` | `/api/videos` | 视频分页、筛选和排序(支持 added/published/heat/七项/互动/增长) | | `GET` | `/api/videos/{aid}` | 视频详情 | | `GET` | `/api/videos/{aid}/trend` | 七项趋势数据 | -| `GET` | `/api/rankings` | 热度、增长、互动率与单项榜 | +| `GET` | `/api/rankings` | 视频榜或 `scope=up` 的 UP 聚合榜 | | `GET` | `/api/ups` | UP 聚合榜单 | +| `GET` | `/api/ups/{mid}` | UP 详情、聚合趋势和视频列表 | | `GET` | `/api/fans` | 粉丝曲线与增量 | -| `GET` | `/api/candidates` | 候选池 | -| `GET` | `/api/system/status` | 最近任务、下次任务、错误日志 | -| `POST` | `/api/candidates/{aid}/favorite` | 收藏候选 | -| `POST` | `/api/candidates/{aid}/ignore` | 忽略候选 | -| `POST` | `/api/candidates/{aid}/blacklist` | 拉黑候选所属 UP | -| `DELETE` | `/api/blacklist/{mid}` | 移除黑名单 | -| `POST` | `/api/videos/{aid}/drop` | 手动停止追踪 | +| `GET` | `/api/candidates` | 候选池(只读) | +| `GET` | `/api/system` | 最近任务、下次任务、备份、黑名单 | +| `GET` | `/api/export.csv` | 按当前视频筛选导出 CSV | ### 9.2 页面 | 页面 | 内容 | |---|---| -| 总览 | 库内数、UP 数、今日新增、增量、容量条、采集成功率、故障提示。 | +| 首页 | 最新动态优先:今日增量、最新入库、最近发布、增长动态、热度速览、容量与采集状态。 | | 榜单 | 综合热度、七项单项、增长、增速、互动率、UP 聚合、筛选和 CSV。 | -| 视频详情 | 元数据、七项趋势、快照表、失败标记、同 UP 对比。 | -| UP 页 | UP 的全部视频、聚合趋势和平均互动率。 | +| 视频详情 | 元数据、七项指标、单指标趋势、快照表、失败标记、同 UP 对比。 | +| UP 页 | UP 的全部视频、聚合趋势、单视频对比和平均互动率。 | | 粉丝页 | 粉丝总数、日增、7 日净增、累计增长;不叠加视频数据。 | -| 候选池 | 待确认候选、规则命中、剩余保留时间和三个操作。 | -| 系统状态 | 最近扫描、同步、快照、下一次运行时间和错误。 | +| 候选池 | 待确认候选、规则命中、剩余保留时间;操作指向 Telegram/CLI。 | +| 系统状态 | 最近扫描、同步、快照、下次运行、备份、鉴权和黑名单。 | + +### 9.3 预览模式 + +- `tools/seed_preview_db.py` 复制真实库并回填合成快照,真实库只读; +- 合成快照写 `src='preview'`,预览库写 `kv preview:seeded=1`; +- `python app.py serve --preview` 校验标记,缺失时拒绝启动; +- 预览配置不包含真实凭据,默认端口 8081,Telegram 关闭; +- 预览页面显示固定“预览数据 · 只读”横幅; +- 重新生成预览库前必须停止预览服务,避免 Windows 文件占用。 --- @@ -583,7 +597,10 @@ uv run python tests/test_moves.py - 热度、增长和互动率计算; - 收藏夹目标选择与排序锚点; - `fav_action` 的重复点击、失败重试和过期处理; -- Telegram 用户与 chat ID 授权校验。 +- Telegram 用户与 chat ID 授权校验; +- 看板查询的筛选、分页、增长冷启动与状态过滤; +- 只读路由、鉴权、静态资源路径穿越和预览标记校验; +- 预览库生成的确定性、单调性、异常样本与真实库隔离。 只有当标准库测试维护成本明显过高时,才考虑通过 `uv add --dev pytest` 引入 pytest。 @@ -656,11 +673,17 @@ uv run python tests/test_moves.py - 真实 `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`、`test_httpx_transport.py`、`test_favsort_http.py`。 -### P2:本地看板 +### P2:只读本地看板 ✅ -- 总览、榜单、详情、UP、粉丝、候选和系统状态页面; -- 原生前端和 ECharts; -- 本机默认绑定 `127.0.0.1:8080`。 +- 首页、榜单、视频/UP 详情、粉丝、候选和系统状态页面; +- 原生前端和本地 vendored ECharts; +- 本机默认绑定 `127.0.0.1:8080`; +- Web 业务接口只读,写操作继续由 Telegram/CLI/数据库承担; +- 首页默认“最新动态”,增长榜在不足 2 天时显示空态; +- 视频趋势按单指标切换,缺失日断开、失败快照按缺失处理; +- 实现 `tools/seed_preview_db.py`:复制真实库并回填 7 天合成快照,支持 `--profile live|first-day`; +- `serve --preview` 校验 `preview:seeded=1` 标记,预览页面显示只读横幅; +- 自动化测试见 `tests/test_analytics.py`、`test_preview_seed.py`、`test_web_queries.py`、`test_web_server.py`。 ### P4:可选部署 diff --git a/README.md b/README.md index 734a4a5..b92f8d7 100644 --- a/README.md +++ b/README.md @@ -4,9 +4,9 @@ 项目以 B 站年度收藏夹为可信视频来源,补充关键词发现和 Telegram 人工确认,持续采集 reaction 视频的七项数据与咻咻满粉丝数,并提供本地数据看板。现有的收藏夹排序工具仍保留并作为一键加入后的排序能力基础。 -> 当前状态:**P0(数据底座与收藏夹同步)、P1(快照与粉丝追踪)、P3(Telegram 与一键加入)已实施;P2 待开始。** +> 当前状态:**P0(数据底座与收藏夹同步)、P1(快照与粉丝追踪)、P2(只读本地看板)、P3(Telegram 与一键加入)已实施。** > -> 当前已可用:扫码授权、收藏夹读取、排序计划生成、执行与校验;SQLite 建库迁移、收藏夹首次导入与增量同步、失效识别、黑名单种子;每日七项视频快照、粉丝数快照、失败占位、断点续跑与日备份;搜索发现、候选池、Telegram 通知与收藏/忽略/拉黑回调。 +> 当前已可用:扫码授权、收藏夹读取、排序计划生成、执行与校验;SQLite 建库迁移、收藏夹首次导入与增量同步、失效识别、黑名单种子;每日七项视频快照、粉丝数快照、失败占位、断点续跑与日备份;搜索发现、候选池、Telegram 通知与收藏/忽略/拉黑回调;只读本地看板与可重复生成的预览数据。 > > 详细业务口径、接口验证和风险记录见 [project.md](project.md);开发架构与实施计划见 [DEVELOPMENT.md](DEVELOPMENT.md)。 @@ -21,7 +21,7 @@ | 粉丝追踪 | 可用(P1) | 每日记录咻咻满等配置 UP 的粉丝数。 | | 搜索发现与候选池 | 可用(P3) | 每小时搜索前 2 页,分类打分后写入候选池。 | | Telegram 通知与一键加入 | 可用(P3) | 收藏 / 忽略 / 拉黑按钮,`deal` + `sort` 回读校验。 | -| 本地数据看板 | 规划(P2) | 总览、榜单、视频/UP 详情、粉丝曲线、候选池和系统状态。 | +| 本地数据看板 | 可用(P2) | 只读总览、榜单、视频/UP 详情、粉丝曲线、候选池和系统状态。 | ## 核心工作流 @@ -150,6 +150,41 @@ uv run python app.py run > 真实 `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 聚合榜;服务端筛选、排序、分页和 CSV 导出; +- 视频详情提供七项指标、单指标趋势、快照表和同 UP 对比;UP 页提供聚合趋势与单视频对比; +- 粉丝页只绘制粉丝曲线,不叠加视频数据; +- 候选池和系统状态只读展示,操作入口指向 Telegram/CLI; +- 本地回环地址默认免登录;配置 `web.auth_token` 后启用登录页和 HttpOnly Cookie;非回环地址且未配置 token 时拒绝启动; +- 所有业务接口只接受 GET,写方法返回 `405`。 + +### 预览数据 + +`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 会因数据库被占用而拒绝覆盖。 + ## 配置 复制样例配置,并填写 B 站账号信息: @@ -293,6 +328,10 @@ 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_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 # 排序参数校验与混合资源类型 @@ -309,6 +348,8 @@ data/journal-.jsonl 排序执行日志 data/app.db SQLite 数据库(收藏夹、视频、快照、粉丝、黑名单) data/backup/app-YYYYMMDD.db 每日快照后的 SQLite 备份 data/backup/app-pre-v*.db 数据库迁移前的自动备份 +data/preview/app.db 合成预览数据库(不提交) +data/preview/config.json 无凭据的预览配置(不提交) ``` ## 文档索引 diff --git a/project.md b/project.md index 3b81402..ac8d2c7 100644 --- a/project.md +++ b/project.md @@ -1,7 +1,7 @@ # 咻咻满 Reaction 视频数据看板 —— 可行性分析与技术路线 -> 状态:**设计定稿;P0(数据底座与收藏夹同步)、P1(每日快照与粉丝追踪)、P3(Telegram 与一键加入)已实施;P2 待开始** -> 最后更新:2026-10-31(第 7 轮:P3 落地) +> 状态:**设计定稿;P0(数据底座与收藏夹同步)、P1(每日快照与粉丝追踪)、P2(只读本地看板)、P3(Telegram 与一键加入)已实施** +> 最后更新:2026-10-31(第 8 轮:P2 只读看板与预览数据落地) > B 站探测均为只读(GET),尚未调用 `fav/resource/deal`、`fav/resource/sort` --- @@ -666,25 +666,28 @@ fan_delta_cum = follower(d) - follower(首日) | 页面 | 内容 | |---|---| -| 总览 | 库内视频数、活跃 UP 数、今日新增、今日总播放/增量、**收藏夹容量条**(664/1000)、昨日采集成功率 | -| 榜单 | Tab:综合热度/播放/点赞/硬币/收藏/转发/评论/弹幕/增长最快/互动率;筛选 UP、搜标题、导出 CSV | -| 视频详情 | 元数据 + 7 项趋势 + 同 UP 对比 + 快照表(含失败标记)+ 「加入收藏夹」按钮 | -| UP 页 | 该 UP 全部视频、聚合趋势、平均互动率 | +| 首页 | 最新动态优先:今日增量、最新入库、最近发布、增长动态、热度速览、收藏夹容量、采集状态 | +| 榜单 | Tab:综合热度/播放/点赞/投币/收藏/转发/评论/弹幕/互动率/增长/增速;视频与 UP 范围切换;筛选、搜索、导出 CSV | +| 视频详情 | 元数据 + 七项指标 + 单指标趋势(7/30/90/全部)+ 同 UP 对比 + 快照表(含失败标记) | +| UP 页 | 该 UP 全部视频、聚合趋势、单视频对比、平均互动率 | | **粉丝页** | 咻咻满粉丝数曲线 + 每日/7 日净增 + 累计增长(只画粉丝,不叠加视频数据) | -| **候选池** | 未达通知阈值 / 未决策的候选(7 天后自动删除),支持收藏/忽略/拉黑 | -| **系统状态** | 最近扫描、采集成功率、收藏夹同步时间、下次任务时间、错误日志 | +| **候选池** | 候选、得分、通知时间、剩余 TTL;只读展示,操作指向 Telegram/CLI | +| **系统状态** | 最近任务、采集成功率、收藏夹同步时间、下次任务、备份、鉴权、黑名单 | ### 9.2 技术 -- 单 `index.html` + 原生 JS,无构建链; -- 图表 **vendored ECharts**(Apache-2.0,离线); +- 单 `index.html` + 原生 ES Module,无构建链; +- 图表本地 vendored ECharts(Apache-2.0,离线); - `/api/*` JSON,前端只渲染; -- 移动端优先(通知点进来多为手机)。 +- 移动端优先,底部 5 项导航;桌面端左侧导航; +- 首页增长榜在不足 2 天快照时显示空态,不伪造 0。 -### 9.3 鉴权 +### 9.3 只读边界与鉴权 -- 公网部署,默认开启:`Authorization: Bearer ` 或一次性登录换 HttpOnly cookie; -- 写操作(加入/忽略)同样校验,CSRF 用签名 token; +- P2 Web 业务接口只读,写方法统一 `405`;数据管理继续通过 Telegram/CLI/数据库; +- 本地回环地址且未配置 `web.auth_token` 时免登录; +- 配置 token 后启用登录页 + HttpOnly Cookie,或使用 `Authorization: Bearer `; +- 非回环地址且未配置 token 时拒绝启动; - 不做多用户(YAGNI)。 --- @@ -792,6 +795,9 @@ storage:SQLite WAL,单写线程 | 31 | **P3 真实发现** | 4 次 WBI 搜索、168 条结果、161 已入库、6 条超时间窗、1 条候选(score=6) | | 32 | **P3 Telegram 通知** | 真实 Bot 发送成功;发现重复结果后已修复按 aid 去重,离线测试覆盖 | | 33 | **P3 同步联动** | 候选被人工加入收藏夹后,同步识别 1 条新增并当天补采快照;候选行自动删除 | +| 34 | **P2 预览数据** | 复制真实库回填 7 天:796 条视频、4,606 条合成快照、3 条失败、4 条候选、1 条预览黑名单 | +| 35 | **P2 只读页面** | 首页/榜单/视频/UP/粉丝/候选/系统 7 个页面在 390px 与 1280px 下无脚本错误 | +| 36 | **P2 只读边界** | 业务 POST/PUT/PATCH/DELETE 均返回 405,请求前后数据库行数不变 | **未验证(需授权或外部配合)**: @@ -806,11 +812,12 @@ storage:SQLite WAL,单写线程 ## 14. 下一步 -P0、P1、P3 已实施。下一步是 **P2 本地看板**: +P0、P1、P2、P3 已实施。P2 交付了只读本地看板与可重复生成的 7 天预览数据: -1. 总览、榜单、视频/UP 详情、粉丝曲线、候选池和系统状态页面; -2. 原生前端 + ECharts,本机默认绑定 `127.0.0.1:8080`; -3. 复用现有 SQLite 查询与状态机,不在前端复制业务判断; -4. P3 的真实 `deal` / `sort` 待用户点击 Telegram 按钮或授权测试视频后补充验证记录。 +1. 首页、榜单、视频/UP 详情、粉丝曲线、候选池和系统状态页面; +2. 原生 ES Module + 本地 ECharts,本机默认绑定 `127.0.0.1:8080`; +3. 查询、热度、增长和互动率全部在服务端计算,前端只渲染; +4. Web 不提供业务写操作,数据管理继续通过 Telegram/CLI/数据库; +5. P3 的真实 `deal` / `sort` 待用户点击 Telegram 按钮或授权测试视频后补充验证记录。 > P4(容器化 + 反代)继续保持可选。