Files
capcut-mate/scripts/gen_effect_docs.py
2026-08-06 10:56:56 +08:00

165 lines
5.8 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# -*- coding: utf-8 -*-
"""Generate effect_title lists and inject them into add_effects docs."""
from __future__ import annotations
import sys
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(ROOT))
from src.pyJianYingDraft.metadata import VideoSceneEffectType, VideoCharacterEffectType
MARKER_START = "<!-- EFFECT_LIST_START -->"
MARKER_END = "<!-- EFFECT_LIST_END -->"
EXAMPLE_EFFECT = "录制边框 III"
EXAMPLE_EFFECT_2 = "简约边框"
def _all_effect_names() -> list[str]:
names = {item.value.name for item in VideoSceneEffectType} | {
item.value.name for item in VideoCharacterEffectType
}
return sorted(names, key=lambda s: (s.casefold(), s))
def _validate(names: list[str]) -> None:
scene = {item.value.name for item in VideoSceneEffectType}
char = {item.value.name for item in VideoCharacterEffectType}
known = scene | char
bad = [n for n in names if n not in known]
if bad:
raise SystemExit(f"unresolvable effects: {bad[:10]}")
for example in (EXAMPLE_EFFECT, EXAMPLE_EFFECT_2):
if example not in known:
raise SystemExit(f"example effect unresolved: {example}")
def build_zh(names: list[str]) -> str:
scene_count = len({item.value.name for item in VideoSceneEffectType})
char_count = len({item.value.name for item in VideoCharacterEffectType})
return "\n".join(
[
"### 支持的特效名称effect_title 可用值)",
"",
"下列名称可直接作为 `effect_title` 的值(与剪映特效展示名一致,来自画面特效与人物特效)。未匹配到时添加会失败。",
"",
f"当前共 **{len(names)}** 种(画面特效 {scene_count} + 人物特效 {char_count},去重后):",
"",
"```text",
*names,
"```",
"",
]
)
def build_en(names: list[str]) -> str:
scene_count = len({item.value.name for item in VideoSceneEffectType})
char_count = len({item.value.name for item in VideoCharacterEffectType})
return "\n".join(
[
"### Supported Effect Names (`effect_title` values)",
"",
"Use the names below directly as `effect_title` (same as CapCut/Jianying display names; from scene effects and character effects). Unmatched names will fail.",
"",
f"Total: **{len(names)}** effects ({scene_count} scene + {char_count} character, after dedupe):",
"",
"```text",
*names,
"```",
"",
]
)
def inject(path: Path, before: str, block: str) -> None:
text = path.read_text(encoding="utf-8")
wrapped = f"{MARKER_START}\n{block.rstrip()}\n{MARKER_END}\n\n"
if MARKER_START in text and MARKER_END in text:
start = text.index(MARKER_START)
end = text.index(MARKER_END) + len(MARKER_END)
after = text[end:].lstrip("\n")
text = text[:start] + wrapped.rstrip("\n") + "\n\n" + after
else:
if before not in text:
raise SystemExit(f"insert marker not found in {path}: {before}")
text = text.replace(before, wrapped + before, 1)
path.write_text(text, encoding="utf-8")
def polish_zh(path: Path) -> None:
text = path.read_text(encoding="utf-8")
text = text.replace(
"[中文版](./add_audios.zh.md) | [English](./add_audios.md)",
"[中文版](./add_effects.zh.md) | [English](./add_effects.md)",
)
text = text.replace(
'- `effect_title`: 特效名称,必须是系统中已存在的特效名称',
'- `effect_title`: 特效名称,须为下方「支持的特效名称」列表中的值',
)
# Replace outdated vague name section with pointer (kept until marker replaces area)
old_section = """#### 特效名称说明
- **effect_title**: 特效的名称
- 格式:字符串
- 示例:`"录制边框 III"`
- 获取方式通过剪映特效库或相关API获取
- 常见特效名称:
- 边框特效:"录制边框 III", "简约边框", "霓虹边框"
- 滤镜特效:"复古滤镜", "黑白滤镜", "暖色调"
- 动态特效:"粒子效果", "光晕效果", "闪烁特效"
- 转场特效:"淡入淡出", "推拉门", "马赛克转场"
"""
if old_section in text and MARKER_START not in text:
text = text.replace(old_section, "")
elif old_section in text:
text = text.replace(old_section, "")
text = text.replace('\\"复古滤镜\\"', f'\\"{EXAMPLE_EFFECT_2}\\"')
text = text.replace('"复古滤镜"', f'"{EXAMPLE_EFFECT_2}"')
path.write_text(text, encoding="utf-8")
def polish_en(path: Path) -> None:
text = path.read_text(encoding="utf-8")
text = text.replace(
'- `effect_title`: Effect name, must be an existing effect name in the system',
'- `effect_title`: Effect name; must be one of the Supported Effect Names below',
)
# Prefer real CapCut titles in examples
text = text.replace("Recording Border III", EXAMPLE_EFFECT)
text = text.replace("Vintage Filter", EXAMPLE_EFFECT_2)
text = text.replace('\\"Recording Border III\\"', f'\\"{EXAMPLE_EFFECT}\\"')
text = text.replace('\\"Vintage Filter\\"', f'\\"{EXAMPLE_EFFECT_2}\\"')
path.write_text(text, encoding="utf-8")
def main() -> None:
names = _all_effect_names()
_validate(names)
docs = ROOT / "docs"
zh_path = docs / "add_effects.zh.md"
en_path = docs / "add_effects.md"
polish_zh(zh_path)
polish_en(en_path)
inject(zh_path, "## 响应格式", build_zh(names))
inject(en_path, "## Response Format", build_en(names))
# Re-run polish for example replacements that may sit after inject target
polish_zh(zh_path)
polish_en(en_path)
print(f"updated add_effects docs with {len(names)} effect titles")
if __name__ == "__main__":
main()