[core] Apply best logic to format selection by extension

Ensure that a format selected with `-f ext` is a combined format unless format extraction is marked incomplete.

Resolves https://github.com/yt-dlp/yt-dlp/issues/5989#issuecomment-1374758043.
This commit is contained in:
dirkf 2023-01-08 23:15:51 +00:00 committed by GitHub
parent 195f22f679
commit ba1399d54d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -87,6 +87,7 @@ from .utils import (
subtitles_filename, subtitles_filename,
UnavailableVideoError, UnavailableVideoError,
url_basename, url_basename,
variadic,
version_tuple, version_tuple,
write_json_file, write_json_file,
write_string, write_string,
@ -1298,57 +1299,46 @@ class YoutubeDL(object):
format_spec = selector.selector format_spec = selector.selector
def selector_function(ctx): def selector_function(ctx):
formats = list(ctx['formats'])
if not formats: def best_worst(fmts, fmt_spec='best'):
return format_idx = 0 if fmt_spec == 'worst' else -1
if format_spec == 'all':
for f in formats:
yield f
elif format_spec in ['best', 'worst', None]:
format_idx = 0 if format_spec == 'worst' else -1
audiovideo_formats = [ audiovideo_formats = [
f for f in formats f for f in fmts
if f.get('vcodec') != 'none' and f.get('acodec') != 'none'] if f.get('vcodec') != 'none' and f.get('acodec') != 'none']
if audiovideo_formats: if audiovideo_formats:
yield audiovideo_formats[format_idx] return audiovideo_formats[format_idx]
# for extractors with incomplete formats (audio only (soundcloud) # for extractors with incomplete formats (audio only (soundcloud)
# or video only (imgur)) we will fallback to best/worst # or video only (imgur)) we will fallback to best/worst
# {video,audio}-only format # {video,audio}-only format
elif ctx['incomplete_formats']: elif ctx['incomplete_formats']:
yield formats[format_idx] return fmts[format_idx]
elif format_spec == 'bestaudio':
formats = list(ctx['formats'])
if not formats:
return
if format_spec == 'all':
pass
elif format_spec in ('best', 'worst', None):
formats = best_worst(formats, format_spec)
elif format_spec in ('bestaudio', 'worstaudio'):
audio_formats = [ audio_formats = [
f for f in formats f for f in formats
if f.get('vcodec') == 'none'] if f.get('vcodec') == 'none']
if audio_formats: formats = audio_formats[:1] if format_spec == 'worstaudio' else audio_formats[-1:]
yield audio_formats[-1] elif format_spec in ('bestvideo', 'worstvideo'):
elif format_spec == 'worstaudio':
audio_formats = [
f for f in formats
if f.get('vcodec') == 'none']
if audio_formats:
yield audio_formats[0]
elif format_spec == 'bestvideo':
video_formats = [ video_formats = [
f for f in formats f for f in formats
if f.get('acodec') == 'none'] if f.get('acodec') == 'none']
if video_formats: formats = video_formats[:1] if format_spec == 'worstvideo' else video_formats[-1:]
yield video_formats[-1]
elif format_spec == 'worstvideo':
video_formats = [
f for f in formats
if f.get('acodec') == 'none']
if video_formats:
yield video_formats[0]
else: else:
extensions = ['mp4', 'flv', 'webm', '3gp', 'm4a', 'mp3', 'ogg', 'aac', 'wav'] extensions = ['mp4', 'flv', 'webm', '3gp', 'm4a', 'mp3', 'ogg', 'aac', 'wav']
if format_spec in extensions: if format_spec in extensions:
filter_f = lambda f: f['ext'] == format_spec filter_f = lambda f: f['ext'] == format_spec
else: else:
filter_f = lambda f: f['format_id'] == format_spec filter_f = lambda f: f['format_id'] == format_spec
matches = list(filter(filter_f, formats)) formats = best_worst(filter(filter_f, formats))
if matches: for f in variadic(formats or []):
yield matches[-1] yield f
elif selector.type == MERGE: elif selector.type == MERGE:
def _merge(formats_info): def _merge(formats_info):
format_1, format_2 = [f['format_id'] for f in formats_info] format_1, format_2 = [f['format_id'] for f in formats_info]