Improve offset parsing in outtmpl

pull/401/head
pukkandan 4 years ago
parent 5c6542ce69
commit 385a27fad1
No known key found for this signature in database
GPG Key ID: 0F00D95A001F4698

@ -752,6 +752,7 @@ class TestYoutubeDL(unittest.TestCase):
test('%(formats.3)s', 'NA') test('%(formats.3)s', 'NA')
test('%(formats.:2:-1)r', repr(FORMATS[:2:-1])) test('%(formats.:2:-1)r', repr(FORMATS[:2:-1]))
test('%(formats.0.id.-1+id)f', '1235.000000') test('%(formats.0.id.-1+id)f', '1235.000000')
test('%(formats.0.id.-1+formats.1.id.-1)d', '3')
# Empty filename # Empty filename
test('%(foo|)s-%(bar|)s.%(ext)s', '-.mp4') test('%(foo|)s-%(bar|)s.%(ext)s', '-.mp4')

@ -847,23 +847,24 @@ class YoutubeDL(object):
'autonumber': self.params.get('autonumber_size') or 5, 'autonumber': self.params.get('autonumber_size') or 5,
} }
EXTERNAL_FORMAT_RE = STR_FORMAT_RE.format('[^)]*') TMPL_DICT = {}
EXTERNAL_FORMAT_RE = re.compile(STR_FORMAT_RE.format('[^)]*'))
MATH_FUNCTIONS = {
'+': float.__add__,
'-': float.__sub__,
}
# Field is of the form key1.key2... # Field is of the form key1.key2...
# where keys (except first) can be string, int or slice # where keys (except first) can be string, int or slice
FIELD_RE = r'\w+(?:\.(?:\w+|[-\d]*(?::[-\d]*){0,2}))*' FIELD_RE = r'\w+(?:\.(?:\w+|{num}|{num}?(?::{num}?){{1,2}}))*'.format(num=r'(?:-?\d+)')
MATH_FIELD_RE = r'''{field}|{num}'''.format(field=FIELD_RE, num=r'-?\d+(?:.\d+)?')
MATH_OPERATORS_RE = r'(?:%s)' % '|'.join(map(re.escape, MATH_FUNCTIONS.keys()))
INTERNAL_FORMAT_RE = re.compile(r'''(?x) INTERNAL_FORMAT_RE = re.compile(r'''(?x)
(?P<negate>-)? (?P<negate>-)?
(?P<fields>{0}) (?P<fields>{field})
(?P<maths>(?:[-+]-?(?:\d+(?:\.\d+)?|{0}))*) (?P<maths>(?:{math_op}{math_field})*)
(?:>(?P<strf_format>.+?))? (?:>(?P<strf_format>.+?))?
(?:\|(?P<default>.*?))? (?:\|(?P<default>.*?))?
$'''.format(FIELD_RE)) $'''.format(field=FIELD_RE, math_op=MATH_OPERATORS_RE, math_field=MATH_FIELD_RE))
MATH_OPERATORS_RE = re.compile(r'(?<![-+])([-+])')
MATH_FUNCTIONS = {
'+': float.__add__,
'-': float.__sub__,
}
tmpl_dict = {}
get_key = lambda k: traverse_obj( get_key = lambda k: traverse_obj(
info_dict, k.split('.'), is_user_input=True, traverse_string=True) info_dict, k.split('.'), is_user_input=True, traverse_string=True)
@ -877,24 +878,27 @@ class YoutubeDL(object):
if value is not None: if value is not None:
value *= -1 value *= -1
# Do maths # Do maths
if mdict['maths']: offset_key = mdict['maths']
if offset_key:
value = float_or_none(value) value = float_or_none(value)
operator = None operator = None
for item in MATH_OPERATORS_RE.split(mdict['maths'])[1:]: while offset_key:
if item == '' or value is None: item = re.match(
return None MATH_FIELD_RE if operator else MATH_OPERATORS_RE,
if operator: offset_key).group(0)
item, multiplier = (item[1:], -1) if item[0] == '-' else (item, 1) offset_key = offset_key[len(item):]
offset = float_or_none(item) if operator is None:
if offset is None:
offset = float_or_none(get_key(item))
try:
value = operator(value, multiplier * offset)
except (TypeError, ZeroDivisionError):
return None
operator = None
else:
operator = MATH_FUNCTIONS[item] operator = MATH_FUNCTIONS[item]
continue
item, multiplier = (item[1:], -1) if item[0] == '-' else (item, 1)
offset = float_or_none(item)
if offset is None:
offset = float_or_none(get_key(item))
try:
value = operator(value, multiplier * offset)
except (TypeError, ZeroDivisionError):
return None
operator = None
# Datetime formatting # Datetime formatting
if mdict['strf_format']: if mdict['strf_format']:
value = strftime_or_none(value, mdict['strf_format']) value = strftime_or_none(value, mdict['strf_format'])
@ -938,10 +942,10 @@ class YoutubeDL(object):
value, fmt = repr(value), '%ss' % fmt[:-1] value, fmt = repr(value), '%ss' % fmt[:-1]
if fmt[-1] in 'csr': if fmt[-1] in 'csr':
value = sanitize(key, value) value = sanitize(key, value)
tmpl_dict[key] = value TMPL_DICT[key] = value
return '%({key}){fmt}'.format(key=key, fmt=fmt) return '%({key}){fmt}'.format(key=key, fmt=fmt)
return re.sub(EXTERNAL_FORMAT_RE, create_key, outtmpl), tmpl_dict return EXTERNAL_FORMAT_RE.sub(create_key, outtmpl), TMPL_DICT
def _prepare_filename(self, info_dict, tmpl_type='default'): def _prepare_filename(self, info_dict, tmpl_type='default'):
try: try:

Loading…
Cancel
Save