网站导航
← 返回资料库

把 B 站视频剪藏自动变成逐字稿和带时间戳可跳转的 AI 摘要(vault-ingest agent)

发布于 2026年9月16日#Obsidian#自动化

把 B 站视频/网页剪藏自动转成带时间戳的逐字稿和 AI 摘要;字幕优先、ASR 兜底,锚点校验杜绝 AI 编造

vault-ingest 是跑在 PARA 知识库里的「视频 / 文章网页剪藏」工作流:把 Obsidian Web Clipper 落在 _Capture/ 根目录的 B 站视频与网页剪藏,批量转成「带时间戳逐字稿 + 基于逐字稿的 AI 总结摘要」,写入 _Capture/_Clipper/ 文件夹,每周人工归类。确定性脚本(无 LLM)+ 摘要 agent + 手动命令三件套,用锚点强制校验杜绝 AI 编造。

一句话概括:三阶段工作流(prepare 抓取转录 → agent 写摘要 → finalize 校验记账),字幕优先、ASR 兜底,产物落进 git 忽略的 _Clipper/,源剪藏全程只读。


一、它是什么

vault-ingest 解决的是「剪藏只进不出」问题:你在 B 站看到好视频、微信读到好文章,用 Obsidian Web Clipper 剪藏进 _Capture/,然后就没有然后了——视频舍不得花时间看、文章堆着不消化,_Capture/ 慢慢变成信息垃圾场。

该工作流把这一步自动化:

  • 输入_Capture/ 根目录下的视频/网页剪藏初始信息(frontmatter 含 source URL,在 Google 扩展程序中格式可配置)。自动区分两类——B 站视频链接(bilibili-video)与网页文章(web-article),跳过 01-/02-/03- 等人工构建笔记与所有子目录(即 _Clipper 文件夹)。
  • 处理:视频优先抓 B 站现成字幕(免费、快、准),无字幕才下载音频走云 ASR 兜底(未测试);文章直接复用剪藏正文。
  • 产出_Capture/_Clipper/ 下每篇剪藏生成「摘要笔记(<缩写>-<author>-<title>.md)+ 完整逐字稿(transcripts/<缩写>-<author>-<title>.md,与摘要笔记同名)」。摘要笔记正文完全按剪藏模板组织**一句话总结** + #### 1. 要点 + #### 2. 个人加工 + #### 参考链接 + #### 编辑历史记录,段间以 --- 分隔);逐字稿 H1 与摘要笔记的来源链接文字统一用 <缩写>-<author>-<title> 格式(bilibili-videoBVweb-articleWAauthor/title 按模板规则过滤:中文标点、空格、Windows 禁止字符一律删除)。另生成 _本周回顾-<日期>.md 供每周归类。

核心设计是摘要绝不脱离逐字稿:视频要点带可点击跳回视频的时间戳链接[MM:SS](视频URL?t=秒#t=MM:SS.ff),配合 media-extended 插件点击即跳转),文章要点带原文引句;--finalize 阶段脚本二次校验每个锚点确实存在于逐字稿,不通过就标记 needs-review,从机制上杜绝「AI 编造内容」。

适合场景:个人知识库的碎片剪藏定期消化、视频课/播客转文字归档、把「收藏夹」变成「可检索的知识」。


二、复现章节(照着做——已拿到资源包)

本节面向已拿到「vault-ingest 资源包」的读者。资源包包括下述 8 个文件。

(一) 资源包构成

材料路径作用
管道主脚本.opencode/scripts/ingest.py扫描/去重/抓取/转录/落盘/校验/报告(确定性、无 LLM)
依赖清单.opencode/scripts/requirements.txtyt-dlprequestsPyYAMLsecretstorage
入口 wrapper.opencode/scripts/ingest.sh固定走 venv 的 Python 调用 ingest.py(规避系统 Python 缺包)
cookie 助手.opencode/scripts/bili-cookies.sh从浏览器导出 B 站 cookie(Netscape 格式)
摘要 agent.opencode/agents/vault-ingestor.md编排管道 + 逐条写摘要(复用 opencode 模型)
触发命令.opencode/commands/vault-ingest.md/vault-ingest 命令入口
git 忽略(库根).gitignore追加 _Capture/_Clipper/(产物不进 git)
git 忽略(opencode).opencode/.gitignore追加 __pycache__/*.pyc

(二) 前置条件

  • opencode 已安装,在 PARA 库根目录(AGENTS.md 生效的目录)操作
  • Python ≥ 3.10(yt-dlp 已提示弃用 3.10,建议 3.11+ 建 venv)
  • ffmpeg 可用(音频时长探测与切分,ASR 接口对音频时长有限制(且长音频一次转写容易超时/截断),所以要先在静音处切段
  • B 站账号(Chrome/Firefox 登录态,用于导出 SESSDATA cookie,让管道能免费、快速、准确地直抓 B 站现成字幕)
  • SiliconFlow 账号(可选——仅无字幕视频的 ASR 兜底需要;有字幕的视频用不到)
  • Obsidian(可选,用于查看产物与周回顾)

(三) 分步骤操作清单(装配)

  1. 放入资源包:把 8 个文件放到对应位置(.opencode/scripts/.opencode/agents/.opencode/commands/.gitignore 两处按内容合并)
    • ✅ 验证:ls .opencode/scripts/ 显示 ingest.pyingest.shbili-cookies.shrequirements.txt
  2. 建 venv 并装依赖:
    python3 -m venv ~/.cache/para-ingest/venv
    ~/.cache/para-ingest/venv/bin/pip install -r .opencode/scripts/requirements.txt
    • ✅ 验证:~/.cache/para-ingest/venv/bin/python -c "import yt_dlp; print(yt_dlp.version.__version__)" 输出 2026 版本号
  3. 导出 B 站 cookie(先确认 Chrome 已登录 bilibili.com):
    bash .opencode/scripts/bili-cookies.sh
    • ✅ 验证:~/.cache/para-ingest/cookies.txt 存在、权限 600、含 SESSDATA
  4. 配置 SiliconFlow key(仅无字幕视频兜底需要,可后补):
    printf '{\n  "siliconflow_api_key": "<REDACTED>"\n}\n' > ~/.cache/para-ingest/secrets.json
    chmod 600 ~/.cache/para-ingest/secrets.json
    • ✅ 验证:bash .opencode/scripts/ingest.sh --check 显示 SILICONFLOW_API_KEY:已设置
  5. Obsidian 排除逐字稿目录(避免全文污染搜索):设置 → 文件与链接 → 忽略文件 → 添加 _Capture/_Clipper/transcripts/
    • ✅ 验证:_Capture/_Clipper/transcripts/ 下的文件不再出现在 Obsidian 搜索
  6. 运行管道:
    • 在 opencode 输入 /vault-ingest(agent 自动完成 prepare → 摘要 → finalize 三阶段)
    • ✅ 验证:终端依次显示「prepare 完成 / 摘要写入 / finalize 完成」,_Capture/_Clipper/ 出现笔记、逐字稿与 _本周回顾-*.md

(四) 验证 / 自测步骤

  • bash .opencode/scripts/ingest.sh --check:打印配置路径、cookie 是否存在、API key 是否设置、Python/ffmpeg 版本
  • bash .opencode/scripts/ingest.sh --dry-run:只扫描+分类+判重,不联网不写文件,确认 bilibili-video / web-article 识别正确、01-/02-/03- 被跳过
  • 首跑 /vault-ingest 后抽查:视频笔记每个带链接的时间戳要点能在逐字稿对应行找到(且点击可跳回视频);文章要点引句逐字出现在正文
  • 打开 _Capture/_Clipper/_本周回顾-*.md:确认「新增 / 失败」两张表内容正确

(五) 坑与注意事项

  1. 不要用系统 yt-dlp:系统自带的可能是 2022 年古董版,B 站接口早已变更。必须用 venv 内安装的新版——ingest.sh wrapper 强制走 venv,勿绕过。
  2. B 站字幕填充开关yt_dlpextract_info(download=False) 返回的 info['subtitles'] 默认是空 dict(连 danmaku 都没有),必须在 YoutubeDL 选项里同时开 writesubtitles: Truewriteautomaticsub: True 才触发 extractor 填充。
  3. 字幕需要登录:不带 SESSDATA cookie 时 --list-subs 只显示 danmakuai-zh 等字幕不可见 → 视频会错误地落到 ASR。cookie 约每月过期,过期重跑 bash .opencode/scripts/bili-cookies.sh
  4. Linux Chrome cookie 解密:Chrome cookie 用系统 keyring 加密,Python 侧需装 secretstorage(否则几百条 cookie 解不开);且新版 yt-dlp 用 --cookies 落盘的是 JSON,读不回来——所以 bili-cookies.shextract_cookies_from_browser + jar.save() 直接写 Netscape 格式。
  5. 相对路径.opencode/scripts/... 只有在库根目录下才有效;在别的目录请用绝对路径或先 cd 到库根。
  6. opencode CLI 不在 PATHingest.py 刻意 shell 调 opencode(避免嵌套与路径依赖),摘要由 agent 直接编排完成。
  7. 去重与续跑:已处理的源剪藏留在 _Capture/ 根目录不动(管道只读源),靠 _Clipper/.ingest-ledger.json 判重;笔记骨架存在但 ingest-status: new 时重跑会「续跑」(不再抓取、不覆盖),summarized 才跳过。
  8. 产物不进 git_Capture/_Clipper/ 整体被 .gitignore 忽略,靠坚果云等同步备份,避免每周提交噪音。

三、架构解析章节(看懂)

(一) 文件职责地图

文件职责关键操作跨文件/模块交互
.opencode/scripts/ingest.py确定性管道主体扫描 _Capture/*.md → 分类(重命名)/去重 → 抓取转录 → 写骨架+逐字稿+manifest → finalize 校验/记账/周回顾yt_dlpffmpeg、SiliconFlow API;读写 _Clipper/ 下笔记与两个 dotfile
.opencode/scripts/ingest.shvenv 统一入口解析 ~/.cache/para-ingest/venv 的 Python 绝对路径后 exec ingest.py保证依赖在 venv 内,规避系统 Python 缺包与版本污染
.opencode/scripts/bili-cookies.shcookie 导出extract_cookies_from_browser + jar.save() 写 Netscape 文件;chmod 600产出 ~/.cache/para-ingest/cookies.txt,供 yt_dlprequests 取用
.opencode/agents/vault-ingestor.md摘要 agentingest.sh --prepare → 逐条写摘要 → --finalize;只改笔记「一句话+要点」两处ingest.sh;读逐字稿写摘要;约束(不改源、不臆造)内嵌于提示词
.opencode/commands/vault-ingest.md触发命令声明 agent: vault-ingestor 与流程说明在 opencode 输入 /vault-ingest 即进入 agent 流程
.gitignore(库根)忽略产物_Capture/_Clipper/管道产物不进 git 历史
.opencode/.gitignore忽略 Python 缓存__pycache__/*.pyc保持 opencode 工具目录干净

关键说明:工作流把「确定性」与「推理」物理分离——ingest.py 全程无 LLM,可幂等、可单测、失败可见;vault-ingestor agent 只做「读逐字稿 → 写摘要」这一件推理事,复用 opencode 当前配置的模型,不新增 API key。

(二) 依赖 / 调用关系

  • 运行时依赖yt-dlp(B 站元数据/字幕/音频)、ffmpeg(静音检测切段)、SiliconFlow /v1/audio/transcriptions(ASR 兜底)、requests(字幕与 ASR HTTP)、PyYAML(frontmatter 解析)、secretstorage(Linux Chrome cookie 解密,仅 cookie 导出用)
  • 调用链/vault-ingest 命令 → vault-ingestor agent → bash ingest.sh → venv python ingest.pyyt_dlp / ffmpeg / SiliconFlow API;bili-cookies.shyt_dlp.cookies.extract_cookies_from_browser
  • 运行时状态~/.cache/para-ingest/config.jsoncookies.txtsecrets.jsonmedia/<id>/ 音频缓存、venv/)+ _Clipper/.ingest-ledger.json(去重账本)+ _Clipper/.ingest-manifest.json(prepare → finalize 交接)
  • 被依赖方:产物笔记是用户周回顾与后续转正为原子笔记的素材,是知识库的「上游原料」

(三) 数据流 / 执行时序

用户: /vault-ingest

① prepare  ingest.py --prepare
   扫描 _Capture/*.md(跳过 01-/02-/03- 编号笔记与子目录)
   → 分类(bilibili-video / web-article)+ canonical id(BV 号 / 去 tracking 参数的 URL)
   → ledger 判重(status=done 跳过;骨架存在且未摘要 → 续跑)
   → 视频:yt_dlp 字幕优先(需 cookie);无字幕 → 下载音频 → ASR 兜底(缺 key 报 asr_key_missing)
   → 文章:复用剪藏正文(正文 <40 字符或含微信墙标记 → clipper_capture_incomplete 失败)
   → 写 _Clipper/<base>.md 骨架 + transcripts/<base>.md 逐字稿
   → 写 .ingest-manifest.json(prepared / failed 清单)

② 摘要    vault-ingestor agent 读 manifest
   对每个 prepared 条目:读逐字稿 → 填「**一句话总结**」下的引用块与「#### 1. 要点」
   视频要点以带跳转链接的时间戳开头(直接从逐字稿复制 [MM:SS](视频URL?t=秒#t=NPT),点击可跳回视频);文章要点用「原句」引句锚点
   —— 只改这两处,不碰 frontmatter / #### 2. 个人加工 / #### 参考链接 / #### 编辑历史记录(正文骨架完全按剪藏模板)

③ finalize  ingest.py --finalize
   校验每个锚点(时间戳/引句)确实在逐字稿中 → ingest-status: summarized 或 needs-review
   → 更新 ledger → 写 _本周回顾-YYYY.MM.DD.md(新增表 + 失败表)

④ 用户周回顾 → 读 _本周回顾 与各笔记 → 人工 triage(转正原子笔记 / 丢弃 / 保留观望)
文件/指令子功能点的描述[函数标注]文字总结
用户/vault-ingest 触发命令入口
① prepare(脚本:写逐字稿 + 空骨架)
ingest.py --prepare扫描 _Capture/*.md,跳过 01-/02-/03- 编号笔记与子目录scan_capture定型
分类 bilibili-video / web-article + canonical id(BV 号 / 去 tracking 参数 URL)analyze_file定身份
ledger 判重(status=done 跳过;骨架存在且未摘要 → 续跑),四态状态机判断后续进行的动作定做不做
视频:yt_dlp 字幕优先(需 cookie);无字幕 → 下载音频 → ASR 兜底(缺 key 报 asr_key_missingfetch_bilibili
文章:复用剪藏正文(正文 <40 字符或含微信墙标记 → clipper_capture_incomplete 失败)fetch_article定内容
_Clipper/<base>.md 骨架 + transcripts/<base>.md 逐字稿build_transcript_file + build_note_file定产物
.ingest-manifest.json(prepared / failed 清单,输入给 finalize)run_prepare定清单/定账
② 摘要(agent:读 manifest → 写摘要)
vault-ingestor agent对每个 prepared 条目:读逐字稿 → 填「一句话总结」下的引用块与「#### 1. 要点」写”一句话总结”和”要点”
视频要点以带跳转链接的时间戳开头(直接从逐字稿复制 [MM:SS](视频URL?t=秒#t=NPT),点击可跳回视频);文章要点用「原句」引句锚点锚点可回跳/可查证
只改这两处,不碰 frontmatter / #### 2. 个人加工 / #### 参考链接 / #### 编辑历史记录(正文骨架完全按剪藏模板)严守骨架
③ finalize(脚本:校验 + 写周回顾)
ingest.py --finalize校验每个锚点(时间戳/引句)确实在逐字稿中 → ingest-status: summarizedneeds-reviewvalidate_note定真伪(校验)
更新 ledger → 写 _本周回顾-YYYY.MM.DD.md(新增表 + 失败表)write_weekly_review定账(周回顾)
④ 用户周回顾_本周回顾 与各笔记 → 人工 triage(转正原子笔记 / 丢弃 / 保留观望)定去留

(四) 设计意图(为什么这么设计)

  • 脚本不做 LLM、agent 不做抓取:抓取/转录是确定性 I/O 活,放脚本里可幂等、可测试、单条失败不拖垮整批;摘要是推理活,交给 agent 复用 opencode 模型。脚本不 shell 调 opencode(CLI 不在 PATH + 会话嵌套有风险),由 agent 编排最稳。
  • 字幕优先、ASR 兜底:B 站大部分视频有 CC/AI 字幕(ai-zh 等),直抓字幕免费、快、准确率高;无字幕才下音频转写。云 ASR 选 SiliconFlow SenseVoiceSmall(免费档、OpenAI 兼容、中文效果好)。
  • 锚点强制防捏造:视频摘要的时间戳锚点直接复用逐字稿里的跳转链接(点击可跳回 B 站对应位置),--finalize 再机械校验一遍(时间戳在逐字稿中真实存在、引句逐字可查),不过则标 needs-review。这是「AI 总结不编造」的机制保障而非提示词愿望。
  • _Clipper/ git 忽略 + 同步备份:管道产物是中间态,进 git 会造成每周噪音;靠坚果云备份,源剪藏保持只读,_Capture/ 收件箱语义不破。
  • 去重靠 ledger、续跑靠 ingest-status:源文件不移动(尊重收件箱),用 canonical id(BV 号 / 去 tracking 参数的 URL)判重;笔记骨架存在但未摘要时续跑,避免重抓和覆盖已写内容。

(五) 二次开发入口

想做的修改改哪里
新增输入源(YouTube / 本地视频 / 图片 OCR)ingest.pyclassify + 新增 fetch_* 函数 + 输出命名扩展
换 ASR 引擎(本地 SenseVoice/Paraformer 等)run_asr(保持 (音频) -> [(ts, text)] 接口,只改这一个函数)
换摘要模型vault-ingestor.md(agent 用 opencode 当前模型即可);或改为脚本直调 API
加定时触发命令外另配 cron / systemd timer:prepare → 摘要 → finalize 三段脚本化
调整摘要锚点规则vault-ingestor.md 摘要硬规则 + ingest.pyvalidate_note
改产物笔记 schema(框架、模板)build_note_file / build_transcript_file

四、二次开发指南

把「二次开发入口」具体化为可操作指引,含资源包重新打包/构建说明。

(一) 核心改动点

示例:新增 YouTube 输入

  1. classify 增加 youtube.com 分支 → kind youtube-video,canonical id 用 youtube:<videoId>
  2. 新增 fetch_youtube():yt_dlp 对 YouTube 字幕同样走 writesubtitles 开关;无字幕复用 run_asr 兜底
  3. 输出命名按 kind 扩展(如 yt-<videoId>.md),validate_note 的时间戳校验规则可复用
  4. 验证:--dry-run 确认分类正确 → 首跑确认字幕/兜底两条路径 → 抽查周回顾

示例:ASR 从云端换本地

  1. run_asr 内把 SiliconFlow POST 替换为本地 funasr/faster-whisper 调用,保持返回 [(时间戳, 文本)]
  2. --check 增加本地模型/环境的可用性检查
  3. 验证:用一个无字幕视频走通,确认时间戳与文本正确

示例:改摘要锚点规则

  1. vault-ingestor.md「摘要硬规则」改要求(如视频要点必须同时带时间戳与引句)
  2. ingest.pyvalidate_note 同步改校验逻辑
  3. 验证:写一条不合规摘要跑 --finalize,应被标 needs-review

(二) 资源包如何打包与构建

让别人在相同环境里复现你改过的管道,需要把改动重新打成资源包。

资源包所需材料

材料来源是否必选
.opencode/scripts/(4 文件)本管道✅ 必选
.opencode/agents/vault-ingestor.md本管道✅ 必选
.opencode/commands/vault-ingest.md本管道✅ 必选
.gitignore.opencode/.gitignore 追加行本管道✅ 必选
~/.cache/para-ingest/venv本机创建环境依赖(不随包分发)

打包/构建步骤

  1. 复制上述 6 个文件 + 2 处 .gitignore 追加行到资源包目录
  2. 随包附 README:前置条件(Python ≥3.10 + ffmpeg + B 站登录态 + SiliconFlow 账号)、venv 创建命令、Obsidian 排除目录设置、cookie/key 配置命令
  3. 校验:干净库放资源包 → 建 venv 装依赖 → --check--dry-run → 首跑 /vault-ingest → 核对 _本周回顾-*.md
  4. 交付时注明:产物笔记的格式约定(原子笔记模板、库整理规范)与 opencode 版本

验证包可复现

  • 在无本管道的干净 opencode 库放入资源包 → 跑 /vault-ingest → 应能走通 prepare → 摘要 → finalize
  • 若失败,回查「前置条件」清单:venv 依赖是否装全、cookie 是否含 SESSDATA、是否在库根目录操作

参考资料

  1. yt-dlp 文档:yt-dlp 是管道里唯一的外部视频/字幕抓取器。
  2. SiliconFlow 文档
下载资源包