🚧 Various fixes
- Platform-dependent sources - Added heroic schema keys - Moved location and is_installed to Source
This commit is contained in:
@@ -44,8 +44,14 @@
|
|||||||
<default>true</default>
|
<default>true</default>
|
||||||
</key>
|
</key>
|
||||||
<key name="heroic-location" type="s">
|
<key name="heroic-location" type="s">
|
||||||
|
<default>"~/.config/heroic/"</default>
|
||||||
|
</key>
|
||||||
|
<key name="heroic-flatpak-location" type="s">
|
||||||
<default>"~/.var/app/com.heroicgameslauncher.hgl/config/heroic/"</default>
|
<default>"~/.var/app/com.heroicgameslauncher.hgl/config/heroic/"</default>
|
||||||
</key>
|
</key>
|
||||||
|
<key name="heroic-windows-location" type="s">
|
||||||
|
<default>""</default>
|
||||||
|
</key>
|
||||||
<key name="heroic-import-epic" type="b">
|
<key name="heroic-import-epic" type="b">
|
||||||
<default>true</default>
|
<default>true</default>
|
||||||
</key>
|
</key>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import json
|
import json
|
||||||
from abc import abstractmethod
|
import logging
|
||||||
from hashlib import sha256
|
from hashlib import sha256
|
||||||
from json import JSONDecodeError
|
from json import JSONDecodeError
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
@@ -8,7 +8,7 @@ from typing import Generator, Optional, TypedDict
|
|||||||
|
|
||||||
from src import shared
|
from src import shared
|
||||||
from src.game import Game
|
from src.game import Game
|
||||||
from src.importer.sources.source import Source, SourceIterator
|
from src.importer.sources.source import NTSource, PosixSource, Source, SourceIterator
|
||||||
from src.utils.decorators import (
|
from src.utils.decorators import (
|
||||||
replaced_by_env_path,
|
replaced_by_env_path,
|
||||||
replaced_by_path,
|
replaced_by_path,
|
||||||
@@ -87,9 +87,9 @@ class HeroicSourceIterator(SourceIterator):
|
|||||||
|
|
||||||
def sub_sources_generator(self):
|
def sub_sources_generator(self):
|
||||||
"""Generator method producing games from all the Heroic sub-sources"""
|
"""Generator method producing games from all the Heroic sub-sources"""
|
||||||
for key, sub_source in self.sub_sources.items():
|
for _key, sub_source in self.sub_sources.items():
|
||||||
# Skip disabled sub-sources
|
# Skip disabled sub-sources
|
||||||
if not shared.schema.get_boolean("heroic-import-" + key):
|
if not shared.schema.get_boolean("heroic-import-" + sub_source["service"]):
|
||||||
continue
|
continue
|
||||||
# Load games from JSON
|
# Load games from JSON
|
||||||
try:
|
try:
|
||||||
@@ -124,32 +124,19 @@ class HeroicSource(Source):
|
|||||||
name = "Heroic"
|
name = "Heroic"
|
||||||
executable_format = "xdg-open heroic://launch/{app_name}"
|
executable_format = "xdg-open heroic://launch/{app_name}"
|
||||||
|
|
||||||
@property
|
|
||||||
@abstractmethod
|
|
||||||
def location(self) -> Path:
|
|
||||||
pass
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def game_id_format(self) -> str:
|
def game_id_format(self) -> str:
|
||||||
"""The string format used to construct game IDs"""
|
"""The string format used to construct game IDs"""
|
||||||
return self.name.lower() + "_{service}_{game_id}"
|
return self.name.lower() + "_{service}_{game_id}"
|
||||||
|
|
||||||
@property
|
|
||||||
def is_installed(self):
|
|
||||||
# pylint: disable=pointless-statement
|
|
||||||
try:
|
|
||||||
self.location
|
|
||||||
except FileNotFoundError:
|
|
||||||
return False
|
|
||||||
return True
|
|
||||||
|
|
||||||
def __iter__(self):
|
def __iter__(self):
|
||||||
return HeroicSourceIterator(source=self)
|
return HeroicSourceIterator(source=self)
|
||||||
|
|
||||||
|
|
||||||
class HeroicNativeSource(HeroicSource):
|
class HeroicNativeSource(HeroicSource, PosixSource):
|
||||||
variant = "native"
|
variant = "native"
|
||||||
|
|
||||||
|
@property
|
||||||
@replaced_by_schema_key("heroic-location")
|
@replaced_by_schema_key("heroic-location")
|
||||||
@replaced_by_env_path("XDG_CONFIG_HOME", "heroic/")
|
@replaced_by_env_path("XDG_CONFIG_HOME", "heroic/")
|
||||||
@replaced_by_path("~/.config/heroic/")
|
@replaced_by_path("~/.config/heroic/")
|
||||||
@@ -157,19 +144,21 @@ class HeroicNativeSource(HeroicSource):
|
|||||||
raise FileNotFoundError()
|
raise FileNotFoundError()
|
||||||
|
|
||||||
|
|
||||||
class HeroicFlatpakSource(HeroicSource):
|
class HeroicFlatpakSource(HeroicSource, PosixSource):
|
||||||
variant = "flatpak"
|
variant = "flatpak"
|
||||||
|
|
||||||
|
@property
|
||||||
@replaced_by_schema_key("heroic-flatpak-location")
|
@replaced_by_schema_key("heroic-flatpak-location")
|
||||||
@replaced_by_path("~/.var/app/com.heroicgameslauncher.hgl/config/heroic/")
|
@replaced_by_path("~/.var/app/com.heroicgameslauncher.hgl/config/heroic/")
|
||||||
def location(self) -> Path:
|
def location(self) -> Path:
|
||||||
raise FileNotFoundError()
|
raise FileNotFoundError()
|
||||||
|
|
||||||
|
|
||||||
class HeroicWindowsSource(HeroicSource):
|
class HeroicWindowsSource(HeroicSource, NTSource):
|
||||||
variant = "windows"
|
variant = "windows"
|
||||||
executable_format = "start heroic://launch/{app_name}"
|
executable_format = "start heroic://launch/{app_name}"
|
||||||
|
|
||||||
|
@property
|
||||||
@replaced_by_schema_key("heroic-windows-location")
|
@replaced_by_schema_key("heroic-windows-location")
|
||||||
@replaced_by_env_path("appdata", "heroic/")
|
@replaced_by_env_path("appdata", "heroic/")
|
||||||
def location(self) -> Path:
|
def location(self) -> Path:
|
||||||
|
|||||||
@@ -1,11 +1,9 @@
|
|||||||
from abc import abstractmethod
|
|
||||||
from pathlib import Path
|
|
||||||
from sqlite3 import connect
|
from sqlite3 import connect
|
||||||
from time import time
|
from time import time
|
||||||
|
|
||||||
from src import shared
|
from src import shared
|
||||||
from src.game import Game
|
from src.game import Game
|
||||||
from src.importer.sources.source import Source, SourceIterator
|
from src.importer.sources.source import PosixSource, Source, SourceIterator
|
||||||
from src.utils.decorators import replaced_by_path, replaced_by_schema_key
|
from src.utils.decorators import replaced_by_path, replaced_by_schema_key
|
||||||
from src.utils.save_cover import resize_cover, save_cover
|
from src.utils.save_cover import resize_cover, save_cover
|
||||||
|
|
||||||
@@ -78,29 +76,15 @@ class LutrisSource(Source):
|
|||||||
name = "Lutris"
|
name = "Lutris"
|
||||||
executable_format = "xdg-open lutris:rungameid/{game_id}"
|
executable_format = "xdg-open lutris:rungameid/{game_id}"
|
||||||
|
|
||||||
@property
|
|
||||||
@abstractmethod
|
|
||||||
def location(self) -> Path:
|
|
||||||
pass
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def game_id_format(self):
|
def game_id_format(self):
|
||||||
return super().game_id_format + "_{game_internal_id}"
|
return super().game_id_format + "_{game_internal_id}"
|
||||||
|
|
||||||
@property
|
|
||||||
def is_installed(self):
|
|
||||||
# pylint: disable=pointless-statement
|
|
||||||
try:
|
|
||||||
self.location
|
|
||||||
except FileNotFoundError:
|
|
||||||
return False
|
|
||||||
return True
|
|
||||||
|
|
||||||
def __iter__(self):
|
def __iter__(self):
|
||||||
return LutrisSourceIterator(source=self)
|
return LutrisSourceIterator(source=self)
|
||||||
|
|
||||||
|
|
||||||
class LutrisNativeSource(LutrisSource):
|
class LutrisNativeSource(LutrisSource, PosixSource):
|
||||||
variant = "native"
|
variant = "native"
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@@ -110,7 +94,7 @@ class LutrisNativeSource(LutrisSource):
|
|||||||
raise FileNotFoundError()
|
raise FileNotFoundError()
|
||||||
|
|
||||||
|
|
||||||
class LutrisFlatpakSource(LutrisSource):
|
class LutrisFlatpakSource(LutrisSource, PosixSource):
|
||||||
variant = "flatpak"
|
variant = "flatpak"
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
|
import os
|
||||||
from abc import abstractmethod
|
from abc import abstractmethod
|
||||||
from collections.abc import Iterable, Iterator
|
from collections.abc import Iterable, Iterator
|
||||||
|
from pathlib import Path
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
from src.game import Game
|
from src.game import Game
|
||||||
@@ -30,6 +32,11 @@ class Source(Iterable):
|
|||||||
|
|
||||||
name: str
|
name: str
|
||||||
variant: str
|
variant: str
|
||||||
|
available_on: set[str]
|
||||||
|
|
||||||
|
def __init__(self) -> None:
|
||||||
|
super().__init__()
|
||||||
|
self.available_on = set()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def full_name(self) -> str:
|
def full_name(self) -> str:
|
||||||
@@ -52,16 +59,41 @@ class Source(Iterable):
|
|||||||
"""The string format used to construct game IDs"""
|
"""The string format used to construct game IDs"""
|
||||||
return self.name.lower() + "_{game_id}"
|
return self.name.lower() + "_{game_id}"
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_installed(self):
|
||||||
|
# pylint: disable=pointless-statement
|
||||||
|
try:
|
||||||
|
self.location
|
||||||
|
except FileNotFoundError:
|
||||||
|
return False
|
||||||
|
return os.name in self.available_on
|
||||||
|
|
||||||
|
@property
|
||||||
|
@abstractmethod
|
||||||
|
def location(self) -> Path:
|
||||||
|
"""The source's location on disk"""
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def executable_format(self) -> str:
|
def executable_format(self) -> str:
|
||||||
"""The executable format used to construct game executables"""
|
"""The executable format used to construct game executables"""
|
||||||
|
|
||||||
@property
|
|
||||||
@abstractmethod
|
|
||||||
def is_installed(self) -> bool:
|
|
||||||
"""Whether the source is detected as installed"""
|
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def __iter__(self) -> SourceIterator:
|
def __iter__(self) -> SourceIterator:
|
||||||
"""Get the source's iterator, to use in for loops"""
|
"""Get the source's iterator, to use in for loops"""
|
||||||
|
|
||||||
|
|
||||||
|
class NTSource(Source):
|
||||||
|
"""Mixin for sources available on Windows"""
|
||||||
|
|
||||||
|
def __init__(self) -> None:
|
||||||
|
super().__init__()
|
||||||
|
self.available_on.add("nt")
|
||||||
|
|
||||||
|
|
||||||
|
class PosixSource(Source):
|
||||||
|
"""Mixin for sources available on POXIX-compliant systems"""
|
||||||
|
|
||||||
|
def __init__(self) -> None:
|
||||||
|
super().__init__()
|
||||||
|
self.available_on.add("posix")
|
||||||
|
|||||||
@@ -1,12 +1,11 @@
|
|||||||
import re
|
import re
|
||||||
from abc import abstractmethod
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from time import time
|
from time import time
|
||||||
from typing import Iterator
|
from typing import Iterator
|
||||||
|
|
||||||
from src import shared
|
from src import shared
|
||||||
from src.game import Game
|
from src.game import Game
|
||||||
from src.importer.sources.source import Source, SourceIterator
|
from src.importer.sources.source import NTSource, PosixSource, Source, SourceIterator
|
||||||
from src.utils.decorators import (
|
from src.utils.decorators import (
|
||||||
replaced_by_env_path,
|
replaced_by_env_path,
|
||||||
replaced_by_path,
|
replaced_by_path,
|
||||||
@@ -94,25 +93,11 @@ class SteamSource(Source):
|
|||||||
name = "Steam"
|
name = "Steam"
|
||||||
executable_format = "xdg-open steam://rungameid/{game_id}"
|
executable_format = "xdg-open steam://rungameid/{game_id}"
|
||||||
|
|
||||||
@property
|
|
||||||
@abstractmethod
|
|
||||||
def location(self) -> Path:
|
|
||||||
pass
|
|
||||||
|
|
||||||
@property
|
|
||||||
def is_installed(self):
|
|
||||||
# pylint: disable=pointless-statement
|
|
||||||
try:
|
|
||||||
self.location
|
|
||||||
except FileNotFoundError:
|
|
||||||
return False
|
|
||||||
return True
|
|
||||||
|
|
||||||
def __iter__(self):
|
def __iter__(self):
|
||||||
return SteamSourceIterator(source=self)
|
return SteamSourceIterator(source=self)
|
||||||
|
|
||||||
|
|
||||||
class SteamNativeSource(SteamSource):
|
class SteamNativeSource(SteamSource, PosixSource):
|
||||||
variant = "native"
|
variant = "native"
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@@ -124,7 +109,7 @@ class SteamNativeSource(SteamSource):
|
|||||||
raise FileNotFoundError()
|
raise FileNotFoundError()
|
||||||
|
|
||||||
|
|
||||||
class SteamFlatpakSource(SteamSource):
|
class SteamFlatpakSource(SteamSource, PosixSource):
|
||||||
variant = "flatpak"
|
variant = "flatpak"
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@@ -134,7 +119,7 @@ class SteamFlatpakSource(SteamSource):
|
|||||||
raise FileNotFoundError()
|
raise FileNotFoundError()
|
||||||
|
|
||||||
|
|
||||||
class SteamWindowsSource(SteamSource):
|
class SteamWindowsSource(SteamSource, NTSource):
|
||||||
variant = "windows"
|
variant = "windows"
|
||||||
executable_format = "start steam://rungameid/{game_id}"
|
executable_format = "start steam://rungameid/{game_id}"
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user