name: youtube-transcript
description: “Fetch YouTube transcripts through DeepAPI or local fallback tooling and save clean text output.”
category: research
risk: safe
source: community
source_repo: davidondrej/skills
source_type: community
date_added: “2026-07-07”
author: davidondrej
tags: [youtube, transcripts, research]
tools: [claude, codex]
license: “MIT”
license_source: “https://github.com/davidondrej/skills/blob/main/LICENSE”

YouTube 转录(通过 DeepAPI,yt-dlp 回退)

何时使用

  • 当用户要求获取 YouTube 转录、字幕、字幕文本或口语内容提取时使用。
  • 当 DeepAPI 或本地回退工具可以安全获取转录时使用。

获取 YouTube 视频的转录并保存干净的原始 .txt 文件。主要路径是 DeepAPI POST /v1/scrape/youtube/transcript。它在服务端运行,因此避免了困扰 yt-dlp 的本地 IP 机器人标记问题。

保存位置

  • 如果用户位于真实的项目/工作目录中 → 保存到那里。
  • 否则(没有给定目录,或当前工作目录无意义)→ 保存到 ~/Downloads
  • 始终将文件命名为 Channel_Title,空格替换为 _(例如 David_Ondrej_title_of_video.txt)。如果元数据不可用,回退到视频 ID。

主要路径 — DeepAPI

DEEPAPI_API_KEY 必须已经存在于环境中。不要读取 shell 启动文件或打印密钥:

test -n "$DEEPAPI_API_KEY" || { echo "DEEPAPI_API_KEY is not set"; exit 1; }
BASE=${DEEPAPI_API_BASE_URL:-https://deepapi.co}

运行抓取(保留幂等键;重试必须复用同一个键):

IDK=$(uuidgen)
curl -s --max-time 120 "$BASE/v1/scrape/youtube/transcript" \
  -H "Authorization: Bearer $DEEPAPI_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $IDK" \
  -d '{"url": "VIDEO_URL", "maxCostUsd": "0.05", "waitForFinishSecs": 60}' \
  > /tmp/yt_transcript.json
  • 非英语视频:在请求体中添加 "language": "de"(等)。
  • status: running → 等待 next.afterSecs,然后 curl "$BASE$(jq -r '.next.path' /tmp/yt_transcript.json)" -H "Authorization: Bearer $KEY",直到 succeededfailed

提取文本并保存:

jq -r '.status' /tmp/yt_transcript.json                # succeeded | running | failed
jq -r '.output[0].text' /tmp/yt_transcript.json > "$OUT/$NAME.txt"
jq -r '.debitMicrousd' /tmp/yt_transcript.json         # cost (50000 = $0.05)

.output[0].segments 也有带时间戳的片段(startSecsdurationSecstext),如果用户想要时间戳。output 为空 = 视频没有字幕;报告这一点,不要重试。

对于 Channel_Title 文件名,用快速的 yt-dlp --print "%(channel)s|%(title)s" --skip-download "URL" 获取元数据;如果失败,使用视频 ID。

何时回退到 yt-dlp

  • 环境中缺少 DEEPAPI_API_KEY
  • HTTP 402 insufficient_credits(先告诉用户在 deepapi.co/credits 充值;只有他们不可用时才回退)。
  • DeepAPI 请求 failed 两次。

每次回退时都要告诉用户——回退意味着产品错过了一个真实用例。

回退路径 — yt-dlp(本地)

OUT="$(pwd)"            # 如果当前工作目录无意义则为 ~/Downloads
META=$(yt-dlp --print "%(channel)s|%(title)s" --skip-download "URL")
NAME=$(echo "$META" | tr '| ' '__' | tr -cd '[:alnum:]_.-')   # "Channel_Title",空格 -> _,去除不安全字符
yt-dlp --skip-download --write-subs --write-auto-subs \
  --sub-langs "en.*" --sub-format json3 \
  -o "$OUT/$NAME.%(ext)s" "URL"
  • 如果 channel 为 null,回退 channeluploaderuploader_id
  • --skip-download = 仅字幕。--write-subs + --write-auto-subs = 优先人工字幕,自动字幕作为回退。
  • 始终使用 json3,绝不用 VTT/SRT——自动 VTT 会把每行重复两次(滚动字幕)。

把 json3 展平为纯文本:

python3 - "$OUT" <<'PY'
import json, html, re, glob, sys, pathlib
f = glob.glob(sys.argv[1] + "/*.json3")
if not f: sys.exit("no json3 file")
data = json.load(open(f[0], encoding="utf-8"))
parts = ["".join(s.get("utf8","") for s in e.get("segs") or []) for e in data.get("events", [])]
txt = re.sub(r"\s+", " ", html.unescape(" ".join(p.strip() for p in parts if p.strip()))).strip()
out = pathlib.Path(f[0]).with_suffix(".txt")
out.write_text(txt, encoding="utf-8"); print(out)
PY

yt-dlp 失败处理

  • 非英语 / 未知语言:先运行 yt-dlp --list-subs "URL",然后设置 --sub-langs
  • 较新的 yt-dlp 可能需要在 PATH 上有 deno 才能进行 YouTube 提取。
  • 首次失败时:运行一次 yt-dlp -U,重试一次,然后停止。
  • 429 / “Sign in to confirm you’re not a bot” = IP 被标记。停止——不要循环重试(会让情况更糟)。
  • 除非用户明确要求,否则绝不回退到为 Whisper 下载音频。

输出

报告保存的路径;如果文本较短则打印出来。如果使用了 DeepAPI,还要以美元报告费用。

局限性

  • 改编自 davidondrej/skills;在行动之前验证本地路径、工具、凭据和代理功能。
  • 对于命令、远程访问、调度、浏览器自动化或文件更改工作流,先获得用户的明确批准并确认目标环境。
Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐