ytdlp.online
홈 Tampermonkey

전체 해결 방법

목차

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 다운로드에서는 다음 세 단계에서 403이 발생할 수 있습니다. 이 글의 플러그인은 두 번째 경우를 해결합니다.

오류 또는 증상 차단된 요청 해결 방법
Unable to download webpage: HTTP Error 403 시청 페이지 HTML 차단(이슈 #15089 참고) 공식 oEmbed API로 /embed/ 주소를 얻고 --impersonate firefox를 함께 사용합니다
Unable to download JSON metadata: HTTP Error 403 embedJS/u3 메타데이터 API 차단(이슈 #17496 참고) 이 글의 플러그인으로 해결: /embed/ 페이지의 인라인 데이터를 읽는 경로로 자동 전환합니다
형식 목록은 표시되지만 세그먼트나 MP4 다운로드 중 403 발생 CDN 미디어 스트림 요청 거부 프록시와 요청 헤더를 확인하거나 다른 화질의 형식을 선택합니다

빠른 해결 방법

1. 플러그인 파일 저장

작업 디렉터리에 다음 구조로 폴더를 만들고, 글 끝의 전체 플러그인 코드를 rumble_player.py로 저장하세요. yt-dlp 소스 코드를 수정할 필요는 없습니다.

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

2. 동영상의 공식 /embed/ 주소 가져오기

Rumble 시청 페이지 URL의 ID(예: v6xxxx)와 임베드 플레이어의 ID(예: vb0ofn)는 서로 다릅니다. 따라서 시청 페이지 ID로 임베드 주소를 직접 조합하면 안 됩니다. 일반 시청 페이지 링크만 있다면 Rumble이 공개한 공식 oEmbed API를 호출해 실제 /embed/ 주소를 가져오세요.

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 폴더가 있는 디렉터리에서 다음 명령을 실행하세요. 실제로 사용할 때는 대상 동영상의 /embed/ 주소로 바꾸면 됩니다.

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>/의 스크립트에는 동일한 구조의 동영상 설정 객체가 이미 포함되어 있습니다. 여기에는 화질별 스트림 주소를 담은 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/ 주소로 변환합니다. --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
yt-dlp 도구 모음
모든 yt-dlp 도구 목록 보기
yt-dlp 도움말 및 문서