Hi guys.
I wasn't able to find a working solution for bunny cdn drm protected videos (used by many course platforms) so i created my own.
It works for both protected / unprotected videos.
It uses playwright to emulate firefox browser and N_M3U8DL-RE for download.
You can pass it a single url of a file with list of urls.
Code:https://github.com/nonab/bunny-cdn-downloader
+ Reply to Thread
Results 1 to 2 of 2
-
-
# Vidéo unique
python bunny_key_grabber.py https://site.com/video-page
# Fichier local
python bunny_key_grabber.py urls.txt
# Fichier distant (GitHub raw, S3, etc.)
python bunny_key_grabber.py https://raw.githubusercontent.com/user/repo/main/urls.txt
# Mode impression uniquement
python bunny_key_grabber.py --print-only https://raw.githubusercontent.com/user/repo/main/urls.txtCode:import sys import re import subprocess import shutil from pathlib import Path import requests from playwright.sync_api import sync_playwright def load_urls(file): path = Path(file) if not path.exists(): print(f"Error: File '{file}' not found.") sys.exit(1) return [line.strip() for line in path.read_text().splitlines() if line.strip()] def load_urls_from_remote(url): try: r = requests.get(url, timeout=15) r.raise_for_status() return [line.strip() for line in r.text.splitlines() if line.strip()] except Exception as e: print(f"Error loading remote URL list: {e}") sys.exit(1) def sanitize_filename(title): return re.sub(r'[\\/:"*?<>|]+', '_', title) # ----------------- CLI FLAGS ----------------- print_only_mode = "--print-only" in sys.argv if print_only_mode: sys.argv.remove("--print-only") if len(sys.argv) < 2: print("Usage: python bunny_key_grabber.py [--print-only] <url | file | remote_txt_url>") sys.exit(1) if not print_only_mode and not shutil.which("N_M3U8DL-RE"): print( "N_M3U8DL-RE not found.\n" "Download: https://github.com/nilaoda/N_m3u8DL-RE/releases\n" "Add it to PATH and retry." ) sys.exit(1) input_arg = sys.argv[1] urls = [] # ----------------- INPUT MODE DETECTION ----------------- if input_arg.lower().startswith(("http://", "https://")): if input_arg.lower().endswith(".txt"): print(f"Detected remote URL list: {input_arg}") urls = load_urls_from_remote(input_arg) else: urls = [input_arg] else: print(f"Detected local file mode: {input_arg}") urls = load_urls(input_arg) # ----------------- PLAYWRIGHT JS ----------------- get_media_playlist_js = """ async (masterPlaylistUrl) => { const response = await fetch(masterPlaylistUrl); const masterPlaylistContent = await response.text(); let mediaPlaylistUrl = null; for (const line of masterPlaylistContent.trim().split('\\n')) { if (line.trim() && !line.startsWith("#")) { mediaPlaylistUrl = new URL(line.trim(), masterPlaylistUrl).href; break; } } const mediaResponse = await fetch(mediaPlaylistUrl); return await mediaResponse.text(); } """ # ----------------- PROCESSING ----------------- commands_list = [] print("\n--- Starting URL Processing ---") with sync_playwright() as p: browser = p.firefox.launch( headless=True, firefox_user_prefs={"media.volume_scale": "0.0"} ) context = browser.new_context() for page_url in urls: print("\n==============================") print("Processing:", page_url) page = context.new_page() state = {"hex_key": None, "playlist_url": None, "title": None} def on_response(response): if "b-cdn.net" in response.url and "/key/" in response.url: try: state["hex_key"] = response.body().hex() except Exception: pass def on_request(request): if "b-cdn.net" in request.url and request.url.endswith("playlist.m3u8"): state["playlist_url"] = request.url page.on("response", on_response) page.on("request", on_request) try: page.goto( page_url, wait_until="domcontentloaded", timeout=60000, referer="https://iframe.mediadelivery.net/" ) title = page.title() if title: state["title"] = sanitize_filename(title) except Exception as e: print(f"Error loading page: {e}") page.close() continue max_wait, elapsed = 15, 0 while not state["playlist_url"] and elapsed < max_wait: page.wait_for_timeout(500) elapsed += 0.5 if not state["playlist_url"]: print("No master playlist found.") page.close() continue try: print("Master playlist found, checking DRM...") media_playlist_content = page.evaluate( get_media_playlist_js, state["playlist_url"] ) except Exception as e: print(f"Failed to read playlist: {e}") page.close() continue is_drm = "#EXT-X-KEY" in media_playlist_content cmd_parts = ["N_M3U8DL-RE", "-sv", "best"] if state["title"]: cmd_parts.append(f'--save-name "{state["title"]}"') if is_drm: print("DRM detected, waiting for key...") key_wait, waited = 5, 0 while not state["hex_key"] and waited < key_wait: page.wait_for_timeout(500) waited += 0.5 if not state["hex_key"]: print("Failed to capture DRM key.") page.close() continue print("Encryption key captured.") cmd_parts.append(f'--custom-hls-key "{state["hex_key"]}"') cmd_parts.append(f'"{state["playlist_url"]}"') cmd_parts.append('--header "Referer: https://iframe.mediadelivery.net/"') cmd = " ".join(cmd_parts) commands_list.append(cmd) print("Command generated.") page.close() browser.close() print("\n--- URL Processing Finished ---") # ----------------- EXECUTION ----------------- if not commands_list: print("No downloadable videos found.") sys.exit(0) print("\n==============================") if print_only_mode: print("--- Print Only Mode ---") for c in commands_list: print(c) else: print(f"Found {len(commands_list)} video(s).") for i, c in enumerate(commands_list, 1): print(f"\n--- Download {i}/{len(commands_list)} ---") print(c) try: subprocess.run(c, shell=True, check=True) print("Download completed.") except subprocess.CalledProcessError as e: print(f"Download error: {e}")
Similar Threads
-
bunny-cdn-drm-video-dl quality
By werty20 in forum Video Streaming DownloadingReplies: 3Last Post: 2nd Jan 2025, 17:10 -
Download from iframe.mediadelivery.net
By andreww in forum Video Streaming DownloadingReplies: 13Last Post: 19th Dec 2023, 15:55 -
Video download from Bunny (b-cdn.net or mediadelivery.net)
By tadkozh in forum Video Streaming DownloadingReplies: 6Last Post: 27th Nov 2023, 16:01 -
iframe.mediadelivery.net gives me 401 Unauthorized
By Anonymous84734 in forum Video Streaming DownloadingReplies: 8Last Post: 18th Sep 2023, 11:15 -
Help to download from iframe.mediadelivery.net
By safinok in forum Video Streaming DownloadingReplies: 1Last Post: 5th Apr 2023, 00:03


Quote