File size: 4,385 Bytes
4aff0b5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
66d5638
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
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 {}