[{"data":1,"prerenderedAt":572},["ShallowReactive",2],{"content-/youtube-javascript-challenge":3,"all-pages-for-dir":550,"related-/youtube-javascript-challenge":551,"og-image-/youtube-javascript-challenge":571},{"id":4,"title":5,"body":6,"category":535,"concepts":535,"description":536,"extension":537,"meta":538,"navigation":539,"ogImage":535,"path":540,"project_name":535,"published":541,"publishedAt":542,"seo":543,"source":535,"stem":544,"tags":545,"todo":535,"unpublished":541,"updatedAt":542,"__hash__":549},"pages/2025-12/2025-12-22/youtube-javascript-challenge.md","YouTubeのJavaScriptチャレンジ（n challenge）とは",{"type":7,"value":8,"toc":508},"minimark",[9,13,17,20,25,41,45,72,82,86,100,103,109,115,119,133,136,143,177,180,194,197,203,214,218,244,247,307,311,315,321,327,331,357,361,423,429,440,444,458,462,469,472,504],[10,11,12],"h2",{"id":12},"背景",[14,15,16],"p",{},"ボットや自動ダウンロードツールを防ぐため、YouTubeは動画のストリーミングURLを保護するJavaScriptベースの「チャレンジ」を導入している。",[10,18,19],{"id":19},"仕組み",[21,22,24],"h3",{"id":23},"_1-通常のブラウザでのアクセス","1. 通常のブラウザでのアクセス",[26,27,28,32,35,38],"ol",{},[29,30,31],"li",{},"ユーザーがYouTube動画ページにアクセス",[29,33,34],{},"YouTubeサーバーがJavaScriptコードを送信",[29,36,37],{},"ブラウザがJavaScriptを実行し、「署名」を生成",[29,39,40],{},"この署名付きのURLで動画をストリーミング",[21,42,44],{"id":43},"_2-n-challengeとは","2. n challengeとは",[46,47,48,56,66,69],"ul",{},[29,49,50,51,55],{},"YouTubeの動画URLには ",[52,53,54],"code",{},"n"," というパラメータが含まれる",[29,57,58,59,61,62],{},"この ",[52,60,54],{}," パラメータは",[63,64,65],"strong",{},"暗号化されたチャレンジ値",[29,67,68],{},"正しく「解読」しないと、動画URLが無効になる（403 Forbiddenエラー）",[29,70,71],{},"解読にはYouTubeが送ってくるJavaScriptコードを実行する必要がある",[73,74,79],"pre",{"className":75,"code":77,"language":78},[76],"language-text","動画URL例:\nhttps://rr1---sn-xxx.googlevideo.com/videoplayback?...&n=暗号化された値&...\n                                                      ↑\n                                            これを解読する必要がある\n","text",[52,80,77],{"__ignoreMap":81},"",[21,83,85],{"id":84},"_3-なぜyt-dlpで問題になるか","3. なぜyt-dlpで問題になるか",[46,87,88,91,94,97],{},[29,89,90],{},"yt-dlpはPythonで書かれている",[29,92,93],{},"YouTubeのチャレンジはJavaScriptで書かれている",[29,95,96],{},"PythonだけではJavaScriptを実行できない",[29,98,99],{},"→ JavaScriptランタイム（Node.js、Deno等）が必要",[10,101,102],{"id":102},"エラーメッセージの意味",[73,104,107],{"className":105,"code":106,"language":78},[76],"WARNING: [youtube] kS8r7UcexJU: n challenge solving failed: Some formats may be missing.\n",[52,108,106],{"__ignoreMap":81},[14,110,111,114],{},[63,112,113],{},"意味",": n challengeの解読に失敗したため、一部（または全部）の動画フォーマットが取得できない",[21,116,118],{"id":117},"なぜ一部なのか","なぜ「一部」なのか",[46,120,121,124,127,130],{},[29,122,123],{},"YouTubeには複数のフォーマット（画質・音質）がある",[29,125,126],{},"高画質の動画フォーマット → n challengeで保護されている",[29,128,129],{},"低品質の音声フォーマット → 保護が緩い場合がある",[29,131,132],{},"→ 音声だけダウンロードできて、動画がダウンロードできない現象が起きる",[10,134,135],{"id":135},"解決策",[21,137,139,142],{"id":138},"remote-components-ejsgithub-オプション",[52,140,141],{},"--remote-components ejs:github"," オプション",[73,144,148],{"className":145,"code":146,"language":147,"meta":81,"style":81},"language-bash shiki shiki-themes vitesse-light vitesse-light","yt-dlp --remote-components ejs:github \"URL\"\n","bash",[52,149,150],{"__ignoreMap":81},[151,152,155,159,163,167,171,174],"span",{"class":153,"line":154},"line",1,[151,156,158],{"class":157},"senZ8","yt-dlp",[151,160,162],{"class":161},"snbK4"," --remote-components",[151,164,166],{"class":165},"sdGka"," ejs:github",[151,168,170],{"class":169},"sMJiu"," \"",[151,172,173],{"class":165},"URL",[151,175,176],{"class":169},"\"\n",[14,178,179],{},"このオプションは：",[26,181,182,185,188,191],{},[29,183,184],{},"GitHubから「チャレンジソルバースクリプト」をダウンロード",[29,186,187],{},"Deno（JavaScriptランタイム）を使ってスクリプトを実行",[29,189,190],{},"n challengeを解読",[29,192,193],{},"正しい動画URLを取得",[21,195,196],{"id":196},"ダウンロードされるもの",[73,198,201],{"className":199,"code":200,"language":78},[76],"[youtube] [jsc:deno] Downloading challenge solver lib script from\nhttps://github.com/yt-dlp/ejs/releases/download/0.3.2/yt.solver.lib.min.js\n",[52,202,200],{"__ignoreMap":81},[46,204,205,211],{},[29,206,207,210],{},[52,208,209],{},"ejs"," = Embedded JavaScript solver",[29,212,213],{},"yt-dlpプロジェクトが管理しているチャレンジソルバー",[10,215,217],{"id":216},"youtubeがこれをする理由","YouTubeがこれをする理由",[26,219,220,226,232,238],{},[29,221,222,225],{},[63,223,224],{},"著作権保護"," - 動画の不正ダウンロードを防ぐ",[29,227,228,231],{},[63,229,230],{},"帯域制御"," - ボットによる大量アクセスを防ぐ",[29,233,234,237],{},[63,235,236],{},"広告収入保護"," - ダウンロードされると広告が見られない",[29,239,240,243],{},[63,241,242],{},"いたちごっこ"," - YouTubeは定期的にチャレンジを更新する → yt-dlpも更新が必要",[10,245,246],{"id":246},"まとめ",[248,249,250,263],"table",{},[251,252,253],"thead",{},[254,255,256,260],"tr",{},[257,258,259],"th",{},"用語",[257,261,262],{},"説明",[264,265,266,275,283,290,298],"tbody",{},[254,267,268,272],{},[269,270,271],"td",{},"n challenge",[269,273,274],{},"YouTubeの動画URL保護機構",[254,276,277,280],{},[269,278,279],{},"チャレンジソルバー",[269,281,282],{},"n challengeを解読するスクリプト",[254,284,285,287],{},[269,286,209],{},[269,288,289],{},"yt-dlpが提供するチャレンジソルバー",[254,291,292,295],{},[269,293,294],{},"Deno",[269,296,297],{},"JavaScriptを実行するランタイム",[254,299,300,304],{},[269,301,302],{},[52,303,141],{},[269,305,306],{},"GitHubからソルバーをダウンロードして使うオプション",[10,308,310],{"id":309},"_2025年11月以降の重要な変更","2025年11月以降の重要な変更",[21,312,314],{"id":313},"外部jsランタイム必須化","外部JSランタイム必須化",[14,316,317,320],{},[63,318,319],{},"yt-dlp 2025.11.12","からYouTubeの完全サポートには外部JavaScriptランタイムが必須になった。",[73,322,325],{"className":323,"code":324,"language":78},[76],"WARNING: [youtube] JavaScript runtime now required for full YouTube support\n",[52,326,324],{"__ignoreMap":81},[328,329,330],"h4",{"id":330},"なぜこの変更が必要だったか",[26,332,333,339,345,351],{},[29,334,335,338],{},[63,336,337],{},"従来のアプローチ",": yt-dlpは巨大な正規表現パターンでJSチャレンジを解読していた",[29,340,341,344],{},[63,342,343],{},"問題点",": YouTubeの難読化が複雑化し、正規表現では対応困難に",[29,346,347,350],{},[63,348,349],{},"新アプローチ",": AST（抽象構文木）ベースのパターンマッチングに移行",[29,352,353,356],{},[63,354,355],{},"結果",": player.jsの変更により迅速に対応可能に",[21,358,360],{"id":359},"サポートされているjsランタイム","サポートされているJSランタイム",[248,362,363,376],{},[251,364,365],{},[254,366,367,370,373],{},[257,368,369],{},"ランタイム",[257,371,372],{},"デフォルト",[257,374,375],{},"備考",[264,377,378,393,404,414],{},[254,379,380,384,387],{},[269,381,382],{},[63,383,294],{},[269,385,386],{},"✅ 有効",[269,388,389,392],{},[63,390,391],{},"推奨","。完全にサンドボックス化、ネットワーク/ファイルアクセスなし",[254,394,395,398,401],{},[269,396,397],{},"Node.js",[269,399,400],{},"❌ 無効",[269,402,403],{},"セキュリティ上の理由でデフォルト無効",[254,405,406,409,411],{},[269,407,408],{},"QuickJS",[269,410,400],{},[269,412,413],{},"パフォーマンス面で推奨される場合も",[254,415,416,419,421],{},[269,417,418],{},"Bun",[269,420,400],{},[269,422,403],{},[14,424,425,428],{},[63,426,427],{},"Denoが推奨される理由",":",[46,430,431,434,437],{},[29,432,433],{},"単一の実行ファイルでポータブル",[29,435,436],{},"完全にサンドボックス化されている",[29,438,439],{},"ネットワークやファイルシステムへのアクセスが一切ない",[21,441,443],{"id":442},"jsランタイムなしの場合","JSランタイムなしの場合",[46,445,446,449,452,455],{},[29,447,448],{},"現時点では「一応」動作する",[29,450,451],{},"ただし利用可能なフォーマットが大幅に制限される",[29,453,454],{},"ログイン状態では特に制限が厳しい",[29,456,457],{},"今後さらに悪化する見込み（バグではなく仕様）",[21,459,461],{"id":460},"今後の懸念-poproof-of-originトークン","今後の懸念: PO（Proof-of-Origin）トークン",[14,463,464,465,468],{},"YouTubeはすべてのプレイヤークライアントに対して",[63,466,467],{},"POトークン","の要求を強化しています。これへの対応にも、ネイティブのjsinterpモジュールでは不可能なJavaScript機能が必要になる見込みです。",[10,470,471],{"id":471},"参考リンク",[46,473,474,483,490,497],{},[29,475,476],{},[477,478,482],"a",{"href":479,"rel":480},"https://github.com/yt-dlp/yt-dlp/wiki/EJS",[481],"nofollow","yt-dlp EJS Wiki",[29,484,485],{},[477,486,489],{"href":487,"rel":488},"https://github.com/yt-dlp/ejs/releases",[481],"yt-dlp ejs リリース",[29,491,492],{},[477,493,496],{"href":494,"rel":495},"https://github.com/yt-dlp/yt-dlp/issues/15012",[481],"Announcement: External JavaScript runtime now required",[29,498,499],{},[477,500,503],{"href":501,"rel":502},"https://github.com/yt-dlp/yt-dlp/issues/14404",[481],"Upcoming new requirements for YouTube downloads",[505,506,507],"style",{},"html pre.shiki code .senZ8, html code.shiki .senZ8{--shiki-default:#59873A;--shiki-dark:#59873A}html pre.shiki code .snbK4, html code.shiki .snbK4{--shiki-default:#A65E2B;--shiki-dark:#A65E2B}html pre.shiki code .sdGka, html code.shiki .sdGka{--shiki-default:#B56959;--shiki-dark:#B56959}html pre.shiki code .sMJiu, html code.shiki .sMJiu{--shiki-default:#B5695977;--shiki-dark:#B5695977}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":81,"searchDepth":509,"depth":509,"links":510},2,[511,512,518,521,526,527,528,534],{"id":12,"depth":509,"text":12},{"id":19,"depth":509,"text":19,"children":513},[514,516,517],{"id":23,"depth":515,"text":24},3,{"id":43,"depth":515,"text":44},{"id":84,"depth":515,"text":85},{"id":102,"depth":509,"text":102,"children":519},[520],{"id":117,"depth":515,"text":118},{"id":135,"depth":509,"text":135,"children":522},[523,525],{"id":138,"depth":515,"text":524},"--remote-components ejs:github オプション",{"id":196,"depth":515,"text":196},{"id":216,"depth":509,"text":217},{"id":246,"depth":509,"text":246},{"id":309,"depth":509,"text":310,"children":529},[530,531,532,533],{"id":313,"depth":515,"text":314},{"id":359,"depth":515,"text":360},{"id":442,"depth":515,"text":443},{"id":460,"depth":515,"text":461},{"id":471,"depth":509,"text":471},null,"YouTubeの動画URL保護機構であるn challengeの仕組みと、yt-dlpでの解決策について解説","md",{},true,"/youtube-javascript-challenge",false,"2025-12-22T00:00:00.000Z",{"title":5,"description":536},"2025-12/2025-12-22/youtube-javascript-challenge",[546,158,547,548],"YouTube","JavaScript","技術解説","MLoY8gp1JqB9EwO2NRcfyIYN2VXv6B27TJtB9fDEEbA",[],[552,556,560,564,568],{"title":553,"path":554,"publishedAt":555},"YouTube動画分析ダッシュボード構築 -- yt-dlpメタデータ取得からコメント分析・Miller Column UIまで","/youtube-analytics-dashboard-2026-02-14","2026-02-14T00:00:00.000Z",{"title":557,"path":558,"publishedAt":559},"開発環境のバックアップを仕上げ、復旧手順をスキル化してGitHubで版管理する","/claude-env-backup-and-restore-skill","2026-07-30T00:00:00.000Z",{"title":561,"path":562,"publishedAt":563},"会計ソフトA内部APIハンズオン3記事のスタイル統一と実機検証","/mf-internal-api-handson-live-verification","2026-06-21T00:00:00.000Z",{"title":565,"path":566,"publishedAt":567},"2026年6月9日の開発日記 - SK Hynixの月次代理指標チャートとGSC機会キーワード即日対応","/2026-06-09-diary","2026-06-09T00:00:00.000Z",{"title":569,"path":570,"publishedAt":567},"IIFE（即時実行関数式）とは何か ― なぜ昔は使われ、今ES Modules時代に減ったのか","/iife-immediately-invoked-function-expression","https://log.eurekapu.com/og/blog/youtube-javascript-challenge.png?v=2025-12-22T00%3A00%3A00.000Z&title=YouTube%E3%81%AEJavaScript%E3%83%81%E3%83%A3%E3%83%AC%E3%83%B3%E3%82%B8%EF%BC%88n%20challenge%EF%BC%89%E3%81%A8%E3%81%AF&author=Kei%20Komatsu&sig=ea7ee2f120da1508",1785654685619]