From 730eaebec9708630cc9919d2529893e5974e11e7 Mon Sep 17 00:00:00 2001 From: derrod Date: Sat, 16 May 2020 12:50:28 +0200 Subject: [PATCH] [cli/core/models] Fix a whole bunch of cloud save issues - Games that didn't already have cloud saves weren't synced - Games that didn't have local saves didn't behave correctly - Games that only had local saves also didn't work correctly --- legendary/cli.py | 30 +++++++++++++++++++----------- legendary/core.py | 13 +++++++++++-- legendary/models/game.py | 8 +++++--- 3 files changed, 35 insertions(+), 16 deletions(-) diff --git a/legendary/cli.py b/legendary/cli.py index acd669b..920e93b 100644 --- a/legendary/cli.py +++ b/legendary/cli.py @@ -251,15 +251,14 @@ class LegendaryCLI: # evaluate current save state for each game. for igame in igames: - if igame.app_name not in latest_save: - continue - game = self.core.get_game(igame.app_name) if 'CloudSaveFolder' not in game.metadata['customAttributes']: - # this should never happen unless cloud save support was removed from a game - logger.warning(f'{igame.app_name} has remote save(s) but does not support cloud saves?!') + if igame.app_name in latest_save: + # this should never happen unless cloud save support was removed from a game + logger.warning(f'{igame.app_name} has remote save(s) but does not support cloud saves?!') continue + logger.info(f'Checking "{igame.title}" ({igame.app_name})') # override save path only if app name is specified if args.app_name and args.save_path: logger.info(f'Overriding save path with "{args.save_path}"...') @@ -290,8 +289,11 @@ class LegendaryCLI: igame.save_path = save_path self.core.lgd.set_installed_game(igame.app_name, igame) - # check if *any* file in the save game directory is newer than the latest uploaded save - res, (dt_l, dt_r) = self.core.check_savegame_state(igame.save_path, latest_save[igame.app_name]) + res, (dt_l, dt_r) = self.core.check_savegame_state(igame.save_path, latest_save.get(igame.app_name)) + + if res == SaveGameStatus.NO_SAVE: + logger.info('No cloud or local savegame found.') + continue if res == SaveGameStatus.SAME_AGE and not (args.force_upload or args.force_download): logger.info(f'Save game for "{igame.title}" is up to date, skipping...') @@ -300,8 +302,11 @@ class LegendaryCLI: if (res == SaveGameStatus.REMOTE_NEWER and not args.force_upload) or args.force_download: if res == SaveGameStatus.REMOTE_NEWER: # only print this info if not forced logger.info(f'Cloud save for "{igame.title}" is newer:') - logger.info(f'- Cloud save date: {dt_l.strftime("%Y-%m-%d %H:%M:%S")}') - logger.info(f'- Local save date: {dt_r.strftime("%Y-%m-%d %H:%M:%S")}') + logger.info(f'- Cloud save date: {dt_r.strftime("%Y-%m-%d %H:%M:%S")}') + if dt_l: + logger.info(f'- Local save date: {dt_l.strftime("%Y-%m-%d %H:%M:%S")}') + else: + logger.info('- Local save date: N/A') if args.upload_only: logger.info('Save game downloading is disabled, skipping...') @@ -319,8 +324,11 @@ class LegendaryCLI: elif res == SaveGameStatus.LOCAL_NEWER or args.force_upload: if res == SaveGameStatus.LOCAL_NEWER: logger.info(f'Local save for "{igame.title}" is newer') - logger.info(f'- Cloud save date: {dt_l.strftime("%Y-%m-%d %H:%M:%S")}') - logger.info(f'- Local save date: {dt_r.strftime("%Y-%m-%d %H:%M:%S")}') + if dt_r: + logger.info(f'- Cloud save date: {dt_r.strftime("%Y-%m-%d %H:%M:%S")}') + else: + logger.info('- Cloud save date: N/A') + logger.info(f'- Local save date: {dt_l.strftime("%Y-%m-%d %H:%M:%S")}') if args.download_only: logger.info('Save game uploading is disabled, skipping...') diff --git a/legendary/core.py b/legendary/core.py index c7f0b04..51c84b6 100644 --- a/legendary/core.py +++ b/legendary/core.py @@ -325,9 +325,18 @@ class LegendaryCore: s = os.stat(os.path.join(_dir, _file)) latest = max(latest, s.st_mtime) + if not latest and not save: + return SaveGameStatus.NO_SAVE, (None, None) + # timezones are fun! dt_local = datetime.fromtimestamp(latest).replace(tzinfo=self.local_timezone).astimezone(timezone.utc) + if not save: + return SaveGameStatus.LOCAL_NEWER, (dt_local, None) + dt_remote = datetime.strptime(save.manifest_name, '%Y.%m.%d-%H.%M.%S.manifest').replace(tzinfo=timezone.utc) + if not latest: + return SaveGameStatus.REMOTE_NEWER, (None, dt_remote) + self.log.debug(f'Local save date: {str(dt_local)}, Remote save date: {str(dt_remote)}') # Ideally we check the files themselves based on manifest, @@ -348,9 +357,9 @@ class LegendaryCore: include_f = exclude_f = None if not disable_filtering: # get file inclusion and exclusion filters if they exist - if _include := custom_attr.get('CloudIncludeList', {}).get('value', None) is not None: + if (_include := custom_attr.get('CloudIncludeList', {}).get('value', None)) is not None: include_f = _include.split(',') - if _exclude := custom_attr.get('CloudExcludeList', {}).get('value', None) is not None: + if (_exclude := custom_attr.get('CloudExcludeList', {}).get('value', None)) is not None: exclude_f = _exclude.split(',') if not save_path: diff --git a/legendary/models/game.py b/legendary/models/game.py index 3b19c10..43852ad 100644 --- a/legendary/models/game.py +++ b/legendary/models/game.py @@ -124,6 +124,8 @@ class SaveGameFile: class SaveGameStatus(Enum): - LOCAL_NEWER = 1 - REMOTE_NEWER = -1 - SAME_AGE = 0 + LOCAL_NEWER = 0 + REMOTE_NEWER = 1 + SAME_AGE = 2 + NO_SAVE = 3 +