import requests from pywidevine.L3.cdm import deviceconfig from base64 import b64encode from pywidevine.L3.decrypt.wvdecryptcustom import WvDecrypt import re import subprocess import shutil from termcolor import colored import pyperclip as PC ## globals headers = { 'Accept': '*/*', 'Accept-Language': 'en-GB,en;q=0.9', 'Connection': 'keep-alive', } # defs def get_pssh_lic(mpd_url): mpd = requests.get(mpd_url, headers).text lines = mpd.split("\n") for line in lines: m = re.search('(AAAA.+?)', line) n = re.search('bc:licenseAcquisitionUrl=\"(http.+?)\" xmlns:bc="urn:brightcove:2015\"', line) if m: pssh = m.group(1) if n: lic_url = n.group(1) return pssh, lic_url def divides(text): text = text l = len(text) count = int(shutil.get_terminal_size().columns) - 2 if count <= 120: count = int(count) else: count = int(count/2) count = count - (l) #line = ('-' * int(count/2)) line = (chr(9601) * int(count/2)) print('\n', colored(line, 'green'), " ", text, " ", colored(line, 'green')) def WV_Function(pssh, lic_url, cert_b64=None): wvdecrypt = WvDecrypt(init_data_b64=pssh, cert_data_b64=cert_b64, device=deviceconfig.device_android_generic) widevine_license = requests.post(url=lic_url, data=wvdecrypt.get_challenge(), headers=None) license_b64 = b64encode(widevine_license.content) wvdecrypt.update_license(license_b64) Correct, keyswvdecrypt = wvdecrypt.start_process() if Correct: return Correct, keyswvdecrypt def parse_vmap(content): lines = content.split("\n") for line in lines: m = re.search('contenturi="(https.+?)" contentlength=', line) if m: mpd_url = m.group(1) return(mpd_url) if __name__ == '__main__': #### main #### print("Copy stream URL as 'Table Entry' from The Stream Detector") input("Press Enter when ready!") fmpd = PC.paste().split('\n') divides('MPD downloader script') for line in fmpd: linetuple = line.split('|') mpd_url = linetuple[0].replace('\n', '').replace(' ', '') print(f"{mpd_url}") videoname = str('test') from sys import argv if argv and len(argv) > 1: mpd_url = argv[1] videoname = argv[2] else: print('\n\n[info] URLs may be mpd, master.m3u8 or vmap from boltdns.net') ### decide type dash (mpd), m3u8 or vmap dash = "dash" #encrypted m3u8 = 'm3u8' vmap = 'vmap' #encrypted/unencrypted if vmap in mpd_url: content = requests.get(mpd_url, headers).text mpd_url = parse_vmap(content) # either m3u8 or dash if dash in mpd_url: pssh, lic = get_pssh_lic(mpd_url) mykeys = '' correct, keys = WV_Function(pssh, lic) for key in keys: mykeys += key divides("getting encrypted streams") print(f"{mpd_url}") command = [ "N_m3u8DL-RE", mpd_url, "--auto-select", "--save-name", videoname, "--save-dir", "./output", "--tmp-dir", "./", "-mt", "--use-shaka-packager", "--key", mykeys, "-M", "format=mkv:muxer=mkvmerge", ] subprocess.run(command) elif m3u8 in mpd_url: divides('Getting encryption free stream') command = [ "N_m3u8DL-RE", mpd_url, "--auto-select", "--save-name", videoname, "--save-dir", "./output/", "--tmp-dir", "./", "-mt", "--use-shaka-packager", "-M", "format=mkv:muxer=mkvmerge", ] subprocess.run(command)