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
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:
@@ -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,
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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\nC/D")
|
||||
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 行")
|
||||
|
||||
Reference in New Issue
Block a user