diff --git a/lutris/gui/views/store.py b/lutris/gui/views/store.py index 1e226a8f9..480baf2d9 100644 --- a/lutris/gui/views/store.py +++ b/lutris/gui/views/store.py @@ -1,9 +1,10 @@ """Store object for a list of games""" +import concurrent.futures from gi.repository import Gtk, GObject, GLib from gi.repository.GdkPixbuf import Pixbuf from lutris import pga from lutris.gui.widgets.utils import get_pixbuf_for_game -from lutris.util.resources import get_icon_path, download_media +from lutris.util.resources import get_icon_path, download_media, update_desktop_icons from lutris.util.log import logger from lutris.util import system from lutris import api @@ -285,8 +286,39 @@ class GameStore(GObject.Object): self.emit("icon-loaded", slug, media_type) def on_media_loaded(self, response): - for slug in self.games_to_refresh: - self.refresh_icon(slug) + """Callback to handle a response from the API with the new media""" + if not self.medias: + return + for media_type in ("banner", "icon"): + self.download_icons([ + (slug, self.medias[media_type][slug], get_icon_path(slug, media_type)) + for slug in self.medias[media_type] + ], media_type) + + def download_icons(self, downloads, media_type): + """Download a list of media files concurrently. + + Limits the number of simultaneous downloads to avoid API throttling + and UI being overloaded with signals. + """ + if not downloads: + return + + with concurrent.futures.ThreadPoolExecutor(max_workers=8) as executor: + future_downloads = { + executor.submit(download_media, url, dest_path): slug + for slug, url, dest_path in downloads + } + for future in concurrent.futures.as_completed(future_downloads): + slug = future_downloads[future] + try: + future.result() + except Exception as ex: # pylint: disable=broad-except + logger.exception('%r failed: %s', slug, ex) + else: + self.emit("icon-loaded", slug, media_type) + if media_type == "icon": + update_desktop_icons() def add_games_by_ids(self, game_ids): self.add_games(pga.get_games_by_ids(game_ids)) diff --git a/lutris/util/resources.py b/lutris/util/resources.py index 56df8ee61..a99863b40 100644 --- a/lutris/util/resources.py +++ b/lutris/util/resources.py @@ -1,11 +1,9 @@ """Utility module to handle media resources""" import os -import concurrent.futures from gi.repository import GLib from lutris import settings from lutris.util.http import Request -from lutris.util.log import logger from lutris.util import system @@ -14,7 +12,7 @@ ICON = "icon" def get_icon_path(game_slug, icon_type=ICON): - """Return the absolute path for a game_slug icon/banner""" + """Return the absolute path for a game_slug icon""" if icon_type == BANNER: return os.path.join(settings.BANNER_PATH, "%s.jpg" % game_slug) if icon_type == ICON: @@ -23,42 +21,14 @@ def get_icon_path(game_slug, icon_type=ICON): def get_banner_path(game_slug): + """Return the absolute path for a game_slug banner""" return get_icon_path(game_slug, BANNER) -def fetch_icons(lutris_media, callback): - """Download missing icons from lutris.net""" - if not lutris_media: - return - - available_banners, available_icons = lutris_media - downloads = [ - (slug, available_banners[slug], get_icon_path(slug, BANNER)) - for slug in available_banners - ] + [ - (slug, available_icons[slug], get_icon_path(slug, ICON)) - for slug in available_icons - ] - with concurrent.futures.ThreadPoolExecutor(max_workers=16) as executor: - future_downloads = { - executor.submit(download_media, url, dest_path): slug - for slug, url, dest_path in downloads - } - for future in concurrent.futures.as_completed(future_downloads): - slug = future_downloads[future] - try: - future.result() - except Exception as ex: # pylint: disable=broad-except - logger.exception('%r generated an exception: %s', slug, ex) - else: - GLib.idle_add(callback, slug, priority=GLib.PRIORITY_LOW) - - if bool(available_icons): - update_desktop_icons() - - def update_desktop_icons(): - """Update Icon for GTK+ desktop manager""" + """Update Icon for GTK+ desktop manager + Other desktop manager icon cache commands must be added here if needed + """ gtk_update_icon_cache = system.find_executable("gtk-update-icon-cache") if gtk_update_icon_cache: os.system( @@ -66,8 +36,6 @@ def update_desktop_icons(): % os.path.join(GLib.get_user_data_dir(), "icons", "hicolor") ) - # Other desktop manager cache command must be added here when needed - def download_media(url, dest, overwrite=False): """Save a remote media locally"""