From e9f9521924a24010b4409fd4936d80b11b1c5aee Mon Sep 17 00:00:00 2001 From: Brett Date: Mon, 20 Nov 2023 21:58:31 -0600 Subject: [PATCH] Report Engine Download Status in UI (#64) * Report downloads in status bar * Update engine_browser.py UI with any active downloads --- src/engines/engine_manager.py | 35 ++++++++++++++++++++++++----------- src/ui/engine_browser.py | 20 +++++++++++++++++--- src/ui/widgets/statusbar.py | 21 ++++++++++++++------- 3 files changed, 55 insertions(+), 21 deletions(-) diff --git a/src/engines/engine_manager.py b/src/engines/engine_manager.py index 1f91072..7f56bff 100644 --- a/src/engines/engine_manager.py +++ b/src/engines/engine_manager.py @@ -129,15 +129,6 @@ class EngineManager: @classmethod def download_engine(cls, engine, version, system_os=None, cpu=None, background=False): - def download_engine_task(engine, version, system_os=None, cpu=None): - existing_download = cls.is_version_downloaded(engine, version, system_os, cpu) - if existing_download: - logger.info(f"Requested download of {engine} {version}, but local copy already exists") - return existing_download - - # Get the appropriate downloader class based on the engine type - cls.engine_with_name(engine).downloader().download_engine(version, download_location=cls.engines_path, - system_os=system_os, cpu=cpu, timeout=300) engine_to_download = cls.engine_with_name(engine) existing_task = cls.is_already_downloading(engine, version, system_os, cpu) @@ -152,8 +143,7 @@ class EngineManager: elif not cls.engines_path: raise FileNotFoundError("Engines path must be set before requesting downloads") - thread = threading.Thread(target=download_engine_task, args=(engine, version, system_os, cpu), - name=f'{engine}-{version}-{system_os}-{cpu}') + thread = EngineDownloadWorker(engine, version, system_os, cpu) cls.download_tasks.append(thread) thread.start() @@ -251,6 +241,29 @@ class EngineManager: return undefined_renderer_support[0] +class EngineDownloadWorker(threading.Thread): + def __init__(self, engine, version, system_os=None, cpu=None): + super().__init__() + self.engine = engine + self.version = version + self.system_os = system_os + self.cpu = cpu + + def run(self): + existing_download = EngineManager.is_version_downloaded(self.engine, self.version, self.system_os, self.cpu) + if existing_download: + logger.info(f"Requested download of {self.engine} {self.version}, but local copy already exists") + return existing_download + + # Get the appropriate downloader class based on the engine type + EngineManager.engine_with_name(self.engine).downloader().download_engine( + self.version, download_location=EngineManager.engines_path, system_os=self.system_os, cpu=self.cpu, + timeout=300) + + # remove itself from the downloader list + EngineManager.download_tasks.remove(self) + + if __name__ == '__main__': logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s') diff --git a/src/ui/engine_browser.py b/src/ui/engine_browser.py index 0b169f2..85c5df9 100644 --- a/src/ui/engine_browser.py +++ b/src/ui/engine_browser.py @@ -4,6 +4,7 @@ import subprocess import sys import threading +from PyQt6.QtCore import QTimer from PyQt6.QtWidgets import ( QMainWindow, QWidget, QVBoxLayout, QPushButton, QTableWidget, QTableWidgetItem, QHBoxLayout, QAbstractItemView, QHeaderView, QProgressBar, QLabel, QMessageBox @@ -28,6 +29,7 @@ class EngineBrowserWindow(QMainWindow): self.setGeometry(100, 100, 500, 300) self.engine_data = [] self.initUI() + self.init_timer() def initUI(self): # Central widget @@ -82,6 +84,12 @@ class EngineBrowserWindow(QMainWindow): self.update_download_status() + def init_timer(self): + # Set up the timer + self.timer = QTimer(self) + self.timer.timeout.connect(self.update_download_status) + self.timer.start(1000) + def update_table(self): def update_table_worker(): @@ -124,9 +132,15 @@ class EngineBrowserWindow(QMainWindow): hide_progress = not bool(running_tasks) self.progress_bar.setHidden(hide_progress) self.progress_label.setHidden(hide_progress) - - # todo: update progress bar with status - self.progress_label.setText(f"Downloading {len(running_tasks)} engines") + # Update the status labels + if len(EngineManager.download_tasks) == 0: + new_status = "" + elif len(EngineManager.download_tasks) == 1: + task = EngineManager.download_tasks[0] + new_status = f"Downloading {task.engine.capitalize()} {task.version}..." + else: + new_status = f"Downloading {len(EngineManager.download_tasks)} engines..." + self.progress_label.setText(new_status) def launch_button_click(self): engine_info = self.engine_data[self.table_widget.currentRow()] diff --git a/src/ui/widgets/statusbar.py b/src/ui/widgets/statusbar.py index 6561f6e..46a50b0 100644 --- a/src/ui/widgets/statusbar.py +++ b/src/ui/widgets/statusbar.py @@ -9,6 +9,7 @@ from PyQt6.QtGui import QPixmap from PyQt6.QtWidgets import QStatusBar, QLabel from src.api.server_proxy import RenderServerProxy +from src.engines.engine_manager import EngineManager from src.utilities.misc_helper import resources_dir @@ -28,17 +29,23 @@ class StatusBar(QStatusBar): proxy = RenderServerProxy(socket.gethostname()) proxy.start_background_update() image_names = {'Ready': 'GreenCircle.png', 'Offline': "RedSquare.png"} - last_update = None # Check for status change every 1s on background thread while True: new_status = proxy.status() - if new_status is not last_update: - new_image_name = image_names.get(new_status, 'Synchronize.png') - image_path = os.path.join(resources_dir(), 'icons', new_image_name) - self.label.setPixmap((QPixmap(image_path).scaled(16, 16, Qt.AspectRatioMode.KeepAspectRatio))) - self.messageLabel.setText(new_status) - last_update = new_status + new_image_name = image_names.get(new_status, 'Synchronize.png') + image_path = os.path.join(resources_dir(), 'icons', new_image_name) + self.label.setPixmap((QPixmap(image_path).scaled(16, 16, Qt.AspectRatioMode.KeepAspectRatio))) + + # add download status + if EngineManager.download_tasks: + if len(EngineManager.download_tasks) == 1: + task = EngineManager.download_tasks[0] + new_status = f"{new_status} | Downloading {task.engine.capitalize()} {task.version}..." + else: + new_status = f"{new_status} | Downloading {len(EngineManager.download_tasks)} engines" + + self.messageLabel.setText(new_status) time.sleep(1) background_thread = threading.Thread(target=background_update,)