[utils] Add orderedSet_from_options

This commit is contained in:
pukkandan 2022-08-24 07:38:55 +05:30
parent 13db4e7b9e
commit 5314b52192
No known key found for this signature in database
GPG key ID: 7EEE9E1E817D0A39
3 changed files with 47 additions and 45 deletions

View file

@ -115,6 +115,7 @@ from .utils import (
network_exceptions, network_exceptions,
number_of_digits, number_of_digits,
orderedSet, orderedSet,
orderedSet_from_options,
parse_filesize, parse_filesize,
preferredencoding, preferredencoding,
prepend_extension, prepend_extension,
@ -2737,27 +2738,11 @@ class YoutubeDL:
if self.params.get('allsubtitles', False): if self.params.get('allsubtitles', False):
requested_langs = all_sub_langs requested_langs = all_sub_langs
elif self.params.get('subtitleslangs', False): elif self.params.get('subtitleslangs', False):
# A list is used so that the order of languages will be the same as try:
# given in subtitleslangs. See https://github.com/yt-dlp/yt-dlp/issues/1041 requested_langs = orderedSet_from_options(
requested_langs = [] self.params.get('subtitleslangs'), {'all': all_sub_langs}, use_regex=True)
for lang_re in self.params.get('subtitleslangs'): except re.error as e:
discard = lang_re[0] == '-' raise ValueError(f'Wrong regex for subtitlelangs: {e.pattern}')
if discard:
lang_re = lang_re[1:]
if lang_re == 'all':
if discard:
requested_langs = []
else:
requested_langs.extend(all_sub_langs)
continue
current_langs = filter(re.compile(lang_re + '$').match, all_sub_langs)
if discard:
for lang in current_langs:
while lang in requested_langs:
requested_langs.remove(lang)
else:
requested_langs.extend(current_langs)
requested_langs = orderedSet(requested_langs)
elif normal_sub_langs: elif normal_sub_langs:
requested_langs = ['en'] if 'en' in normal_sub_langs else normal_sub_langs[:1] requested_langs = ['en'] if 'en' in normal_sub_langs else normal_sub_langs[:1]
else: else:

View file

@ -29,6 +29,7 @@ from .utils import (
format_field, format_field,
get_executable_path, get_executable_path,
join_nonempty, join_nonempty,
orderedSet_from_options,
remove_end, remove_end,
write_string, write_string,
) )
@ -232,30 +233,16 @@ def create_parser():
current + value if append is True else value + current) current + value if append is True else value + current)
def _set_from_options_callback( def _set_from_options_callback(
option, opt_str, value, parser, delim=',', allowed_values=None, aliases={}, option, opt_str, value, parser, allowed_values, delim=',', aliases={},
process=lambda x: x.lower().strip()): process=lambda x: x.lower().strip()):
current = set(getattr(parser.values, option.dest)) values = [process(value)] if delim is None else map(process, value.split(delim))
values = [process(value)] if delim is None else list(map(process, value.split(delim)[::-1])) try:
while values: requested = orderedSet_from_options(values, collections.ChainMap(aliases, {'all': allowed_values}),
actual_val = val = values.pop() start=getattr(parser.values, option.dest))
if not val: except ValueError as e:
raise optparse.OptionValueError(f'Invalid {option.metavar} for {opt_str}: {value}') raise optparse.OptionValueError(f'wrong {option.metavar} for {opt_str}: {e.args[0]}')
if val == 'all':
current.update(allowed_values)
elif val == '-all':
current = set()
elif val in aliases:
values.extend(aliases[val])
else:
if val[0] == '-':
val = val[1:]
current.discard(val)
else:
current.update([val])
if allowed_values is not None and val not in allowed_values:
raise optparse.OptionValueError(f'wrong {option.metavar} for {opt_str}: {actual_val}')
setattr(parser.values, option.dest, current) setattr(parser.values, option.dest, set(requested))
def _dict_from_options_callback( def _dict_from_options_callback(
option, opt_str, value, parser, option, opt_str, value, parser,
@ -447,8 +434,8 @@ def create_parser():
'no-youtube-channel-redirect', 'no-youtube-unavailable-videos', 'no-attach-info-json', 'embed-metadata', 'no-youtube-channel-redirect', 'no-youtube-unavailable-videos', 'no-attach-info-json', 'embed-metadata',
'embed-thumbnail-atomicparsley', 'seperate-video-versions', 'no-clean-infojson', 'no-keep-subs', 'no-certifi', 'embed-thumbnail-atomicparsley', 'seperate-video-versions', 'no-clean-infojson', 'no-keep-subs', 'no-certifi',
}, 'aliases': { }, 'aliases': {
'youtube-dl': ['-multistreams', 'all'], 'youtube-dl': ['all', '-multistreams'],
'youtube-dlc': ['-no-youtube-channel-redirect', '-no-live-chat', 'all'], 'youtube-dlc': ['all', '-no-youtube-channel-redirect', '-no-live-chat'],
} }
}, help=( }, help=(
'Options that can help keep compatibility with youtube-dl or youtube-dlc ' 'Options that can help keep compatibility with youtube-dl or youtube-dlc '

View file

@ -5785,6 +5785,36 @@ def truncate_string(s, left, right=0):
return f'{s[:left-3]}...{s[-right:]}' return f'{s[:left-3]}...{s[-right:]}'
def orderedSet_from_options(options, alias_dict, *, use_regex=False, start=None):
assert 'all' in alias_dict, '"all" alias is required'
requested = list(start or [])
for val in options:
discard = val.startswith('-')
if discard:
val = val[1:]
if val in alias_dict:
val = alias_dict[val] if not discard else [
i[1:] if i.startswith('-') else f'-{i}' for i in alias_dict[val]]
# NB: Do not allow regex in aliases for performance
requested = orderedSet_from_options(val, alias_dict, start=requested)
continue
current = (filter(re.compile(val, re.I).fullmatch, alias_dict['all']) if use_regex
else [val] if val in alias_dict['all'] else None)
if current is None:
raise ValueError(val)
if discard:
for item in current:
while item in requested:
requested.remove(item)
else:
requested.extend(current)
return orderedSet(requested)
# Deprecated # Deprecated
has_certifi = bool(certifi) has_certifi = bool(certifi)
has_websockets = bool(websockets) has_websockets = bool(websockets)