ytdlp.online
Inicio Tampermonkey

Todas las soluciones

En esta página

Error 403 de Rumble en yt-dlp: usar los datos del reproductor

Fecha de publicación

Descargar complemento de corrección rumble_player.py

Si al descargar un video de Rumble con yt-dlp aparece Unable to download JSON metadata: HTTP Error 403: Forbidden, puedes cargar el plugin de compatibilidad de este artículo. Cuando la API JSON embedJS/u3 de Rumble devuelve un error 403, el plugin solicita automáticamente la página del reproductor integrado oficial (/embed/) del mismo video, extrae los datos multimedia incluidos en ella y continúa la descarga.

Si prefieres evitar la configuración local del plugin o la conversión manual de enlaces, puedes usar nuestro descargador de videos de Rumble, que ya incluye esta solución.

Identifica en qué paso aparece el error 403

El error 403 puede aparecer en tres etapas distintas de una descarga de Rumble. Este plugin resuelve específicamente la segunda:

Mensaje de error Dónde se bloquea la petición Qué hacer
Unable to download webpage: HTTP Error 403 Se bloquea el HTML de la página del video (véase el issue #15089) Obtén la dirección /embed/ con la API oEmbed oficial y usa --impersonate firefox
Unable to download JSON metadata: HTTP Error 403 Se bloquea la API de metadatos embedJS/u3 (véase el issue #17496) Usa el plugin de este artículo: recurre automáticamente a los datos incluidos en la página /embed/
La lista de formatos aparece, pero los fragmentos o el MP4 devuelven un error 403 al descargarse La CDN rechaza la petición del contenido multimedia Revisa el proxy y las cabeceras de la petición, o elige otro formato de calidad

Pasos para aplicar la solución

1. Guarda el archivo del plugin

Crea esta estructura de carpetas en tu directorio de trabajo y guarda el código completo del plugin como rumble_player.py. No hace falta modificar el código fuente de yt-dlp:

plugins/
└── rumble/
    └── yt_dlp_plugins/
        └── extractor/
            └── rumble_player.py

2. Obtén la dirección /embed/ oficial del video

El ID de la URL de la página de Rumble, por ejemplo v6xxxx, y el del reproductor integrado, como vb0ofn, son distintos. No puedes formar la dirección simplemente sustituyendo la ruta. Si solo tienes el enlace normal del video, consulta la API oEmbed pública de Rumble para obtener la dirección /embed/ correcta:

curl -fsSG --data-urlencode "url=https://rumble.com/your-video.html" "https://rumble.com/api/Media/oembed.json"

En el campo html del JSON de respuesta, busca <iframe src="https://rumble.com/embed/xxxx/..." y copia la parte https://rumble.com/embed/xxxx/.

Si oEmbed devuelve un 403, instala curl_cffi y vuelve a intentarlo con la huella digital de Firefox. Sustituye la URL del ejemplo por la URL completa de la página 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"

Si vuelve a fallar, usa el descargador en línea para convertir el enlace automáticamente.

3. Lista los formatos y comprueba la ruta alternativa

Ejecuta el siguiente comando desde el directorio que contiene la carpeta plugins. Sustituye la dirección por la URL /embed/ del video que quieras descargar:

yt-dlp --ignore-config --plugin-dirs ./plugins --no-cache-dir -v -F "https://rumble.com/embed/vb0ofn/"

La etiqueta [RumbleEmbed+PlayerFallback] en el registro confirma que se ha cargado el plugin:

  • Si la API JSON devuelve un error 403, a continuación aparecerá Downloading player webpage. Esta línea solo confirma que se ha activado la ruta alternativa. Para confirmar que los datos se han analizado correctamente, debe aparecer después la lista de formatos.
  • Si la API JSON devuelve un estado 200 desde tu conexión, se utiliza el procedimiento original sin solicitar además la página del reproductor.

4. Descarga el video y comprueba la decodificación

Elige un ID de formato de la lista que devuelve -F, por ejemplo mp4-360p, y descarga el video:

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/"

Este es el registro de terminal de la prueba en la que se activó la ruta alternativa:

[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

Para comprobar la integridad del contenedor MP4 y de las pistas de audio y video descargadas, utiliza ffprobe y 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 -

Cómo permite el reproductor continuar tras el error 403 de JSON

1. Reutilizar los datos incluidos en la página oficial

De forma predeterminada, RumbleEmbedIE solicita los metadatos JSON directamente a https://rumble.com/embedJS/u3/?request=video&ver=2&v=.... Si Cloudflare o las medidas de protección del sitio bloquean específicamente esa API con un estado HTTP 403, la extracción se interrumpe.

Sin embargo, la página oficial https://rumble.com/embed/<video_id>/ ya incluye en sus scripts un objeto de configuración del video con la misma estructura: el campo ua con las direcciones de las distintas calidades, el título, la duración y otros datos. Al extraer ese objeto y devolverlo desde _download_json, el código posterior de yt-dlp puede seguir procesando los formatos sin cambios.

2. Eliminar el campo que no es JSON válido (loaded: h())

El objeto incluido en la página no es un literal JSON estricto. Al final contiene una llamada a una función en tiempo de ejecución, loaded: h(), como en este ejemplo:

u.f["vb0ofn"] = {"ua": {"mp4": {"360": {"url": "https://..."}}}, "title": "...", loaded: h()};

Si se pasa directamente a un analizador JSON, h() provoca un error de sintaxis. Por eso el plugin utiliza el parámetro transform_source de _search_json para eliminar únicamente el fragmento final , loaded: xxx() mediante una expresión regular antes de analizar el objeto. Toda la operación se realiza sobre texto en memoria, sin ejecutar JavaScript de la página:

  • Coincidencia exacta: solo extrae el objeto cuya clave coincide con el video_id actual (\b[\w$]+\.f\[\s*["']{video_id}["']\s*\]\s*=) y comprueba que el resultado sea un diccionario con un campo multimedia ua no vacío.
  • Intervención limitada: la ruta alternativa solo se activa cuando _download_json captura un HTTPError con estado 403. Ante errores 401, 404, 429 o 500, o si la página no contiene un objeto válido, se vuelve a lanzar la excepción original sin modificarla.
  • Integración en nuestro servicio: además de cargar el plugin, nuestro servicio online consulta oEmbed para convertir los enlaces normales en direcciones /embed/. También utiliza por defecto la huella de navegador firefox-135 si no se especifica --impersonate.

Código completo del plugin

Guarda este código como plugins/rumble/yt_dlp_plugins/extractor/rumble_player.py. Se ha verificado con Python 3.12+ y 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
Herramientas yt-dlp
Ver todas las herramientas yt-dlp
Ayuda y documentación de yt-dlp