|
|
|
@ -6,7 +6,7 @@ import subprocess
|
|
|
|
|
import sys
|
|
|
|
|
import time
|
|
|
|
|
|
|
|
|
|
from .common import FileDownloader
|
|
|
|
|
from .fragment import FragmentFD
|
|
|
|
|
from ..aes import aes_cbc_decrypt_bytes
|
|
|
|
|
from ..compat import (
|
|
|
|
|
compat_setenv,
|
|
|
|
@ -30,7 +30,7 @@ from ..utils import (
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class ExternalFD(FileDownloader):
|
|
|
|
|
class ExternalFD(FragmentFD):
|
|
|
|
|
SUPPORTED_PROTOCOLS = ('http', 'https', 'ftp', 'ftps')
|
|
|
|
|
can_download_to_stdout = False
|
|
|
|
|
|
|
|
|
@ -142,6 +142,7 @@ class ExternalFD(FileDownloader):
|
|
|
|
|
self.report_error('Giving up after %s fragment retries' % fragment_retries)
|
|
|
|
|
return -1
|
|
|
|
|
|
|
|
|
|
decrypt_fragment = self.decrypter(info_dict)
|
|
|
|
|
dest, _ = sanitize_open(tmpfilename, 'wb')
|
|
|
|
|
for frag_index, fragment in enumerate(info_dict['fragments']):
|
|
|
|
|
fragment_filename = '%s-Frag%d' % (tmpfilename, frag_index)
|
|
|
|
@ -153,21 +154,7 @@ class ExternalFD(FileDownloader):
|
|
|
|
|
continue
|
|
|
|
|
self.report_error('Unable to open fragment %d' % frag_index)
|
|
|
|
|
return -1
|
|
|
|
|
decrypt_info = fragment.get('decrypt_info')
|
|
|
|
|
if decrypt_info:
|
|
|
|
|
if decrypt_info['METHOD'] == 'AES-128':
|
|
|
|
|
iv = decrypt_info.get('IV') or compat_struct_pack('>8xq', fragment['media_sequence'])
|
|
|
|
|
decrypt_info['KEY'] = decrypt_info.get('KEY') or self.ydl.urlopen(
|
|
|
|
|
self._prepare_url(info_dict, info_dict.get('_decryption_key_url') or decrypt_info['URI'])).read()
|
|
|
|
|
encrypted_data = src.read()
|
|
|
|
|
decrypted_data = aes_cbc_decrypt_bytes(encrypted_data, decrypt_info['KEY'], iv)
|
|
|
|
|
dest.write(decrypted_data)
|
|
|
|
|
else:
|
|
|
|
|
fragment_data = src.read()
|
|
|
|
|
dest.write(fragment_data)
|
|
|
|
|
else:
|
|
|
|
|
fragment_data = src.read()
|
|
|
|
|
dest.write(fragment_data)
|
|
|
|
|
dest.write(decrypt_fragment(fragment, src.read()))
|
|
|
|
|
src.close()
|
|
|
|
|
if not self.params.get('keep_fragments', False):
|
|
|
|
|
os.remove(encodeFilename(fragment_filename))
|
|
|
|
@ -181,10 +168,6 @@ class ExternalFD(FileDownloader):
|
|
|
|
|
self.to_stderr(stderr.decode('utf-8', 'replace'))
|
|
|
|
|
return p.returncode
|
|
|
|
|
|
|
|
|
|
def _prepare_url(self, info_dict, url):
|
|
|
|
|
headers = info_dict.get('http_headers')
|
|
|
|
|
return sanitized_Request(url, None, headers) if headers else url
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class CurlFD(ExternalFD):
|
|
|
|
|
AVAILABLE_OPT = '-V'
|
|
|
|
@ -518,7 +501,7 @@ class AVconvFD(FFmpegFD):
|
|
|
|
|
_BY_NAME = dict(
|
|
|
|
|
(klass.get_basename(), klass)
|
|
|
|
|
for name, klass in globals().items()
|
|
|
|
|
if name.endswith('FD') and name != 'ExternalFD'
|
|
|
|
|
if name.endswith('FD') and name not in ('ExternalFD', 'FragmentFD')
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|