aboutsummaryrefslogtreecommitdiffstats
path: root/yt_dlp
diff options
context:
space:
mode:
Diffstat (limited to 'yt_dlp')
-rw-r--r--yt_dlp/YoutubeDL.py24
-rw-r--r--yt_dlp/options.py4
-rw-r--r--yt_dlp/utils.py2
3 files changed, 22 insertions, 8 deletions
diff --git a/yt_dlp/YoutubeDL.py b/yt_dlp/YoutubeDL.py
index 3350042c9..6ce0d19c3 100644
--- a/yt_dlp/YoutubeDL.py
+++ b/yt_dlp/YoutubeDL.py
@@ -35,6 +35,7 @@ from .compat import (
compat_kwargs,
compat_numeric_types,
compat_os_name,
+ compat_shlex_quote,
compat_str,
compat_tokenize_tokenize,
compat_urllib_error,
@@ -108,6 +109,7 @@ from .utils import (
try_get,
UnavailableVideoError,
url_basename,
+ variadic,
version_tuple,
write_json_file,
write_string,
@@ -871,9 +873,12 @@ class YoutubeDL(object):
@classmethod
def validate_outtmpl(cls, outtmpl):
''' @return None or Exception object '''
- outtmpl = cls.escape_outtmpl(cls._outtmpl_expandpath(outtmpl))
+ outtmpl = re.sub(
+ STR_FORMAT_RE_TMPL.format('[^)]*', '[ljq]'),
+ lambda mobj: f'{mobj.group(0)[:-1]}s',
+ cls._outtmpl_expandpath(outtmpl))
try:
- outtmpl % collections.defaultdict(int)
+ cls.escape_outtmpl(outtmpl) % collections.defaultdict(int)
return None
except ValueError as err:
return err
@@ -900,7 +905,7 @@ class YoutubeDL(object):
}
TMPL_DICT = {}
- EXTERNAL_FORMAT_RE = re.compile(STR_FORMAT_RE_TMPL.format('[^)]*', f'[{STR_FORMAT_TYPES}]'))
+ EXTERNAL_FORMAT_RE = re.compile(STR_FORMAT_RE_TMPL.format('[^)]*', f'[{STR_FORMAT_TYPES}ljq]'))
MATH_FUNCTIONS = {
'+': float.__add__,
'-': float.__sub__,
@@ -977,8 +982,15 @@ class YoutubeDL(object):
value = default if value is None else value
- if fmt == 'c':
- value = compat_str(value)
+ str_fmt = f'{fmt[:-1]}s'
+ if fmt[-1] == 'l':
+ value, fmt = ', '.join(variadic(value)), str_fmt
+ elif fmt[-1] == 'j':
+ value, fmt = json.dumps(value), str_fmt
+ elif fmt[-1] == 'q':
+ value, fmt = compat_shlex_quote(str(value)), str_fmt
+ elif fmt[-1] == 'c':
+ value = str(value)
if value is None:
value, fmt = default, 's'
else:
@@ -992,7 +1004,7 @@ class YoutubeDL(object):
if fmt[-1] == 'r':
# If value is an object, sanitize might convert it to a string
# So we convert it to repr first
- value, fmt = repr(value), '%ss' % fmt[:-1]
+ value, fmt = repr(value), str_fmt
if fmt[-1] in 'csr':
value = sanitize(mobj['fields'].split('.')[-1], value)
diff --git a/yt_dlp/options.py b/yt_dlp/options.py
index 5c3ac0dcd..9b71427d1 100644
--- a/yt_dlp/options.py
+++ b/yt_dlp/options.py
@@ -1286,11 +1286,11 @@ def parseOpts(overrideArguments=None):
'Execute a command on the file after downloading and post-processing. '
'Similar syntax to the output template can be used to pass any field as arguments to the command. '
'An additional field "filepath" that contains the final path of the downloaded file is also available. '
- 'If no fields are passed, "%(filepath)s" is appended to the end of the command'))
+ 'If no fields are passed, %(filepath)q is appended to the end of the command'))
postproc.add_option(
'--exec-before-download',
metavar='CMD', dest='exec_before_dl_cmd',
- help='Execute a command before the actual download. The syntax is the same as --exec')
+ help='Execute a command before the actual download. The syntax is the same as --exec but "filepath" is not available')
postproc.add_option(
'--convert-subs', '--convert-sub', '--convert-subtitles',
metavar='FORMAT', dest='convertsubtitles', default=None,
diff --git a/yt_dlp/utils.py b/yt_dlp/utils.py
index 2bd0925b6..998689efe 100644
--- a/yt_dlp/utils.py
+++ b/yt_dlp/utils.py
@@ -4451,8 +4451,10 @@ STR_FORMAT_RE_TMPL = r'''(?x)
)
'''
+
STR_FORMAT_TYPES = 'diouxXeEfFgGcrs'
+
def limit_length(s, length):
""" Add ellipses to overly long strings """
if s is None: