# Bilibili Transcript

> 把哔哩哔哩直播回放（单 P 视频）转成时间线回顾（Recap）。输入 BV 号或视频 URL。

- Skill: `cnife/bilibili-transcript` (Agent Skill, multi-file: 8 files)
- Install (CLI): `npx skillmds@latest add cnife/bilibili-transcript`
- Raw SKILL.md: https://api.skillmd.com/api/skills/cnife/bilibili-transcript/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: cnife (https://skillmd.com/u/cnife)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/cnife/bilibili-transcript

---


# Bilibili Transcript

把哔哩哔哩直播回放转成按时间线组织、按主题分组的 Recap Markdown。

领域语言见 `CONTEXT.md`；形态决策见 `docs/adr/`。

## 前置

1. **Linux** 一等支持；仓库根即 skill 根（本文件与代码同仓）
2. 已 clone 本仓库，并按所选后端安装依赖（见 README）
3. 宿主 agent 能在本仓库根目录执行命令、读写文件，并用自身 LLM 写 Recap
4. 公开可下载的单 P 视频（无 cookie；大会员 / 地区限制 / 非公开内容不保证）

## 产物链

Video → Audio → Transcript → Recap

- **prepare 脚本**（确定性）：下载音频 + ASR → Transcript（`transcript.json` + `meta.json`）
- **agent LLM**（推理）：读 Transcript 写 Recap

Transcript 是缓存层：同一 BV 已生成则跳过 ASR。重跑 Recap 时步骤 2 直接**缓存命中**，不重下载、不重转录。

## 步骤

### 0. 解析 Backend（首次必问）

后端三选一，**禁止静默替用户决定、禁止自动降级**：

| backend | 含义 | 依赖 extra | 费用 |
|---------|------|------------|------|
| `cpu` | 本地 SenseVoice，CPU | `cpu` | 免费 |
| `rocm` | 本地 SenseVoice，ROCm GPU | `rocm` | 免费 |
| `aliyun` | 云端 Paraformer-v2 | `aliyun` + `.env` 凭证 | 按量 |

**解析顺序**：

1. 若项目根已有 `.bilibili-transcript.json` 且含合法 `backend` → 采用之，向用户确认本次沿用（一句话即可）
2. 否则在仓库根执行：

```bash
uv run bili-prepare --probe
```

根据 JSON（`suggested`、`rocm_available`、`aliyun_ready` 等）给出**建议**，**询问用户选 cpu / rocm / aliyun**。
3. 用户确认后写入项目根（该文件已 gitignore）：

```json
{
  "backend": "cpu"
}
```

可用 shell 写入，例如：

```bash
printf '%s\n' '{"backend":"cpu"}' > .bilibili-transcript.json
```

4. 后端不可用（如选 `rocm` 但 GPU 不可用、选 `aliyun` 缺凭证）→ **硬失败**；向用户解释错误，征得同意后改配置/参数再跑，**不要**擅自换后端重试。

### 1. 跑 prepare（下载 + ASR）

在项目根目录**同步**执行（不要后台）：

```bash
uv run bili-prepare <BV号或URL> --backend <cpu|rocm|aliyun> [--force]
```

- 已写入配置时可省略 `--backend`；**推荐显式传入**以便日志与用户预期一致
- 时长参考（约）：16 分钟音频 rocm ~25s；同长 cpu 约 1 分钟量级；2h 音频 rocm 约 1–3 分钟、cpu 约 5 分钟、aliyun 约 5–10 分钟 → 长音频把命令超时放宽到 10–15 分钟
- 产物在 `.cache/<BV>/`：`transcript.json`（segments `[{start, end, text}]`，秒）、`meta.json`（元信息 + ASR 统计）
- 失败即退出（exit ≠ 0，ASR 零段也视为失败）；`--force` 重下载并重跑 ASR

**完成标准**：exit 0，`transcript.json` 非空（≥1 段），`meta.json` 可读且含 `backend`、`duration_s`、`title`。

### 2. 读 Transcript 写 Recap（单次 LLM 调用）

读 `.cache/<BV>/transcript.json` 的全部 segments（整段喂入，不做 map-reduce）与 `meta.json`（title、uploader、duration_s）。

**超长分支**：转录文本超出上下文窗口时，按时间顺序切块，每块按同一契约归纳，再按时间合并；任何块不得整块丢弃。

**Recap Markdown 契约**：

- 标题：`# {视频标题}`
- 主题段：`## {主题} (start-end)`，时间戳 `MM:SS`，时间戳只出现在段级标题，条目内不加
- 段内正文：用简洁的一段话总结该主题内容（2-4 行，一句起）
- 主题从内容归纳，不机械切片；段落按时间线排序，同一主题聚在一段
- 段数约 1 段/2-3 分钟（2h 视频 15-30 段）

示例：

```markdown
# 老木匠直播20260808（弹幕版）

## 开场闲聊 (00:00-05:00)
开场打招呼说早上变冷了，和弹幕聊了会儿天气，气氛轻松。

## 木工话题 (05:00-30:00)
开始讲今天的木工活：准备做一张桌子，先交代木料选择和尺寸规划。
```

**完成标准**（全部可检查）：

- **覆盖到结尾**：最后一段的区间终点 ≥ `duration_s - 60`，尾段不得遗漏
- 每段带 `MM:SS-MM:SS` 区间，与段内内容的时间范围一致；段内正文无时间戳
- 段数约 1 段/2-3 分钟；主题从内容归纳（可辨认的素材，不是机械切片）

### 3. 交付

写 `recaps/{标题}.md`（`recaps/` 在项目根，不存在则创建；标题取 meta.json 的 title，把 `/\:*?"<>|` 替换为 `_`，去掉首尾空白）。

告知用户：Recap 路径 + ASR 统计（backend、耗时、成本，取自 meta.json）。

## 边界

- 单视频（单 P UGC 直播回放）；不处理合集、多 P
- 不做说话人分离；下载无 cookie（仅公开视频）
- 大会员 / 登录墙 / 地区限制内容不保证可下载
- 一次只处理一个 BV
- 首发不支持 NVIDIA CUDA 一等后端（本地 GPU 仅 rocm）

