我关闭了 vlc 媒体,但在这个音频仍然存在之后我无法使用 gui

I close vlc media, but after this audio remains and i can't use gui

当我用叉号关闭视频时,音频仍然存在。我使用 pafy 和 vlc。我也无法在关闭视频后关闭 PyQt 应用程序。

我用的是python3.8.

import sys
import pafy
import vlc

from PyQt5.QtWidgets import QApplication, QDialog, QLabel, QHBoxLayout, QPushButton

class GoodYoutubeGUI(QDialog):
    def __init__(self):
        super().__init__()
        self.setFixedSize(800, 800)
        self.setWindowTitle("Good Youtube")
        self.buttons = []
        self.generate_content()

    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: self.open_video(link))
            button.move(100, pos_y * 100)
            pos_y += 1

    def open_video(self, url):
        video = pafy.new("https://www.youtube.com/watch?v=zPA2Een1EQA")
        best = video.getbest()
        media = vlc.MediaPlayer(best.url)
        media.play()
        while media.get_state() != vlc.State.Ended:
            continue

        media.stop()


if __name__ == '__main__':
    app = QApplication(sys.argv)
    dlg_main = GoodYoutubeGUI()
    dlg_main.show()
    sys.exit(app.exec_())

您遇到以下问题:

  • 你不应该在 Qt 事件循环中使用耗时的任务,因为它会阻止它导致 GUI 冻结,例如 while.loop 和 pafy 的 getbest 函数,第一个应该使用回调以了解视频何时完成重现,第二个必须在辅助线程中执行。

  • 您还必须在 lambda 中传递参数,否则您将遇到范围问题。

  • 要检测 window 何时关闭,一个可能的解决方案是将视频播放器嵌入 QWidget,然后使用事件过滤器了解 window 何时关闭然后停止玩家。

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_())