From 0898c5c8ccadfc404472456a7a7751b72afebadd Mon Sep 17 00:00:00 2001 From: Simon Sawicki Date: Sat, 25 Mar 2023 19:41:28 +0100 Subject: [PATCH] [utils] `js_to_json`: Implement template strings (#6623) Authored by: Grub4K --- test/test_utils.py | 7 +++++++ yt_dlp/utils.py | 11 +++++++++-- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/test/test_utils.py b/test/test_utils.py index 3045b6d7e..d4a301583 100644 --- a/test/test_utils.py +++ b/test/test_utils.py @@ -1190,6 +1190,13 @@ class TestUtil(unittest.TestCase): self.assertEqual(js_to_json('42a1'), '42"a1"') self.assertEqual(js_to_json('42a-1'), '42"a"-1') + def test_js_to_json_template_literal(self): + self.assertEqual(js_to_json('`Hello ${name}`', {'name': '"world"'}), '"Hello world"') + self.assertEqual(js_to_json('`${name}${name}`', {'name': '"X"'}), '"XX"') + self.assertEqual(js_to_json('`${name}${name}`', {'name': '5'}), '"55"') + self.assertEqual(js_to_json('`${name}"${name}"`', {'name': '5'}), '"5\\"5\\""') + self.assertEqual(js_to_json('`${name}`', {}), '"name"') + def test_extract_attributes(self): self.assertEqual(extract_attributes(''), {'x': 'y'}) self.assertEqual(extract_attributes(""), {'x': 'y'}) diff --git a/yt_dlp/utils.py b/yt_dlp/utils.py index 8c2c5593c..40533c2cb 100644 --- a/yt_dlp/utils.py +++ b/yt_dlp/utils.py @@ -3366,7 +3366,7 @@ def strip_jsonp(code): def js_to_json(code, vars={}, *, strict=False): # vars is a dict of var, val pairs to substitute - STRING_QUOTES = '\'"' + STRING_QUOTES = '\'"`' STRING_RE = '|'.join(rf'{q}(?:\\.|[^\\{q}])*{q}' for q in STRING_QUOTES) COMMENT_RE = r'/\*(?:(?!\*/).)*?\*/|//[^\n]*\n' SKIP_RE = fr'\s*(?:{COMMENT_RE})?\s*' @@ -3384,6 +3384,12 @@ def js_to_json(code, vars={}, *, strict=False): else '' if escape == '\n' else escape) + def template_substitute(match): + evaluated = js_to_json(match.group(1), vars, strict=strict) + if evaluated[0] == '"': + return json.loads(evaluated) + return evaluated + def fix_kv(m): v = m.group(0) if v in ('true', 'false', 'null'): @@ -3394,7 +3400,8 @@ def js_to_json(code, vars={}, *, strict=False): return '' if v[0] in STRING_QUOTES: - escaped = re.sub(r'(?s)(")|\\(.)', process_escape, v[1:-1]) + v = re.sub(r'(?s)\${([^}]+)}', template_substitute, v[1:-1]) if v[0] == '`' else v[1:-1] + escaped = re.sub(r'(?s)(")|\\(.)', process_escape, v) return f'"{escaped}"' for regex, base in INTEGER_TABLE: