From 2142dbad7ebec36b0233098f82a2b07a08b45f48 Mon Sep 17 00:00:00 2001 From: NinjaCheetah <58050615+NinjaCheetah@users.noreply.github.com> Date: Thu, 19 Dec 2024 20:16:15 -0500 Subject: [PATCH] Added error reporting to script downloads, errors do not stop scripts --- NUSGet.py | 74 +++++++++++++++++++++++++++++---------- modules/core.py | 9 +++++ modules/download_batch.py | 35 +++++++++++++----- 3 files changed, 90 insertions(+), 28 deletions(-) diff --git a/NUSGet.py b/NUSGet.py index ba24bea..76973df 100644 --- a/NUSGet.py +++ b/NUSGet.py @@ -203,7 +203,7 @@ class MainWindow(QMainWindow, Ui_MainWindow): self.log_text = f"{tid} - {selected_title.name}\nVersion: {selected_title.version}\n\n{danger_text}\n" self.ui.log_text_browser.setText(self.log_text) - def lock_ui_for_download(self): + def lock_ui(self): # Lock the UI prior to the download beginning to avoid spawning multiple threads or changing info part way in. # Also resets the log. self.ui.tid_entry.setEnabled(False) @@ -221,6 +221,21 @@ class MainWindow(QMainWindow, Ui_MainWindow): self.log_text = "" self.ui.log_text_browser.setText(self.log_text) + def unlock_ui(self): + # Unlock the UI again after the current download finishes. + self.ui.tid_entry.setEnabled(True) + self.ui.version_entry.setEnabled(True) + self.ui.download_btn.setEnabled(True) + self.ui.script_btn.setEnabled(True) + self.ui.pack_archive_chkbox.setEnabled(True) + self.ui.keep_enc_chkbox.setEnabled(True) + self.ui.create_dec_chkbox.setEnabled(True) + self.ui.use_local_chkbox.setEnabled(True) + self.ui.use_wiiu_nus_chkbox.setEnabled(True) + self.ui.console_select_dropdown.setEnabled(True) + if self.ui.pack_archive_chkbox.isChecked() is True: + self.ui.archive_file_entry.setEnabled(True) + def download_btn_pressed(self): # Throw an error and make a message box appear if you haven't selected any options to output the title. if (self.ui.pack_archive_chkbox.isChecked() is False and self.ui.keep_enc_chkbox.isChecked() is False and @@ -235,9 +250,7 @@ class MainWindow(QMainWindow, Ui_MainWindow): "like the download to be saved.")) msg_box.exec() return - - self.lock_ui_for_download() - + self.lock_ui() # Create a new worker object to handle the download in a new thread. if self.ui.console_select_dropdown.currentText() == "DSi": worker = Worker(run_nus_download_dsi, out_folder, self.ui.tid_entry.text(), @@ -294,23 +307,46 @@ class MainWindow(QMainWindow, Ui_MainWindow): msg_box.setText(title_text) msg_box.setInformativeText(body_text) msg_box.exec() - # Now that the thread has closed, unlock the UI to allow for the next download. - self.ui.tid_entry.setEnabled(True) - self.ui.version_entry.setEnabled(True) - self.ui.download_btn.setEnabled(True) - self.ui.script_btn.setEnabled(True) - self.ui.pack_archive_chkbox.setEnabled(True) - self.ui.keep_enc_chkbox.setEnabled(True) - self.ui.create_dec_chkbox.setEnabled(True) - self.ui.use_local_chkbox.setEnabled(True) - self.ui.use_wiiu_nus_chkbox.setEnabled(True) - self.ui.console_select_dropdown.setEnabled(True) - if self.ui.pack_archive_chkbox.isChecked() is True: - self.ui.archive_file_entry.setEnabled(True) + self.unlock_ui() # Call the dropdown callback because this will automagically handle setting console-specific settings based # on the currently selected console, and saves on duplicate code. self.selected_console_changed() + def check_batch_result(self, result: BatchResults): + if result.code != 0: + print(result.warning_titles) + print(result.failed_titles) + msg_box = QMessageBox() + if result.failed_titles: + msg_box.setIcon(QMessageBox.Icon.Critical) + else: + msg_box.setIcon(QMessageBox.Icon.Warning) + msg_box.setStandardButtons(QMessageBox.StandardButton.Ok) + msg_box.setDefaultButton(QMessageBox.StandardButton.Ok) + msg_box.setWindowTitle("Script Issues Occurred") + msg_box.setText("Some issues occurred while running the download script.") + msg_box.setInformativeText("Check the log for more details about what issues were encountered.") + msg_box.exec() + self.log_text = "" + if result.failed_titles: + self.update_log_text(app.translate("MainWindow", + "The following titles could not be downloaded due to an error. " + "Please ensure that the Title ID and version listed in the script " + "are valid.")) + for title in result.failed_titles: + self.update_log_text(f" - {title}") + if result.warning_titles: + if result.failed_titles: + self.update_log_text("") + self.update_log_text(app.translate("MainWindow", + "You enabled \"Create decrypted contents\" or \"Pack installable " + "archive\", but the following titles in the script do not have " + "tickets available. If enabled, encrypted contents were still " + "downloaded.")) + for title in result.warning_titles: + self.update_log_text(f" - {title}") + self.unlock_ui() + def pack_wad_chkbox_toggled(self): # Simple function to catch when the WAD/TAD checkbox is toggled and enable/disable the file name entry box # accordingly. @@ -397,12 +433,12 @@ class MainWindow(QMainWindow, Ui_MainWindow): archive_name = "" break titles.append(BatchTitleData(tid, title_version, console, archive_name)) - self.lock_ui_for_download() + self.lock_ui() worker = Worker(run_nus_download_batch, out_folder, titles, self.ui.pack_archive_chkbox.isChecked(), self.ui.keep_enc_chkbox.isChecked(), self.ui.create_dec_chkbox.isChecked(), self.ui.use_wiiu_nus_chkbox.isChecked(), self.ui.use_local_chkbox.isChecked(), self.ui.pack_vwii_mode_chkbox.isChecked(), self.ui.patch_ios_chkbox.isChecked()) - worker.signals.result.connect(self.check_download_result) + worker.signals.result.connect(self.check_batch_result) worker.signals.progress.connect(self.update_log_text) self.threadpool.start(worker) diff --git a/modules/core.py b/modules/core.py index e0123ce..6c0033a 100644 --- a/modules/core.py +++ b/modules/core.py @@ -3,6 +3,7 @@ import requests from dataclasses import dataclass +from typing import List @dataclass @@ -27,6 +28,14 @@ class BatchTitleData: archive_name: str +@dataclass +class BatchResults: + # Class to store the results of a batch download. + code: int + warning_titles: List[str] + failed_titles: List[str] + + def check_nusget_updates(app, current_version: str, progress_callback=None) -> str | None: # Simple function to make a request to the GitHub API and then check if the latest available version is newer. gh_api_request = requests.get(url="https://api.github.com/repos/NinjaCheetah/NUSGet/releases/latest", stream=True) diff --git a/modules/download_batch.py b/modules/download_batch.py index e2083be..d2c3cb9 100644 --- a/modules/download_batch.py +++ b/modules/download_batch.py @@ -3,7 +3,7 @@ import pathlib from typing import List -from modules.core import BatchTitleData +from modules.core import BatchTitleData, BatchResults from modules.download_dsi import run_nus_download_dsi from modules.download_wii import run_nus_download_wii @@ -11,7 +11,10 @@ from modules.download_wii import run_nus_download_wii def run_nus_download_batch(out_folder: pathlib.Path, titles: List[BatchTitleData], pack_wad_chkbox: bool, keep_enc_chkbox: bool, decrypt_contents_chkbox: bool, wiiu_nus_chkbox: bool, use_local_chkbox: bool, repack_vwii_chkbox: bool, patch_ios: bool, - progress_callback=None): + progress_callback=None) -> BatchResults: + result = 0 + warning_titles = [] + failed_titles = [] for title in titles: if title.version == -1: version_str = "Latest" @@ -22,19 +25,33 @@ def run_nus_download_batch(out_folder: pathlib.Path, titles: List[BatchTitleData archive_name = f"{title.archive_name}-v{version_str}-{title.console}.wad" else: archive_name = f"{title.tid}-v{version_str}-{title.console}.wad" - result = run_nus_download_wii(out_folder, title.tid, version_str, pack_wad_chkbox, keep_enc_chkbox, + code = run_nus_download_wii(out_folder, title.tid, version_str, pack_wad_chkbox, keep_enc_chkbox, decrypt_contents_chkbox, wiiu_nus_chkbox, use_local_chkbox, repack_vwii_chkbox, patch_ios, archive_name, progress_callback) - if result != 0: - return result + if code == 1: + # Code 1 means no ticket available, so mark that as a warning title. + result = 1 + warning_titles.append(title.tid) + elif code != 0: + # Any other non-zero return code means that an error occurred during the download, so mark that as a + # failed title. + result = 1 + failed_titles.append(title.tid) elif title.console == "DSi": if title.archive_name != "": archive_name = f"{title.archive_name}-v{version_str}-{title.console}.tad" else: archive_name = f"{title.tid}-v{version_str}-{title.console}.tad" - result = run_nus_download_dsi(out_folder, title.tid, version_str, pack_wad_chkbox, keep_enc_chkbox, + code = run_nus_download_dsi(out_folder, title.tid, version_str, pack_wad_chkbox, keep_enc_chkbox, decrypt_contents_chkbox, use_local_chkbox, archive_name, progress_callback) - if result != 0: - return result + if code == 1: + # Code 1 means no ticket available, so mark that as a warning title. + result = 1 + warning_titles.append(title.tid) + elif code != 0: + # Any other non-zero return code means that an error occurred during the download, so mark that as a + # failed title. + result = 1 + failed_titles.append(title.tid) progress_callback.emit(f"Batch download finished.") - return 0 + return BatchResults(result, warning_titles, failed_titles)