在这篇博客中,我们将深入探讨一个使用Python和wxPython构建的音频/视频提取器应用程序。这个应用程序允许用户从视频文件中提取音频,或者从音频文件中截取特定时间段。让我们逐步分析这个程序的功能和实现。
C:\pythoncode\new\MP3towav.py
全部代码
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. 导入必要的库
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. 主应用程序类
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组件
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. 导出功能
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)
这个方法是程序的核心,它处理音频/视频的导出过程:
- 获取用户输入的所有必要信息。
- 检查输入文件的类型(音频或视频)。
- 根据用户指定的时间范围截取音频。
- 生成一个唯一的输出文件名。
- 导出音频文件。
- 保存用户设置以便下次使用。
6. 在PotPlayer中打开文件
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. 设置的保存和加载
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. 主程序入口
if __name__ == '__main__':
app = wx.App()
frame = AudioVideoExtractor()
frame.Show()
app.MainLoop()
这是程序的入口点,它创建了wxPython应用程序实例,实例化了我们的AudioVideoExtractor
类,并启动主事件循环。
运行结果
结论
这个音频/视频提取器是一个功能强大yet易用的工具,展示了如何使用Python和wxPython创建实用的桌面应用程序。它结合了文件I/O、音频/视频处理、GUI编程和设置管理等多个方面,是一个很好的学习案例。