🎨 Various changes
- Changed source additional data to dict - Moved local cover saving into a manager - Added stub for itch cover manager
This commit is contained in:
@@ -120,7 +120,7 @@ class Importer:
|
||||
# Handle the result depending on its type
|
||||
if isinstance(iteration_result, Game):
|
||||
game = iteration_result
|
||||
additional_data = tuple()
|
||||
additional_data = {}
|
||||
elif isinstance(iteration_result, tuple):
|
||||
game, additional_data = iteration_result
|
||||
elif iteration_result is None:
|
||||
|
||||
@@ -1,20 +1,23 @@
|
||||
from pathlib import Path
|
||||
from time import time
|
||||
from typing import Optional, Generator
|
||||
|
||||
import yaml
|
||||
|
||||
from src import shared
|
||||
from src.game import Game
|
||||
from src.importer.sources.source import LinuxSource, Source, SourceIterator
|
||||
from src.importer.sources.source import (
|
||||
LinuxSource,
|
||||
Source,
|
||||
SourceIterationResult,
|
||||
SourceIterator,
|
||||
)
|
||||
from src.utils.decorators import replaced_by_env_path, replaced_by_path
|
||||
from src.utils.save_cover import resize_cover, save_cover
|
||||
|
||||
|
||||
class BottlesSourceIterator(SourceIterator):
|
||||
source: "BottlesSource"
|
||||
|
||||
def generator_builder(self) -> Generator[Optional[Game], None, None]:
|
||||
def generator_builder(self) -> SourceIterationResult:
|
||||
"""Generator method producing games"""
|
||||
|
||||
data = (self.source.location / "library.yml").read_text("utf-8")
|
||||
@@ -34,17 +37,16 @@ class BottlesSourceIterator(SourceIterator):
|
||||
}
|
||||
game = Game(values, allow_side_effects=False)
|
||||
|
||||
# Save official cover
|
||||
# Get official cover path
|
||||
bottle_path = entry["bottle"]["path"]
|
||||
image_name = entry["thumbnail"].split(":")[1]
|
||||
image_path = (
|
||||
self.source.location / "bottles" / bottle_path / "grids" / image_name
|
||||
)
|
||||
if image_path.is_file():
|
||||
save_cover(values["game_id"], resize_cover(image_path))
|
||||
additional_data = {"local_image_path": image_path}
|
||||
|
||||
# Produce game
|
||||
yield game
|
||||
yield (game, additional_data)
|
||||
|
||||
|
||||
class BottlesSource(Source):
|
||||
|
||||
@@ -4,18 +4,18 @@ from hashlib import sha256
|
||||
from json import JSONDecodeError
|
||||
from pathlib import Path
|
||||
from time import time
|
||||
from typing import Optional, TypedDict, Generator
|
||||
from typing import Optional, TypedDict
|
||||
|
||||
from src import shared
|
||||
from src.game import Game
|
||||
from src.importer.sources.source import (
|
||||
LinuxSource,
|
||||
Source,
|
||||
SourceIterationResult,
|
||||
SourceIterator,
|
||||
WindowsSource,
|
||||
)
|
||||
from src.utils.decorators import replaced_by_env_path, replaced_by_path
|
||||
from src.utils.save_cover import resize_cover, save_cover
|
||||
|
||||
|
||||
class HeroicLibraryEntry(TypedDict):
|
||||
@@ -50,7 +50,9 @@ class HeroicSourceIterator(SourceIterator):
|
||||
},
|
||||
}
|
||||
|
||||
def game_from_library_entry(self, entry: HeroicLibraryEntry) -> Optional[Game]:
|
||||
def game_from_library_entry(
|
||||
self, entry: HeroicLibraryEntry
|
||||
) -> SourceIterationResult:
|
||||
"""Helper method used to build a Game from a Heroic library entry"""
|
||||
|
||||
# Skip games that are not installed
|
||||
@@ -72,20 +74,20 @@ class HeroicSourceIterator(SourceIterator):
|
||||
),
|
||||
"executable": self.source.executable_format.format(app_name=app_name),
|
||||
}
|
||||
game = Game(values, allow_side_effects=False)
|
||||
|
||||
# Save image from the heroic cache
|
||||
# Get the image path from the heroic cache
|
||||
# Filenames are derived from the URL that heroic used to get the file
|
||||
uri: str = entry["art_square"]
|
||||
if service == "epic":
|
||||
uri += "?h=400&resize=1&w=300"
|
||||
digest = sha256(uri.encode()).hexdigest()
|
||||
image_path = self.source.location / "images-cache" / digest
|
||||
if image_path.is_file():
|
||||
save_cover(values["game_id"], resize_cover(image_path))
|
||||
additional_data = {"local_image_path": image_path}
|
||||
|
||||
return Game(values, allow_side_effects=False)
|
||||
return (game, additional_data)
|
||||
|
||||
def generator_builder(self) -> Generator[Optional[Game], None, None]:
|
||||
def generator_builder(self) -> SourceIterationResult:
|
||||
"""Generator method producing games from all the Heroic sub-sources"""
|
||||
|
||||
for sub_source in self.sub_sources.values():
|
||||
@@ -102,12 +104,12 @@ class HeroicSourceIterator(SourceIterator):
|
||||
continue
|
||||
for entry in library:
|
||||
try:
|
||||
game = self.game_from_library_entry(entry)
|
||||
result = self.game_from_library_entry(entry)
|
||||
except KeyError:
|
||||
# Skip invalid games
|
||||
logging.warning("Invalid Heroic game skipped in %s", str(file))
|
||||
continue
|
||||
yield game
|
||||
yield result
|
||||
|
||||
|
||||
class HeroicSource(Source):
|
||||
|
||||
@@ -1,23 +1,23 @@
|
||||
from sqlite3 import connect
|
||||
from pathlib import Path
|
||||
from sqlite3 import connect
|
||||
from time import time
|
||||
from typing import Optional, Generator
|
||||
|
||||
from src import shared
|
||||
from src.utils.decorators import replaced_by_env_path, replaced_by_path
|
||||
from src.game import Game
|
||||
from src.importer.sources.source import (
|
||||
Source,
|
||||
SourceIterator,
|
||||
LinuxSource,
|
||||
Source,
|
||||
SourceIterationResult,
|
||||
SourceIterator,
|
||||
WindowsSource,
|
||||
)
|
||||
from src.utils.decorators import replaced_by_env_path, replaced_by_path
|
||||
|
||||
|
||||
class ItchSourceIterator(SourceIterator):
|
||||
source: "ItchSource"
|
||||
|
||||
def generator_builder(self) -> Generator[Optional[Game], None, None]:
|
||||
def generator_builder(self) -> SourceIterationResult:
|
||||
"""Generator method producing games"""
|
||||
|
||||
# Query the database
|
||||
@@ -48,7 +48,7 @@ class ItchSourceIterator(SourceIterator):
|
||||
"game_id": self.source.game_id_format.format(game_id=row[0]),
|
||||
"executable": self.source.executable_format.format(cave_id=row[4]),
|
||||
}
|
||||
additional_data = (row[3], row[2])
|
||||
additional_data = {"itch_cover_url": row[2], "itch_still_cover_url": row[3]}
|
||||
game = Game(values, allow_side_effects=False)
|
||||
yield (game, additional_data)
|
||||
|
||||
|
||||
@@ -1,18 +1,21 @@
|
||||
from sqlite3 import connect
|
||||
from time import time
|
||||
from typing import Optional, Generator
|
||||
|
||||
from src import shared
|
||||
from src.game import Game
|
||||
from src.importer.sources.source import LinuxSource, Source, SourceIterator
|
||||
from src.importer.sources.source import (
|
||||
LinuxSource,
|
||||
Source,
|
||||
SourceIterationResult,
|
||||
SourceIterator,
|
||||
)
|
||||
from src.utils.decorators import replaced_by_path
|
||||
from src.utils.save_cover import resize_cover, save_cover
|
||||
|
||||
|
||||
class LutrisSourceIterator(SourceIterator):
|
||||
source: "LutrisSource"
|
||||
|
||||
def generator_builder(self) -> Generator[Optional[Game], None, None]:
|
||||
def generator_builder(self) -> SourceIterationResult:
|
||||
"""Generator method producing games"""
|
||||
|
||||
# Query the database
|
||||
@@ -48,13 +51,12 @@ class LutrisSourceIterator(SourceIterator):
|
||||
}
|
||||
game = Game(values, allow_side_effects=False)
|
||||
|
||||
# Save official image
|
||||
# Get official image path
|
||||
image_path = self.source.location / "covers" / "coverart" / f"{row[2]}.jpg"
|
||||
if image_path.exists():
|
||||
save_cover(values["game_id"], resize_cover(image_path))
|
||||
additional_data = {"local_image_path": image_path}
|
||||
|
||||
# Produce game
|
||||
yield game
|
||||
yield (game, additional_data)
|
||||
|
||||
|
||||
class LutrisSource(Source):
|
||||
|
||||
@@ -3,7 +3,7 @@ from abc import abstractmethod
|
||||
from collections.abc import Iterable, Iterator
|
||||
from functools import wraps
|
||||
from pathlib import Path
|
||||
from typing import Generator, Any
|
||||
from typing import Generator, Any, TypedDict
|
||||
|
||||
from src import shared
|
||||
from src.game import Game
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
import re
|
||||
from pathlib import Path
|
||||
from time import time
|
||||
from typing import Iterable, Optional, Generator
|
||||
from typing import Iterable
|
||||
|
||||
from src import shared
|
||||
from src.game import Game
|
||||
from src.importer.sources.source import (
|
||||
LinuxSource,
|
||||
Source,
|
||||
SourceIterationResult,
|
||||
SourceIterator,
|
||||
WindowsSource,
|
||||
)
|
||||
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
|
||||
|
||||
|
||||
@@ -44,7 +44,7 @@ class SteamSourceIterator(SourceIterator):
|
||||
)
|
||||
return manifests
|
||||
|
||||
def generator_builder(self) -> Generator[Optional[Game], None, None]:
|
||||
def generator_builder(self) -> SourceIterationResult:
|
||||
"""Generator method producing games"""
|
||||
appid_cache = set()
|
||||
manifests = self.get_manifests()
|
||||
@@ -85,11 +85,10 @@ class SteamSourceIterator(SourceIterator):
|
||||
/ "librarycache"
|
||||
/ f"{appid}_library_600x900.jpg"
|
||||
)
|
||||
if image_path.is_file():
|
||||
save_cover(game.game_id, resize_cover(image_path))
|
||||
additional_data = {"local_image_path": image_path}
|
||||
|
||||
# Produce game
|
||||
yield game
|
||||
yield (game, additional_data)
|
||||
|
||||
|
||||
class SteamSource(Source):
|
||||
|
||||
Reference in New Issue
Block a user