Home / All Skills / Content & Media Creation / baoyu-youtube-transcript
Content & Media Creation · JimLiu/baoyu-skills

baoyu-youtube-transcript

Downloads YouTube video transcripts/subtitles and cover images by URL or video ID. Supports multiple languages, translation, chapters, and speaker identification. Caches raw data for fast re-formatting. Use when user asks to "get YouTube transcript", "download subtitles", "get captions", "YouTube字幕", "YouTube封面", "视频封面", "video thumbnail", "video cover image", or provides a YouTube URL and wants the transcript/subtitle text or cover image extracted.

L5 Restricted · Isolated sandbox & strict auditV2 Human-AuditedReverse APICredential / SessionExecute CommandNetwork AccessWrite FileDual-pass Audit
Author JimLiuGitHub JimLiu/baoyu-skills ↗Stars 25926License MIT(仓库根 LICENSE:Copyright (c) 2026 Jim Liu;根 package.json 同声明 "license": "MIT")Commit 1567581c26
Control levels describe skill capabilities and suggested control measures; they do not represent quality or safety certifications, nor do they dictate usability. Usage decisions rest entirely with users and administrators. Different agent hosts apply varying constraints; do not assume hosts provide automatic protection. Third-party skill copyrights belong to their original authors. Use at your own risk.

1How It Works & Mechanism

The subtitle source is YouTube's internal InnerTube player endpoint rather than the official Data API: the script extracts INNERTUBE_API_KEY directly from the watch page HTML via regex on the fly, then sends a POST request with it to the player endpoint.

skills/baoyu-youtube-transcript/scripts/youtube.ts
const apiKey = html.match(/"INNERTUBE_API_KEY":\s*"([a-zA-Z0-9_-]+)"/)?.[1];
What is happening here: The key is a public web key fetched on demand, allowing the skill to claim "No API key" needed. The same HTML snippet extracts visitorData to use as X-Goog-Visitor-Id, serving as an anonymous session identity without login. The endpoint constant resides in the same file: INNERTUBE_URL = https://www.youtube.com/youtubei/v1/player — constructing custom requests to unofficial endpoints instead of calling the official Data API.

When flagged as a bot by YouTube, it avoids brute-force retries and instead rotates client identities: sequentially retrying across ANDROID, WEB, and IOS client declarations and User-Agents, falling back to yt-dlp only if all fail.

skills/baoyu-youtube-transcript/scripts/youtube.ts
com.google.android.youtube/20.10.38 (Linux; U; Android 14; en_US; Pixel 8 Pro; Build/AP1A.240405.002)
What is happening here: Requests impersonate YouTube App clients (configured with X-YouTube-Client-Name / X-YouTube-Client-Version / X-Goog-Visitor-Id headers) to bypass web-based bot detection.

The yt-dlp fallback operates by "probing first, selecting commands based on capabilities": testing yt-dlp, uvx --from yt-dlp yt-dlp, and python3 -m yt_dlp sequentially, requiring both --js-runtimes and --remote-components to appear in --help to qualify.

skills/baoyu-youtube-transcript/scripts/youtube.ts
helpText.includes("--js-runtimes") &&
Outdated, unqualified versions of yt-dlp are skipped because the script requires --js-runtimes bun to decipher signatures and --remote-components ejs:github to fetch EJS components. SKILL.md also delegates handling missing dependencies directly to the agent rather than prompting the user.

The final execution uses spawnSync(command, argvArray) without shell string concatenation; both probing and execution enforce a maxBuffer limit.

skills/baoyu-youtube-transcript/scripts/youtube.ts
const result = spawnSync(command.command, args, {
The execution surface is narrowed to fixed argv (-J, --skip-download, --js-runtimes, bun, --remote-components, ejs:github, optional --cookies-from-browser), eliminating shell injection risks; the video ID parameter originates from user input.

--translate does not invoke any external translation API; it simply appends &tlang=<code> to the subtitle track URL to leverage YouTube's native machine-translated tracks.

skills/baoyu-youtube-transcript/scripts/youtube.ts
url += `&tlang=${translateTo}`;
It pre-checks that info.isTranslatable is true and the target language exists in translationLanguages; when branching to yt-dlp, it reselects the language list instead of appending tlang.

--speakers uses a "script generates source + sub-agent processes" approach: the script outputs raw markdown with SRT timestamps, and the agent delegates speaker labeling and chapter segmentation to a cost-effective model sub-agent.

skills/baoyu-youtube-transcript/SKILL.md
spawn a sub-agent (use a cheaper model like Sonnet for cost efficiency)
The prompt template is located in prompts/speaker-transcript.md, strictly requiring verbatim fidelity, merging existing SRT timestamps into paragraphs, and prefixing paragraphs with **Speaker Name:**.

The cache serves as the data surface: the initial run outputs meta.json + transcript-raw.json + transcript-sentences.json + imgs/cover.jpg, while `.index.json` maintains the videoId-to-directory mapping, enabling zero network requests for subsequent runs on the same video.

skills/baoyu-youtube-transcript/scripts/storage.ts
return existsSync(join(videoDir, "meta.json")) && existsSync(join(videoDir, "transcript-raw.json"));
Changing languages or passing --refresh forces a re-fetch; SRT is generated from raw snippets, while markdown uses sentences, allowing a single cache to power both rendering formats.

Text output consists of "sentences" rather than raw snippets: split by punctuation, with timestamps allocated proportionally based on character length, and CJK text merged.

skills/baoyu-youtube-transcript/SKILL.md
split by sentence-ending punctuation (`.?!…。?!` etc.), timestamps proportionally allocated by character length, CJK-aware text merging
This explains why its markdown output is significantly more readable than raw subtitles: paragraph boundaries are defined by full sentences rather than short cue chunks lasting a few seconds.

2Core Capabilities

01Fetches subtitles by URL or video ID and outputs markdown / SRT (no API key, no browser required)
02Multi-language prioritization and available track listing (--languages / --list)
03Machine-translated subtitle tracks (--translate zh-Hans), utilizing YouTube's native translation tracks
04Chapter segmentation based on timestamps in the video description (--chapters)
05Speaker identification (--speakers): script provides raw material, sub-agent performs verbatim speaker labeling and paragraph splitting
06Fetches and locally caches cover images and metadata (imgs/cover.jpg + meta.json)
07Anti-scraping fallback chain: 3-client identity rotation retry → yt-dlp
08Cache reuse and forced refresh (--refresh / auto-invalidation on language change)

3External Dependencies

KindDependency / Endpoint
apiYouTube InnerTube player API(非公开接口)
networkYouTube watch 页(抓 INNERTUBE_API_KEY / visitorData)
network字幕轨 baseUrl(InnerTube/yt-dlp 返回,fmt=json3/xml)
networkYouTube 缩略图 CDN(封面)
networkconsent.youtube.com 表单(仅字符串匹配,重试用 CONSENT cookie 再请求 watch 页)
cliyt-dlp(直接二进制)
cliuvx --from yt-dlp yt-dlp(免安装形态)
clipython3 -m yt_dlp(已安装模块形态)
clibun / npx -y bun(脚本运行时)
networkyt-dlp --remote-components ejs:github 拉取的 GitHub 远端 EJS 组件

4Recommended Governance & Evidence

Suggested Controls for Safe Operation
For Agent Runtime
Isolated environment, per-use explicit authorization
For Administrators
Strict authorization, full audit, compliance signoff
Evidence & Triggers (File Paths & Excerpts)
  • SKILL.md / 脚本: Invokes unofficial or reverse-engineered private APIs / spoofs client identifiers
  • SKILL.md / 会话存储: Reads or reuses browser user login states and session cookies
  • 本地凭据 / 浏览器配置: Reads user login cookies/sessions/keyrings: process.env.YOUTUBE_TRANSCRIPT_COOKIES_FROM_BROWSER (the only env read in the entire skill) → used as yt-dlp parameter
  • scripts/: Executes local scripts or commands: ${BUN_X} {baseDir}/scripts/main.ts <url|id> (via bun, or npx -y bun; skill directory contains only TS)
  • 网络端点: Declares external network access: https://www.youtube.com/watch?v=<id>&hl=en&persist_hl=1&has_verified=1&bpct
  • 本地工作目录: File I/O and artifact output: youtube-transcript/ (default, configurable via --output-dir)
Audit Notes: (Evaluated at capability/policy level, not malicious code injection: code is clean, readable, un-obfuscated, lacks hardcoded secrets, and has no exfiltration to unexpected destinations). Three grounds for Red rating: ① [Reverse Engineering / Impersonation] Bypasses official Data API by crafting custom requests to youtubei/v1/player, regex-extracting INNERTUBE_API_KEY from watch page HTML on each run ('const apiKey = html.match(/"INNERTUBE_API_KEY":\s*"([a-zA-Z0-9_-]+)"/)?.[1];'), and spoofing official clients via ANDROID / IOS / WEB identities and mobile UAs to bypass bot detection (verbatim UA: 'com.google.android.youtube/20.10.38 (Linux; U; Android 14; en_US; Pixel 8 Pro; Build/AP1A.240405.002)'). ② [Credential Surface] The skill's built-in logic passes YOUTUBE_TRANSCRIPT_COOKIES_FROM_BROWSER through to yt-dlp --cookies-from-browser, delegating access to third-party CLIs to read local browser cookie stores and egress with active user sessions; context: guarded by an env flag, delegated to third-party tools, does not use CDP, and does not persist tokens to disk. ③ [Third-Party CLI Bootstrapping] Fallback path invokes uvx --from yt-dlp yt-dlp / python3 -m yt_dlp on demand, fetching and executing remote GitHub components via --js-runtimes bun --remote-components ejs:github, while SKILL.md directs the agent to acquire missing dependencies automatically without prompting the user. Benchmark comparison: bilibili-source was rated Orange solely for "touching cookies"; this skill triggers both reverse-engineered spoofing and credential delegation, warranting Red. The default path (without env configured) only touches fixed public endpoints without credentials (inherently Yellow); per site capability-level security paradigms, the capability ceiling determines the rating tier.

5Second-Pass Verification

  • [ok] InnerTube 端点与 key 现场抓取(无硬编码 key) — youtube.ts 含 INNERTUBE_URL/WATCH_URL 常量与 html.match(/"INNERTUBE_API_KEY":...) 抓取逻辑;全仓无硬编码 API key,只有会随版本过期的客户端版本号与 UA 常量。
  • [ok] 三套客户端身份轮换(ANDROID/WEB/IOS)+ 对应头 — clientName "ANDROID"/"WEB"/"IOS"、X-YouTube-Client-Name / X-YouTube-Client-Version / X-Goog-Visitor-Id 头与 Pixel 8 Pro UA 均在源码中;与 SKILL.md 的『bot detected』说明一致。
  • [ok] yt-dlp 回退的探测与参数 — 三个候选命令(yt-dlp / uvx / python3 -m yt_dlp),--version 探测后还要 --help 命中 --js-runtimes 与 --remote-components;执行参数为 -J --skip-download --js-runtimes bun --remote-components ejs:github(可选 --cookies-from-browser)。
  • [ok] --translate 无任何外部翻译服务 — 只有 url += `&tlang=${translateTo}` 与 isTranslatable / translationLanguages 前置检查;无 Google Translate / LLM / HTTP 翻译调用,依赖面为零 npm 包。
  • [ok] 零 npm 依赖、skill 内无 package.json — skill 目录仅 .ts 与 prompt 模板;全部 import 为 node 内置(fs/path/child_process/node:test/node:assert)与相对 .ts;根 package.json 的 workspaces 只覆盖 packages/*。
  • [ok] 全 skill 唯一 env 读取 = YOUTUBE_TRANSCRIPT_COOKIES_FROM_BROWSER — 跨目录 grep process.env / env[ / YOUTUBE_ 仅命中该变量(读取一处、拼参数一处);未设置时回退路径不带 cookie,故凭证面为『闸门 + 委派』而非默认开启。
  • [ok] 写盘清单与 SKILL.md 输出树一致 — 代码写入 .index.json / meta.json / transcript-raw.json / transcript-sentences.json / imgs/cover.jpg / transcript.md|.srt,与 SKILL.md 目录树逐项对齐;不落盘任何 token。
  • [ok] 文档与代码的次要出入 — SKILL.md 工作流小节出现两个编号为 3 的步骤(文档笔误,不影响结论);--speakers 隐含 --chapters 的说明与代码分支一致。

6Verdict & Scenarios

  • Zero dependencies and zero build steps: runs purely on bun + Node.js built-in modules, ready to run immediately upon cloning with virtually zero supply chain surface.
  • Retrieves subtitles without requiring an API key or browser, turning anti-scraping blocks into a recoverable path (identity rotation → yt-dlp).
  • Superior output quality over raw subtitles: punctuation-based sentence splitting + chapters + speaker labeling + combinable timestamps, with markdown and SRT sharing a single source.
  • Cache-first data surface: re-formatting after initial fetch (e.g., text then SRT) requires zero network calls, saving time and staying friendly to YouTube.
  • Well-disciplined documentation: clearly documents zsh quoting caveats, optional cookie environment variables, and error code handling.
  • Best for: Ideal for individuals and content teams converting YouTube interviews, lectures, and podcasts into readable transcripts and subtitles: needing long-form markdown, SRT for media players, chapter and speaker annotations, or bilingual machine-translated references, all while avoiding redundant network calls for repeated processing of the same video. Ready out of the box in a Bun environment; best suited for personal use with full awareness of its reverse-engineering, client spoofing, and optional cookie delegation behavior.
    Not for: Not suitable for compliance-sensitive enterprise environments or high-privacy setups (involves client identity spoofing, optional browser cookie delegation, and remote component fetching); not suitable for production pipelines requiring stable, guaranteed official API SLAs; not suitable for feeding unverified remote video text directly into agents with write permissions without human review; not suitable for downloading video files themselves (this skill only extracts subtitles and cover images).
    Install Agent-Ready
    ① Verified Mirror 2026-09-15
    Option A · Direct DownloadDownload baoyu-youtube-transcript.tar.gz
    sha256: dbf11afd644a4963…
    Option B · Copy Guide for Agent
    install.json
    Agents automatically download and verify mirrors from this JSON guide.
    ② Upstream GitHub
    GitHub Repo ↗
    Pinned to commit 1567581c26.