Fix allow-u in core

This commit is contained in:
Simon Sawicki 2024-12-20 21:44:10 +01:00
parent d298693b1b
commit 6e7072c53a
No known key found for this signature in database
6 changed files with 29 additions and 47 deletions

View file

@ -2319,7 +2319,7 @@ These options are not intended to be used by the end-user
--test Download only part of video for testing extractors --test Download only part of video for testing extractors
--load-pages Load pages dumped by --write-pages --load-pages Load pages dumped by --write-pages
--youtube-print-sig-code For testing youtube signatures --youtube-print-sig-code For testing youtube signatures
--allow-unplayable-formats List unplayable formats also --allow-unplayable-formats List unplayable formats also. Implies `--simulate` and `--list-formats`.
--no-allow-unplayable-formats Default --no-allow-unplayable-formats Default
#### Old aliases #### Old aliases

View file

@ -240,7 +240,7 @@ class YoutubeDL:
You can also pass a function. The function takes 'ctx' as You can also pass a function. The function takes 'ctx' as
argument and returns the formats to download. argument and returns the formats to download.
See "build_format_selector" for an implementation See "build_format_selector" for an implementation
allow_unplayable_formats: Allow unplayable formats to be extracted and downloaded. allow_unplayable_formats: Allow unplayable formats to be extracted.
ignore_no_formats_error: Ignore "No video formats" error. Usefull for ignore_no_formats_error: Ignore "No video formats" error. Usefull for
extracting metadata even if the video is not actually extracting metadata even if the video is not actually
available for download (experimental) available for download (experimental)
@ -683,11 +683,14 @@ class YoutubeDL:
self.deprecated_feature(system_deprecation.replace('\n', '\n ')) self.deprecated_feature(system_deprecation.replace('\n', '\n '))
if self.params.get('allow_unplayable_formats'): if self.params.get('allow_unplayable_formats'):
from . import _IN_CLI
switch = '--allow-unplayable-formats' if _IN_CLI else 'allow_unplayable_formats'
self.report_warning( self.report_warning(
f'You have asked for {self._format_err("UNPLAYABLE", self.Styles.EMPHASIS)} formats to be listed/downloaded. ' f'{switch} is a {self._format_err("developer option", self.Styles.EMPHASIS)} intended for {self._format_err("debugging", self.Styles.EMPHASIS)}. \n'
'This is a developer option intended for debugging. \n' f' If you experience issues {self._format_err("DO NOT", self.Styles.ERROR)} open a bug report.')
' If you experience any issues while using this option, ' self.params['listformats'] = True
f'{self._format_err("DO NOT", self.Styles.ERROR)} open a bug report') self.params['simulate'] = 'list_only'
if self.params.get('bidi_workaround', False): if self.params.get('bidi_workaround', False):
try: try:
@ -2811,6 +2814,7 @@ class YoutubeDL:
info_dict['_has_drm'] = any( # or None ensures --clean-infojson removes it info_dict['_has_drm'] = any( # or None ensures --clean-infojson removes it
f.get('has_drm') and f['has_drm'] != 'maybe' for f in formats) or None f.get('has_drm') and f['has_drm'] != 'maybe' for f in formats) or None
if not self.params.get('allow_unplayable_formats'): if not self.params.get('allow_unplayable_formats'):
# Allow bypassing flaky `has_drm` detection
formats = [f for f in formats if not f.get('has_drm') or f['has_drm'] == 'maybe'] formats = [f for f in formats if not f.get('has_drm') or f['has_drm'] == 'maybe']
if formats and all(f.get('acodec') == f.get('vcodec') == 'none' for f in formats): if formats and all(f.get('acodec') == f.get('vcodec') == 'none' for f in formats):
@ -3426,12 +3430,7 @@ class YoutubeDL:
success, real_download = self.dl(temp_filename, info_dict) success, real_download = self.dl(temp_filename, info_dict)
info_dict['__real_download'] = real_download info_dict['__real_download'] = real_download
else: else:
if self.params.get('allow_unplayable_formats'): if not merger.available:
self.report_warning(
'You have requested merging of multiple formats '
'while also allowing unplayable formats to be downloaded. '
'The formats won\'t be merged to prevent data corruption.')
elif not merger.available:
msg = 'You have requested merging of multiple formats but ffmpeg is not installed' msg = 'You have requested merging of multiple formats but ffmpeg is not installed'
if not self.params.get('ignoreerrors'): if not self.params.get('ignoreerrors'):
self.report_error(f'{msg}. Aborting due to --abort-on-error') self.report_error(f'{msg}. Aborting due to --abort-on-error')
@ -3462,7 +3461,7 @@ class YoutubeDL:
info_dict['__real_download'] = info_dict['__real_download'] or real_download info_dict['__real_download'] = info_dict['__real_download'] or real_download
success = success and partial_success success = success and partial_success
if downloaded and merger.available and not self.params.get('allow_unplayable_formats'): if downloaded and merger.available:
info_dict['__postprocessors'].append(merger) info_dict['__postprocessors'].append(merger)
info_dict['__files_to_merge'] = downloaded info_dict['__files_to_merge'] = downloaded
# Even if there were no downloads, it is being merged only now # Even if there were no downloads, it is being merged only now

View file

@ -504,8 +504,7 @@ def validate_options(opts):
opts.postprocessor_args['default'] = opts.postprocessor_args.pop('default-compat') opts.postprocessor_args['default'] = opts.postprocessor_args.pop('default-compat')
opts.postprocessor_args.setdefault('sponskrub', []) opts.postprocessor_args.setdefault('sponskrub', [])
def report_conflict(arg1, opt1, arg2='--allow-unplayable-formats', opt2='allow_unplayable_formats', def report_conflict(arg1, opt1, arg2, opt2, val1=NO_DEFAULT, val2=NO_DEFAULT, default=False):
val1=NO_DEFAULT, val2=NO_DEFAULT, default=False):
if val2 is NO_DEFAULT: if val2 is NO_DEFAULT:
val2 = getattr(opts, opt2) val2 = getattr(opts, opt2)
if not val2: if not val2:
@ -533,21 +532,6 @@ def validate_options(opts):
report_conflict('--sponskrub-cut', 'sponskrub_cut', '--split-chapter', 'split_chapters', report_conflict('--sponskrub-cut', 'sponskrub_cut', '--split-chapter', 'split_chapters',
val1=opts.sponskrub and opts.sponskrub_cut) val1=opts.sponskrub and opts.sponskrub_cut)
# Conflicts with --allow-unplayable-formats
report_conflict('--embed-metadata', 'addmetadata')
report_conflict('--embed-chapters', 'addchapters')
report_conflict('--embed-info-json', 'embed_infojson')
report_conflict('--embed-subs', 'embedsubtitles')
report_conflict('--embed-thumbnail', 'embedthumbnail')
report_conflict('--extract-audio', 'extractaudio')
report_conflict('--fixup', 'fixup', val1=opts.fixup not in (None, 'never', 'ignore'), default='never')
report_conflict('--recode-video', 'recodevideo')
report_conflict('--remove-chapters', 'remove_chapters', default=[])
report_conflict('--remux-video', 'remuxvideo')
report_conflict('--sponskrub', 'sponskrub')
report_conflict('--sponsorblock-remove', 'sponsorblock_remove', default=set())
report_conflict('--xattrs', 'xattrs')
# Fully deprecated options # Fully deprecated options
def report_deprecation(val, old, new=None): def report_deprecation(val, old, new=None):
if not val: if not val:

View file

@ -470,7 +470,6 @@ class FFmpegFD(ExternalFD):
return ( return (
info_dict.get('requested_formats') info_dict.get('requested_formats')
and info_dict.get('protocol') and info_dict.get('protocol')
and not params.get('allow_unplayable_formats')
and 'no-direct-merge' not in params.get('compat_opts', []) and 'no-direct-merge' not in params.get('compat_opts', [])
and cls.can_download(info_dict)) and cls.can_download(info_dict))

View file

@ -256,14 +256,13 @@ class F4mFD(FragmentFD):
media = doc.findall(_add_ns('media')) media = doc.findall(_add_ns('media'))
if not media: if not media:
self.report_error('No media found') self.report_error('No media found')
if not self.params.get('allow_unplayable_formats'): for e in (doc.findall(_add_ns('drmAdditionalHeader'))
for e in (doc.findall(_add_ns('drmAdditionalHeader')) + doc.findall(_add_ns('drmAdditionalHeaderSet'))):
+ doc.findall(_add_ns('drmAdditionalHeaderSet'))): # If id attribute is missing it's valid for all media nodes
# If id attribute is missing it's valid for all media nodes # without drmAdditionalHeaderId or drmAdditionalHeaderSetId attribute
# without drmAdditionalHeaderId or drmAdditionalHeaderSetId attribute if 'id' not in e.attrib:
if 'id' not in e.attrib: self.report_error('Missing ID in f4m DRM')
self.report_error('Missing ID in f4m DRM') media = remove_encrypted_media(media)
media = remove_encrypted_media(media)
if not media: if not media:
self.report_error('Unsupported DRM') self.report_error('Unsupported DRM')
return media return media

View file

@ -15,6 +15,7 @@ from ..utils import (
traverse_obj, traverse_obj,
update_url_query, update_url_query,
urljoin, urljoin,
deprecation_warning,
) )
@ -38,6 +39,8 @@ class HlsFD(FragmentFD):
@classmethod @classmethod
def can_download(cls, manifest, info_dict, allow_unplayable_formats=False): def can_download(cls, manifest, info_dict, allow_unplayable_formats=False):
if allow_unplayable_formats:
deprecation_warning('allow_unplayable_formats is not supported', stacklevel=1)
UNSUPPORTED_FEATURES = [ UNSUPPORTED_FEATURES = [
# r'#EXT-X-BYTERANGE', # playlists composed of byte ranges of media files [2] # r'#EXT-X-BYTERANGE', # playlists composed of byte ranges of media files [2]
@ -57,17 +60,15 @@ class HlsFD(FragmentFD):
# 4. https://tools.ietf.org/html/draft-pantos-http-live-streaming-17#section-4.3.3.5 # 4. https://tools.ietf.org/html/draft-pantos-http-live-streaming-17#section-4.3.3.5
# 5. https://tools.ietf.org/html/draft-pantos-http-live-streaming-17#section-4.3.2.5 # 5. https://tools.ietf.org/html/draft-pantos-http-live-streaming-17#section-4.3.2.5
] ]
if not allow_unplayable_formats: UNSUPPORTED_FEATURES += [
UNSUPPORTED_FEATURES += [ r'#EXT-X-KEY:METHOD=(?!NONE|AES-128)', # encrypted streams [1], but not necessarily DRM
r'#EXT-X-KEY:METHOD=(?!NONE|AES-128)', # encrypted streams [1], but not necessarily DRM ]
]
def check_results(): def check_results():
yield not info_dict.get('is_live') yield not info_dict.get('is_live')
for feature in UNSUPPORTED_FEATURES: for feature in UNSUPPORTED_FEATURES:
yield not re.search(feature, manifest) yield not re.search(feature, manifest)
if not allow_unplayable_formats: yield not cls._has_drm(manifest)
yield not cls._has_drm(manifest)
return all(check_results()) return all(check_results())
def real_download(self, filename, info_dict): def real_download(self, filename, info_dict):
@ -78,7 +79,7 @@ class HlsFD(FragmentFD):
man_url = urlh.url man_url = urlh.url
s = urlh.read().decode('utf-8', 'ignore') s = urlh.read().decode('utf-8', 'ignore')
can_download, message = self.can_download(s, info_dict, self.params.get('allow_unplayable_formats')), None can_download, message = self.can_download(s, info_dict), None
if can_download: if can_download:
has_ffmpeg = FFmpegFD.available() has_ffmpeg = FFmpegFD.available()
no_crypto = not Cryptodome.AES and '#EXT-X-KEY:METHOD=AES-128' in s no_crypto = not Cryptodome.AES and '#EXT-X-KEY:METHOD=AES-128' in s
@ -92,7 +93,7 @@ class HlsFD(FragmentFD):
message = ('Live HLS streams are not supported by the native downloader. If this is a livestream, ' message = ('Live HLS streams are not supported by the native downloader. If this is a livestream, '
f'please {install_ffmpeg}add "--downloader ffmpeg --hls-use-mpegts" to your command') f'please {install_ffmpeg}add "--downloader ffmpeg --hls-use-mpegts" to your command')
if not can_download: if not can_download:
if self._has_drm(s) and not self.params.get('allow_unplayable_formats'): if self._has_drm(s):
if info_dict.get('has_drm') and self.params.get('test'): if info_dict.get('has_drm') and self.params.get('test'):
self.to_screen(f'[{self.FD_NAME}] This format is DRM protected', skip_eol=True) self.to_screen(f'[{self.FD_NAME}] This format is DRM protected', skip_eol=True)
else: else: