在win10电脑上设置默认编码为UTF-8,无法正常播放U盘中的音乐,我写了一个播放器解决

背景

我打开了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”。
当时我真是一脸懵逼,在网上搜了半天也没有找到。最后尝试着解决的。

posted @ 2020-06-01 17:45  风吹云动  阅读(864)  评论(0编辑  收藏  举报