diff --git a/vinetrimmer/commands/dl.py b/vinetrimmer/commands/dl.py index 6270bb0..8332fb6 100644 --- a/vinetrimmer/commands/dl.py +++ b/vinetrimmer/commands/dl.py @@ -27,6 +27,7 @@ from vinetrimmer.utils.click import (AliasedGroup, ContextData, acodec_param, la from vinetrimmer.utils.collections import as_list, merge_dict from vinetrimmer.utils.io import load_yaml from pywidevine import Device, Cdm, RemoteCdm +from pywidevine import PSSH as PSSHWV from vinetrimmer.vendor.pymp4.parser import Box @@ -476,7 +477,7 @@ def result(ctx, service, quality, range_, wanted, alang, slang, audio_only, subs skip_title = True break if "common_privacy_cert" in dir(ctx.obj.cdm): - session_id = ctx.obj.cdm.open(track.pssh) + session_id = ctx.obj.cdm.open() log.info(f"CDM Session ID - {session_id.hex()}") ctx.obj.cdm.set_service_certificate( session_id, @@ -490,7 +491,7 @@ def result(ctx, service, quality, range_, wanted, alang, slang, audio_only, subs ctx.obj.cdm.parse_license( session_id, service.license( - challenge=ctx.obj.cdm.get_license_challenge(session_id), + challenge=ctx.obj.cdm.get_license_challenge(session_id=session_id, pssh=PSSHWV(track.pssh)), title=title, track=track, session_id=session_id @@ -515,7 +516,7 @@ def result(ctx, service, quality, range_, wanted, alang, slang, audio_only, subs content_keys = [ - (x.kid, x.key) for x in ctx.obj.cdm.get_keys(session_id, content_only=True) + (str(x.kid).replace("-", ""), x.key.hex()) for x in ctx.obj.cdm.get_keys(session_id) if x.type == "CONTENT" ] if "common_privacy_cert" in dir(ctx.obj.cdm) else [ (str(x.key_id).replace("-", ""), x.key.hex()) for x in ctx.obj.cdm.get_keys(session_id) ] diff --git a/vinetrimmer/key_store.db b/vinetrimmer/key_store.db index 9ab4f96..e02d63c 100644 Binary files a/vinetrimmer/key_store.db and b/vinetrimmer/key_store.db differ diff --git a/vinetrimmer/objects/tracks.py b/vinetrimmer/objects/tracks.py index 85c4d45..61d6e72 100644 --- a/vinetrimmer/objects/tracks.py +++ b/vinetrimmer/objects/tracks.py @@ -419,6 +419,8 @@ class Track: headers, proxy if self.needs_proxy else None )) + if self.__class__.__name__ == "AudioTrack": + save_path = save_path.replace(".mp4", f".{str(self.language)[:2]}.m4a") else: asyncio.run(aria2c( self.url, diff --git a/vinetrimmer/parsers/mpd.py b/vinetrimmer/parsers/mpd.py index fffc549..115b7d5 100644 --- a/vinetrimmer/parsers/mpd.py +++ b/vinetrimmer/parsers/mpd.py @@ -139,17 +139,33 @@ def parse(*, url=None, data=None, source, session=None, downloader=None): for protection in protections: # For HMAX, the PSSH has multiple keys but the PlayReady ContentProtection tag # contains the correct KID - kid = protection.get("default_KID") - if kid: - kid = uuid.UUID(kid).hex - else: - kid = protection.get("kid") - if kid: - kid = uuid.UUID(bytes_le=base64.b64decode(kid)).hex - if (protection.get("schemeIdUri") or "").lower() != "urn:uuid:9a04f079-9840-4286-ab92-e65be0885f95": + if not kid: + kid = protection.get("default_KID") + if not kid: + kid = protection.get("kid") + if kid: + kid = uuid.UUID(bytes_le=base64.b64decode(kid)).hex + else: + kid = uuid.UUID(kid).hex + if (protection.get("schemeIdUri") or "").lower() not in ["urn:uuid:9a04f079-9840-4286-ab92-e65be0885f95", "urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed"]: continue pssh = protection.findtext("pssh") + """ + if pssh and ((protection.get("schemeIdUri") or "").lower() == "urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed3"): + pssh = base64.b64decode(pssh) + # noinspection PyBroadException + try: + pssh = Box.parse(pssh) + except Exception: + pssh = Box.parse(Box.build(dict( + type=b"pssh", + version=0, # can only assume version & flag are 0 + flags=0, + system_ID=Cdm.uuid, + init_data=pssh + ))) + """ rep_base_url = rep.findtext("BaseURL") if rep_base_url and source not in ["DSCP", "DSNY"]: # TODO: Don't hardcode services diff --git a/vinetrimmer/utils/io.py b/vinetrimmer/utils/io.py index bd79805..10cea0f 100644 --- a/vinetrimmer/utils/io.py +++ b/vinetrimmer/utils/io.py @@ -294,8 +294,9 @@ async def m3u8dl(uri, out, track, headers=None, proxy=None): arguments.extend([ "-dv", "all", "-ds", "all", - "-M", "format=mp4:muxer=ffmpeg", ]) + if track.source != "HS": + arguments.extend(["-M", "format=mp4"]) else: raise ValueError(f"{track.__class__.__name__} not supported yet!") @@ -303,8 +304,5 @@ async def m3u8dl(uri, out, track, headers=None, proxy=None): arg_str = " ".join(arguments) #print(arg_str) p = subprocess.run(arg_str, check=True) - #os.system(arg_str) except subprocess.CalledProcessError: - raise ValueError("N_m3u8DL-RE failed too many times, aborting") - - # Removed above call using subprocess due to it failing to correctly pass --header value. The problem might be with spaces within the header string, I think? I know it's not recommended to use os.system but didn't have a choice \ No newline at end of file + raise ValueError("N_m3u8DL-RE failed too many times, aborting") \ No newline at end of file