diff --git a/unshackle/core/drm/playready.py b/unshackle/core/drm/playready.py index bc9a713..253e4a5 100644 --- a/unshackle/core/drm/playready.py +++ b/unshackle/core/drm/playready.py @@ -359,9 +359,8 @@ class PlayReady: key_hex = key if isinstance(key, str) else key.hex() key_args.extend(["--key", f"{kid_hex}:{key_hex}"]) - # Some services use a blank/zero default KID in the tenc box, - # but the real KID for the license server. Add zero-KID fallback entries so - # mp4decrypt can match when the file's default KID is all zeros. + # Fallback for tracks whose tenc default_KID is all-zero and whose real + # KID is signalled out-of-band: emit a zero-KID entry per content key. zero_kid = "00" * 16 existing_kids = {kid.hex if hasattr(kid, "hex") else str(kid).replace("-", "") for kid in self.content_keys} if zero_kid not in existing_kids: diff --git a/unshackle/core/drm/widevine.py b/unshackle/core/drm/widevine.py index 82c6419..0bad0a6 100644 --- a/unshackle/core/drm/widevine.py +++ b/unshackle/core/drm/widevine.py @@ -296,9 +296,8 @@ class Widevine: key_hex = key if isinstance(key, str) else key.hex() key_args.extend(["--key", f"{kid_hex}:{key_hex}"]) - # Some services use a blank/zero default KID in the tenc box, - # but the real KID for the license server. Add zero-KID fallback entries so - # mp4decrypt can match when the file's default KID is all zeros. + # Fallback for tracks whose tenc default_KID is all-zero and whose real + # KID is signalled out-of-band: emit a zero-KID entry per content key. zero_kid = "00" * 16 existing_kids = {kid.hex if hasattr(kid, "hex") else str(kid).replace("-", "") for kid in self.content_keys} if zero_kid not in existing_kids: diff --git a/unshackle/core/manifests/hls.py b/unshackle/core/manifests/hls.py index a381ac8..8547565 100644 --- a/unshackle/core/manifests/hls.py +++ b/unshackle/core/manifests/hls.py @@ -858,6 +858,14 @@ class HLS: DOWNLOAD_CANCELLED.set() # skip pending track downloads progress(downloaded="[red]FAILED") raise + if ( + encryption_data + and isinstance(drm, (Widevine, PlayReady)) + and isinstance(encryption_data[1], type(drm)) + and getattr(encryption_data[1], "content_keys", None) + ): + for prev_kid, prev_key in encryption_data[1].content_keys.items(): + drm.content_keys.setdefault(prev_kid, prev_key) encryption_data = (key, drm) if DOWNLOAD_LICENCE_ONLY.is_set():