youtube-transcript について
youtube-transcriptは、YouTube動画の字幕を取得して整形済みテキストとして保存するスキルです。DeepAPIを優先し、代替手段としてyt-dlpを使えます。タイムスタンプ付き区間にも対応します。
主な機能
- 01DeepAPI経由の字幕取得
- 02yt-dlpによる代替取得
- 03整形済み字幕テキストの保存
- 04タイムスタンプ付き区間の取得
- 05字幕言語の指定
活用シーン
- 01動画字幕のプロジェクトへの保存
- 02確認用字幕テキストの作成
- 03タイムスタンプ付き区間の取得
- 04DeepAPIが使えない場合の字幕取得
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ davidondrej/ skills --skill youtube-transcriptインストール後、Claude Code で/youtube-transcriptを入力して読み込まれたか確認します。
詳細
YouTube の文字起こし(DeepAPI 経由、yt-dlp にフォールバック)
YouTube 動画の文字起こしを取得し、整形済みのプレーンな .txt ファイルとして保存します。通常は DeepAPI の POST /v1/scrape/youtube/transcript を使用します。サーバー側で実行されるため、yt-dlp で頻発するローカル IP のボット判定を回避できます。
保存先
- ユーザーが実際のプロジェクト/作業ディレクトリにいる場合 → そこに保存します。
- それ以外(ディレクトリの指定がない場合、または現在の作業ディレクトリが適切でない場合) →
~/Downloadsに保存します。 - ファイル名は必ず
Channel_Titleとし、スペースは_に置き換えます(例:David_Ondrej_title_of_video.txt)。メタデータを取得できない場合は、動画 ID を使用します。
通常の方法 — DeepAPI
環境変数からキーを読み込みます。セットアップ時にキーは ~/.deepapi/env に書き込まれます。~/.zshrc は決して source しないでください(シェルが壊れ、終了コード 126 になります)。
[ -n "$DEEPAPI_API_KEY" ] || . ~/.deepapi/env
KEY=$DEEPAPI_API_KEY
BASE=${DEEPAPI_API_BASE_URL:-https://deepapi.co}
スクレイピングを実行します(Idempotency-Key は保持してください。再試行時も必ず同じキーを使用します)。
IDK=$(uuidgen)
curl -s --max-time 120 "$BASE/v1/scrape/youtube/transcript" \
-H "Authorization: Bearer $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"を実行します。succeededまたはfailedになるまで繰り返します。
テキストを抽出して保存します。
jq -r '.status' /tmp/yt_transcript.json # succeeded | running | failed
jq -r '.output[0].text' /tmp/yt_transcript.json > "$OUT/$NAME.txt"
.output[0].segments には、タイムスタンプ付きのセグメント(startSecs、durationSecs、text)も含まれています。ユーザーがタイムスタンプを希望する場合は、これを使用します。output が空の場合、動画に字幕がありません。再試行せず、その旨を伝えてください。
ファイル名 Channel_Title を決めるには、yt-dlp --print "%(channel)s|%(title)s" --skip-download "URL" を実行してメタデータを取得します。失敗した場合は、動画 ID を使用します。
yt-dlp にフォールバックする条件
DEEPAPI_API_KEYが設定されておらず、~/.deepapi/envも存在しない場合。- HTTP 402
insufficient_creditsが返された場合(まず deepapi.co/credits でクレジットを追加するようユーザーに伝え、利用できない場合に限りフォールバックします)。 - DeepAPI リクエストが 2 回失敗した場合。
フォールバックする際は、必ずユーザーに伝えてください。フォールバックは、DeepAPI が実際のユースケースに対応できなかったことを意味します。
フォールバック方法 — yt-dlp(ローカル)
OUT="$(pwd)" # or ~/Downloads if cwd makes no sense
META=$(yt-dlp --print "%(channel)s|%(title)s" --skip-download "URL")
NAME=$(echo "$META" | tr '| ' '__' | tr -cd '[:alnum:]_.-') # "Channel_Title", spaces -> _, strip unsafe chars
yt-dlp --skip-download --write-subs --write-auto-subs \
--sub-langs "en.*" --sub-format json3 \
-o "$OUT/$NAME.%(ext)s" "URL"
channelが null の場合は、channel→uploader→uploader_idの順に使用します。--skip-download= 字幕のみを取得します。--write-subs+--write-auto-subs= 手動字幕を優先し、利用できない場合は自動字幕を使います。- 必ず
json3を使用し、VTT/SRT は使用しないでください。自動生成の VTT は各行を 2 回繰り返します(ローリング字幕)。
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 では、YouTube から抽出する際に
denoを PATH に追加する必要がある場合があります。 - 最初に失敗した場合は、
yt-dlp -Uを 1 回実行してから、1 回だけ再試行し、その後は停止します。 - 429/「Sign in to confirm you're not a bot」 = IP がブロックされています。停止してください。ループして再試行してはいけません(状況が悪化します)。
- ユーザーから明示的に依頼された場合を除き、Whisper 用に音声をダウンロードする方法へフォールバックしないでください。
出力
保存先のパスを伝えます。短い場合はテキストも出力します。ユーザーに求められない限り、費用は伝えないでください。