您有以下问题:
您不应该在 Qt 事件循环中使用耗时的任务,因为它会阻止它导致 GUI 冻结,例如 while.loop 和 pafy 的 getbest 函数,第一个应该使用回调来知道视频何时从再现结束,第二个必须在辅助线程中执行。
您还必须在 lambda 中传递参数,否则您将遇到范围问题。
要检测窗口何时关闭,一种可能的解决方案是将视频播放器嵌入到 QWidget 中,然后使用事件过滤器来了解窗口何时关闭,然后停止播放器。
from functools import cached_property
import sys
import threading
import pafy
import vlc
from PyQt5.QtCore import pyqtSignal, QEvent, QObject
from PyQt5.QtWidgets import QApplication, QDialog, QPushButton, QWidget
class PlayerManager(QObject):
def __init__(self, parent=None):
super().__init__(parent)
self.window = QWidget()
if sys.platform.startswith("linux"): # for Linux using the X Server
self.player.set_xwindow(self.window.winId())
elif sys.platform == "win32": # for Windows
self.player.set_hwnd(self.window.winId())
elif sys.platform == "darwin": # for MacOS
self.player.set_nsobject(self.window.winId())
self.window.installEventFilter(self)
@cached_property
def player(self):
player = vlc.MediaPlayer()
player.event_manager().event_attach(
vlc.EventType.MediaPlayerEndReached, self._handle_finished
)
return player
def _handle_finished(self, event):
if event.type == vlc.EventType.MediaPlayerEndReached:
self.player.stop()
def play(self):
self.player.play()
self.window.show()
def set_media(self, url):
media = vlc.Media(url)
self.player.set_media(media)
def eventFilter(self, obj, event):
if obj is self.window and event.type() == QEvent.Close:
self.player.stop()
return super().eventFilter(obj, event)
class UrlProvider(QObject):
finished = pyqtSignal(str)
def find_url(self, url):
threading.Thread(target=self._find_url, args=(url,), daemon=True).start()
def _find_url(self, url):
video = pafy.new(url)
best = video.getbest()
self.finished.emit(best.url)
class GoodYoutubeGUI(QDialog):
def __init__(self):
super().__init__()
self.setFixedSize(800, 800)
self.setWindowTitle("Good Youtube")
self.buttons = []
self.url_provider.finished.connect(self.handle_url_finished)
self.generate_content()
@cached_property
def player_manager(self):
return PlayerManager()
@cached_property
def url_provider(self):
return UrlProvider()
def generate_buttons_info(self):
buttons_info = {}
for _ in range(5):
button = QPushButton("Открыть видео", self)
buttons_info[button] = "https://www.youtube.com/watch?v=zPA2Een1EQA"
return buttons_info
def generate_content(self):
pos_y = 0
for button, link in self.generate_buttons_info().items():
button.clicked.connect(lambda checked, link=link: self.open_video(link))
button.move(100, pos_y * 100)
pos_y += 1
def open_video(self, url):
self.url_provider.find_url(url)
def handle_url_finished(self, url):
self.player_manager.set_media(url)
self.player_manager.play()
if __name__ == "__main__":
app = QApplication(sys.argv)
dlg_main = GoodYoutubeGUI()
dlg_main.show()
sys.exit(app.exec_())