Files
modorganizer-basic_games/eadesktop_utils.py
T

86 lines
2.6 KiB
Python
Raw Normal View History

2022-04-11 21:35:21 +02:00
# -*- encoding: utf-8 -*-
import configparser
import os
import sys
2022-04-11 21:35:21 +02:00
import xml.etree.ElementTree as et
2022-05-05 13:04:42 +02:00
from configparser import NoOptionError
2022-04-11 21:35:21 +02:00
from pathlib import Path
2022-05-02 16:59:21 +02:00
from typing import Dict
2022-04-11 21:35:21 +02:00
def find_games(errors: list[tuple[str, Exception]] | None = None) -> Dict[str, Path]:
2022-04-11 21:35:21 +02:00
"""
Find the list of EA Desktop games installed.
Returns:
A mapping from EA Desktop content IDs to install locations for available
EA Desktop games.
"""
games: Dict[str, Path] = {}
local_app_data_path = os.path.expandvars("%LocalAppData%")
2022-05-02 16:59:21 +02:00
ea_desktop_settings_path = Path(local_app_data_path).joinpath(
"Electronic Arts", "EA Desktop"
)
2022-04-11 21:35:21 +02:00
2022-05-02 16:59:21 +02:00
if not ea_desktop_settings_path.exists():
2022-04-11 21:35:21 +02:00
return games
2023-09-12 15:19:45 -05:00
try:
user_ini, *_ = list(ea_desktop_settings_path.glob("user_*.ini"))
except ValueError:
return games
2022-04-11 21:35:21 +02:00
# The INI file in its current form has no section headers.
# So we wrangle the input to add it all under a fake section.
with open(user_ini) as f:
ini_content = "[mod_organizer]\n" + f.read()
config = configparser.ConfigParser()
try:
config.read_string(ini_content)
except configparser.ParsingError as e:
error_message = (
f'Failed to parse EA Desktop games list file "{user_ini}",\n'
" Try to run the launcher to recreate it."
)
print(error_message, e, file=sys.stderr)
if errors is not None:
errors.append((error_message, e))
return games
2022-04-11 21:35:21 +02:00
try:
install_path = Path(config.get("mod_organizer", "user.downloadinplacedir"))
except NoOptionError:
install_path = Path(os.environ["ProgramW6432"]) / "EA Games"
config.set("mod_organizer", "user.downloadinplacedir", install_path.__str__())
2022-04-11 21:35:21 +02:00
2023-09-12 16:18:33 -05:00
if not install_path.exists():
return games
2022-04-11 21:35:21 +02:00
for game_dir in install_path.iterdir():
try:
installer_file = game_dir.joinpath("__Installer", "installerdata.xml")
xml_tree = et.parse(installer_file)
root = xml_tree.getroot()
2022-04-11 21:35:21 +02:00
# For all manifest files the following XPath expression returns the
# numeric ID. There are, in some cases, also name IDs but we do not
# consider these.
content_id = root.find(".//contentIDs/contentID[1]")
2022-05-02 16:59:21 +02:00
2023-12-29 11:16:20 +01:00
if content_id is not None and content_id.text:
game_id = content_id.text
games[game_id] = game_dir
except FileNotFoundError:
pass
2022-04-11 21:35:21 +02:00
return games
if __name__ == "__main__":
games = find_games()
for k, v in games.items():
print("Found game with id {} at {}.".format(k, v))