YouTube 字幕下载
从 YouTube 视频下载字幕(副标题/隐藏式字幕)。支持手动创建和自动生成的字幕。无需 API 密钥或浏览器——直接使用 YouTube 的 InnerTube API,当 YouTube 阻断直接 API 路径时自动回退至 yt-dlp。
首次运行时获取视频元数据和封面图片,缓存原始数据以便快速重新格式化。
脚本目录
脚本位于 scripts/ 子目录中。{baseDir} = 此 SKILL.md 的目录路径。解析 ${BUN_X} 运行时:如果已安装 bun → 使用 bun;如果 npx 可用 → 使用 npx -y bun;否则建议安装 bun。将 {baseDir} 和 ${BUN_X} 替换为实际值。
| 脚本 | 用途 |
|---|---|
scripts/main.ts | 字幕下载命令行工具 |
用法
# 默认:带时间戳的 Markdown(英文)
${BUN_X} {baseDir}/scripts/main.ts <youtube-url-or-id>
# 指定语言(按优先级顺序)
${BUN_X} {baseDir}/scripts/main.ts <url> --languages zh,en,ja
# 不带时间戳
${BUN_X} {baseDir}/scripts/main.ts <url> --no-timestamps
# 带章节划分
${BUN_X} {baseDir}/scripts/main.ts <url> --chapters
# 带说话人识别(需要 AI 后处理)
${BUN_X} {baseDir}/scripts/main.ts <url> --speakers
# SRT 字幕文件
${BUN_X} {baseDir}/scripts/main.ts <url> --format srt
# 翻译字幕
${BUN_X} {baseDir}/scripts/main.ts <url> --translate zh-Hans
# 列出可用字幕
${BUN_X} {baseDir}/scripts/main.ts <url> --list
# 强制重新获取(忽略缓存)
${BUN_X} {baseDir}/scripts/main.ts <url> --refresh
选项
| 选项 | 描述 | 默认值 |
|---|---|---|
<url-or-id> | YouTube 网址或视频 ID(允许多个) | 必需 |
--languages <codes> | 语言代码,逗号分隔,按优先级顺序 | en |
--format <fmt> | 输出格式:text、srt | text |
--translate <code> | 翻译为指定的语言代码 | |
--list | 列出可用字幕,而不是获取 | |
--timestamps | 每个段落包含 [HH:MM:SS → HH:MM:SS] 时间戳 | 开启 |
--no-timestamps | 禁用时间戳 | |
--chapters | 从视频描述中进行章节划分 | |
--speakers | 带元数据的原始字幕,用于说话人识别 | |
--exclude-generated | 跳过自动生成的字幕 | |
--exclude-manually-created | 跳过手动创建的字幕 | |
--refresh | 强制重新获取,忽略缓存数据 | |
-o, --output <path> | 保存到指定的文件路径 | 自动生成 |
--output-dir <dir> | 基础输出目录 | youtube-transcript |
可选环境变量
| 变量 | 描述 |
|---|---|
YOUTUBE_TRANSCRIPT_COOKIES_FROM_BROWSER | 在回退时传递给 yt-dlp --cookies-from-browser,例如 chrome、safari、firefox 或 chrome:Profile 1 |
输入格式
接受以下任意一种作为视频输入:
- 完整网址:
https://www.youtube.com/watch?v=dQw4w9WgXcQ - 短网址:
https://youtu.be/dQw4w9WgXcQ - 嵌入网址:
https://www.youtube.com/embed/dQw4w9WgXcQ - Shorts 网址:
https://www.youtube.com/shorts/dQw4w9WgXcQ - 视频 ID:
dQw4w9WgXcQ
输出格式
| 格式 | 扩展名 | 描述 |
|---|---|---|
text | .md | 带前置元数据(包括 description)、标题、摘要、可选的目录/封面/时间戳/章节/说话人的 Markdown |
srt | .srt | 供视频播放器使用的 SubRip 字幕格式 |
输出目录
youtube-transcript/
├── .index.json # 视频 ID → 目录路径映射(用于缓存查找)
└── {channel-slug}/{title-full-slug}/
├── meta.json # 视频元数据(标题、频道、描述、时长、章节等)
├── transcript-raw.json # 来自 YouTube API 的原始字幕片段(缓存)
├── transcript-sentences.json # 按句子分割的字幕(按标点分割,跨片段合并)
├── imgs/
│ └── cover.jpg # 视频缩略图
├── transcript.md # Markdown 字幕(由句子生成)
└── transcript.srt # SRT 字幕(由原始片段生成,如果使用 --format srt)
{channel-slug}:频道名称的短横线命名{title-full-slug}:完整视频标题的短横线命名
--list 模式仅输出至标准输出(不保存文件)。
缓存机制
首次获取时,脚本会保存:
meta.json— 视频元数据、章节、封面图片路径、语言信息transcript-raw.json— 来自 YouTube API 的原始字幕片段({ text, start, duration }[])transcript-sentences.json— 按句子分割的字幕({ text, start: "HH:mm:ss", end: "HH:mm:ss" }[]),按句子结束标点(.?!…。?!等)分割,时间戳按字符长度比例分配,兼顾中日韩文字合并imgs/cover.jpg— 视频缩略图
同一视频的后续运行使用缓存数据(无网络请求)。使用 --refresh 强制重新获取。如果请求了其他语言,缓存会自动刷新。
当 YouTube 在直接 InnerTube 路径上返回反机器人/被屏蔽的响应时,脚本会尝试使用备用客户端身份,然后如果可用,则回退至 yt-dlp。如果需要回退但 yt-dlp 不可用,代理应自行决定如何使 yt-dlp 可用并继续,而不是将安装决定推给用户。
SRT 输出(--format srt)由 transcript-raw.json 生成。文本/Markdown 输出使用 transcript-sentences.json 以获得自然句子边界。
工作流程
当用户提供 YouTube 网址并想要字幕时:
- 如果用户未指定语言,先使用
--list运行,以显示可用选项 - 运行脚本时始终对 URL 使用单引号——zsh 将
?视为通配符,因此不加引号的 YouTube 网址会导致“未找到匹配项”:应使用'https://www.youtube.com/watch?v=ID' - 默认:使用
--chapters --speakers运行以获得最丰富的输出(章节 + 说话人识别) - 脚本自动保存缓存数据和输出文件,并打印文件路径
- 对于
--speakers模式:在脚本保存原始文件后,按照下面的说话人识别工作流程进行后处理,添加说话人标签
当用户仅想要封面图片或元数据时,使用任何选项运行脚本都会缓存 meta.json 和 imgs/cover.jpg。
当重新格式化同一视频时(例如,先是文本然后 SRT),会重用缓存数据——无需重新获取。
章节与说话人工作流程
章节(--chapters)
脚本从视频描述中解析章节时间戳(例如 0:00 引言),按章节边界分割字幕,将片段分组为可读段落,并以 .md 文件保存,包含目录。无需进一步处理。
如果描述中不存在章节时间戳,则字幕以分组段落形式输出,不含章节标题。
说话人识别(--speakers)
说话人识别需要 AI 处理。脚本输出一个原始 .md 文件,包含:
- 带有视频元数据的 YAML 前置内容(标题、频道、日期、封面、描述、语言)
- 视频描述(用于提取说话人姓名)
- 描述中的章节列表(如果可用)
- SRT 格式的原始字幕(预计算的开始/结束时间戳,节省 token)
在脚本保存原始文件后,生成一个子代理(为了节约成本,可使用 Sonnet 等较便宜的模型)来处理说话人识别:
- 读取保存的
.md文件 - 读取
{baseDir}/prompts/speaker-transcript.md处的提示词模板 - 按照提示词处理原始字幕:
- 使用视频元数据识别说话人(标题 → 嘉宾,频道 → 主持人,描述 → 姓名)
- 根据对话流、问答模式和上下文线索检测说话人转换
- 划分章节(如果有描述中的章节则使用,否则根据话题转换创建)
- 使用
**说话人姓名:**标签、段落分组(2-4 个句子)和[HH:MM:SS → HH:MM:SS]时间戳进行格式化
- 用处理后的字幕覆盖
.md文件(保留 YAML 前置内容)
当使用 --speakers 时,隐含了 --chapters——处理后的输出始终包含章节划分。
错误情况
| 错误 | 说明 |
|---|---|
| 字幕已禁用 | 视频没有任何字幕 |
| 未找到字幕 | 请求的语言不可用 |
| 视频不可用 | 视频已被删除、设为私密或存在地区限制 |
| IP 被屏蔽 | 请求过多,请稍后重试 |
| 年龄限制 | 视频需要登录以进行年龄验证 |
| 检测到机器人 | 脚本会尝试使用备用客户端,然后尝试 yt-dlp;如果缺少回退工具,代理应自行解决,否则如果仍然失败,请尝试 YOUTUBE_TRANSCRIPT_COOKIES_FROM_BROWSER=safari(或您的浏览器) |


