แก้ yt-dlp Rumble 403: อ่านข้อมูลจากตัวเล่นเมื่อคำขอ JSON ล้มเหลว
วันที่เผยแพร่
ดาวน์โหลดปลั๊กอินแก้ไขข้อผิดพลาด rumble_player.py
หากใช้ yt-dlp ดาวน์โหลดวิดีโอ Rumble แล้วพบ Unable to download JSON metadata: HTTP Error 403: Forbidden สามารถโหลดปลั๊กอินแก้ปัญหาความเข้ากันได้ที่ให้ไว้ในบทความนี้ได้ เมื่อ JSON API embedJS/u3 ของ Rumble ส่งกลับ 403 ปลั๊กอินจะเปลี่ยนไปดึงหน้าตัวเล่นแบบฝังทางการ (/embed/) ของวิดีโอเดียวกันโดยอัตโนมัติ แล้วแยกข้อมูลสื่อที่ฝังอยู่ในหน้าเพื่อดาวน์โหลดต่อ
หากไม่ต้องการตั้งค่าปลั๊กอินบนเครื่องหรือแปลงลิงก์ด้วยตนเอง สามารถใช้เครื่องมือดาวน์โหลดวิดีโอ Rumble ของเว็บไซต์นี้ ซึ่งรวมวิธีแก้ดังกล่าวไว้แล้ว
ตรวจสอบก่อนว่า 403 เกิดขึ้นในขั้นตอนไหน
ข้อผิดพลาด 403 ระหว่างดาวน์โหลด Rumble อาจเกิดได้ในสามขั้นตอน ปลั๊กอินในบทความนี้แก้เฉพาะกรณีที่สอง:
| ข้อผิดพลาดหรืออาการ | คำขอที่ถูกบล็อก | วิธีจัดการ |
|---|---|---|
Unable to download webpage: HTTP Error 403 |
HTML ของหน้ารับชมถูกบล็อก (ดู issue #15089) | ใช้ oEmbed API ทางการเพื่อแปลงเป็น URL /embed/ พร้อมใช้ --impersonate firefox |
Unable to download JSON metadata: HTTP Error 403 |
API เมทาดาทา embedJS/u3 ถูกบล็อก (ดู issue #17496) |
ใช้ปลั๊กอินในบทความนี้ เพื่อเปลี่ยนไปอ่านข้อมูลที่ฝังอยู่ในหน้า /embed/ โดยอัตโนมัติ |
| แสดงรายการรูปแบบได้ แต่เกิด 403 ขณะดาวน์โหลดส่วนย่อยหรือ MP4 | คำขอสตรีมสื่อไปยัง CDN ถูกปฏิเสธ | ตรวจสอบพร็อกซีและเฮดเดอร์ของคำขอ หรือเลือกรูปแบบที่มีความละเอียดอื่น |
ขั้นตอนแก้ไขอย่างรวดเร็ว
1. บันทึกไฟล์ปลั๊กอิน
สร้างโฟลเดอร์ตามโครงสร้างต่อไปนี้ในไดเรกทอรีทำงาน แล้วบันทึกโค้ดปลั๊กอินฉบับเต็มท้ายบทความ เป็น rumble_player.py โดยไม่ต้องแก้ซอร์สโค้ดของ yt-dlp:
plugins/
└── rumble/
└── yt_dlp_plugins/
└── extractor/
└── rumble_player.py
2. ดึง URL /embed/ ทางการของวิดีโอ
ID ใน URL หน้ารับชมของ Rumble เช่น v6xxxx ไม่ใช่ ID เดียวกัน กับ ID ของตัวเล่นแบบฝัง เช่น vb0ofn จึงนำ ID จากหน้ารับชมมาประกอบเป็น URL แบบฝังโดยตรงไม่ได้ หากมีเพียงลิงก์หน้ารับชมทั่วไป ให้เรียก oEmbed API สาธารณะของ Rumble เพื่อรับ URL /embed/ ที่ถูกต้อง:
curl -fsSG --data-urlencode "url=https://rumble.com/your-video.html" "https://rumble.com/api/Media/oembed.json"
ค้นหา <iframe src="https://rumble.com/embed/xxxx/..." ในฟิลด์ html ของ JSON ที่ส่งกลับ แล้วนำส่วน 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/ ของวิดีโอเป้าหมาย:
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. ดาวน์โหลดวิดีโอและตรวจสอบการถอดรหัส
เลือก ID รูปแบบจากรายการที่ได้ด้วย -F เช่น 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 ซึ่งเก็บ URL สตรีมแต่ละระดับความละเอียด รวมถึงชื่อวิดีโอ ระยะเวลา และฟิลด์อื่น ๆ เพียงแยกออบเจ็กต์นี้ออกมาแล้วคืนค่าให้ _download_json yt-dlp ก็ทำงานต่อได้โดยไม่ต้องเปลี่ยนโค้ดแยกวิเคราะห์รูปแบบในขั้นตอนถัดไปแม้แต่บรรทัดเดียว
2. ลบฟิลด์ที่ไม่ใช่ JSON มาตรฐาน (loaded: h())
ออบเจ็กต์ข้อมูลที่ฝังในหน้าไม่ได้เป็น JSON literal ที่ถูกต้องทั้งหมด ส่วนท้ายมีการเรียกฟังก์ชันขณะรัน loaded: h() ดังนี้:
u.f["vb0ofn"] = {"ua": {"mp4": {"360": {"url": "https://..."}}}, "title": "...", loaded: h()};
หากส่งเข้า JSON parser โดยตรง h() จะทำให้เกิดข้อผิดพลาดทางไวยากรณ์ ปลั๊กอินจึงใช้ฮุก transform_source ใน _search_json เพื่อลบเฉพาะส่วน , 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/และใช้ลายนิ้วมือfirefox-135เป็นค่าเริ่มต้นเมื่อไม่ได้ระบุ--impersonate
โค้ดปลั๊กอินฉบับเต็ม
บันทึกโค้ดต่อไปนี้เป็น 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