diff --git a/legendary/cli.py b/legendary/cli.py index 0703fab..cacfd71 100644 --- a/legendary/cli.py +++ b/legendary/cli.py @@ -627,8 +627,12 @@ class LegendaryCLI: if not args.install_tag and not game.is_dlc and ((sdl_name := get_sdl_appname(game.app_name)) is not None): config_tags = self.core.lgd.config.get(game.app_name, 'install_tags', fallback=None) if not self.core.is_installed(game.app_name) or config_tags is None or args.reset_sdl: - args.install_tag = sdl_prompt(sdl_name, game.app_title) - self.core.lgd.config.set(game.app_name, 'install_tags', ','.join(args.install_tag)) + sdl_data = self.core.get_sdl_data(sdl_name) + if sdl_data: + args.install_tag = sdl_prompt(sdl_data, game.app_title) + self.core.lgd.config.set(game.app_name, 'install_tags', ','.join(args.install_tag)) + else: + logger.error(f'Unable to get SDL data for {sdl_name}') else: args.install_tag = config_tags.split(',') elif args.install_tag and not game.is_dlc and not args.no_install: diff --git a/legendary/core.py b/legendary/core.py index c0263f7..4bdd46f 100644 --- a/legendary/core.py +++ b/legendary/core.py @@ -34,6 +34,7 @@ from legendary.models.chunk import Chunk from legendary.utils.env import is_windows_or_pyi from legendary.utils.game_workarounds import is_opt_enabled, update_workarounds from legendary.utils.savegame_helper import SaveGameHelper +from legendary.utils.selective_dl import games as sdl_games from legendary.utils.manifests import combine_manifests from legendary.utils.wine_helpers import read_registry, get_shell_folders @@ -239,12 +240,39 @@ class LegendaryCore: if 'egl_config' in version_info: self.egs.update_egs_params(version_info['egl_config']) self._egl_version = version_info['egl_config'].get('version', self._egl_version) - if 'game_overrides' in version_info: - update_workarounds(version_info['game_overrides']) + if game_overrides := version_info.get('game_overrides'): + update_workarounds(game_overrides) + if sdl_config := game_overrides.get('sdl_config'): + # add placeholder for games to fetch from API that aren't hardcoded + for app_name in sdl_config.keys(): + if app_name not in sdl_games: + sdl_games[app_name] = None def get_update_info(self): return self.lgd.get_cached_version()['data'].get('release_info') + def get_sdl_data(self, app_name): + if app_name not in sdl_games: + return None + # load hardcoded data as fallback + sdl_data = sdl_games[app_name] + # get cached data + cached = self.lgd.get_cached_sdl_data(app_name) + # check if newer version is available and/or download if necessary + version_info = self.lgd.get_cached_version()['data'] + latest = version_info.get('game_overrides', {}).get('sdl_config', {}).get(app_name) + if (not cached and latest) or (cached and latest and latest > cached['version']): + try: + sdl_data = self.lgdapi.get_sdl_config(app_name) + self.log.debug(f'Downloaded SDL data for "{app_name}", version: {latest}') + self.lgd.set_cached_sdl_data(app_name, latest, sdl_data) + except Exception as e: + self.log.warning(f'Downloading SDL data failed with {e!r}') + elif cached: + sdl_data = cached['data'] + # return data if available + return sdl_data + def get_assets(self, update_assets=False, platform_override=None) -> List[GameAsset]: # do not save and always fetch list when platform is overridden if platform_override: diff --git a/legendary/lfs/lgndry.py b/legendary/lfs/lgndry.py index 8e9cf99..d0401b3 100644 --- a/legendary/lfs/lgndry.py +++ b/legendary/lfs/lgndry.py @@ -315,3 +315,17 @@ class LGDLFS: self._update_info = dict(last_update=time(), data=version_data) json.dump(self._update_info, open(os.path.join(self.path, 'version.json'), 'w'), indent=2, sort_keys=True) + + def get_cached_sdl_data(self, app_name): + try: + return json.load(open(os.path.join(self.path, 'tmp', f'{app_name}.json'))) + except Exception as e: + self.log.debug(f'Failed to load cached update data: {e!r}') + return None + + def set_cached_sdl_data(self, app_name, sdl_version, sdl_data): + if not app_name or not sdl_data: + return + json.dump(dict(version=sdl_version, data=sdl_data), + open(os.path.join(self.path, 'tmp', f'{app_name}.json'), 'w'), + indent=2, sort_keys=True) diff --git a/legendary/utils/cli.py b/legendary/utils/cli.py index 2ee7fcd..8dfead5 100644 --- a/legendary/utils/cli.py +++ b/legendary/utils/cli.py @@ -1,6 +1,3 @@ -from legendary.utils.selective_dl import games - - def get_boolean_choice(prompt, default=True): if default: yn = 'Y/n' @@ -16,28 +13,28 @@ def get_boolean_choice(prompt, default=True): return False -def sdl_prompt(app_name, title): +def sdl_prompt(sdl_data, title): tags = [''] - if '__required' in games[app_name]: - tags.extend(games[app_name]['__required']['tags']) + if '__required' in sdl_data: + tags.extend(sdl_data['__required']['tags']) print(f'You are about to install {title}, this game supports selective downloads.') print('The following optional packs are available:') - for tag, info in games[app_name].items(): + for tag, info in sdl_data.items(): if tag == '__required': continue print(' *', tag, '-', info['name']) print('Please enter a comma-separated list of optional packs to install (leave blank for defaults)') - examples = ','.join([g for g in games[app_name].keys() if g != '__required'][:2]) + examples = ','.join([g for g in sdl_data.keys() if g != '__required'][:2]) choices = input(f'Additional packs [e.g. {examples}]: ') if not choices: return tags for c in choices.split(','): c = c.strip() - if c in games[app_name]: - tags.extend(games[app_name][c]['tags']) + if c in sdl_data: + tags.extend(sdl_data[c]['tags']) else: print('Invalid tag:', c)