]> jfr.im git - yt-dlp.git/commitdiff
[HLS] Fix decryption issues (#1117)
authorshirt <redacted>
Tue, 28 Sep 2021 18:53:24 +0000 (14:53 -0400)
committerGitHub <redacted>
Tue, 28 Sep 2021 18:53:24 +0000 (00:23 +0530)
* Unpad HLS fragments with PKCS#7 according to datatracker.ietf.org/doc/html/rfc8216
* media_sequence should only be incremented in for media fragments
* The native decryption should only be used if ffmpeg is unavailable since it is significantly slower. Closes #1086

Authored by: shirt-dev, pukkandan

yt_dlp/downloader/fragment.py
yt_dlp/downloader/hls.py

index 31f9467922e868f5a13f212e180e21da0d4641b6..22134f3b6c6fdd522a7306f8c6cee45a4cf36404 100644 (file)
@@ -355,7 +355,8 @@ def decrypt_fragment(fragment, frag_content):
             # not what it decrypts to.
             if self.params.get('test', False):
                 return frag_content
-            return aes_cbc_decrypt_bytes(frag_content, decrypt_info['KEY'], iv)
+            decrypted_data = aes_cbc_decrypt_bytes(frag_content, decrypt_info['KEY'], iv)
+            return decrypted_data[:-decrypted_data[-1]]
 
         return decrypt_fragment
 
index f343e1879722968e49ac463b32c6dd21c287426f..751d874d4218c94ecd511c84740f2cee747411d3 100644 (file)
@@ -9,6 +9,7 @@
 from .external import FFmpegFD
 
 from ..compat import (
+    compat_pycrypto_AES,
     compat_urlparse,
 )
 from ..utils import (
@@ -68,14 +69,20 @@ def real_download(self, filename, info_dict):
         man_url = urlh.geturl()
         s = urlh.read().decode('utf-8', 'ignore')
 
-        if not self.can_download(s, info_dict, self.params.get('allow_unplayable_formats')):
-            if info_dict.get('extra_param_to_segment_url') or info_dict.get('_decryption_key_url'):
-                self.report_error('pycryptodome not found. Please install')
-                return False
+        can_download, message = self.can_download(s, info_dict, self.params.get('allow_unplayable_formats')), None
+        if can_download and not compat_pycrypto_AES and '#EXT-X-KEY:METHOD=AES-128' in s:
+            if FFmpegFD.available():
+                can_download, message = False, 'The stream has AES-128 encryption and pycryptodome is not available'
+            else:
+                message = ('The stream has AES-128 encryption and neither ffmpeg nor pycryptodome are available; '
+                           'Decryption will be performed natively, but will be extremely slow')
+        if not can_download:
+            message = message or 'Unsupported features have been detected'
             fd = FFmpegFD(self.ydl, self.params)
-            self.report_warning(
-                '%s detected unsupported features; extraction will be delegated to %s' % (self.FD_NAME, fd.get_basename()))
+            self.report_warning(f'{message}; extraction will be delegated to {fd.get_basename()}')
             return fd.real_download(filename, info_dict)
+        elif message:
+            self.report_warning(message)
 
         is_webvtt = info_dict['ext'] == 'vtt'
         if is_webvtt:
@@ -232,7 +239,6 @@ def is_ad_fragment_end(s):
                 elif line.startswith('#EXT-X-DISCONTINUITY'):
                     discontinuity_count += 1
                 i += 1
-                media_sequence += 1
 
         # We only download the first fragment during the test
         if self.params.get('test', False):