当前位置: 代码网 > it编程>前端脚本>Python > 基于Python编写一个MP3分割工具

基于Python编写一个MP3分割工具

2025年02月11日 Python 我要评论
最终效果图代码import tkinter as tkfrom tkinter import filedialog, messagebox, ttkimport osimport subprocess

最终效果图

代码

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

  • 支持将 mp4 视频文件转换为 mp3 音频文件
  • 保持高质量音频输出

2.按时长分割

  • 默认预设 4:30 的分割时长
  • 可自定义分割时长(分:秒)
  • 自动跳过小于 1 秒的片段

3.按歌曲分割

  • 自动检测音频中的静音部分
  • 智能判断歌曲分隔点
  • 自动跳过过短的片段(小于 20 秒)

安装要求

python 3.x

ffmpeg

必需的 python 库

pip install tkinter

ffmpeg 安装

下载 ffmpeg:

访问:releases · btbn/ffmpeg-builds

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

安装步骤:

  • 解压下载的 zip 文件
  • 将解压出的文件夹重命名为 "ffmpeg"
  • 将 ffmpeg 文件夹放在程序同目录下

目录结构应如下:

你的程序目录/

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

使用说明

1.mp4 转 mp3:

  • 点击"选择文件"选择 mp4 文件
  • 点击"mp4转mp3"按钮
  • 等待转换完成

2.按时长分割:

  • 选择 mp3 文件
  • 在输入框中设置分割时长(默认 4:30)
  • 点击"按时长分割"按钮

3.按歌曲分割:

  • 选择 mp3 文件
  • 点击"按歌曲分割"按钮
  • 程序会自动检测歌曲分隔点并分割

输出说明

1.mp4 转 mp3:

  • 输出文件将保存在原视频同目录下
  • 文件名相同但扩展名改为 .mp3

2.按时长分割:

  • 输出文件保存在原文件同目录下的 "_split" 文件夹中
  • 文件名格式:segment_001.mp3, segment_002.mp3, ...

3.按歌曲分割:

  • 输出文件保存在原文件同目录下的 "_songs" 文件夹中
  • 文件名格式:song_001.mp3, song_002.mp3, ...

注意事项

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

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

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

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

开发说明

使用 tkinter 构建图形界面

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

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

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

到此这篇关于基于python编写一个mp3分割工具的文章就介绍到这了,更多相关python分割mp3内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com