From: James Bunton Date: Sun, 17 Feb 2013 08:55:18 +0000 (+1100) Subject: Improved error handling and messages X-Git-Url: https://code.delx.au/bluplayer/commitdiff_plain/043a74aa8df629028bbcaf7a953a450322bd9791 Improved error handling and messages --- diff --git a/bluplayer.py b/bluplayer.py index 42db223..d119a3a 100755 --- a/bluplayer.py +++ b/bluplayer.py @@ -17,10 +17,26 @@ XHTML = "http://www.w3.org/1999/xhtml" NS = { "xhtml": XHTML, } +DEFAULT_PATH = "/usr/local/bin:/usr/bin:/bin" -MAKEMKV_DIR = os.environ.get("MAKEMKV_DIR", os.path.expanduser("~/.makemkv_install")) -MAKEMKVCON_PATH = os.environ.get("MAKEMKVCON_PATH", os.path.join(MAKEMKV_DIR, "current", "makemkvcon")) -MPLAYER_PATH = os.environ.get("MPLAYER_PATH", "mplayer") + +def set_env_config(name, value): + value = os.environ.get(name, value) + globals()[name] = value + +def find_path(binary): + value = "" + paths = os.environ.get("PATH", DEFAULT_PATH).split(":") + for path in paths: + path = os.path.join(path, binary) + if os.path.isfile(path): + value = path + break + return value + +set_env_config("MAKEMKVCON_PATH", find_path("makemkvcon")) +set_env_config("MPLAYER_PATH", find_path("mplayer")) +set_env_config("MPLAYER_OPTS", None) def grab_xml(url): @@ -47,15 +63,21 @@ def parse_doc(doc): i += 2 return d +def get_num_cpus(): + logging.info("Determing number of CPUs") + try: + return subprocess.check_output("nproc").strip() + except Exception, e: + logging.warn("Unable to run nproc: %s", fmt_exc(e)) + return 1 + def grab_dict(url): doc = grab_xml(url) d = parse_doc(doc) return d -def format_exception(msg, e=None): - msg = "%s\n%s: %s" % (msg, e.__class__.__name__, str(e)) - logging.error(msg) - return msg +def fmt_exc(e): + return "%s: %s" % (e.__class__.__name__, str(e)) class Title(object): @@ -115,21 +137,36 @@ class MakeMkvCon(object): class MPlayer(QObject): play_finished = pyqtSignal() - fatal_error = pyqtSignal(str) + fatal_error = pyqtSignal(str, str) - def play(self, video_url): - logging.info("Running mplayer: %s", video_url) - try: - cmd = [ - MPLAYER_PATH, + def run(self): + logging.info("mplayer thread started") + + if not os.path.isfile(MPLAYER_PATH): + self.fatal_error.emit( + "MPlayer was not found.", + "Please install MPlayer. If you already have done so you " + + "may set the MPLAYER_PATH environment variable to the " + + "absolute path to the mplayer executable." + ) + return + + if MPLAYER_OPTS: + self.opts = MPLAYER_OPTS.split() + else: + self.opts = [ "-fs", - "-lavdopts", "threads=%s" % subprocess.check_output("nproc").strip(), + "-lavdopts", "threads=%s" % get_num_cpus(), "-volume", "100", - video_url, ] - subprocess.check_call(cmd) + + def play(self, video_url): + video_url = str(video_url) + logging.info("Running mplayer: %s", video_url) + try: + subprocess.check_call([MPLAYER_PATH] + self.opts + [video_url]) except Exception, e: - self.fatal_error.emit(format_exception("MPlayer failed to play the video", e)) + self.fatal_error.emit("MPlayer failed to play the video.", fmt_exc(e)) finally: self.play_finished.emit() @@ -138,10 +175,7 @@ class MakeMkv(QObject): title_loaded = pyqtSignal(Title) title_load_complete = pyqtSignal() status = pyqtSignal(str) - fatal_error = pyqtSignal(str) - - def install(self): - raise NotImplementedError("auto-install not implemented") + fatal_error = pyqtSignal(str, str) def find_disc(self): self.url = "http://192.168.1.114:51001/" @@ -171,7 +205,10 @@ class MakeMkv(QObject): self.status.emit(line[3]) if makemkvcon.status != 0: - self.fatal_error.emit("MakeMKV exited with error status: %s" % makemkvcon.status) + self.fatal_error.emit( + "MakeMKV quit unexpectedly.", + "makemkvcon exited with code %s" % makemkvcon.status + ) def load_titles(self, url): home_page = grab_dict(url) @@ -184,35 +221,41 @@ class MakeMkv(QObject): self.title_load_complete.emit() def run(self): - logging.info("MakeMKV thread started") + logging.info("makemkv thread started") if not os.path.isfile(MAKEMKVCON_PATH): - try: - self.install() - except Exception, e: - self.fatal_error.emit(format_exception("Failed to install MakeMKV", e)) - raise + self.fatal_error.emit( + "MakeMKV was not found.", + "Please install MakeMKV. If you already have done so you " + + "may set the MAKEMKVCON_PATH environment variable to the " + + "absolute path to the makemkvcon executable." + ) + return try: disc_number = self.find_disc() except Exception, e: - self.fatal_error.emit(format_exception("Error searching for disc", e)) + self.fatal_error.emit("Error searching for disc.", fmt_exc(e)) raise if not disc_number: - self.fatal_error.emit("No disc found, please insert a disc and try again.") + self.fatal_error.emit( + "No disc found.", + "Please insert a BluRay disc and try again." + ) return try: self.run_stream(disc_number) except Exception, e: - self.fatal_error.emit(format_exception("Failed to start MakeMKV", e)) + self.fatal_error.emit("Failed to start MakeMKV.", fmt_exc(e)) raise - logging.info("MakeMKV thread finished") + logging.info("makemkv thread finished") class PlayerWindow(QWidget): + fatal_error = pyqtSignal(str, str) video_selected = pyqtSignal(str) def __init__(self): @@ -236,6 +279,7 @@ class PlayerWindow(QWidget): self.layout = QVBoxLayout(self) self.layout.addWidget(self.splitter) self.setWindowTitle("BluPlayer") + self.resize(1200, 700) def add_title(self, title): name = "Title %s (%s)" % (int(title.id)+1, title.duration) @@ -259,10 +303,6 @@ class PlayerWindow(QWidget): def add_log_entry(self, text): self.log.append(text) - def popup_fatal_error(self, text): - QMessageBox.critical(None, "Fatal error", text) - qApp.quit() - def handle_activated(self, item): if self.is_playing: return @@ -283,10 +323,43 @@ class PlayerWindow(QWidget): return QWidget.keyPressEvent(self, e) +class LoadingDialog(QProgressDialog): + def __init__(self, parent): + QProgressDialog.__init__(self, parent) + self.setWindowModality(Qt.WindowModal); + self.setWindowTitle("Loading disc") + self.setLabelText("Loading BluRay disc. Please wait...") + self.setCancelButtonText("Exit") + self.setMinimum(0) + self.setMaximum(0) + +class ErrorDialog(QMessageBox): + fatal_error = pyqtSignal(str, str) + + def __init__(self, parent): + QMessageBox.__init__(self, parent) + self.setStandardButtons(QMessageBox.Ok) + self.setDefaultButton(QMessageBox.Ok) + self.fatal_error.connect(self.configure_popup) + self.setWindowTitle("Fatal error") + self.has_run = False + + def configure_popup(self, text, detail): + if self.has_run: + return + self.has_run = True + self.setText(text) + self.setInformativeText(detail) + QTimer.singleShot(0, self.show_and_exit) + + def show_and_exit(self): + logging.info("showing and exiting") + self.exec_() + qApp.quit() def killall_makemkvcon(): - logging.info("killing makemkvcon") - subprocess.Popen(["killall", "makemkvcon"]).wait() + logging.info("Stopping any makemkvcon processes") + subprocess.Popen(["killall", "--quiet", "makemkvcon"]).wait() def main(): logging.basicConfig(format="%(levelname)s: %(message)s") @@ -301,37 +374,36 @@ def main(): app.setFont(default_font) player_window = PlayerWindow() - player_window.resize(1200, 700) player_window.show() + loading_dialog = LoadingDialog(player_window) + loading_dialog.show() + + error_dialog = ErrorDialog(player_window) + makemkv = MakeMkv() makemkv_thread = QThread() makemkv.moveToThread(makemkv_thread) + makemkv_thread.started.connect(makemkv.run) mplayer = MPlayer() mplayer_thread = QThread() mplayer.moveToThread(mplayer_thread) + mplayer_thread.started.connect(mplayer.run) - 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) + makemkv.fatal_error.connect(error_dialog.fatal_error) + makemkv.title_load_complete.connect(loading_dialog.reset) player_window.video_selected.connect(mplayer.play) mplayer.play_finished.connect(player_window.set_play_finished) + mplayer.fatal_error.connect(error_dialog.fatal_error) - loading_window = QProgressDialog( - "Loading BluRay disc. Please wait...", - "Exit", - 0, 0, # 'infinite' style progress bar - player_window - ) - loading_window.setWindowTitle("Loading disc") - loading_window.setWindowModality(Qt.WindowModal); - loading_window.show() - loading_window.canceled.connect(qApp.quit) - makemkv.title_load_complete.connect(loading_window.reset) + player_window.fatal_error.connect(error_dialog.fatal_error) + error_dialog.fatal_error.connect(loading_dialog.reset) + loading_dialog.canceled.connect(qApp.quit) logging.info("Starting application") makemkv_thread.start()