在 python 中播放 mp3 时 window.read() 和 time.sleep() 的问题

问题描述

我正在使用 pafy、vlc、PySimpleGUI 制作一个程序,该程序采用 youtube 网址并将其作为 mp3 播放 我第一次尝试控制台模式时遇到的问题是 mp3 在一段时间后停止,我用 time.sleep(seconds) 修复了它,现在在控制台版本中一切正常。 当我使用 time.sleep(seconds) 尝试使用 PySimpleGUI 使其成为 GUI 时出现问题。GUI 冻结,直到 mp3 结束,我搜索并发现 window.read() 可能解决了问题,但确实如此,但我暂停后无法继续播放 mp3(如控制台模式),当我按下播放时它会播放,当我按下暂停时它会暂停,当我再次按下播放时它会从头开始,但我希望它从什么时候开始暂停是因为 window.read() 吗? 对不起,如果我不能清楚地解释它。 控制台模式:

class Dataset(Dataset):
    def __init__(self,directory,transform,preload=False,device: torch.device = torch.device('cpu'),**kwargs):
        self.device = device
        self.directory = directory
        self.transform = transform
        self.labels = []
        self.images = []
        self.preload = preload

        for i,file in enumerate(os.listdir(self.directory)):
            file_labels = parse('{}_{}_{age}_{gender}.jpg',file)
            
            if file_labels is None:
                continue
                
            if self.preload:
                image = Image.open(os.path.join(self.directory,file)).convert('RGB')
                if self.transform is not None:
                    image = self.transform(image).to(self.device)
            else:
                image = os.path.join(self.directory,file)

            self.images.append(image)
            
            gender_to_class_id = {
                'm': 0,'f': 1
            }
            gender = gender_to_class_id[file_labels['gender']]
            age = int(file_labels['age'])
            self.labels.append({
                'age': age,'gender': gender
            })
        pass

    def __len__(self):
        return len(self.labels)

    def __getitem__(self,idx):
        if torch.is_tensor(idx):
            idx = idx.tolist()

        image = self.images[idx]

        if not self.preload:
            image = Image.open(image).convert('RGB')
            if self.transform is not None:
                image = self.transform(image).to(self.device)

        labels = {
            'age': self.labels[idx]['age'],'gender': self.labels[idx]['gender'],}
        return image.to(self.device),labels
    
    def get_loaders(self,train_size=0.7,validate_size=0.2,test_size=0.1,batch_size=15,**kwargs):
        if round(train_size + validate_size + test_size,1) > 1.0:
            sys.exit("Sum of the percentages should be less than 1. it's " + str(
                train_size + validate_size + test_size) + " Now!")

        train_len = int(len(self) * train_size)
        validate_len = int(len(self) * validate_size)
        test_len = int(len(self) * test_size)
        others_len = len(self) - train_len - validate_len - test_len

        self.trainDataset,self.validateDataset,self.testDataset,_ = torch.utils.data.random_split(
            self,[train_len,validate_len,test_len,others_len]
        )

        train_loader = DataLoader(self.trainDataset,batch_size=batch_size)
        validate_loader = DataLoader(self.validateDataset,batch_size=batch_size)
        test_loader = DataLoader(self.testDataset,batch_size=batch_size)

        return train_loader,validate_loader,test_loader

GUI 模式:

import pafy
import vlc
player = vlc.Instance()
media_player = player.media_player_new()    
def readurl():
    url=input("URL : ")
    vid=pafy.new(url)
    l=vid.length
    aud=vid.getbestaudio()
    media = player.media_new(aud.url)
    media.get_mrl()
    media_player.set_media(media)
def ans(a):
    if(a.upper()=="S"):
        media_player.pause()
    elif(a.upper()=="P"):
        media_player.play()
    elif(a.upper()=="R"):
        media_player.pause()
        readurl()
        ans("P")
    else:
        exit()
readurl()
while True:
    a=input("Choose from options P to play,S to stop(pause),Q to quit,R to get another video. ")
    ans(a)
    

解决方法

定义您的 GUI,然后进入您的事件循环并确保您的 GUI 中将发生什么事件,然后下一步是哪个事件。

这里是修改后的代码供大家参考,代码不做测试。

import PySimpleGUI as sg
import vlc
import pafy
import time

def vlc_player():
    player = vlc.Instance()
    media_player = player.media_player_new()
    return media_player

def Button(button_text):
    return sg.Button(button_text,size=(6,1),pad=(1,1))

media_player = vlc_player()

sg.theme('DarkBlue')
sg.set_options(font=("Courier New",16))

layout = [
    [sg.Button(button_text='Get video from youtube url : ',size=(20,key='-GET_URL-'),sg.Input(default_text='',size=(50,10),key='URL')],[Button('PLAY'),BUTTON('PAUSE'),Button('QUIT')],[sg.Text("",size=(0,key='-STATUS-')],]

window = sg.Window('Youtube Radio Mode',layout,element_justification='center',finalize=True,resizable=True)

status = window['-STATUS-']
mp3_load = False

#------------ The Event Loop ------------#

while True:

    event,values = window.read()

    if event in (sg.WIN_CLOSED,'QUIT'):
        break

    status.update(value='')

    if event == '-GET_URL-':
        """
        if player.is_playing():
            player.stop()
        """
        url = values['-URL-'].strip()

        try:
            vid     = pafy.new(url)
            aud     = vid.getbestaudio()
            media   = player.media_new(aud.url)
            media.get_mrl()
            media_player.set_media(media)
            mp3_load = True
            continue
        except:
            pass
        status.update('URL load failed !')
        mp3_load = False

    elif event == 'PLAY' and mp3_load:
        media_player.play()

    elif event == 'PAUSE' and mp3_load:
        media_player.pause()

if player.is_playing():
    media_player.stop()
window.close()

如果需要很长时间,可以使用多线程从 Youtube 加载 mp3,并设置一些标志以确认是否正在下载或下载完成,或者禁用按钮“-GET_URL-”或其他按钮。

不要直接在另一个线程中更新GUI,可以调用window.write_event_value生成新事件,然后在事件循环中更新GUI。

参考https://github.com/PySimpleGUI/PySimpleGUI/blob/master/DemoPrograms/Demo_Media_Player_VLC_Based.py

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...