背景
我打开了win10系统里的“beta版:使用Unicode UTF-8 提供全球语言支持”,
其副作用之一就是播放U盘中的音乐时会出现错误,无法播放。
如图:
在U盘端上只能正常播放名称全由ascii字符组成的文件。
我的解决办法是将音乐文件复制到本地,再播放。
实现播放器
首先使用os.listdir
获取文件列表,再从中获取.mp3文件。
如下:
import os
def get_mp3_files(path = r'D:/audios'):
'''
获取.mp3文件,path是音乐文件夹的路径。
'''
return [f'{path}//{i}' for i in os.listdir(path)
if i.endswith('.mp3')]
接下来实现播放器的核心,也就是播放音乐。
因为我修改了设置,需要先将文件复制到本地,再播放。
这里我使用shutil.copy
进行复制,pygame.mixer
实现播放。
import shutil
from pygame import mixer
mixer.init()
def play_file(path):
'''
播放.mp3音乐文件。
'''
shutil.copy(path, "_.mp3")
#将 path 对应的文件复制到工作区,命名为“_.mp3”。
mixer.music.load('_.mp3')
#加载文件。
mixer.music.play()
#播放文件,非阻塞。
最后,用tkinter
实现图形化界面。
import tkinter as tk
def tk_show(path=r'D:/audios'):
'''
'''
mp3_list = get_mp3_files(path)
#含有指定文件夹的所有mp3文件列表,使用的是我刚才定义的函数。
from random import choice
from collections import deque
#`deque`是“双向队列”,将用于储存播放记录,利用其自动删除过量元素的属性。
music_log = deque(maxlen = 10)
#记录十首播放过的音乐(含正在播放的)。
root = tk.Tk()
shower = tk.Label(root, text='Empty!')
def button_play(music_name = None):
'''
随机播放一首音乐,并将音乐名写入文本框'shower'。
如果'music_name'为'None',
则在'mp3_list'里随机获取一个,写入播放记录并播放。
否则只播放'music_name,不写入记录表。
'''
if music_name is None:
music_name = choice(mp3_list)
#随机获取一个音乐文件名。
while music_name in music_log:
#如果获取的音乐在近期被播放过,也就是在记录表中,
#就再次重新随机获取。
music_name = choice(mp3_list)
else:
music_log.append(music_name)
#把将要播放的音乐写入记录表。
#如果表中已有maxlen(前面设置为10)个元素,则第一个元素会被删除。
#所以记录表只会记录最后十首音乐。
shower.config(text=os.path.basename(music_name))
#将歌名写入文本框。`os.path.basename`返回文件名。
play_file(music_name)
button_p.config(text='display', command=button_display)
#重新设置按钮的显示文本、命令。
def button_display():
'''
结束播放。并将'Empty!'文本框'shower'。
'''
mixer.music.stop()
#结束正在播放的音乐。
mixer.music.load('_a_file_to_unload.mp3')
#将底层播放器加载到另一个文件上,以释放刚才在播放的'_.mp3',
#否则在复制文件时会出错。
button_p.config(text='play', command=button_play)
#重新设置'button_p'。
shower.config(text='Empty!')
def button_again():
'''
重播。
'''
button_display()
#先停止播放。
button_play(music_log[-1])
def button_last():
'''
播放上一首。
'''
button_display()
#先停止播放。
music_log.pop()
#删去最后的播放记录,也就是正在播放的。
button_play(music_log[-1])
#提供现在的最后一条播放记录。
buttoms = tk.Frame(root)
#操作按钮都挂载在它上面。
button_p = tk.Button(buttoms, text='PLAY', command=button_play)
button_p.pack(side='left')
tk.Button(buttoms, text='play last one', command=button_last)
.pack(side='left')
tk.Button(buttoms, text='again', command=button_again)
.pack(side='left')
shower.pack()
buttoms.pack()
return root
写一个main函数:
def main(path=r'D:/audios'):
tk_show(path).mainloop()
效果图:
闲谈
如果不在结束播放时,将'mixer.music'挂载在别的文件上,
覆盖刚才播放的文件会出现“PermissionError”。
当时我真是一脸懵逼,在网上搜了半天也没有找到。最后尝试着解决的。