diff --git a/bin/arg_assembly.py b/bin/arg_assembly.py new file mode 100644 index 0000000..ddbb568 --- /dev/null +++ b/bin/arg_assembly.py @@ -0,0 +1,15 @@ +class ArgAssembly: + def __init__(self): + pass + + def get(self, quality): + if quality == "2x": + return "Performance" + elif quality == "1.7x": + return "Balanced" + elif quality == "1.5x": + return "Quality" + elif quality == "1.3x": + return "UltraQuality" + else: + raise Exception diff --git a/bin/checks.py b/bin/checks.py new file mode 100644 index 0000000..6e506c9 --- /dev/null +++ b/bin/checks.py @@ -0,0 +1,41 @@ +class Checks: + def __init__(self): + self.custom_quality = 0.0 + self.i_file_extension = "" + + def perform(self, quality_selection, custom_quality, input_filepath, output_filepath): + # Call this function to perform entry checks. + # Returns True if all checks passed, False if one or more not passed. + if self.quality_checks(quality_selection, custom_quality) and self.file_checks(input_filepath, output_filepath): + return True + else: + return False + + def quality_checks(self, quality_sel, custom_q): + if quality_sel != "Custom (will respect value below)": + return True + else: + try: + self.custom_quality = float(custom_q) + except ValueError: + return False + return True + + def file_checks(self, i_fp, o_fp): + self.i_file_extension = str(i_fp)[len(i_fp) - 4:] + if self.i_file_extension == ".png" or self.i_file_extension == ".jpg": + pass + elif self.i_file_extension == "jpeg": + if str(i_fp)[len(i_fp) - 5:] == ".jpeg": + pass + else: + return False + elif self.i_file_extension == ".mp4" or self.i_file_extension == ".mkv": + pass + else: + return False + + if str(i_fp)[len(i_fp) - 4:] == str(o_fp)[len(o_fp) - 4:]: + return True + else: + return False diff --git a/bin/handler.py b/bin/handler.py index 985e688..3976caa 100644 --- a/bin/handler.py +++ b/bin/handler.py @@ -47,7 +47,7 @@ class Handler: if str(filepath)[len(filepath) - 4:] == ".mp4" or str(filepath)[len(filepath) - 4:] == ".mkv": print("upscaling video") self.video_scaling(ffmpegpath, fsrpath, filepath, quality_mode, quality_setting, output_path) - elif str(filepath)[len(filepath) - 4:] == ".JPG" or str(filepath)[len(filepath) - 4:] == ".png" or str(filepath)[len(filepath) - 4:] == ".jpg": + elif str(filepath)[len(filepath) - 4:] == ".JPG" or str(filepath)[len(filepath) - 4:] == ".png" or str(filepath)[len(filepath) - 4:] == ".jpg" or str(filepath)[len(filepath) - 5:] == ".jpeg": print("upscaling image") self.photo_scaling(fsrpath, filepath, quality_mode, quality_setting, output_path) else: @@ -192,8 +192,11 @@ class Handler: # get Video's audio print("Retrieving Video's audio to append") - os.remove(f"{self.tmppath}audio.aac") - os.remove(f"{output_path}") + try: + os.remove(f"{self.tmppath}audio.aac") + os.remove(f"{output_path}") + except FileNotFoundError: + pass if self.os_type == "linux": self.command = f"ffmpeg -i {self.filepath} -vn -acodec copy {self.tmppath}audio.aac" elif self.os_type == "win32": diff --git a/fsrimagevideoupscaler.py b/fsrimagevideoupscaler.py index e0167d4..a6ed40d 100644 --- a/fsrimagevideoupscaler.py +++ b/fsrimagevideoupscaler.py @@ -10,14 +10,65 @@ import gi import bin.handler import multiprocessing +import bin.checks +import bin.arg_assembly gi.require_version("Gtk", "3.0") from gi.repository import Gtk +arg = bin.arg_assembly.ArgAssembly() +checks = bin.checks.Checks() handler = bin.handler.Handler() +class ProgressIndicator(Gtk.Dialog): + def __init__(self, parent): + super().__init__(title="Upscaling", transient_for=parent, flags=0) + self.add_buttons(Gtk.STOCK_OK, Gtk.ResponseType.OK) + self.set_default_size(150, 100) + self.spinner = Gtk.Spinner() + self.label = Gtk.Label(label=" Upscaling. This process will take long (if a Video). \n Duration depends on your Hardware and length and resolution of video \n You may see the output of the app, if you switch to the other window that is behind it. ") + self.box = self.get_content_area() + self.box.pack_start(self.label, True, True, 20) + self.box.pack_start(self.spinner, True, True, 20) + self.spinner.start() + self.show_all() + + +class ErrorDialogFileMissing(Gtk.Dialog): + def __init__(self, parent): + super().__init__(title="Error", transient_for=parent, flags=0) + self.add_buttons(Gtk.STOCK_OK, Gtk.ResponseType.OK) + self.set_default_size(150, 100) + self.label = Gtk.Label(label=" No file specified. Please select a input AND output file! ") + self.box = self.get_content_area() + self.box.pack_start(self.label, True, True, 20) + self.show_all() + + +class ErrorDialogRunning(Gtk.Dialog): + def __init__(self, parent): + super().__init__(title="Error", transient_for=parent, flags=0) + self.add_buttons(Gtk.STOCK_OK, Gtk.ResponseType.OK) + self.set_default_size(150, 100) + self.label = Gtk.Label(label=" You are already upscaling. Please wait for the current job to finish! ") + self.box = self.get_content_area() + self.box.pack_start(self.label, True, True, 20) + self.show_all() + + +class ErrorDialogCheckFail(Gtk.Dialog): + def __init__(self, parent): + super().__init__(title="Error", transient_for=parent, flags=0) + self.add_buttons(Gtk.STOCK_OK, Gtk.ResponseType.OK) + self.set_default_size(150, 100) + self.label = Gtk.Label(label=" Filechecks failed. Make sure to specify the same file extension in the output like in the input ") + self.box = self.get_content_area() + self.box.pack_start(self.label, True, True, 20) + self.show_all() + + class HomeWindow(Gtk.Window): def __init__(self): super().__init__(title="Test") @@ -28,6 +79,9 @@ class HomeWindow(Gtk.Window): self.main_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) self.sub_box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL) self.box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL) + self.top_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) + self.quality_select_box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL) + self.custom_quality_selector_box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL) # Headerbar self.hb = Gtk.HeaderBar() @@ -50,15 +104,54 @@ class HomeWindow(Gtk.Window): self.start_button.connect("clicked", self.start_clicked) self.box.pack_start(self.start_button, True, True, 0) - # Title - self.title = Gtk.Label(label="Test") - self.title.set_text("FSR Image & Video Upscaler") + # QualitySelect + self.title = Gtk.Label(label="Upscaling Multiplier Presets") + self.qualities = Gtk.ListStore(str) + self.qualities.append(["2x"]) + self.qualities.append(["1.7x"]) + self.qualities.append(["1.5x"]) + self.qualities.append(["1.3x"]) + self.qualities.append(["Custom (will respect value below)"]) + self.quality_select = Gtk.ComboBox.new_with_model(self.qualities) + self.text_renderer = Gtk.CellRendererText() + self.quality_select.pack_start(self.text_renderer, True) + self.quality_select.add_attribute(self.text_renderer, "text", 0) + self.quality_select.connect("changed", self.on_quality_change) + self.quality_select_shrink = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) + self.quality_select_shrink.pack_start(self.quality_select, True, False, 30) + + self.quality_select_box.pack_start(self.title, True, True, 0) + self.quality_select_box.pack_start(self.quality_select_shrink, True, True, 20) + + # Custom Quality Selector + self.custom_quality_selector_title = Gtk.Label(label="Custom Upscaling Multiplier") + self.custom_quality_selector_shrink = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) + self.custom_quality_selector = Gtk.Entry() + self.custom_quality_selector_shrink.pack_start(self.custom_quality_selector, True, False, 30) + + self.custom_quality_selector_box.pack_start(self.custom_quality_selector_title, True, True, 0) + self.custom_quality_selector_box.pack_start(self.custom_quality_selector_shrink, True, True, 20) + + # Info + self.infos = Gtk.Label(label="Settings") + + # Packing boxes + self.top_box.pack_start(self.infos, True, True, 0) + self.top_box.pack_start(self.quality_select_box, True, True, 0) + self.top_box.pack_start(self.custom_quality_selector_box, True, True, 0) self.sub_box.pack_start(self.box, True, True, 30) - self.main_box.pack_start(self.title, True, True, 0) + self.main_box.pack_start(self.top_box, True, True, 20) self.main_box.pack_end(self.sub_box, True, True, 20) self.add(self.main_box) + def on_quality_change(self, quality): + # get data from quality changer + self.tree_iter = quality.get_active_iter() + if self.tree_iter is not None: + self.model = quality.get_model() + self.output = self.model[self.tree_iter][0] + def filechooser_clicked(self, widget): self.filechooserdialog = Gtk.FileChooserDialog(title="Choose input file", action=Gtk.FileChooserAction.OPEN) self.filechooserdialog.add_buttons( @@ -94,22 +187,64 @@ class HomeWindow(Gtk.Window): self.filechooserdialog_save.destroy() def start_clicked(self, widget): - if str(self.open_file) != "" and str(self.save_file) != "": - print("ok") - self.go = True - if self.go: - self.scaler = multiprocessing.Process(name="scaler", - target=handler.handler, - args=("./bin/lib/FidelityFX_CLI.exe", - self.open_file, - "default", - "Quality", - self.save_file, - "./bin/lib/ffmpeg.exe") - ) - self.scaler.start() + self.respawn = True + try: + if self.scaler.is_alive(): + self.respawn = False + else: + self.respawn = True + + except AttributeError: + self.respawn = True + + if self.respawn: + if str(self.open_file) != "" and str(self.save_file) != "": + print("ok") + if checks.perform(self.output, self.custom_quality_selector.get_text(), self.open_file, self.save_file): + if self.output == "Custom (will respect value below)": + self.quality_selected = "custom" + self.q = f"{self.custom_quality_selector.get_text()} {self.custom_quality_selector.get_text()}" + else: + self.quality_selected = "default" + self.q = str(arg.get(self.output)) + self.go = True + if self.go: + self.pr_i = ProgressIndicator(self) + self.pr_i.run() + self.pr_i.destroy() + self.scaler = multiprocessing.Process(name="scaler", + target=handler.handler, + args=("./bin/lib/FidelityFX_CLI.exe", + self.open_file, + self.quality_selected, + self.q, + self.save_file, + "./bin/lib/ffmpeg.exe") + ) + self.scaler.start() + else: + print("File-checks unsuccessful. Please check your entries!") + self.checkerror() + else: + print("no file specified") + self.fileerror() else: - print("no file specified") + print("Already running!") + + def runningerror(self): + self.runningerrordialog = ErrorDialogRunning(self) + self.runningerrordialog.run() + self.runningerrordialog.destroy() + + def fileerror(self): + self.fileerrordialog = ErrorDialogFileMissing(self) + self.fileerrordialog.run() + self.fileerrordialog.destroy() + + def checkerror(self): + self.checkerrordialog = ErrorDialogCheckFail(self) + self.checkerrordialog.run() + self.checkerrordialog.destroy() win = HomeWindow()