When I close the video with a cross, the audio remains. I use pafy and vlc. Also i can't close PyQt app after closing video.
I use python 3.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_())
You have the following problems:
You should not use time consuming tasks within the Qt eventloop as it blocks it causing the GUI to freeze, for example the while.loop and pafy's getbest function, the first one should use a callback to know when the video finishes from reproduce and the second must be executed in a secondary thread.
You also have to pass arguments in the lambda since otherwise you will have problems with the scope.
To detect when the window closes, a possible solution is to embed the videoplayer in a QWidget and then use an eventfilter to know when the window closes and then stops the player.
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_())