From 1f385df69310978f282791fd90063d4fc89ed89b Mon Sep 17 00:00:00 2001 From: DavidoTek <54072917+DavidoTek@users.noreply.github.com> Date: Fri, 20 Sep 2024 08:20:30 +0200 Subject: [PATCH] Add vdf_safe_load function (#455) * steamutil: Implement vdf_safe_load * Replace vdf.load(...) with vdf_safe_load(...) --- pupgui2/datastructures.py | 4 ++- pupgui2/steamutil.py | 60 +++++++++++++++++++++++++-------------- 2 files changed, 42 insertions(+), 22 deletions(-) diff --git a/pupgui2/datastructures.py b/pupgui2/datastructures.py index 089b788e..87220f7f 100644 --- a/pupgui2/datastructures.py +++ b/pupgui2/datastructures.py @@ -150,7 +150,9 @@ def get_internal_name(self) -> str: """ compat_tool_vdf_path = os.path.join(self.install_dir, self.install_folder, 'compatibilitytool.vdf') if os.path.exists(compat_tool_vdf_path): - compat_tool_vdf = vdf.load(open(compat_tool_vdf_path)) + # TODO: Move this somewhere else and use steamutil.py#vdf_safe_load + with open(compat_tool_vdf_path, 'r', encoding='utf-8', errors='replace') as f: + compat_tool_vdf = vdf.loads(f.read()) if 'compatibilitytools' in compat_tool_vdf and 'compat_tools' in compat_tool_vdf['compatibilitytools']: return list(compat_tool_vdf['compatibilitytools']['compat_tools'].keys())[0] diff --git a/pupgui2/steamutil.py b/pupgui2/steamutil.py index ad8c4361..7d1db8d1 100644 --- a/pupgui2/steamutil.py +++ b/pupgui2/steamutil.py @@ -58,8 +58,8 @@ def get_steam_app_list(steam_config_folder: str, cached=False, no_shortcuts=Fals apps = [] try: - v = vdf.load(open(libraryfolders_vdf_file)) - c = get_steam_vdf_compat_tool_mapping(vdf.load(open(config_vdf_file))) + v = vdf_safe_load(libraryfolders_vdf_file) + c = get_steam_vdf_compat_tool_mapping(vdf_safe_load(config_vdf_file)) for fid in v.get('libraryfolders'): if 'apps' not in v.get('libraryfolders').get(fid): @@ -73,7 +73,7 @@ def get_steam_app_list(steam_config_folder: str, cached=False, no_shortcuts=Fals fid_steamapps_path = os.path.join(fid_libraryfolder_path, 'steamapps') # e.g. /home/gaben/Games/steamapps appmanifest_path = os.path.join(fid_steamapps_path, f'appmanifest_{appid}.acf') if os.path.isfile(appmanifest_path): - appmanifest_install_path = vdf.load(open(appmanifest_path)).get('AppState', {}).get('installdir', None) + appmanifest_install_path = vdf_safe_load(appmanifest_path).get('AppState', {}).get('installdir', None) if not appmanifest_install_path or not os.path.isdir(os.path.join(fid_steamapps_path, 'common', appmanifest_install_path)): continue @@ -111,7 +111,7 @@ def get_steam_shortcuts_list(steam_config_folder: str, compat_tools: dict=None) try: if not compat_tools: - compat_tools = get_steam_vdf_compat_tool_mapping(vdf.load(open(config_vdf_file))) + compat_tools = get_steam_vdf_compat_tool_mapping(vdf_safe_load(config_vdf_file)) for userf in os.listdir(users_folder): user_directory = os.path.join(users_folder, userf) @@ -218,7 +218,7 @@ def get_steam_global_ctool_name(steam_config_folder: str) -> str: """ config_vdf_file = os.path.join(os.path.expanduser(steam_config_folder), 'config.vdf') - d = get_steam_vdf_compat_tool_mapping(vdf.load(open(config_vdf_file))) + d = get_steam_vdf_compat_tool_mapping(vdf_safe_load(config_vdf_file)) return d.get('0', {}).get('name', '') @@ -388,7 +388,7 @@ def steam_update_ctool(game: SteamApp, new_ctool=None, steam_config_folder='') - game_id = game.app_id try: - d = vdf.load(open(config_vdf_file)) + d = vdf_safe_load(config_vdf_file) c = get_steam_vdf_compat_tool_mapping(d) if str(game_id) in c: @@ -417,7 +417,7 @@ def steam_update_ctools(games: Dict[SteamApp, str], steam_config_folder='') -> b return False try: - d = vdf.load(open(config_vdf_file)) + d = vdf_safe_load(config_vdf_file) c = get_steam_vdf_compat_tool_mapping(d) for game, new_ctool in games.items(): @@ -751,20 +751,19 @@ def get_steam_user_list(steam_config_folder: str) -> List[SteamUser]: return [] try: - with open(loginusers_vdf_file) as f: - d = vdf.load(f) - u = d.get('users', {}) - for uid in list(u.keys()): - uvalue = u.get(uid, {}) - - user = SteamUser() - user.long_id = int(uid) - user.account_name = uvalue.get('AccountName', '') - user.persona_name = uvalue.get('PersonaName', '') - user.most_recent = bool(int(uvalue.get('MostRecent', '0'))) - user.timestamp = int(uvalue.get('Timestamp', '-1')) - - users.append(user) + d = vdf_safe_load(loginusers_vdf_file) + u = d.get('users', {}) + for uid in list(u.keys()): + uvalue = u.get(uid, {}) + + user = SteamUser() + user.long_id = int(uid) + user.account_name = uvalue.get('AccountName', '') + user.persona_name = uvalue.get('PersonaName', '') + user.most_recent = bool(int(uvalue.get('MostRecent', '0'))) + user.timestamp = int(uvalue.get('Timestamp', '-1')) + + users.append(user) except Exception as e: print('Error: Could not get a list of Steam users:', e) @@ -809,3 +808,22 @@ def is_valid_steam_install(steam_path) -> bool: is_valid_steam_install = os.path.exists(config_vdf) and os.path.exists(libraryfolders_vdf) return is_valid_steam_install + +def vdf_safe_load(vdf_file: str) -> dict: + """ + Loads a vdf file and returns its contents as a dict. + In case of an error, the error is printed and {} is returned. + + Args: + vdf_file (str): Path to the vdf file + + Returns: + dict + """ + + try: + # See https://github.com/DavidoTek/ProtonUp-Qt/issues/424 (unicode errors) + with open(vdf_file, 'r', encoding='utf-8', errors='replace') as f: + return vdf.loads(f.read()) + except Exception as e: + print(f'An error occured while calling vdf_safe_load({vdf_file}): {e}')