1
0
Fork 0
mirror of synced 2024-09-12 23:54:24 +12:00
Rare/rare/utils/steam_shortcuts.py
loathingKernel 89b765b64d
SteamShortcuts: Fix a couple of crashes
* The grid directory might not exist, so create it before copying the coverart
* The shortcuts files might not exist, so don't try to open it.
2024-06-04 17:28:15 +03:00

203 lines
6.9 KiB
Python

import os
import platform
import shutil
from logging import getLogger
from pathlib import Path
from typing import Optional, List, Dict
from dataclasses import asdict
import vdf
from rare.utils.paths import image_icon_path, image_wide_path, image_tall_path, desktop_icon_path, get_rare_executable
from rare.models.steam import SteamUser, SteamShortcut
if platform.system() == "Windows":
# noinspection PyUnresolvedReferences
import winreg # pylint: disable=E0401
logger = getLogger("SteamShortcuts")
steam_client_install_paths = [os.path.expanduser("~/.local/share/Steam")]
def find_steam() -> Optional[str]:
if platform.system() == "Windows":
# Find the Steam install directory or raise an error
try: # 32-bit
key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, "SOFTWARE\\Valve\\Steams")
except FileNotFoundError:
try: # 64-bit
key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, "SOFTWARE\\Wow6432Node\\Valve\\Steam")
except FileNotFoundError as e:
return None
return winreg.QueryValueEx(key, "InstallPath")[0]
# return the first valid path
elif platform.system() in {"Linux", "FreeBSD"}:
for path in steam_client_install_paths:
if os.path.isdir(path) and os.path.isfile(os.path.join(path, "steam.sh")):
return path
return None
def find_steam_users(steam_path: str) -> List[SteamUser]:
_users = []
vdf_path = os.path.join(steam_path, "config", "loginusers.vdf")
with open(vdf_path, 'r') as f:
users = vdf.load(f).get("users", {})
for long_id, user in users.items():
_users.append(SteamUser(long_id, user))
return _users
def _load_shortcuts(steam_path: str, user: SteamUser) -> Dict[str, SteamShortcut]:
_shortcuts = {}
vdf_path = os.path.join(steam_path, "userdata", str(user.short_id), "config", "shortcuts.vdf")
if not os.path.exists(vdf_path):
return _shortcuts
with open(vdf_path, 'rb') as f:
shortcuts = vdf.binary_load(f).get("shortcuts", {})
for idx, shortcut in shortcuts.items():
_shortcuts[idx] = SteamShortcut.from_dict(shortcut)
return _shortcuts
def _save_shortcuts(steam_path: str, user: SteamUser, shortcuts: Dict[str, SteamShortcut]) -> None:
_shortcuts = {k: asdict(v) for k, v in shortcuts.items()}
vdf_path = os.path.join(steam_path, "userdata", str(user.short_id), "config", "shortcuts.vdf")
with open(vdf_path, 'wb') as f:
vdf.binary_dump({"shortcuts": _shortcuts}, f)
__steam_dir: Optional[str] = None
__steam_user: Optional[SteamUser] = None
__steam_shortcuts: Optional[Dict] = None
def steam_shortcuts_supported() -> bool:
return __steam_dir is not None and __steam_user is not None and __steam_shortcuts is not None
def load_steam_shortcuts():
global __steam_shortcuts, __steam_dir, __steam_user
if __steam_shortcuts is not None:
return
steam_dir = find_steam()
if not steam_dir:
logger.error("Failed to find Steam install directory")
return
__steam_dir = steam_dir
steam_users = find_steam_users(steam_dir)
if not steam_users:
logger.error("Failed to find any Steam users")
return
else:
steam_user = next(filter(lambda x: x.most_recent, steam_users))
logger.info("Found most recently logged-in user %s(%s)", steam_user.account_name, steam_user.persona_name)
__steam_user = steam_user
__steam_shortcuts = _load_shortcuts(steam_dir, steam_user)
def save_steam_shortcuts():
logger.info(
"%s Steam shortcuts for user %s(%s)",
"Saving" if __steam_shortcuts else "Removing",
__steam_user.account_name,
__steam_user.persona_name
)
_save_shortcuts(__steam_dir, __steam_user, __steam_shortcuts)
def steam_shortcut_exists(app_name: str) -> bool:
return SteamShortcut.calculate_appid(app_name) in {s.appid for s in __steam_shortcuts.values()}
def remove_steam_shortcut(app_name: str) -> Optional[SteamShortcut]:
global __steam_shortcuts
if not steam_shortcut_exists(app_name):
logger.error("Game %s doesn't have an associated Steam shortcut", app_name)
return None
appid = SteamShortcut.calculate_appid(app_name)
removed = next(filter(lambda item: item[1].appid == appid, __steam_shortcuts.items()))
shortcuts = dict(filter(lambda item: item[1].appid != appid, __steam_shortcuts.items()))
__steam_shortcuts = shortcuts
return removed[1]
def add_steam_shortcut(app_name: str, app_title: str) -> SteamShortcut:
global __steam_shortcuts
if steam_shortcut_exists(app_name):
logger.info("Removing old Steam shortcut for %s", app_name)
remove_steam_shortcut(app_name)
command = get_rare_executable()
arguments = ["launch", app_name]
if len(command) > 1:
arguments = command[1:] + arguments
shortcut = SteamShortcut.create(
app_name=app_name,
app_title=f"{app_title} (Rare)",
executable=command[0],
start_dir=os.path.dirname(command[0]),
icon=desktop_icon_path(app_name).as_posix(),
launch_options=arguments,
)
key = int(max(__steam_shortcuts.keys(), default="0"))
__steam_shortcuts[str(key+1)] = shortcut
return shortcut
def add_steam_coverart(app_name: str, shortcut: SteamShortcut):
steam_grid_dir = os.path.join(__steam_dir, "userdata", str(__steam_user.short_id), "config", "grid")
if not os.path.exists(steam_grid_dir):
os.mkdir(steam_grid_dir)
shutil.copy(image_wide_path(app_name), os.path.join(steam_grid_dir, shortcut.game_hero))
shutil.copy(image_icon_path(app_name), os.path.join(steam_grid_dir, shortcut.game_logo))
shutil.copy(image_wide_path(app_name), os.path.join(steam_grid_dir, shortcut.grid_wide))
shutil.copy(image_tall_path(app_name), os.path.join(steam_grid_dir, shortcut.grid_tall))
def remove_steam_coverart(shortcut: SteamShortcut):
steam_grid_dir = os.path.join(__steam_dir, "userdata", str(__steam_user.short_id), "config", "grid")
if not os.path.exists(steam_grid_dir):
logger.warning("Path does not exist %s", steam_grid_dir)
return
Path(steam_grid_dir).joinpath(shortcut.game_hero).unlink(missing_ok=True)
Path(steam_grid_dir).joinpath(shortcut.game_logo).unlink(missing_ok=True)
Path(steam_grid_dir).joinpath(shortcut.grid_wide).unlink(missing_ok=True)
Path(steam_grid_dir).joinpath(shortcut.grid_tall).unlink(missing_ok=True)
if __name__ == "__main__":
from pprint import pprint
load_steam_shortcuts()
print(__steam_dir)
print(__steam_user)
print(__steam_shortcuts)
def print_shortcuts():
for k, s in __steam_shortcuts.items():
print({k: asdict(s)})
print(vars(s))
print()
print_shortcuts()
add_steam_shortcut("test1", "Test1")
add_steam_shortcut("test2", "Test2")
add_steam_shortcut("test3", "Test3")
add_steam_shortcut("test1", "Test1")
remove_steam_shortcut("test2")
print_shortcuts()