Files
harry0703--moneyprinterturbo/test/services/test_subtitle_background_settings.py
wehub-resource-sync 9a6da7d40d
Publish Docker image / Build and publish (push) Failing after 0s
CI / Python tests (push) Failing after 4s
chore: import upstream snapshot with attribution
2026-07-13 12:03:55 +08:00

165 lines
6.0 KiB
Python

import json
from pathlib import Path
import unittest
import numpy as np
from app.models.schema import SubtitleRequest, VideoParams
from app.services import video
class TestSubtitleBackgroundSettings(unittest.TestCase):
def test_subtitle_background_is_disabled_by_default(self):
"""新任务和独立字幕接口都不应在用户未指定时渲染字幕背景。"""
video_params = VideoParams(video_subject="default subtitle background")
subtitle_request = SubtitleRequest(video_script="default subtitle background")
self.assertFalse(video_params.text_background_color)
self.assertFalse(subtitle_request.text_background_color)
def test_all_locales_include_subtitle_background_labels(self):
"""
WebUI 新增字幕背景开关和颜色选择器后,所有已有语言都必须包含对应
翻译 key,避免某些语言界面直接显示英文内部 key。
"""
i18n_dir = Path(__file__).parent.parent.parent / "webui" / "i18n"
required_keys = {
"Enable Subtitle Background",
"Subtitle Background Color",
"Subtitle Colors Are Indistinguishable",
"Subtitle Font Does Not Support Text",
"No Voice",
}
for locale_file in i18n_dir.glob("*.json"):
with self.subTest(locale=locale_file.name):
data = json.loads(locale_file.read_text(encoding="utf-8"))
translations = data.get("Translation", {})
missing_keys = required_keys - translations.keys()
self.assertEqual(missing_keys, set())
def test_video_params_accepts_disabled_and_colored_subtitle_background(self):
"""
UI 会根据开关向后端传递 False 或颜色字符串。这里验证 schema 仍然
接受这两种值,避免后续依赖或类型调整破坏 WebUI 与合成逻辑的契约。
"""
base_params = {
"video_subject": "subtitle background smoke",
}
disabled_params = VideoParams(
**base_params,
text_background_color=False,
)
colored_params = VideoParams(
**base_params,
text_background_color="#123456",
)
self.assertFalse(disabled_params.text_background_color)
self.assertEqual(colored_params.text_background_color, "#123456")
def test_visible_text_position_centers_actual_mask_bounds(self):
"""
TextClip 的画布会包含字体行高和 baseline 空白,直接居中画布会让
字幕在背景里看起来偏下。这里用一个假 mask 模拟“可见文字像素
在画布下半部分”的情况,验证 helper 会按真实可见区域重新计算 y。
"""
class FakeMask:
def get_frame(self, _):
mask = np.zeros((46, 100), dtype=float)
mask[12:46, 10:90] = 1.0
return mask
class FakeTextClip:
w = 100
h = 46
mask = FakeMask()
x, y = video._get_visible_center_position(
FakeTextClip(), container_width=100, container_height=93
)
self.assertEqual(x, 0)
# 可见像素高度为 34px,放在 93px 容器中应上下各约 29px;
# 因为 mask 顶部从 12px 开始,所以 TextClip 本身需要向上移动到 18px。
self.assertEqual(y, 18)
def test_detects_indistinguishable_subtitle_colors(self):
invisible_params = VideoParams(
video_subject="subtitle color validation",
text_fore_color="#000000",
text_background_color="#000000",
stroke_color="#000000",
stroke_width=1.5,
)
different_outline_params = VideoParams(
video_subject="subtitle color validation",
text_fore_color="#000000",
text_background_color="#000000",
stroke_color="#FFFFFF",
stroke_width=1.5,
)
background_disabled_params = VideoParams(
video_subject="subtitle color validation",
text_fore_color="#000000",
text_background_color=False,
stroke_color="#000000",
stroke_width=1.5,
)
self.assertTrue(
video.subtitle_colors_are_indistinguishable(invisible_params)
)
self.assertTrue(
video.subtitle_colors_are_indistinguishable(different_outline_params)
)
self.assertFalse(
video.subtitle_colors_are_indistinguishable(background_disabled_params)
)
def test_detects_font_without_chinese_glyphs(self):
fonts_dir = (
Path(__file__).parent.parent.parent / "resource" / "fonts"
)
self.assertFalse(
video.subtitle_font_supports_text(
str(fonts_dir / "BeVietnamPro-Bold.ttf"), "人工智能改变生活"
)
)
self.assertTrue(
video.subtitle_font_supports_text(
str(fonts_dir / "MicrosoftYaHeiBold.ttc"), "人工智能改变生活"
)
)
self.assertTrue(
video.subtitle_font_supports_text(
str(fonts_dir / "BeVietnamPro-Bold.ttf"), "Artificial intelligence"
)
)
def test_wrap_text_keeps_closing_punctuation_with_text(self):
"""
中文长句按字符换行时,句号等闭合标点不能独占一行,否则字幕背景
会被一个单独的小点撑高。这里复现大字号中文长句的边界情况。
"""
font_path = (
Path(__file__).parent.parent.parent
/ "resource"
/ "fonts"
/ "MicrosoftYaHeiBold.ttc"
)
wrapped_text, _ = video.wrap_text(
"如果你调整字号,中文笔画也不能被黑色背景遮挡。",
max_width=1642,
font=str(font_path),
fontsize=72,
)
self.assertNotIn("\n。", wrapped_text)
self.assertIn("挡。", wrapped_text)