Install
openclaw skills install @pavelpeng7/video-to-article将视频、字幕文件或大型课程目录转换为结构化图文笔记。用户提到下载视频、转录、抽帧截图、整理成 Obsidian 风格图文笔记、基于字幕学习,或批量导入课程时,都应优先使用这个技能。
openclaw skills install @pavelpeng7/video-to-article这个技能用于把视频内容转换成可读、可复用的图文笔记,偏重实际可落地的生产流程。
| 模式 | 输入 | 输出 | 适用场景 |
|---|---|---|---|
| A: 单视频笔记 | 视频 URL 或本地视频文件 | 图文混排 Obsidian 笔记,可选 Git 推送 | 影评、教程、做饭视频、Vlog |
| B: 字幕学习 | 已有字幕文件(.srt / .vtt) | 摘要、测验、词汇表、章节笔记、问答 | 基于已有转录内容学习 |
| C: 大课程导入 | 含大量视频的课程文件夹 | Section 级图文文章和索引 | Udemy / 慕课 / 培训课程批量导入 |
“转成笔记”、“做成图文笔记”、“下载并分析这个视频”、“把这个视频整理成文章”
| 平台 | 是否通常需要 Cookie | 格式策略 | 备注 |
|---|---|---|---|
Bilibili (b23.tv / bilibili.com) | 通常需要 | 先跑 -F,再显式选择格式 ID | BV 号视频,可能遇到 412 反爬 |
YouTube (youtube.com / youtu.be) | 通常不需要 | 优先 bestvideo[height<=720]+bestaudio | 下载相对直接 |
| TED / Coursera / Udemy | 视情况 | 先跑 -F | 付费内容可能要求登录 |
| 抖音 / TikTok / 小红书 | 通常不需要 | 自动选择通常够用 | 短视频居多 |
| 其他 1700+ 平台 | 视情况 | 先跑 -F | 需要时用平台特定兜底策略 |
Bilibili Cookie 导出示例:
# 将浏览器 Cookie 导出成 Netscape 格式
python3 path/to/bili_cookie_to_netscape.py
# 解析 Bilibili 短链
VIDEO_ID=$(curl -sL "https://b23.tv/XXXXX" -o /dev/null -w "%{url_effective}" | sed 's/.*\/video\///;s/[\/?].*//')
# 不下载直接读取元信息
yt-dlp --no-download --print "%(title)s|%(duration)s|%(uploader)s" "<URL>"
实用默认策略:
# 先查看可用格式
yt-dlp -F "<URL>"
# 下载(Bilibili 需要时加 --cookies)
mkdir -p "<TEMP_DIR>/<VIDEO_ID>"
yt-dlp -o "<TEMP_DIR>/<VIDEO_ID>/video.%(ext)s" \
-f "<chosen-format-id>" --merge-output-format mp4 "<URL>"
python3 << 'PYEOF'
from faster_whisper import WhisperModel
model = WhisperModel("base", device="cpu", compute_type="float32",
download_root="<CACHE_DIR>")
segments, _ = model.transcribe("<TEMP_DIR>/<ID>/video.mp4", language="zh", beam_size=5)
with open("<TEMP_DIR>/<ID>/transcript.txt", "w") as f:
for seg in segments:
f.write(f"[{seg.start:.1f}s - {seg.end:.1f}s] {seg.text.strip()}\n")
PYEOF
语言建议:
language="zh"language="en"模型取舍:
tiny:最快base:推荐默认small:更准但更慢Apple Silicon 加速:
device="mps", compute_type="float16"先根据转录内容判断视频类型,再决定截图密度。
| 视频类型 | 特征 | 截图数量 | 密度规则 |
|---|---|---|---|
| 讲演 / 影评 / 长分析 | 论点推进,口播为主 | 8-12 | 大约每 30-40 秒 1 张 |
| 教程 / 实操演示 | 步骤递进,UI 或代码变化明显 | 3-8 | 每个关键步骤 1 张 |
| 论坛 / 对谈 | 多人发言,话题切换明显 | 5-8 | 说话人切换或话题转折时截 |
| Vlog / 随口杂谈 | 叙事松散 | 3-5 | 按场景变化截 |
| 30 秒以内 | 单点信息 | 1 | 开头帧即可 |
| 30-120 秒 | 短内容分段明显 | 3-5 | 按段落切分 |
截图时间点经验:
命名规范:
01-intro.jpg、02-core-concept.jpgVIDEO="<TEMP_DIR>/<ID>/video.mp4"
OUTDIR="<TEMP_DIR>/<ID>/screenshots"
mkdir -p "$OUTDIR"
ffmpeg -y -ss <seconds> -i "$VIDEO" -frames:v 1 "$OUTDIR/01-intro.jpg"
mkdir -p "<VAULT>/assets/video/<VIDEO_ID>"
cp <TEMP_DIR>/<ID>/screenshots/*.jpg "<VAULT>/assets/video/<VIDEO_ID>/"
推荐笔记结构:
---
title: <核心主题>
source: <Bilibili|YouTube|...>
author: <作者>
type: 文献笔记
tags: [视频笔记, <主题标签>]
created: <YYYY-MM-DD>
---
# <作者>:<标题>
> **来源**:<平台> @<作者>
## 核心洞见
1-2 段概括
![[../../../assets/video/<ID>/02-xxx.jpg]]
## <分节标题>
...
![[../../../assets/video/<ID>/xxx.jpg]]
> "<转录中的引用原文>"
## 行动清单
- [ ] ...
## 金句
> ...
## 相关笔记
- [[已有笔记]] - 关联原因
图片引用格式:
![[../../../assets/video/<ID>/<filename>.jpg]]
find "<VAULT>" -name "*.md" | xargs grep -li "<core keyword>"
cd "<VAULT>" && git add -A && git commit -m "video note: <title>" && git push
“学习这个字幕”、“总结这个转录”、“根据这个字幕出题”、“整理术语”、“考考我这个视频”
| 来源 | 获取方式 | 预处理 |
|---|---|---|
自带 .srt / .vtt 字幕 | 直接读取 | 优先使用 |
| 下载的视频但没有字幕 | 用 yt-dlp 字幕下载或 Whisper | 先去时间码转纯文本 |
| 用户直接粘贴字幕 | 直接使用 | 清洗后可直接分析 |
输出结构化学习指南,包括:
按主题切换拆章,每章总结 2-3 句。
主题切换信号:
提取领域术语、高频词、明确定义的概念和缩写。输出表格包含:
原始字幕文件通常大部分都是元数据,先清理再分析。
import re
def strip_srt(srt_text):
lines = srt_text.split('\n')
result = []
for line in lines:
line = line.strip()
if re.match(r'^\d+$', line): continue
if re.match(r'^\d{2}:\d{2}:\d{2}', line): continue
if not line: continue
result.append(line)
return ' '.join(result)
[possible transcription error][visual content here]| Phase | 目的 | Token 策略 |
|---|---|---|
| 1. 目录分析 | 建立 section 和 lesson 树 | Token 很低 |
| 2. 字幕预处理 | 把字幕批量转成纯文本 | 终端脚本,零 token |
| 3. 截图规划 | 预计算 slug 和 ffmpeg 命令 | 终端脚本,零 token |
| 4. 批量截图 | 后台运行 ffmpeg | 终端脚本,零 token |
| 5. 并行写文章 | 最多 3 个子代理并发处理 section | 只传纯文本和 slug 表 |
| 6. 收尾 | 生成 index.md 和导入日志 | Token 很低 |
遍历课程目录,建立如下结构:
{Section: [video list]}
课程名和课时名要按数字前缀精确匹配。
使用 scripts/preprocess-srt.py:
_preprocessed/section-<slug>.txt使用 scripts/plan-screenshots.py 根据时长和内容类型决定截图点。
预期输出:
_screenshot_plan.json_batch_screenshots.shbash _batch_screenshots.sh
顺序后台运行即可。ffmpeg 比较吃 CPU,不建议并发抽帧。
子代理上下文写法会强烈影响 token 浪费情况,遵守这三条:
示例上下文:
context = """
用英文写课程笔记。
Input: _preprocessed/section-01.txt
All screenshots are already prepared. Do not verify files.
Reference them directly as:
![[../../../assets/<course>/<slug>-<label>.jpg]]
Slug table (each slug has overview/detail/result unless noted otherwise):
- Installation -> installation (3 images)
- Intro -> intro (no screenshots)
Density: Intro gets no screenshots. Other lessons get 3 screenshots each.
Output: sources/<course>/section-01-xxx.md
"""
并行分配建议:
index.mdyt-dlp:下载视频ffmpeg:音频处理和截图faster-whisper:语音转录git:版本控制和同步环境检查:
which yt-dlp ffmpeg 2>&1
python3 -c "from faster_whisper import WhisperModel; print('OK')" 2>&1
| 变量 | 用途 | 示例 |
|---|---|---|
<TEMP_DIR> | 临时下载和处理目录 | 项目内临时目录 |
<VAULT> | Obsidian 库根目录 | ~/Documents/Obsidian |
<ATTACH_DIR> | Vault 内截图目录 | <VAULT>/assets/video/<VIDEO_ID>/ |
<NOTE_DIR> | 笔记输出目录 | <VAULT>/reference-notes/ |
| 问题 | 解决方式 |
|---|---|
Bilibili 412 反爬 | 刷新 Cookie 并重新登录 |
| Bilibili 格式 ID 失效 | 先跑 -F,因为每个视频的 ID 可能不同 |
| YouTube 下载失败 | 处理地区限制,或降级到 -f "best[height<=720]" |
| Whisper 太慢 | 切到 tiny,或在 Apple Silicon 上用 device="mps" |
| 截图文件名导致链接混乱 | 使用英文 kebab-case |
| Git push 失败 | 先试 git pull --rebase && git push |
| 子代理反复验证截图 | 硬编码 slug 表,并明确写 do not verify files |