File size: 3,098 Bytes
5d782cc
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
from __future__ import annotations

import re
from copy import deepcopy
from typing import Any


PLACEHOLDER = re.compile(r"{{\s*([A-Za-z_][A-Za-z0-9_.-]*)\s*}}")

AUTOMATION_TEMPLATES: dict[str, dict[str, Any]] = {
    "vertical-captioned-clip": {
        "preset": "tiktok_9_16_fast",
        "output_name": "{{output_name}}",
        "scenes": "{{scenes}}",
        "voiceover": "{{voiceover}}",
        "background_music": "{{background_music}}",
        "auto_subtitles": True,
        "audio_normalize": True,
    },
    "podcast-clip": {
        "preset": "podcast_square",
        "output_name": "{{output_name}}",
        "scenes": "{{scenes}}",
        "auto_subtitles": True,
        "audio_normalize": True,
    },
    "product-promo": {
        "preset": "capcut_product_launch",
        "output_name": "{{output_name}}",
        "scenes": "{{scenes}}",
        "watermark": "{{watermark}}",
        "background_music": "{{background_music}}",
    },
}


def list_automation_templates() -> list[str]:
    return sorted(AUTOMATION_TEMPLATES)


def automation_template_catalog() -> dict[str, dict[str, Any]]:
    return deepcopy(AUTOMATION_TEMPLATES)


def resolve_render_template(
    template: str | dict[str, Any],
    variables: dict[str, Any],
    overrides: dict[str, Any] | None = None,
) -> dict[str, Any]:
    if isinstance(template, str):
        if template not in AUTOMATION_TEMPLATES:
            raise ValueError(f"Unknown automation template: {template}")
        source = deepcopy(AUTOMATION_TEMPLATES[template])
    elif isinstance(template, dict):
        source = deepcopy(template)
    else:
        raise ValueError("Template must be a registered name or JSON object")

    rendered = _substitute(source, variables)
    if not isinstance(rendered, dict):
        raise ValueError("Rendered template must produce a JSON object")
    return _deep_merge(rendered, overrides or {})


def _substitute(value: Any, variables: dict[str, Any]) -> Any:
    if isinstance(value, dict):
        return {key: _substitute(item, variables) for key, item in value.items()}
    if isinstance(value, list):
        return [_substitute(item, variables) for item in value]
    if not isinstance(value, str):
        return value

    exact = PLACEHOLDER.fullmatch(value)
    if exact:
        return deepcopy(_lookup(variables, exact.group(1)))

    return PLACEHOLDER.sub(lambda match: str(_lookup(variables, match.group(1))), value)


def _lookup(variables: dict[str, Any], key: str) -> Any:
    value: Any = variables
    for part in key.split("."):
        if not isinstance(value, dict) or part not in value:
            raise ValueError(f"Missing template variable: {key}")
        value = value[part]
    return value


def _deep_merge(base: dict[str, Any], overrides: dict[str, Any]) -> dict[str, Any]:
    output = deepcopy(base)
    for key, value in overrides.items():
        if isinstance(value, dict) and isinstance(output.get(key), dict):
            output[key] = _deep_merge(output[key], value)
        else:
            output[key] = deepcopy(value)
    return output