Download cover bundle through the transfer queue (fix QProgressDialog NameError)

This commit is contained in:
2026-09-14 12:47:13 -04:00
parent 76eb6a6ef4
commit 0110b50a07
2 changed files with 44 additions and 78 deletions
+17 -78
View File
@@ -2670,6 +2670,7 @@ class QueuePage(QWidget):
"umd-dump": "UMD dump", "umd-dump": "UMD dump",
"save-sync": "Save sync", "save-sync": "Save sync",
"nps-download": "NoPayStation", "nps-download": "NoPayStation",
"covers": "Covers bundle",
} }
def __init__(self, parent=None): def __init__(self, parent=None):
@@ -3809,35 +3810,6 @@ class LibraryWorker(QObject):
self.finished.emit() self.finished.emit()
class CoversBundleWorker(QObject):
"""Download + extract the offline cover bundle off the GUI thread."""
progress = Signal(int, int) # done bytes, total bytes (0 = unknown)
succeeded = Signal()
failed = Signal(str)
finished = Signal()
def __init__(self):
super().__init__()
self._cancel = threading.Event()
def cancel(self):
self._cancel.set()
def run(self):
try:
covers.download_covers_bundle(
progress_cb=lambda d, t: self.progress.emit(d, t),
cancel_event=self._cancel)
except InterruptedError:
pass
except Exception as exc: # noqa: BLE001
self.failed.emit(str(exc))
else:
self.succeeded.emit()
finally:
self.finished.emit()
class SaveSyncPlanWorker(QObject): class SaveSyncPlanWorker(QObject):
"""Compute the save-sync plan off the GUI thread (content hashing is I/O-heavy).""" """Compute the save-sync plan off the GUI thread (content hashing is I/O-heavy)."""
plan = Signal(list, bool) # plan, switch_to_queue plan = Signal(list, bool) # plan, switch_to_queue
@@ -5434,6 +5406,9 @@ class MainWindow(QMainWindow):
QTimer.singleShot(0, self._refresh_psp) QTimer.singleShot(0, self._refresh_psp)
if kind == "save-sync": if kind == "save-sync":
QTimer.singleShot(0, self._refresh_saves) QTimer.singleShot(0, self._refresh_saves)
if kind == "covers":
covers.clear_miss_cache()
QTimer.singleShot(0, self.load_library)
if kind == "ps1-convert": if kind == "ps1-convert":
QTimer.singleShot(0, self.ps1_page.refresh) QTimer.singleShot(0, self.ps1_page.refresh)
QTimer.singleShot(0, self.load_library) QTimer.singleShot(0, self.load_library)
@@ -5796,51 +5771,20 @@ class MainWindow(QMainWindow):
self._download_covers_bundle() self._download_covers_bundle()
def _download_covers_bundle(self): def _download_covers_bundle(self):
"""Download + extract the offline cover bundle with a progress dialog.""" """Queue the offline cover bundle download in the transfer queue."""
if self._closing or getattr(self, "_bundle_worker", None) is not None: if self._closing:
return return
prog = QProgressDialog("Downloading cover bundle…", "Cancel", 0, 0, self) for j in self.queue.jobs:
prog.setWindowTitle("Offline covers") if j.kind == "covers" and j.status in ("queued", "running", "cancelling"):
prog.setWindowModality(Qt.WindowModal) return # already queued or running
prog.setMinimumDuration(0) self.queue.enqueue(
prog.setAutoClose(False) transfers.CoversBundleSource(),
prog.setAutoReset(False) str(config.COVERS_DIR),
None,
result = {"ok": False, "err": ""} "Offline cover bundle",
thread = QThread(self) kind="covers",
worker = CoversBundleWorker() )
worker.moveToThread(thread) self.tabs.setCurrentWidget(self.queue_page)
thread.started.connect(worker.run)
worker.progress.connect(lambda d, t: self._on_bundle_progress(prog, d, t))
worker.succeeded.connect(lambda: result.update(ok=True))
worker.failed.connect(lambda e: result.update(err=str(e)))
prog.canceled.connect(worker.cancel)
worker.finished.connect(thread.quit)
thread.finished.connect(lambda: self._on_bundle_done(prog, result, worker, thread))
self._bundle_worker = worker
self._bundle_thread = thread
thread.start()
@staticmethod
def _on_bundle_progress(prog, done, total):
if total > 0:
prog.setRange(0, total)
prog.setValue(done)
prog.setLabelText(
f"Downloading cover bundle… {done / (1 << 20):.0f} / {total / (1 << 20):.0f} MB")
else:
prog.setRange(0, 0)
def _on_bundle_done(self, prog, result, worker, thread):
prog.close()
self._bundle_worker = None
self._bundle_thread = None
if result["ok"]:
QMessageBox.information(self, "Offline covers", "Cover bundle installed.")
covers.clear_miss_cache()
self.load_library()
elif result["err"]:
QMessageBox.warning(self, "Offline covers", f"Download failed:\n{result['err']}")
def closeEvent(self, event): def closeEvent(self, event):
self._closing = True self._closing = True
@@ -5850,11 +5794,6 @@ class MainWindow(QMainWindow):
self.worker.choose(None) self.worker.choose(None)
self.worker.cancel() self.worker.cancel()
self._thread_cleanup() self._thread_cleanup()
if getattr(self, "_bundle_worker", None) is not None:
self._bundle_worker.cancel()
if getattr(self, "_bundle_thread", None) is not None and _thread_running(self._bundle_thread):
self._bundle_thread.quit()
self._bundle_thread.wait()
self.cover_grid.shutdown() self.cover_grid.shutdown()
for t in self._meta_threads: for t in self._meta_threads:
if _thread_running(t): if _thread_running(t):
+27
View File
@@ -175,6 +175,33 @@ class Source:
raise NotImplementedError raise NotImplementedError
class CoversBundleSource:
"""Download the combined offline cover bundle (runs as a queue job)."""
label = "psppt-covers.zip"
def __init__(self, url=""):
self.url = url
def download(self, item, dest_dir, progress_cb=None, cancel_event=None):
from . import covers
def on_progress(done, total):
if progress_cb is None:
return
frac = (done / total) if total else 0.0
detail = (f"{done / (1 << 20):.0f} / {total / (1 << 20):.0f} MB"
if total else "")
progress_cb("Downloading", frac, detail)
try:
result = covers.download_covers_bundle(self.url,
progress_cb=on_progress,
cancel_event=cancel_event)
except InterruptedError:
raise TransferCancelled() from None
return str(result)
class FileCopySource(Source): class FileCopySource(Source):
"""Copy a single local file (library -> PSP or PSP -> library). """Copy a single local file (library -> PSP or PSP -> library).