docs: 为全部代码补充中文注释并加入 AGENTS 注释规范

This commit is contained in:
cat-shark
2026-08-13 22:09:55 +08:00
parent 41f8dc8d46
commit 90583d1dca
5 changed files with 46 additions and 1 deletions
+4 -1
View File
@@ -1 +1,4 @@
"""WOV SRT to dual-eye ASS node."""
"""WOV SRT 转 VR 双眼 ASS 字幕节点。
把翻译后的中文 SRT 转换为左右眼并排显示的 ASS 字幕,供 VR 播放器使用。
"""
+19
View File
@@ -1,3 +1,9 @@
"""SRT 转 ASS 节点入口。
解析标准 SRT 后生成 ASS 文件,其中同一句字幕同时输出 LeftEye 与 RightEye
两个样式,分别落在屏幕左右两半,形成 VR 双眼叠加效果。
"""
from __future__ import annotations
import json
@@ -8,7 +14,9 @@ from wov_sdk.server import run_node
def _ass_header(resolution: str) -> str:
"""生成 ASS 文件头:脚本信息、左右眼样式和事件格式。"""
width, height = resolution.lower().split("x", 1)
# 左眼样式占左半边,右眼样式占右半边,各留 50px 内边距。
left_margin = 50
right_margin = int(width) - 50
return f"""[Script Info]
@@ -31,21 +39,27 @@ Format: Layer,Start,End,Style,Name,MarginL,MarginR,MarginV,Effect,Text
def parse_srt(text: str) -> list[tuple[str, str, str]]:
"""把 SRT 文本解析为 (开始时间, 结束时间, 文本) 条目列表。"""
entries: list[tuple[str, str, str]] = []
lines = text.splitlines()
index = 0
while index < len(lines):
# 跳过序号前的空行,兼容文件开头有换行的情况。
if not lines[index].strip():
index += 1
continue
# 跳过序号行,直接读取下一行时间轴。
index += 1
if index >= len(lines):
break
time_line = lines[index].strip()
index += 1
# 时间轴必须包含分隔符,否则按畸形输入跳过。
if " --> " not in time_line:
continue
# SRT 使用逗号毫秒,ASS 使用点号,需要转换。
start, end = [part.replace(",", ".") for part in time_line.split(" --> ")]
# 连续读取非空行作为字幕文本,多行用 ASS 换行符 \N 连接。
text_lines: list[str] = []
while index < len(lines) and lines[index].strip():
text_lines.append(lines[index])
@@ -56,14 +70,17 @@ def parse_srt(text: str) -> list[tuple[str, str, str]]:
def write_ass(entries: list[tuple[str, str, str]], output_path: Path, resolution: str) -> None:
"""把解析后的条目写入 ASS 文件,每个条目输出左右眼两行 Dialogue。"""
lines = [_ass_header(resolution)]
for start, end, text in entries:
# an2 对齐到屏幕中央偏下,保证双眼字幕视线自然。
lines.append(f"Dialogue: 0,{start},{end},LeftEye,,0,0,0,,{{\\an2}}{text}")
lines.append(f"Dialogue: 0,{start},{end},RightEye,,0,0,0,,{{\\an2}}{text}")
output_path.write_text("\n".join(lines) + "\n", encoding="utf-8")
def invoke(request: InvokeRequest) -> InvokeResponse:
"""把 cn_srt_uri 指向的 SRT 转为 dual_eye.ass 产物。"""
srt_uri = request.inputs.get("cn_srt_uri")
if not srt_uri:
return InvokeResponse(status="failed", error="cn_srt_uri is required")
@@ -76,12 +93,14 @@ def invoke(request: InvokeRequest) -> InvokeResponse:
output_dir = Path(request.output_dir)
output_dir.mkdir(parents=True, exist_ok=True)
output_path = output_dir / "dual_eye.ass"
# 分辨率默认 3840x1920,覆盖常见 VR 视频尺寸。
resolution = str(request.params.get("resolution", "3840x1920"))
write_ass(entries, output_path, resolution)
return InvokeResponse(status="completed", outputs={"ass_uri": str(output_path)})
def main() -> None:
"""加载节点清单并以本模块的 invoke 处理器启动服务。"""
manifest_path = Path(__file__).resolve().parent.parent / "node.manifest.json"
with open(manifest_path, "r", encoding="utf-8") as f:
manifest = NodeManifest.from_dict(json.load(f))