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

problem with window.read() and time.sleep() when playing an mp3 in python

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

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模式:

import PySimpleGUI as sg
import vlc
import pafy
import time
player = vlc.Instance()
media_player = player.media_player_new()    
sg.theme('DarkBlue')
def btn(name):  
    return sg.Button(name, size=(6, 1), pad=(1, 1))
layout = [[sg.Button(button_text='Get video from youtube url : ', size=(20,1), key='geturl'),sg.Input(default_text='', size=(50, 10), key='-VIDEO_LOCATION-')],
          [btn('play'), btn('pause')]]
window = sg.Window('Youtube Radio Mode', layout, element_justification='center', finalize=True, resizable=True)              
#------------ Media Player Setup ---------#
"""
    """
def ans(a,q):
    if(a.upper()=="S"):
        media_player.pause()
        #window.read(q)
    elif(a.upper()=="P"):# or (a.upper()=="R")):
        media_player.play()
        window.read(q)
    else:
        exit()
#------------ The Event Loop ------------#
#def vi()
while True:
    event, values = window.read(timeout=1000)      
    url=values['-VIDEO_LOCATION-']
    z=''
    if event == sg.WIN_CLOSED:
        break
    if (url!='' or event == 'geturl'):
        vid=pafy.new(url)
        #l=vid.length
        aud=vid.getbestaudio()
        media = player.media_new(aud.url)
        media.get_mrl()
        media_player.set_media(media)
        z='l'
        q=vid.length*1000
    if event == 'play':
        if(z!='l'):
            sg.popup_error('PLEASE GET A URL FIRST')    
            continue
        ans("P",q)
        #window.refresh()
        z=''
    if event == 'pause':
        ans("S",q)
window.close()

定义您的 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,1), key='-GET_URL-'),
     sg.Input(default_text='', size=(50, 10), key='URL')],
    [Button('PLAY'), BUTTON('PAUSE'), Button('QUIT')],
    [sg.Text("", size=(0, 1), 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