2022-04-11 21:35:21 +02:00
|
|
|
# -*- encoding: utf-8 -*-
|
|
|
|
|
|
|
|
|
|
import configparser
|
|
|
|
|
import os
|
|
|
|
|
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() -> Dict[str, Path]:
|
|
|
|
|
"""
|
|
|
|
|
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()
|
|
|
|
|
config.read_string(ini_content)
|
|
|
|
|
|
2022-05-02 21:13:28 -05: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():
|
2022-05-02 21:13:28 -05:00
|
|
|
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
|
|
|
|
2022-05-02 21:13:28 -05: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:
|
2022-05-02 21:13:28 -05:00
|
|
|
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))
|