mirror of
https://github.com/yt-dlp/yt-dlp.git
synced 2024-11-02 06:27:21 +00:00
[fd/dash] support DASH SEA (AES-128-CBC) decryption
This commit is contained in:
parent
e0ce6eed92
commit
bd62cdba1a
|
@ -8,7 +8,7 @@
|
||||||
from .fragment import FragmentFD
|
from .fragment import FragmentFD
|
||||||
from ..networking import Request
|
from ..networking import Request
|
||||||
from ..networking.exceptions import RequestError
|
from ..networking.exceptions import RequestError
|
||||||
from ..utils import update_url_query, urljoin
|
from ..utils import remove_start, traverse_obj, update_url_query, urljoin
|
||||||
|
|
||||||
|
|
||||||
class DashSegmentsFD(FragmentFD):
|
class DashSegmentsFD(FragmentFD):
|
||||||
|
@ -54,6 +54,25 @@ def real_download(self, filename, info_dict):
|
||||||
if extra_param_to_segment_url:
|
if extra_param_to_segment_url:
|
||||||
extra_query = urllib.parse.parse_qs(extra_param_to_segment_url)
|
extra_query = urllib.parse.parse_qs(extra_param_to_segment_url)
|
||||||
|
|
||||||
|
hls_aes = fmt.get('hls_aes', {})
|
||||||
|
if hls_aes:
|
||||||
|
decrypt_info = {'METHOD', 'AES-128'}
|
||||||
|
key = hls_aes.get('key')
|
||||||
|
if key:
|
||||||
|
key = binascii.unhexlify(remove_start(key, '0x'))
|
||||||
|
assert len(key) in (16, 24, 32), 'Invalid length for HLS AES-128 key'
|
||||||
|
decrypt_info['KEY'] = key
|
||||||
|
iv = hls_aes.get('iv')
|
||||||
|
if iv:
|
||||||
|
iv = binascii.unhexlify(remove_start(iv, '0x').zfill(32))
|
||||||
|
decrypt_info['IV'] = iv
|
||||||
|
uri = hls_aes.get('uri')
|
||||||
|
if uri:
|
||||||
|
if extra_query:
|
||||||
|
uri = update_url_query(uri, extra_query)
|
||||||
|
decrypt_info['URI'] = uri
|
||||||
|
ctx['decrypt_info'] = decrypt_info
|
||||||
|
|
||||||
fragments_to_download = self._get_fragments(fmt, ctx, extra_query)
|
fragments_to_download = self._get_fragments(fmt, ctx, extra_query)
|
||||||
|
|
||||||
if real_downloader:
|
if real_downloader:
|
||||||
|
@ -65,8 +84,11 @@ def real_download(self, filename, info_dict):
|
||||||
|
|
||||||
args.append([ctx, fragments_to_download, fmt])
|
args.append([ctx, fragments_to_download, fmt])
|
||||||
|
|
||||||
if 'dash_cenc' in info_dict and not info_dict['dash_cenc'].get('key'):
|
cenc_key = traverse_obj(info_dict, ('dash_cenc', 'key'))
|
||||||
self._get_clearkey_cenc(info_dict)
|
cenc_key_ids = traverse_obj(info_dict, ('dash_cenc', 'key_ids'))
|
||||||
|
clearkey_laurl = traverse_obj(info_dict, ('dash_cenc', 'laurl'))
|
||||||
|
if not cenc_key and cenc_key_ids and clearkey_laurl:
|
||||||
|
self._get_clearkey_cenc(info_dict, clearkey_laurl, cenc_key_ids)
|
||||||
|
|
||||||
return self.download_and_append_fragments_multiple(*args, is_fatal=lambda idx: idx == 0)
|
return self.download_and_append_fragments_multiple(*args, is_fatal=lambda idx: idx == 0)
|
||||||
|
|
||||||
|
@ -95,18 +117,11 @@ def _get_fragments(self, fmt, ctx, extra_query):
|
||||||
'fragment_count': fragment.get('fragment_count'),
|
'fragment_count': fragment.get('fragment_count'),
|
||||||
'index': i,
|
'index': i,
|
||||||
'url': fragment_url,
|
'url': fragment_url,
|
||||||
|
'decrypt_info': ctx.get('decrypt_info', {'METHOD': 'NONE'}),
|
||||||
}
|
}
|
||||||
|
|
||||||
def _get_clearkey_cenc(self, info_dict):
|
def _get_clearkey_cenc(self, info_dict, laurl, key_ids):
|
||||||
dash_cenc = info_dict.get('dash_cenc', {})
|
dash_cenc = info_dict.get('dash_cenc', {})
|
||||||
laurl = dash_cenc.get('laurl')
|
|
||||||
if not laurl:
|
|
||||||
self.report_error('No Clear Key license server URL for encrypted DASH stream')
|
|
||||||
return
|
|
||||||
key_ids = dash_cenc.get('key_ids')
|
|
||||||
if not key_ids:
|
|
||||||
self.report_error('No requested CENC KIDs for encrypted DASH stream')
|
|
||||||
return
|
|
||||||
payload = json.dumps({
|
payload = json.dumps({
|
||||||
'kids': [
|
'kids': [
|
||||||
base64.urlsafe_b64encode(bytes.fromhex(k)).decode().rstrip('=')
|
base64.urlsafe_b64encode(bytes.fromhex(k)).decode().rstrip('=')
|
||||||
|
@ -128,7 +143,7 @@ def _get_clearkey_cenc(self, info_dict):
|
||||||
k = key.get('k')
|
k = key.get('k')
|
||||||
if k:
|
if k:
|
||||||
try:
|
try:
|
||||||
dash_cenc['key'] = base64.urlsafe_b64decode(f'{k}==').hex()
|
dash_cenc.update({'key': base64.urlsafe_b64decode(f'{k}==').hex()})
|
||||||
info_dict['dash_cenc'] = dash_cenc
|
info_dict['dash_cenc'] = dash_cenc
|
||||||
return
|
return
|
||||||
except (ValueError, binascii.Error):
|
except (ValueError, binascii.Error):
|
||||||
|
|
Loading…
Reference in a new issue