From d818eb747361117ec86a5c4fe217d5d6956f36d3 Mon Sep 17 00:00:00 2001 From: pukkandan Date: Sat, 10 Apr 2021 20:30:38 +0530 Subject: [PATCH] Improve argument parsing for `-P`, `-o`, `-S` * `-P "subtitle,thumbnail:PATH"` is now possible. Similarly for `-o` * `-S "fps,br" -S "res,codec"` is now interpreted as `-S res,codec,fps,br`. Previously, `-S fps,br` was ignored in this case. --- README.md | 4 ++-- yt_dlp/options.py | 32 ++++++++++++++++++++++---------- 2 files changed, 24 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 67c3c4923..5c085c6f2 100644 --- a/README.md +++ b/README.md @@ -365,7 +365,7 @@ Then simply run `make`. You can also run `make yt-dlp` instead to compile only t stdin), one URL per line. Lines starting with '#', ';' or ']' are considered as comments and ignored - -P, --paths TYPE:PATH The paths where the files should be + -P, --paths TYPES:PATH The paths where the files should be downloaded. Specify the type of file and the path separated by a colon ":". All the same types as --output are supported. @@ -376,7 +376,7 @@ Then simply run `make`. You can also run `make yt-dlp` instead to compile only t home path after download is finished. This option is ignored if --output is an absolute path - -o, --output [TYPE:]TEMPLATE Output filename template, see "OUTPUT + -o, --output [TYPES:]TEMPLATE Output filename template; see "OUTPUT TEMPLATE" for details --output-na-placeholder TEXT Placeholder value for unavailable meta fields in output filename template diff --git a/yt_dlp/options.py b/yt_dlp/options.py index 1057cb643..6b4736e97 100644 --- a/yt_dlp/options.py +++ b/yt_dlp/options.py @@ -107,22 +107,31 @@ def parseOpts(overrideArguments=None): return ''.join(opts) - def _comma_separated_values_options_callback(option, opt_str, value, parser): - setattr(parser.values, option.dest, value.split(',')) + def _comma_separated_values_options_callback(option, opt_str, value, parser, prepend=True): + setattr( + parser.values, option.dest, + value.split(',') if not prepend + else value.split(',') + getattr(parser.values, option.dest)) def _dict_from_multiple_values_options_callback( - option, opt_str, value, parser, allowed_keys=r'[\w-]+', delimiter=':', default_key=None, process=None): + option, opt_str, value, parser, + allowed_keys=r'[\w-]+', delimiter=':', default_key=None, process=None, multiple_keys=True): out_dict = getattr(parser.values, option.dest) - mobj = re.match(r'(?i)(?P%s)%s(?P.*)$' % (allowed_keys, delimiter), value) + if multiple_keys: + allowed_keys = r'(%s)(,(%s))*' % (allowed_keys, allowed_keys) + mobj = re.match(r'(?i)(?P%s)%s(?P.*)$' % (allowed_keys, delimiter), value) if mobj is not None: - key, val = mobj.group('key').lower(), mobj.group('val') + keys = [k.strip() for k in mobj.group('keys').lower().split(',')] + val = mobj.group('val') elif default_key is not None: - key, val = default_key, value + keys, val = [default_key], value else: raise optparse.OptionValueError( 'wrong %s formatting; it should be %s, not "%s"' % (opt_str, option.metavar, value)) - out_dict[key] = process(val) if callable(process) else val + val = process(val) if callable(process) else val + for key in keys: + out_dict[key] = val # No need to wrap help messages if we're on a wide console columns = compat_get_terminal_size().columns @@ -693,6 +702,7 @@ def parseOpts(overrideArguments=None): '--add-header', metavar='FIELD:VALUE', dest='headers', default={}, type='str', action='callback', callback=_dict_from_multiple_values_options_callback, + callback_kwargs={'multiple_keys': False}, help='Specify a custom HTTP header and its value, separated by a colon ":". You can use this option multiple times', ) workarounds.add_option( @@ -842,7 +852,7 @@ def parseOpts(overrideArguments=None): action='store_true', dest='useid', help=optparse.SUPPRESS_HELP) filesystem.add_option( '-P', '--paths', - metavar='TYPE:PATH', dest='paths', default={}, type='str', + metavar='TYPES:PATH', dest='paths', default={}, type='str', action='callback', callback=_dict_from_multiple_values_options_callback, callback_kwargs={ 'allowed_keys': 'home|temp|%s' % '|'.join(OUTTMPL_TYPES.keys()), @@ -857,7 +867,7 @@ def parseOpts(overrideArguments=None): 'This option is ignored if --output is an absolute path')) filesystem.add_option( '-o', '--output', - metavar='[TYPE:]TEMPLATE', dest='outtmpl', default={}, type='str', + metavar='[TYPES:]TEMPLATE', dest='outtmpl', default={}, type='str', action='callback', callback=_dict_from_multiple_values_options_callback, callback_kwargs={ 'allowed_keys': '|'.join(OUTTMPL_TYPES.keys()), @@ -1084,7 +1094,9 @@ def parseOpts(overrideArguments=None): '--postprocessor-args', '--ppa', metavar='NAME:ARGS', dest='postprocessor_args', default={}, type='str', action='callback', callback=_dict_from_multiple_values_options_callback, - callback_kwargs={'default_key': 'default-compat', 'allowed_keys': r'\w+(?:\+\w+)?', 'process': compat_shlex_split}, + callback_kwargs={ + 'allowed_keys': r'\w+(?:\+\w+)?', 'default_key': 'default-compat', + 'process': compat_shlex_split, 'multiple_keys': False}, help=( 'Give these arguments to the postprocessors. ' 'Specify the postprocessor/executable name and the arguments separated by a colon ":" '