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):
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):
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(),
+ "-nocache",
+ "-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()
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/"
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)
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):
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)
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
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")
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()