[extractor/common] Improve _sort_formats behavior customization
* Introduce the notion of criterion * Improve absolute criteria preference * Add ability to tweak relative criteria preference * Add ability to exclude criteria from consideration
This commit is contained in:
parent
141a273a8b
commit
c3f44d7db0
@ -764,7 +764,57 @@ class InfoExtractor(object):
|
|||||||
html, '%s form' % form_id, group='form')
|
html, '%s form' % form_id, group='form')
|
||||||
return self._hidden_inputs(form)
|
return self._hidden_inputs(form)
|
||||||
|
|
||||||
def _sort_formats(self, formats, field_preference=None):
|
def _sort_formats(self, formats, criteria_preference=None,
|
||||||
|
criteria_relative_preference=None, criteria_exclusion=None):
|
||||||
|
"""
|
||||||
|
Sort formats.
|
||||||
|
|
||||||
|
Sorting behavior can be customized by specifying absolute or relative criteria
|
||||||
|
order and criteria exclusion. Criteria is either a field from formats dictionary
|
||||||
|
or a synthetic expression calculated based on some data from formats dictionary.
|
||||||
|
Currently following criteria are supported for sorting customization:
|
||||||
|
|
||||||
|
Field criteria (see description of formats dict for each field explanation):
|
||||||
|
format_id
|
||||||
|
width
|
||||||
|
height
|
||||||
|
tbr
|
||||||
|
abr
|
||||||
|
vbr
|
||||||
|
fps
|
||||||
|
filesize
|
||||||
|
filesize_approx
|
||||||
|
language_preference
|
||||||
|
quality
|
||||||
|
source_preference
|
||||||
|
|
||||||
|
Synthetic criteria:
|
||||||
|
preference Calculated based on preference field with some corrections
|
||||||
|
proto_preference Calculated based on protocol field and prioritizes
|
||||||
|
direct HTTP(s) URLs
|
||||||
|
ext_preference Video extension preference, calculated based on ext field
|
||||||
|
and value of prefer_free_formats setting
|
||||||
|
audio_ext_preference Audio extension preference, calculated based on ext field
|
||||||
|
and value of prefer_free_formats setting
|
||||||
|
|
||||||
|
Default criteria preference (from most priority to least):
|
||||||
|
preference
|
||||||
|
language_preference
|
||||||
|
quality
|
||||||
|
tbr
|
||||||
|
filesize
|
||||||
|
vbr
|
||||||
|
height
|
||||||
|
width
|
||||||
|
proto_preference
|
||||||
|
ext_preference
|
||||||
|
abr
|
||||||
|
audio_ext_preference
|
||||||
|
fps
|
||||||
|
filesize_approx
|
||||||
|
source_preference
|
||||||
|
format_id
|
||||||
|
"""
|
||||||
if not formats:
|
if not formats:
|
||||||
raise ExtractorError('No video formats found')
|
raise ExtractorError('No video formats found')
|
||||||
|
|
||||||
@ -774,9 +824,6 @@ class InfoExtractor(object):
|
|||||||
if not f.get('ext') and 'url' in f:
|
if not f.get('ext') and 'url' in f:
|
||||||
f['ext'] = determine_ext(f['url'])
|
f['ext'] = determine_ext(f['url'])
|
||||||
|
|
||||||
if isinstance(field_preference, (list, tuple)):
|
|
||||||
return tuple(f.get(field) if f.get(field) is not None else -1 for field in field_preference)
|
|
||||||
|
|
||||||
preference = f.get('preference')
|
preference = f.get('preference')
|
||||||
if preference is None:
|
if preference is None:
|
||||||
preference = 0
|
preference = 0
|
||||||
@ -806,24 +853,59 @@ class InfoExtractor(object):
|
|||||||
ext_preference = -1
|
ext_preference = -1
|
||||||
audio_ext_preference = 0
|
audio_ext_preference = 0
|
||||||
|
|
||||||
return (
|
def synthetic_criterion(name, value):
|
||||||
preference,
|
return name, value
|
||||||
f.get('language_preference') if f.get('language_preference') is not None else -1,
|
|
||||||
f.get('quality') if f.get('quality') is not None else -1,
|
def field_criterion(name, default=-1):
|
||||||
f.get('tbr') if f.get('tbr') is not None else -1,
|
return name, f.get(name) if f.get(name) is not None else default
|
||||||
f.get('filesize') if f.get('filesize') is not None else -1,
|
|
||||||
f.get('vbr') if f.get('vbr') is not None else -1,
|
default_key = (
|
||||||
f.get('height') if f.get('height') is not None else -1,
|
synthetic_criterion('preference', preference),
|
||||||
f.get('width') if f.get('width') is not None else -1,
|
field_criterion('language_preference'),
|
||||||
proto_preference,
|
field_criterion('quality'),
|
||||||
ext_preference,
|
field_criterion('tbr'),
|
||||||
f.get('abr') if f.get('abr') is not None else -1,
|
field_criterion('filesize'),
|
||||||
audio_ext_preference,
|
field_criterion('vbr'),
|
||||||
f.get('fps') if f.get('fps') is not None else -1,
|
field_criterion('height'),
|
||||||
f.get('filesize_approx') if f.get('filesize_approx') is not None else -1,
|
field_criterion('width'),
|
||||||
f.get('source_preference') if f.get('source_preference') is not None else -1,
|
synthetic_criterion('proto_preference', proto_preference),
|
||||||
f.get('format_id') if f.get('format_id') is not None else '',
|
synthetic_criterion('ext_preference', ext_preference),
|
||||||
|
field_criterion('abr'),
|
||||||
|
synthetic_criterion('audio_ext_preference', audio_ext_preference),
|
||||||
|
field_criterion('fps'),
|
||||||
|
field_criterion('filesize_approx'),
|
||||||
|
field_criterion('source_preference'),
|
||||||
|
field_criterion('format_id', ''),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if (not criteria_preference and not criteria_relative_preference and
|
||||||
|
not criteria_exclusion):
|
||||||
|
return default_key
|
||||||
|
|
||||||
|
default_criteria_order = list(list(zip(*default_key))[0])
|
||||||
|
criteria_order = []
|
||||||
|
if criteria_preference:
|
||||||
|
for field in criteria_preference:
|
||||||
|
if field in default_criteria_order:
|
||||||
|
criteria_order.append(field)
|
||||||
|
else:
|
||||||
|
relative_order = (list(criteria_relative_preference)
|
||||||
|
if criteria_relative_preference else [])
|
||||||
|
while default_criteria_order:
|
||||||
|
field = default_criteria_order[0]
|
||||||
|
if field in relative_order:
|
||||||
|
for rel_field in relative_order:
|
||||||
|
if rel_field in default_criteria_order:
|
||||||
|
criteria_order.append(rel_field)
|
||||||
|
default_criteria_order.remove(rel_field)
|
||||||
|
else:
|
||||||
|
if not criteria_exclusion or field not in criteria_exclusion:
|
||||||
|
criteria_order.append(field)
|
||||||
|
default_criteria_order.remove(field)
|
||||||
|
|
||||||
|
default_key_dict = dict(default_key)
|
||||||
|
return [default_key_dict[field] for field in criteria_order]
|
||||||
|
|
||||||
formats.sort(key=_formats_key)
|
formats.sort(key=_formats_key)
|
||||||
|
|
||||||
def _check_formats(self, formats, video_id):
|
def _check_formats(self, formats, video_id):
|
||||||
|
Loading…
x
Reference in New Issue
Block a user