perf(8502): 并行生图(6并发)+超时重试;视频URL直连预览/下载;路径隔离
This commit is contained in:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user