From 0d9d5c4f43c0b8ef0e10b7ad389a44420973f705 Mon Sep 17 00:00:00 2001 From: k4yt3x Date: Fri, 8 May 2020 22:12:24 -0400 Subject: [PATCH] fixed progress monitor error, enhanced GUI error display --- src/upscaler.py | 12 ++++- src/video2x_gui.py | 108 ++++++++++++++++++++++++++++++--------------- 2 files changed, 82 insertions(+), 38 deletions(-) diff --git a/src/upscaler.py b/src/upscaler.py index 780dbf2..d211b1d 100755 --- a/src/upscaler.py +++ b/src/upscaler.py @@ -142,8 +142,12 @@ class Upscaler: raise ArgumentError('input output path type mismatch') for input_path in self.input: if not input_path.is_file() and not input_path.is_dir(): - Avalon.error(_('Input path {} is neither a file nor a directory'.format(input_path))) + Avalon.error(_('Input path {} is neither a file nor a directory').format(input_path)) raise FileNotFoundError(f'{input_path} is neither file nor directory') + with contextlib.suppress(FileNotFoundError): + if input_path.samefile(self.output): + Avalon.error(_('Input directory and output directory cannot be the same')) + raise FileExistsError('input directory and output directory are the same') # if input is a file elif self.input.is_file(): @@ -162,6 +166,10 @@ class Upscaler: Avalon.error(_('Input and output path type mismatch')) Avalon.error(_('Input is directory but output is existing single file')) raise ArgumentError('input output path type mismatch') + with contextlib.suppress(FileNotFoundError): + if self.input.samefile(self.output): + Avalon.error(_('Input directory and output directory cannot be the same')) + raise FileExistsError('input directory and output directory are the same') # if input is neither else: @@ -461,7 +469,7 @@ class Upscaler: Avalon.info(_('Reading video information')) video_info = fm.get_video_info(self.current_input_video) - # analyze original video with ffprobe and retrieve framerate + # analyze original video with FFprobe and retrieve framerate # width, height = info['streams'][0]['width'], info['streams'][0]['height'] # find index of video stream diff --git a/src/video2x_gui.py b/src/video2x_gui.py index d57cc78..0a00dd8 100755 --- a/src/video2x_gui.py +++ b/src/video2x_gui.py @@ -53,14 +53,14 @@ def resource_path(relative_path: str) -> pathlib.Path: class WorkerSignals(QObject): progress = pyqtSignal(tuple) - error = pyqtSignal(str) + error = pyqtSignal(Exception) interrupted = pyqtSignal() finished = pyqtSignal() -class ProgressBarWorker(QRunnable): +class ProgressMonitorWorkder(QRunnable): def __init__(self, fn, *args, **kwargs): - super(ProgressBarWorker, self).__init__() + super(ProgressMonitorWorkder, self).__init__() self.fn = fn self.args = args self.kwargs = kwargs @@ -94,10 +94,9 @@ class UpscalerWorker(QRunnable): self.fn(*self.args, **self.kwargs) except (KeyboardInterrupt, SystemExit): self.signals.interrupted.emit() - except Exception: - error_message = traceback.format_exc() - print(error_message, file=sys.stderr) - self.signals.error.emit(error_message) + except Exception as e: + traceback.print_exc() + self.signals.error.emit(e) else: self.signals.finished.emit() @@ -164,7 +163,7 @@ class Video2XMainWindow(QMainWindow): self.action_exit.triggered.connect(sys.exit) self.action_about = self.findChild(QAction, 'actionAbout') - self.action_about.triggered.connect(lambda: self.show_message(LEGAL_INFO, custom_icon=QtGui.QPixmap(self.video2x_icon_path))) + self.action_about.triggered.connect(self.show_about) # main tab # select input file/folder @@ -617,20 +616,46 @@ class Video2XMainWindow(QMainWindow): return driver_line_edit.setText(str(driver_binary_path.absolute())) - def show_error(self, message: str): - QErrorMessage(self).showMessage(message.replace('\n', '
')) + def show_about(self, message: str): + message_box = QMessageBox(self) + message_box.setWindowTitle('About Video2X') + message_box.setIconPixmap(QtGui.QPixmap(self.video2x_icon_path).scaled(64, 64)) + message_box.setText(LEGAL_INFO) + message_box.exec_() - def show_message(self, message: str, custom_icon=None): - message_box = QMessageBox() - message_box.setWindowTitle('Message') - if custom_icon: - message_box.setIconPixmap(custom_icon.scaled(64, 64)) - else: - message_box.setIcon(QMessageBox.Information) + def show_information(self, message: str): + message_box = QMessageBox(self) + message_box.setWindowTitle('Information') + message_box.setIcon(QMessageBox.Information) message_box.setText(message) message_box.exec_() - def start_progress_bar(self, progress_callback): + def show_warning(self, message: str): + message_box = QMessageBox(self) + message_box.setWindowTitle('Warning') + message_box.setIcon(QMessageBox.Warning) + message_box.setText(message) + message_box.exec_() + + def show_error(self, exception: Exception): + # QErrorMessage(self).showMessage(message.replace('\n', '
')) + message_box = QMessageBox(self) + message_box.setWindowTitle('Error') + message_box.setIcon(QMessageBox.Critical) + + error_message = '''Upscaler ran into an error: +{} +Check the console output for details. +When reporting an error, please include console output.''' + + try: + message_box.setText(error_message.format(exception.args[0])) + except (AttributeError, IndexError): + message_box.setText(error_message.format(exception)) + + message_box.exec_() + + def progress_monitor(self, progress_callback): # initialize progress bar values upscale_begin_time = time.time() @@ -702,16 +727,18 @@ class Video2XMainWindow(QMainWindow): # resolve input and output directories from GUI if len(self.input_table_data) == 0: - self.show_error('Input path unspecified') + self.show_warning('Input path unspecified', standard_icon=QMessageBox.Warning) return if self.output_line_edit.text().strip() == '': - self.show_error('Output path unspecified') + self.show_warning('Output path unspecified', standard_icon=QMessageBox.Warning) return if len(self.input_table_data) == 1: input_directory = self.input_table_data[0] else: input_directory = self.input_table_data + + # resolve output directory output_directory = pathlib.Path(os.path.expandvars(self.output_line_edit.text())) # load driver settings from GUI @@ -733,33 +760,35 @@ class Video2XMainWindow(QMainWindow): self.upscaler.image_format = self.config['video2x']['image_format'].lower() self.upscaler.preserve_frames = bool(self.preserve_frames_check_box.isChecked()) - # start progress bar - if AVAILABLE_DRIVERS[self.driver_combo_box.currentText()] != 'anime4kcpp': - progress_bar_worker = ProgressBarWorker(self.start_progress_bar) - progress_bar_worker.signals.progress.connect(self.set_progress) - self.threadpool.start(progress_bar_worker) - # run upscaler worker = UpscalerWorker(self.upscaler.run) worker.signals.error.connect(self.upscale_errored) worker.signals.interrupted.connect(self.upscale_interrupted) worker.signals.finished.connect(self.upscale_successful) self.threadpool.start(worker) + + # start progress monitoring + if AVAILABLE_DRIVERS[self.driver_combo_box.currentText()] != 'anime4kcpp': + progress_bar_worker = ProgressMonitorWorkder(self.progress_monitor) + progress_bar_worker.signals.progress.connect(self.set_progress) + self.threadpool.start(progress_bar_worker) + self.start_button.setEnabled(False) self.stop_button.setEnabled(True) - except Exception: - self.upscale_errored(traceback.format_exc()) + except Exception as e: + traceback.print_exc() + self.upscale_errored(e) - def upscale_errored(self, error_message): - self.show_error(f'Upscaler ran into an error:\n{error_message}') + def upscale_errored(self, exception: Exception): + self.show_error(exception) self.threadpool.waitForDone(5) self.start_button.setEnabled(True) self.stop_button.setEnabled(False) self.reset_progress_display() def upscale_interrupted(self): - self.show_message('Upscale has been interrupted') + self.show_information('Upscale has been interrupted') self.threadpool.waitForDone(5) self.start_button.setEnabled(True) self.stop_button.setEnabled(False) @@ -768,7 +797,7 @@ class Video2XMainWindow(QMainWindow): def upscale_successful(self): # if all threads have finished self.threadpool.waitForDone(5) - self.show_message('Upscale finished successfully, taking {} seconds'.format(round((time.time() - self.begin_time), 5))) + self.show_information('Upscale finished successfully, taking {} seconds'.format(round((time.time() - self.begin_time), 5))) self.start_button.setEnabled(True) self.stop_button.setEnabled(False) self.reset_progress_display() @@ -785,7 +814,14 @@ class Video2XMainWindow(QMainWindow): # this file shouldn't be imported if __name__ == '__main__': - app = QApplication(sys.argv) - window = Video2XMainWindow() - window.show() - app.exec_() + try: + app = QApplication(sys.argv) + window = Video2XMainWindow() + window.show() + app.exec_() + + # on GUI exception, print error message in console + # and hold window open using input() + except Exception: + traceback.print_exc() + input('Press enter to close')