音频/视频提取器: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编程和设置管理等多个方面,是一个很好的学习案例。

相关推荐
人工智能技术派13 分钟前
Qwen-Audio:一种新的大规模音频-语言模型
人工智能·语言模型·音视频
xiaohanbao091 小时前
Transformer架构与NLP词表示演进
python·深度学习·神经网络
love530love2 小时前
【笔记】 Podman Desktop 中部署 Stable Diffusion WebUI (GPU 支持)
人工智能·windows·笔记·python·容器·stable diffusion·podman
程序员晚枫2 小时前
Python 3.14正式发布!这5大新特性太炸裂了
python
先做个垃圾出来………2 小时前
SortedList
python
这里有鱼汤2 小时前
从DeepSeek到Kronos,3个原因告诉你:Kronos如何颠覆传统量化预测
后端·python·aigc
晓宜2 小时前
Java25 新特性介绍
java·python·算法
深栈3 小时前
机器学习:决策树
人工智能·python·决策树·机器学习·sklearn
MediaTea3 小时前
Python:匿名函数 lambda
开发语言·python
hui函数3 小时前
Python全栈(基础篇)——Day07:后端内容(函数的参数+递归函数+实战演示+每日一题)
后端·python