Run mplayer in a background thread so it doesn't block UI
authorJames Bunton <jamesbunton@delx.net.au>
Sun, 17 Feb 2013 00:47:06 +0000 (11:47 +1100)
committerJames Bunton <jamesbunton@delx.net.au>
Sun, 17 Feb 2013 00:47:06 +0000 (11:47 +1100)
bluplayer.py

index 15f6c97..4b6f2b8 100755 (executable)
@@ -67,17 +67,6 @@ class Title(object):
        def __str__(self):
                return "Title%s: %s %s" % (self.id, self.duration, self.video_url)
 
-       def play(self):
-               cmd = [
-                       MPLAYER_PATH,
-                       "-fs",
-                       "-lavdopts", "threads=%s" % subprocess.check_output("nproc").strip(),
-                       "-volume", "100",
-                       self.video_url,
-               ]
-               logging.info("Running mplayer: %s", self.video_url)
-               subprocess.check_call(cmd)
-
 
 class MakeMkvCon(object):
        def __init__(self, params):
@@ -124,6 +113,27 @@ class MakeMkvCon(object):
                        self.buf += data
 
 
+class MPlayer(QObject):
+       play_finished = pyqtSignal()
+       fatal_error = pyqtSignal(str)
+
+       def play(self, video_url):
+               logging.info("Running mplayer: %s", video_url)
+               try:
+                       cmd = [
+                               MPLAYER_PATH,
+                               "-fs",
+                               "-lavdopts", "threads=%s" % subprocess.check_output("nproc").strip(),
+                               "-volume", "100",
+                               video_url,
+                       ]
+                       subprocess.check_call(cmd)
+               except Exception, e:
+                       self.fatal_error.emit(format_exception("MPlayer failed to play the video", e))
+               finally:
+                       self.play_finished.emit()
+
+
 class MakeMkv(QObject):
        title_loaded = pyqtSignal(Title)
        title_load_complete = pyqtSignal()
@@ -203,13 +213,17 @@ class MakeMkv(QObject):
 
 
 class PlayerWindow(QWidget):
+       video_selected = pyqtSignal(str)
+
        def __init__(self):
                QWidget.__init__(self)
+
                self.title_map = {}
+               self.is_playing = False
 
                self.list_widget = QListWidget(self)
                self.list_widget.itemActivated.connect(self.handle_activated)
-               self.list_widget.setFocus()
+               self.list_widget.setEnabled(False)
 
                self.log = QTextEdit(self)
                self.log.setReadOnly(True)
@@ -239,6 +253,8 @@ class PlayerWindow(QWidget):
                                longest_title = title
                                longest_item = item
                self.list_widget.setCurrentItem(longest_item)
+               self.list_widget.setEnabled(True)
+               self.list_widget.setFocus()
 
        def add_log_entry(self, text):
                self.log.append(text)
@@ -248,12 +264,18 @@ class PlayerWindow(QWidget):
                qApp.quit()
 
        def handle_activated(self, item):
+               if self.is_playing:
+                       return
                name = str(item.text())
                title = self.title_map[name]
-               try:
-                       title.play()
-               except Exception, e:
-                       popup_error_exit("MPlayer failed to play the video", e)
+               self.is_playing = True
+               self.list_widget.setEnabled(False)
+               self.video_selected.emit(title.video_url)
+
+       def set_play_finished(self):
+               self.is_playing = False
+               self.list_widget.setEnabled(True)
+               self.list_widget.setFocus()
 
        def keyPressEvent(self, e):
                if e.key() in (Qt.Key_Escape, Qt.Key_Backspace):
@@ -269,6 +291,7 @@ def killall_makemkvcon():
 def main():
        logging.basicConfig(format="%(levelname)s: %(message)s")
        logging.getLogger().setLevel(logging.DEBUG)
+       logging.info("Configuring application")
 
        app = QApplication(sys.argv)
        app.setQuitOnLastWindowClosed(True)
@@ -282,24 +305,35 @@ def main():
        player_window.show()
 
        makemkv = MakeMkv()
-       worker_thread = QThread()
-       makemkv.moveToThread(worker_thread)
+       makemkv_thread = QThread()
+       makemkv.moveToThread(makemkv_thread)
 
-       worker_thread.started.connect(makemkv.run)
+       mplayer = MPlayer()
+       mplayer_thread = QThread()
+       mplayer.moveToThread(mplayer_thread)
+
+       makemkv_thread.started.connect(makemkv.run)
        makemkv.title_loaded.connect(player_window.add_title)
        makemkv.title_load_complete.connect(player_window.select_longest_title)
        makemkv.status.connect(player_window.add_log_entry)
        makemkv.fatal_error.connect(player_window.popup_fatal_error)
 
-       logging.info("Starting worker thread")
-       worker_thread.start()
+       player_window.video_selected.connect(mplayer.play)
+       mplayer.play_finished.connect(player_window.set_play_finished)
+
+       logging.info("Starting application")
+       makemkv_thread.start()
+       mplayer_thread.start()
        result = app.exec_()
 
        logging.info("Shutting down")
-       worker_thread.quit()
+       makemkv_thread.quit()
+       mplayer_thread.quit()
        killall_makemkvcon()
-       logging.info("Waiting for worker thread")
-       worker_thread.wait(2000)
+       logging.info("Waiting for makemkv thread")
+       makemkv_thread.wait(2000)
+       logging.info("Waiting for mplayer thread")
+       mplayer_thread.wait(2000)
        logging.info("Exiting...")
        sys.exit(result)