From 8eca19d9a19a2d586e5faa75c7b1828ba8ff23b6 Mon Sep 17 00:00:00 2001 From: Rilic Date: Sun, 23 Jul 2023 17:11:14 +0100 Subject: [PATCH] Changes - Add Windows support - Add Steam RetroArch support - Add support for custom playlist and thumbnail directories --- src/importer/sources/retroarch_source.py | 64 ++++++++++++++++++++---- src/shared.py.in | 1 + 2 files changed, 56 insertions(+), 9 deletions(-) diff --git a/src/importer/sources/retroarch_source.py b/src/importer/sources/retroarch_source.py index 0e7c3a9..0960368 100644 --- a/src/importer/sources/retroarch_source.py +++ b/src/importer/sources/retroarch_source.py @@ -19,9 +19,10 @@ import json import logging +import re from hashlib import md5 from json import JSONDecodeError -from re import sub +from pathlib import Path from time import time from src import shared @@ -29,19 +30,39 @@ from src.errors.friendly_error import FriendlyError from src.game import Game from src.importer.sources.location import Location from src.importer.sources.source import Source, SourceIterationResult, SourceIterator +from src.importer.sources.steam_source import SteamSource class RetroarchSourceIterator(SourceIterator): source: "RetroarchSource" + def get_config_value(self, key: str, config_data: str): + for item in re.findall(f'{key}\\s*=\\s*"(.*)"\n', config_data, re.IGNORECASE): + logging.debug(str(item)) + return item + + raise KeyError(f"Key not found in RetroArch config: {key}") + def generator_builder(self) -> SourceIterationResult: added_time = int(time()) bad_playlists = set() + config_file = self.source.config_location["config"] + with config_file.open(encoding="utf-8") as open_file: + config_data = open_file.read() + + playlist_folder = Path( + self.get_config_value("playlist_directory", config_data) + ).expanduser() + thumbnail_folder = Path( + self.get_config_value("thumbnails_directory", config_data) + ).expanduser() + # Get all playlist files, ending in .lpl - playlist_files = self.source.config_location["playlists"].glob("*.lpl") + playlist_files = playlist_folder.glob("*.lpl") for playlist_file in playlist_files: + logging.debug(playlist_file) try: with playlist_file.open( encoding="utf-8", @@ -84,10 +105,10 @@ class RetroarchSourceIterator(SourceIterator): # Get boxart boxart_image_name = item["label"] + ".png" - boxart_image_name = sub(r"[&\*\/:`<>\?\\\|]", "_", boxart_image_name) + boxart_image_name = re.sub(r"[&\*\/:`<>\?\\\|]", "_", boxart_image_name) boxart_folder_name = playlist_file.stem image_path = ( - self.source.config_location["thumbnails"] + thumbnail_folder / boxart_folder_name / "Named_Boxarts" / boxart_image_name @@ -107,20 +128,45 @@ class RetroarchSourceIterator(SourceIterator): class RetroarchSource(Source): + def __init__(self) -> None: + super().__init__() + # Find steam location + libraryfolders = SteamSource().data_location["libraryfolders.vdf"] + library_path = "" + + with open(libraryfolders, "r", encoding="utf-8") as open_file: + for line in open_file: + if '"path"' in line: + library_path = re.findall( + '"path"\\s+"(.*)"\n', line, re.IGNORECASE + )[0] + elif "1118310" in line: + break + + if library_path: + self.config_location.candidates.append( + Path(f"{library_path}/steamapps/common/RetroArch") + ) + name = _("RetroArch") - available_on = {"linux"} + available_on = {"linux", "windows"} iterator_class = RetroarchSourceIterator config_location = Location( schema_key="retroarch-location", - candidates=( + candidates=[ shared.flatpak_dir / "org.libretro.RetroArch" / "config" / "retroarch", shared.config_dir / "retroarch", shared.home / ".config" / "retroarch", - ), + Path("C:\\RetroArch-Win64"), + Path("C:\\RetroArch-Win32"), + shared.local_appdata_dir + / "Packages" + / "1e4cf179-f3c2-404f-b9f3-cb2070a5aad8_8ngdn9a6dx1ma" + / "LocalState", + ], paths={ - "playlists": (True, "playlists"), - "thumbnails": (True, "thumbnails"), + "config": (False, "retroarch.cfg"), }, ) diff --git a/src/shared.py.in b/src/shared.py.in index 92fc574..91e7b6d 100644 --- a/src/shared.py.in +++ b/src/shared.py.in @@ -41,6 +41,7 @@ games_dir = data_dir / "cartridges" / "games" covers_dir = data_dir / "cartridges" / "covers" appdata_dir = Path(os.getenv("appdata") or "C:\\Users\\Default\\AppData\\Roaming") +local_appdata_dir = Path(os.getenv("csidl_local_appdata") or "C:\\Users\\Default\\AppData\\Local") programfiles32_dir = Path(os.getenv("programfiles(x86)") or "C:\\Program Files (x86)") scale_factor = max(