yt-dlp e Rumble: risolvere l’errore JSON 403 con i dati del player
Data di pubblicazione
Scarica il plugin correttivo rumble_player.py
Se yt-dlp mostra Unable to download JSON metadata: HTTP Error 403: Forbidden mentre scarichi un video da Rumble, puoi caricare il plugin di compatibilità descritto in questo articolo. Quando l’API JSON embedJS/u3 di Rumble restituisce 403, il plugin recupera automaticamente la pagina del player incorporato ufficiale (/embed/) dello stesso video. Ne estrae i dati multimediali incorporati e prosegue il download.
Se preferisci evitare la configurazione di un plugin locale e la conversione manuale dei link, puoi usare il nostro downloader di video Rumble, che include già questa correzione.
Individuare prima la fase in cui si verifica l’errore 403
Durante un download da Rumble, l’errore 403 può comparire in tre fasi diverse. Questo plugin risolve specificamente il secondo caso:
| Messaggio di errore | Richiesta bloccata | Intervento |
|---|---|---|
Unable to download webpage: HTTP Error 403 |
Viene bloccato l’HTML della pagina del video (vedi issue #15089) | Ricavare l’indirizzo /embed/ tramite l’API oEmbed ufficiale e usare --impersonate firefox |
Unable to download JSON metadata: HTTP Error 403 |
Viene bloccata l’API dei metadati embedJS/u3 (vedi issue #17496) |
Usare questo plugin: recupera automaticamente i dati incorporati nella pagina /embed/ |
| L’elenco dei formati compare, ma il download dei frammenti o del file MP4 restituisce 403 | Il CDN rifiuta la richiesta del flusso multimediale | Controllare proxy e header della richiesta oppure scegliere un formato con una risoluzione diversa |
Procedura rapida di correzione
1. Salvare il file del plugin
Crea questa struttura di cartelle nella directory di lavoro e salva il codice completo del plugin in fondo all’articolo come rumble_player.py. Non occorre modificare il codice sorgente di yt-dlp:
plugins/
└── rumble/
└── yt_dlp_plugins/
└── extractor/
└── rumble_player.py
2. Ottenere l’indirizzo /embed/ ufficiale del video
L’ID nell’URL della pagina di un video Rumble, per esempio v6xxxx, è diverso dall’ID del player incorporato, per esempio vb0ofn. Non puoi quindi costruire direttamente l’URL del player sostituendo una parte dell’indirizzo. Se hai soltanto il normale link del video, interroga l’API oEmbed pubblica di Rumble per ottenere il vero indirizzo /embed/:
curl -fsSG --data-urlencode "url=https://rumble.com/your-video.html" "https://rumble.com/api/Media/oembed.json"
Nel campo JSON html della risposta, cerca <iframe src="https://rumble.com/embed/xxxx/..." e ricava l’indirizzo https://rumble.com/embed/xxxx/.
Se oEmbed restituisce un errore 403, installa curl_cffi e riprova con l’impronta di Firefox. Sostituisci l’URL di esempio qui sotto con quello completo della pagina del video.
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"
Se anche il secondo tentativo fallisce, usa il downloader online per convertire automaticamente il link.
3. Elencare i formati e verificare il percorso alternativo
Esegui il comando nella directory che contiene la cartella plugins. Sostituisci l’URL di esempio con l’indirizzo /embed/ del video desiderato:
yt-dlp --ignore-config --plugin-dirs ./plugins --no-cache-dir -v -F "https://rumble.com/embed/vb0ofn/"
La presenza di [RumbleEmbed+PlayerFallback] nel log conferma che il plugin è stato caricato:
- Se l’API JSON restituisce 403, segue il messaggio
Downloading player webpage, che indica l’attivazione del percorso alternativo. La successiva visualizzazione dell’elenco dei formati conferma che i dati sono stati analizzati correttamente. - Se l’API JSON restituisce direttamente 200 dalla tua rete, yt-dlp segue il normale percorso senza inviare richieste aggiuntive alla pagina del player.
4. Scaricare il video e verificarne la decodifica
Scegli un ID di formato nell’output di -F, per esempio mp4-360p, quindi avvia il download:
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/"
Questo è il log completo del terminale registrato durante il test in cui è stato attivato il percorso alternativo:
[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
Per verificare che il contenitore MP4 e le tracce audio e video scaricate siano integri, usa ffprobe e 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 -
Come funziona: perché la pagina del player permette di superare l’errore JSON 403
1. Riutilizzare i dati incorporati della stessa origine
Per impostazione predefinita, RumbleEmbedIE richiede i metadati JSON direttamente a https://rumble.com/embedJS/u3/?request=video&ver=2&v=.... Se Cloudflare o i sistemi di protezione del sito bloccano specificamente questa API con una risposta HTTP 403, l’estrazione si interrompe.
La pagina del player ufficiale https://rumble.com/embed/<video_id>/, però, contiene già nel proprio script un oggetto di configurazione video con la stessa struttura. L’oggetto include ua, con gli indirizzi dei flussi per le varie risoluzioni, oltre a titolo, durata e altri campi. Basta estrarlo e restituirlo a _download_json: il codice di yt-dlp che analizza i formati può proseguire senza modifiche.
2. Rimuovere il campo JSON non standard loaded: h()
L’oggetto incorporato nella pagina non è un letterale JSON valido: termina con la chiamata di funzione loaded: h(), per esempio:
u.f["vb0ofn"] = {"ua": {"mp4": {"360": {"url": "https://..."}}}, "title": "...", loaded: h()};
Un parser JSON segnalerebbe un errore di sintassi su h(). Il plugin usa quindi l’hook transform_source di _search_json per rimuovere con un’espressione regolare soltanto il , loaded: xxx() finale, prima del parsing. L’operazione lavora esclusivamente sul testo in memoria e non esegue JavaScript della pagina:
- Corrispondenza precisa: viene estratto soltanto l’oggetto la cui chiave coincide esattamente con la
video_idcorrente (\b[\w$]+\.f\[\s*["']{video_id}["']\s*\]\s*=). Il risultato deve essere un dizionario con un campo di flussiuanon vuoto. - Intervento limitato: il percorso alternativo si attiva solo quando
_download_jsonintercetta unHTTPErrorcon stato403. Con errori 401, 404, 429, 500 o di altro tipo, oppure se la pagina non contiene un oggetto valido, viene propagata l’eccezione originale senza modifiche. - Integrazione nel nostro servizio online: oltre a caricare il plugin, il servizio converte automaticamente gli URL delle pagine video in indirizzi
/embed/tramite oEmbed. Quando--impersonatenon è specificato, usa per impostazione predefinita l’improntafirefox-135.
Codice completo del plugin
Salva questo codice come plugins/rumble/yt_dlp_plugins/extractor/rumble_player.py. È stato verificato con Python 3.12+ e 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