diff --git a/docs/formatting.md b/docs/formatting.md index bf88d275..75f32f6a 100644 --- a/docs/formatting.md +++ b/docs/formatting.md @@ -202,6 +202,12 @@ Format specifiers can be used for advanced formatting by using the options provi {foo:Ro/()/} F()() Bar + + A<op><value>/ + Apply arithmetic operation <op> (+, -, *) to the current value + {num:A+1/} + "2" + C<conversion(s)>/ Apply Conversions to the current value diff --git a/gallery_dl/formatter.py b/gallery_dl/formatter.py index ec1c926a..f197e5db 100644 --- a/gallery_dl/formatter.py +++ b/gallery_dl/formatter.py @@ -325,6 +325,23 @@ def _parse_slice(format_spec, default): return apply_slice +def _parse_arithmetic(format_spec, default): + op, _, format_spec = format_spec.partition(_SEPARATOR) + fmt = _build_format_func(format_spec, default) + + value = int(op[2:]) + op = op[1] + + if op == "+": + return lambda obj: fmt(obj + value) + if op == "-": + return lambda obj: fmt(obj - value) + if op == "*": + return lambda obj: fmt(obj * value) + + return fmt + + def _parse_conversion(format_spec, default): conversions, _, format_spec = format_spec.partition(_SEPARATOR) convs = [_CONVERSIONS[c] for c in conversions[1:]] @@ -480,6 +497,7 @@ _CONVERSIONS = { _FORMAT_SPECIFIERS = { "?": _parse_optional, "[": _parse_slice, + "A": _parse_arithmetic, "C": _parse_conversion, "D": _parse_datetime, "J": _parse_join, diff --git a/test/test_formatter.py b/test/test_formatter.py index e00af854..75324fb9 100644 --- a/test/test_formatter.py +++ b/test/test_formatter.py @@ -25,6 +25,7 @@ class TestFormatter(unittest.TestCase): "b": "äöü", "j": "げんそうきょう", "d": {"a": "foo", "b": 0, "c": None}, + "i": 2, "l": ["a", "b", "c"], "n": None, "s": " \n\r\tSPACE ", @@ -267,6 +268,11 @@ class TestFormatter(unittest.TestCase): "{a:Sort-reverse}", # starts with 'S', contains 'r' "['w', 'r', 'o', 'l', 'h', 'd', 'O', 'L', 'L', 'E', ' ']") + def test_specifier_arithmetic(self): + self._run_test("{i:A+1}", "3") + self._run_test("{i:A-1}", "1") + self._run_test("{i:A*3}", "6") + def test_specifier_conversions(self): self._run_test("{a:Cl}" , "hello world") self._run_test("{h:CHC}" , "Foo & Bar")