AgentStack
SKILL verified MIT Self-run

Lark Video2note

skill-teemoweng-lark-video2note-lark-video2note · by teemoweng

把抖音 / 哔哩哔哩 / 小红书 / YouTube 等平台的视频或音频链接,转成飞书妙记 + 飞书文档归档。当用户**明确要求**把视频转成笔记 / 文稿 / 总结 / 逐字稿 / 归档 / 留档,或显式使用 /video2note 时使用。替代 Get 笔记的能力。⚠️ 仅看到 URL 而无明确意图时,先按全局 CLAUDE.md「URL 链接处理」规则做 triage,不要直接触发本 skill。

No reviews yet
0 installs
0 views
view→install

Install

$ agentstack add skill-teemoweng-lark-video2note-lark-video2note

✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access No
  • Filesystem access No
  • Shell / process execution No
  • Environment & secrets No
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

Are you the author of Lark Video2note? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

视频链接 → 飞书妙记 + 飞书文档

> 前置条件:先读 [../lark-shared/SKILL.md](../lark-shared/SKILL.md)。 > 已经登录过 lark-cli,且 scope 至少包含: > drive:drivedocs:documentminutes:minutes:readonlyminutes:minutes.artifacts:readminutes:minutes.transcript:export。 > 缺 scope 时按 lark-shared 的提示让用户授权后再继续。

触发场景

仅在以下两种情况触发本 skill:

  1. 用户明确表达要把视频转成笔记:消息里包含视频 URL(或分享口令,如「2.33 复制打开抖音…https://v.douyin.com/xxx/」)伴随明确动词——"转成笔记"、"留档"、"归档"、"整理这个视频"、"转成逐字稿/文稿"、"沉淀一下"、"帮我看里面讲了啥" 等
  2. 显式触发:用户使用 /video2note $video2note

⚠️ 仅看到 URL 而无明确意图时不要触发。按全局 CLAUDE.md「URL 链接处理」规则先做 triage——看一眼是什么内容,问用户想做什么,再决定是否调用本 skill。

配置

skill 的归档目标飞书云盘文件夹 token 存在 config.json 里(首次使用前请运行 bash scripts/setup.sh)。

Step 0 时务必先读取:

SKILL_ROOT=~/.claude/skills/lark-video2note
[ -f "$SKILL_ROOT/config.json" ] || { echo "缺少 config.json,请先跑 bash $SKILL_ROOT/scripts/setup.sh" >&2; exit 1; }
FOLDER_TOKEN=$(python3 -c "import json;print(json.load(open('$SKILL_ROOT/config.json'))['folder_token'])")

之后所有 lark-cli drive +upload --folder-tokenlark-cli docs +create --parent-token 都用 $FOLDER_TOKEN 而不是写死的字符串。

  • 工作目录:/tmp/video2note//(每次新建,跑完保留 mp4 直到归档完成)

工具

| 平台 | 下载方式 | 逐字稿来源 | |------|---------|------------| | 抖音 | iesdouyin.com/share/video// 解析 play_addr | 妙记 ASR | | B站 | yt-dlp | 优先平台字幕(默认带 Chrome cookies,B站字幕需登录态)→ 妙记兜底 | | YouTube | yt-dlp | 优先 auto-captions(默认带 Chrome cookies)→ 妙记兜底 | | 小红书 | yt-dlp --cookies-from-browser chrome | 妙记 ASR |

两个核心脚本

scripts/download.sh:下载视频 mp4。输入 URL + 输出目录,输出一行 JSON:

{"file":"...","title":"...","platform":"douyin","author":"...","duration_s":485,"source_url":"...","size_bytes":...}

scripts/get-captions.sh:尝试从 B站 / YouTube 抓现成字幕。成功输出:

{"transcript_file":"$WORK/transcript.txt","language":"zh-CN","lines":243}

失败 exit 1(适用任何没字幕的视频或非 B站/YT 平台)。

流程

# Step 0: 加载配置 + 准备工作目录(静默初始化,正常时不向 stdout 输出)
SKILL_ROOT=~/.claude/skills/lark-video2note
[ -f "$SKILL_ROOT/config.json" ] || {
  echo "❌ 缺少 config.json,请先运行:bash $SKILL_ROOT/scripts/setup.sh" >&2; exit 1;
}
FOLDER_TOKEN=$(python3 -c "import json;print(json.load(open('$SKILL_ROOT/config.json'))['folder_token'])")
TS=$(date +%s)
WORK="/tmp/video2note/$TS"
mkdir -p "$WORK"

# 把状态写到约定路径,后续 Step 用 `WORK=$(cat /tmp/video2note_current_work)` /
# `FOLDER_TOKEN=$(cat /tmp/video2note_current_folder)` 读回。每个 Bash 工具调用
# 是独立 shell 进程,环境变量不持续——只能通过文件或 inline 重新赋值传递。
# ⚠️ 不要 `echo "WORK=$WORK"` 当回显——空载 init 应该完全安静,输出留给真有事时。
echo "$WORK" > /tmp/video2note_current_work
echo "$FOLDER_TOKEN" > /tmp/video2note_current_folder

# Step 1: 下载视频(自动识别平台)
# 关键:捕获 exit code
set +e
META=$(bash ~/.claude/skills/lark-video2note/scripts/download.sh "" "$WORK" 2>"$WORK/.dl-err")
DL_EXIT=$?
set -e

# Exit code 2 = "这不是视频"。立即停止本 skill 流程,路由到 defuddle
if [ $DL_EXIT -eq 2 ]; then
  # 把 .dl-err 里 NOT_A_VIDEO 那段原样转给用户,并主动建议改走 defuddle
  # 不要继续 Step 2-4,不要上传、不要建妙记、不要建 docx
  cat "$WORK/.dl-err" >&2
  # 然后用 defuddle 抓那条 URL 的文本内容,按用户原意做总结/归档
  exit 0
fi

# 其它非零 exit 是真失败(网络/cookies/格式),按"失败回退"小节处理
# ⚠️ 不要写 `[ $DL_EXIT -ne 0 ] && { ... }` 形式——当 DL_EXIT=0 时 test 退 1,
#    会变成整个 Bash 工具调用的退出码,触发假阳性 "Error: Exit code 1"。
#    用 if 块包起来,避免把判断结果当退出码。
if [ $DL_EXIT -ne 0 ]; then
  cat "$WORK/.dl-err" >&2
  exit $DL_EXIT
fi

# 解析 META:file / title / platform / author / duration_s / source_url

# Step 2: 拿逐字稿 —— 先试平台字幕,没有再走妙记
# 关键判断:抖音 / 小红书直接跳过,进 Step 2b。B站 / YouTube 先试 Step 2a
PLATFORM=$(echo "$META" | python3 -c 'import sys,json;print(json.load(sys.stdin)["platform"])')

# Step 2a: 尝试平台字幕(仅 B站 / YouTube 有意义)
TRANSCRIPT_FILE=""
MINUTE_URL=""
if [ "$PLATFORM" = "bilibili" ] || [ "$PLATFORM" = "youtube" ]; then
  if CAPTIONS=$(bash ~/.claude/skills/lark-video2note/scripts/get-captions.sh "" "$WORK" 2>/dev/null); then
    TRANSCRIPT_FILE=$(echo "$CAPTIONS" | python3 -c 'import sys,json;print(json.load(sys.stdin)["transcript_file"])')
    # 拿到字幕 → 跳过妙记,直奔 Step 3
  fi
fi

# Step 2b: 没拿到字幕 → 走完整妙记 ASR 流程(上传云盘 → 生成妙记 → 拉产物)
if [ -z "$TRANSCRIPT_FILE" ]; then
  # 2b-i: 上传到飞书云盘 视频笔记 文件夹
  # 注意:drive +upload 要求 --file 是相对于 CWD 的相对路径
  cd "$WORK"
  FILE_BASENAME=$(basename "$(echo "$META" | python3 -c 'import sys,json;print(json.load(sys.stdin)["file"])')")
  TITLE=$(echo "$META" | python3 -c 'import sys,json;print(json.load(sys.stdin)["title"])')
  lark-cli drive +upload \
    --file "./$FILE_BASENAME" \
    --folder-token $FOLDER_TOKEN \
    --name "$TITLE.mp4"
  # → 记录 data.file_token 为 FILE_TOKEN

  # 2b-ii: 生成妙记(异步)
  lark-cli minutes +upload --file-token "$FILE_TOKEN"
  # → 返回 data.minute_url;从 URL 末段取 minute_token

  # 2b-iii: 等妙记 ASR 转写完成,拉逐字稿
  # 用 wait-for-minute.sh 轮询,不要再写固定 sleep。
  # 短视频 ~30-60s 退出;长视频自适应;最长 10 分钟兜底。
  #
  # 就绪信号:transcript.txt 里出现「说话人」标签(ASR 真实产出的结构标记)。
  # 不等 artifacts.summary——飞书 AI 总结是独立流水线,比 ASR 慢 3-10 分钟,
  # 而本 skill 用不到它(自己基于逐字稿写更密的版本,见 Step 3)。
  #
  # ⚠️ vc +notes 会把 transcript 下载到调用时的 CWD 下(minutes//transcript.txt),
  #    不是绝对路径。脚本内部已 cd 到 $WORK 之类的环境时仍要确保 CWD 正确。
  cd "$WORK"
  bash ~/.claude/skills/lark-video2note/scripts/wait-for-minute.sh "$MINUTE_TOKEN" > _notes.json
  # → _notes.json 是 vc +notes 的完整响应
  # → data.notes[0].artifacts.transcript_file 是相对 CWD 的逐字稿路径
  # → AI summary 字段忽略(我们自己写更密的)
  TRANSCRIPT_FILE="$WORK/minutes/$MINUTE_TOKEN/transcript.txt"
fi

# 走到这里:TRANSCRIPT_FILE 一定有了
# 字幕路径下 MINUTE_URL 为空,文档里就不写「飞书妙记」那一行
# 妙记路径下 MINUTE_URL 写到元信息 callout 里

# Step 3: 由你(Claude)基于逐字稿撰写结构化文档,并落成飞书 docx
# 重要:即使有妙记 summary 也不要直接用,那个总结太瘦
# 用下方「文档结构」模板,自己读完逐字稿写一版密度更高的版本
# 把内容写进 note.xml(CWD 必须是 $WORK)

# 3a. 短视频(XML  标签、
#    snake_case 属性、 根标签等),失败时**立即停下,改正 note.xml 后重试**。
#    不要带着违规 XML 硬上传——服务器会静默吞掉/转义未知标签,文档表面"创建成功"
#    但渲染稀烂,bug 拖到用户打开飞书才发现。
bash ~/.claude/skills/lark-video2note/scripts/validate-docx-xml.sh ./note.xml || exit 1

lark-cli docs +create \
  --api-version v2 \
  --parent-token $FOLDER_TOKEN \
  --content @./note.xml
# 注意:v2 用 --content(不是 --markdown)和 --parent-token(不是 --folder-token)
# --content 支持 @file,但 file 必须是 CWD 相对路径
# 文档默认 XML 格式,标题从  自动提取,不要传 --title
# → 返回 data.document.url

# 3b. 长视频(XML ≥ 40KB,对应大约 > 20 分钟内容)— 骨架 + 分段追加
# 长内容一次性 POST 容易超字数限制或被截。建议拆 3 段:
#   ① 创建骨架:标题 + 元信息 callout + 执行摘要 + 核心论点 + 占位 heading
#   ② 用 docs +update --command append 追加:完整论证链路 + Demo + 名词解释 + 金句
#   ③ 再 append:逐字稿章节
# 每一段 .xml 都要先过 validate-docx-xml.sh 再 append。
# 例:
#   bash ~/.claude/skills/lark-video2note/scripts/validate-docx-xml.sh ./part2.xml || exit 1
#   lark-cli docs +update --api-version v2 --doc  \
#       --mode append --content @./part2.xml
# 写入前用 wc -c note.xml 看大小,> 40KB 走 3b
# 参考:飞书 docs v2 推荐"先建骨架再 append",详见 lark-doc skill

# Step 4: 给用户回结果
# 输出 docx URL(绝对路径形式,方便 ⌘+Click)
# 如果走的是妙记路径,附带妙记 URL;走字幕路径则不提

文档结构(11 大块,固定顺序)

使用飞书 docx XML 格式(不要用 markdown,markdown 不支持 callout)。 模板和示例见 [references/doc-template.xml](references/doc-template.xml)。

⚠️ XML schema 是硬约束,不允许"发挥"。常见踩坑:

| 错的写法 | 正确写法 | |---------|---------| | ` / 当根标签 | 直接 ... 开头,无外层根 | | 正文 | 正文 ——飞书 docx **没有 标签**,写出来会被原样转义成可见字符串 | | backgroundcolor="light-blue"(下划线)| background-color="light-blue"(连字符)| | emojiid="round_pushpin" | emoji="📍"(直接放 emoji 字符,不是名称 id)| | 把所有内容塞进一个 包起来 | 用 / / / ` 按结构拼,11 大块各就各位 |

属性名一律 kebab-case;段落标签只能用 `;emoji 必须是字符不是名称。不在 references/doc-template.xml 出现的标签或属性都视为非法。生成完 note.xmlscripts/validate-docx-xml.sh` 会做一次硬性校验,发现违规直接 fail,必须先改对再上传。

1. {视频标题}
2. 📍 来源信息 callout(light-blue)— 平台/作者/时长/原视频/妙记/归档日期
3. ✨ 执行摘要 callout(light-yellow)— 一段话讲清作者真正想说什么,3-5 行
4. 🎯 核心论点 — 一句话立场
5. 🧭 完整论证链路 — 按视频推进逻辑切 4-6 个 h2 小节,每节用「叙述段落 + 必要时穿插 bullet」的方式写
6. 🎬 Demo 实操(如视频里有 demo)— 几段叙述讲清楚步骤
7. 📚 名词解释 — 只解释 2-4 个真正生僻的(如 Ontology、FDE、AIP),用大白话 + 类比
8. 💬 金句原文 callout(light-gray)— 最多 3 句
9. 📜 逐字稿 callout 头(medium-gray)+ 章节列表说明
10. h2 章节标题 + blockquote 引用块装原文(按 5-7 个主题切分,每个标题带 emoji + 时间戳)

撰写要求(基于真实使用反馈)

叙述优先,bullet 谨慎:完整论证链路和 Demo 部分主要用段落,不要无脑列 bullet。bullet 只在以下情况用:

  • 真正是并列的清单(如三家产品对比、几个数字统计)
  • 步骤型分解(但每条要写完整句子)

bullet 之间一定要有衔接句,避免读者跳着扫一遍只看到散点。

名词解释要"看了能懂"

  • 只解释非通用术语,跳过 CLI / PR / star / SKU / ROI 这种业内常识
  • 用大白话 + 实例/类比,不要照搬词典定义
  • 举例:解释 Ontology 时类比"传统数据库像字典只能查,Ontology 像说明书能让人照着改"

金句压到 3 句以内:选「能代表作者核心立场 / 最有传播性 / 最锐利」的,宁缺毋滥。

口误修正:在名词解释或行文里温和指出明显口误(如视频里说"Clang code"实指"Claude Code"),但不要在逐字稿原文里改动。

配色规范(callout 用):

  • light-blue 元信息 · light-yellow 摘要/重点 · light-red 关键问题/警示
  • light-purple 理论/定义 · light-green Demo 上下文 · light-gray 引语
  • medium-gray 整段往后退(如逐字稿头)

platform_cn 映射:douyin=抖音bilibili=哔哩哔哩xhs=小红书youtube=YouTubegeneric=未知平台

返回给用户

跑完后给用户的简短回复格式:

字幕路径(B站/YT 有字幕,跳过妙记):

✅ 已归档({x 分 x 秒} · 平台:{平台} · 作者:{author})

📄 文档:{docx_url}
📝 逐字稿来源:平台 AI 字幕

(执行摘要前 1-2 句)

妙记路径(抖音/小红书,或 B站/YT 没字幕):

✅ 已归档({x 分 x 秒} · 平台:{平台} · 作者:{author})

📄 文档:{docx_url}
🎬 妙记:{minute_url}

(执行摘要前 1-2 句)

关键约束

  1. drive +upload 的 --file 必须是相对路径(CLI 限制),上传前必须 cd "$WORK"
  2. 抖音不要走 yt-dlp:当前 yt-dlp 抖音 extractor 要 fresh cookies,share API 更稳
  3. 小红书需要登录态:用户 Chrome 没登录小红书时直接报错,不要静默卡住
  4. 字幕优先:B站 / YouTube 先试 get-captions.sh,拿到字幕直接跳过妙记,省 8-15 分钟
  5. 妙记是异步的:minutes +upload 返回的瞬间 transcript 是空的,用 scripts/wait-for-minute.sh 轮询(见 Step 2b-iii)
  6. 不要动「第二大脑」Base:归档目标只有云盘 视频笔记 文件夹,保持精简
  7. 不删除本地 mp4 直到 docx 创建成功,方便失败时不丢源
  8. Bash 工具调用末尾不要写 [ test ] && cmd——bash 工具调用的退出码 = 最后一条命令的退出码。当 test 不满足时(空文件 / 等于 0 等正常情况),[ ] 自己退 1,整个 Bash 调用就变成 "Error: Exit code 1" 假阳性,掩盖真实成功。一律用 if [ ... ]; then ...; fi 包起来——if 块不会把判断结果当作整体退出码外泄。
  9. Step 0 静默初始化:跑完 init 不要 echo "WORK=$WORK" / echo "FOLDER_TOKEN=$FOLDER_TOKEN" 当回显——状态已写到 /tmp/video2note_current_*,后续 step cat 回读即可。空载 init 应该完全无输出,让每次跑 skill 的视觉噪声降到最低。

失败回退

  • download.sh exit code 2(NOTAVIDEO):链接是图文笔记 / 纯文章 / 不支持的页面,不是视频。立即停止 video2note 流程,转告用户并主动改用 defuddle skill 抓文本来总结。不要重试,不要上传,不要建妙记。
  • 其它下载失败(exit 1):把 download.sh 的 stderr 原样给用户,提示是否是分享口令格式有误 / cookies 失效 / 网络问题
  • 上传失败:保留本地 mp4,提示用户磁盘空间或飞书云盘配额
  • 妙记 vc +notes 一直返回 artifact 未就绪:检查 lark-cli minutes minutes get --minute-token 看妙记是否还在处理;超过 10 分钟仍未好,把妙记 URL 直接给用户让其手动等

权限

| 操作 | 所需 scope | |------|-----------| | 上传到云盘 | drive:drive | | 移动文件 | drive:drive | | 创建文档 | docs:document | | 生成妙记 | (随上传走,无额外 scope)| | 读妙记总结 | minutes:minutes.artifacts:read | | 读逐字稿 | minutes:minutes.transcript:export | | 读妙记元信息 | minutes:minutes:readonly |

Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet — be the first.

Versions

  • v0.1.0 Imported from the upstream source.