音频/视频提取器:Python和moviepy实现

在这篇博客中,我们将深入探讨一个使用Python和wxPython构建的音频/视频提取器应用程序。这个应用程序允许用户从视频文件中提取音频,或者从音频文件中截取特定时间段。让我们逐步分析这个程序的功能和实现。

C:\pythoncode\new\MP3towav.py

全部代码

python 复制代码
import wx
import os
import subprocess
from datetime import datetime
import json
from moviepy.editor import VideoFileClip, AudioFileClip

class AudioVideoExtractor(wx.Frame):
    def __init__(self):
        super().__init__(parent=None, title='Audio/Video Extractor')
        self.panel = wx.Panel(self)
        self.create_widgets()
        self.load_settings()

    def create_widgets(self):
        # File selection
        self.file_picker = wx.FilePickerCtrl(self.panel, message="Choose an audio or video file")
        
        # Time range
        self.start_time = wx.TextCtrl(self.panel, value="00:00:00")
        self.end_time = wx.TextCtrl(self.panel, value="00:00:00")
        
        # Output format
        self.formats = ['mp3', 'wav', 'aac']
        self.format_choice = wx.Choice(self.panel, choices=self.formats)
        
        # Output directory
        self.dir_picker = wx.DirPickerCtrl(self.panel, message="Choose output directory")
        
        # Export button
        self.export_btn = wx.Button(self.panel, label="Export")
        self.export_btn.Bind(wx.EVT_BUTTON, self.on_export)
        
        # Open button
        self.open_btn = wx.Button(self.panel, label="Open in PotPlayer")
        self.open_btn.Bind(wx.EVT_BUTTON, self.on_open)
        
        # Layout
        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(wx.StaticText(self.panel, label="Select Audio or Video File:"), 0, wx.ALL, 5)
        sizer.Add(self.file_picker, 0, wx.EXPAND|wx.ALL, 5)
        sizer.Add(wx.StaticText(self.panel, label="Start Time (HH:MM:SS):"), 0, wx.ALL, 5)
        sizer.Add(self.start_time, 0, wx.EXPAND|wx.ALL, 5)
        sizer.Add(wx.StaticText(self.panel, label="End Time (HH:MM:SS):"), 0, wx.ALL, 5)
        sizer.Add(self.end_time, 0, wx.EXPAND|wx.ALL, 5)
        sizer.Add(wx.StaticText(self.panel, label="Output Format:"), 0, wx.ALL, 5)
        sizer.Add(self.format_choice, 0, wx.EXPAND|wx.ALL, 5)
        sizer.Add(wx.StaticText(self.panel, label="Output Directory:"), 0, wx.ALL, 5)
        sizer.Add(self.dir_picker, 0, wx.EXPAND|wx.ALL, 5)
        sizer.Add(self.export_btn, 0, wx.ALL|wx.CENTER, 5)
        sizer.Add(self.open_btn, 0, wx.ALL|wx.CENTER, 5)
        
        self.panel.SetSizer(sizer)
        
    def on_export(self, event):
        input_path = self.file_picker.GetPath()
        start_time = self.start_time.GetValue()
        end_time = self.end_time.GetValue()
        output_format = self.formats[self.format_choice.GetSelection()]
        output_dir = self.dir_picker.GetPath()
        
        if not all([input_path, start_time, end_time, output_format, output_dir]):
            wx.MessageBox("Please fill in all fields", "Error", wx.OK | wx.ICON_ERROR)
            return
        
        try:
            # Check if the input file is video or audio
            file_extension = os.path.splitext(input_path)[1].lower()
            if file_extension in ['.mp4', '.avi', '.mov', '.flv']:  # Add more video extensions if needed
                clip = VideoFileClip(input_path).audio
            elif file_extension in ['.mp3', '.wav', '.aac', '.flac']:  # Add more audio extensions if needed
                clip = AudioFileClip(input_path)
            else:
                raise ValueError("Unsupported file format")

            start = self.time_to_seconds(start_time)
            end = self.time_to_seconds(end_time)
            
            clip = clip.subclip(start, end)
            
            timestamp = datetime.now().strftime("%Y%m%d")
            counter = 1
            while True:
                output_filename = f"{timestamp}_{counter:03d}.{output_format}"
                output_path = os.path.join(output_dir, output_filename)
                if not os.path.exists(output_path):
                    break
                counter += 1
            
            clip.write_audiofile(output_path)
            clip.close()
            
            self.last_exported_file = output_path
            wx.MessageBox(f"Audio exported to {output_path}", "Success", wx.OK | wx.ICON_INFORMATION)
            
            self.save_settings()
        except Exception as e:
            wx.MessageBox(f"Error: {str(e)}", "Error", wx.OK | wx.ICON_ERROR)
    
    def on_open(self, event):
        if hasattr(self, 'last_exported_file') and os.path.exists(self.last_exported_file):
            try:
                subprocess.Popen(['C:\\Program Files\\DAUM\\PotPlayer\\PotPlayerMini64.exe', self.last_exported_file])
            except Exception as e:
                wx.MessageBox(f"Error opening file: {str(e)}", "Error", wx.OK | wx.ICON_ERROR)
        else:
            wx.MessageBox("No file has been exported yet", "Error", wx.OK | wx.ICON_ERROR)
    
    def time_to_seconds(self, time_str):
        h, m, s = map(int, time_str.split(':'))
        return h * 3600 + m * 60 + s
    
    def save_settings(self):
        settings = {
            'last_file': self.file_picker.GetPath(),
            'start_time': self.start_time.GetValue(),
            'end_time': self.end_time.GetValue(),
            'format': self.format_choice.GetSelection(),
            'output_dir': self.dir_picker.GetPath()
        }
        with open('settings.json', 'w') as f:
            json.dump(settings, f)
    
    def load_settings(self):
        if os.path.exists('settings.json'):
            with open('settings.json', 'r') as f:
                settings = json.load(f)
            self.file_picker.SetPath(settings.get('last_file', ''))
            self.start_time.SetValue(settings.get('start_time', '00:00:00'))
            self.end_time.SetValue(settings.get('end_time', '00:00:00'))
            self.format_choice.SetSelection(settings.get('format', 0))
            self.dir_picker.SetPath(settings.get('output_dir', ''))

if __name__ == '__main__':
    app = wx.App()
    frame = AudioVideoExtractor()
    frame.Show()
    app.MainLoop()

1. 概述

这个应用程序的主要功能包括:

  • 从视频文件中提取音频
  • 从音频文件中截取特定时间段
  • 设置输出音频格式
  • 自定义输出文件名和路径
  • 使用PotPlayer播放导出的音频文件
  • 保存和加载用户设置

2. 导入必要的库

python 复制代码
import wx
import os
import subprocess
from datetime import datetime
import json
from moviepy.editor import VideoFileClip, AudioFileClip

这些库为我们提供了以下功能:

  • wx: 用于创建图形用户界面
  • os: 用于文件和路径操作
  • subprocess: 用于启动外部程序(PotPlayer)
  • datetime: 用于生成时间戳
  • json: 用于保存和加载设置
  • moviepy.editor: 用于处理音频和视频文件

3. 主应用程序类

python 复制代码
class AudioVideoExtractor(wx.Frame):
    def __init__(self):
        super().__init__(parent=None, title='Audio/Video Extractor')
        self.panel = wx.Panel(self)
        self.create_widgets()
        self.load_settings()

这个类继承自wx.Frame,是我们应用程序的主窗口。在初始化方法中,我们创建了一个面板,调用方法来创建UI组件,并加载之前保存的设置。

4. 创建UI组件

python 复制代码
def create_widgets(self):
    # 文件选择器
    self.file_picker = wx.FilePickerCtrl(self.panel, message="Choose an audio or video file")
    
    # 时间范围输入
    self.start_time = wx.TextCtrl(self.panel, value="00:00:00")
    self.end_time = wx.TextCtrl(self.panel, value="00:00:00")
    
    # 输出格式选择
    self.formats = ['mp3', 'wav', 'aac']
    self.format_choice = wx.Choice(self.panel, choices=self.formats)
    
    # 输出目录选择
    self.dir_picker = wx.DirPickerCtrl(self.panel, message="Choose output directory")
    
    # 导出按钮
    self.export_btn = wx.Button(self.panel, label="Export")
    self.export_btn.Bind(wx.EVT_BUTTON, self.on_export)
    
    # 打开按钮
    self.open_btn = wx.Button(self.panel, label="Open in PotPlayer")
    self.open_btn.Bind(wx.EVT_BUTTON, self.on_open)
    
    # 布局设置
    # ...

这个方法创建了所有的UI组件,包括文件选择器、时间输入框、格式选择下拉框、目录选择器和按钮。它还设置了组件的布局。

5. 导出功能

python 复制代码
def on_export(self, event):
    # 获取用户输入
    input_path = self.file_picker.GetPath()
    start_time = self.start_time.GetValue()
    end_time = self.end_time.GetValue()
    output_format = self.formats[self.format_choice.GetSelection()]
    output_dir = self.dir_picker.GetPath()
    
    # 检查输入是否完整
    if not all([input_path, start_time, end_time, output_format, output_dir]):
        wx.MessageBox("Please fill in all fields", "Error", wx.OK | wx.ICON_ERROR)
        return
    
    try:
        # 检查输入文件类型
        file_extension = os.path.splitext(input_path)[1].lower()
        if file_extension in ['.mp4', '.avi', '.mov', '.flv']:
            clip = VideoFileClip(input_path).audio
        elif file_extension in ['.mp3', '.wav', '.aac', '.flac']:
            clip = AudioFileClip(input_path)
        else:
            raise ValueError("Unsupported file format")

        # 处理音频
        start = self.time_to_seconds(start_time)
        end = self.time_to_seconds(end_time)
        clip = clip.subclip(start, end)
        
        # 生成输出文件名
        timestamp = datetime.now().strftime("%Y%m%d")
        counter = 1
        while True:
            output_filename = f"{timestamp}_{counter:03d}.{output_format}"
            output_path = os.path.join(output_dir, output_filename)
            if not os.path.exists(output_path):
                break
            counter += 1
        
        # 导出音频
        clip.write_audiofile(output_path)
        clip.close()
        
        self.last_exported_file = output_path
        wx.MessageBox(f"Audio exported to {output_path}", "Success", wx.OK | wx.ICON_INFORMATION)
        
        self.save_settings()
    except Exception as e:
        wx.MessageBox(f"Error: {str(e)}", "Error", wx.OK | wx.ICON_ERROR)

这个方法是程序的核心,它处理音频/视频的导出过程:

  1. 获取用户输入的所有必要信息。
  2. 检查输入文件的类型(音频或视频)。
  3. 根据用户指定的时间范围截取音频。
  4. 生成一个唯一的输出文件名。
  5. 导出音频文件。
  6. 保存用户设置以便下次使用。

6. 在PotPlayer中打开文件

python 复制代码
def on_open(self, event):
    if hasattr(self, 'last_exported_file') and os.path.exists(self.last_exported_file):
        try:
            subprocess.Popen(['potplayer.exe', self.last_exported_file])
        except Exception as e:
            wx.MessageBox(f"Error opening file: {str(e)}", "Error", wx.OK | wx.ICON_ERROR)
    else:
        wx.MessageBox("No file has been exported yet", "Error", wx.OK | wx.ICON_ERROR)

这个方法允许用户直接在PotPlayer中打开最近导出的文件。

7. 设置的保存和加载

python 复制代码
def save_settings(self):
    settings = {
        'last_file': self.file_picker.GetPath(),
        'start_time': self.start_time.GetValue(),
        'end_time': self.end_time.GetValue(),
        'format': self.format_choice.GetSelection(),
        'output_dir': self.dir_picker.GetPath()
    }
    with open('settings.json', 'w') as f:
        json.dump(settings, f)

def load_settings(self):
    if os.path.exists('settings.json'):
        with open('settings.json', 'r') as f:
            settings = json.load(f)
        self.file_picker.SetPath(settings.get('last_file', ''))
        self.start_time.SetValue(settings.get('start_time', '00:00:00'))
        self.end_time.SetValue(settings.get('end_time', '00:00:00'))
        self.format_choice.SetSelection(settings.get('format', 0))
        self.dir_picker.SetPath(settings.get('output_dir', ''))

这些方法允许程序保存用户的设置并在下次启动时加载它们,提高了用户体验。

8. 主程序入口

python 复制代码
if __name__ == '__main__':
    app = wx.App()
    frame = AudioVideoExtractor()
    frame.Show()
    app.MainLoop()

这是程序的入口点,它创建了wxPython应用程序实例,实例化了我们的AudioVideoExtractor类,并启动主事件循环。

运行结果

结论

这个音频/视频提取器是一个功能强大yet易用的工具,展示了如何使用Python和wxPython创建实用的桌面应用程序。它结合了文件I/O、音频/视频处理、GUI编程和设置管理等多个方面,是一个很好的学习案例。

相关推荐
nuclear201120 分钟前
使用Python 在Excel中创建和取消数据分组 - 详解
python·excel数据分组·创建excel分组·excel分类汇总·excel嵌套分组·excel大纲级别·取消excel分组
Lucky小小吴35 分钟前
有关django、python版本、sqlite3版本冲突问题
python·django·sqlite
GIS 数据栈1 小时前
每日一书 《基于ArcGIS的Python编程秘笈》
开发语言·python·arcgis
爱分享的码瑞哥1 小时前
Python爬虫中的IP封禁问题及其解决方案
爬虫·python·tcp/ip
傻啦嘿哟2 小时前
如何使用 Python 开发一个简单的文本数据转换为 Excel 工具
开发语言·python·excel
B站计算机毕业设计超人2 小时前
计算机毕业设计SparkStreaming+Kafka旅游推荐系统 旅游景点客流量预测 旅游可视化 旅游大数据 Hive数据仓库 机器学习 深度学习
大数据·数据仓库·hadoop·python·kafka·课程设计·数据可视化
IT古董3 小时前
【人工智能】Python在机器学习与人工智能中的应用
开发语言·人工智能·python·机器学习
湫ccc3 小时前
《Python基础》之pip换国内镜像源
开发语言·python·pip
hakesashou3 小时前
Python中常用的函数介绍
java·网络·python
菜鸟的人工智能之路3 小时前
极坐标气泡图:医学数据分析的可视化新视角
python·数据分析·健康医疗