python
主页 > 脚本 > python >

用Python编写一个MP3分割工具

2025-02-11 | 佚名 | 点击:

最终效果图

代码

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

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

184

185

186

187

188

189

190

191

192

193

194

195

196

197

198

199

200

201

202

203

204

205

206

207

208

209

210

211

212

213

214

215

216

217

218

219

220

221

222

223

224

225

226

227

228

229

230

231

232

233

234

235

236

237

238

239

240

241

242

243

244

245

246

247

248

249

250

251

252

253

254

255

256

257

258

259

260

261

262

263

264

265

266

267

268

269

270

271

272

273

274

275

276

277

278

279

280

281

282

283

284

285

286

287

288

289

290

291

292

293

294

295

296

297

298

299

300

301

302

303

304

305

306

307

308

309

310

311

312

313

314

315

316

317

318

319

320

321

322

323

324

325

326

327

import tkinter as tk

from tkinter import filedialog, messagebox, ttk

import os

import subprocess

  

class MP3SplitterApp:

    def __init__(self, root):

        self.root = root

        self.root.title("MP3 分割工具")

        self.root.geometry("600x400")

         

        # 文件路径变量

        self.file_path = tk.StringVar()

         

        # 创建界面元素

        self.create_widgets()

         

        # 预设分割时长为 4:30

        self.minutes_entry.insert(0, "4")

        self.seconds_entry.insert(0, "30")

         

        # 存储分割点的列表

        self.split_points = []

  

    def create_widgets(self):

        # 文件选择框

        file_frame = ttk.Frame(self.root)

        file_frame.pack(pady=10, padx=10, fill=tk.X)

         

        ttk.Label(file_frame, text="选择文件:").pack(side=tk.LEFT)

        ttk.Entry(file_frame, textvariable=self.file_path, width=50).pack(side=tk.LEFT, padx=5)

        ttk.Button(file_frame, text="选择文件", command=self.select_file).pack(side=tk.LEFT)

         

        # 分割时长输入区域

        split_frame = ttk.Frame(self.root)

        split_frame.pack(pady=10, padx=10, fill=tk.BOTH)

         

        ttk.Label(split_frame, text="设置分割时长(格式:分:秒):").pack()

         

        input_frame = ttk.Frame(split_frame)

        input_frame.pack(pady=5)

         

        self.minutes_entry = ttk.Entry(input_frame, width=5)

        self.minutes_entry.pack(side=tk.LEFT)

        ttk.Label(input_frame, text=":").pack(side=tk.LEFT)

        self.seconds_entry = ttk.Entry(input_frame, width=5)

        self.seconds_entry.pack(side=tk.LEFT)

         

        # 控制按钮

        button_frame = ttk.Frame(self.root)

        button_frame.pack(pady=10, padx=10)

         

        ttk.Button(button_frame, text="MP4转MP3", command=self.convert_mp4_to_mp3).pack(side=tk.LEFT, padx=5)

        ttk.Button(button_frame, text="按时长分割", command=self.split_mp3).pack(side=tk.LEFT, padx=5)

        ttk.Button(button_frame, text="按歌曲分割", command=self.detect_songs).pack(side=tk.LEFT, padx=5)

  

    def select_file(self):

        file_path = filedialog.askopenfilename(filetypes=[("视频/音频文件", "*.mp4 *.mp3")])

        if file_path:

            self.file_path.set(file_path)

  

    def detect_songs(self):

        if not self.file_path.get():

            messagebox.showerror("错误", "请选择MP3文件")

            return

         

        try:

            # 检查FFmpeg路径

            possible_paths = [

                r"ffmpeg\bin\ffmpeg.exe",

                r".\ffmpeg\bin\ffmpeg.exe",

                r"C:\ffmpeg\bin\ffmpeg.exe",

                "ffmpeg"

            ]

             

            ffmpeg_path = None

            for path in possible_paths:

                if os.path.exists(path):

                    ffmpeg_path = path

                    break

                 

            if ffmpeg_path is None:

                messagebox.showerror("错误", "找不到FFmpeg,请确保已正确安装FFmpeg")

                return

             

            input_file = self.file_path.get()

             

            # 使用FFmpeg的silencedetect过滤器检测静音部分

            cmd = [

                ffmpeg_path, '-i', input_file,

                '-af', 'silencedetect=noise=-35dB:d=1',  # 更宽松的参数

                '-f', 'null', '-'

            ]

             

            result = subprocess.run(cmd, capture_output=True, encoding='utf-8', errors='ignore')

             

            # 解析静音检测结果

            silence_starts = []

            silence_ends = []

             

            if result.stderr:  # 确保有输出

                for line in result.stderr.split('\n'):

                    if line:  # 确保行不为空

                        if 'silence_start:' in line:

                            try:

                                parts = line.split('silence_start:')

                                if len(parts) > 1:

                                    time = float(parts[1].strip().split()[0])

                                    silence_starts.append(time)

                            except:

                                continue

                        elif 'silence_end:' in line:

                            try:

                                parts = line.split('silence_end:')

                                if len(parts) > 1:

                                    time = float(parts[1].strip().split()[0])

                                    silence_ends.append(time)

                            except:

                                continue

             

            # 使用检测到的静音点进行分割

            if silence_starts and silence_ends:

                output_dir = os.path.splitext(input_file)[0] + "_songs"

                os.makedirs(output_dir, exist_ok=True)

                 

                # 获取总时长

                probe = subprocess.run([

                    ffmpeg_path, '-i', input_file

                ], capture_output=True, encoding='utf-8', errors='ignore')

                 

                duration = None

                if probe.stderr:

                    for line in probe.stderr.split('\n'):

                        if "Duration:" in line:

                            try:

                                time_str = line.split("Duration:")[1].split(",")[0].strip()

                                h, m, s = map(float, time_str.split(":"))

                                duration = h * 3600 + m * 60 + s

                                break

                            except:

                                continue

                 

                if duration is None:

                    duration = max(silence_ends[-1] if silence_ends else 0, 3600)

                 

                # 构建分割点列表

                split_points = [0]  # 添加开始点

                for start, end in zip(silence_starts, silence_ends):

                    # 使用静音段的中点作为分割点

                    split_point = (start + end) / 2

                    # 只有当两个分割点间隔超过20秒时才考虑这是一首新歌

                    if split_point - split_points[-1] > 20:

                        split_points.append(split_point)

                 

                split_points.append(duration)  # 添加结束点

                 

                # 分割文件

                for i in range(len(split_points) - 1):

                    start_time = split_points[i]

                    end_time = split_points[i + 1]

                     

                    if end_time - start_time < 20:  # 如果片段小于20秒则跳过

                        continue

                         

                    output_path = os.path.join(output_dir, f"song_{i+1:03d}.mp3")

                     

                    subprocess.run([

                        ffmpeg_path, '-i', input_file,

                        '-ss', str(start_time),

                        '-t', str(end_time - start_time),

                        '-acodec', 'copy',

                        '-y',

                        output_path

                    ], capture_output=True)

                 

                messagebox.showinfo("成功", f"文件已按歌曲分割完成,保存在:{output_dir}")

            else:

                messagebox.showerror("错误", "未能检测到有效的歌曲分隔点")

             

        except Exception as e:

            messagebox.showerror("错误", f"分割过程中出现错误:{str(e)}")

  

    def convert_mp4_to_mp3(self):

        if not self.file_path.get():

            messagebox.showerror("错误", "请选择MP4文件")

            return

         

        if not self.file_path.get().lower().endswith('.mp4'):

            messagebox.showerror("错误", "请选择MP4文件")

            return

         

        try:

            # 检查FFmpeg路径

            possible_paths = [

                r"ffmpeg\bin\ffmpeg.exe",

                r".\ffmpeg\bin\ffmpeg.exe",

                r"C:\ffmpeg\bin\ffmpeg.exe",

                "ffmpeg"

            ]

             

            ffmpeg_path = None

            for path in possible_paths:

                if os.path.exists(path):

                    ffmpeg_path = path

                    break

                 

            if ffmpeg_path is None:

                messagebox.showerror("错误", "找不到FFmpeg,请确保已正确安装FFmpeg")

                return

             

            input_file = self.file_path.get()

            output_file = os.path.splitext(input_file)[0] + ".mp3"

             

            # 显示转换中的消息

            messagebox.showinfo("提示", "开始转换,请稍候...")

             

            # 执行转换

            subprocess.run([

                ffmpeg_path, '-i', input_file,

                '-vn',

                '-acodec', 'libmp3lame',

                '-q:a', '2',

                '-y',

                output_file

            ], check=True)

             

            # 更新文件路径为新生成的MP3文件

            self.file_path.set(output_file)

            messagebox.showinfo("成功", f"MP4已转换为MP3:\n{output_file}")

             

        except Exception as e:

            messagebox.showerror("错误", f"转换过程中出现错误:{str(e)}")

  

    def split_mp3(self):

        if not self.file_path.get():

            messagebox.showerror("错误", "请选择MP3文件")

            return

         

        try:

            # 获取用户输入的分割时长

            try:

                minutes = int(self.minutes_entry.get() or "0")

                seconds = int(self.seconds_entry.get() or "0")

                if minutes < 0 or seconds < 0 or seconds >= 60:

                    raise ValueError

                segment_duration = minutes * 60 + seconds

                if segment_duration <= 0:

                    raise ValueError

            except ValueError:

                messagebox.showerror("错误", "请输入有效的分割时长")

                return

             

            # 检查FFmpeg路径

            possible_paths = [

                r"ffmpeg\bin\ffmpeg.exe",

                r".\ffmpeg\bin\ffmpeg.exe",

                r"C:\ffmpeg\bin\ffmpeg.exe",

                "ffmpeg"

            ]

             

            ffmpeg_path = None

            for path in possible_paths:

                if os.path.exists(path):

                    ffmpeg_path = path

                    break

             

            if ffmpeg_path is None:

                messagebox.showerror("错误", "找不到FFmpeg,请确保已正确安装FFmpeg")

                return

             

            input_file = self.file_path.get()

            output_dir = os.path.splitext(input_file)[0] + "_split"

            os.makedirs(output_dir, exist_ok=True)

             

            # 获取音频总时长

            result = subprocess.run([ffmpeg_path, '-i', input_file],

                                  capture_output=True,

                                  encoding='utf-8',

                                  errors='ignore')

             

            # 从输出中提取持续时间

            duration = None

            for line in result.stderr.split('\n'):

                if "Duration:" in line:

                    try:

                        time_str = line.split("Duration:")[1].split(",")[0].strip()

                        h, m, s = map(float, time_str.split(":"))

                        duration = h * 3600 + m * 60 + s

                        break

                    except:

                        continue

             

            if duration is None:

                duration = 3600

                messagebox.showwarning("警告", "无法获取音频时长,将使用默认时长进行分割")

             

            # 计算分割点

            num_segments = int(duration // segment_duration) + 1

             

            # 分割文件

            for i in range(num_segments):

                start_time = i * segment_duration

                end_time = min((i + 1) * segment_duration, duration)

                 

                if end_time - start_time < 1:  # 如果片段小于1秒则跳过

                    continue

                     

                output_path = os.path.join(output_dir, f"segment_{i+1:03d}.mp3")

                 

                subprocess.run([

                    ffmpeg_path, '-i', input_file,

                    '-ss', str(start_time),

                    '-t', str(end_time - start_time),

                    '-acodec', 'copy',

                    '-y',

                    output_path

                ], capture_output=True)

             

            messagebox.showinfo("成功", f"文件已分割完成,保存在:{output_dir}\n共分割成 {num_segments} 个文件")

             

        except Exception as e:

            messagebox.showerror("错误", f"分割过程中出现错误:{str(e)}")

  

if __name__ == "__main__":

    root = tk.Tk()

    app = MP3SplitterApp(root)

    root.mainloop()

说明

MP3 分割工具

这是一个使用 Python 和 FFmpeg 开发的 MP3 分割工具,支持 MP4 转 MP3、按时长分割和按歌曲自动分割等功能。

功能特点

1.MP4 转 MP3

2.按时长分割

3.按歌曲分割

安装要求

Python 3.x

FFmpeg

必需的 Python 库

1

pip install tkinter

FFmpeg 安装

下载 FFmpeg:

访问:Releases · BtbN/FFmpeg-Builds

下载 "ffmpeg-master-latest-win64-gpl-shared.zip"

安装步骤:

目录结构应如下:

你的程序目录/

├── mp3_splitter.py
└── ffmpeg/
    └── bin/
        ├── ffmpeg.exe
        ├── ffplay.exe
        └── ffprobe.exe

使用说明

1.MP4 转 MP3:

2.按时长分割:

3.按歌曲分割:

输出说明

1.MP4 转 MP3:

2.按时长分割:

3.按歌曲分割:

注意事项

确保已正确安装 FFmpeg 并放置在正确位置

按歌曲分割功能的效果取决于音频特征,可能并非所有音频都能准确分割

建议在分割大文件前先进行测试

程序会自动跳过过短的片段以避免产生无效文件

开发说明

使用 Tkinter 构建图形界面

使用 subprocess 调用 FFmpeg 进行音频处理

代码采用面向对象方式组织,主要类为 MP3SplitterApp

所有文件操作都有错误处理机制

原文链接:
相关文章
最新更新