用Python打造媒体管理播放器:从零到全功能GUI应用

news2024/12/23 9:10:47

背景

在日常生活中,我们经常需要管理和播放大量媒体文件。市面上的音频播放器可能功能单一,或者界面复杂。作为一名程序员,我决定使用Python自己打造一个简单yet强大的媒体管理播放器。
C:\pythoncode\new\playsong.py

全部代码

import os
import wx
import json
import pygame
from mutagen.mp3 import MP3
from mutagen.wave import WAVE

class MediaManagerApp(wx.Frame):
    def __init__(self):
        super().__init__(parent=None, title='媒体文件管理器', size=(800, 600))
        
        # 初始化pygame mixer
        pygame.mixer.init()
        
        # 配置文件路径
        self.config_path = 'favorites.json'
        
        # 创建面板
        panel = wx.Panel(self)
        
        # 垂直布局
        main_sizer = wx.BoxSizer(wx.VERTICAL)
        
        # 水平布局用于两个ListBox
        list_sizer = wx.BoxSizer(wx.HORIZONTAL)
        
        # 创建ListBox1(所有媒体文件)
        wx.StaticText(panel, label='所有媒体文件:')
        self.listbox1 = wx.ListBox(panel, style=wx.LB_MULTIPLE)
        list_sizer.Add(wx.StaticText(panel, label='所有媒体文件:'), 0, wx.ALL, 5)
        list_sizer.Add(self.listbox1, 1, wx.EXPAND | wx.ALL, 5)
        
        # 创建ListBox2(收藏文件)
        wx.StaticText(panel, label='收藏文件:')
        self.listbox2 = wx.ListBox(panel, style=wx.LB_MULTIPLE)
        list_sizer.Add(wx.StaticText(panel, label='收藏文件:'), 0, wx.ALL, 5)
        list_sizer.Add(self.listbox2, 1, wx.EXPAND | wx.ALL, 5)
        
        main_sizer.Add(list_sizer, 1, wx.EXPAND)
        
        # 进度条
        self.progress_slider = wx.Slider(panel, style=wx.SL_HORIZONTAL | wx.SL_LABELS)
        main_sizer.Add(self.progress_slider, 0, wx.EXPAND | wx.ALL, 5)
        
        # 按钮区域
        btn_sizer = wx.BoxSizer(wx.HORIZONTAL)
        
        # 选择文件夹按钮
        select_folder_btn = wx.Button(panel, label='选择文件夹')
        select_folder_btn.Bind(wx.EVT_BUTTON, self.on_select_folder)
        btn_sizer.Add(select_folder_btn, 0, wx.ALL, 5)
        
        # 收藏按钮
        collect_btn = wx.Button(panel, label='收藏')
        collect_btn.Bind(wx.EVT_BUTTON, self.on_collect)
        btn_sizer.Add(collect_btn, 0, wx.ALL, 5)
        
        # 保存按钮
        save_btn = wx.Button(panel, label='保存')
        save_btn.Bind(wx.EVT_BUTTON, self.on_save)
        btn_sizer.Add(save_btn, 0, wx.ALL, 5)
        
        # 加载按钮
        load_btn = wx.Button(panel, label='加载')
        load_btn.Bind(wx.EVT_BUTTON, self.on_load)
        btn_sizer.Add(load_btn, 0, wx.ALL, 5)
        
        # 播放按钮
        play_btn = wx.Button(panel, label='播放')
        play_btn.Bind(wx.EVT_BUTTON, self.on_play)
        btn_sizer.Add(play_btn, 0, wx.ALL, 5)
        
        # 停止按钮
        stop_btn = wx.Button(panel, label='停止')
        stop_btn.Bind(wx.EVT_BUTTON, self.on_stop)
        btn_sizer.Add(stop_btn, 0, wx.ALL, 5)
        
        main_sizer.Add(btn_sizer, 0, wx.CENTER)
        
        panel.SetSizer(main_sizer)
        
        # 绑定滑动条事件
        self.progress_slider.Bind(wx.EVT_SLIDER, self.on_slider_change)
        
        # 音频播放相关变量
        self.current_track = None
        self.track_length = 0
        
        # 定时器用于更新进度
        self.timer = wx.Timer(self)
        self.Bind(wx.EVT_TIMER, self.update_progress, self.timer)
        
    def on_select_folder(self, event):
        # 选择文件夹并列出媒体文件
        with wx.DirDialog(self, "选择包含媒体文件的文件夹") as dirDialog:
            if dirDialog.ShowModal() == wx.ID_OK:
                folder_path = dirDialog.GetPath()
                self.listbox1.Clear()
                
                # 支持的媒体文件扩展名
                media_extensions = ['.mp3', '.wav', '.ogg', '.flac']
                
                # 遍历文件夹
                for filename in os.listdir(folder_path):
                    if os.path.splitext(filename)[1].lower() in media_extensions:
                        full_path = os.path.join(folder_path, filename)
                        self.listbox1.Append(full_path)
    
    def on_collect(self, event):
        # 将选中的文件从listbox1移动到listbox2
        selections = self.listbox1.GetSelections()
        for index in reversed(selections):
            item = self.listbox1.GetString(index)
            self.listbox2.Append(item)
            self.listbox1.Delete(index)
    
    def on_save(self, event):
        # 将收藏的文件保存到配置文件
        favorites = [self.listbox2.GetString(i) for i in range(self.listbox2.GetCount())]
        with open(self.config_path, 'w', encoding='utf-8') as f:
            json.dump(favorites, f)
        wx.MessageBox('收藏已保存', '提示')
    
    def on_load(self, event):
        # 从配置文件加载收藏的文件
        try:
            with open(self.config_path, 'r', encoding='utf-8') as f:
                favorites = json.load(f)
            
            self.listbox2.Clear()
            for filepath in favorites:
                if os.path.exists(filepath):
                    self.listbox2.Append(filepath)
        except FileNotFoundError:
            wx.MessageBox('没有找到收藏文件', '错误')
    
    def on_play(self, event):
        # 播放选中的文件
        selections = self.listbox2.GetSelections()
        if selections:
            filepath = self.listbox2.GetString(selections[0])
            pygame.mixer.music.load(filepath)
            pygame.mixer.music.play()
            
            # 获取音频文件长度
            if filepath.lower().endswith('.mp3'):
                audio = MP3(filepath)
                self.track_length = audio.info.length
            elif filepath.lower().endswith('.wav'):
                audio = WAVE(filepath)
                self.track_length = audio.info.length
            else:
                self.track_length = 0
            
            # 设置进度条最大值
            self.progress_slider.SetRange(0, int(self.track_length))
            
            # 启动定时器更新进度
            self.timer.Start(1000)  # 每秒更新
            
            self.current_track = filepath
    
    def on_stop(self, event):
        # 停止播放
        pygame.mixer.music.stop()
        self.timer.Stop()
        self.progress_slider.SetValue(0)
    
    def on_slider_change(self, event):
        # 拖动进度条
        if self.current_track:
            new_pos = self.progress_slider.GetValue()
            pygame.mixer.music.rewind()
            pygame.mixer.music.set_pos(new_pos)
    
    def update_progress(self, event):
        # 更新进度条
        if pygame.mixer.music.get_busy():
            current_time = pygame.mixer.music.get_pos() / 1000  # 毫秒转秒
            self.progress_slider.SetValue(int(current_time))

def main():
    app = wx.App()
    frame = MediaManagerApp()
    frame.Show()
    app.MainLoop()

if __name__ == '__main__':
    main()

技术选型

对于这个项目,我选择了以下Python库:

  • wxPython:构建跨平台GUI界面
  • pygame:音频播放和控制
  • mutagen:获取音频文件元数据
  • json:配置文件存储

核心功能设计

1. 文件浏览与收藏

用户可以轻松地:

  • 选择文件夹
  • 浏览媒体文件列表
  • 快速将文件添加到收藏列表
  • 保存和加载收藏列表

2. 音频播放控制

提供完整的播放体验:

  • 播放选中的音频文件
  • 停止当前播放
  • 拖动进度条调节播放位置
  • 实时显示播放进度

关键代码解析

文件遍历

def on_select_folder(self, event):
    with wx.DirDialog(self, "选择包含媒体文件的文件夹") as dirDialog:
        if dirDialog.ShowModal() == wx.ID_OK:
            folder_path = dirDialog.GetPath()
            # 遍历支持的媒体文件
            media_extensions = ['.mp3', '.wav', '.ogg', '.flac']
            for filename in os.listdir(folder_path):
                if os.path.splitext(filename)[1].lower() in media_extensions:
                    full_path = os.path.join(folder_path, filename)
                    self.listbox1.Append(full_path)

音频播放控制

def on_play(self, event):
    selections = self.listbox2.GetSelections()
    if selections:
        filepath = self.listbox2.GetString(selections[0])
        pygame.mixer.music.load(filepath)
        pygame.mixer.music.play()
        
        # 获取音频文件长度
        audio = MP3(filepath) if filepath.lower().endswith('.mp3') else WAVE(filepath)
        self.track_length = audio.info.length
        
        # 设置进度条
        self.progress_slider.SetRange(0, int(self.track_length))
        self.timer.Start(1000)

技术亮点

  1. 跨平台GUI:使用wxPython确保应用在Windows、Mac、Linux上都能运行
  2. 灵活的文件管理:支持多种音频格式
  3. 配置持久化:使用JSON保存收藏列表
  4. 实时进度控制:通过定时器实现播放进度追踪

安装与运行

# 安装依赖
pip install wxPython pygame mutagen

# 运行应用
python media_manager.py

使用场景

  • 个人音乐收藏管理
  • 音频文件快速浏览
  • 简单的本地音乐播放需求

未来改进方向

  • 添加播放列表功能
  • 支持更多音频格式
  • 增加音量控制
  • 实现歌词显示

运行结果

在这里插入图片描述

结语

这个项目证明了Python强大的跨平台开发能力。短短200行代码,我们就实现了一个功能完善的媒体管理播放器。对于想要定制音频管理工具的开发者来说,这是一个很好的起点。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2230126.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Cisco Packet Tracer 8.0 路由器静态路由配置

文章目录 静态路由简介一、定义与特点二、配置与命令三、优点与缺点四、应用场景 一,搭建拓扑图二,配置pc IP地址三,pc0 ping pc1 timeout四,配置路由器Router0五,配置路由器Router1六,测试 静态路由简介 …

【HarmonyOS】鸿蒙系统

文章目录 前言一、鸿蒙OS概述1. 定义与特性2. 核心技术理念3. 技术架构设计1. 应用层2. 框架层3. 系统服务层4. 内核层 二、分布式架构分布式架构的核心理念分布式能力的实现关键技术 三、 总结 前言 鸿蒙OS是由华为推出的一款开源操作系统,旨在满足智能终端设备的…

《双指针篇》---移动零

题目传送门 这道题可以归类为 数组划分/数组分块 。 题目制定了一个规则,我们可以在这个规则下,将数组划分为若干个区间。 这道题让我们把所有非零元素移动到左边。所有零元素移动到右边。 将数组划分为: 左区间非0; 右区间&…

网络编程项目之UDP聊天室

项目要求 利用UDP协议,实现一套聊天室软件。服务器端记录客户端的地址,客户端发送消息后,服务器群发给各个客户端软件。 问题思考 客户端会不会知道其它客户端地址? UDP客户端不会直接互连,所以不会获知其它客户端地址…

【NOIP普及组】 FBI树

【NOIP普及组】 FBI树 C语言版本C 版本Java版本Python版本 💐The Begin💐点点关注,收藏不迷路💐 我们可以把由“0”和“1”组成的字符串分为三类:全“0”串称为B串,全“1”串称为I串,既含“0”又…

Lucene的概述与应用场景(1)

文章目录 第1章 Lucene概述1.1 搜索的实现方案1.1.1 传统实现方案1.1.2 Lucene实现方案 1.2 数据查询方法1.1.1 顺序扫描法1.1.2 倒排索引法 1.3 Lucene相关概念1.3.1 文档对象1.3.2 域对象1)分词2)索引3)存储 1.3.3 常用的Field种类 1.4 分词…

不适合的学习方法

文章目录 不适合的学习方法1. 纯粹死记硬背2. 过度依赖单一资料3. 线性学习4. 被动学习5. 一次性学习6. 忽视实践7. 缺乏目标导向8. 过度依赖技术9. 忽视个人学习风格10. 过于频繁的切换 结论 以下是关于不适合的学习方法的更详细描述,包括额外的内容和相关公式&…

华为OD机试真题(Python/JS/C/C++)- 考点 - 细节

华为OD机试 2024E卷题库疯狂收录中,刷题 点这里。 本专栏收录于《华为OD机试真题(Python/JS/C/C)》。

Linux中使用NGINX

NGINX简介 Nginx(engine x)是俄罗斯人编写的十分轻量级的HTTP服务器是一个高性能的HTTP和反向代理服务器,同时也是一个IMAP/POP3/SMTP代理服务器官方网站:http://nginx.org/ NGINX概述 Nginx默认配置文件:/etc/ngin…

scrapy爬取名人名言

爬取名人名言:http://quotes.toscrape.com/ 1 创建爬虫项目,在终端中输入: scrapy startproject quotes2 创建之后,在spiders文件夹下面创建爬虫文件quotes.py,内容如下: import scrapy from scrapy.spi…

mmsegmentation训练自己的数据集

文章目录 前言一、安装MMSegmentation二、数据集转换1.labelme标签数据转化为voc数据 三、训练设置1.建立数据集文件,并存入数据集2.设置训练配置文件 四、使用官方权重1、选择预测的方法2、查看方法支持的预训练数据集和权重权重位置找到对应的数据集下载权重 3、使…

LeetCode994. 腐烂的橘子(2024秋季每日一题 54)

在给定的 m x n 网格 grid 中,每个单元格可以有以下三个值之一: 值 0 代表空单元格;值 1 代表新鲜橘子;值 2 代表腐烂的橘子。 每分钟,腐烂的橘子 周围 4 个方向上相邻 的新鲜橘子都会腐烂。 返回 直到单元格中没有…

Pinctrl子系统中Pincontroller构造过程驱动分析:imx_pinctrl_soc_info结构体

往期内容 本专栏往期内容: Pinctrl子系统和其主要结构体引入Pinctrl子系统pinctrl_desc结构体进一步介绍Pinctrl子系统中client端设备树相关数据结构介绍和解析 input子系统专栏: 专栏地址:input子系统input角度:I2C触摸屏驱动分析…

地理信息科学专业想搞GIS开发:学前端还是后端?

地理信息科学专业的同学是学前端开发比较好呢还是学后端开发比较好呢? 部分网友:学前端更好 主修前端更好,因为地信学后端,是卷不赢学计算机的 本科卷前端,硕士阶段可以卷后端 甚至有网友直呼,地信根本没有…

批处理之for语句从入门到精通--呕血整理

文章目录 一、前言二、for语句的基本用法三、文本解析显神威:for /f 用法详解四、翻箱倒柜遍历文件夹:for /r五、仅仅为了匹配第一层目录而存在:for /d六、计数循环:for /l后记 for语句从入门到精通 一、前言 在批处理中&#…

第8章利用CSS制作导航菜单(第八次作业)

效果图如下&#xff1a; Html代码如下&#xff1a; <!DOCTYPE html> <html><head><meta charset"utf-8"><title>山水之间</title><style type"text/css">import url("../css/work1.css");</style…

Ubuntu22.04 安装图形界面以及XRDP教程

一、准备环境 1.一台服务器安装系统ubuntu&#xff08;这里大部分ubuntu系统可以同用&#xff09; 2.安装的ubuntu系统未安装图形界面 二、操作步骤 1.远程ssh或者直接登录服务器命令行界面 ssh -p 远程端口 rootIP 2.更新系统软件包 sudo apt update # 更新本地的软件包…

深度学习基础知识-编解码结构理论超详细讲解

编解码结构&#xff08;Encoder-Decoder&#xff09;是一种应用广泛且高效的神经网络架构&#xff0c;最早用于序列到序列&#xff08;Seq2Seq&#xff09;任务&#xff0c;如机器翻译、图像生成、文本生成等。随着深度学习的发展&#xff0c;编解码结构不断演变出多种模型变体…

扫描电镜的超低温冷冻制样及传输技术(Cryo-SEM)

扫描电镜的超低温冷冻制样及传输技术(Cryo-SEM) 扫描电镜&#xff08;Scanning Electron Microscope&#xff0c;简称SEM&#xff09;是一种利用聚焦电子束扫描样品表面&#xff0c;通过检测二次电子或反射电子等信号来获取样品表面形貌信息的显微观察技术&#xff1b;然而&…

JS手写:从0开始认识【柯里化】【支持占位符的柯里化】

柯里化 功能介绍 柯里化是拆分函数的一种手段&#xff0c;允许我们以偏函数的方式调用这个函数。 比如说&#xff0c;原来的函数A必须传入三个参数才能运行。经过柯里化处理之后的函数KA传入三个参数&#xff0c;能成功运行&#xff1b;传入两个参数也能&#xff0c;但是会返…