🎨 Simplified source location user override
This commit is contained in:
@@ -1,17 +1,13 @@
|
||||
from pathlib import Path
|
||||
from time import time
|
||||
from typing import Generator, Optional
|
||||
from typing import Optional
|
||||
|
||||
import yaml
|
||||
|
||||
from src import shared
|
||||
from src.game import Game
|
||||
from src.importer.sources.source import LinuxSource, Source, SourceIterator
|
||||
from src.utils.decorators import (
|
||||
replaced_by_env_path,
|
||||
replaced_by_path,
|
||||
replaced_by_schema_key,
|
||||
)
|
||||
from src.utils.decorators import replaced_by_env_path, replaced_by_path
|
||||
from src.utils.save_cover import resize_cover, save_cover
|
||||
|
||||
|
||||
@@ -55,6 +51,7 @@ class BottlesSource(Source):
|
||||
"""Generic Bottles source"""
|
||||
|
||||
name = "Bottles"
|
||||
location_key = "bottles-location"
|
||||
|
||||
def __iter__(self) -> SourceIterator:
|
||||
return BottlesSourceIterator(self)
|
||||
@@ -65,7 +62,7 @@ class BottlesLinuxSource(BottlesSource, LinuxSource):
|
||||
executable_format = 'xdg-open bottles:run/"{bottle_name}"/"{game_name}"'
|
||||
|
||||
@property
|
||||
@replaced_by_schema_key("bottles-location")
|
||||
@Source.replaced_by_schema_key()
|
||||
@replaced_by_path("~/.var/app/com.usebottles.bottles/data/bottles/")
|
||||
@replaced_by_env_path("XDG_DATA_HOME", "bottles/")
|
||||
@replaced_by_path("~/.local/share/bottles/")
|
||||
|
||||
@@ -4,7 +4,7 @@ from hashlib import sha256
|
||||
from json import JSONDecodeError
|
||||
from pathlib import Path
|
||||
from time import time
|
||||
from typing import Generator, Optional, TypedDict
|
||||
from typing import Optional, TypedDict
|
||||
|
||||
from src import shared
|
||||
from src.game import Game
|
||||
@@ -14,11 +14,7 @@ from src.importer.sources.source import (
|
||||
SourceIterator,
|
||||
WindowsSource,
|
||||
)
|
||||
from src.utils.decorators import (
|
||||
replaced_by_env_path,
|
||||
replaced_by_path,
|
||||
replaced_by_schema_key,
|
||||
)
|
||||
from src.utils.decorators import replaced_by_env_path, replaced_by_path
|
||||
from src.utils.save_cover import resize_cover, save_cover
|
||||
|
||||
|
||||
@@ -118,6 +114,7 @@ class HeroicSource(Source):
|
||||
"""Generic heroic games launcher source"""
|
||||
|
||||
name = "Heroic"
|
||||
location_key = "heroic-location"
|
||||
|
||||
@property
|
||||
def game_id_format(self) -> str:
|
||||
@@ -133,7 +130,7 @@ class HeroicLinuxSource(HeroicSource, LinuxSource):
|
||||
executable_format = "xdg-open heroic://launch/{app_name}"
|
||||
|
||||
@property
|
||||
@replaced_by_schema_key("heroic-location")
|
||||
@Source.replaced_by_schema_key()
|
||||
@replaced_by_path("~/.var/app/com.heroicgameslauncher.hgl/config/heroic/")
|
||||
@replaced_by_env_path("XDG_CONFIG_HOME", "heroic/")
|
||||
@replaced_by_path("~/.config/heroic/")
|
||||
@@ -146,7 +143,7 @@ class HeroicWindowsSource(HeroicSource, WindowsSource):
|
||||
executable_format = "start heroic://launch/{app_name}"
|
||||
|
||||
@property
|
||||
@replaced_by_schema_key("heroic-location")
|
||||
@Source.replaced_by_schema_key()
|
||||
@replaced_by_env_path("appdata", "heroic/")
|
||||
def location(self) -> Path:
|
||||
raise FileNotFoundError()
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
from sqlite3 import connect
|
||||
from time import time
|
||||
from typing import Optional, Generator
|
||||
from typing import Optional
|
||||
|
||||
from src import shared
|
||||
from src.game import Game
|
||||
from src.importer.sources.source import LinuxSource, Source, SourceIterator
|
||||
from src.utils.decorators import replaced_by_path, replaced_by_schema_key
|
||||
from src.utils.decorators import replaced_by_path
|
||||
from src.utils.save_cover import resize_cover, save_cover
|
||||
|
||||
|
||||
@@ -61,6 +61,7 @@ class LutrisSource(Source):
|
||||
"""Generic lutris source"""
|
||||
|
||||
name = "Lutris"
|
||||
location_key = "lutris-location"
|
||||
|
||||
@property
|
||||
def game_id_format(self):
|
||||
@@ -75,7 +76,7 @@ class LutrisLinuxSource(LutrisSource, LinuxSource):
|
||||
executable_format = "xdg-open lutris:rungameid/{game_id}"
|
||||
|
||||
@property
|
||||
@replaced_by_schema_key("lutris-location")
|
||||
@Source.replaced_by_schema_key()
|
||||
@replaced_by_path("~/.var/app/net.lutris.Lutris/data/lutris/")
|
||||
@replaced_by_path("~/.local/share/lutris/")
|
||||
def location(self):
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
import sys
|
||||
from abc import abstractmethod
|
||||
from collections.abc import Iterable, Iterator
|
||||
from functools import wraps
|
||||
from pathlib import Path
|
||||
from typing import Optional, Generator
|
||||
from typing import Generator, Optional
|
||||
|
||||
from src import shared
|
||||
from src.game import Game
|
||||
from src.utils.decorators import replaced_by_path
|
||||
|
||||
|
||||
class SourceIterator(Iterator):
|
||||
@@ -40,11 +43,13 @@ class Source(Iterable):
|
||||
|
||||
name: str
|
||||
variant: str
|
||||
location_key: str
|
||||
available_on: set[str]
|
||||
|
||||
def __init__(self) -> None:
|
||||
super().__init__()
|
||||
self.available_on = set()
|
||||
self.update_location_schema_key()
|
||||
|
||||
@property
|
||||
def full_name(self) -> str:
|
||||
@@ -76,6 +81,28 @@ class Source(Iterable):
|
||||
return False
|
||||
return sys.platform in self.available_on
|
||||
|
||||
def update_location_schema_key(self):
|
||||
"""Update the schema value for this source's location if possible"""
|
||||
try:
|
||||
location = self.location
|
||||
except FileNotFoundError:
|
||||
return
|
||||
shared.schema.set_string(self.location_key, location)
|
||||
|
||||
@classmethod
|
||||
def replaced_by_schema_key(cls): # Decorator builder
|
||||
"""Replace the returned path with schema's path if valid"""
|
||||
|
||||
def decorator(original_function): # Built decorator (closure)
|
||||
@wraps(original_function)
|
||||
def wrapper(*args, **kwargs): # func's override
|
||||
override = shared.schema.get_string(cls.location_key)
|
||||
return replaced_by_path(override)(original_function)(*args, **kwargs)
|
||||
|
||||
return wrapper
|
||||
|
||||
return decorator
|
||||
|
||||
@property
|
||||
@abstractmethod
|
||||
def location(self) -> Path:
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import re
|
||||
from pathlib import Path
|
||||
from time import time
|
||||
from typing import Iterable, Optional, Generator
|
||||
from typing import Iterable, Optional
|
||||
|
||||
from src import shared
|
||||
from src.game import Game
|
||||
@@ -11,11 +11,7 @@ from src.importer.sources.source import (
|
||||
SourceIterator,
|
||||
WindowsSource,
|
||||
)
|
||||
from src.utils.decorators import (
|
||||
replaced_by_env_path,
|
||||
replaced_by_path,
|
||||
replaced_by_schema_key,
|
||||
)
|
||||
from src.utils.decorators import replaced_by_env_path, replaced_by_path
|
||||
from src.utils.save_cover import resize_cover, save_cover
|
||||
from src.utils.steam import SteamHelper, SteamInvalidManifestError
|
||||
|
||||
@@ -98,6 +94,7 @@ class SteamSourceIterator(SourceIterator):
|
||||
|
||||
class SteamSource(Source):
|
||||
name = "Steam"
|
||||
location_key = "steam-location"
|
||||
|
||||
def __iter__(self):
|
||||
return SteamSourceIterator(source=self)
|
||||
@@ -108,7 +105,7 @@ class SteamLinuxSource(SteamSource, LinuxSource):
|
||||
executable_format = "xdg-open steam://rungameid/{game_id}"
|
||||
|
||||
@property
|
||||
@replaced_by_schema_key("steam-location")
|
||||
@Source.replaced_by_schema_key()
|
||||
@replaced_by_path("~/.var/app/com.valvesoftware.Steam/data/Steam/")
|
||||
@replaced_by_env_path("XDG_DATA_HOME", "Steam/")
|
||||
@replaced_by_path("~/.steam/")
|
||||
@@ -122,7 +119,7 @@ class SteamWindowsSource(SteamSource, WindowsSource):
|
||||
executable_format = "start steam://rungameid/{game_id}"
|
||||
|
||||
@property
|
||||
@replaced_by_schema_key("steam-location")
|
||||
@Source.replaced_by_schema_key()
|
||||
@replaced_by_env_path("programfiles(x86)", "Steam")
|
||||
def location(self):
|
||||
raise FileNotFoundError()
|
||||
|
||||
@@ -1,24 +1,7 @@
|
||||
"""
|
||||
A decorator takes a callable A and returns a callable B that will override the name of A.
|
||||
A decorator with arguments returns a closure decorator having access to the arguments.
|
||||
|
||||
Example usage for the location decorators:
|
||||
|
||||
class MyClass():
|
||||
@cached_property
|
||||
@replaced_by_schema_key(key="source-location")
|
||||
@replaced_by_path(override="/somewhere/that/doesnt/exist")
|
||||
@replaced_by_path(override="/somewhere/that/exists")
|
||||
def location(self):
|
||||
return None
|
||||
"""
|
||||
|
||||
from pathlib import Path
|
||||
from os import PathLike, environ
|
||||
from functools import wraps
|
||||
|
||||
from src import shared
|
||||
|
||||
|
||||
def replaced_by_path(override: PathLike): # Decorator builder
|
||||
"""Replace the method's returned path with the override
|
||||
@@ -37,24 +20,6 @@ def replaced_by_path(override: PathLike): # Decorator builder
|
||||
return decorator
|
||||
|
||||
|
||||
def replaced_by_schema_key(key: str): # Decorator builder
|
||||
"""Replace the method's returned path with the path pointed by the key
|
||||
if it exists on disk"""
|
||||
|
||||
def decorator(original_function): # Built decorator (closure)
|
||||
@wraps(original_function)
|
||||
def wrapper(*args, **kwargs): # func's override
|
||||
try:
|
||||
override = shared.schema.get_string(key)
|
||||
except Exception: # pylint: disable=broad-exception-caught
|
||||
return original_function(*args, **kwargs)
|
||||
return replaced_by_path(override)(original_function)(*args, **kwargs)
|
||||
|
||||
return wrapper
|
||||
|
||||
return decorator
|
||||
|
||||
|
||||
def replaced_by_env_path(env_var_name: str, suffix: PathLike | None = None):
|
||||
"""Replace the method's returned path with a path whose root is the env variable"""
|
||||
|
||||
|
||||
Reference in New Issue
Block a user