perf(8502): 并行生图(6并发)+超时重试;视频URL直连预览/下载;路径隔离

This commit is contained in:
Tony Zhang
2025-12-17 12:21:22 +08:00
parent ebcf165c3f
commit 1e210ffccf
12 changed files with 1168 additions and 201 deletions

View File

@@ -7,6 +7,7 @@ import re
import subprocess
import tempfile
import logging
import shutil
from pathlib import Path
from typing import List, Dict, Any, Optional, Tuple
@@ -14,9 +15,39 @@ import config
logger = logging.getLogger(__name__)
# FFmpeg/FFprobe 路径(优先使用项目内的二进制)
FFMPEG_PATH = str(config.BASE_DIR / "bin" / "ffmpeg") if (config.BASE_DIR / "bin" / "ffmpeg").exists() else "ffmpeg"
FFPROBE_PATH = str(config.BASE_DIR / "bin" / "ffprobe") if (config.BASE_DIR / "bin" / "ffprobe").exists() else "ffprobe"
def _pick_exec(preferred_path: str, fallback_name: str) -> str:
"""
Pick an executable path.
Why:
- In docker, /app/bin may accidentally contain binaries built for another OS/arch,
causing `Exec format error` at runtime (seen on /app/bin/ffprobe).
Strategy:
- Prefer preferred_path if it exists AND is runnable.
- Otherwise fall back to PATH-resolved command (fallback_name).
"""
if preferred_path and os.path.exists(preferred_path):
try:
# Validate it can be executed (arch OK) and is a real binary.
# ffmpeg/ffprobe both support `-version`.
result = subprocess.run(
[preferred_path, "-version"],
capture_output=True,
text=True,
)
if result.returncode == 0:
return preferred_path
except OSError:
# Exec format error / permission error -> fall back
pass
resolved = shutil.which(fallback_name)
return resolved or fallback_name
# FFmpeg/FFprobe 路径(优先使用项目内的二进制,但会做可执行性自检)
FFMPEG_PATH = _pick_exec(str(config.BASE_DIR / "bin" / "ffmpeg"), "ffmpeg")
FFPROBE_PATH = _pick_exec(str(config.BASE_DIR / "bin" / "ffprobe"), "ffprobe")
# 字体路径:优先使用项目内置字体,然后按平台回退到系统字体
DEFAULT_FONT_PATHS = [
@@ -159,15 +190,6 @@ def concat_videos(
logger.info(f"Concatenating {len(video_paths)} videos...")
# 创建 concat 文件列表
concat_file = config.TEMP_DIR / f"concat_{os.getpid()}.txt"
with open(concat_file, "w", encoding="utf-8") as f:
for vp in video_paths:
# 使用绝对路径并转义单引号
abs_path = os.path.abspath(vp)
f.write(f"file '{abs_path}'\n")
width, height = target_size
# 使用 filter_complex 统一分辨率后拼接
@@ -203,10 +225,6 @@ def concat_videos(
_run_ffmpeg(cmd)
# 清理临时文件
if concat_file.exists():
concat_file.unlink()
logger.info(f"Concatenated video saved: {output_path}")
return output_path
@@ -825,10 +843,10 @@ def add_bgm(
bgm_volume: BGM音量
loop: 是否循环BGM
"""
# 验证 BGM 文件存在
# 验证 BGM 文件存在(默认保持兼容:仍会输出视频,但会明确打日志)
if not bgm_path or not os.path.exists(bgm_path):
logger.error(f"BGM file not found: {bgm_path}")
# 直接复制原视频,不添加 BGM
logger.error(f"BGM file not found (skip add_bgm): {bgm_path}")
# 直接复制原视频,不添加 BGM(上层应当提示用户/写入 metadata
import shutil
shutil.copy(video_path, output_path)
return output_path