fix: 标题/换行 + TTS replace模式静音原音 + 配音素材库静音原音 (#1504)
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 46s
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 56s
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 2m52s
CI/CD Pipeline / Build Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 3m7s
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 3m2s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 3m4s
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 29s
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 32s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been skipped
CI/CD Pipeline / Build Staging API Image (push) Successful in 5m38s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 5m38s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 2m56s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 3m13s
AI Code Review / AI Code Review (pull_request) Successful in 5m25s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 55s
CI/CD Pipeline / Staging E2E Tests (push) Successful in 1m16s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 1m19s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 7m9s
CI/CD Pipeline / Validate - Code Quality (push) Successful in 9m47s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 3m28s
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 9m40s
CI/CD Pipeline / Integration Tests (push) Successful in 4m40s
CI/CD Pipeline / Unit Tests (push) Successful in 14m37s
CI/CD Pipeline / Build Production API Image (push) Has been skipped
CI/CD Pipeline / CI Gate (push) Has been skipped
CI/CD Pipeline / Build Production Web Image (push) Has been skipped
CI/CD Pipeline / Build Production Worker Image (push) Has been skipped
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Canary Release to Production (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / Integration Tests (pull_request) Successful in 4m58s
CI/CD Pipeline / Unit Tests (pull_request) Successful in 12m59s
CI/CD Pipeline / Build Production API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Deploy Production (pull_request) Has been skipped
CI/CD Pipeline / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / CI Gate (pull_request) Successful in 7s

Co-authored-by: xiaoxia <dev@xiaoxiajianji.com>
Co-committed-by: xiaoxia <dev@xiaoxiajianji.com>
This commit was merged in pull request #1504.
This commit is contained in:
2026-08-25 23:06:00 +08:00
committed by auto-approve-bot
parent 058bfac5c2
commit 323bd2da5e
5 changed files with 82 additions and 0 deletions
@@ -824,6 +824,17 @@ class UnifiedRenderService:
)
audio_layer.clips.append(vo_clip)
# replace 模式:静音原视频音轨(main + broll 图层)
if tts_config.overlap_mode == "replace":
for layer in layers:
if layer.role in ("main", "broll"):
for clip in layer.clips:
clip.config["volume"] = 0
logger.info(
"TTS replace 模式:已静音原视频音轨: plan_id=%s",
self.plan.id,
)
logger.info(
"TTS 配音已添加: plan_id=%s voice_id=%s segments=%d total_%.2fs",
self.plan.id,
@@ -889,6 +900,16 @@ class UnifiedRenderService:
)
audio_layer.clips.append(vo_clip)
# 配音素材库默认替换原音:静音原视频音轨(main + broll 图层)
for layer in layers:
if layer.role in ("main", "broll"):
for clip in layer.clips:
clip.config["volume"] = 0
logger.info(
"配音素材库:已静音原视频音轨: plan_id=%s",
self.plan.id,
)
logger.info(
"配音素材库音频已添加到 audio 图层: plan_id=%s duration=%.2fs",
self.plan.id,
+2
View File
@@ -147,6 +147,8 @@ def escape_ass_text(text: str) -> str:
Returns:
转义后的 ASS 文本
"""
# 用户手动换行符(半角/全角斜杠)转为 ASS 硬换行(在自动换行之前优先处理)
text = text.replace("", "\\N").replace("/", "\\N")
# 将实际换行转为 ASS 硬换行
text = text.replace("\r\n", "\\N").replace("\n", "\\N").replace("\r", "\\N")
# 转义大括号(ASS 用它做样式覆盖标签)
@@ -218,6 +218,14 @@ class TestEscapeAssText:
def test_chinese_text(self):
assert escape_ass_text("你好世界") == "你好世界"
def test_slash_converted_to_newline(self):
"""半角斜杠 / 应转为 ASS 硬换行。"""
assert escape_ass_text("标题一/标题二") == "标题一\\N标题二"
def test_fullwidth_slash_converted_to_newline(self):
"""全角斜杠 应转为 ASS 硬换行。"""
assert escape_ass_text("标题一/标题二") == "标题一\\N标题二"
def test_backslash_n_in_input(self):
# 文本里本身有 \n 字符串(不是换行符)
result = escape_ass_text("\\n")
+13
View File
@@ -190,6 +190,19 @@ class TestEscapeAssText:
def test_chinese_text(self):
assert escape_ass_text("你好世界") == "你好世界"
def test_slash_converted_to_newline(self):
"""半角斜杠 / 应转为 ASS 硬换行。"""
assert escape_ass_text("第一行/第二行") == "第一行\\N第二行"
def test_fullwidth_slash_converted_to_newline(self):
"""全角斜杠 应转为 ASS 硬换行。"""
assert escape_ass_text("第一行/第二行") == "第一行\\N第二行"
def test_mixed_slashes_and_newlines(self):
"""斜杠和换行符都应转为硬换行。"""
result = escape_ass_text("A/B\nCD")
assert result == "A\\NB\\NC\\ND"
# ── 时间格式化 ────────────────────────────────────────────────────────────────
@@ -10,6 +10,8 @@
import sys
from pathlib import Path
import pytest
# Ensure packages is importable
sys.path.insert(0, str(Path(__file__).resolve().parents[2] / "packages"))
@@ -239,3 +241,39 @@ class TestFullStyleConsistency:
assert int(fields[17]) == 2
# Alignment = 8 (top)
assert int(fields[18]) == 8
class TestTitleSlashNewline:
"""用户输入 / 或 应触发标题换行。"""
def test_halfwidth_slash_in_title(self):
content = build_ass_content(
video_width=1080,
video_height=1920,
video_duration=10.0,
title_text="第一行/第二行",
title_config={"size": 48},
)
for line in content.splitlines():
if "Dialogue" in line and "TitleStyle" in line:
assert "\\N" in line, f"斜杠应转为换行: {line}"
assert "第一行" in line
assert "第二行" in line
break
else:
pytest.fail("未找到 TitleStyle Dialogue 行")
def test_fullwidth_slash_in_title(self):
content = build_ass_content(
video_width=1080,
video_height=1920,
video_duration=10.0,
title_text="第一行/第二行",
title_config={"size": 48},
)
for line in content.splitlines():
if "Dialogue" in line and "TitleStyle" in line:
assert "\\N" in line, f"全角斜杠应转为换行: {line}"
break
else:
pytest.fail("未找到 TitleStyle Dialogue 行")