从WebM到MP3:利用Python和wxPython提取音乐的魔法

前言

有没有遇到过这样的问题:你有一个包含多首歌曲的WebM视频文件,但你只想提取其中的每一首歌曲,并将它们保存为单独的MP3文件?这听起来可能有些复杂,但借助Python和几个强大的库,这个任务变得异常简单。今天,我将带你一步步实现这个小工具,并且给它取个有趣的名字:"魔法音乐分离器"

C:\pythoncode\new\splitsongfromwebmintomp3.py

准备工作

在开始之前,确保你已经安装了以下Python库:

  • wxPython:用于创建GUI界面。
  • moviepy:用于处理视频文件。
  • pydub:用于音频转换。

你可以通过以下命令安装这些库:

bash 复制代码
pip install wxPython moviepy pydub

此外,还需要安装并配置ffmpeg,这可以通过以下命令在命令行中测试是否安装正确:

bash 复制代码
ffmpeg -version

如果看到版本信息,说明ffmpeg已经正确安装。

完整代码:

python 复制代码
import wx
import os
import subprocess

class MyFrame(wx.Frame):
    def __init__(self):
        super().__init__(parent=None, title='Music Extractor')
        panel = wx.Panel(self)

        self.vbox = wx.BoxSizer(wx.VERTICAL)

        self.file_picker = wx.FilePickerCtrl(panel, message="Choose a webm file")
        self.vbox.Add(self.file_picker, 0, wx.ALL | wx.EXPAND, 5)

        self.dir_picker = wx.DirPickerCtrl(panel, message="Choose a save directory")
        self.vbox.Add(self.dir_picker, 0, wx.ALL | wx.EXPAND, 5)

        self.memo = wx.TextCtrl(panel, style=wx.TE_MULTILINE, size=(400, 300))
        self.vbox.Add(self.memo, 1, wx.ALL | wx.EXPAND, 5)

        self.extract_button = wx.Button(panel, label='Extract Music')
        self.extract_button.Bind(wx.EVT_BUTTON, self.on_extract)
        self.vbox.Add(self.extract_button, 0, wx.ALL | wx.CENTER, 5)

        panel.SetSizer(self.vbox)
        self.Show()

    def on_extract(self, event):
        webm_path = self.file_picker.GetPath()
        save_dir = self.dir_picker.GetPath()
        memo_content = self.memo.GetValue()

        if not webm_path or not save_dir or not memo_content:
            wx.MessageBox('Please select a webm file, a save directory, and provide memo content.', 'Error', wx.OK | wx.ICON_ERROR)
            return

        timestamps = self.parse_memo_content(memo_content)

        def hms_to_seconds(hms):
            h, m, s = map(int, hms.split(':'))
            return h * 3600 + m * 60 + s

        for i in range(len(timestamps)):
            start_time = hms_to_seconds(timestamps[i][0])
            end_time = hms_to_seconds(timestamps[i+1][0]) if i+1 < len(timestamps) else None

            song_name = timestamps[i][1]
            output_path = os.path.join(save_dir, f"{song_name}.mp3")

            if end_time:
                duration = end_time - start_time
                ffmpeg_command = [
                    'ffmpeg', '-i', webm_path, '-ss', str(start_time),
                    '-t', str(duration), '-q:a', '0', '-map', 'a', output_path
                ]
            else:
                ffmpeg_command = [
                    'ffmpeg', '-i', webm_path, '-ss', str(start_time),
                    '-q:a', '0', '-map', 'a', output_path
                ]

            subprocess.run(ffmpeg_command)

        wx.MessageBox('Extraction completed successfully!', 'Info', wx.OK | wx.ICON_INFORMATION)

    def parse_memo_content(self, content):
        lines = content.strip().split('\n')
        timestamps = []
        for line in lines:
            if line:
                parts = line.split(' - ')
                time_str = parts[0].strip('[]')
                song_name = parts[1]
                timestamps.append((time_str, song_name))
        return timestamps


if __name__ == '__main__':
    app = wx.App(False)
    frame = MyFrame()
    app.MainLoop()

代码详解

创建GUI界面

首先,我们使用wxPython创建一个简单的GUI界面,包含文件选择器、路径选择器以及一个文本区域(memo组件)用于输入时间戳和歌曲信息。

python 复制代码
import wx
import os
import subprocess

class MyFrame(wx.Frame):
    def __init__(self):
        super().__init__(parent=None, title='魔法音乐分离器')
        panel = wx.Panel(self)

        self.vbox = wx.BoxSizer(wx.VERTICAL)

        self.file_picker = wx.FilePickerCtrl(panel, message="选择一个WebM文件")
        self.vbox.Add(self.file_picker, 0, wx.ALL | wx.EXPAND, 5)

        self.dir_picker = wx.DirPickerCtrl(panel, message="选择保存路径")
        self.vbox.Add(self.dir_picker, 0, wx.ALL | wx.EXPAND, 5)

        self.memo = wx.TextCtrl(panel, style=wx.TE_MULTILINE, size=(400, 300))
        self.vbox.Add(self.memo, 1, wx.ALL | wx.EXPAND, 5)

        self.extract_button = wx.Button(panel, label='提取音乐')
        self.extract_button.Bind(wx.EVT_BUTTON, self.on_extract)
        self.vbox.Add(self.extract_button, 0, wx.ALL | wx.CENTER, 5)

        panel.SetSizer(self.vbox)
        self.Show()

提取音乐的魔法

接下来,我们需要在点击"提取音乐"按钮后进行实际的音频提取和转换。这里我们使用ffmpeg命令行工具来处理音频,因为它非常强大且灵活。

python 复制代码
    def on_extract(self, event):
        webm_path = self.file_picker.GetPath()
        save_dir = self.dir_picker.GetPath()
        memo_content = self.memo.GetValue()

        if not webm_path or not save_dir or not memo_content:
            wx.MessageBox('请选择一个WebM文件、保存路径,并提供memo内容。', '错误', wx.OK | wx.ICON_ERROR)
            return

        timestamps = self.parse_memo_content(memo_content)

        def hms_to_seconds(hms):
            h, m, s = map(int, hms.split(':'))
            return h * 3600 + m * 60 + s

        for i in range(len(timestamps)):
            start_time = hms_to_seconds(timestamps[i][0])
            end_time = hms_to_seconds(timestamps[i+1][0]) if i+1 < len(timestamps) else None

            song_name = timestamps[i][1]
            output_path = os.path.join(save_dir, f"{song_name}.mp3")

            if end_time:
                duration = end_time - start_time
                ffmpeg_command = [
                    'ffmpeg', '-i', webm_path, '-ss', str(start_time),
                    '-t', str(duration), '-q:a', '0', '-map', 'a', output_path
                ]
            else:
                ffmpeg_command = [
                    'ffmpeg', '-i', webm_path, '-ss', str(start_time),
                    '-q:a', '0', '-map', 'a', output_path
                ]

            subprocess.run(ffmpeg_command)

        wx.MessageBox('提取完成!', '信息', wx.OK | wx.ICON_INFORMATION)

    def parse_memo_content(self, content):
        lines = content.strip().split('\n')
        timestamps = []
        for line in lines:
            if line:
                parts = line.split(' - ')
                time_str = parts[0].strip('[]')
                song_name = parts[1]
                timestamps.append((time_str, song_name))
        return timestamps

解析memo内容

我们需要将memo中的内容解析成时间戳和歌曲信息的列表。这里我们定义了一个parse_memo_content方法来处理这个任务。

python 复制代码
    def parse_memo_content(self, content):
        lines = content.strip().split('\n')
        timestamps = []
        for line in lines:
            if line:
                parts = line.split(' - ')
                time_str = parts[0].strip('[]')
                song_name = parts[1]
                timestamps.append((time_str, song_name))
        return timestamps

主程序入口

最后,我们定义主程序入口,启动wxPython应用。

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

界面:

结果:

结语

至此,我们的"魔法音乐分离器"已经完成。你可以通过简单的图形界面选择一个包含多首歌曲的WebM文件,指定保存路径,并输入时间戳和歌曲信息,程序会自动提取每一首歌曲并保存为MP3文件。

希望这个小工具能为你的音乐提取工作带来便利。如果你有任何问题或建议,欢迎留言讨论!

相关推荐
B站_计算机毕业设计之家4 小时前
豆瓣电影数据采集分析推荐系统 | Python Vue Flask框架 LSTM Echarts多技术融合开发 毕业设计源码 计算机
vue.js·python·机器学习·flask·echarts·lstm·推荐算法
渣渣苏5 小时前
Langchain实战快速入门
人工智能·python·langchain
lili-felicity5 小时前
CANN模型量化详解:从FP32到INT8的精度与性能平衡
人工智能·python
数据知道5 小时前
PostgreSQL实战:详解如何用Python优雅地从PG中存取处理JSON
python·postgresql·json
ZH15455891315 小时前
Flutter for OpenHarmony Python学习助手实战:面向对象编程实战的实现
python·学习·flutter
玄同7655 小时前
SQLite + LLM:大模型应用落地的轻量级数据存储方案
jvm·数据库·人工智能·python·语言模型·sqlite·知识图谱
User_芊芊君子5 小时前
CANN010:PyASC Python编程接口—简化AI算子开发的Python框架
开发语言·人工智能·python
白日做梦Q5 小时前
Anchor-free检测器全解析:CenterNet vs FCOS
python·深度学习·神经网络·目标检测·机器学习
喵手5 小时前
Python爬虫实战:公共自行车站点智能采集系统 - 从零构建生产级爬虫的完整实战(附CSV导出 + SQLite持久化存储)!
爬虫·python·爬虫实战·零基础python爬虫教学·采集公共自行车站点·公共自行车站点智能采集系统·采集公共自行车站点导出csv
喵手6 小时前
Python爬虫实战:地图 POI + 行政区反查实战 - 商圈热力数据准备完整方案(附CSV导出 + SQLite持久化存储)!
爬虫·python·爬虫实战·零基础python爬虫教学·地区poi·行政区反查·商圈热力数据采集