translator / utils.py
felix1968839's picture
配置自动保存功能
66d5638 verified
import subprocess
import os
import json
class VideoUtils:
@staticmethod
def prepare_audio(input_path, output_path):
"""从视频或音频中提取/转换音频为标准格式 (16kHz, mono, wav)"""
# 使用 wav 格式更通用,不需要 libmp3lame 编码器
cmd = [
'ffmpeg', '-y', '-i', input_path,
'-vn', '-acodec', 'pcm_s16le', '-ar', '16000', '-ac', '1',
output_path
]
try:
result = subprocess.run(cmd, check=True, capture_output=True, text=True)
return result
except subprocess.CalledProcessError as e:
error_msg = f"FFmpeg 处理音频失败!\n错误代码: {e.returncode}\n错误输出: {e.stderr}"
print(error_msg) # 控制台打印
raise Exception(error_msg)
except FileNotFoundError:
raise Exception("找不到 FFmpeg 命令。请确保 FFmpeg 已安装并已添加到系统环境变量 PATH 中。")
@staticmethod
def embed_subtitles(video_path, srt_path, output_path):
"""将字幕嵌入视频 (硬压)"""
# 注意:Windows下路径处理较复杂,ffmpeg 的 subtitles 滤镜需要特殊转义
abs_srt_path = os.path.abspath(srt_path).replace('\\', '/').replace(':', '\\:')
cmd = [
'ffmpeg', '-y', '-i', video_path,
'-vf', f"subtitles='{abs_srt_path}'",
'-c:a', 'copy',
output_path
]
try:
result = subprocess.run(cmd, check=True, capture_output=True, text=True)
return result
except subprocess.CalledProcessError as e:
error_msg = f"FFmpeg 合成视频失败!\n错误代码: {e.returncode}\n错误输出: {e.stderr}"
print(error_msg)
raise Exception(error_msg)
except FileNotFoundError:
raise Exception("找不到 FFmpeg 命令。")
@staticmethod
def format_timestamp(seconds: float):
"""将秒转换为 SRT 时间格式 00:00:00,000"""
td_hours = int(seconds // 3600)
td_mins = int((seconds % 3600) // 60)
td_secs = int(seconds % 60)
td_msecs = int((seconds - int(seconds)) * 1000)
return f"{td_hours:02}:{td_mins:02}:{td_secs:02},{td_msecs:03}"
@staticmethod
def write_srt(segments, output_path):
"""生成 SRT 格式文件"""
with open(output_path, 'w', encoding='utf-8') as f:
for i, segment in enumerate(segments, 1):
start = VideoUtils.format_timestamp(segment.start)
end = VideoUtils.format_timestamp(segment.end)
f.write(f"{i}\n{start} --> {end}\n{segment.text.strip()}\n\n")
@staticmethod
def parse_srt(srt_content):
"""简单的 SRT 解析器,返回 segments 列表"""
import re
segments = []
# 正则匹配 SRT 块
pattern = re.compile(r'(\d+)\n(\d{2}:\d{2}:\d{2},\d{3}) --> (\d{2}:\d{2}:\d{2},\d{3})\n(.*?)(?=\n\n|\n$|$)', re.DOTALL)
def time_to_seconds(t_str):
h, m, s_ms = t_str.split(':')
s, ms = s_ms.split(',')
return int(h) * 3600 + int(m) * 60 + int(s) + int(ms) / 1000.0
matches = pattern.findall(srt_content)
for m in matches:
idx, start_t, end_t, text = m
seg = type('Segment', (), {
'start': time_to_seconds(start_t),
'end': time_to_seconds(end_t),
'text': text.strip()
})
segments.append(seg)
return segments
class SettingsManager:
SETTINGS_FILE = ".user_settings.json"
@staticmethod
def save_settings(settings):
"""保存设置到本地 JSON 文件"""
try:
with open(SettingsManager.SETTINGS_FILE, 'w', encoding='utf-8') as f:
json.dump(settings, f, ensure_ascii=False, indent=4)
except Exception as e:
print(f"保存设置失败: {e}")
@staticmethod
def load_settings():
"""从本地 JSON 文件加载设置"""
if os.path.exists(SettingsManager.SETTINGS_FILE):
try:
with open(SettingsManager.SETTINGS_FILE, 'r', encoding='utf-8') as f:
return json.load(f)
except Exception as e:
print(f"加载设置失败: {e}")
return {}