From 033307cfc95accf3e15aaed26d2e9b3f3a538c2f Mon Sep 17 00:00:00 2001 From: Fabian Dill Date: Wed, 11 Nov 2020 13:45:21 +0100 Subject: [PATCH] Allow just updating sprites and remove old alternate sprite folder --- Gui.py | 209 ++++++++++++++++++++++++++-------------------------- GuiUtils.py | 8 +- Utils.py | 2 +- 3 files changed, 111 insertions(+), 108 deletions(-) diff --git a/Gui.py b/Gui.py index 369ce38a..3aeafead 100755 --- a/Gui.py +++ b/Gui.py @@ -1495,7 +1495,8 @@ def guiMain(args=None): mainWindow.mainloop() -class SpriteSelector(object): + +class SpriteSelector(): def __init__(self, parent, callback, adjuster=False): if is_bundled(): self.deploy_icons() @@ -1618,93 +1619,15 @@ class SpriteSelector(object): self.window.destroy() self.parent.update() - def work(task): - resultmessage = "" - successful = True - - def finished(): - task.close_window() - if successful: - messagebox.showinfo("Sprite Updater", resultmessage) - else: - messagebox.showerror("Sprite Updater", resultmessage) - SpriteSelector(self.parent, self.callback, self.adjuster) - - try: - task.update_status("Downloading alttpr sprites list") - with urlopen('https://alttpr.com/sprites') as response: - sprites_arr = json.loads(response.read().decode("utf-8")) - except Exception as e: - resultmessage = "Error getting list of alttpr sprites. Sprites not updated.\n\n%s: %s" % (type(e).__name__, e) - successful = False - task.queue_event(finished) - return - - try: - task.update_status("Determining needed sprites") - current_sprites = [os.path.basename(file) for file in glob(self.alttpr_sprite_dir + '/*')] - alttpr_sprites = [(sprite['file'], os.path.basename(urlparse(sprite['file']).path)) for sprite in sprites_arr] - needed_sprites = [(sprite_url, filename) for (sprite_url, filename) in alttpr_sprites if filename not in current_sprites] - - alttpr_filenames = [filename for (_, filename) in alttpr_sprites] - obsolete_sprites = [sprite for sprite in current_sprites if sprite not in alttpr_filenames] - except Exception as e: - resultmessage = "Error Determining which sprites to update. Sprites not updated.\n\n%s: %s" % (type(e).__name__, e) - successful = False - task.queue_event(finished) - return - - - def dl(sprite_url, filename): - target = os.path.join(self.alttpr_sprite_dir, filename) - with urlopen(sprite_url) as response, open(target, 'wb') as out: - shutil.copyfileobj(response, out) - - def rem(sprite): - os.remove(os.path.join(self.alttpr_sprite_dir, sprite)) - - - with ThreadPoolExecutor() as pool: - dl_tasks = [] - rem_tasks = [] - - for (sprite_url, filename) in needed_sprites: - dl_tasks.append(pool.submit(dl, sprite_url, filename)) - - for sprite in obsolete_sprites: - rem_tasks.append(pool.submit(rem, sprite)) - - deleted = 0 - updated = 0 - - for dl_task in as_completed(dl_tasks): - updated += 1 - task.update_status("Downloading needed sprite %g/%g" % (updated, len(needed_sprites))) - try: - dl_task.result() - except Exception as e: - logging.exception(e) - resultmessage = "Error downloading sprite. Not all sprites updated.\n\n%s: %s" % ( - type(e).__name__, e) - successful = False - - for rem_task in as_completed(rem_tasks): - deleted += 1 - task.update_status("Removing obsolete sprite %g/%g" % (deleted, len(obsolete_sprites))) - try: - rem_task.result() - except Exception as e: - logging.exception(e) - resultmessage = "Error removing obsolete sprite. Not all sprites updated.\n\n%s: %s" % ( - type(e).__name__, e) - successful = False - + def on_finish(successful, resultmessage): if successful: - resultmessage = "alttpr sprites updated successfully" + messagebox.showinfo("Sprite Updater", resultmessage) + else: + logging.error(resultmessage) + messagebox.showerror("Sprite Updater", resultmessage) + SpriteSelector(self.parent, self.callback, self.adjuster) - task.queue_event(finished) - - BackgroundTaskProgress(self.parent, work, "Updating Sprites") + BackgroundTaskProgress(self.parent, update_sprites, "Updating Sprites", on_finish) def browse_for_sprite(self): @@ -1748,34 +1671,103 @@ class SpriteSelector(object): self.callback(spritename) self.window.destroy() - def deploy_icons(self): if not os.path.exists(self.custom_sprite_dir): os.makedirs(self.custom_sprite_dir) - if not os.path.exists(self.alttpr_sprite_dir): - shutil.copytree(self.local_alttpr_sprite_dir, self.alttpr_sprite_dir) @property def alttpr_sprite_dir(self): - if is_bundled(): - return output_path("sprites", "alttpr") - return self.local_alttpr_sprite_dir - - @property - def local_alttpr_sprite_dir(self): return local_path("data", "sprites", "alttpr") @property def custom_sprite_dir(self): - if is_bundled(): - return output_path("sprites", "custom") - return self.local_custom_sprite_dir - - @property - def local_custom_sprite_dir(self): return local_path("data", "sprites", "custom") +def update_sprites(task, on_finish=None): + resultmessage = "" + successful = True + sprite_dir = local_path("data", "sprites", "alttpr") + + def finished(): + task.close_window() + if on_finish: + on_finish(successful, resultmessage) + + try: + task.update_status("Downloading alttpr sprites list") + with urlopen('https://alttpr.com/sprites') as response: + sprites_arr = json.loads(response.read().decode("utf-8")) + except Exception as e: + resultmessage = "Error getting list of alttpr sprites. Sprites not updated.\n\n%s: %s" % (type(e).__name__, e) + successful = False + task.queue_event(finished) + return + + try: + task.update_status("Determining needed sprites") + current_sprites = [os.path.basename(file) for file in glob(sprite_dir + '/*')] + alttpr_sprites = [(sprite['file'], os.path.basename(urlparse(sprite['file']).path)) for sprite in sprites_arr] + needed_sprites = [(sprite_url, filename) for (sprite_url, filename) in alttpr_sprites if filename not in current_sprites] + + alttpr_filenames = [filename for (_, filename) in alttpr_sprites] + obsolete_sprites = [sprite for sprite in current_sprites if sprite not in alttpr_filenames] + except Exception as e: + resultmessage = "Error Determining which sprites to update. Sprites not updated.\n\n%s: %s" % (type(e).__name__, e) + successful = False + task.queue_event(finished) + return + + + def dl(sprite_url, filename): + target = os.path.join(sprite_dir, filename) + with urlopen(sprite_url) as response, open(target, 'wb') as out: + shutil.copyfileobj(response, out) + + def rem(sprite): + os.remove(os.path.join(sprite_dir, sprite)) + + + with ThreadPoolExecutor() as pool: + dl_tasks = [] + rem_tasks = [] + + for (sprite_url, filename) in needed_sprites: + dl_tasks.append(pool.submit(dl, sprite_url, filename)) + + for sprite in obsolete_sprites: + rem_tasks.append(pool.submit(rem, sprite)) + + deleted = 0 + updated = 0 + + for dl_task in as_completed(dl_tasks): + updated += 1 + task.update_status("Downloading needed sprite %g/%g" % (updated, len(needed_sprites))) + try: + dl_task.result() + except Exception as e: + logging.exception(e) + resultmessage = "Error downloading sprite. Not all sprites updated.\n\n%s: %s" % ( + type(e).__name__, e) + successful = False + + for rem_task in as_completed(rem_tasks): + deleted += 1 + task.update_status("Removing obsolete sprite %g/%g" % (deleted, len(obsolete_sprites))) + try: + rem_task.result() + except Exception as e: + logging.exception(e) + resultmessage = "Error removing obsolete sprite. Not all sprites updated.\n\n%s: %s" % ( + type(e).__name__, e) + successful = False + + if successful: + resultmessage = "alttpr sprites updated successfully" + + task.queue_event(finished) + def get_image_for_sprite(sprite, gif_only: bool = False): if not sprite.valid: return None @@ -1880,5 +1872,16 @@ def get_image_for_sprite(sprite, gif_only: bool = False): return image.zoom(2) if __name__ == '__main__': - logging.basicConfig(format='%(message)s', level=logging.INFO) - guiMain() + import sys + if "update_sprites" in sys.argv: + import threading + done = threading.Event() + top = Tk() + top.withdraw() + BackgroundTaskProgress(top, update_sprites, "Updating Sprites", lambda succesful, resultmessage: done.set()) + while not done.isSet(): + top.update() + print("Done updating sprites") + else: + logging.basicConfig(format='%(message)s', level=logging.INFO) + guiMain() diff --git a/GuiUtils.py b/GuiUtils.py index 0bebfda6..c0542076 100644 --- a/GuiUtils.py +++ b/GuiUtils.py @@ -14,12 +14,12 @@ def set_icon(window): # some which may be platform specific, or depend on if the TCL library was compiled without # multithreading support. Therefore I will assume it is not thread safe to avoid any possible problems class BackgroundTask(object): - def __init__(self, window, code_to_run): + def __init__(self, window, code_to_run, *args): self.window = window self.queue = queue.Queue() self.running = True self.process_queue() - self.task = threading.Thread(target=code_to_run, args=(self,)) + self.task = threading.Thread(target=code_to_run, args=(self, *args)) self.task.start() def stop(self): @@ -45,7 +45,7 @@ class BackgroundTask(object): self.window.after(100, self.process_queue) class BackgroundTaskProgress(BackgroundTask): - def __init__(self, parent, code_to_run, title): + def __init__(self, parent, code_to_run, title, *args): self.parent = parent self.window = tk.Toplevel(parent) self.window['padx'] = 5 @@ -65,7 +65,7 @@ class BackgroundTaskProgress(BackgroundTask): set_icon(self.window) self.window.focus() - super().__init__(self.window, code_to_run) + super().__init__(self.window, code_to_run, *args) #safe to call from worker thread def update_status(self, text): diff --git a/Utils.py b/Utils.py index 358776d8..5680abc6 100644 --- a/Utils.py +++ b/Utils.py @@ -6,7 +6,7 @@ def tuplize_version(version: str) -> typing.Tuple[int, ...]: return tuple(int(piece, 10) for piece in version.split(".")) -__version__ = "3.3.2" +__version__ = "3.3.3" _version_tuple = tuplize_version(__version__) import os