Files
modorganizer-basic_games/origin_utils.py
T

105 lines
3.2 KiB
Python
Raw Normal View History

2021-11-24 17:23:34 -07:00
# -*- encoding: utf-8 -*-
# Heavily influenced by https://github.com/erri120/GameFinder
import os
2021-11-24 20:55:11 -07:00
import threading
import time
from collections.abc import Sequence
2021-11-24 17:23:34 -07:00
from pathlib import Path
from urllib import parse
2022-04-21 22:13:00 +02:00
import psutil
2021-11-24 20:55:11 -07:00
class OriginWatcher:
"""
This is a class to control killing Origin when needed. This is used in
order to hook and unhook Origin to get around the Origin DRM. Support
for launching Origin is not included as it's intended for the game's
DRM to launch Origin as needed.
"""
def __init__(self, executables: Sequence[str] = []):
2021-11-24 20:55:11 -07:00
self.executables = list(map(lambda s: s.lower(), executables))
def spawn_origin_watcher(self) -> bool:
self.kill_origin()
self.worker_alive = True
self.worker = threading.Thread(target=self._workerFunc)
self.worker.start()
return True
def stop_origin_watcher(self) -> None:
self.worker_alive = False
self.worker.join(10.0)
def kill_origin(self) -> None:
"""
Kills the Origin application
"""
for proc in psutil.process_iter():
if proc.name().lower() == "origin.exe":
proc.kill()
def _workerFunc(self) -> None:
gameAliveCount = 300 # Large number to allow Origin and the game to launch
while self.worker_alive:
gameAlive = False
# See if the game is still alive
for proc in psutil.process_iter():
if proc.name().lower() in self.executables:
gameAlive = True
break
if gameAlive:
# Game is alive, sleep and keep monitoring at faster pace
gameAliveCount = 5
else:
gameAliveCount -= 1
if gameAliveCount <= 0:
self.kill_origin()
self.worker_alive = False
time.sleep(1)
2021-11-24 17:23:34 -07:00
def find_games() -> dict[str, Path]:
2021-11-24 17:23:34 -07:00
"""
Find the list of Origin games installed.
Returns:
A mapping from Origin manifest IDs to install locations for available
Origin games.
"""
games: dict[str, Path] = {}
2021-11-24 20:55:11 -07:00
program_data_path = os.path.expandvars("%PROGRAMDATA%")
local_content_path = Path(program_data_path).joinpath("Origin", "LocalContent")
2021-11-24 17:23:34 -07:00
for manifest in local_content_path.glob("**/*.mfst"):
# Skip any manifest file with '@steam'
2021-11-24 20:55:11 -07:00
if "@steam" in manifest.name.lower():
2021-11-24 17:23:34 -07:00
continue
# Read the file and look for &id= and &dipinstallpath=
2021-11-24 20:55:11 -07:00
with open(manifest, "r") as f:
2021-11-24 17:23:34 -07:00
manifest_query = f.read()
url = parse.urlparse(manifest_query)
query = parse.parse_qs(url.query)
2021-11-24 20:55:11 -07:00
if "id" not in query:
2021-11-24 17:23:34 -07:00
# If id is not present, we have no clue what to do.
continue
2021-11-24 20:55:11 -07:00
if "dipinstallpath" not in query:
2021-11-24 17:23:34 -07:00
# We could query the Origin server for the install location but... no?
continue
2021-11-24 20:55:11 -07:00
for id_ in query["id"]:
for path_ in query["dipinstallpath"]:
2021-11-24 17:23:34 -07:00
games[id_] = Path(path_)
2021-11-24 20:55:11 -07:00
2021-11-24 17:23:34 -07:00
return games
2021-11-24 20:55:11 -07:00
2021-11-24 17:23:34 -07:00
if __name__ == "__main__":
games = find_games()
for k, v in games.items():
2021-11-24 20:55:11 -07:00
print("Found game with id {} at {}.".format(k, v))