-
Notifications
You must be signed in to change notification settings - Fork 54
/
origin_utils.py
104 lines (85 loc) · 3.2 KB
/
origin_utils.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
# -*- encoding: utf-8 -*-
# Heavily influenced by https://github.com/erri120/GameFinder
import os
import threading
import time
from collections.abc import Sequence
from pathlib import Path
from urllib import parse
import psutil
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] = []):
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)
def find_games() -> dict[str, Path]:
"""
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] = {}
program_data_path = os.path.expandvars("%PROGRAMDATA%")
local_content_path = Path(program_data_path).joinpath("Origin", "LocalContent")
for manifest in local_content_path.glob("**/*.mfst"):
# Skip any manifest file with '@steam'
if "@steam" in manifest.name.lower():
continue
# Read the file and look for &id= and &dipinstallpath=
with open(manifest, "r") as f:
manifest_query = f.read()
url = parse.urlparse(manifest_query)
query = parse.parse_qs(url.query)
if "id" not in query:
# If id is not present, we have no clue what to do.
continue
if "dipinstallpath" not in query:
# We could query the Origin server for the install location but... no?
continue
for id_ in query["id"]:
for path_ in query["dipinstallpath"]:
games[id_] = Path(path_)
return games
if __name__ == "__main__":
games = find_games()
for k, v in games.items():
print("Found game with id {} at {}.".format(k, v))