diff --git a/apps/worker/video_processing/subtitle_render_engine.py b/apps/worker/video_processing/subtitle_render_engine.py index 768f4317e..1daac15a4 100755 --- a/apps/worker/video_processing/subtitle_render_engine.py +++ b/apps/worker/video_processing/subtitle_render_engine.py @@ -27,7 +27,11 @@ import logging from typing import Any from pathlib import Path -from video_processing.path_security import PathSecurityError, is_in_allowed_dirs, safe_resolve_path +from video_processing.path_security import ( + PathSecurityError, + is_in_allowed_dirs, + safe_resolve_path, +) from packages.domain.subtitle_style import ( ALLOWED_SUBTITLE_EXTENSIONS, @@ -36,7 +40,9 @@ from packages.domain.subtitle_style import ( SubtitleSegment, SubtitleStyle, ) -from packages.domain.subtitle_style import escape_ass_text as _escape_ass_text # noqa: F401 向后兼容导出 +from packages.domain.subtitle_style import ( + escape_ass_text as _escape_ass_text, +) # noqa: F401 向后兼容导出 from packages.domain.subtitle_style import format_ass_time as _format_ass_time from packages.domain.subtitle_style import wrap_text as _wrap_text @@ -165,7 +171,9 @@ class SubtitleRenderEngine: except (TypeError, ValueError): continue - def add_asr_timeline(self, timeline: Any, style: SubtitleStyle | None = None) -> None: + def add_asr_timeline( + self, timeline: Any, style: SubtitleStyle | None = None + ) -> None: """从 SubtitleTimeline 对象添加 ASR 字幕.""" if not timeline or not hasattr(timeline, "segments") or not timeline.segments: return @@ -246,7 +254,9 @@ Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text back_color = style.ass_background_color else: border_style = 1 - back_color = style.ass_shadow_color if style.shadow_enabled else style.ass_font_color + back_color = ( + style.ass_shadow_color if style.shadow_enabled else style.ass_font_color + ) outline_val = style.stroke_width if style.stroke_enabled else 0.0 shadow_val = style.shadow_offset_y if style.shadow_enabled else 0 @@ -279,7 +289,10 @@ Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text start_time = _format_ass_time(max(0, seg.start)) end_time = _format_ass_time(max(seg.start + 0.1, seg.end)) - return f"Dialogue: 0,{start_time},{end_time},{seg.style_name},,0,0,0,," f"{effect_tags}{safe_text}" + return ( + f"Dialogue: 0,{start_time},{end_time},{seg.style_name},,0,0,0,," + f"{effect_tags}{safe_text}" + ) @property def has_subtitles(self) -> bool: @@ -327,7 +340,10 @@ def build_subtitles_from_plan( style_dict = title_cfg.get("style") or {} style = SubtitleStyle.from_dict(style_dict) # 标题默认样式:顶部、大字号、粗体 - if style.position == DEFAULT_POSITION and style.font_size == DEFAULT_FONT_SIZE: + if ( + style.position == DEFAULT_POSITION + and style.font_size == DEFAULT_FONT_SIZE + ): style.position = "top_center" style.font_size = 48 style.bold = True @@ -403,7 +419,9 @@ def build_subtitle_filter( # - Windows 路径的 \ → / # - 冒号 : → \: # - 单引号 ' → '\'' - safe_path = ass_path_str.replace("\\", "/").replace(":", "\\:").replace("'", "'\\''") + safe_path = ( + ass_path_str.replace("\\", "/").replace(":", "\\:").replace("'", "'\\''") + ) return f"{video_input_label}subtitles='{safe_path}'[{output_label}]" @@ -443,4 +461,6 @@ def _validate_subtitle_path(subtitle_path: str, work_dir: Path) -> None: resolved_path.relative_to(resolved_work_dir) except ValueError as _e: if not is_in_allowed_dirs(resolved_path): - raise PathSecurityError(f"字幕路径不在允许目录内: {subtitle_path[:80]}") from _e + raise PathSecurityError( + f"字幕路径不在允许目录内: {subtitle_path[:80]}" + ) from _e