yt-dlp の Rumble 403 エラーを修正:JSON 取得失敗時にプレーヤーデータへフォールバック
公開日
修正プラグインをダウンロード rumble_player.py
yt-dlp で Rumble の動画をダウンロードするときに Unable to download JSON metadata: HTTP Error 403: Forbidden が出る場合は、この記事の互換プラグインを読み込むことで対処できます。Rumble の embedJS/u3 JSON API が 403 を返すと、プラグインが同じ動画の公式埋め込みプレーヤーページ(/embed/)を取得し、ページ内のメディアデータを読み取ってダウンロードを続行します。
ローカル環境でのプラグイン設定やリンクの変換を省きたい場合は、この修正を組み込んだ当サイトの Rumble 動画ダウンローダーも利用できます。
まず 403 が発生している段階を確認する
Rumble のダウンロードでは、次の 3 つの段階で 403 が発生する可能性があります。この記事のプラグインが対応するのは2 番目です。
| エラーや症状 | 拒否されたリクエスト | 対処法 |
|---|---|---|
Unable to download webpage: HTTP Error 403 |
視聴ページの HTML(issue #15089 を参照) | 公式 oEmbed API で /embed/ URL に変換し、--impersonate firefox を併用します |
Unable to download JSON metadata: HTTP Error 403 |
embedJS/u3 メタデータ API(issue #17496 を参照) |
この記事のプラグインが対応します。/embed/ ページのインラインデータ取得へ自動的に切り替えます |
| 形式一覧は表示されるが、セグメントや MP4 のダウンロード時に 403 が出る | CDN へのメディアストリームのリクエスト | プロキシやリクエストヘッダーを確認するか、別の画質の形式を選択します |
修正の手順
1. プラグインファイルを保存する
作業ディレクトリ内に次の構成でフォルダーを作成し、記事末尾のプラグインの全コードを rumble_player.py として保存します。yt-dlp 本体のソースコードを変更する必要はありません。
plugins/
└── rumble/
└── yt_dlp_plugins/
└── extractor/
└── rumble_player.py
2. 動画の公式 /embed/ URL を取得する
Rumble の視聴ページ URL に含まれる ID(例:v6xxxx)と、埋め込みプレーヤーの ID(例:vb0ofn)は異なります。視聴ページの ID を使って埋め込み URL を組み立てることはできません。通常の視聴ページのリンクしかない場合は、Rumble が公開している公式 oEmbed API を呼び出して、実際の /embed/ URL を取得します。
curl -fsSG --data-urlencode "url=https://rumble.com/your-video.html" "https://rumble.com/api/Media/oembed.json"
返された JSON の html フィールドで <iframe src="https://rumble.com/embed/xxxx/..." を探し、その中の https://rumble.com/embed/xxxx/ を取り出します。
oEmbed が 403 を返す場合は、curl_cffi をインストールし、Firefox のフィンガープリントで再試行します。下の例の URL は、動画の視聴ページの URL 全体に置き換えてください。
python -m pip install curl_cffi
python -c "import sys; from curl_cffi import requests; r = requests.get('https://rumble.com/api/Media/oembed.json', params=dict(url=sys.argv[1]), impersonate='firefox', timeout=15); r.raise_for_status(); print(r.text)" "https://rumble.com/your-video.html"
再試行しても取得できない場合は、オンラインダウンローダーでリンクを自動変換できます。
3. 利用可能な形式を一覧表示し、フォールバックを確認する
plugins フォルダーがあるディレクトリで次のコマンドを実行します。URL は対象動画の /embed/ URL に置き換えてください。
yt-dlp --ignore-config --plugin-dirs ./plugins --no-cache-dir -v -F "https://rumble.com/embed/vb0ofn/"
ログに [RumbleEmbed+PlayerFallback] と表示されれば、プラグインが読み込まれています。
- JSON API が 403 を返した場合は、続けて
Downloading player webpageというログが表示されます。このログは代替経路が開始されたことを示します。データの解析に成功したことを確認するには、その後に形式一覧が表示される必要があります。 - 現在のネットワーク環境で JSON API が 200 を返す場合は、yt-dlp 本来の処理をそのまま使います。プレーヤーページへの追加リクエストは発生しません。
4. 動画をダウンロードし、デコードを検証する
-F で表示された形式 ID(例:mp4-360p)を選んでダウンロードします。
yt-dlp --ignore-config --plugin-dirs ./plugins --no-cache-dir -v --no-playlist -f mp4-360p -o "rumble-test.%(ext)s" "https://rumble.com/embed/vb0ofn/"
実際のテストでフォールバックが動作した際のターミナルログは次のとおりです。
[RumbleEmbed+PlayerFallback] vb0ofn: Downloading JSON metadata
[RumbleEmbed+PlayerFallback] vb0ofn: Downloading player webpage
[info] vb0ofn: Downloading 1 format(s): mp4-360p
[download] 100% of 7.85MiB in 00:01:20 at 99.48KiB/s
ダウンロードした MP4 のコンテナーと映像・音声ストリームに欠損や破損がないか確認するには、ffprobe と ffmpeg を使用します。
ffprobe -v error -show_entries stream=codec_name,codec_type,width,height:format=duration,size -of json "rumble-test.mp4"
ffmpeg -nostdin -v error -xerror -i "rumble-test.mp4" -map 0:v:0 -map "0:a:0?" -f null -
技術的な仕組み:プレーヤーページで JSON の 403 を回避できる理由
1. 同じサイトのインラインデータを再利用する
RumbleEmbedIE は通常、https://rumble.com/embedJS/u3/?request=video&ver=2&v=... に直接リクエストして JSON メタデータを取得します。Cloudflare やサイト側のアクセス制御がこの API だけを拒否し、HTTP 403 を返すと、抽出処理はそこで停止します。
一方、公式埋め込みページ https://rumble.com/embed/<video_id>/ のスクリプトには、同じ構造の動画設定オブジェクトが含まれています。このオブジェクトには、画質ごとのストリーム URL を持つ ua、タイトル、再生時間などがあります。これを取り出して _download_json の戻り値として渡せば、後続の形式解析コードを変更せずに yt-dlp の処理を続けられます。
2. JSON として無効なフィールド(loaded: h())を取り除く
埋め込みページのインラインデータは、厳密な JSON リテラルではありません。末尾には次のように、実行時の関数呼び出し loaded: h() が含まれます。
u.f["vb0ofn"] = {"ua": {"mp4": {"360": {"url": "https://..."}}}, "title": "...", loaded: h()};
そのまま JSON パーサーに渡すと、h() が構文エラーになります。そこでプラグインは、_search_json の transform_source フックを使い、解析の直前に正規表現で末尾の , loaded: xxx() だけを取り除きます。処理はメモリー上のテキストに対して行い、ページの JavaScript は実行しません。
- 対象の厳密な指定:キー名が現在の
video_idと完全に一致するオブジェクトだけを抽出します(\b[\w$]+\.f\[\s*["']{video_id}["']\s*\]\s*=)。戻り値が辞書であり、空でないuaメディアストリームフィールドを含むことも確認します。 - 変更範囲の限定:
_download_jsonが捕捉したHTTPErrorのステータスコードが403の場合だけフォールバックします。401、404、429、500 などのエラーや、ページに有効なオブジェクトがない場合は、元の例外をそのまま送出します。 - オンラインサービスでの補助処理:当サイトではプラグインを読み込むほか、oEmbed API を自動で呼び出して、入力された視聴ページ URL を
/embed/URL に変換します。また、--impersonateが指定されていない場合は、既定でfirefox-135のフィンガープリントを使用します。
プラグインの全コード
次のコードを plugins/rumble/yt_dlp_plugins/extractor/rumble_player.py として保存します。Python 3.12+ と yt-dlp 2026.10.10+ で動作を確認しています。
"""Reuse official player media data when Rumble's JSON endpoint is blocked."""
import re
from yt_dlp.extractor.rumble import RumbleEmbedIE as BaseRumbleEmbedIE
from yt_dlp.networking.exceptions import HTTPError
from yt_dlp.utils import ExtractorError
class RumbleEmbedIE(BaseRumbleEmbedIE, plugin_name='PlayerFallback'):
def _real_extract(self, url):
self._player_url = url
return super()._real_extract(url)
def _download_json(self, url_or_request, video_id, *args, **kwargs):
try:
return super()._download_json(url_or_request, video_id, *args, **kwargs)
except ExtractorError as error:
if not isinstance(error.cause, HTTPError) or error.cause.status != 403:
raise
webpage = self._download_webpage(self._player_url, video_id, note='Downloading player webpage')
# Parse this video's object and strip the runtime call without executing page scripts.
data = self._search_json(
rf'''\b[\w$]+\.f\[\s*["']{re.escape(video_id)}["']\s*\]\s*=\s*''',
webpage, 'player data', video_id,
fatal=False,
transform_source=lambda source: re.sub(r',\s*loaded\s*:\s*[\w$]+\(\s*\)\s*(?=})', '', source))
if not isinstance(data, dict) or not data.get('ua'):
raise error
return data