• #YouTube
  • #yt-dlp
  • #JavaScript
  • #技術解説
未分類

背景

ボットや自動ダウンロードツールを防ぐため、YouTubeは動画のストリーミングURLを保護するJavaScriptベースの「チャレンジ」を導入している。

仕組み

1. 通常のブラウザでのアクセス

  1. ユーザーがYouTube動画ページにアクセス
  2. YouTubeサーバーがJavaScriptコードを送信
  3. ブラウザがJavaScriptを実行し、「署名」を生成
  4. この署名付きのURLで動画をストリーミング

2. n challengeとは

  • YouTubeの動画URLには n というパラメータが含まれる
  • この n パラメータは暗号化されたチャレンジ値
  • 正しく「解読」しないと、動画URLが無効になる(403 Forbiddenエラー)
  • 解読にはYouTubeが送ってくるJavaScriptコードを実行する必要がある
動画URL例:
https://rr1---sn-xxx.googlevideo.com/videoplayback?...&n=暗号化された値&...
                                                      ↑
                                            これを解読する必要がある

3. なぜyt-dlpで問題になるか

  • yt-dlpはPythonで書かれている
  • YouTubeのチャレンジはJavaScriptで書かれている
  • PythonだけではJavaScriptを実行できない
  • → JavaScriptランタイム(Node.js、Deno等)が必要

エラーメッセージの意味

WARNING: [youtube] kS8r7UcexJU: n challenge solving failed: Some formats may be missing.

意味: n challengeの解読に失敗したため、一部(または全部)の動画フォーマットが取得できない

なぜ「一部」なのか

  • YouTubeには複数のフォーマット(画質・音質)がある
  • 高画質の動画フォーマット → n challengeで保護されている
  • 低品質の音声フォーマット → 保護が緩い場合がある
  • → 音声だけダウンロードできて、動画がダウンロードできない現象が起きる

解決策

--remote-components ejs:github オプション

yt-dlp --remote-components ejs:github "URL"

このオプションは:

  1. GitHubから「チャレンジソルバースクリプト」をダウンロード
  2. Deno(JavaScriptランタイム)を使ってスクリプトを実行
  3. n challengeを解読
  4. 正しい動画URLを取得

ダウンロードされるもの

[youtube] [jsc:deno] Downloading challenge solver lib script from
https://github.com/yt-dlp/ejs/releases/download/0.3.2/yt.solver.lib.min.js
  • ejs = Embedded JavaScript solver
  • yt-dlpプロジェクトが管理しているチャレンジソルバー

YouTubeがこれをする理由

  1. 著作権保護 - 動画の不正ダウンロードを防ぐ
  2. 帯域制御 - ボットによる大量アクセスを防ぐ
  3. 広告収入保護 - ダウンロードされると広告が見られない
  4. いたちごっこ - YouTubeは定期的にチャレンジを更新する → yt-dlpも更新が必要

まとめ

用語説明
n challengeYouTubeの動画URL保護機構
チャレンジソルバーn challengeを解読するスクリプト
ejsyt-dlpが提供するチャレンジソルバー
DenoJavaScriptを実行するランタイム
--remote-components ejs:githubGitHubからソルバーをダウンロードして使うオプション

2025年11月以降の重要な変更

外部JSランタイム必須化

yt-dlp 2025.11.12からYouTubeの完全サポートには外部JavaScriptランタイムが必須になった。

WARNING: [youtube] JavaScript runtime now required for full YouTube support

なぜこの変更が必要だったか

  1. 従来のアプローチ: yt-dlpは巨大な正規表現パターンでJSチャレンジを解読していた
  2. 問題点: YouTubeの難読化が複雑化し、正規表現では対応困難に
  3. 新アプローチ: AST(抽象構文木)ベースのパターンマッチングに移行
  4. 結果: player.jsの変更により迅速に対応可能に

サポートされているJSランタイム

ランタイムデフォルト備考
Deno✅ 有効推奨。完全にサンドボックス化、ネットワーク/ファイルアクセスなし
Node.js❌ 無効セキュリティ上の理由でデフォルト無効
QuickJS❌ 無効パフォーマンス面で推奨される場合も
Bun❌ 無効セキュリティ上の理由でデフォルト無効

Denoが推奨される理由:

  • 単一の実行ファイルでポータブル
  • 完全にサンドボックス化されている
  • ネットワークやファイルシステムへのアクセスが一切ない

JSランタイムなしの場合

  • 現時点では「一応」動作する
  • ただし利用可能なフォーマットが大幅に制限される
  • ログイン状態では特に制限が厳しい
  • 今後さらに悪化する見込み(バグではなく仕様)

今後の懸念: PO(Proof-of-Origin)トークン

YouTubeはすべてのプレイヤークライアントに対してPOトークンの要求を強化しています。これへの対応にも、ネイティブのjsinterpモジュールでは不可能なJavaScript機能が必要になる見込みです。

参考リンク