feat: package docker deployment and publish flow

This commit is contained in:
theshy
2026-04-22 16:20:03 +08:00
parent 055474360e
commit 2146687dc6
178 changed files with 24318 additions and 20855 deletions

View File

@ -1,64 +1,64 @@
# ADR 0001: Use A Modular Monolith As The Target Architecture
## Status
Accepted
## Context
当前项目由多个 Python 脚本、目录扫描逻辑、flag 文件和外部命令拼接而成。
主要问题:
- 状态不统一
- 配置不统一
- 重复逻辑多
- 扩展新功能需要继续增加脚本
- 运维和业务边界不清晰
重构目标要求:
- 可扩展
- 可配置
- 可观测
- 易部署
- 易文档化
## Decision
新系统采用模块化单体架构,而不是:
- 继续维护脚本集合
- 直接拆成微服务
## Rationale
选择模块化单体的原因:
- 当前系统规模和团队协作模式不需要微服务
- 单机部署和本地运维是核心需求
- 统一数据库、配置和日志对当前问题最直接有效
- 模块化单体足以提供清晰边界和未来插件扩展能力
## Consequences
正面影响:
- 部署简单
- 重构成本可控
- 便于引入统一状态机和管理 API
- 后续可以逐步插件化
负面影响:
- 需要严格维持模块边界,避免重新长成“大脚本”
- 单进程内错误隔离不如微服务天然
## Follow-Up Decisions
后续还需要补充的 ADR
- 是否使用 SQLite 作为主状态存储
- 是否引入事件总线
- 插件机制如何注册
- 管理台采用什么技术栈
# ADR 0001: Use A Modular Monolith As The Target Architecture
## Status
Accepted
## Context
当前项目由多个 Python 脚本、目录扫描逻辑、flag 文件和外部命令拼接而成。
主要问题:
- 状态不统一
- 配置不统一
- 重复逻辑多
- 扩展新功能需要继续增加脚本
- 运维和业务边界不清晰
重构目标要求:
- 可扩展
- 可配置
- 可观测
- 易部署
- 易文档化
## Decision
新系统采用模块化单体架构,而不是:
- 继续维护脚本集合
- 直接拆成微服务
## Rationale
选择模块化单体的原因:
- 当前系统规模和团队协作模式不需要微服务
- 单机部署和本地运维是核心需求
- 统一数据库、配置和日志对当前问题最直接有效
- 模块化单体足以提供清晰边界和未来插件扩展能力
## Consequences
正面影响:
- 部署简单
- 重构成本可控
- 便于引入统一状态机和管理 API
- 后续可以逐步插件化
负面影响:
- 需要严格维持模块边界,避免重新长成“大脚本”
- 单进程内错误隔离不如微服务天然
## Follow-Up Decisions
后续还需要补充的 ADR
- 是否使用 SQLite 作为主状态存储
- 是否引入事件总线
- 插件机制如何注册
- 管理台采用什么技术栈

View File

@ -1,251 +1,251 @@
openapi: 3.1.0
info:
title: biliup-next Control API
version: 0.1.0
summary: 本地 worker、任务和控制台 API
servers:
- url: http://127.0.0.1:8787
paths:
/:
get:
summary: 控制台首页
responses:
"200":
description: HTML dashboard
/health:
get:
summary: 健康检查
responses:
"200":
description: OK
/settings:
get:
summary: 获取当前设置
responses:
"200":
description: 当前配置,敏感字段已掩码
put:
summary: 更新设置
responses:
"200":
description: 保存成功
/settings/schema:
get:
summary: 获取 settings schema
responses:
"200":
description: schema-first UI 元数据
/doctor:
get:
summary: 运行时依赖检查
responses:
"200":
description: doctor result
/modules:
get:
summary: 查询已注册模块与 manifest
responses:
"200":
description: module list
/runtime/services:
get:
summary: 查询 systemd 服务状态
responses:
"200":
description: service list
/runtime/services/{serviceId}/{action}:
post:
summary: 执行 service start/stop/restart
parameters:
- in: path
name: serviceId
required: true
schema:
type: string
- in: path
name: action
required: true
schema:
type: string
enum: [start, stop, restart]
responses:
"202":
description: action accepted
/logs:
get:
summary: 查询日志列表或日志内容
parameters:
- in: query
name: name
schema:
type: string
- in: query
name: lines
schema:
type: integer
- in: query
name: contains
schema:
type: string
responses:
"200":
description: log list or log content
/history:
get:
summary: 查询全局动作流
parameters:
- in: query
name: task_id
schema:
type: string
- in: query
name: action_name
schema:
type: string
- in: query
name: status
schema:
type: string
- in: query
name: limit
schema:
type: integer
responses:
"200":
description: action records
/tasks:
get:
summary: 查询任务列表
parameters:
- in: query
name: limit
schema:
type: integer
responses:
"200":
description: task list
post:
summary: 从 source_path 手动创建任务
responses:
"201":
description: task created
/webhooks/full-video-uploaded:
post:
summary: 接收原视频上传成功后的完整版 BV webhook
responses:
"202":
description: accepted
/tasks/{taskId}:
get:
summary: 查询任务详情
parameters:
- in: path
name: taskId
required: true
schema:
type: string
responses:
"200":
description: task detail
/tasks/{taskId}/steps:
get:
summary: 查询任务步骤
parameters:
- in: path
name: taskId
required: true
schema:
type: string
responses:
"200":
description: task steps
/tasks/{taskId}/artifacts:
get:
summary: 查询任务产物
parameters:
- in: path
name: taskId
required: true
schema:
type: string
responses:
"200":
description: task artifacts
/tasks/{taskId}/history:
get:
summary: 查询单任务动作历史
parameters:
- in: path
name: taskId
required: true
schema:
type: string
responses:
"200":
description: task action history
/tasks/{taskId}/timeline:
get:
summary: 查询单任务时间线
parameters:
- in: path
name: taskId
required: true
schema:
type: string
responses:
"200":
description: task timeline
/tasks/{taskId}/actions/run:
post:
summary: 推进单个任务
parameters:
- in: path
name: taskId
required: true
schema:
type: string
responses:
"202":
description: accepted
/tasks/{taskId}/actions/retry-step:
post:
summary: 从指定 step 重试
parameters:
- in: path
name: taskId
required: true
schema:
type: string
responses:
"202":
description: accepted
/tasks/{taskId}/actions/reset-to-step:
post:
summary: 重置到指定 step 并重跑
parameters:
- in: path
name: taskId
required: true
schema:
type: string
responses:
"202":
description: accepted
/worker/run-once:
post:
summary: 执行一轮 worker
responses:
"202":
description: accepted
/stage/import:
post:
summary: 从本机已有绝对路径复制到隔离 stage
responses:
"201":
description: imported
/stage/upload:
post:
summary: 上传文件到隔离 stage
responses:
"201":
description: uploaded
openapi: 3.1.0
info:
title: biliup-next Control API
version: 0.1.0
summary: 本地 worker、任务和控制台 API
servers:
- url: http://127.0.0.1:8787
paths:
/:
get:
summary: 控制台首页
responses:
"200":
description: HTML dashboard
/health:
get:
summary: 健康检查
responses:
"200":
description: OK
/settings:
get:
summary: 获取当前设置
responses:
"200":
description: 当前配置,敏感字段已掩码
put:
summary: 更新设置
responses:
"200":
description: 保存成功
/settings/schema:
get:
summary: 获取 settings schema
responses:
"200":
description: schema-first UI 元数据
/doctor:
get:
summary: 运行时依赖检查
responses:
"200":
description: doctor result
/modules:
get:
summary: 查询已注册模块与 manifest
responses:
"200":
description: module list
/runtime/services:
get:
summary: 查询 systemd 服务状态
responses:
"200":
description: service list
/runtime/services/{serviceId}/{action}:
post:
summary: 执行 service start/stop/restart
parameters:
- in: path
name: serviceId
required: true
schema:
type: string
- in: path
name: action
required: true
schema:
type: string
enum: [start, stop, restart]
responses:
"202":
description: action accepted
/logs:
get:
summary: 查询日志列表或日志内容
parameters:
- in: query
name: name
schema:
type: string
- in: query
name: lines
schema:
type: integer
- in: query
name: contains
schema:
type: string
responses:
"200":
description: log list or log content
/history:
get:
summary: 查询全局动作流
parameters:
- in: query
name: task_id
schema:
type: string
- in: query
name: action_name
schema:
type: string
- in: query
name: status
schema:
type: string
- in: query
name: limit
schema:
type: integer
responses:
"200":
description: action records
/tasks:
get:
summary: 查询任务列表
parameters:
- in: query
name: limit
schema:
type: integer
responses:
"200":
description: task list
post:
summary: 从 source_path 手动创建任务
responses:
"201":
description: task created
/webhooks/full-video-uploaded:
post:
summary: 接收原视频上传成功后的完整版 BV webhook
responses:
"202":
description: accepted
/tasks/{taskId}:
get:
summary: 查询任务详情
parameters:
- in: path
name: taskId
required: true
schema:
type: string
responses:
"200":
description: task detail
/tasks/{taskId}/steps:
get:
summary: 查询任务步骤
parameters:
- in: path
name: taskId
required: true
schema:
type: string
responses:
"200":
description: task steps
/tasks/{taskId}/artifacts:
get:
summary: 查询任务产物
parameters:
- in: path
name: taskId
required: true
schema:
type: string
responses:
"200":
description: task artifacts
/tasks/{taskId}/history:
get:
summary: 查询单任务动作历史
parameters:
- in: path
name: taskId
required: true
schema:
type: string
responses:
"200":
description: task action history
/tasks/{taskId}/timeline:
get:
summary: 查询单任务时间线
parameters:
- in: path
name: taskId
required: true
schema:
type: string
responses:
"200":
description: task timeline
/tasks/{taskId}/actions/run:
post:
summary: 推进单个任务
parameters:
- in: path
name: taskId
required: true
schema:
type: string
responses:
"202":
description: accepted
/tasks/{taskId}/actions/retry-step:
post:
summary: 从指定 step 重试
parameters:
- in: path
name: taskId
required: true
schema:
type: string
responses:
"202":
description: accepted
/tasks/{taskId}/actions/reset-to-step:
post:
summary: 重置到指定 step 并重跑
parameters:
- in: path
name: taskId
required: true
schema:
type: string
responses:
"202":
description: accepted
/worker/run-once:
post:
summary: 执行一轮 worker
responses:
"202":
description: accepted
/stage/import:
post:
summary: 从本机已有绝对路径复制到隔离 stage
responses:
"201":
description: imported
/stage/upload:
post:
summary: 上传文件到隔离 stage
responses:
"201":
description: uploaded

View File

@ -1,203 +1,203 @@
# Architecture
## Architecture Style
采用模块化单体架构。
原因:
- 当前规模不需要微服务
- 需要统一配置、状态和任务模型
- 需要较低部署复杂度
- 需要明确模块边界和未来插件扩展能力
## High-Level Layers
### 1. Core
核心领域层,不依赖具体外部服务。
- 领域模型
- 状态机
- 任务编排接口
- 事件定义
- 配置模型
### 2. Modules
业务模块层,每个模块只关心自己的一步能力。
- `ingest`
- `transcribe`
- `song_detect`
- `split`
- `publish`
- `comment`
- `collection`
### 3. Infra
基础设施层,对外部依赖做适配。
- 文件系统
- SQLite 存储
- Groq adapter
- Codex adapter
- FFmpeg adapter
- Bili API adapter
- biliup adapter
- 日志与审计
### 4. App
应用层,对外暴露统一运行入口。
- API Server
- Worker
- Scheduler
- CLI
- Admin Web
## Proposed Directory Layout
```text
biliup-next/
src/
app/
api/
worker/
scheduler/
cli/
core/
models/
services/
events/
state_machine/
config/
modules/
ingest/
transcribe/
song_detect/
split/
publish/
comment/
collection/
infra/
db/
fs/
adapters/
groq/
codex/
ffmpeg/
bili/
biliup/
logging/
plugins/
docs/
tests/
```
## Runtime Components
### API Server
负责:
- 配置管理
- 任务查询
- 手动操作
- 日志聚合查询
- 模块与插件可见性展示
### Worker
负责:
- 消费任务
- 推进状态机
- 执行模块步骤
### Scheduler
负责:
- 定时扫描待补偿任务
- 定时同步外部状态
- 触发重试
## Control Plane
新系统应明确区分控制面和数据面。
### Control Plane
负责:
- 配置管理
- 模块/插件注册
- 任务可视化
- 手动操作入口
- 日志与诊断
### Data Plane
负责:
- 实际执行转录
- 实际执行识歌
- 实际执行切歌
- 实际执行上传
- 实际执行评论和合集归档
## Registry
系统内部建立统一 registry用于注册和查找模块能力。
例如:
- 当前转录 provider
- 当前识歌 provider
- 当前上传 provider
- 当前合集策略
核心模块只依赖抽象接口和 registry不直接依赖具体实现。
## Task Lifecycle
```text
created
-> running
-> transcribed
-> running
-> songs_detected
-> running
-> split_done
-> running
-> published
-> running
-> commented
-> running
-> collection_synced
```
失败状态不结束任务,而是转入:
- `failed_retryable`
- `failed_manual`
## Data Ownership
- SQLite任务、步骤、产物索引、配置、审计记录
- 文件系统视频、字幕、切片、AI 输出、日志
- 外部平台B 站稿件、评论、合集
## Key Design Rules
- 所有状态变更必须落库
- 模块间只通过领域对象和事件通信
- 外部依赖不可直接在业务模块中调用 shell 或 HTTP
- 配置统一由 `core.config` 读取
- 管理端展示的数据优先来自数据库,不直接从日志推断
- 工作区 flag 只表达交付副作用和产物标记,不作为 task 主状态事实源
- 配置系统必须 schema-first
- 插件系统必须 manifest-first
# Architecture
## Architecture Style
采用模块化单体架构。
原因:
- 当前规模不需要微服务
- 需要统一配置、状态和任务模型
- 需要较低部署复杂度
- 需要明确模块边界和未来插件扩展能力
## High-Level Layers
### 1. Core
核心领域层,不依赖具体外部服务。
- 领域模型
- 状态机
- 任务编排接口
- 事件定义
- 配置模型
### 2. Modules
业务模块层,每个模块只关心自己的一步能力。
- `ingest`
- `transcribe`
- `song_detect`
- `split`
- `publish`
- `comment`
- `collection`
### 3. Infra
基础设施层,对外部依赖做适配。
- 文件系统
- SQLite 存储
- Groq adapter
- Codex adapter
- FFmpeg adapter
- Bili API adapter
- biliup adapter
- 日志与审计
### 4. App
应用层,对外暴露统一运行入口。
- API Server
- Worker
- Scheduler
- CLI
- Admin Web
## Proposed Directory Layout
```text
biliup-next/
src/
app/
api/
worker/
scheduler/
cli/
core/
models/
services/
events/
state_machine/
config/
modules/
ingest/
transcribe/
song_detect/
split/
publish/
comment/
collection/
infra/
db/
fs/
adapters/
groq/
codex/
ffmpeg/
bili/
biliup/
logging/
plugins/
docs/
tests/
```
## Runtime Components
### API Server
负责:
- 配置管理
- 任务查询
- 手动操作
- 日志聚合查询
- 模块与插件可见性展示
### Worker
负责:
- 消费任务
- 推进状态机
- 执行模块步骤
### Scheduler
负责:
- 定时扫描待补偿任务
- 定时同步外部状态
- 触发重试
## Control Plane
新系统应明确区分控制面和数据面。
### Control Plane
负责:
- 配置管理
- 模块/插件注册
- 任务可视化
- 手动操作入口
- 日志与诊断
### Data Plane
负责:
- 实际执行转录
- 实际执行识歌
- 实际执行切歌
- 实际执行上传
- 实际执行评论和合集归档
## Registry
系统内部建立统一 registry用于注册和查找模块能力。
例如:
- 当前转录 provider
- 当前识歌 provider
- 当前上传 provider
- 当前合集策略
核心模块只依赖抽象接口和 registry不直接依赖具体实现。
## Task Lifecycle
```text
created
-> running
-> transcribed
-> running
-> songs_detected
-> running
-> split_done
-> running
-> published
-> running
-> commented
-> running
-> collection_synced
```
失败状态不结束任务,而是转入:
- `failed_retryable`
- `failed_manual`
## Data Ownership
- SQLite任务、步骤、产物索引、配置、审计记录
- 文件系统视频、字幕、切片、AI 输出、日志
- 外部平台B 站稿件、评论、合集
## Key Design Rules
- 所有状态变更必须落库
- 模块间只通过领域对象和事件通信
- 外部依赖不可直接在业务模块中调用 shell 或 HTTP
- 配置统一由 `core.config` 读取
- 管理端展示的数据优先来自数据库,不直接从日志推断
- 工作区 flag 只表达交付副作用和产物标记,不作为 task 主状态事实源
- 配置系统必须 schema-first
- 插件系统必须 manifest-first

View File

@ -1,82 +1,82 @@
# biliup-next Cold Start Checklist
目标:在一台没有旧环境残留的新机器上,把 `biliup-next` 启动到“可配置、可 doctor、可进入控制面”的状态。
## 1. 基础环境
- 安装 `python3`
- 安装 `ffmpeg``ffprobe`
- 如需完整歌曲识别,安装 `codex`
- 如需完整上传链路,准备 `biliup` 可执行文件
## 2. 获取项目
```bash
git clone <your-repo> biliup
cd biliup/biliup-next
```
## 3. 一键初始化
```bash
bash setup.sh
```
初始化完成后,项目会自动生成:
- `config/settings.json`
- `config/settings.staged.json`
- `runtime/cookies.json`
- `runtime/upload_config.json`
- `data/workspace/*`
注意:
- 这些文件默认都是模板或占位内容
- 此时项目应当已经能执行 `doctor`,但不代表上传链路已经可用
## 4. 填写真实运行资产
- 编辑 `runtime/cookies.json`
- 编辑 `runtime/upload_config.json`
-`biliup` 放到 `runtime/biliup`,或在 `settings.json` 里改成系统路径
- 填写 `transcribe.groq_api_key`
- 按机器实际情况调整 `song_detect.provider`
- 如果用 `codex`,调整 `song_detect.codex_cmd`
- 如果用 `qwen_cli`,调整 `song_detect.qwen_cmd`
- 按需要填写 `collection.season_id_a` / `collection.season_id_b`
## 5. 验收
```bash
./.venv/bin/biliup-next doctor
./.venv/bin/biliup-next init-workspace
./.venv/bin/biliup-next serve --host 127.0.0.1 --port 8787
bash cold-start-smoke.sh
```
浏览器打开:
```text
http://127.0.0.1:8787/
```
验收通过标准:
- `doctor` 输出可读,缺失项只剩你尚未填写的外部依赖
- 控制面可以打开
- `Settings` 页可正常保存
- `stage` 目录可导入或上传文件
- `cold-start-smoke.sh` 能完整通过
## 6. 完整链路前检查
在开始真实处理前,确认以下项目已经真实可用:
- `runtime/cookies.json`
- `runtime/upload_config.json`
- `publish.biliup_path`
- `song_detect.provider`
- `song_detect.codex_cmd``song_detect.qwen_cmd`
- `transcribe.groq_api_key`
- `collection.season_id_a` / `collection.season_id_b`
# biliup-next Cold Start Checklist
目标:在一台没有旧环境残留的新机器上,把 `biliup-next` 启动到“可配置、可 doctor、可进入控制面”的状态。
## 1. 基础环境
- 安装 `python3`
- 安装 `ffmpeg``ffprobe`
- 如需完整歌曲识别,安装 `codex`
- 如需完整上传链路,准备 `biliup` 可执行文件
## 2. 获取项目
```bash
git clone <your-repo> biliup
cd biliup/biliup-next
```
## 3. 一键初始化
```bash
bash setup.sh
```
初始化完成后,项目会自动生成:
- `config/settings.json`
- `config/settings.staged.json`
- `runtime/cookies.json`
- `runtime/upload_config.json`
- `data/workspace/*`
注意:
- 这些文件默认都是模板或占位内容
- 此时项目应当已经能执行 `doctor`,但不代表上传链路已经可用
## 4. 填写真实运行资产
- 编辑 `runtime/cookies.json`
- 编辑 `runtime/upload_config.json`
-`biliup` 放到 `runtime/biliup`,或在 `settings.json` 里改成系统路径
- 填写 `transcribe.groq_api_key`
- 按机器实际情况调整 `song_detect.provider`
- 如果用 `codex`,调整 `song_detect.codex_cmd`
- 如果用 `qwen_cli`,调整 `song_detect.qwen_cmd`
- 按需要填写 `collection.season_id_a` / `collection.season_id_b`
## 5. 验收
```bash
./.venv/bin/biliup-next doctor
./.venv/bin/biliup-next init-workspace
./.venv/bin/biliup-next serve --host 127.0.0.1 --port 8787
bash cold-start-smoke.sh
```
浏览器打开:
```text
http://127.0.0.1:8787/
```
验收通过标准:
- `doctor` 输出可读,缺失项只剩你尚未填写的外部依赖
- 控制面可以打开
- `Settings` 页可正常保存
- `stage` 目录可导入或上传文件
- `cold-start-smoke.sh` 能完整通过
## 6. 完整链路前检查
在开始真实处理前,确认以下项目已经真实可用:
- `runtime/cookies.json`
- `runtime/upload_config.json`
- `publish.biliup_path`
- `song_detect.provider`
- `song_detect.codex_cmd``song_detect.qwen_cmd`
- `transcribe.groq_api_key`
- `collection.season_id_a` / `collection.season_id_b`

View File

@ -155,6 +155,60 @@ User edits config
- `base_delay_seconds`
- `poll_interval_seconds`
## Upload And Comment Templates
`paths.upload_config_file` 指向 `runtime/upload_config.json`。这个文件不只控制 `biliup upload` 的标题、简介、动态和标签,也控制 B 站置顶评论格式。
投稿字段在 `template` 中:
```json
{
"template": {
"title": "【{streamer} (歌曲纯享版)】 {date} 共{song_count}首歌",
"description": "{streamer} {date} 歌曲纯享版。\n\n完整歌单与时间轴见置顶评论。\n直播完整版{current_full_video_link}\n上次直播{previous_full_video_link}",
"tag": "可爱,王海颖,唱歌,音乐",
"dynamic": "{streamer} {date} 歌曲纯享版已发布。\n直播完整版{current_full_video_link}"
}
}
```
评论字段在 `comment_template` 中:
```json
{
"comment_template": {
"split_header": "当前视频:歌曲纯享版:只保留本场直播中的歌曲片段,歌单见下方。\n直播完整版{current_full_video_link} (完整录播,含聊天/互动/完整流程)\n上次纯享{previous_pure_video_link} (上一场歌曲纯享版)",
"full_header": "当前视频:直播完整版:保留本场完整录播内容,歌曲时间轴见下方。\n歌曲纯享版{current_pure_video_link} (只听歌曲看这里)\n上次完整版{previous_full_video_link} (上一场完整录播)",
"split_part_header": "P{part_index}:",
"full_part_header": "P{part_index}:",
"split_song_line": "{song_index}. {title}{artist_suffix}",
"split_text_song_line": "{song_index}. {song_text}",
"full_timeline_line": "{song_index}. {line_text}"
}
}
```
可用变量:
- `streamer`:主播名。
- `date`:从文件名解析出来的日期和时间。
- `song_count`:识别到的歌曲数量。
- `songs_list``songs.txt` 原始歌单内容。
- `daily_quote` / `quote_author`:随机引用文本。
- `current_full_video_bvid` / `current_full_video_link`:本场直播完整版 BV 和链接。
- `current_pure_video_bvid` / `current_pure_video_link`:本场歌曲纯享版 BV 和链接。
- `previous_full_video_bvid` / `previous_full_video_link`:上一场直播完整版 BV 和链接。
- `previous_pure_video_bvid` / `previous_pure_video_link`:上一场歌曲纯享版 BV 和链接。
- `part_index`:评论中的 `P1/P2/P3` 分段序号。
- `song_index`:全局歌曲序号。
- `title` / `artist` / `artist_suffix`:从 `songs.json` 生成纯享歌单时使用。
- `song_text`:从 `songs.txt` 兜底生成纯享歌单时使用,通常不含时间戳。
- `line_text`:完整版时间轴的原始行,通常包含时间戳。
评论头部模板有一条额外规则:如果某一行包含空链接变量,例如 `{previous_full_video_link}` 为空,这一整行会自动跳过,避免发出空链接提示。
Docker 部署时 `./runtime` 是宿主机挂载目录。镜像更新不会覆盖已有 `runtime/upload_config.json`,因此调整文案或评论格式时应修改宿主机上的这个文件,然后重启容器。
### collection
- `enabled`

View File

@ -1,491 +1,491 @@
# Control Plane Guide
本文档面向 `biliup-next` 控制台的日常使用。
默认地址:
```text
http://127.0.0.1:8787/
```
如果当前机器已经开放公网访问,也可以使用服务器 IP + `8787` 端口访问。
## 页面分区
控制台主要分成两列:
- 左侧全局状态、服务、动作流、导入入口、任务列表、Settings
- 右侧:当前任务详情、步骤、产物、历史、时间线、模块、日志
建议的使用顺序是:
1. 先看 `Runtime`
2. 再看 `Tasks`
3. 选中一个任务后,看右侧详情
4. 如果任务异常,再看 `Logs``History`
## Runtime
这里可以看 3 个汇总指标:
- `Health`
- `Doctor`
- `Tasks`
含义:
- `Health = OK`
- API 服务本身还活着
- `Doctor = OK`
- 关键路径、二进制和依赖文件都存在
- `Tasks`
- 当前数据库里的任务数
如果 `Doctor` 不是 `OK`,优先不要继续点任务操作,先修运行环境。
## Services
这里可以查看并控制:
- `biliup-next-worker.service`
- `biliup-next-api.service`
- 如果还保留旧服务,也可能看到 `biliup-python.service`
可执行操作:
- `start`
- `restart`
- `stop`
建议:
- 页面打不开时,先看 `biliup-next-api.service`
- 任务不推进时,先看 `biliup-next-worker.service`
- 不要随便再启动旧 `biliup-python.service`,除非你明确知道自己要同时跑旧链路
## Recent Actions
这里显示最近的控制面动作流,例如:
- `worker_run_once`
- `task_run`
- `retry_step`
- `reset_to_step`
- `stage_import`
- `stage_upload`
- `service_action`
可过滤:
- 仅当前任务
- `status`
- `action_name`
用途:
- 判断最近有没有人工操作过任务
- 判断任务是不是被重试过
- 判断服务是不是被重启过
## Import To Stage
这里有两种入口。
### 1. 复制本机已有文件到隔离 stage
输入服务器上的绝对路径,例如:
```text
/home/theshy/video/test.mp4
```
点击:
```text
复制到隔离 Stage
```
适合:
- 服务器本地已有文件
- 想快速把已有文件丢进新系统测试
### 2. 浏览器直接上传文件
选择本地文件后点击:
```text
上传到隔离 Stage
```
适合:
- 本地电脑上的测试视频
- 不想先手动传到服务器
上传成功后,`worker` 会自动扫描 `stage` 并开始建任务。
## Tasks
这里列出任务列表。
每个任务会显示:
- 标题
- 当前状态
- 任务 ID
常见状态:
- `created`
- `transcribed`
- `songs_detected`
- `split_done`
- `published`
- `commented`
- `collection_synced`
- `failed_retryable`
- `failed_manual`
建议:
- 先选中你关心的任务
- 再看右侧 `Task Detail / Steps / Logs`
## Task Detail
显示当前选中任务的核心信息:
- `Task ID`
- `Status`
- `Title`
- `Source`
- `Created`
- `Updated`
上方有 3 个操作按钮:
- `执行当前任务`
- `重试选中 Step`
- `重置到选中 Step`
### 执行当前任务
作用:
- 手动推进当前任务一次
适合:
- 你刚改完配置
- 你不想等下一轮 worker 轮询
### 重试选中 Step
作用:
- 从当前选中的 step 重新尝试
适合:
- 某一步是临时失败
- 不需要删除后续产物
### 重置到选中 Step
作用:
- 清理该 step 之后的产物和标记
- 把任务回拨到该 step
- 然后重新执行
适合:
- 后续结果已经不可信
- 需要从某一步重新跑整段链路
注意:
- 这是破坏性动作
- 页面会要求确认
## Steps
这里显示任务步骤列表,例如:
- `ingest`
- `transcribe`
- `song_detect`
- `split`
- `publish`
- `comment`
- `collection_a`
- `collection_b`
点击某个 step 之后:
- 这个 step 会成为“当前选中 step”
- 然后你就可以点:
- `重试选中 Step`
- `重置到选中 Step`
排查原则:
- `transcribe` 失败:先看 `Groq API Key``ffmpeg`
- `song_detect` 失败:先看 `song_detect.provider`,再看 `codex_cmd``qwen_cmd`
- `publish` 失败:先看 `cookies.json``biliup`
- `collection_*` 失败:再看任务历史和日志
评论规则补充:
- `comment`
- 纯享版视频下默认发 session 级聚合“编号歌单”
- 内容按 `P1/P2/P3` 分组
- 同一 session 只由 anchor task 发一次
- 完整版主视频下默认才发 session 级“带时间轴评论”
- 内容按 `P1/P2/P3` 分组
- 同一 session 只由 anchor task 发一次
- 如果当前任务找不到 `full_video_bvid.txt`,也没能从最近发布列表解析出完整版 BV主视频评论会跳过
session 规则补充:
- 同主播、文件名时间 `3` 小时内的任务会自动归到同一 session
- session 的 `session_key` 使用最早片段标题
- 同一 session 内:
- 只有 anchor task 真正执行纯享版上传
- 纯享版上传会聚合整组 `split_video`
- 整组 task 共用同一个 `bvid.txt`
- split/full 评论都只发一次
## Artifacts
这里显示任务当前已经产出的文件,例如:
- `source_video`
- `subtitle_srt`
- `songs_json`
- `songs_txt`
- `clip_video`
- `publish_bvid`
用途:
- 判断任务跑到了哪一步
- 判断关键输出是否已经落盘
如果开启了 cleanup 配置,任务在 `collection_synced` 后:
- `source_video` 对应的原始视频可能会被删除
- `clip_video` 对应的 `split_video/` 目录也可能被清理
这是正常收尾行为,不代表任务失败。
## History
这里是单任务动作历史。
`Recent Actions` 的区别:
- `Recent Actions` 看全局
- `History` 只看当前任务
可以看到:
- 动作名
- 状态
- 摘要
- 时间
- 结构化 `details_json`
用途:
- 判断某次 `retry``reset` 的结果
- 判断 worker 最近对这个任务做了什么
## Timeline
这里把任务事件串成一条时间线:
- `Task Created`
- step started / finished
- artifact created
- action records
适合:
- 回放任务完整过程
- 查清楚任务到底卡在什么时候
## Modules
这里显示当前注册的模块 / provider。
用途:
- 确认当前用的是哪套 provider
- 确认模块有没有注册成功
如果将来切 provider这里会很有用。
## Doctor Checks
这里比顶部的 `Doctor = OK/FAIL` 更详细。
会列出:
- workspace 目录
- `cookies_file`
- `upload_config_file`
- `ffprobe`
- `ffmpeg`
- `codex_cmd``qwen_cmd`
- `biliup_path`
如果某个依赖显示 `(external)`,表示它还在用系统或父项目路径,不是 `biliup-next` 自己目录内的副本。
## Logs
这里可以看日志文件。
支持:
- 切换日志文件
- 刷新日志
- 按当前任务标题过滤
使用建议:
- 任务异常时,先选中任务
- 再勾选“按当前任务标题过滤”
- 然后查看相关日志
这样比直接翻整份日志快很多。
## Settings
Settings 分成两层:
- 上半部分schema 驱动表单
- 下半部分:`Advanced JSON Editor`
### 表单区
这里适合日常参数调整,例如:
- `min_duration_seconds`
- `groq_api_key`
- `codex_cmd`
- `qwen_cmd`
- `retry_count`
- `season_id_a`
- `season_id_b`
- `post_split_comment`
- `post_full_video_timeline_comment`
- `delete_source_video_after_collection_synced`
- `delete_split_videos_after_collection_synced`
支持:
- 搜索配置项
- 高频参数优先展示
- 低频参数收纳到 `Advanced Settings`
### Advanced JSON Editor
适合:
- 批量调整
- 一次改多个字段
- 需要直接编辑原始 JSON
页面上有两个同步按钮:
- `表单同步到 JSON`
- `JSON 重绘表单`
### 敏感字段规则
敏感字段会显示为:
```text
__BILIUP_NEXT_SECRET__
```
规则:
- 保留占位符:不改原值
- 改成空字符串:清空原值
- 改成新的字符串:更新为新值
## 推荐操作流
### 新上传一个测试视频
1. 打开控制台
2.`Import To Stage` 上传视频
3.`Tasks` 是否出现新任务
4. 选中该任务
5. 观察 `Steps / Artifacts / Timeline`
6. 如需加速,点击 `执行当前任务`
### 某个任务失败
1. 选中任务
2.`Task Detail` 当前状态
3.`Steps` 哪一步失败
4.`Logs`
5. 若只是临时失败:
- 选中 step
-`重试选中 Step`
6. 若后续产物也需要重建:
- 选中 step
-`重置到选中 Step`
### 修改合集或上传参数
1. 打开 `Settings`
2. 搜索目标参数,例如 `season` / `retry`
3. 修改表单
4. 点击 `保存 Settings`
5. 对目标任务执行:
- `执行当前任务`
-`重置到相关 step`
### 控制评论与清理行为
1. 打开 `Settings`
2. 搜索:
- `post_split_comment`
- `post_full_video_timeline_comment`
- `delete_source_video_after_collection_synced`
- `delete_split_videos_after_collection_synced`
3. 修改后保存
4. 新任务会按新规则执行
建议:
- 如果你希望纯享版评论以 session 级聚合歌单展示,保持 `post_split_comment = true`
- 如果你不希望尝试给完整版主视频发时间轴评论,可以关闭 `post_full_video_timeline_comment`
- 如果磁盘紧张,再开启 cleanup默认建议先关闭等确认流程稳定后再开
### 服务异常
1.`Services`
2. 优先 `restart biliup-next-worker.service`
3. 如果页面自身异常,再 `restart biliup-next-api.service`
4. 重启后看:
- `Health`
- `Doctor`
- `Recent Actions`
## 安全建议
当前控制台已经对公网开放时,建议立刻设置:
- `runtime.control_token`
设置后:
-`/``/health` 外,其余 API 都要求 `X-Biliup-Token`
如果你通过公网访问控制台,不建议长期保持空 token。
# Control Plane Guide
本文档面向 `biliup-next` 控制台的日常使用。
默认地址:
```text
http://127.0.0.1:8787/
```
如果当前机器已经开放公网访问,也可以使用服务器 IP + `8787` 端口访问。
## 页面分区
控制台主要分成两列:
- 左侧全局状态、服务、动作流、导入入口、任务列表、Settings
- 右侧:当前任务详情、步骤、产物、历史、时间线、模块、日志
建议的使用顺序是:
1. 先看 `Runtime`
2. 再看 `Tasks`
3. 选中一个任务后,看右侧详情
4. 如果任务异常,再看 `Logs``History`
## Runtime
这里可以看 3 个汇总指标:
- `Health`
- `Doctor`
- `Tasks`
含义:
- `Health = OK`
- API 服务本身还活着
- `Doctor = OK`
- 关键路径、二进制和依赖文件都存在
- `Tasks`
- 当前数据库里的任务数
如果 `Doctor` 不是 `OK`,优先不要继续点任务操作,先修运行环境。
## Services
这里可以查看并控制:
- `biliup-next-worker.service`
- `biliup-next-api.service`
- 如果还保留旧服务,也可能看到 `biliup-python.service`
可执行操作:
- `start`
- `restart`
- `stop`
建议:
- 页面打不开时,先看 `biliup-next-api.service`
- 任务不推进时,先看 `biliup-next-worker.service`
- 不要随便再启动旧 `biliup-python.service`,除非你明确知道自己要同时跑旧链路
## Recent Actions
这里显示最近的控制面动作流,例如:
- `worker_run_once`
- `task_run`
- `retry_step`
- `reset_to_step`
- `stage_import`
- `stage_upload`
- `service_action`
可过滤:
- 仅当前任务
- `status`
- `action_name`
用途:
- 判断最近有没有人工操作过任务
- 判断任务是不是被重试过
- 判断服务是不是被重启过
## Import To Stage
这里有两种入口。
### 1. 复制本机已有文件到隔离 stage
输入服务器上的绝对路径,例如:
```text
/home/theshy/video/test.mp4
```
点击:
```text
复制到隔离 Stage
```
适合:
- 服务器本地已有文件
- 想快速把已有文件丢进新系统测试
### 2. 浏览器直接上传文件
选择本地文件后点击:
```text
上传到隔离 Stage
```
适合:
- 本地电脑上的测试视频
- 不想先手动传到服务器
上传成功后,`worker` 会自动扫描 `stage` 并开始建任务。
## Tasks
这里列出任务列表。
每个任务会显示:
- 标题
- 当前状态
- 任务 ID
常见状态:
- `created`
- `transcribed`
- `songs_detected`
- `split_done`
- `published`
- `commented`
- `collection_synced`
- `failed_retryable`
- `failed_manual`
建议:
- 先选中你关心的任务
- 再看右侧 `Task Detail / Steps / Logs`
## Task Detail
显示当前选中任务的核心信息:
- `Task ID`
- `Status`
- `Title`
- `Source`
- `Created`
- `Updated`
上方有 3 个操作按钮:
- `执行当前任务`
- `重试选中 Step`
- `重置到选中 Step`
### 执行当前任务
作用:
- 手动推进当前任务一次
适合:
- 你刚改完配置
- 你不想等下一轮 worker 轮询
### 重试选中 Step
作用:
- 从当前选中的 step 重新尝试
适合:
- 某一步是临时失败
- 不需要删除后续产物
### 重置到选中 Step
作用:
- 清理该 step 之后的产物和标记
- 把任务回拨到该 step
- 然后重新执行
适合:
- 后续结果已经不可信
- 需要从某一步重新跑整段链路
注意:
- 这是破坏性动作
- 页面会要求确认
## Steps
这里显示任务步骤列表,例如:
- `ingest`
- `transcribe`
- `song_detect`
- `split`
- `publish`
- `comment`
- `collection_a`
- `collection_b`
点击某个 step 之后:
- 这个 step 会成为“当前选中 step”
- 然后你就可以点:
- `重试选中 Step`
- `重置到选中 Step`
排查原则:
- `transcribe` 失败:先看 `Groq API Key``ffmpeg`
- `song_detect` 失败:先看 `song_detect.provider`,再看 `codex_cmd``qwen_cmd`
- `publish` 失败:先看 `cookies.json``biliup`
- `collection_*` 失败:再看任务历史和日志
评论规则补充:
- `comment`
- 纯享版视频下默认发 session 级聚合“编号歌单”
- 内容按 `P1/P2/P3` 分组
- 同一 session 只由 anchor task 发一次
- 完整版主视频下默认才发 session 级“带时间轴评论”
- 内容按 `P1/P2/P3` 分组
- 同一 session 只由 anchor task 发一次
- 如果当前任务找不到 `full_video_bvid.txt`,也没能从最近发布列表解析出完整版 BV主视频评论会跳过
session 规则补充:
- 同主播、文件名时间 `3` 小时内的任务会自动归到同一 session
- session 的 `session_key` 使用最早片段标题
- 同一 session 内:
- 只有 anchor task 真正执行纯享版上传
- 纯享版上传会聚合整组 `split_video`
- 整组 task 共用同一个 `bvid.txt`
- split/full 评论都只发一次
## Artifacts
这里显示任务当前已经产出的文件,例如:
- `source_video`
- `subtitle_srt`
- `songs_json`
- `songs_txt`
- `clip_video`
- `publish_bvid`
用途:
- 判断任务跑到了哪一步
- 判断关键输出是否已经落盘
如果开启了 cleanup 配置,任务在 `collection_synced` 后:
- `source_video` 对应的原始视频可能会被删除
- `clip_video` 对应的 `split_video/` 目录也可能被清理
这是正常收尾行为,不代表任务失败。
## History
这里是单任务动作历史。
`Recent Actions` 的区别:
- `Recent Actions` 看全局
- `History` 只看当前任务
可以看到:
- 动作名
- 状态
- 摘要
- 时间
- 结构化 `details_json`
用途:
- 判断某次 `retry``reset` 的结果
- 判断 worker 最近对这个任务做了什么
## Timeline
这里把任务事件串成一条时间线:
- `Task Created`
- step started / finished
- artifact created
- action records
适合:
- 回放任务完整过程
- 查清楚任务到底卡在什么时候
## Modules
这里显示当前注册的模块 / provider。
用途:
- 确认当前用的是哪套 provider
- 确认模块有没有注册成功
如果将来切 provider这里会很有用。
## Doctor Checks
这里比顶部的 `Doctor = OK/FAIL` 更详细。
会列出:
- workspace 目录
- `cookies_file`
- `upload_config_file`
- `ffprobe`
- `ffmpeg`
- `codex_cmd``qwen_cmd`
- `biliup_path`
如果某个依赖显示 `(external)`,表示它还在用系统或父项目路径,不是 `biliup-next` 自己目录内的副本。
## Logs
这里可以看日志文件。
支持:
- 切换日志文件
- 刷新日志
- 按当前任务标题过滤
使用建议:
- 任务异常时,先选中任务
- 再勾选“按当前任务标题过滤”
- 然后查看相关日志
这样比直接翻整份日志快很多。
## Settings
Settings 分成两层:
- 上半部分schema 驱动表单
- 下半部分:`Advanced JSON Editor`
### 表单区
这里适合日常参数调整,例如:
- `min_duration_seconds`
- `groq_api_key`
- `codex_cmd`
- `qwen_cmd`
- `retry_count`
- `season_id_a`
- `season_id_b`
- `post_split_comment`
- `post_full_video_timeline_comment`
- `delete_source_video_after_collection_synced`
- `delete_split_videos_after_collection_synced`
支持:
- 搜索配置项
- 高频参数优先展示
- 低频参数收纳到 `Advanced Settings`
### Advanced JSON Editor
适合:
- 批量调整
- 一次改多个字段
- 需要直接编辑原始 JSON
页面上有两个同步按钮:
- `表单同步到 JSON`
- `JSON 重绘表单`
### 敏感字段规则
敏感字段会显示为:
```text
__BILIUP_NEXT_SECRET__
```
规则:
- 保留占位符:不改原值
- 改成空字符串:清空原值
- 改成新的字符串:更新为新值
## 推荐操作流
### 新上传一个测试视频
1. 打开控制台
2.`Import To Stage` 上传视频
3.`Tasks` 是否出现新任务
4. 选中该任务
5. 观察 `Steps / Artifacts / Timeline`
6. 如需加速,点击 `执行当前任务`
### 某个任务失败
1. 选中任务
2.`Task Detail` 当前状态
3.`Steps` 哪一步失败
4.`Logs`
5. 若只是临时失败:
- 选中 step
-`重试选中 Step`
6. 若后续产物也需要重建:
- 选中 step
-`重置到选中 Step`
### 修改合集或上传参数
1. 打开 `Settings`
2. 搜索目标参数,例如 `season` / `retry`
3. 修改表单
4. 点击 `保存 Settings`
5. 对目标任务执行:
- `执行当前任务`
-`重置到相关 step`
### 控制评论与清理行为
1. 打开 `Settings`
2. 搜索:
- `post_split_comment`
- `post_full_video_timeline_comment`
- `delete_source_video_after_collection_synced`
- `delete_split_videos_after_collection_synced`
3. 修改后保存
4. 新任务会按新规则执行
建议:
- 如果你希望纯享版评论以 session 级聚合歌单展示,保持 `post_split_comment = true`
- 如果你不希望尝试给完整版主视频发时间轴评论,可以关闭 `post_full_video_timeline_comment`
- 如果磁盘紧张,再开启 cleanup默认建议先关闭等确认流程稳定后再开
### 服务异常
1.`Services`
2. 优先 `restart biliup-next-worker.service`
3. 如果页面自身异常,再 `restart biliup-next-api.service`
4. 重启后看:
- `Health`
- `Doctor`
- `Recent Actions`
## 安全建议
当前控制台已经对公网开放时,建议立刻设置:
- `runtime.control_token`
设置后:
-`/``/health` 外,其余 API 都要求 `X-Biliup-Token`
如果你通过公网访问控制台,不建议长期保持空 token。

View File

@ -1,243 +1,243 @@
# Design Principles
## Positioning
`biliup-next` 以 OpenClaw 的设计哲学为指引,但不复制它的产品形态。
本项目的核心目标不是做聊天代理系统,而是构建一个面向本地视频流水线的控制面驱动系统。
因此我们借鉴的是方法论:
- 单体优先
- 控制面优先
- 配置与扩展元数据优先
- 严格校验
- 本地优先
- 可读、可审计、可替换
## Principle 1: Modular Monolith First
系统优先采用模块化单体架构,而不是微服务。
原因:
- 当前问题主要来自边界混乱,而不是部署扩展性不足
- 单机部署和 systemd 管理仍然是核心场景
- 统一配置、任务状态和日志比进程拆分更重要
约束:
- 所有模块运行在同一系统边界内
- 模块之间通过抽象接口和统一模型交互
- 不得通过随意脚本调用形成隐式耦合
## Principle 2: Control Plane First
功能模块不是系统中心,控制面才是系统中心。
控制面负责:
- 配置管理
- 任务状态管理
- 模块与插件注册
- 手动操作入口
- 日志与诊断
数据面负责:
- 执行转录
- 执行识歌
- 执行切歌
- 执行上传
- 执行评论和合集归档
任何新增功能,都必须先回答:
- 它如何进入控制面
- 它的状态如何呈现
- 它的配置如何管理
- 它失败后如何恢复
## Principle 3: Schema-First Configuration
配置必须先有 schema再有实现和 UI。
要求:
- 所有配置项先定义在 schema
- 所有配置项有默认值、校验规则和说明
- UI 基于 schema 生成
- CLI 和 API 使用同一套字段定义
禁止:
- 在模块里私自增加隐藏配置常量
- UI 和代码维护不同字段名
- 配置错误仍然带病启动
## Principle 4: Manifest-First Extensibility
扩展能力先注册元数据,再执行运行时代码。
manifest 负责描述:
- 插件是谁
- 提供什么能力
- 需要什么配置
- 入口在哪
- 是否可启用
这样控制面可以在不执行插件代码时完成:
- 能力发现
- 配置渲染
- 可用性检查
- 兼容性检查
## Principle 5: Registry Over Direct Coupling
模块和插件必须通过统一 registry 接入。
例如:
- transcriber registry
- song detector registry
- publisher registry
- collection strategy registry
核心模块只依赖接口,不依赖具体 provider。
这意味着:
- 更换 Groq 为其他转录器不影响任务引擎
- 更换 Codex 为其他识歌器不影响控制面
- 更换 biliup 为其他上传方式不影响领域模型
## Principle 6: Local-First And Human-Readable
系统优先本地运行,本地保存,本地可读。
要求:
- 主状态存储可本地访问
- 日志保存在本地
- 配置保存在本地
- 关键元数据可被开发者直接理解
这不意味着只靠文件系统。
建议做法:
- SQLite 保存结构化状态
- 文件系统保存产物
- JSON / YAML 保存配置
- 文本日志保存审计和错误
## Principle 7: Strict Validation
系统不能接受“差不多能跑”的配置和模块状态。
启动或配置变更前,应验证:
- schema 是否合法
- 可执行依赖是否存在
- 必要凭证是否存在
- provider 是否可初始化
- 插件 manifest 是否正确
失败时:
- 保留旧运行态
- 返回明确错误
- 不进入半失效状态
## Principle 8: Single Source Of Truth
任务状态必须有统一来源。
不得同时依赖:
- flag 文件推断状态
- 日志推断状态
- 目录结构推断状态
正确做法:
- 数据库记录任务状态
- 文件系统存放任务产物
- 日志记录过程和诊断
三者职责分离,不互相替代。
补充:
- 工作区 flag 可以保留,用于表示某些外部动作已经发生,例如评论、合集、上传等副作用完成。
- 但这些 flag 不应被提升为 task 主状态本身。
## Principle 9: Replaceability With Stable Core
可替换的是 provider不可随意漂移的是核心模型。
稳定核心包括:
- Task
- TaskStep
- Artifact
- PublishRecord
- CollectionBinding
- Settings
这些模型一旦定义,应保持长期稳定,避免每新增一个模块就改核心语义。
## Principle 10: Observability Is A First-Class Feature
可观测性不是补丁,而是正式能力。
管理台必须能够回答:
- 当前有哪些任务
- 每个任务在哪一步
- 最近一次失败是什么
- 当前启用的 provider 是谁
- 当前配置是否有效
- 哪个模块健康异常
如果系统不能快速回答这些问题,说明设计不完整。
## Principle 11: Backward-Compatible Migration
重构必须与旧系统并行推进。
要求:
- 原项目继续运行
- 新项目只在 `./biliup-next` 演进
- 先搭文档和骨架
- 再逐步迁移模块
- 最后切换生产入口
禁止:
- 直接在旧系统里边修边重构
- 在未定义状态模型前大规模搬代码
## Principle 12: Documentation Before Expansion
任何新的模块、插件、控制面能力,在动手实现前都要先回答:
- 它属于哪个层
- 它的输入输出是什么
- 它如何配置
- 它如何注册
- 它如何被 UI 展示
- 它如何失败和恢复
如果这些问题没有写清楚,就不应进入实现阶段。
## Summary
`biliup-next` 的核心方向不是“把旧脚本改漂亮”,而是:
- 建立一个本地优先、控制面驱动、模块边界清晰的系统
- 让配置、模块、状态、操作和诊断都回到统一模型之下
- 让未来扩展建立在 schema、manifest、registry 和稳定领域模型之上
# Design Principles
## Positioning
`biliup-next` 以 OpenClaw 的设计哲学为指引,但不复制它的产品形态。
本项目的核心目标不是做聊天代理系统,而是构建一个面向本地视频流水线的控制面驱动系统。
因此我们借鉴的是方法论:
- 单体优先
- 控制面优先
- 配置与扩展元数据优先
- 严格校验
- 本地优先
- 可读、可审计、可替换
## Principle 1: Modular Monolith First
系统优先采用模块化单体架构,而不是微服务。
原因:
- 当前问题主要来自边界混乱,而不是部署扩展性不足
- 单机部署和 systemd 管理仍然是核心场景
- 统一配置、任务状态和日志比进程拆分更重要
约束:
- 所有模块运行在同一系统边界内
- 模块之间通过抽象接口和统一模型交互
- 不得通过随意脚本调用形成隐式耦合
## Principle 2: Control Plane First
功能模块不是系统中心,控制面才是系统中心。
控制面负责:
- 配置管理
- 任务状态管理
- 模块与插件注册
- 手动操作入口
- 日志与诊断
数据面负责:
- 执行转录
- 执行识歌
- 执行切歌
- 执行上传
- 执行评论和合集归档
任何新增功能,都必须先回答:
- 它如何进入控制面
- 它的状态如何呈现
- 它的配置如何管理
- 它失败后如何恢复
## Principle 3: Schema-First Configuration
配置必须先有 schema再有实现和 UI。
要求:
- 所有配置项先定义在 schema
- 所有配置项有默认值、校验规则和说明
- UI 基于 schema 生成
- CLI 和 API 使用同一套字段定义
禁止:
- 在模块里私自增加隐藏配置常量
- UI 和代码维护不同字段名
- 配置错误仍然带病启动
## Principle 4: Manifest-First Extensibility
扩展能力先注册元数据,再执行运行时代码。
manifest 负责描述:
- 插件是谁
- 提供什么能力
- 需要什么配置
- 入口在哪
- 是否可启用
这样控制面可以在不执行插件代码时完成:
- 能力发现
- 配置渲染
- 可用性检查
- 兼容性检查
## Principle 5: Registry Over Direct Coupling
模块和插件必须通过统一 registry 接入。
例如:
- transcriber registry
- song detector registry
- publisher registry
- collection strategy registry
核心模块只依赖接口,不依赖具体 provider。
这意味着:
- 更换 Groq 为其他转录器不影响任务引擎
- 更换 Codex 为其他识歌器不影响控制面
- 更换 biliup 为其他上传方式不影响领域模型
## Principle 6: Local-First And Human-Readable
系统优先本地运行,本地保存,本地可读。
要求:
- 主状态存储可本地访问
- 日志保存在本地
- 配置保存在本地
- 关键元数据可被开发者直接理解
这不意味着只靠文件系统。
建议做法:
- SQLite 保存结构化状态
- 文件系统保存产物
- JSON / YAML 保存配置
- 文本日志保存审计和错误
## Principle 7: Strict Validation
系统不能接受“差不多能跑”的配置和模块状态。
启动或配置变更前,应验证:
- schema 是否合法
- 可执行依赖是否存在
- 必要凭证是否存在
- provider 是否可初始化
- 插件 manifest 是否正确
失败时:
- 保留旧运行态
- 返回明确错误
- 不进入半失效状态
## Principle 8: Single Source Of Truth
任务状态必须有统一来源。
不得同时依赖:
- flag 文件推断状态
- 日志推断状态
- 目录结构推断状态
正确做法:
- 数据库记录任务状态
- 文件系统存放任务产物
- 日志记录过程和诊断
三者职责分离,不互相替代。
补充:
- 工作区 flag 可以保留,用于表示某些外部动作已经发生,例如评论、合集、上传等副作用完成。
- 但这些 flag 不应被提升为 task 主状态本身。
## Principle 9: Replaceability With Stable Core
可替换的是 provider不可随意漂移的是核心模型。
稳定核心包括:
- Task
- TaskStep
- Artifact
- PublishRecord
- CollectionBinding
- Settings
这些模型一旦定义,应保持长期稳定,避免每新增一个模块就改核心语义。
## Principle 10: Observability Is A First-Class Feature
可观测性不是补丁,而是正式能力。
管理台必须能够回答:
- 当前有哪些任务
- 每个任务在哪一步
- 最近一次失败是什么
- 当前启用的 provider 是谁
- 当前配置是否有效
- 哪个模块健康异常
如果系统不能快速回答这些问题,说明设计不完整。
## Principle 11: Backward-Compatible Migration
重构必须与旧系统并行推进。
要求:
- 原项目继续运行
- 新项目只在 `./biliup-next` 演进
- 先搭文档和骨架
- 再逐步迁移模块
- 最后切换生产入口
禁止:
- 直接在旧系统里边修边重构
- 在未定义状态模型前大规模搬代码
## Principle 12: Documentation Before Expansion
任何新的模块、插件、控制面能力,在动手实现前都要先回答:
- 它属于哪个层
- 它的输入输出是什么
- 它如何配置
- 它如何注册
- 它如何被 UI 展示
- 它如何失败和恢复
如果这些问题没有写清楚,就不应进入实现阶段。
## Summary
`biliup-next` 的核心方向不是“把旧脚本改漂亮”,而是:
- 建立一个本地优先、控制面驱动、模块边界清晰的系统
- 让配置、模块、状态、操作和诊断都回到统一模型之下
- 让未来扩展建立在 schema、manifest、registry 和稳定领域模型之上

View File

@ -75,7 +75,7 @@
"platform": "bilibili",
"aid": 123456,
"bvid": "BV1xxxx",
"title": "【王海颖 (歌曲纯享版)】_03月29日 22时02分 共18首歌",
"title": "【王海颖 (歌曲纯享版)】 03月29日 22时02分 共18首歌",
"published_at": "2026-03-30T07:56:13+08:00"
}
```

View File

@ -1,335 +1,335 @@
# Frontend Implementation Checklist
## Goal
把当前 `biliup-next` 已有的后端能力,整理成前端可直接开发的任务清单。
这份清单面向前端开发,不讨论后端架构,只回答 3 个问题:
1. 先做哪些页面最值钱
2. 每个页面要拆哪些组件
3. 每个组件依赖哪些接口和字段
## Priority
建议按这个顺序推进:
1. 任务列表页状态升级
2. 任务详情页
3. 手工绑定完整版 BV
4. Session 合并 / 重绑
5. 设置页常用配置强化
## Milestone 1: 任务列表页状态升级
目标:
- 用户一眼看懂任务是在运行、等待、失败还是完成
- 不需要理解内部状态机字段
### 页面任务
- 把当前任务列表中的内部状态替换成用户态状态
- 在任务列表中增加“当前步骤”列
- 在任务列表中增加“下次重试时间”列
- 在任务列表中增加“分P BV / 完整版 BV”列
- 在任务列表中增加“评论 / 合集 / 清理”状态列
### 组件任务
- `TaskStatusBadge`
- 输入:`task.status`, `task.retry_state`, `steps`
- 输出:`已接收 / 上传中 / 等待B站可见 / 需人工处理 / 已完成`
- `TaskStepBadge`
- 输入:`steps`
- 输出当前步骤文案
- `TaskDeliverySummary`
- 输入:`delivery_state`, `session_context`
- 输出:
- 分P BV
- 完整版 BV
- 评论状态
- 合集状态
- 清理状态
### 接口依赖
- `GET /tasks`
### 建议后端字段
- 现有可直接使用:
- `status`
- `retry_state`
- `delivery_state`
- `session_context`
- 建议前端先本地派生:
- `display_status`
- `current_step`
## Milestone 2: 任务详情页
目标:
- 用户不看日志也能知道这个任务发生了什么
- 用户能在单任务页完成最常见修复动作
### 页面任务
- 新建任务详情页 Hero 区
- 新建步骤时间线
- 新建交付结果卡片
- 新建 Session 信息卡片
- 新建产物列表卡片
- 新建历史动作卡片
- 新建错误说明卡片
### 组件任务
- `TaskHero`
- 标题
- 用户态状态
- 当前步骤
- 下次重试时间
- `TaskTimeline`
- ingest -> collection_b 全步骤
- `TaskDeliveryPanel`
- 分P `BV`
- 完整版 `BV`
- 分P链接
- 完整版链接
- 合集状态
- `TaskSessionPanel`
- `session_key`
- `streamer`
- `room_id`
- `segment_started_at`
- `segment_duration_seconds`
- `context_source`
- `TaskArtifactsPanel`
- source_video
- subtitle_srt
- songs.json
- songs.txt
- clip_video
- `TaskActionsPanel`
- 运行
- 重试
- 重置
- 绑定完整版 BV
### 接口依赖
- `GET /tasks/<id>`
- `GET /tasks/<id>/steps`
- `GET /tasks/<id>/artifacts`
- `GET /tasks/<id>/history`
- `GET /tasks/<id>/timeline`
- `GET /tasks/<id>/context`
### 操作接口依赖
- `POST /tasks/<id>/actions/run`
- `POST /tasks/<id>/actions/retry-step`
- `POST /tasks/<id>/actions/reset-to-step`
## Milestone 3: 手工绑定完整版 BV
目标:
- 用户在前端直接补 `full_video_bvid`
- 不需要再手工写 `full_video_bvid.txt`
### 页面任务
- 在任务详情页增加“绑定完整版 BV”表单
- 显示当前已绑定 BV
- 显示绑定来源:
- fallback
- task_context
- meta_sidecar
- webhook
### 组件任务
- `BindFullVideoForm`
- 输入框:`BV...`
- 提交按钮
- 成功反馈
- 错误反馈
### 接口依赖
- `POST /tasks/<id>/bind-full-video`
### 交互要求
- 提交前本地校验 `BV[0-9A-Za-z]+`
- 成功后刷新:
- `GET /tasks/<id>`
- `GET /tasks/<id>/context`
## Milestone 4: Session 合并 / 重绑
目标:
- 用户能处理“同一场多个断流片段”
- 用户能统一给整个 session 重绑完整版 BV
### 页面任务
- 在任务详情页显示当前任务所属 session
- 增加“查看同 session 任务”入口
- 增加“合并到现有 session”弹窗
- 增加“整个 session 重绑完整版 BV”表单
### 组件任务
- `SessionSummaryCard`
- `session_key`
- task count
- 当前 `full_video_bvid`
- `SessionTaskList`
- 列出该 session 下所有任务
- `MergeSessionDialog`
- 输入目标 `session_key`
- 选择任务
- `RebindSessionForm`
- 输入新的完整版 `BV`
### 接口依赖
- `GET /sessions/<session_key>`
- `POST /sessions/<session_key>/merge`
- `POST /sessions/<session_key>/rebind`
### 交互要求
- 合并成功后刷新:
- 当前任务详情
- session 详情
- 任务列表
- 如果目标 session 已有 `full_video_bvid`
- 前端提示“合并后会继承该完整版 BV”
## Milestone 5: 设置页常用配置强化
目标:
- 用户无需直接改 JSON 就能调优常用行为
### 页面任务
- 在设置页高亮常用 ingest/session 配置
- 在设置页高亮 comment 重试配置
- 在设置页高亮 cleanup 配置
### 应优先暴露的配置
- `ingest.session_gap_minutes`
- `ingest.meta_sidecar_enabled`
- `ingest.meta_sidecar_suffix`
- `comment.max_retries`
- `comment.base_delay_seconds`
- `cleanup.delete_source_video_after_collection_synced`
- `cleanup.delete_split_videos_after_collection_synced`
### 接口依赖
- `GET /settings`
- `GET /settings/schema`
- `PUT /settings`
## Common UX Rules
### 状态文案
- `failed_retryable` 不显示“失败”
- 优先显示:
- `等待自动重试`
- `等待B站可见`
- `正在处理中`
- `需人工处理`
### 错误提示
错误提示统一分成 2 行:
- 原因
- 建议动作
例如:
- 原因视频刚上传B站暂未可见
- 建议:系统会自动重试,无需人工处理
### 操作反馈
所有写操作都要有:
- loading 态
- 成功 toast
- 错误 toast
### 刷新策略
这些动作成功后必须自动刷新详情数据:
- `retry-step`
- `reset-to-step`
- `bind-full-video`
- `session merge`
- `session rebind`
## Suggested Frontend Types
建议前端统一定义这些类型:
```ts
type TaskDisplayStatus =
| "accepted"
| "processing"
| "waiting_retry"
| "waiting_visibility"
| "manual_action"
| "done";
type TaskSessionContext = {
task_id: string;
session_key: string | null;
streamer: string | null;
room_id: string | null;
source_title: string | null;
segment_started_at: string | null;
segment_duration_seconds: number | null;
full_video_bvid: string | null;
split_bvid: string | null;
context_source: string;
video_links: {
split_video_url: string | null;
full_video_url: string | null;
};
};
```
## Suggested Build Order Inside Frontend Repo
建议按这个顺序拆 PR
1. 状态映射工具函数
2. 任务列表页文案升级
3. 任务详情页 Session/Delivery 面板
4. 绑定完整版 BV 表单
5. Session 合并 / 重绑弹窗
6. 设置页常用配置高亮
## Definition Of Done
这一轮前端完成的标准建议是:
- 用户可以在任务列表页看懂所有任务当前状态
- 用户可以在任务详情页看到分P/完整版 BV 和链接
- 用户可以手工绑定完整版 BV
- 用户可以把多个任务合并为同一个 session
- 用户可以给整个 session 重绑完整版 BV
- 用户不需要 ssh 登录机器改 txt 文件
# Frontend Implementation Checklist
## Goal
把当前 `biliup-next` 已有的后端能力,整理成前端可直接开发的任务清单。
这份清单面向前端开发,不讨论后端架构,只回答 3 个问题:
1. 先做哪些页面最值钱
2. 每个页面要拆哪些组件
3. 每个组件依赖哪些接口和字段
## Priority
建议按这个顺序推进:
1. 任务列表页状态升级
2. 任务详情页
3. 手工绑定完整版 BV
4. Session 合并 / 重绑
5. 设置页常用配置强化
## Milestone 1: 任务列表页状态升级
目标:
- 用户一眼看懂任务是在运行、等待、失败还是完成
- 不需要理解内部状态机字段
### 页面任务
- 把当前任务列表中的内部状态替换成用户态状态
- 在任务列表中增加“当前步骤”列
- 在任务列表中增加“下次重试时间”列
- 在任务列表中增加“分P BV / 完整版 BV”列
- 在任务列表中增加“评论 / 合集 / 清理”状态列
### 组件任务
- `TaskStatusBadge`
- 输入:`task.status`, `task.retry_state`, `steps`
- 输出:`已接收 / 上传中 / 等待B站可见 / 需人工处理 / 已完成`
- `TaskStepBadge`
- 输入:`steps`
- 输出当前步骤文案
- `TaskDeliverySummary`
- 输入:`delivery_state`, `session_context`
- 输出:
- 分P BV
- 完整版 BV
- 评论状态
- 合集状态
- 清理状态
### 接口依赖
- `GET /tasks`
### 建议后端字段
- 现有可直接使用:
- `status`
- `retry_state`
- `delivery_state`
- `session_context`
- 建议前端先本地派生:
- `display_status`
- `current_step`
## Milestone 2: 任务详情页
目标:
- 用户不看日志也能知道这个任务发生了什么
- 用户能在单任务页完成最常见修复动作
### 页面任务
- 新建任务详情页 Hero 区
- 新建步骤时间线
- 新建交付结果卡片
- 新建 Session 信息卡片
- 新建产物列表卡片
- 新建历史动作卡片
- 新建错误说明卡片
### 组件任务
- `TaskHero`
- 标题
- 用户态状态
- 当前步骤
- 下次重试时间
- `TaskTimeline`
- ingest -> collection_b 全步骤
- `TaskDeliveryPanel`
- 分P `BV`
- 完整版 `BV`
- 分P链接
- 完整版链接
- 合集状态
- `TaskSessionPanel`
- `session_key`
- `streamer`
- `room_id`
- `segment_started_at`
- `segment_duration_seconds`
- `context_source`
- `TaskArtifactsPanel`
- source_video
- subtitle_srt
- songs.json
- songs.txt
- clip_video
- `TaskActionsPanel`
- 运行
- 重试
- 重置
- 绑定完整版 BV
### 接口依赖
- `GET /tasks/<id>`
- `GET /tasks/<id>/steps`
- `GET /tasks/<id>/artifacts`
- `GET /tasks/<id>/history`
- `GET /tasks/<id>/timeline`
- `GET /tasks/<id>/context`
### 操作接口依赖
- `POST /tasks/<id>/actions/run`
- `POST /tasks/<id>/actions/retry-step`
- `POST /tasks/<id>/actions/reset-to-step`
## Milestone 3: 手工绑定完整版 BV
目标:
- 用户在前端直接补 `full_video_bvid`
- 不需要再手工写 `full_video_bvid.txt`
### 页面任务
- 在任务详情页增加“绑定完整版 BV”表单
- 显示当前已绑定 BV
- 显示绑定来源:
- fallback
- task_context
- meta_sidecar
- webhook
### 组件任务
- `BindFullVideoForm`
- 输入框:`BV...`
- 提交按钮
- 成功反馈
- 错误反馈
### 接口依赖
- `POST /tasks/<id>/bind-full-video`
### 交互要求
- 提交前本地校验 `BV[0-9A-Za-z]+`
- 成功后刷新:
- `GET /tasks/<id>`
- `GET /tasks/<id>/context`
## Milestone 4: Session 合并 / 重绑
目标:
- 用户能处理“同一场多个断流片段”
- 用户能统一给整个 session 重绑完整版 BV
### 页面任务
- 在任务详情页显示当前任务所属 session
- 增加“查看同 session 任务”入口
- 增加“合并到现有 session”弹窗
- 增加“整个 session 重绑完整版 BV”表单
### 组件任务
- `SessionSummaryCard`
- `session_key`
- task count
- 当前 `full_video_bvid`
- `SessionTaskList`
- 列出该 session 下所有任务
- `MergeSessionDialog`
- 输入目标 `session_key`
- 选择任务
- `RebindSessionForm`
- 输入新的完整版 `BV`
### 接口依赖
- `GET /sessions/<session_key>`
- `POST /sessions/<session_key>/merge`
- `POST /sessions/<session_key>/rebind`
### 交互要求
- 合并成功后刷新:
- 当前任务详情
- session 详情
- 任务列表
- 如果目标 session 已有 `full_video_bvid`
- 前端提示“合并后会继承该完整版 BV”
## Milestone 5: 设置页常用配置强化
目标:
- 用户无需直接改 JSON 就能调优常用行为
### 页面任务
- 在设置页高亮常用 ingest/session 配置
- 在设置页高亮 comment 重试配置
- 在设置页高亮 cleanup 配置
### 应优先暴露的配置
- `ingest.session_gap_minutes`
- `ingest.meta_sidecar_enabled`
- `ingest.meta_sidecar_suffix`
- `comment.max_retries`
- `comment.base_delay_seconds`
- `cleanup.delete_source_video_after_collection_synced`
- `cleanup.delete_split_videos_after_collection_synced`
### 接口依赖
- `GET /settings`
- `GET /settings/schema`
- `PUT /settings`
## Common UX Rules
### 状态文案
- `failed_retryable` 不显示“失败”
- 优先显示:
- `等待自动重试`
- `等待B站可见`
- `正在处理中`
- `需人工处理`
### 错误提示
错误提示统一分成 2 行:
- 原因
- 建议动作
例如:
- 原因视频刚上传B站暂未可见
- 建议:系统会自动重试,无需人工处理
### 操作反馈
所有写操作都要有:
- loading 态
- 成功 toast
- 错误 toast
### 刷新策略
这些动作成功后必须自动刷新详情数据:
- `retry-step`
- `reset-to-step`
- `bind-full-video`
- `session merge`
- `session rebind`
## Suggested Frontend Types
建议前端统一定义这些类型:
```ts
type TaskDisplayStatus =
| "accepted"
| "processing"
| "waiting_retry"
| "waiting_visibility"
| "manual_action"
| "done";
type TaskSessionContext = {
task_id: string;
session_key: string | null;
streamer: string | null;
room_id: string | null;
source_title: string | null;
segment_started_at: string | null;
segment_duration_seconds: number | null;
full_video_bvid: string | null;
split_bvid: string | null;
context_source: string;
video_links: {
split_video_url: string | null;
full_video_url: string | null;
};
};
```
## Suggested Build Order Inside Frontend Repo
建议按这个顺序拆 PR
1. 状态映射工具函数
2. 任务列表页文案升级
3. 任务详情页 Session/Delivery 面板
4. 绑定完整版 BV 表单
5. Session 合并 / 重绑弹窗
6. 设置页常用配置高亮
## Definition Of Done
这一轮前端完成的标准建议是:
- 用户可以在任务列表页看懂所有任务当前状态
- 用户可以在任务详情页看到分P/完整版 BV 和链接
- 用户可以手工绑定完整版 BV
- 用户可以把多个任务合并为同一个 session
- 用户可以给整个 session 重绑完整版 BV
- 用户不需要 ssh 登录机器改 txt 文件

View File

@ -1,383 +1,383 @@
# Frontend Product Integration
## Goal
从用户视角,把当前 `biliup-next` 的任务状态机包装成可操作、可理解的控制面。
这份文档面向前端与后端联调,目标不是描述内部实现,而是明确:
- 前端应该有哪些页面
- 每个页面需要哪些字段
- 当前后端已经提供了哪些接口
- 哪些字段/接口还需要补
## User Goals
用户最关心的不是数据库状态,而是这 6 件事:
1. 视频有没有被接收
2. 现在卡在哪一步
3. 这是自动等待还是需要人工处理
4. 上传后的分P BV 和完整版 BV 是什么
5. 评论和合集有没有完成
6. 失败后应该点哪里恢复
因此,前端不应该直接暴露 `created/transcribed/failed_retryable` 这类内部状态,而应该提供一层用户可理解的派生展示。
## Information Architecture
建议前端固定成 4 个一级页面:
1. 总览页
2. 任务列表页
3. 任务详情页
4. 设置页
可选扩展页:
5. 日志页
6. Webhook / Sidecar 调试页
## Page Spec
### 1. 总览页
目标:让用户在 10 秒内知道系统是否正常、当前队列是否卡住。
核心模块:
- 任务摘要卡片
- 运行中
- 等待自动重试
- 需人工处理
- 已完成
- 最近 10 个任务
- 标题
- 用户态状态
- 当前步骤
- 下次重试时间
- 运行时摘要
- API 服务状态
- Worker 服务状态
- stage 目录文件数
- 最近一次调度结果
- 风险提示
- cookies 缺失
- 磁盘空间不足
- Groq/Codex/Biliup 不可用
现有接口可复用:
- `GET /health`
- `GET /doctor`
- `GET /tasks?limit=100`
- `GET /runtime/services`
- `GET /scheduler`
### 2. 任务列表页
目标:批量查看任务,快速定位失败或等待中的任务。
表格建议字段:
- 任务标题
- 用户态状态
- 当前步骤
- 完成进度
- 下次重试时间
- 分P BV
- 完整版 BV
- 评论状态
- 合集状态
- 清理状态
- 最近更新时间
筛选项建议:
- 全部
- 运行中
- 等待自动重试
- 需人工处理
- 已完成
- 仅显示未完成评论
- 仅显示未完成合集
- 仅显示未清理文件
现有接口可复用:
- `GET /tasks`
建议新增的派生字段:
- `display_status`
- `current_step`
- `progress_percent`
- `split_bvid`
- `full_video_bvid`
- `session_key`
- `session_binding_state`
### 3. 任务详情页
目标:让用户不看日志也能处理单个任务。
建议布局:
- Hero 区
- 标题
- 用户态状态
- 当前步骤
- 下次重试时间
- 主要操作按钮
- 步骤时间线
- ingest
- transcribe
- song_detect
- split
- publish
- comment
- collection_a
- collection_b
- 交付结果区
- 分P BV
- 完整版 BV
- 分P 链接
- 完整版链接
- 合集 A / B 链接
- Session 信息区
- session_key
- streamer
- room_id
- segment_started_at
- segment_duration_seconds
- 是否由 sidecar 提供
- 是否由时间连续性自动归并
- 文件与产物区
- source_video
- subtitle_srt
- songs.json
- songs.txt
- clip_video
- 历史动作区
- run
- retry-step
- reset-to-step
- 错误与建议区
- 错误码
- 错误摘要
- 系统建议动作
现有接口可复用:
- `GET /tasks/<id>`
- `GET /tasks/<id>/steps`
- `GET /tasks/<id>/artifacts`
- `GET /tasks/<id>/history`
- `GET /tasks/<id>/timeline`
- `POST /tasks/<id>/actions/run`
- `POST /tasks/<id>/actions/retry-step`
- `POST /tasks/<id>/actions/reset-to-step`
建议新增接口:
- `GET /tasks/<id>/context`
### 4. 设置页
目标:把常用配置变成可理解、可搜索、可修改的产品设置,而不是裸 JSON。
优先展示的用户级配置:
- `ingest.session_gap_minutes`
- `ingest.meta_sidecar_enabled`
- `ingest.meta_sidecar_suffix`
- `comment.max_retries`
- `comment.base_delay_seconds`
- `cleanup.delete_source_video_after_collection_synced`
- `cleanup.delete_split_videos_after_collection_synced`
- `collection.season_id_a`
- `collection.season_id_b`
现有接口可复用:
- `GET /settings`
- `GET /settings/schema`
- `PUT /settings`
## User-Facing Status Mapping
前端必须提供一层用户态状态,不要直接显示内部状态。
建议映射:
- `created` -> `已接收`
- `transcribed` -> `已转录`
- `songs_detected` -> `已识歌`
- `split_done` -> `已切片`
- `published` -> `已上传`
- `commented` -> `评论完成`
- `collection_synced` -> `已完成`
- `failed_retryable` + `step=comment` -> `等待B站可见`
- `failed_retryable` 其他 -> `等待自动重试`
- `failed_manual` -> `需人工处理`
- 任一步 `running` -> `<步骤名>处理中`
建议步骤名展示:
- `ingest` -> `接收视频`
- `transcribe` -> `转录字幕`
- `song_detect` -> `识别歌曲`
- `split` -> `切分分P`
- `publish` -> `上传分P`
- `comment` -> `发布评论`
- `collection_a` -> `加入完整版合集`
- `collection_b` -> `加入分P合集`
## API Integration
### Existing APIs That Frontend Should Reuse
- `GET /tasks`
- `GET /tasks/<id>`
- `GET /tasks/<id>/steps`
- `GET /tasks/<id>/artifacts`
- `GET /tasks/<id>/history`
- `GET /tasks/<id>/timeline`
- `POST /tasks/<id>/actions/run`
- `POST /tasks/<id>/actions/retry-step`
- `POST /tasks/<id>/actions/reset-to-step`
- `GET /settings`
- `GET /settings/schema`
- `PUT /settings`
- `GET /runtime/services`
- `POST /runtime/services/<service>/<action>`
- `POST /worker/run-once`
### Recommended New APIs
#### `GET /tasks/<id>/context`
用途:给任务详情页和 session 归并 UI 提供上下文。
返回建议:
```json
{
"task_id": "xxx",
"session_key": "王海颖:20260402T2203",
"streamer": "王海颖",
"room_id": "581192190066",
"source_title": "王海颖唱歌录播 04月02日 22时03分",
"segment_started_at": "2026-04-02T22:03:00+08:00",
"segment_duration_seconds": 4076.443,
"full_video_bvid": "BV1uH9wBsELC",
"binding_source": "meta_sidecar"
}
```
#### `POST /tasks/<id>/bind-full-video`
用途:用户在前端手工补绑完整版 BV。
请求:
```json
{
"full_video_bvid": "BV1uH9wBsELC"
}
```
#### `POST /sessions/<session_key>/merge`
用途:把多个任务手工归并到同一个 session。
请求:
```json
{
"task_ids": ["why-2205", "why-2306"]
}
```
#### `POST /sessions/<session_key>/rebind`
用途:修改 session 级完整版 BV。
请求:
```json
{
"full_video_bvid": "BV1uH9wBsELC"
}
```
## Derived Fields For UI
后端最好直接给前端这些派生字段,减少前端自行拼状态:
- `display_status`
- `display_step`
- `progress_percent`
- `split_bvid`
- `full_video_bvid`
- `video_links`
- `delivery_state`
- `retry_state`
- `session_context`
- `actions_available`
其中 `actions_available` 建议返回:
```json
{
"run": true,
"retry_step": true,
"reset_to_step": true,
"bind_full_video": true,
"merge_session": true
}
```
## Delivery State Contract
任务列表和详情页都依赖统一的交付状态模型。
建议结构:
```json
{
"split_bvid": "BV1GoDPBtEUg",
"full_video_bvid": "BV1uH9wBsELC",
"split_video_url": "https://www.bilibili.com/video/BV1GoDPBtEUg",
"full_video_url": "https://www.bilibili.com/video/BV1uH9wBsELC",
"comment_split_done": false,
"comment_full_done": false,
"collection_a_done": false,
"collection_b_done": false,
"source_video_present": true,
"split_videos_present": true
}
```
## Suggested Frontend Build Order
按实际价值排序:
1. 任务列表页状态文案升级
2. 任务详情页增加交付结果和重试说明
3. 详情页增加 session/context 区块
4. 设置页增加 session 归并相关配置
5. 增加“手工绑定完整版 BV”操作
6. 增加“合并 session”操作
## MVP Scope
如果只做一轮最小交付,建议先完成:
- 用户态状态映射
- 单任务详情页
- `GET /tasks/<id>/context`
- 手工绑定 `full_video_bvid`
- 前端重试/重置按钮统一化
这样即使 webhook 和自动 session 归并后面再完善,用户也已经能在前端完整处理问题。
# Frontend Product Integration
## Goal
从用户视角,把当前 `biliup-next` 的任务状态机包装成可操作、可理解的控制面。
这份文档面向前端与后端联调,目标不是描述内部实现,而是明确:
- 前端应该有哪些页面
- 每个页面需要哪些字段
- 当前后端已经提供了哪些接口
- 哪些字段/接口还需要补
## User Goals
用户最关心的不是数据库状态,而是这 6 件事:
1. 视频有没有被接收
2. 现在卡在哪一步
3. 这是自动等待还是需要人工处理
4. 上传后的分P BV 和完整版 BV 是什么
5. 评论和合集有没有完成
6. 失败后应该点哪里恢复
因此,前端不应该直接暴露 `created/transcribed/failed_retryable` 这类内部状态,而应该提供一层用户可理解的派生展示。
## Information Architecture
建议前端固定成 4 个一级页面:
1. 总览页
2. 任务列表页
3. 任务详情页
4. 设置页
可选扩展页:
5. 日志页
6. Webhook / Sidecar 调试页
## Page Spec
### 1. 总览页
目标:让用户在 10 秒内知道系统是否正常、当前队列是否卡住。
核心模块:
- 任务摘要卡片
- 运行中
- 等待自动重试
- 需人工处理
- 已完成
- 最近 10 个任务
- 标题
- 用户态状态
- 当前步骤
- 下次重试时间
- 运行时摘要
- API 服务状态
- Worker 服务状态
- stage 目录文件数
- 最近一次调度结果
- 风险提示
- cookies 缺失
- 磁盘空间不足
- Groq/Codex/Biliup 不可用
现有接口可复用:
- `GET /health`
- `GET /doctor`
- `GET /tasks?limit=100`
- `GET /runtime/services`
- `GET /scheduler`
### 2. 任务列表页
目标:批量查看任务,快速定位失败或等待中的任务。
表格建议字段:
- 任务标题
- 用户态状态
- 当前步骤
- 完成进度
- 下次重试时间
- 分P BV
- 完整版 BV
- 评论状态
- 合集状态
- 清理状态
- 最近更新时间
筛选项建议:
- 全部
- 运行中
- 等待自动重试
- 需人工处理
- 已完成
- 仅显示未完成评论
- 仅显示未完成合集
- 仅显示未清理文件
现有接口可复用:
- `GET /tasks`
建议新增的派生字段:
- `display_status`
- `current_step`
- `progress_percent`
- `split_bvid`
- `full_video_bvid`
- `session_key`
- `session_binding_state`
### 3. 任务详情页
目标:让用户不看日志也能处理单个任务。
建议布局:
- Hero 区
- 标题
- 用户态状态
- 当前步骤
- 下次重试时间
- 主要操作按钮
- 步骤时间线
- ingest
- transcribe
- song_detect
- split
- publish
- comment
- collection_a
- collection_b
- 交付结果区
- 分P BV
- 完整版 BV
- 分P 链接
- 完整版链接
- 合集 A / B 链接
- Session 信息区
- session_key
- streamer
- room_id
- segment_started_at
- segment_duration_seconds
- 是否由 sidecar 提供
- 是否由时间连续性自动归并
- 文件与产物区
- source_video
- subtitle_srt
- songs.json
- songs.txt
- clip_video
- 历史动作区
- run
- retry-step
- reset-to-step
- 错误与建议区
- 错误码
- 错误摘要
- 系统建议动作
现有接口可复用:
- `GET /tasks/<id>`
- `GET /tasks/<id>/steps`
- `GET /tasks/<id>/artifacts`
- `GET /tasks/<id>/history`
- `GET /tasks/<id>/timeline`
- `POST /tasks/<id>/actions/run`
- `POST /tasks/<id>/actions/retry-step`
- `POST /tasks/<id>/actions/reset-to-step`
建议新增接口:
- `GET /tasks/<id>/context`
### 4. 设置页
目标:把常用配置变成可理解、可搜索、可修改的产品设置,而不是裸 JSON。
优先展示的用户级配置:
- `ingest.session_gap_minutes`
- `ingest.meta_sidecar_enabled`
- `ingest.meta_sidecar_suffix`
- `comment.max_retries`
- `comment.base_delay_seconds`
- `cleanup.delete_source_video_after_collection_synced`
- `cleanup.delete_split_videos_after_collection_synced`
- `collection.season_id_a`
- `collection.season_id_b`
现有接口可复用:
- `GET /settings`
- `GET /settings/schema`
- `PUT /settings`
## User-Facing Status Mapping
前端必须提供一层用户态状态,不要直接显示内部状态。
建议映射:
- `created` -> `已接收`
- `transcribed` -> `已转录`
- `songs_detected` -> `已识歌`
- `split_done` -> `已切片`
- `published` -> `已上传`
- `commented` -> `评论完成`
- `collection_synced` -> `已完成`
- `failed_retryable` + `step=comment` -> `等待B站可见`
- `failed_retryable` 其他 -> `等待自动重试`
- `failed_manual` -> `需人工处理`
- 任一步 `running` -> `<步骤名>处理中`
建议步骤名展示:
- `ingest` -> `接收视频`
- `transcribe` -> `转录字幕`
- `song_detect` -> `识别歌曲`
- `split` -> `切分分P`
- `publish` -> `上传分P`
- `comment` -> `发布评论`
- `collection_a` -> `加入完整版合集`
- `collection_b` -> `加入分P合集`
## API Integration
### Existing APIs That Frontend Should Reuse
- `GET /tasks`
- `GET /tasks/<id>`
- `GET /tasks/<id>/steps`
- `GET /tasks/<id>/artifacts`
- `GET /tasks/<id>/history`
- `GET /tasks/<id>/timeline`
- `POST /tasks/<id>/actions/run`
- `POST /tasks/<id>/actions/retry-step`
- `POST /tasks/<id>/actions/reset-to-step`
- `GET /settings`
- `GET /settings/schema`
- `PUT /settings`
- `GET /runtime/services`
- `POST /runtime/services/<service>/<action>`
- `POST /worker/run-once`
### Recommended New APIs
#### `GET /tasks/<id>/context`
用途:给任务详情页和 session 归并 UI 提供上下文。
返回建议:
```json
{
"task_id": "xxx",
"session_key": "王海颖:20260402T2203",
"streamer": "王海颖",
"room_id": "581192190066",
"source_title": "王海颖唱歌录播 04月02日 22时03分",
"segment_started_at": "2026-04-02T22:03:00+08:00",
"segment_duration_seconds": 4076.443,
"full_video_bvid": "BV1uH9wBsELC",
"binding_source": "meta_sidecar"
}
```
#### `POST /tasks/<id>/bind-full-video`
用途:用户在前端手工补绑完整版 BV。
请求:
```json
{
"full_video_bvid": "BV1uH9wBsELC"
}
```
#### `POST /sessions/<session_key>/merge`
用途:把多个任务手工归并到同一个 session。
请求:
```json
{
"task_ids": ["why-2205", "why-2306"]
}
```
#### `POST /sessions/<session_key>/rebind`
用途:修改 session 级完整版 BV。
请求:
```json
{
"full_video_bvid": "BV1uH9wBsELC"
}
```
## Derived Fields For UI
后端最好直接给前端这些派生字段,减少前端自行拼状态:
- `display_status`
- `display_step`
- `progress_percent`
- `split_bvid`
- `full_video_bvid`
- `video_links`
- `delivery_state`
- `retry_state`
- `session_context`
- `actions_available`
其中 `actions_available` 建议返回:
```json
{
"run": true,
"retry_step": true,
"reset_to_step": true,
"bind_full_video": true,
"merge_session": true
}
```
## Delivery State Contract
任务列表和详情页都依赖统一的交付状态模型。
建议结构:
```json
{
"split_bvid": "BV1GoDPBtEUg",
"full_video_bvid": "BV1uH9wBsELC",
"split_video_url": "https://www.bilibili.com/video/BV1GoDPBtEUg",
"full_video_url": "https://www.bilibili.com/video/BV1uH9wBsELC",
"comment_split_done": false,
"comment_full_done": false,
"collection_a_done": false,
"collection_b_done": false,
"source_video_present": true,
"split_videos_present": true
}
```
## Suggested Frontend Build Order
按实际价值排序:
1. 任务列表页状态文案升级
2. 任务详情页增加交付结果和重试说明
3. 详情页增加 session/context 区块
4. 设置页增加 session 归并相关配置
5. 增加“手工绑定完整版 BV”操作
6. 增加“合并 session”操作
## MVP Scope
如果只做一轮最小交付,建议先完成:
- 用户态状态映射
- 单任务详情页
- `GET /tasks/<id>/context`
- 手工绑定 `full_video_bvid`
- 前端重试/重置按钮统一化
这样即使 webhook 和自动 session 归并后面再完善,用户也已经能在前端完整处理问题。

View File

@ -1,192 +1,192 @@
# Migration Plan
## Goal
在不破坏原项目运行的前提下,逐步将能力迁移到 `biliup-next`
## Migration Principles
- 原项目继续作为生产系统运行
- 新项目只在 `./biliup-next` 中演进
- 先文档、后骨架、再迁移功能
- 先控制面,后数据面
- 先兼容旧目录结构,再逐步替换旧入口
## Phase 0: Documentation Baseline
目标:
- 明确设计原则
- 明确架构分层
- 明确领域模型
- 明确配置系统和插件系统
产物:
- `vision.md`
- `architecture.md`
- `domain-model.md`
- `design-principles.md`
- `config-system.md`
- `plugin-system.md`
- `state-machine.md`
- `module-contracts.md`
- `migration-plan.md`
## Phase 1: Project Skeleton
目标:
- 建立 `biliup-next/src` 目录结构
- 建立基础 Python 包
- 建立最小配置系统
- 建立 SQLite 存储层
- 建立任务模型和状态模型
不做:
- 不迁移业务逻辑
- 不接管生产入口
## Phase 2: Control Plane MVP
目标:
- 提供最小 API
- 提供任务列表和配置读取能力
- 提供最小 CLI
- 提供 health / logs / settings / tasks 查询能力
产物:
- API server
- config service
- task repository
- runtime doctor
## Phase 3: Data Plane Adapters
目标:
- 把旧系统依赖的外部能力封装成 adapter
优先顺序:
1. `ffmpeg` adapter
2. `Groq` adapter
3. `Codex` adapter
4. `biliup` adapter
5. `Bili API` adapter
理由:
- 先封装外部依赖,后迁移业务模块,能减少后续反复返工
## Phase 4: Module Migration
按顺序迁移业务模块。
### 4.1 Ingest
- 替代 `monitor.py` 的任务创建部分
### 4.2 Transcribe
- 替代 `video2srt.py`
### 4.3 Song Detect
- 替代 `monitorSrt.py`
### 4.4 Split
- 替代 `monitorSongs.py`
### 4.5 Publish
- 替代 `upload.py`
### 4.6 Comment
- 替代 `session_top_comment.py`
### 4.7 Collection
- 替代 `add_to_collection.py`
## Phase 5: Parallel Verification
目标:
- 新旧系统并行验证
- 新系统只处理测试任务
- 对比产物、日志、状态和 B 站结果
重点检查:
- 字幕结果
- 歌曲识别结果
- 切片结果
- 上传结果
- 评论和合集结果
## Phase 6: Admin UI
目标:
- 构建本地控制台
第一版包含:
- 配置页
- 任务页
- 模块页
- 日志页
- 手动操作页
## Phase 7: Cutover
目标:
- 新系统逐步接管生产入口
顺序建议:
1. 只接管任务可视化
2. 接管配置管理
3. 接管测试任务处理
4. 接管单模块生产流量
5. 最终接管全部生产流量
## Risks
### Risk 1: 旧系统与新系统语义不一致
缓解:
- 先定义领域模型和状态机
- 迁移前写适配层,不直接照抄旧脚本行为
### Risk 2: 边迁移边污染旧项目
缓解:
- 所有新内容只放在 `./biliup-next`
- 不改原项目运行入口
### Risk 3: UI 先行导致底层不稳
缓解:
- 先做控制面模型和 API
- 最后做 UI
## Definition Of Done
迁移完成的标准不是“代码搬完”,而是:
- 新系统可以独立运行
- 配置统一管理
- 状态统一落库
- UI 可以完整观察任务
- 旧脚本不再是主入口
# Migration Plan
## Goal
在不破坏原项目运行的前提下,逐步将能力迁移到 `biliup-next`
## Migration Principles
- 原项目继续作为生产系统运行
- 新项目只在 `./biliup-next` 中演进
- 先文档、后骨架、再迁移功能
- 先控制面,后数据面
- 先兼容旧目录结构,再逐步替换旧入口
## Phase 0: Documentation Baseline
目标:
- 明确设计原则
- 明确架构分层
- 明确领域模型
- 明确配置系统和插件系统
产物:
- `vision.md`
- `architecture.md`
- `domain-model.md`
- `design-principles.md`
- `config-system.md`
- `plugin-system.md`
- `state-machine.md`
- `module-contracts.md`
- `migration-plan.md`
## Phase 1: Project Skeleton
目标:
- 建立 `biliup-next/src` 目录结构
- 建立基础 Python 包
- 建立最小配置系统
- 建立 SQLite 存储层
- 建立任务模型和状态模型
不做:
- 不迁移业务逻辑
- 不接管生产入口
## Phase 2: Control Plane MVP
目标:
- 提供最小 API
- 提供任务列表和配置读取能力
- 提供最小 CLI
- 提供 health / logs / settings / tasks 查询能力
产物:
- API server
- config service
- task repository
- runtime doctor
## Phase 3: Data Plane Adapters
目标:
- 把旧系统依赖的外部能力封装成 adapter
优先顺序:
1. `ffmpeg` adapter
2. `Groq` adapter
3. `Codex` adapter
4. `biliup` adapter
5. `Bili API` adapter
理由:
- 先封装外部依赖,后迁移业务模块,能减少后续反复返工
## Phase 4: Module Migration
按顺序迁移业务模块。
### 4.1 Ingest
- 替代 `monitor.py` 的任务创建部分
### 4.2 Transcribe
- 替代 `video2srt.py`
### 4.3 Song Detect
- 替代 `monitorSrt.py`
### 4.4 Split
- 替代 `monitorSongs.py`
### 4.5 Publish
- 替代 `upload.py`
### 4.6 Comment
- 替代 `session_top_comment.py`
### 4.7 Collection
- 替代 `add_to_collection.py`
## Phase 5: Parallel Verification
目标:
- 新旧系统并行验证
- 新系统只处理测试任务
- 对比产物、日志、状态和 B 站结果
重点检查:
- 字幕结果
- 歌曲识别结果
- 切片结果
- 上传结果
- 评论和合集结果
## Phase 6: Admin UI
目标:
- 构建本地控制台
第一版包含:
- 配置页
- 任务页
- 模块页
- 日志页
- 手动操作页
## Phase 7: Cutover
目标:
- 新系统逐步接管生产入口
顺序建议:
1. 只接管任务可视化
2. 接管配置管理
3. 接管测试任务处理
4. 接管单模块生产流量
5. 最终接管全部生产流量
## Risks
### Risk 1: 旧系统与新系统语义不一致
缓解:
- 先定义领域模型和状态机
- 迁移前写适配层,不直接照抄旧脚本行为
### Risk 2: 边迁移边污染旧项目
缓解:
- 所有新内容只放在 `./biliup-next`
- 不改原项目运行入口
### Risk 3: UI 先行导致底层不稳
缓解:
- 先做控制面模型和 API
- 最后做 UI
## Definition Of Done
迁移完成的标准不是“代码搬完”,而是:
- 新系统可以独立运行
- 配置统一管理
- 状态统一落库
- UI 可以完整观察任务
- 旧脚本不再是主入口

View File

@ -1,229 +1,229 @@
# Module Contracts
## Goal
定义各模块的职责边界、输入输出和契约,避免旧系统中“脚本互相读目录、互相猜状态”的耦合方式。
## Contract Principles
- 每个模块只处理一类能力
- 模块只接收明确输入,不扫描全世界
- 模块输出必须结构化
- 模块不直接操控其他模块的内部实现
- 模块不直接依赖具体 provider
## Shared Concepts
所有模块统一围绕这些对象协作:
- `Task`
- `TaskStep`
- `Artifact`
- `Settings`
- `ProviderRef`
## Ingest Module
### Responsibility
- 接收文件输入
- 校验最小处理条件
- 创建任务
### Input
- 本地文件路径
- 当前配置
### Output
- `Task`
- `source_video` artifact
### Must Not Do
- 不直接转录
- 不写上传状态
## Transcribe Module
### Responsibility
- 调用转录 provider
- 生成字幕产物
### Input
- `Task`
- `source_video` artifact
- `transcribe` settings
### Output
- `subtitle_srt` artifact
### Must Not Do
- 不识别歌曲
- 不决定切歌策略
## Song Detect Module
### Responsibility
- 根据字幕识别歌曲
- 生成歌曲结构化结果
### Input
- `Task`
- `subtitle_srt` artifact
- `song_detect` settings
### Output
- `songs_json` artifact
- `songs_txt` artifact
### Must Not Do
- 不切歌
- 不上传
## Split Module
### Responsibility
- 根据歌曲列表切割纯享版片段
### Input
- `Task`
- `songs_json` artifact
- `source_video` artifact
- `split` settings
### Output
- 多个 `clip_video` artifact
## Publish Module
### Responsibility
- 上传纯享版视频
- 记录发布结果
### Input
- `Task`
- `clip_video[]`
- `publish` settings
### Output
- `PublishRecord`
- `publish_bvid` artifact
### Must Not Do
- 不负责评论文案生成
- 不负责合集匹配策略
## Comment Module
### Responsibility
- 发布并置顶评论
### Input
- `Task`
- `PublishRecord`
- `songs_txt` artifact
- `comment` settings
### Output
- `comment_record` artifact
## Collection Module
### Responsibility
- 根据策略同步合集 A / B
### Input
- `Task`
- `PublishRecord` 或外部 `full_video_bvid`
- `collection` settings
- `collection strategy`
### Output
- `CollectionBinding`
### Internal Sub-Strategies
- `full_video_collection_strategy`
- `song_collection_strategy`
## Provider Contracts
### TranscribeProvider
```text
transcribe(task, source_video, settings) -> subtitle_srt
```
### SongDetector
```text
detect(task, subtitle_srt, settings) -> songs_json, songs_txt
```
### PublishProvider
```text
publish(task, clip_videos, settings) -> PublishRecord
```
### CommentStrategy
```text
sync_comment(task, publish_record, songs_txt, settings) -> comment_record
```
### CollectionStrategy
```text
sync_collection(task, context, settings) -> CollectionBinding[]
```
## Orchestration Rules
模块本身不负责全局编排。
全局编排由任务引擎或 worker 负责:
- 判断下一步该跑什么
- 决定是否重试
- 写入状态
- 调度具体模块
## Error Contract
所有模块失败时应返回统一错误结构:
- `code`
- `message`
- `retryable`
- `details`
不得只返回原始字符串日志作为唯一错误结果。
## Non-Goals
- 模块之间不共享私有目录扫描逻辑
- 模块契约不直接暴露 shell 命令细节
# Module Contracts
## Goal
定义各模块的职责边界、输入输出和契约,避免旧系统中“脚本互相读目录、互相猜状态”的耦合方式。
## Contract Principles
- 每个模块只处理一类能力
- 模块只接收明确输入,不扫描全世界
- 模块输出必须结构化
- 模块不直接操控其他模块的内部实现
- 模块不直接依赖具体 provider
## Shared Concepts
所有模块统一围绕这些对象协作:
- `Task`
- `TaskStep`
- `Artifact`
- `Settings`
- `ProviderRef`
## Ingest Module
### Responsibility
- 接收文件输入
- 校验最小处理条件
- 创建任务
### Input
- 本地文件路径
- 当前配置
### Output
- `Task`
- `source_video` artifact
### Must Not Do
- 不直接转录
- 不写上传状态
## Transcribe Module
### Responsibility
- 调用转录 provider
- 生成字幕产物
### Input
- `Task`
- `source_video` artifact
- `transcribe` settings
### Output
- `subtitle_srt` artifact
### Must Not Do
- 不识别歌曲
- 不决定切歌策略
## Song Detect Module
### Responsibility
- 根据字幕识别歌曲
- 生成歌曲结构化结果
### Input
- `Task`
- `subtitle_srt` artifact
- `song_detect` settings
### Output
- `songs_json` artifact
- `songs_txt` artifact
### Must Not Do
- 不切歌
- 不上传
## Split Module
### Responsibility
- 根据歌曲列表切割纯享版片段
### Input
- `Task`
- `songs_json` artifact
- `source_video` artifact
- `split` settings
### Output
- 多个 `clip_video` artifact
## Publish Module
### Responsibility
- 上传纯享版视频
- 记录发布结果
### Input
- `Task`
- `clip_video[]`
- `publish` settings
### Output
- `PublishRecord`
- `publish_bvid` artifact
### Must Not Do
- 不负责评论文案生成
- 不负责合集匹配策略
## Comment Module
### Responsibility
- 发布并置顶评论
### Input
- `Task`
- `PublishRecord`
- `songs_txt` artifact
- `comment` settings
### Output
- `comment_record` artifact
## Collection Module
### Responsibility
- 根据策略同步合集 A / B
### Input
- `Task`
- `PublishRecord` 或外部 `full_video_bvid`
- `collection` settings
- `collection strategy`
### Output
- `CollectionBinding`
### Internal Sub-Strategies
- `full_video_collection_strategy`
- `song_collection_strategy`
## Provider Contracts
### TranscribeProvider
```text
transcribe(task, source_video, settings) -> subtitle_srt
```
### SongDetector
```text
detect(task, subtitle_srt, settings) -> songs_json, songs_txt
```
### PublishProvider
```text
publish(task, clip_videos, settings) -> PublishRecord
```
### CommentStrategy
```text
sync_comment(task, publish_record, songs_txt, settings) -> comment_record
```
### CollectionStrategy
```text
sync_collection(task, context, settings) -> CollectionBinding[]
```
## Orchestration Rules
模块本身不负责全局编排。
全局编排由任务引擎或 worker 负责:
- 判断下一步该跑什么
- 决定是否重试
- 写入状态
- 调度具体模块
## Error Contract
所有模块失败时应返回统一错误结构:
- `code`
- `message`
- `retryable`
- `details`
不得只返回原始字符串日志作为唯一错误结果。
## Non-Goals
- 模块之间不共享私有目录扫描逻辑
- 模块契约不直接暴露 shell 命令细节

View File

@ -1,156 +1,156 @@
# Plugin System
## Goal
插件系统的目标不是“让任何东西都能热插拔”,而是为未来的能力替换和扩展提供稳定边界。
优先支持:
- 转录提供者替换
- 歌曲识别提供者替换
- 上传器替换
- 评论策略替换
- 合集策略替换
- 输入源扩展
## Design Principles
借鉴 OpenClaw 的思路,采用 `manifest-first` + `registry` 设计。
原则:
- 插件先注册元信息,再执行运行时代码
- 控制面优先读取 manifest 和 schema
- 核心系统只依赖抽象接口和 registry
- 插件配置必须可校验
## Plugin Composition
每个插件由两部分组成:
### 1. Manifest
描述插件的元信息和配置能力。
例如:
```json
{
"id": "codex-song-detector",
"name": "Codex Song Detector",
"version": "0.1.0",
"type": "song_detector",
"entrypoint": "plugins.codex_song_detector.runtime:register",
"configSchema": "plugins/codex_song_detector/config.schema.json",
"capabilities": ["song_detect"],
"enabledByDefault": true
}
```
### 2. Runtime
真正实现业务逻辑的代码。
## Registry
系统启动时统一构建 registry。
registry 负责:
- 注册插件能力
- 按类型查找实现
- 根据配置激活当前 provider
### Registry Types
- `ingest_provider`
- `transcribe_provider`
- `song_detector`
- `split_provider`
- `publish_provider`
- `comment_strategy`
- `collection_strategy`
## Plugin Loading Flow
```text
Discover manifests
-> Validate manifests
-> Register capabilities in registry
-> Load plugin config schema
-> Validate plugin config
-> Activate runtime implementation
```
## Why Manifest-First
这样设计有 4 个直接好处:
- 管理台可以在不执行插件代码时展示插件信息
- UI 可以根据 schema 渲染配置表单
- 系统可以提前发现缺失字段或不兼容版本
- 插件运行失败不会影响元数据层的可见性
## Suggested Plugin Boundaries
### Transcribe Provider
示例:
- `groq`
- `openai`
- `local_whisper`
### Song Detector
示例:
- `codex`
- `rule_engine`
- `custom_llm`
### Publish Provider
示例:
- `biliup_cli`
- `bilibili_api`
### Collection Strategy
示例:
- `default_song_collection`
- `title_match_full_video`
- `manual_binding`
## Control Plane Integration
插件系统必须服务于控制面。
因此管理台至少需要知道:
- 当前有哪些插件
- 每个插件类型是什么
- 当前启用的是哪一个
- 配置是否有效
- 最近一次健康检查结果
## Restrictions
为了避免再次走向“任意脚本散落”,插件系统需要约束:
- 插件不得直接修改核心数据库结构
- 插件不得绕过统一配置系统
- 插件不得私自写独立日志目录作为唯一状态来源
- 插件不得直接互相调用具体实现
## Initial Strategy
第一阶段不追求真正的第三方插件生态。
先实现“内置插件化”:
- 核心仓库内提供多个 provider
- 统一用 manifest + registry 管理
- 等边界稳定后,再考虑开放外部插件目录
# Plugin System
## Goal
插件系统的目标不是“让任何东西都能热插拔”,而是为未来的能力替换和扩展提供稳定边界。
优先支持:
- 转录提供者替换
- 歌曲识别提供者替换
- 上传器替换
- 评论策略替换
- 合集策略替换
- 输入源扩展
## Design Principles
借鉴 OpenClaw 的思路,采用 `manifest-first` + `registry` 设计。
原则:
- 插件先注册元信息,再执行运行时代码
- 控制面优先读取 manifest 和 schema
- 核心系统只依赖抽象接口和 registry
- 插件配置必须可校验
## Plugin Composition
每个插件由两部分组成:
### 1. Manifest
描述插件的元信息和配置能力。
例如:
```json
{
"id": "codex-song-detector",
"name": "Codex Song Detector",
"version": "0.1.0",
"type": "song_detector",
"entrypoint": "plugins.codex_song_detector.runtime:register",
"configSchema": "plugins/codex_song_detector/config.schema.json",
"capabilities": ["song_detect"],
"enabledByDefault": true
}
```
### 2. Runtime
真正实现业务逻辑的代码。
## Registry
系统启动时统一构建 registry。
registry 负责:
- 注册插件能力
- 按类型查找实现
- 根据配置激活当前 provider
### Registry Types
- `ingest_provider`
- `transcribe_provider`
- `song_detector`
- `split_provider`
- `publish_provider`
- `comment_strategy`
- `collection_strategy`
## Plugin Loading Flow
```text
Discover manifests
-> Validate manifests
-> Register capabilities in registry
-> Load plugin config schema
-> Validate plugin config
-> Activate runtime implementation
```
## Why Manifest-First
这样设计有 4 个直接好处:
- 管理台可以在不执行插件代码时展示插件信息
- UI 可以根据 schema 渲染配置表单
- 系统可以提前发现缺失字段或不兼容版本
- 插件运行失败不会影响元数据层的可见性
## Suggested Plugin Boundaries
### Transcribe Provider
示例:
- `groq`
- `openai`
- `local_whisper`
### Song Detector
示例:
- `codex`
- `rule_engine`
- `custom_llm`
### Publish Provider
示例:
- `biliup_cli`
- `bilibili_api`
### Collection Strategy
示例:
- `default_song_collection`
- `title_match_full_video`
- `manual_binding`
## Control Plane Integration
插件系统必须服务于控制面。
因此管理台至少需要知道:
- 当前有哪些插件
- 每个插件类型是什么
- 当前启用的是哪一个
- 配置是否有效
- 最近一次健康检查结果
## Restrictions
为了避免再次走向“任意脚本散落”,插件系统需要约束:
- 插件不得直接修改核心数据库结构
- 插件不得绕过统一配置系统
- 插件不得私自写独立日志目录作为唯一状态来源
- 插件不得直接互相调用具体实现
## Initial Strategy
第一阶段不追求真正的第三方插件生态。
先实现“内置插件化”:
- 核心仓库内提供多个 provider
- 统一用 manifest + registry 管理
- 等边界稳定后,再考虑开放外部插件目录

View File

@ -1,178 +1,178 @@
# biliup-next Professionalization Roadmap - 2026-04-06
## 目标
`biliup-next` 从“方向正确的重构工程”推进到“边界清晰、契约稳定、可持续演进的专业级本地控制面系统”。
本路线图以当前仓库中已经明确吸收的 OpenClaw 设计哲学为参照:
- modular monolith
- control-plane first
- schema-first
- manifest-first
- registry over direct coupling
- single source of truth
重点不是重复这些口号,而是把它们继续落实到真实代码和工程制度中。
## 维度一:平台边界
### 当前差距
- provider 内仍大量直接调用 `subprocess``requests`
- adapter / provider / module service 的边界还不够硬
- 外部依赖的超时、重试、错误翻译和观测没有统一制度
### 目标状态
- 外部命令和外部 HTTP 都通过稳定 adapter 层进入系统
- provider 只消费标准化 adapter 能力和统一错误语义
- 超时、重试、限流、日志和诊断在 adapter 层具备统一约束
### 改进事项
-`ffmpeg``codex``biliup`、Bili API、Groq 定义统一 adapter 接口
- 将 provider 中的直接 `subprocess.run()``requests` 逐步下沉到 adapter
- 统一 adapter 错误模型,减少 provider 自己拼接临时错误码
- 为 adapter 增加可观测上下文,例如 command name、target、duration、attempt
### 完成标志
- 业务模块不再直接拼 shell/http 调用
- adapter 成为唯一外部依赖入口
## 维度二:领域模型
### 当前差距
- 核心规则分散在 `task_engine``task_policies``task_actions`、provider 和部分工作区文件
- 文档已有 domain model但还没有形成更稳定的应用服务/领域服务边界
- `task``session``full_video_bvid` 这类跨模块关系仍有隐式规则
### 目标状态
- task lifecycle、retry policy、session binding、delivery side effects 都有清晰归属
- 领域规则主要存在于少数稳定模块,而不是散落在控制器和 provider 中
- “谁负责写什么状态”有明确制度
### 改进事项
- 明确 `Task``TaskContext``SessionBinding` 的边界和 ownership
-`full_video_bvid`、session 归并、评论/合集副作用收敛成独立领域服务
- 评估是否引入显式 domain event 或最小事件记录层
- 为状态迁移建立更显式的 transition table 或 policy object
### 完成标志
- 关键规则不再分散在多个入口函数中重复实现
- task/session/delivery 的事实源和写入职责稳定
## 维度三:接口契约
### 当前差距
- API handler 仍承担较多 payload 组装和视图拼接工作
- OpenAPI 与真实控制面细节还不够同步
- 内部领域模型与外部 API 视图没有充分分层
### 目标状态
- API 对外暴露稳定 DTO而不是直接拼内部模型
- handler 更薄,组装逻辑集中在 service / presenter / serializer 层
- 契约变更可追踪、可校验
### 改进事项
- 为 task detail、task list、session detail、timeline 建立稳定 serializer
- 清理 API handler 中的重复组装逻辑
- 更新 `docs/api/openapi.yaml`,让其覆盖真实控制面接口
- 明确哪些字段属于内部实现细节,不直接暴露给前端
### 完成标志
- handler 只做路由、鉴权、输入解析和响应返回
- API 文档与真实返回结构保持同步
## 维度四:测试体系
### 当前差距
- 已有最小回归测试,但仍偏重纯逻辑
- repository、API、provider 契约、端到端场景覆盖不足
### 目标状态
- 核心编排、存储、API、adapter 都有分层测试
- 关键重构不需要依赖手工回归
### 改进事项
- 新增 repository 的 SQLite 集成测试
- 为 API handler 增加最小接口行为测试
- 为 adapter/provider 增加契约测试和失败场景测试
- 保留现有纯逻辑 unittest继续增加 smoke 回归脚本
### 完成标志
- 至少形成:
- 逻辑单元测试
- SQLite 集成测试
- API 行为测试
- smoke / regression 流程
## 维度五:运维成熟度
### 当前差距
- 已有 doctor、logs、systemd 控制和 workspace 隔离
- 但健康度、指标、审计、恢复机制还不够体系化
### 目标状态
- 控制面不仅能“看到状态”,还能帮助判断风险和恢复问题
- 运行问题可以靠结构化信号而不是人工翻日志定位
### 改进事项
- 区分 health / readiness / degraded
- 规范结构化日志字段
- 为 task/step 增加最小指标视图
- 完善审计事件分类
- 明确数据库/配置变更/运行资产的迁移与回滚流程
### 完成标志
- 常见运行问题可以靠控制面和标准日志定位
- 关键操作具备审计和回滚说明
## 推荐优先顺序
1. 平台边界
2. 领域模型
3. 接口契约
4. 测试体系
5. 运维成熟度
## 下一批优先项
### Priority A
-`biliup`、Bili API 和 `codex` 建立统一 adapter 边界
-`task_actions` 中与 session/delivery 相关的规则继续抽成稳定服务
- 为 task list / task detail / session detail 提供 serializer 层
### Priority B
- 新增 repository SQLite 集成测试
- 新增 API 行为测试
- 更新 OpenAPI 契约
### Priority C
- 设计 health/readiness/degraded 模型
- 规范日志和审计字段
## 备注
- 这份路线图描述的是“距离专业化还有哪些结构性工作”,不是说当前系统不可用。
- 当前项目已经具备正确方向;接下来的重点是把设计哲学继续固化为代码边界、测试制度和运维约束。
# biliup-next Professionalization Roadmap - 2026-04-06
## 目标
`biliup-next` 从“方向正确的重构工程”推进到“边界清晰、契约稳定、可持续演进的专业级本地控制面系统”。
本路线图以当前仓库中已经明确吸收的 OpenClaw 设计哲学为参照:
- modular monolith
- control-plane first
- schema-first
- manifest-first
- registry over direct coupling
- single source of truth
重点不是重复这些口号,而是把它们继续落实到真实代码和工程制度中。
## 维度一:平台边界
### 当前差距
- provider 内仍大量直接调用 `subprocess``requests`
- adapter / provider / module service 的边界还不够硬
- 外部依赖的超时、重试、错误翻译和观测没有统一制度
### 目标状态
- 外部命令和外部 HTTP 都通过稳定 adapter 层进入系统
- provider 只消费标准化 adapter 能力和统一错误语义
- 超时、重试、限流、日志和诊断在 adapter 层具备统一约束
### 改进事项
-`ffmpeg``codex``biliup`、Bili API、Groq 定义统一 adapter 接口
- 将 provider 中的直接 `subprocess.run()``requests` 逐步下沉到 adapter
- 统一 adapter 错误模型,减少 provider 自己拼接临时错误码
- 为 adapter 增加可观测上下文,例如 command name、target、duration、attempt
### 完成标志
- 业务模块不再直接拼 shell/http 调用
- adapter 成为唯一外部依赖入口
## 维度二:领域模型
### 当前差距
- 核心规则分散在 `task_engine``task_policies``task_actions`、provider 和部分工作区文件
- 文档已有 domain model但还没有形成更稳定的应用服务/领域服务边界
- `task``session``full_video_bvid` 这类跨模块关系仍有隐式规则
### 目标状态
- task lifecycle、retry policy、session binding、delivery side effects 都有清晰归属
- 领域规则主要存在于少数稳定模块,而不是散落在控制器和 provider 中
- “谁负责写什么状态”有明确制度
### 改进事项
- 明确 `Task``TaskContext``SessionBinding` 的边界和 ownership
-`full_video_bvid`、session 归并、评论/合集副作用收敛成独立领域服务
- 评估是否引入显式 domain event 或最小事件记录层
- 为状态迁移建立更显式的 transition table 或 policy object
### 完成标志
- 关键规则不再分散在多个入口函数中重复实现
- task/session/delivery 的事实源和写入职责稳定
## 维度三:接口契约
### 当前差距
- API handler 仍承担较多 payload 组装和视图拼接工作
- OpenAPI 与真实控制面细节还不够同步
- 内部领域模型与外部 API 视图没有充分分层
### 目标状态
- API 对外暴露稳定 DTO而不是直接拼内部模型
- handler 更薄,组装逻辑集中在 service / presenter / serializer 层
- 契约变更可追踪、可校验
### 改进事项
- 为 task detail、task list、session detail、timeline 建立稳定 serializer
- 清理 API handler 中的重复组装逻辑
- 更新 `docs/api/openapi.yaml`,让其覆盖真实控制面接口
- 明确哪些字段属于内部实现细节,不直接暴露给前端
### 完成标志
- handler 只做路由、鉴权、输入解析和响应返回
- API 文档与真实返回结构保持同步
## 维度四:测试体系
### 当前差距
- 已有最小回归测试,但仍偏重纯逻辑
- repository、API、provider 契约、端到端场景覆盖不足
### 目标状态
- 核心编排、存储、API、adapter 都有分层测试
- 关键重构不需要依赖手工回归
### 改进事项
- 新增 repository 的 SQLite 集成测试
- 为 API handler 增加最小接口行为测试
- 为 adapter/provider 增加契约测试和失败场景测试
- 保留现有纯逻辑 unittest继续增加 smoke 回归脚本
### 完成标志
- 至少形成:
- 逻辑单元测试
- SQLite 集成测试
- API 行为测试
- smoke / regression 流程
## 维度五:运维成熟度
### 当前差距
- 已有 doctor、logs、systemd 控制和 workspace 隔离
- 但健康度、指标、审计、恢复机制还不够体系化
### 目标状态
- 控制面不仅能“看到状态”,还能帮助判断风险和恢复问题
- 运行问题可以靠结构化信号而不是人工翻日志定位
### 改进事项
- 区分 health / readiness / degraded
- 规范结构化日志字段
- 为 task/step 增加最小指标视图
- 完善审计事件分类
- 明确数据库/配置变更/运行资产的迁移与回滚流程
### 完成标志
- 常见运行问题可以靠控制面和标准日志定位
- 关键操作具备审计和回滚说明
## 推荐优先顺序
1. 平台边界
2. 领域模型
3. 接口契约
4. 测试体系
5. 运维成熟度
## 下一批优先项
### Priority A
-`biliup`、Bili API 和 `codex` 建立统一 adapter 边界
-`task_actions` 中与 session/delivery 相关的规则继续抽成稳定服务
- 为 task list / task detail / session detail 提供 serializer 层
### Priority B
- 新增 repository SQLite 集成测试
- 新增 API 行为测试
- 更新 OpenAPI 契约
### Priority C
- 设计 health/readiness/degraded 模型
- 规范日志和审计字段
## 备注
- 这份路线图描述的是“距离专业化还有哪些结构性工作”,不是说当前系统不可用。
- 当前项目已经具备正确方向;接下来的重点是把设计哲学继续固化为代码边界、测试制度和运维约束。

View File

@ -0,0 +1,321 @@
# 发布输出示例与流程说明
本文档面向使用者说明 `biliup-next` 的主流程、输入输出、当前已实现功能,以及一次多段同场直播发布后的示例文案。
## 项目功能
`biliup-next` 将一场直播录播拆成两个最终发布目标:
- 直播完整版:由外部流程或人工上传到 B 站,本项目负责记录/绑定它的 BV 号,并给它补充置顶时间轴评论、加入完整版合集。
- 歌曲纯享版:由本项目从直播录播中识别歌曲、切出歌曲片段、合并发布为一个分 P 视频,并给它补充置顶歌单评论、加入纯享版合集。
当前主链路:
```text
stage 输入视频
-> ingest 导入并归并 session
-> transcribe 语音转字幕
-> song_detect 识别歌曲
-> split 切出歌曲片段
-> publish 发布歌曲纯享版
-> comment 发布/置顶评论
-> collection 加入合集
```
## 输入
最常见输入是把录播视频放入 `data/workspace/stage/`
支持的形式:
- 单个视频文件:一场直播只有一个录播文件。
- 多个视频文件:同一场直播被分成多段录播文件。
- 浏览器上传:通过控制台上传到 stage。
- 本机复制:通过控制台把服务器上的文件复制到 stage。
输入文件名会用于推测主播和直播开始时间,例如:
```text
王海颖唱歌录播 04月19日 22时10分.mp4
王海颖唱歌录播 04月19日 23时05分.mp4
王海颖唱歌录播 04月20日 00时01分.mp4
```
## Session 归并
同一主播、时间接近的多个录播片段会归入同一个 session。
同一 session 的行为:
- 只发布一个歌曲纯享版 BV。
- 多段录播的歌曲会按时间顺序聚合。
- 评论按 `P1``P2``P3` 分段展示。
- 歌曲序号全局递增,不在每个 P 内重新从 1 开始。
示例:
```text
P1:
1. 程艾影 — 赵雷
2. 钟无艳 — 谢安琪
P2:
3. 慢慢喜欢你 — 莫文蔚
P3:
4. 空白格 — 蔡健雅
```
## BV 获取
### 歌曲纯享版 BV
歌曲纯享版由本项目调用 `biliup upload` 发布。
发布成功后,项目会从 `biliup` 输出中提取 BV 号,并写入当前 session 目录:
```text
bvid.txt
```
这个 BV 会用于:
- 纯享版评论发布。
- 完整版评论顶部反向链接。
- 纯享版合集同步。
### 直播完整版 BV
完整版 BV 可以来自三种方式:
- 控制台手动绑定。
- API/webhook 传入。
- `biliup list` 标题匹配。
`biliup list` 会同时接受 `开放浏览``审核中` 状态。完整版视频只要上传后生成了 BV即使仍在审核中也可以被写入纯享版简介、动态和评论互链。
成功解析后会写入:
```text
full_video_bvid.txt
```
默认标题匹配是保守的精确匹配:会先去掉空格、标点、括号、冒号等,只保留中文、英文、数字,再比较标题是否相等。
如果 `allow_fuzzy_full_video_match=false`,不会做包含式模糊匹配。为了避免误匹配,推荐在完整版上传完成后手动绑定 BV。
## 示例场景
假设本次直播由三段录播组成:
```text
王海颖唱歌录播 04月19日 22时10分
王海颖唱歌录播 04月19日 23时05分
王海颖唱歌录播 04月20日 00时01分
```
假设 BV 绑定结果如下:
```text
本次直播完整版BVFULLCURR
本次歌曲纯享版BVPURECURR
上次直播完整版BVFULLPREV
```
假设识别出的歌曲如下:
```text
P1:
00:06:32 程艾影 — 赵雷
00:14:45 钟无艳 — 谢安琪
P2:
00:20:57 慢慢喜欢你 — 莫文蔚
P3:
00:27:16 空白格 — 蔡健雅
```
## 歌曲纯享版标题
当前模板:
```text
【{streamer} (歌曲纯享版)】 {date} 共{song_count}首歌
```
示例:
```text
【王海颖 (歌曲纯享版)】 04月19日 22时10分 共4首歌
```
## 歌曲纯享版简介
当前模板会保持简介较短,完整歌单放到置顶评论中,避免 B 站简介截断。
示例:
```text
王海颖 04月19日 22时10分 歌曲纯享版。
完整歌单与时间轴见置顶评论。
直播完整版https://www.bilibili.com/video/BVFULLCURR
上次直播https://www.bilibili.com/video/BVFULLPREV
本视频为歌曲纯享切片,适合只听歌曲。
```
如果某个链接暂时没有 BV项目会自动移除对应的空链接行。
## 歌曲纯享版动态
示例:
```text
王海颖 04月19日 22时10分 歌曲纯享版已发布。完整歌单见置顶评论。
直播完整版https://www.bilibili.com/video/BVFULLCURR
上次直播https://www.bilibili.com/video/BVFULLPREV
```
## 歌曲纯享版置顶评论
纯享版评论主要给听歌用户看,不带歌曲时间轴,只展示歌名、歌手和互链。
默认由 `runtime/upload_config.json``comment_template.split_header``comment_template.split_part_header``comment_template.split_song_line` 生成。
示例:
```text
当前视频:歌曲纯享版:只保留本场直播中的歌曲片段,歌单见下方。
直播完整版https://www.bilibili.com/video/BVFULLCURR (完整录播,含聊天/互动/完整流程)
上次纯享https://www.bilibili.com/video/BVPUREPREV (上一场歌曲纯享版)
P1:
1. 程艾影 — 赵雷
2. 钟无艳 — 谢安琪
P2:
3. 慢慢喜欢你 — 莫文蔚
P3:
4. 空白格 — 蔡健雅
```
## 直播完整版置顶评论
完整版评论主要给看完整录播的用户跳转歌曲纯享版,并提供完整时间轴。
默认由 `runtime/upload_config.json``comment_template.full_header``comment_template.full_part_header``comment_template.full_timeline_line` 生成。
示例:
```text
当前视频:直播完整版:保留本场完整录播内容,歌曲时间轴见下方。
歌曲纯享版https://www.bilibili.com/video/BVPURECURR (只听歌曲看这里)
上次完整版https://www.bilibili.com/video/BVFULLPREV (上一场完整录播)
P1:
1. 00:06:32 程艾影 — 赵雷
2. 00:14:45 钟无艳 — 谢安琪
P2:
3. 00:20:57 慢慢喜欢你 — 莫文蔚
P3:
4. 00:27:16 空白格 — 蔡健雅
```
## 评论格式配置
评论格式可以像标题、简介、动态一样通过 `runtime/upload_config.json` 修改:
```json
"comment_template": {
"split_header": "当前视频:歌曲纯享版:只保留本场直播中的歌曲片段,歌单见下方。\n直播完整版{current_full_video_link} (完整录播,含聊天/互动/完整流程)\n上次纯享{previous_pure_video_link} (上一场歌曲纯享版)",
"full_header": "当前视频:直播完整版:保留本场完整录播内容,歌曲时间轴见下方。\n歌曲纯享版{current_pure_video_link} (只听歌曲看这里)\n上次完整版{previous_full_video_link} (上一场完整录播)",
"split_part_header": "P{part_index}:",
"full_part_header": "P{part_index}:",
"split_song_line": "{song_index}. {title}{artist_suffix}",
"split_text_song_line": "{song_index}. {song_text}",
"full_timeline_line": "{song_index}. {line_text}"
}
```
字段含义:
- `split_header`:纯享版评论顶部说明。
- `full_header`:完整版评论顶部说明。
- `split_part_header` / `full_part_header`:多片段 session 的分段标题,例如 `P1:`
- `split_song_line`:从 `songs.json` 生成纯享歌单时的单行格式。
- `split_text_song_line``songs.json` 不可用时,从 `songs.txt` 兜底生成纯享歌单的单行格式。
- `full_timeline_line`:完整版时间轴评论的单行格式。
常用变量:
- `{current_full_video_link}`:本场直播完整版链接。
- `{current_pure_video_link}`:本场歌曲纯享版链接。
- `{previous_full_video_link}`:上一场直播完整版链接。
- `{previous_pure_video_link}`:上一场歌曲纯享版链接。
- `{part_index}`P 分段序号。
- `{song_index}`:歌曲全局序号。
- `{title}` / `{artist}` / `{artist_suffix}`:歌曲标题、歌手、带分隔符的歌手后缀。
- `{song_text}`:不带时间戳的歌曲文本。
- `{line_text}`:原始时间轴行,通常包含时间戳。
如果评论头部某一行包含空链接变量,例如 `{previous_full_video_link}` 为空,这一整行会自动省略。
## 合集同步
项目维护两个合集目标:
- 合集 A直播完整版。
- 合集 B歌曲纯享版。
当前配置中的示例 ID
```text
直播完整版合集7196643
歌曲纯享版合集7196624
```
合集同步完成后,如果启用了清理策略,项目可以删除本地原视频或切片视频以节省空间。当前默认不删除。
## 幂等与重试
项目会在 session 目录写入标记文件,避免重复上传和重复评论。
常见标记:
```text
bvid.txt
full_video_bvid.txt
upload_done.flag
comment_split_done.flag
comment_full_done.flag
collection_a_done.flag
collection_b_done.flag
```
发布阶段的关键行为:
- 首批最多上传 5 个分 P。
- 超过 5 个分 P 时,后续通过 append 追加。
- 已经写入 `bvid.txt` 后,重试会优先 append 到已有视频,而不是重新发布。
- `publish_progress.json` 记录 append 进度,避免重试时重复追加已完成批次。
评论阶段的关键行为:
- 同一 session 只由最早片段负责聚合评论。
- 非 anchor 片段进入评论步骤时会跳过实际发评。
- 这样可以避免同一场直播的多个片段重复发布相同评论。
## 使用建议
发布前建议确认:
- stage 中的视频文件名能解析出主播和时间。
- `runtime/upload_config.json` 中标题、简介、动态符合预期。
- 完整版上传完成后,尽量手动绑定 `full_video_bvid`
- worker 重启前确认已有 `bvid.txt``publish_progress.json` 是否符合当前发布进度。
- 如需自动匹配完整版 BV确认 `biliup list` 中完整视频标题与任务标题标准化后相等。

View File

@ -1,134 +1,134 @@
# biliup-next Refactor Plan - 2026-04-06
## 目标
围绕当前重构项目已暴露出的状态一致性、数据一致性、运行稳定性和控制面性能问题,分阶段推进改造,优先修复会影响真实运行结果的问题,再收敛模型和技术债。
## 改造原则
- 先修正单一事实源,再优化展示层。
- 先修正状态机真实行为,再修正文档和 UI 映射。
- 先处理运行稳定性,再处理性能和结构整理。
- 每一阶段都要求有可验证的验收结果,避免只做“结构看起来更好”。
## 阶段划分
### Phase 1: 状态与事实源收敛
目标:
- 让 task 具备真实可用的 `running` 语义。
-`full_video_bvid` 只有一套权威写入路径。
- 消除“数据库状态”和“工作区文件状态”互相覆盖的问题。
任务:
- 在 step 开始执行时同步更新 task 运行态。
- 明确 task 完成后 task 状态如何从 `running` 返回业务态。
- 统一 `bind/rebind/webhook/ingest``full_video_bvid` 的读写入口。
- 明确 `task_contexts``session_bindings``full_video_bvid.txt` 的职责。
验收标准:
- 控制台能正确筛选和显示运行中的任务。
- 手工绑定、session 重绑、webhook 注入后,新旧任务读取到相同 BV。
- 不再出现新任务 ingest 继承旧 BV 的情况。
### Phase 2: 运行稳定性加固
目标:
- 让 API 与 worker 并行运行时的 SQLite 行为可控。
- 降低锁冲突、脏状态和半成功写入风险。
任务:
- 为 SQLite 连接增加 `busy_timeout``WAL``foreign_keys=ON`
- 检查高频 repo 写入点,减少不必要的小事务。
- 梳理关键写路径是否需要合并成原子操作。
验收标准:
- API 和 worker 并行运行时,不再轻易触发数据库锁错误。
- 关键任务状态写入具备基本原子性,不出现“步骤更新了、任务没更新”一类半状态。
### Phase 3: 控制面装配与查询优化
目标:
- 去掉 API 请求路径上的重复初始化。
- 解决 `/tasks` 列表的全量扫描和 N+1 查询问题。
任务:
-`ensure_initialized()` 从“每次请求即装配”改为更稳定的应用级初始化方式。
- 收敛 provider/registry 生命周期,避免每次请求重复扫描 manifest 和实例化 provider。
- 优化任务列表接口,把可下推的过滤逻辑下推到 repository 或持久化层。
- 减少列表查询时对工作区文件的逐条读取。
验收标准:
- 常规 API 请求不再重复做全量装配。
- 大量任务下的列表页和筛选页响应明显改善。
### Phase 4: 状态机与文档对齐
目标:
- 让文档状态机、代码状态机、控制面展示口径一致。
任务:
- 决定是否保留 `ingested``completed``cancelled`
- 明确 flag 文件在系统中的角色。
- 如果数据库是任务状态唯一来源,则把 delivery flag 降级为产物或外部副作用标记。
- 更新状态机文档、控制面展示文案和开发约束。
验收标准:
- 文档中的状态集合与代码中的状态集合一致。
- UI 不再依赖不存在或含义不稳定的 task 状态。
### Phase 5: 回归测试与维护收尾
目标:
- 为核心编排逻辑补回归保护。
- 降低后续重构再次引入状态漂移的概率。
任务:
- 新增 `tests/`
- 优先覆盖:
- `task_engine`
- `task_policies`
- `task_actions`
- `retry_meta`
- `task_reset`
- 决定 classic 控制台的保留策略。
验收标准:
- 核心状态流转具备最小自动化回归覆盖。
- 控制台维护策略明确,不再长期双线漂移。
## 推荐执行顺序
1. Phase 1
2. Phase 2
3. Phase 3
4. Phase 4
5. Phase 5
## 本轮起步范围
本轮先从以下子项开始:
- Phase 1.1: task `running` 状态落地
- Phase 1.2: `full_video_bvid` 写路径统一
- Phase 2.1: SQLite 连接配置加固
## 过程记录
- 2026-04-06完成代码审查确认当前优先问题集中在 task 运行态缺失、`full_video_bvid` 多源不一致、SQLite 并发配置不足、重复初始化、列表查询 N+1、状态机文档与实现漂移、测试缺失。
- 2026-04-06将问题整理为本改造计划按阶段拆分并确定先做状态一致性与运行稳定性。
# biliup-next Refactor Plan - 2026-04-06
## 目标
围绕当前重构项目已暴露出的状态一致性、数据一致性、运行稳定性和控制面性能问题,分阶段推进改造,优先修复会影响真实运行结果的问题,再收敛模型和技术债。
## 改造原则
- 先修正单一事实源,再优化展示层。
- 先修正状态机真实行为,再修正文档和 UI 映射。
- 先处理运行稳定性,再处理性能和结构整理。
- 每一阶段都要求有可验证的验收结果,避免只做“结构看起来更好”。
## 阶段划分
### Phase 1: 状态与事实源收敛
目标:
- 让 task 具备真实可用的 `running` 语义。
-`full_video_bvid` 只有一套权威写入路径。
- 消除“数据库状态”和“工作区文件状态”互相覆盖的问题。
任务:
- 在 step 开始执行时同步更新 task 运行态。
- 明确 task 完成后 task 状态如何从 `running` 返回业务态。
- 统一 `bind/rebind/webhook/ingest``full_video_bvid` 的读写入口。
- 明确 `task_contexts``session_bindings``full_video_bvid.txt` 的职责。
验收标准:
- 控制台能正确筛选和显示运行中的任务。
- 手工绑定、session 重绑、webhook 注入后,新旧任务读取到相同 BV。
- 不再出现新任务 ingest 继承旧 BV 的情况。
### Phase 2: 运行稳定性加固
目标:
- 让 API 与 worker 并行运行时的 SQLite 行为可控。
- 降低锁冲突、脏状态和半成功写入风险。
任务:
- 为 SQLite 连接增加 `busy_timeout``WAL``foreign_keys=ON`
- 检查高频 repo 写入点,减少不必要的小事务。
- 梳理关键写路径是否需要合并成原子操作。
验收标准:
- API 和 worker 并行运行时,不再轻易触发数据库锁错误。
- 关键任务状态写入具备基本原子性,不出现“步骤更新了、任务没更新”一类半状态。
### Phase 3: 控制面装配与查询优化
目标:
- 去掉 API 请求路径上的重复初始化。
- 解决 `/tasks` 列表的全量扫描和 N+1 查询问题。
任务:
-`ensure_initialized()` 从“每次请求即装配”改为更稳定的应用级初始化方式。
- 收敛 provider/registry 生命周期,避免每次请求重复扫描 manifest 和实例化 provider。
- 优化任务列表接口,把可下推的过滤逻辑下推到 repository 或持久化层。
- 减少列表查询时对工作区文件的逐条读取。
验收标准:
- 常规 API 请求不再重复做全量装配。
- 大量任务下的列表页和筛选页响应明显改善。
### Phase 4: 状态机与文档对齐
目标:
- 让文档状态机、代码状态机、控制面展示口径一致。
任务:
- 决定是否保留 `ingested``completed``cancelled`
- 明确 flag 文件在系统中的角色。
- 如果数据库是任务状态唯一来源,则把 delivery flag 降级为产物或外部副作用标记。
- 更新状态机文档、控制面展示文案和开发约束。
验收标准:
- 文档中的状态集合与代码中的状态集合一致。
- UI 不再依赖不存在或含义不稳定的 task 状态。
### Phase 5: 回归测试与维护收尾
目标:
- 为核心编排逻辑补回归保护。
- 降低后续重构再次引入状态漂移的概率。
任务:
- 新增 `tests/`
- 优先覆盖:
- `task_engine`
- `task_policies`
- `task_actions`
- `retry_meta`
- `task_reset`
- 决定 classic 控制台的保留策略。
验收标准:
- 核心状态流转具备最小自动化回归覆盖。
- 控制台维护策略明确,不再长期双线漂移。
## 推荐执行顺序
1. Phase 1
2. Phase 2
3. Phase 3
4. Phase 4
5. Phase 5
## 本轮起步范围
本轮先从以下子项开始:
- Phase 1.1: task `running` 状态落地
- Phase 1.2: `full_video_bvid` 写路径统一
- Phase 2.1: SQLite 连接配置加固
## 过程记录
- 2026-04-06完成代码审查确认当前优先问题集中在 task 运行态缺失、`full_video_bvid` 多源不一致、SQLite 并发配置不足、重复初始化、列表查询 N+1、状态机文档与实现漂移、测试缺失。
- 2026-04-06将问题整理为本改造计划按阶段拆分并确定先做状态一致性与运行稳定性。

View File

@ -1,271 +1,271 @@
# State Machine
## Goal
定义 `biliup-next` 当前实现使用的任务状态机,并明确数据库状态与工作区 flag 的职责边界。
状态机目标:
- 让每个任务始终有明确状态
- 支持失败重试和人工介入
- 让 UI 和 API 可以直接消费状态
- 保证步骤顺序和依赖关系清晰
## State Model
任务状态分为两层:
- `task status`:任务整体状态
- `step status`:任务中每一步的执行状态
## Task Status
### Core Statuses
- `created`
- `running`
- `transcribed`
- `songs_detected`
- `split_done`
- `published`
- `commented`
- `collection_synced`
### Failure Statuses
- `failed_retryable`
- `failed_manual`
### Terminal Statuses
- `collection_synced`
- `failed_manual`
## Step Status
每个步骤都独立维护自己的状态。
- `pending`
- `running`
- `succeeded`
- `failed_retryable`
- `failed_manual`
- `skipped`
## Step Definitions
### ingest
负责:
- 接收输入视频
- 基础校验
- 创建任务记录
### transcribe
负责:
- 生成字幕
- 记录字幕产物
### song_detect
负责:
- 识别歌曲列表
- 生成 `songs.json``songs.txt`
### split
负责:
- 根据歌单切割视频
- 生成切片产物
### publish
负责:
- 上传纯享版视频
- 同 session 多个 task 时,只由 anchor task 真正执行上传
- 聚合同 session 的全部 `clip_video`
- 成功后把同一个 `bvid` 写回整组 task
### comment
负责:
- 发布评论
- 置顶评论
- split 评论在 session 级聚合为 `P1/P2/P3`
- full 评论在 session 级聚合为 `P1/P2/P3`
- 同一 session 的评论只由 anchor task 执行一次
### collection_a
负责:
- 将完整版视频加入合集 A
### collection_b
负责:
- 将纯享版视频加入合集 B
## State Transition Rules
### Task-Level
```text
created
-> running
-> transcribed
-> running
-> songs_detected
-> running
-> split_done
-> running
-> published
-> running
-> commented
-> running
-> collection_synced
```
说明:
- `running` 是任务级瞬时状态,表示当前已有某个 step 被 claim 并正在执行。
- 当该 step 成功结束后task 会回到对应业务状态,例如 `transcribed``split_done``published`
- 当前实现中未使用 `ingested``completed``cancelled` 作为 task 状态。
### Failure Transition
任何步骤失败后:
- 若允许自动重试:任务进入 `failed_retryable`
- 若必须人工介入:任务进入 `failed_manual`
重试成功后:
- 任务回到该步骤成功后的下一个合法状态
## Dependency Rules
- `transcribe` 必须依赖 `ingest`
- `song_detect` 必须依赖 `transcribe`
- `split` 必须依赖 `song_detect`
- `publish` 必须依赖 `split`
- `comment` 必须依赖 `publish`
- `collection_b` 必须依赖 `publish`
- `collection_a` 通常依赖外部完整版 BV可独立于 `publish`
## Session Semantics
当多个 task 属于同一个 `session_key` 时,系统会引入 session 级语义:
- `split` 仍然保持 task 级
- `publish` 升级为 session 级
- `comment` 升级为 session 级
当前 anchor 规则:
- 同一 session 内按 `segment_started_at` 升序排序
- 最早那个 task 作为 anchor
当前 session 级行为:
- `publish`
- 只有 anchor task 执行真实上传
- 其余 task 复用同一个纯享 `BV`
- `comment.split`
- 只有 anchor task 对纯享版视频发评论
- 评论内容按 `P1/P2/P3` 聚合
- `comment.full`
- 只有 anchor task 对完整版视频发评论
- 评论内容按 `P1/P2/P3` 聚合
## Special Case: Collection A
合集 A 的数据来源与主上传链路不同。
因此:
- `collection_a` 不应阻塞主任务完成
- `collection_a` 可作为独立步骤存在
- 任务整体完成不必强依赖 `collection_a` 成功
当前实现:
- `collection_synced` 表示当前任务已经完成既定收尾流程。
- `collection_a` / `collection_b` 仍作为独立 step 存在,但系统暂未额外引入 `completed` 状态。
## Retry Strategy
### Retryable Errors
适合自动重试:
- 网络错误
- 外部 API 临时失败
- 上传频控
- 外部命令短时异常
### Manual Errors
需要人工介入:
- 配置缺失
- 凭证失效
- 文件损坏
- provider 不可用
- 标题无法匹配完整版 BV
## Persistence Requirements
每次状态变更都必须落库:
- 任务状态
- 步骤状态
- 开始时间
- 结束时间
- 错误码
- 错误信息
- 重试次数
## Flags And Files
工作区中的 flag 文件仍然存在,但它们不是 task 主状态的权威来源。
当前职责划分:
- 数据库:
- task 状态
- step 状态
- 重试信息
- 结构化上下文
- 工作区文件与 flag
- 外部副作用是否已执行
- 产物是否已落地
- 评论/合集等交付标记
换句话说:
- “任务现在处于什么状态”以数据库为准。
- “某个外部动作是否已经做过”可以由工作区 flag 辅助表达。
## UI Expectations
UI 至少需要直接展示:
- 当前任务状态
- 当前正在运行的步骤
- 最近失败步骤
- 重试次数
- 是否需要人工介入
## Non-Goals
- 不追求一个任务多个步骤完全并发执行
- 不把工作区 flag 文件当作 task 主状态来源
# State Machine
## Goal
定义 `biliup-next` 当前实现使用的任务状态机,并明确数据库状态与工作区 flag 的职责边界。
状态机目标:
- 让每个任务始终有明确状态
- 支持失败重试和人工介入
- 让 UI 和 API 可以直接消费状态
- 保证步骤顺序和依赖关系清晰
## State Model
任务状态分为两层:
- `task status`:任务整体状态
- `step status`:任务中每一步的执行状态
## Task Status
### Core Statuses
- `created`
- `running`
- `transcribed`
- `songs_detected`
- `split_done`
- `published`
- `commented`
- `collection_synced`
### Failure Statuses
- `failed_retryable`
- `failed_manual`
### Terminal Statuses
- `collection_synced`
- `failed_manual`
## Step Status
每个步骤都独立维护自己的状态。
- `pending`
- `running`
- `succeeded`
- `failed_retryable`
- `failed_manual`
- `skipped`
## Step Definitions
### ingest
负责:
- 接收输入视频
- 基础校验
- 创建任务记录
### transcribe
负责:
- 生成字幕
- 记录字幕产物
### song_detect
负责:
- 识别歌曲列表
- 生成 `songs.json``songs.txt`
### split
负责:
- 根据歌单切割视频
- 生成切片产物
### publish
负责:
- 上传纯享版视频
- 同 session 多个 task 时,只由 anchor task 真正执行上传
- 聚合同 session 的全部 `clip_video`
- 成功后把同一个 `bvid` 写回整组 task
### comment
负责:
- 发布评论
- 置顶评论
- split 评论在 session 级聚合为 `P1/P2/P3`
- full 评论在 session 级聚合为 `P1/P2/P3`
- 同一 session 的评论只由 anchor task 执行一次
### collection_a
负责:
- 将完整版视频加入合集 A
### collection_b
负责:
- 将纯享版视频加入合集 B
## State Transition Rules
### Task-Level
```text
created
-> running
-> transcribed
-> running
-> songs_detected
-> running
-> split_done
-> running
-> published
-> running
-> commented
-> running
-> collection_synced
```
说明:
- `running` 是任务级瞬时状态,表示当前已有某个 step 被 claim 并正在执行。
- 当该 step 成功结束后task 会回到对应业务状态,例如 `transcribed``split_done``published`
- 当前实现中未使用 `ingested``completed``cancelled` 作为 task 状态。
### Failure Transition
任何步骤失败后:
- 若允许自动重试:任务进入 `failed_retryable`
- 若必须人工介入:任务进入 `failed_manual`
重试成功后:
- 任务回到该步骤成功后的下一个合法状态
## Dependency Rules
- `transcribe` 必须依赖 `ingest`
- `song_detect` 必须依赖 `transcribe`
- `split` 必须依赖 `song_detect`
- `publish` 必须依赖 `split`
- `comment` 必须依赖 `publish`
- `collection_b` 必须依赖 `publish`
- `collection_a` 通常依赖外部完整版 BV可独立于 `publish`
## Session Semantics
当多个 task 属于同一个 `session_key` 时,系统会引入 session 级语义:
- `split` 仍然保持 task 级
- `publish` 升级为 session 级
- `comment` 升级为 session 级
当前 anchor 规则:
- 同一 session 内按 `segment_started_at` 升序排序
- 最早那个 task 作为 anchor
当前 session 级行为:
- `publish`
- 只有 anchor task 执行真实上传
- 其余 task 复用同一个纯享 `BV`
- `comment.split`
- 只有 anchor task 对纯享版视频发评论
- 评论内容按 `P1/P2/P3` 聚合
- `comment.full`
- 只有 anchor task 对完整版视频发评论
- 评论内容按 `P1/P2/P3` 聚合
## Special Case: Collection A
合集 A 的数据来源与主上传链路不同。
因此:
- `collection_a` 不应阻塞主任务完成
- `collection_a` 可作为独立步骤存在
- 任务整体完成不必强依赖 `collection_a` 成功
当前实现:
- `collection_synced` 表示当前任务已经完成既定收尾流程。
- `collection_a` / `collection_b` 仍作为独立 step 存在,但系统暂未额外引入 `completed` 状态。
## Retry Strategy
### Retryable Errors
适合自动重试:
- 网络错误
- 外部 API 临时失败
- 上传频控
- 外部命令短时异常
### Manual Errors
需要人工介入:
- 配置缺失
- 凭证失效
- 文件损坏
- provider 不可用
- 标题无法匹配完整版 BV
## Persistence Requirements
每次状态变更都必须落库:
- 任务状态
- 步骤状态
- 开始时间
- 结束时间
- 错误码
- 错误信息
- 重试次数
## Flags And Files
工作区中的 flag 文件仍然存在,但它们不是 task 主状态的权威来源。
当前职责划分:
- 数据库:
- task 状态
- step 状态
- 重试信息
- 结构化上下文
- 工作区文件与 flag
- 外部副作用是否已执行
- 产物是否已落地
- 评论/合集等交付标记
换句话说:
- “任务现在处于什么状态”以数据库为准。
- “某个外部动作是否已经做过”可以由工作区 flag 辅助表达。
## UI Expectations
UI 至少需要直接展示:
- 当前任务状态
- 当前正在运行的步骤
- 最近失败步骤
- 重试次数
- 是否需要人工介入
## Non-Goals
- 不追求一个任务多个步骤完全并发执行
- 不把工作区 flag 文件当作 task 主状态来源

View File

@ -1,196 +1,196 @@
# biliup-next Todo - 2026-04-06
## 今日待办
### P0
- 修正任务级 `running` 状态缺失问题。
- 当前 step 会进入 `running`,但 task 不会进入 `running`,导致控制台“处理中”筛选、优先级判断和注意力状态失真。
- 相关位置:
- `src/biliup_next/app/task_engine.py`
- `src/biliup_next/app/api_server.py`
- `src/biliup_next/modules/*/service.py`
- 收敛 `full_video_bvid` 的单一事实源。
- 当前 `task_contexts``session_bindings``session/full_video_bvid.txt` 三处状态可能不一致。
- `rebind_session_full_video_action()` 没有同步更新 `session_bindings`,后续新任务 ingest 仍可能继承旧 BV。
- 相关位置:
- `src/biliup_next/app/task_actions.py`
- `src/biliup_next/modules/ingest/service.py`
- `src/biliup_next/infra/task_repository.py`
- 补强 SQLite 并发配置。
- 当前 API 与 worker 可并行运行,但数据库连接仍是最基础配置,缺少 `busy_timeout``WAL``foreign_keys=ON` 等保护。
- 后续任务量或并发操作增加时,容易出现 `database is locked` 一类问题。
- 相关位置:
- `src/biliup_next/infra/db.py`
### P1
- 消除 API 路径上的重复初始化。
- `ensure_initialized()` 目前会重复执行配置加载、DB 初始化、插件扫描和 provider 实例化。
- API 每次请求都可能再次触发整套装配,后续会拖慢控制面并增加维护成本。
- 相关位置:
- `src/biliup_next/app/bootstrap.py`
- `src/biliup_next/app/api_server.py`
- 优化 `/tasks` 的全量扫描和 N+1 查询。
- 当前 `attention/delivery` 过滤会先拉最多 5000 条任务,再逐条补 task payload、step、context 和文件系统状态。
- 任务规模上来后会明显拖慢列表页和筛选体验。
- 相关位置:
- `src/biliup_next/app/api_server.py`
- `src/biliup_next/infra/task_repository.py`
- 收敛文档状态机与代码实现。
- 文档中存在 `ingested``completed``cancelled`,并声明不再依赖 flag 文件作为权威状态。
- 实际实现中这些状态并未完整落地,评论/合集完成态仍依赖多个 flag 文件。
- 需要统一“文档模型”和“代码真实状态机”,避免后续继续漂移。
- 相关位置:
- `docs/state-machine.md`
- `src/biliup_next/app/api_server.py`
- `src/biliup_next/modules/comment/providers/bilibili_top_comment.py`
- `src/biliup_next/modules/collection/providers/bilibili_collection.py`
### P2
- 为状态机、重试和手工干预流程补测试。
- 当前仓库没有看到 `tests/` 或自动化回归覆盖。
- 优先覆盖:
- `task_engine`
- `task_policies`
- `task_actions`
- `retry_meta`
- `task_reset`
- 明确两套控制台的维护策略。
- 当前 React 控制台和 classic 控制台并存。
- 需要决定 classic 是长期保留、冻结维护,还是逐步退役。
## 备注
- 以上问题来自 2026-04-06 对 `biliup-next` 当前重构实现的代码审查。
- 优先顺序按“状态一致性 / 数据一致性 / 运行稳定性 / 控制面性能 / 可维护性”排列。
## 过程记录
- 2026-04-06完成首轮代码审查确认当前优先问题。
- 2026-04-06基于问题清单拆出分阶段改造计划`docs/refactor-plan-2026-04-06.md`
- 2026-04-06确定首批执行范围为 task `running` 状态落地、`full_video_bvid` 写路径统一、SQLite 连接加固。
- 2026-04-06已完成首轮代码改造。
- task 在 step 被 claim 后会进入 `running`
- `bind/rebind/webhook` 已统一复用 `full_video_bvid` 持久化路径。
- SQLite 连接已增加 `foreign_keys``busy_timeout``WAL``synchronous=NORMAL`
- 已执行 `python -m compileall biliup-next/src/biliup_next` 验证语法通过。
- 2026-04-06已完成第二轮控制面改造。
- `ensure_initialized()` 已改为进程内复用,避免 API 请求重复装配全套应用状态。
- `PUT /settings` 后会主动失效并重建缓存状态,避免新旧配置混用。
- `/tasks` 列表已改为批量预取 task context 和 steps减少列表页 N+1 查询。
- 已再次执行 `python -m compileall biliup-next/src/biliup_next` 验证语法通过。
- 2026-04-06已完成状态机文档对齐。
- `state-machine.md``architecture.md` 已改成当前代码真实状态集合:`created/running/transcribed/songs_detected/split_done/published/commented/collection_synced/failed_*`
- 已明确 `ingested/completed/cancelled` 当前未落地,不再作为现阶段实现口径。
- 已明确工作区 flag 仅表示交付副作用和产物标记,不作为 task 主状态事实源。
- 2026-04-06已补最小回归测试集。
- 新增 `tests/test_task_engine.py`
- 新增 `tests/test_retry_meta.py`
- 新增 `tests/test_task_actions.py`
- 已执行 `PYTHONPATH=biliup-next/src python -m unittest discover -s biliup-next/tests -v`
- 当前 7 个测试全部通过。
- 2026-04-06已继续收口 `task_actions` 的写路径。
- `rebind_session_full_video_action()` 不再重复 upsert session binding。
- `merge_session_action()` 在继承 `full_video_bvid` 时已复用统一持久化路径。
- 已补对应测试,当前测试数为 8全部通过。
- 2026-04-06已补第二层状态流转测试。
- 新增 `tests/test_task_policies.py`
- 新增 `tests/test_task_runner.py`
- 已覆盖 disabled step fallback、publish 重试调度、reset 后回退状态、step claim 后 task 进入 `running`
- 已执行 `PYTHONPATH=biliup-next/src python -m unittest discover -s biliup-next/tests -v`
- 当前 12 个测试全部通过。
- 2026-04-06已完成一轮 API 代码清理。
- `api_server.py` 新增批量 task payload 组装 helper。
- `/tasks``/sessions/:session_key` 已复用同一套 task payload 预取与组装逻辑。
- 已重新执行测试,当前 12 个测试全部通过。
- 2026-04-06已整理专业化路线图。
- 新增 `docs/professionalization-roadmap-2026-04-06.md`
- 按平台边界、领域模型、接口契约、测试体系、运维成熟度五个维度拆解后续改进方向。
- 已明确下一批优先项为 adapter 边界、session/delivery 领域服务收敛、serializer 层、SQLite/API 测试与 OpenAPI 对齐。
- 2026-04-06已开始落最小 adapter 边界。
- 新增 `infra/adapters/codex_cli.py`
- 新增 `infra/adapters/biliup_cli.py`
- 新增 `infra/adapters/bilibili_api.py`
- `codex``biliup_cli``bilibili_top_comment``bilibili_collection` provider 已改为依赖 adapter
- 已执行 unittest 与 `python -m compileall biliup-next/src/biliup_next`,当前验证通过。
- 2026-04-06已开始落 serializer 层。
- 新增 `app/serializers.py`
- task list / task detail / session detail 的 payload 组装已从 `api_server.py` 抽到 `ControlPlaneSerializer`
- `api_server.py` 进一步收敛为路由、鉴权和响应控制
- 已执行 unittest 与 `python -m compileall biliup-next/src/biliup_next`,当前验证通过。
- 2026-04-06已继续收口 serializer 层。
- task timeline 的组装逻辑已从 `api_server.py` 抽到 `ControlPlaneSerializer.timeline_payload()`
- `api_server.py` 中 task 详情相关展示逻辑继续变薄
- 已重新执行 unittest 与 `python -m compileall biliup-next/src/biliup_next`,当前验证通过。
- 2026-04-06已补 serializer 层测试。
- 新增 `tests/test_serializers.py`
- 已覆盖 task payload、session payload、timeline payload 的控制面展示契约
- 已执行 `PYTHONPATH=biliup-next/src python -m unittest discover -s biliup-next/tests -v`
- 当前 15 个测试全部通过。
- 2026-04-06已补 repository 的 SQLite 集成测试。
- 新增 `tests/test_task_repository_sqlite.py`
- 已覆盖 `query_tasks`、批量 context/steps 查询、`session_bindings` upsert 与 fallback 读取
- 已执行 `PYTHONPATH=biliup-next/src python -m unittest discover -s biliup-next/tests -v`
- 当前 18 个测试全部通过。
- 2026-04-06已补 API 行为测试。
- 扩展 `tests/test_api_server.py`
- 已覆盖 `GET /tasks``GET /tasks/:id/timeline``GET /sessions/:session_key``PUT /settings`
- 已覆盖 control token 鉴权分支
- 已执行 `PYTHONPATH=biliup-next/src python -m unittest discover -s biliup-next/tests -v`
- 2026-04-06已继续补执行面 API 行为测试。
- `tests/test_api_server.py` 已新增 `POST /tasks``POST /tasks/:id/actions/run``POST /tasks/:id/actions/retry-step``POST /tasks/:id/actions/reset-to-step`
- 已覆盖写操作成功分支与 `missing step_name` 参数校验
- 已执行 `PYTHONPATH=biliup-next/src python -m unittest discover -s biliup-next/tests -v`
- 当前 28 个测试全部通过。
- 2026-04-06已补人工干预相关 API 行为测试。
- `tests/test_api_server.py` 已新增 `POST /tasks/:id/bind-full-video``POST /sessions/:session_key/rebind``POST /sessions/:session_key/merge``POST /webhooks/full-video-uploaded`
- 已覆盖成功分支、参数校验,以及 `TASK_NOT_FOUND/SESSION_NOT_FOUND` 的状态码映射
- 已执行 `PYTHONPATH=biliup-next/src python -m unittest discover -s biliup-next/tests -v`
- 当前 37 个测试全部通过。
- 2026-04-06已补运行面 API 行为测试。
- `tests/test_api_server.py` 已新增 `POST /worker/run-once``POST /scheduler/run-once``POST /runtime/services/:name/:action``POST /stage/import`
- 已覆盖 action record 落库、副作用返回值、`invalid action``missing source_path` 错误分支
- 已执行 `PYTHONPATH=biliup-next/src python -m unittest discover -s biliup-next/tests -v`
- 当前 43 个测试全部通过。
- 2026-04-06已补剩余控制面 GET 与上传接口测试。
- `tests/test_api_server.py` 已新增 `GET /history``GET /modules``GET /scheduler/preview``GET /settings/schema``POST /stage/upload`
- `stage/upload` 成功分支已通过 patch `cgi.FieldStorage` 固定最小 handler 契约,避免 multipart 解析细节导致测试脆弱
- 已执行 `PYTHONPATH=biliup-next/src python -m unittest discover -s biliup-next/tests -v`
- 当前 49 个测试全部通过。
- 2026-04-06已开始收口 session / delivery 领域服务。
- 新增 `app/session_delivery_service.py`,承接 `bind/rebind/merge/webhook` 的核心规则与持久化路径
- `app/task_actions.py` 已改为薄封装,仅保留 `ensure_initialized()`、审计记录与 service 调用
- 新增 `tests/test_session_delivery_service.py`
- 已执行 `PYTHONPATH=biliup-next/src python -m unittest discover -s biliup-next/tests -v`
- 当前 51 个测试全部通过。
- 2026-04-06已继续收口 task control 领域服务。
- 新增 `app/task_control_service.py`,承接 `run/retry/reset` 编排
- `app/task_actions.py` 已进一步变薄,`run_task_action/retry_step_action/reset_to_step_action` 改为纯 service 封装 + 审计
- 新增 `tests/test_task_control_service.py`
- 已执行 `PYTHONPATH=biliup-next/src python -m unittest discover -s biliup-next/tests -v`
- 当前 54 个测试全部通过。
- 2026-04-06已将 POST 路径分发从 API handler 中下沉。
- 新增 `app/control_plane_post_dispatcher.py`,统一承接 POST 路径的用例分发、状态码映射和运行面 action record
- `app/api_server.py``do_POST()` 已收敛为请求解析、dispatcher 调用和响应写出
- 已执行 `PYTHONPATH=biliup-next/src python -m unittest discover -s biliup-next/tests -v`
- 当前 54 个测试全部通过。
- 2026-04-06已补 dispatcher 直测。
- 新增 `tests/test_control_plane_get_dispatcher.py`
- 新增 `tests/test_control_plane_post_dispatcher.py`
- 已覆盖 dispatcher 层的状态码映射、过滤逻辑、运行面 action record 与创建任务冲突映射
- 已执行 `PYTHONPATH=biliup-next/src python -m unittest discover -s biliup-next/tests -v`
- 当前 62 个测试全部通过。
- 2026-04-06已开始做可迁移交付清理。
- `config/settings.json``config/settings.staged.json` 已替换为 standalone 默认模板,不再携带本机绝对路径和真实密钥
- `runtime/cookies.json``runtime/upload_config.json` 已替换为可分发模板
- 新增 `docs/cold-start-checklist.md`
- `README.md` 已补充冷启动入口说明
- 已执行 `PYTHONPATH=biliup-next/src python -m unittest discover -s biliup-next/tests -v`
- 当前 63 个测试全部通过。
# biliup-next Todo - 2026-04-06
## 今日待办
### P0
- 修正任务级 `running` 状态缺失问题。
- 当前 step 会进入 `running`,但 task 不会进入 `running`,导致控制台“处理中”筛选、优先级判断和注意力状态失真。
- 相关位置:
- `src/biliup_next/app/task_engine.py`
- `src/biliup_next/app/api_server.py`
- `src/biliup_next/modules/*/service.py`
- 收敛 `full_video_bvid` 的单一事实源。
- 当前 `task_contexts``session_bindings``session/full_video_bvid.txt` 三处状态可能不一致。
- `rebind_session_full_video_action()` 没有同步更新 `session_bindings`,后续新任务 ingest 仍可能继承旧 BV。
- 相关位置:
- `src/biliup_next/app/task_actions.py`
- `src/biliup_next/modules/ingest/service.py`
- `src/biliup_next/infra/task_repository.py`
- 补强 SQLite 并发配置。
- 当前 API 与 worker 可并行运行,但数据库连接仍是最基础配置,缺少 `busy_timeout``WAL``foreign_keys=ON` 等保护。
- 后续任务量或并发操作增加时,容易出现 `database is locked` 一类问题。
- 相关位置:
- `src/biliup_next/infra/db.py`
### P1
- 消除 API 路径上的重复初始化。
- `ensure_initialized()` 目前会重复执行配置加载、DB 初始化、插件扫描和 provider 实例化。
- API 每次请求都可能再次触发整套装配,后续会拖慢控制面并增加维护成本。
- 相关位置:
- `src/biliup_next/app/bootstrap.py`
- `src/biliup_next/app/api_server.py`
- 优化 `/tasks` 的全量扫描和 N+1 查询。
- 当前 `attention/delivery` 过滤会先拉最多 5000 条任务,再逐条补 task payload、step、context 和文件系统状态。
- 任务规模上来后会明显拖慢列表页和筛选体验。
- 相关位置:
- `src/biliup_next/app/api_server.py`
- `src/biliup_next/infra/task_repository.py`
- 收敛文档状态机与代码实现。
- 文档中存在 `ingested``completed``cancelled`,并声明不再依赖 flag 文件作为权威状态。
- 实际实现中这些状态并未完整落地,评论/合集完成态仍依赖多个 flag 文件。
- 需要统一“文档模型”和“代码真实状态机”,避免后续继续漂移。
- 相关位置:
- `docs/state-machine.md`
- `src/biliup_next/app/api_server.py`
- `src/biliup_next/modules/comment/providers/bilibili_top_comment.py`
- `src/biliup_next/modules/collection/providers/bilibili_collection.py`
### P2
- 为状态机、重试和手工干预流程补测试。
- 当前仓库没有看到 `tests/` 或自动化回归覆盖。
- 优先覆盖:
- `task_engine`
- `task_policies`
- `task_actions`
- `retry_meta`
- `task_reset`
- 明确两套控制台的维护策略。
- 当前 React 控制台和 classic 控制台并存。
- 需要决定 classic 是长期保留、冻结维护,还是逐步退役。
## 备注
- 以上问题来自 2026-04-06 对 `biliup-next` 当前重构实现的代码审查。
- 优先顺序按“状态一致性 / 数据一致性 / 运行稳定性 / 控制面性能 / 可维护性”排列。
## 过程记录
- 2026-04-06完成首轮代码审查确认当前优先问题。
- 2026-04-06基于问题清单拆出分阶段改造计划`docs/refactor-plan-2026-04-06.md`
- 2026-04-06确定首批执行范围为 task `running` 状态落地、`full_video_bvid` 写路径统一、SQLite 连接加固。
- 2026-04-06已完成首轮代码改造。
- task 在 step 被 claim 后会进入 `running`
- `bind/rebind/webhook` 已统一复用 `full_video_bvid` 持久化路径。
- SQLite 连接已增加 `foreign_keys``busy_timeout``WAL``synchronous=NORMAL`
- 已执行 `python -m compileall biliup-next/src/biliup_next` 验证语法通过。
- 2026-04-06已完成第二轮控制面改造。
- `ensure_initialized()` 已改为进程内复用,避免 API 请求重复装配全套应用状态。
- `PUT /settings` 后会主动失效并重建缓存状态,避免新旧配置混用。
- `/tasks` 列表已改为批量预取 task context 和 steps减少列表页 N+1 查询。
- 已再次执行 `python -m compileall biliup-next/src/biliup_next` 验证语法通过。
- 2026-04-06已完成状态机文档对齐。
- `state-machine.md``architecture.md` 已改成当前代码真实状态集合:`created/running/transcribed/songs_detected/split_done/published/commented/collection_synced/failed_*`
- 已明确 `ingested/completed/cancelled` 当前未落地,不再作为现阶段实现口径。
- 已明确工作区 flag 仅表示交付副作用和产物标记,不作为 task 主状态事实源。
- 2026-04-06已补最小回归测试集。
- 新增 `tests/test_task_engine.py`
- 新增 `tests/test_retry_meta.py`
- 新增 `tests/test_task_actions.py`
- 已执行 `PYTHONPATH=biliup-next/src python -m unittest discover -s biliup-next/tests -v`
- 当前 7 个测试全部通过。
- 2026-04-06已继续收口 `task_actions` 的写路径。
- `rebind_session_full_video_action()` 不再重复 upsert session binding。
- `merge_session_action()` 在继承 `full_video_bvid` 时已复用统一持久化路径。
- 已补对应测试,当前测试数为 8全部通过。
- 2026-04-06已补第二层状态流转测试。
- 新增 `tests/test_task_policies.py`
- 新增 `tests/test_task_runner.py`
- 已覆盖 disabled step fallback、publish 重试调度、reset 后回退状态、step claim 后 task 进入 `running`
- 已执行 `PYTHONPATH=biliup-next/src python -m unittest discover -s biliup-next/tests -v`
- 当前 12 个测试全部通过。
- 2026-04-06已完成一轮 API 代码清理。
- `api_server.py` 新增批量 task payload 组装 helper。
- `/tasks``/sessions/:session_key` 已复用同一套 task payload 预取与组装逻辑。
- 已重新执行测试,当前 12 个测试全部通过。
- 2026-04-06已整理专业化路线图。
- 新增 `docs/professionalization-roadmap-2026-04-06.md`
- 按平台边界、领域模型、接口契约、测试体系、运维成熟度五个维度拆解后续改进方向。
- 已明确下一批优先项为 adapter 边界、session/delivery 领域服务收敛、serializer 层、SQLite/API 测试与 OpenAPI 对齐。
- 2026-04-06已开始落最小 adapter 边界。
- 新增 `infra/adapters/codex_cli.py`
- 新增 `infra/adapters/biliup_cli.py`
- 新增 `infra/adapters/bilibili_api.py`
- `codex``biliup_cli``bilibili_top_comment``bilibili_collection` provider 已改为依赖 adapter
- 已执行 unittest 与 `python -m compileall biliup-next/src/biliup_next`,当前验证通过。
- 2026-04-06已开始落 serializer 层。
- 新增 `app/serializers.py`
- task list / task detail / session detail 的 payload 组装已从 `api_server.py` 抽到 `ControlPlaneSerializer`
- `api_server.py` 进一步收敛为路由、鉴权和响应控制
- 已执行 unittest 与 `python -m compileall biliup-next/src/biliup_next`,当前验证通过。
- 2026-04-06已继续收口 serializer 层。
- task timeline 的组装逻辑已从 `api_server.py` 抽到 `ControlPlaneSerializer.timeline_payload()`
- `api_server.py` 中 task 详情相关展示逻辑继续变薄
- 已重新执行 unittest 与 `python -m compileall biliup-next/src/biliup_next`,当前验证通过。
- 2026-04-06已补 serializer 层测试。
- 新增 `tests/test_serializers.py`
- 已覆盖 task payload、session payload、timeline payload 的控制面展示契约
- 已执行 `PYTHONPATH=biliup-next/src python -m unittest discover -s biliup-next/tests -v`
- 当前 15 个测试全部通过。
- 2026-04-06已补 repository 的 SQLite 集成测试。
- 新增 `tests/test_task_repository_sqlite.py`
- 已覆盖 `query_tasks`、批量 context/steps 查询、`session_bindings` upsert 与 fallback 读取
- 已执行 `PYTHONPATH=biliup-next/src python -m unittest discover -s biliup-next/tests -v`
- 当前 18 个测试全部通过。
- 2026-04-06已补 API 行为测试。
- 扩展 `tests/test_api_server.py`
- 已覆盖 `GET /tasks``GET /tasks/:id/timeline``GET /sessions/:session_key``PUT /settings`
- 已覆盖 control token 鉴权分支
- 已执行 `PYTHONPATH=biliup-next/src python -m unittest discover -s biliup-next/tests -v`
- 2026-04-06已继续补执行面 API 行为测试。
- `tests/test_api_server.py` 已新增 `POST /tasks``POST /tasks/:id/actions/run``POST /tasks/:id/actions/retry-step``POST /tasks/:id/actions/reset-to-step`
- 已覆盖写操作成功分支与 `missing step_name` 参数校验
- 已执行 `PYTHONPATH=biliup-next/src python -m unittest discover -s biliup-next/tests -v`
- 当前 28 个测试全部通过。
- 2026-04-06已补人工干预相关 API 行为测试。
- `tests/test_api_server.py` 已新增 `POST /tasks/:id/bind-full-video``POST /sessions/:session_key/rebind``POST /sessions/:session_key/merge``POST /webhooks/full-video-uploaded`
- 已覆盖成功分支、参数校验,以及 `TASK_NOT_FOUND/SESSION_NOT_FOUND` 的状态码映射
- 已执行 `PYTHONPATH=biliup-next/src python -m unittest discover -s biliup-next/tests -v`
- 当前 37 个测试全部通过。
- 2026-04-06已补运行面 API 行为测试。
- `tests/test_api_server.py` 已新增 `POST /worker/run-once``POST /scheduler/run-once``POST /runtime/services/:name/:action``POST /stage/import`
- 已覆盖 action record 落库、副作用返回值、`invalid action``missing source_path` 错误分支
- 已执行 `PYTHONPATH=biliup-next/src python -m unittest discover -s biliup-next/tests -v`
- 当前 43 个测试全部通过。
- 2026-04-06已补剩余控制面 GET 与上传接口测试。
- `tests/test_api_server.py` 已新增 `GET /history``GET /modules``GET /scheduler/preview``GET /settings/schema``POST /stage/upload`
- `stage/upload` 成功分支已通过 patch `cgi.FieldStorage` 固定最小 handler 契约,避免 multipart 解析细节导致测试脆弱
- 已执行 `PYTHONPATH=biliup-next/src python -m unittest discover -s biliup-next/tests -v`
- 当前 49 个测试全部通过。
- 2026-04-06已开始收口 session / delivery 领域服务。
- 新增 `app/session_delivery_service.py`,承接 `bind/rebind/merge/webhook` 的核心规则与持久化路径
- `app/task_actions.py` 已改为薄封装,仅保留 `ensure_initialized()`、审计记录与 service 调用
- 新增 `tests/test_session_delivery_service.py`
- 已执行 `PYTHONPATH=biliup-next/src python -m unittest discover -s biliup-next/tests -v`
- 当前 51 个测试全部通过。
- 2026-04-06已继续收口 task control 领域服务。
- 新增 `app/task_control_service.py`,承接 `run/retry/reset` 编排
- `app/task_actions.py` 已进一步变薄,`run_task_action/retry_step_action/reset_to_step_action` 改为纯 service 封装 + 审计
- 新增 `tests/test_task_control_service.py`
- 已执行 `PYTHONPATH=biliup-next/src python -m unittest discover -s biliup-next/tests -v`
- 当前 54 个测试全部通过。
- 2026-04-06已将 POST 路径分发从 API handler 中下沉。
- 新增 `app/control_plane_post_dispatcher.py`,统一承接 POST 路径的用例分发、状态码映射和运行面 action record
- `app/api_server.py``do_POST()` 已收敛为请求解析、dispatcher 调用和响应写出
- 已执行 `PYTHONPATH=biliup-next/src python -m unittest discover -s biliup-next/tests -v`
- 当前 54 个测试全部通过。
- 2026-04-06已补 dispatcher 直测。
- 新增 `tests/test_control_plane_get_dispatcher.py`
- 新增 `tests/test_control_plane_post_dispatcher.py`
- 已覆盖 dispatcher 层的状态码映射、过滤逻辑、运行面 action record 与创建任务冲突映射
- 已执行 `PYTHONPATH=biliup-next/src python -m unittest discover -s biliup-next/tests -v`
- 当前 62 个测试全部通过。
- 2026-04-06已开始做可迁移交付清理。
- `config/settings.json``config/settings.staged.json` 已替换为 standalone 默认模板,不再携带本机绝对路径和真实密钥
- `runtime/cookies.json``runtime/upload_config.json` 已替换为可分发模板
- 新增 `docs/cold-start-checklist.md`
- `README.md` 已补充冷启动入口说明
- 已执行 `PYTHONPATH=biliup-next/src python -m unittest discover -s biliup-next/tests -v`
- 当前 63 个测试全部通过。

View File

@ -1,54 +1,54 @@
# Vision
## Goal
将当前基于目录监听和脚本拼接的流水线,重构为一个模块化、可扩展、可观测、可运维的单体系统。
系统负责:
- 接收本地视频任务
- 执行转录、识歌、切歌、上传、评论、合集归档
- 记录任务状态、产物、错误和外部结果
- 提供统一配置和管理入口
系统不负责:
- 直播录制
- 完整版视频的外部发布流程
- 多账号复杂运营后台
- 分布式调度
## Users
- 运维者:部署、启动、排查、重试任务
- 内容生产者:投放视频、观察任务状态
- 开发者:新增模块、替换外部依赖、扩展功能
## Problems In Current Project
- 状态分散在目录名、flag 文件、日志中,缺少单一事实来源
- 业务逻辑和运维逻辑耦合严重
- 配置项散落在多个脚本和常量中
- 同类逻辑重复实现,例如 B 站列表解析、合集处理、任务扫描
- 可观测性不足,失败后需要人工翻日志定位
- 扩展新能力时只能继续加脚本,结构会越来越乱
## Target Characteristics
- 模块化单体,而不是脚本集合
- 显式任务状态机
- 统一配置系统
- 外部依赖适配器化
- 结构化任务存储
- 插件式扩展点
- Web 管理台
- 文档优先
## Milestones
1. 定义架构、领域模型、模块接口和 API。
2. 建立新系统骨架,不影响旧系统运行。
3. 落地统一配置、任务状态存储和最小管理 API。
4. 按模块迁移旧能力:转录、识歌、切歌、上传、评论、合集。
5. 接入 Web 管理台。
6. 逐步切换生产流量,最终替换旧脚本体系。
# Vision
## Goal
将当前基于目录监听和脚本拼接的流水线,重构为一个模块化、可扩展、可观测、可运维的单体系统。
系统负责:
- 接收本地视频任务
- 执行转录、识歌、切歌、上传、评论、合集归档
- 记录任务状态、产物、错误和外部结果
- 提供统一配置和管理入口
系统不负责:
- 直播录制
- 完整版视频的外部发布流程
- 多账号复杂运营后台
- 分布式调度
## Users
- 运维者:部署、启动、排查、重试任务
- 内容生产者:投放视频、观察任务状态
- 开发者:新增模块、替换外部依赖、扩展功能
## Problems In Current Project
- 状态分散在目录名、flag 文件、日志中,缺少单一事实来源
- 业务逻辑和运维逻辑耦合严重
- 配置项散落在多个脚本和常量中
- 同类逻辑重复实现,例如 B 站列表解析、合集处理、任务扫描
- 可观测性不足,失败后需要人工翻日志定位
- 扩展新能力时只能继续加脚本,结构会越来越乱
## Target Characteristics
- 模块化单体,而不是脚本集合
- 显式任务状态机
- 统一配置系统
- 外部依赖适配器化
- 结构化任务存储
- 插件式扩展点
- Web 管理台
- 文档优先
## Milestones
1. 定义架构、领域模型、模块接口和 API。
2. 建立新系统骨架,不影响旧系统运行。
3. 落地统一配置、任务状态存储和最小管理 API。
4. 按模块迁移旧能力:转录、识歌、切歌、上传、评论、合集。
5. 接入 Web 管理台。
6. 逐步切换生产流量,最终替换旧脚本体系。