问题描述
我正在使用 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