From 1e3b17828123f04f53df8c3a0f129b0030b94248 Mon Sep 17 00:00:00 2001 From: Roy <88516395+moraroy@users.noreply.github.com> Date: Mon, 15 Jul 2024 22:57:09 -0700 Subject: [PATCH] Add files via upload --- NSLGameScanner.py | 508 ---------------------------------------------- 1 file changed, 508 deletions(-) diff --git a/NSLGameScanner.py b/NSLGameScanner.py index f2ae73f..dd3b7c3 100644 --- a/NSLGameScanner.py +++ b/NSLGameScanner.py @@ -599,514 +599,6 @@ else: -# Ubisoft Connect Scanner -def getUplayGameInfo(folderPath, filePath): - # Get the game IDs from the folder - listOfFiles = os.listdir(folderPath) - uplay_ids = [re.findall(r'\d+', str(entry))[0] for entry in listOfFiles if re.findall(r'\d+', str(entry))] - - # Parse the registry file - game_dict = {} - with open(filePath, 'r') as file: - uplay_id = None - game_name = None - uplay_install_found = False - for line in file: - line = line.replace("\\x2019", "’") - if "Uplay Install" in line: - uplay_id = re.findall(r'Uplay Install (\d+)', line) - if uplay_id: - uplay_id = uplay_id[0] - game_name = None # Reset game_name - uplay_install_found = True - if "DisplayName" in line and uplay_install_found: - game_name = re.findall(r'\"(.+?)\"', line.split("=")[1]) - if game_name: - game_name = game_name[0] - uplay_install_found = False - if uplay_id and game_name and uplay_id in uplay_ids: - game_dict[game_name] = uplay_id - uplay_id = None # Reset uplay_id - game_name = None # Reset game_name - - return game_dict - -# Define your paths -data_folder_path = f"{logged_in_home}/.local/share/Steam/steamapps/compatdata/{ubisoft_connect_launcher}/pfx/drive_c/Program Files (x86)/Ubisoft/Ubisoft Game Launcher/data/" -registry_file_path = f"{logged_in_home}/.local/share/Steam/steamapps/compatdata/{ubisoft_connect_launcher}/pfx/system.reg" - -# Check if the paths exist -if not os.path.exists(data_folder_path) or not os.path.exists(registry_file_path): - print("One or more paths do not exist.") - print("Ubisoft Connect game data not found. Skipping Ubisoft Games Scanner.") -else: - game_dict = getUplayGameInfo(data_folder_path, registry_file_path) - - for game, uplay_id in game_dict.items(): - if uplay_id: - launch_options = f"STEAM_COMPAT_DATA_PATH=\"{logged_in_home}/.local/share/Steam/steamapps/compatdata/{ubisoft_connect_launcher}/\" %command% \"uplay://launch/{uplay_id}/0\"" - exe_path = f"\"{logged_in_home}/.local/share/Steam/steamapps/compatdata/{ubisoft_connect_launcher}/pfx/drive_c/Program Files (x86)/Ubisoft/Ubisoft Game Launcher/upc.exe\"" - start_dir = f"\"{logged_in_home}/.local/share/Steam/steamapps/compatdata/{ubisoft_connect_launcher}/pfx/drive_c/Program Files (x86)/Ubisoft/Ubisoft Game Launcher/\"" - create_new_entry(exe_path, game, launch_options, start_dir) - -# End of Ubisoft Game Scanner - -# EA App Game Scanner - -def get_ea_app_game_info(installed_games, game_directory_path): - game_dict = {} - for game in installed_games: - xml_file = ET.parse(f"{game_directory_path}{game}/__Installer/installerdata.xml") - xml_root = xml_file.getroot() - ea_ids = None - game_name = None - for content_id in xml_root.iter('contentID'): - if ea_ids is None: - ea_ids = content_id.text - else: - ea_ids = ea_ids + ',' + content_id.text - for game_title in xml_root.iter('gameTitle'): - if game_name is None: - game_name = game_title.text - continue - for game_title in xml_root.iter('title'): - if game_name is None: - game_name = game_title.text - continue - if game_name is None: - game_name = game - if ea_ids: # Add the game's info to the dictionary if its ID was found in the folder - game_dict[game_name] = ea_ids - return game_dict - -game_directory_path = f"{logged_in_home}/.local/share/Steam/steamapps/compatdata/{ea_app_launcher}/pfx/drive_c/Program Files/EA Games/" - -if not os.path.isdir(game_directory_path): - print("EA App game data not found. Skipping EA App Scanner.") -else: - installed_games = os.listdir(game_directory_path) # Get a list of game folders - game_dict = get_ea_app_game_info(installed_games, game_directory_path) - - for game, ea_ids in game_dict.items(): - launch_options = f"STEAM_COMPAT_DATA_PATH=\"{logged_in_home}/.local/share/Steam/steamapps/compatdata/{ea_app_launcher}/\" %command% \"origin2://game/launch?offerIds={ea_ids}\"" - exe_path = f"\"{logged_in_home}/.local/share/Steam/steamapps/compatdata/{ea_app_launcher}/pfx/drive_c/Program Files/Electronic Arts/EA Desktop/EA Desktop/EALaunchHelper.exe\"" - start_dir = f"\"{logged_in_home}/.local/share/Steam/steamapps/compatdata/{ea_app_launcher}/pfx/drive_c/Program Files/Electronic Arts/EA Desktop/EA Desktop/\"" - create_new_entry(exe_path, game, launch_options, start_dir) - -#End of EA App Scanner - - - -#Gog Galaxy Scanner -def getGogGameInfo(filePath): - # Check if the file contains any GOG entries - with open(filePath, 'r') as file: - if "GOG.com" not in file.read(): - print("No GOG entries found in the registry file. Skipping GOG Galaxy Games Scanner.") - return {} - - # If GOG entries exist, parse the registry file - game_dict = {} - with open(filePath, 'r') as file: - game_id = None - game_name = None - exe_path = None - depends_on = None - launch_command = None - start_menu_link = None - gog_entry = False - for line in file: - if "GOG.com" in line: - gog_entry = True - if gog_entry: - split_line = line.split("=") - if len(split_line) > 1: - if "gameID" in line: - game_id = re.findall(r'\"(.+?)\"', split_line[1]) - if game_id: - game_id = game_id[0] - if "gameName" in line: - game_name = re.findall(r'\"(.+?)\"', split_line[1]) - if game_name: - game_name = bytes(game_name[0], 'utf-8').decode('unicode_escape') - game_name = game_name.replace('!22', '™') - if "exe" in line and not "unins000.exe" in line: - exe_path = re.findall(r'\"(.+?)\"', split_line[1]) - if exe_path: - exe_path = exe_path[0].replace('\\\\', '\\') - if "dependsOn" in line: - depends_on = re.findall(r'\"(.+?)\"', split_line[1]) - if depends_on: - depends_on = depends_on[0] - if "launchCommand" in line: - launch_command = re.findall(r'\"(.+?)\"\s*$', split_line[1]) - if launch_command: - # Remove leading and trailing whitespace from the path - path = launch_command[0].strip() - # Reconstruct the launch command with the cleaned path - launch_command = f"\"{path}\"" - if "startMenuLink" in line: - start_menu_link = re.findall(r'\"(.+?)\"', split_line[1]) - if start_menu_link: - start_menu_link = start_menu_link[0] - if game_id and game_name and launch_command and start_menu_link and 'GOG.com' in start_menu_link: - game_dict[game_name] = {'id': game_id, 'exe': exe_path} - game_id = None - game_name = None - exe_path = None - depends_on = None - launch_command = None - start_menu_link = None - - return game_dict - - - - -# Define your paths -gog_games_directory = f"{logged_in_home}/.local/share/Steam/steamapps/compatdata/{gog_galaxy_launcher}/pfx/drive_c/Program Files (x86)/GOG Galaxy/Games" -registry_file_path = f"{logged_in_home}/.local/share/Steam/steamapps/compatdata/{gog_galaxy_launcher}/pfx/system.reg" - -# Check if the paths exist -if not os.path.exists(gog_games_directory) or not os.path.exists(registry_file_path): - print("One or more paths do not exist.") - print("GOG Galaxy game data not found. Skipping GOG Galaxy Games Scanner.") -else: - game_dict = getGogGameInfo(registry_file_path) - - for game, game_info in game_dict.items(): - if game_info['id']: - # Strip leading and trailing spaces from the exe path - exe_path = game_info['exe'].strip() - launch_options = f"STEAM_COMPAT_DATA_PATH=\"{logged_in_home}/.local/share/Steam/steamapps/compatdata/{gog_galaxy_launcher}/\" %command% /command=runGame /gameId={game_info['id']} /path=\"{exe_path}\"" - exe_path = f"\"{logged_in_home}/.local/share/Steam/steamapps/compatdata/{gog_galaxy_launcher}/pfx/drive_c/Program Files (x86)/GOG Galaxy/GalaxyClient.exe\"" - start_dir = f"\"{logged_in_home}/.local/share/Steam/steamapps/compatdata/{gog_galaxy_launcher}/pfx/drive_c/Program Files (x86)/GOG Galaxy/\"" - create_new_entry(exe_path, game, launch_options, start_dir) - -# End of Gog Galaxy Scanner - - - - - -#Battle.net Scanner -# Define your mapping -flavor_mapping = { - "Blizzard Arcade Collection": "RTRO", - "Diablo": "D1", - "Diablo II: Resurrected": "OSI", - "Diablo III": "D3", - "Diablo IV": "Fen", - "Diablo Immortal (PC)": "ANBS", - "Hearthstone": "WTCG", - "Heroes of the Storm": "Hero", - "Overwatch": "Pro", - "Overwatch 2": "Pro", - "StarCraft": "S1", - "StarCraft 2": "S2", - "Warcraft: Orcs & Humans": "W1", - "Warcraft II: Battle.net Edition": "W2", - "Warcraft III: Reforged": "W3", - "World of Warcraft": "WoW", - "World of Warcraft Classic": "WoWC", - "Warcraft Arclight Rumble": "GRY", - "Call of Duty: Black Ops - Cold War": "ZEUS", - "Call of Duty: Black Ops 4": "VIPR", - "Call of Duty: Modern Warfare": "ODIN", - "Call of Duty": "AUKS", - "Call of Duty: MW 2 Campaign Remastered": "LAZR", - "Call of Duty: Vanguard": "FORE", - "Call of Duty: Modern Warfare III": "SPOT", - "Crash Bandicoot 4: It's About Time": "WLBY", - # Add more games here... -} - -def get_flavor_from_file(game_path): - game_path = game_path.replace('\\', '/') - flavor_file = os.path.join(game_path, '_retail_', '.flavor.info') - if os.path.exists(flavor_file): - with open(flavor_file, 'r') as file: - for line in file: - if 'STRING' in line: - return line.split(':')[-1].strip().capitalize() - else: - print(f"Flavor file not found: {flavor_file}") - # Use the mapping as a fallback - game_name = os.path.basename(game_path) - print(f"Game name from file path: {game_name}") - return flavor_mapping.get(game_name, 'unknown') - -def getBnetGameInfo(filePath): - # Check if the file contains any Battle.net entries - with open(filePath, 'r') as file: - if "Battle.net" not in file.read(): - print("No Battle.net entries found in the registry file. Skipping Battle.net Games Scanner.") - return None - - # If Battle.net entries exist, parse the registry file - game_dict = {} - with open(filePath, 'r') as file: - game_name = None - exe_path = None - publisher = None - contact = None - for line in file: - split_line = line.split("=") - if len(split_line) > 1: - if "Publisher" in line: - publisher = re.findall(r'\"(.+?)\"', split_line[1]) - if publisher: - publisher = publisher[0] - # Skip if the publisher is not Blizzard Entertainment - if publisher != "Blizzard Entertainment": - game_name = None - exe_path = None - publisher = None - continue - if "Contact" in line: - contact = re.findall(r'\"(.+?)\"', split_line[1]) - if contact: - contact = contact[0] - if "DisplayName" in line: - game_name = re.findall(r'\"(.+?)\"', split_line[1]) - if game_name: - game_name = game_name[0] - if "InstallLocation" in line: - exe_path = re.findall(r'\"(.+?)\"', split_line[1]) - if exe_path: - exe_path = exe_path[0].replace('\\\\', '\\') - # Skip if the install location is for the Battle.net launcher - if "Battle.net" in exe_path: - game_name = None - exe_path = None - publisher = None - continue - if game_name and exe_path and publisher == "Blizzard Entertainment" and contact == "Blizzard Support": - game_dict[game_name] = {'exe': exe_path} - print(f"Game added to dictionary: {game_name}") - game_name = None - exe_path = None - publisher = None - contact = None - - # If no games were found, return None - if not game_dict: - print("No Battle.net games found. Skipping Battle.net Games Scanner.") - return None - - return game_dict - -# Define your paths -registry_file_path = f"{logged_in_home}/.local/share/Steam/steamapps/compatdata/{bnet_launcher}/pfx/system.reg" - -game_dict = {} - -# Check if the paths exist -if not os.path.exists(registry_file_path): - print("One or more paths do not exist.") - print("Battle.net game data not found. Skipping Battle.net Games Scanner.") -else: - game_dict = getBnetGameInfo(registry_file_path) - if game_dict is None: - # Skip the rest of the Battle.net scanner - pass - else: - # Extract the flavor for each game and create the launch options - for game, game_info in game_dict.items(): - game_info['flavor'] = get_flavor_from_file(game_info['exe']) - print(f"Flavor inferred: {game_info['flavor']}") - - # Check if the game name is "Overwatch" and update it to "Overwatch 2" - if game == "Overwatch": - game = "Overwatch 2" - - if game_info['flavor'] == "unknown": - pass - - elif game_info['flavor']: - launch_options = f"STEAM_COMPAT_DATA_PATH=\"{logged_in_home}/.local/share/Steam/steamapps/compatdata/{bnet_launcher}/\" %command% \"battlenet://{game_info['flavor']}\"" - exe_path = f"\"{logged_in_home}/.local/share/Steam/steamapps/compatdata/{bnet_launcher}/pfx/drive_c/Program Files (x86)/Battle.net/Battle.net.exe\" --exec=\"launch {game_info['flavor']}\"" - start_dir = f"\"{logged_in_home}/.local/share/Steam/steamapps/compatdata/{bnet_launcher}/pfx/drive_c/Program Files (x86)/Battle.net/\"" - create_new_entry(exe_path, game, launch_options, start_dir) - -# End of Battle.net Scanner - - - - -# Amazon Games Scanner -def get_sqlite_path(): - # Specify the full path to the SQLite file - path = f"{logged_in_home}/.local/share/Steam/steamapps/compatdata/{amazon_launcher}/pfx/drive_c/users/steamuser/AppData/Local/Amazon Games/Data/Games/Sql/GameInstallInfo.sqlite" - if os.path.exists(path): - return path - else: - print(f"Amazon GameInstallInfo.sqlite not found at {path}") - return None - -def get_launcher_path(): - # Specify the full path to the Amazon Games launcher executable - path = f"{logged_in_home}/.local/share/Steam/steamapps/compatdata/{amazon_launcher}/pfx/drive_c/users/steamuser/AppData/Local/Amazon Games/App/Amazon Games.exe" - if os.path.exists(path): - return path - else: - print(f"Could not find Amazon Games.exe at {path}") - return None - -def get_amazon_games(): - sqllite_path = get_sqlite_path() - launcher_path = get_launcher_path() - if sqllite_path is None or launcher_path is None: - print("Skipping Amazon Games Scanner due to missing paths.") - return [] - result = [] - connection = sqlite3.connect(sqllite_path) - cursor = connection.cursor() - cursor.execute("SELECT Id, ProductTitle FROM DbSet WHERE Installed = 1") - for row in cursor.fetchall(): - id, title = row - result.append({"id": id, "title": title, "launcher_path": launcher_path}) - return result - -amazon_games = get_amazon_games() -if amazon_games: - for game in amazon_games: - - # Initialize variables - display_name = game['title'] - exe_path = f"\"{logged_in_home}/.local/share/Steam/steamapps/compatdata/{amazon_launcher}/pfx/drive_c/users/steamuser/AppData/Local/Amazon Games/App/Amazon Games.exe\"" - start_dir = f"\"{logged_in_home}/.local/share/Steam/steamapps/compatdata/{amazon_launcher}/pfx/drive_c/users/steamuser/AppData/Local/Amazon Games/App/\"" - launch_options = f"STEAM_COMPAT_DATA_PATH=\"{logged_in_home}/.local/share/Steam/steamapps/compatdata/{amazon_launcher}\" %command% -'amazon-games://play/{game['id']}'" - create_new_entry(exe_path, display_name, launch_options, start_dir) - - -#End of Amazon Games Scanner - - - -#Itchio Scanner -def get_itch_games(itch_db_location): - print(f"Checking if {itch_db_location} exists...") - if not os.path.exists(itch_db_location): - print(f"Path not found: {itch_db_location}. Continuing with the rest of the code...") - return [] - - print("Opening and reading the database file...") - with open(itch_db_location, 'rb') as f: - shortcut_bytes = f.read() - - print("Parsing the database file...") - paths = parse_butler_db(shortcut_bytes) - - print("Converting paths to games...") - games = [dbpath_to_game(path) for path in paths if dbpath_to_game(path) is not None] - # Remove duplicates - games = list(set(games)) - print(f"Found {len(games)} unique games.") - return games - -def parse_butler_db(content): - print("Finding matches in the database content...") - pattern = rb'\{"basePath":"(.*?)","totalSize".*?"candidates":\[(.*?)\]\}' - matches = re.findall(pattern, content) - print(f"Found {len(matches)} matches.") - - print("Converting matches to database paths...") - db_paths = [] - for match in matches: - base_path = match[0].decode(errors='ignore') - candidates_json = b'[' + match[1] + b']' - candidates = json.loads(candidates_json.decode(errors='ignore')) - paths = [candidate['path'] for candidate in candidates] - db_paths.append((base_path, paths)) - print(f"Converted {len(matches)} matches to {len(db_paths)} database paths.") - return db_paths - -def dbpath_to_game(paths): - # Convert the Windows-style path from the database to a Unix-style path - db_path = paths[0].replace("\\\\", "/").replace("C:", "") - linux_path = f"{logged_in_home}/.local/share/Steam/steamapps/compatdata/{itchio_launcher}/pfx/drive_c" + db_path - receipt_path = os.path.join(linux_path, ".itch", "receipt.json.gz") - if not os.path.exists(receipt_path): - return None - - for executable in paths[1]: - exe_path = os.path.join(linux_path, executable) - if os.access(exe_path, os.X_OK): # check if file is executable - with gzip.open(receipt_path, 'rb') as f: - receipt_str = f.read().decode() - receipt = json.loads(receipt_str) - return (linux_path, executable, receipt['game']['title']) -# Usage: -itch_db_location = f"{logged_in_home}/.local/share/Steam/steamapps/compatdata/{itchio_launcher}/pfx/drive_c/users/steamuser/AppData/Roaming/itch/db/butler.db-wal" -print(f"Getting games from {itch_db_location}...") -games = get_itch_games(itch_db_location) -print("Printing games...") -for game in games: - print(game) - -for game in games: - linux_path, executable, game_title = game - exe_path = f"\"{os.path.join(linux_path, executable)}\"" - start_dir = f"\"{linux_path}\"" - launchoptions = f"STEAM_COMPAT_DATA_PATH=\"{logged_in_home}/.local/share/Steam/steamapps/compatdata/{itchio_launcher}/\" %command%" - create_new_entry(exe_path, game_title, launchoptions, start_dir) - -#End of Itchio Scanner - - -#Legacy Games Scanner -legacy_dir = f"{logged_in_home}/.local/share/Steam/steamapps/compatdata/{legacy_launcher}/pfx/drive_c/Program Files/Legacy Games/" -user_reg_path = f"{logged_in_home}/.local/share/Steam/steamapps/compatdata/{legacy_launcher}/pfx/user.reg" - -if not os.path.exists(legacy_dir) or not os.path.exists(user_reg_path): - print("Path not found. Skipping Legacy Games Scanner.") -else: - print("Directory and user.reg file found.") - with open(user_reg_path, 'r') as file: - user_reg = file.read() - - for game_dir in os.listdir(legacy_dir): - if game_dir == "Legacy Games Launcher": - continue - - print(f"Processing game directory: {game_dir}") - - if game_dir == "100 Doors Escape from School": - app_info_path = f"{legacy_dir}/100 Doors Escape from School/100 Doors Escape From School_Data/app.info" - exe_path = f"{legacy_dir}/100 Doors Escape from School/100 Doors Escape From School.exe" - else: - app_info_path = os.path.join(legacy_dir, game_dir, game_dir.replace(" ", "") + "_Data", "app.info") - exe_path = os.path.join(legacy_dir, game_dir, game_dir.replace(" ", "") + ".exe") - - if os.path.exists(app_info_path): - print("app.info file found.") - with open(app_info_path, 'r') as file: - lines = file.read().split('\n') - game_name = lines[1].strip() - print(f"Game Name: {game_name}") - else: - print("No app.info file found.") - - if os.path.exists(exe_path): - game_exe_reg = re.search(r'\[Software\\\\Legacy Games\\\\' + re.escape(game_dir) + r'\].*?"GameExe"="([^"]*)"', user_reg, re.DOTALL | re.IGNORECASE) - if game_exe_reg and game_exe_reg.group(1).lower() == os.path.basename(exe_path).lower(): - print(f"GameExe found in user.reg: {game_exe_reg.group(1)}") - start_dir = f"{legacy_dir}{game_dir}" - launch_options = f"STEAM_COMPAT_DATA_PATH=\"{logged_in_home}/.local/share/Steam/steamapps/compatdata/{legacy_launcher}\" %command%" - create_new_entry(f'"{exe_path}"', game_name, launch_options, f'"{start_dir}"') - else: - print(f"No matching .exe file found for game: {game_dir}") - else: - print(f"No .exe file found for game: {game_dir}") - -#End of the Legacy Games Scanner - - - - - - # Only write back to the shortcuts.vdf and config.vdf files if new shortcuts were added or compattools changed if new_shortcuts_added or shortcuts_updated: print(f"Saving new config and shortcuts files")