YouTube トランスクリプト
YouTube動画の字幕(サブタイトル/キャプション)をダウンロードします。手動作成された字幕と自動生成された字幕の両方に対応。APIキーやブラウザは不要 — YouTubeのInnerTube APIを直接使用し、直接APIパスがブロックされた場合は自動的にyt-dlpにフォールバックします。
初回実行時に動画のメタデータとカバー画像を取得し、生データをキャッシュして高速な再フォーマットを可能にします。
スクリプトディレクトリ
スクリプトは scripts/ サブディレクトリにあります。{baseDir} = この SKILL.md のディレクトリパス。${BUN_X} ランタイムの解決方法: bun がインストールされている場合 → bun; npx が利用可能な場合 → npx -y bun; それ以外の場合は bun のインストールを提案します。{baseDir} と ${BUN_X} を実際の値に置き換えてください。
| スクリプト | 目的 |
|---|---|
scripts/main.ts | トランスクリプトダウンロードCLI |
使い方
# デフォルト: タイムスタンプ付きマークダウン (英語)
${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のURLまたは動画ID (複数指定可) | 必須 |
--languages <codes> | 言語コード、カンマ区切り、優先順 | en |
--format <fmt> | 出力形式: text, srt | text |
--translate <code> | 指定された言語コードに翻訳 | |
--list | トランスクリプトの一覧表示 (取得はしない) | |
--timestamps | 段落ごとに [HH:MM:SS → HH:MM:SS] のタイムスタンプを含める | on |
--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 |
入力形式
動画入力として以下を受け付けます:
- 完全なURL:
https://www.youtube.com/watch?v=dQw4w9WgXcQ - 短縮URL:
https://youtu.be/dQw4w9WgXcQ - 埋め込みURL:
https://www.youtube.com/embed/dQw4w9WgXcQ - ショートURL:
https://www.youtube.com/shorts/dQw4w9WgXcQ - 動画ID:
dQw4w9WgXcQ
出力形式
| 形式 | 拡張子 | 説明 |
|---|---|---|
text | .md | フロントマター(descriptionを含む)、タイトル見出し、要約、オプションの目次/カバー/タイムスタンプ/チャプター/話者付きマークダウン |
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 # マークダウントランスクリプト (文から生成)
└── 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" }[])、文末の句読点 (.?!…。?!など) で分割、タイムスタンプは文字数に比例して割り当て、CJK対応のテキストマージimgs/cover.jpg— 動画サムネイル
同じ動画の後続の実行ではキャッシュデータを使用します (ネットワーク呼び出しなし)。再取得を強制するには --refresh を使用します。異なる言語が要求された場合、キャッシュは自動的に更新されます。
YouTubeが直接InnerTubeパスでアンチボット/ブロック応答を返す場合、スクリプトは代替クライアントIDで再試行し、その後利用可能であれば yt-dlp にフォールバックします。フォールバックが必要だが yt-dlp が利用できない場合、エージェントは yt-dlp を利用可能にする方法を自己判断し、ユーザーにインストールの決定を押し付けるのではなく続行する必要があります。
SRT出力 (--format srt) は transcript-raw.json から生成されます。テキスト/マークダウン出力では、自然な文の区切りに transcript-sentences.json を使用します。
ワークフロー
ユーザーがYouTube URLを提供し、トランスクリプトを希望する場合:
- ユーザーが言語を指定していない場合は、最初に
--listを実行して利用可能なオプションを表示します - スクリプト実行時は 常にURLをシングルクォートで囲む — zshは
?をグロブのワイルドカードとして扱うため、クォートなしのYouTube URLは "no matches found" を引き起こします:'https://www.youtube.com/watch?v=ID'を使用します - デフォルト: 最もリッチな出力のために
--chapters --speakersを付けて実行します (チャプター + 話者識別) - スクリプトはキャッシュデータと出力ファイルを自動保存し、ファイルパスを表示します
--speakersモードの場合: スクリプトが生ファイルを保存した後、以下の話者識別ワークフローに従って話者ラベルで後処理します
ユーザーがカバー画像またはメタデータのみを希望する場合、任意のオプションでスクリプトを実行すると、meta.json と imgs/cover.jpg もキャッシュされます。
同じ動画を再フォーマットする場合 (例: 最初にテキスト、次にSRT)、キャッシュデータが再利用されます — 再取得は不要です。
チャプターと話者ワークフロー
チャプター (--chapters)
スクリプトは動画説明からチャプターのタイムスタンプ (例: 0:00 Introduction) を解析し、チャプター境界でトランスクリプトを分割、スニペットを読みやすい段落にグループ化し、目次付きの .md として保存します。これ以上の処理は不要です。
説明にチャプターのタイムスタンプが存在しない場合、トランスクリプトはチャプター見出しなしのグループ化された段落として出力されます。
話者識別 (--speakers)
話者識別にはAI処理が必要です。スクリプトは以下の内容を含む生の .md ファイルを出力します:
- 動画メタデータ (タイトル、チャンネル、日付、カバー、説明、言語) を含むYAMLフロントマター
- 話者名抽出のための動画説明
- 説明からのチャプターリスト (利用可能な場合)
- SRT形式の生トランスクリプト (事前計算された開始/終了タイムスタンプ、トークン効率的)
スクリプトが生ファイルを保存した後、サブエージェントを起動し (コスト効率のためにSonnetなどの安価なモデルを使用)、話者識別を処理します:
- 保存された
.mdファイルを読み取る {baseDir}/prompts/speaker-transcript.mdのプロンプトテンプレートを読み取る- プロンプトに従って生トランスクリプトを処理:
- 動画メタデータを使用して話者を識別 (タイトル → ゲスト、チャンネル → ホスト、説明 → 名前)
- 会話の流れ、質問-回答パターン、文脈上の手がかりから話者のターンを検出
- チャプターに分割 (利用可能な場合は説明のチャプターを使用、なければトピックの移り変わりから作成)
**話者名:**ラベル、段落グループ化 (2-4文)、[HH:MM:SS → HH:MM:SS]タイムスタンプでフォーマット
- 処理済みトランスクリプトで
.mdファイルを上書き (YAMLフロントマターは保持)
--speakers を使用すると、--chapters が暗黙的に有効になります — 処理された出力には常にチャプター分割が含まれます。
エラーケース
| エラー | 意味 |
|---|---|
| トランスクリプト無効 | 動画にキャプションがまったくない |
| トランスクリプトが見つかりません | 要求された言語が利用不可 |
| 動画が利用できません | 動画が削除されている、非公開、または地域制限あり |
| IPブロック | リクエストが多すぎます、後で再試行してください |
| 年齢制限 | 動画は年齢確認のためのログインが必要です |
| bot検出 | スクリプトは代替クライアントを再試行し、次に yt-dlp を試します。フォールバックツールが不足している場合、エージェントが自己解決する必要があります。それでも失敗する場合は、YOUTUBE_TRANSCRIPT_COOKIES_FROM_BROWSER=safari (またはお使いのブラウザ) を試してください |


