Created source subclass, improved RetroArch exec
Steam RetroArch still not working on my machine.
This commit is contained in:
@@ -26,7 +26,7 @@ from gi.repository import GLib, Gtk
|
|||||||
from src import shared
|
from src import shared
|
||||||
from src.game import Game
|
from src.game import Game
|
||||||
from src.importer.sources.location import Location, LocationSubPath
|
from src.importer.sources.location import Location, LocationSubPath
|
||||||
from src.importer.sources.source import Source, SourceIterable
|
from src.importer.sources.source import ExecutableFormatSource, SourceIterable
|
||||||
|
|
||||||
|
|
||||||
class FlatpakSourceIterable(SourceIterable):
|
class FlatpakSourceIterable(SourceIterable):
|
||||||
@@ -116,7 +116,7 @@ class FlatpakLocations(NamedTuple):
|
|||||||
data: Location
|
data: Location
|
||||||
|
|
||||||
|
|
||||||
class FlatpakSource(Source):
|
class FlatpakSource(ExecutableFormatSource):
|
||||||
"""Generic Flatpak source"""
|
"""Generic Flatpak source"""
|
||||||
|
|
||||||
source_id = "flatpak"
|
source_id = "flatpak"
|
||||||
|
|||||||
@@ -26,7 +26,11 @@ from typing import NamedTuple
|
|||||||
from src import shared
|
from src import shared
|
||||||
from src.game import Game
|
from src.game import Game
|
||||||
from src.importer.sources.location import Location, LocationSubPath
|
from src.importer.sources.location import Location, LocationSubPath
|
||||||
from src.importer.sources.source import Source, SourceIterationResult, SourceIterable
|
from src.importer.sources.source import (
|
||||||
|
ExecutableFormatSource,
|
||||||
|
SourceIterationResult,
|
||||||
|
SourceIterable,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class LegendarySourceIterable(SourceIterable):
|
class LegendarySourceIterable(SourceIterable):
|
||||||
@@ -93,7 +97,7 @@ class LegendaryLocations(NamedTuple):
|
|||||||
config: Location
|
config: Location
|
||||||
|
|
||||||
|
|
||||||
class LegendarySource(Source):
|
class LegendarySource(ExecutableFormatSource):
|
||||||
source_id = "legendary"
|
source_id = "legendary"
|
||||||
name = _("Legendary")
|
name = _("Legendary")
|
||||||
executable_format = "legendary launch {app_name}"
|
executable_format = "legendary launch {app_name}"
|
||||||
|
|||||||
@@ -26,6 +26,8 @@ from pathlib import Path
|
|||||||
from time import time
|
from time import time
|
||||||
from typing import NamedTuple
|
from typing import NamedTuple
|
||||||
|
|
||||||
|
from urllib.parse import quote
|
||||||
|
|
||||||
from src import shared
|
from src import shared
|
||||||
from src.errors.friendly_error import FriendlyError
|
from src.errors.friendly_error import FriendlyError
|
||||||
from src.game import Game
|
from src.game import Game
|
||||||
@@ -103,7 +105,7 @@ class RetroarchSourceIterable(SourceIterable):
|
|||||||
"added": added_time,
|
"added": added_time,
|
||||||
"name": item["label"],
|
"name": item["label"],
|
||||||
"game_id": self.source.game_id_format.format(game_id=game_id),
|
"game_id": self.source.game_id_format.format(game_id=game_id),
|
||||||
"executable": self.source.executable_format.format(
|
"executable": self.source.make_executable(
|
||||||
rom_path=item["path"],
|
rom_path=item["path"],
|
||||||
core_path=core_path,
|
core_path=core_path,
|
||||||
),
|
),
|
||||||
@@ -168,14 +170,6 @@ class RetroarchSource(Source):
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
@property
|
|
||||||
def executable_format(self):
|
|
||||||
self.locations.config.resolve()
|
|
||||||
is_flatpak = self.locations.config.root.is_relative_to(shared.flatpak_dir)
|
|
||||||
base = "flatpak run org.libretro.RetroArch" if is_flatpak else "retroarch"
|
|
||||||
args = '-L "{core_path}" "{rom_path}"'
|
|
||||||
return f"{base} {args}"
|
|
||||||
|
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
super().__init__()
|
super().__init__()
|
||||||
try:
|
try:
|
||||||
@@ -214,3 +208,36 @@ class RetroarchSource(Source):
|
|||||||
return Path(f"{library_path}/steamapps/common/RetroArch")
|
return Path(f"{library_path}/steamapps/common/RetroArch")
|
||||||
# Not found
|
# Not found
|
||||||
raise ValueError("RetroArch not found in Steam library")
|
raise ValueError("RetroArch not found in Steam library")
|
||||||
|
|
||||||
|
def make_executable(self, rom_path: Path, core_path: Path) -> str:
|
||||||
|
"""
|
||||||
|
Generate an executable command from the rom path and core path,
|
||||||
|
depending on the source's location.
|
||||||
|
|
||||||
|
The format depends on RetroArch's installation method,
|
||||||
|
detected from the source config location
|
||||||
|
|
||||||
|
:param Path rom_path: the game's rom path
|
||||||
|
:param Path core_path: the game's core path
|
||||||
|
:return str: an executable command
|
||||||
|
"""
|
||||||
|
|
||||||
|
self.locations.config.resolve()
|
||||||
|
args = f'-L "{core_path}" "{rom_path}"'
|
||||||
|
|
||||||
|
# Steam RetroArch
|
||||||
|
# (Must check before Flatpak, because Steam itself can be installed as one)
|
||||||
|
if self.locations.config.root.parent.parent.name == "steamapps":
|
||||||
|
uri = "steam://run/1118310//" + quote(args) + "/"
|
||||||
|
return f"xdg-open {uri}"
|
||||||
|
|
||||||
|
# Flatpak RetroArch
|
||||||
|
if self.locations.config.root.is_relative_to(shared.flatpak_dir):
|
||||||
|
return f"flatpak run org.libretro.RetroArch {args}"
|
||||||
|
|
||||||
|
# TODO executable override for non-sandboxed sources
|
||||||
|
|
||||||
|
# Linux native RetroArch
|
||||||
|
return f"retroarch {args}"
|
||||||
|
|
||||||
|
# TODO implement for windows (needs override)
|
||||||
|
|||||||
@@ -75,10 +75,12 @@ class Source(Iterable):
|
|||||||
def is_available(self):
|
def is_available(self):
|
||||||
return sys.platform in self.available_on
|
return sys.platform in self.available_on
|
||||||
|
|
||||||
@property
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def executable_format(self) -> str:
|
def make_executable(self, *args, **kwargs) -> str:
|
||||||
"""The executable format used to construct game executables"""
|
"""
|
||||||
|
Create a game executable command.
|
||||||
|
Should be implemented by child classes.
|
||||||
|
"""
|
||||||
|
|
||||||
def __iter__(self) -> Generator[SourceIterationResult, None, None]:
|
def __iter__(self) -> Generator[SourceIterationResult, None, None]:
|
||||||
"""
|
"""
|
||||||
@@ -93,8 +95,21 @@ class Source(Iterable):
|
|||||||
return iter(self.iterable_class(self))
|
return iter(self.iterable_class(self))
|
||||||
|
|
||||||
|
|
||||||
|
class ExecutableFormatSource(Source):
|
||||||
|
"""Source class that uses a simple executable format to start games"""
|
||||||
|
|
||||||
|
@property
|
||||||
|
@abstractmethod
|
||||||
|
def executable_format(self) -> str:
|
||||||
|
"""The executable format used to construct game executables"""
|
||||||
|
|
||||||
|
def make_executable(self, *args, **kwargs) -> str:
|
||||||
|
"""Use the executable format to"""
|
||||||
|
return self.executable_format.format(args, kwargs)
|
||||||
|
|
||||||
|
|
||||||
# pylint: disable=abstract-method
|
# pylint: disable=abstract-method
|
||||||
class URLExecutableSource(Source):
|
class URLExecutableSource(ExecutableFormatSource):
|
||||||
"""Source class that use custom URLs to start games"""
|
"""Source class that use custom URLs to start games"""
|
||||||
|
|
||||||
url_format: str
|
url_format: str
|
||||||
|
|||||||
Reference in New Issue
Block a user