Initial importer work done

This commit is contained in:
GeoffreyCoulaud
2023-05-09 11:25:15 +02:00
parent 48ca1d938f
commit 78b91c0d52
6 changed files with 70 additions and 41 deletions

View File

@@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<schemalist gettext-domain="cartridges"> <schemalist gettext-domain="cartridges">
<schema id="hu.kramo.Cartridges" path="/hu/kramo/Cartridges/"> <schema id="hu.kramo.Cartridges" path="/hu/kramo/Cartridges/">
<key name="exit-after-launch" type="b"> <key name="exit-after-launch" type="b">
<default>false</default> <default>false</default>
</key> </key>
<key name="cover-launches-game" type="b"> <key name="cover-launches-game" type="b">
<default>false</default> <default>false</default>
</key> </key>
@@ -25,6 +25,12 @@
<key name="lutris-cache-location" type="s"> <key name="lutris-cache-location" type="s">
<default>"~/.var/app/net.lutris.Lutris/cache/lutris"</default> <default>"~/.var/app/net.lutris.Lutris/cache/lutris"</default>
</key> </key>
<key name="lutris-flatpak-location" type="s">
<default>"~/.var/app/net.lutris.Lutris/data/lutris/"</default>
</key>
<key name="lutris-flatpak-cache-location" type="s">
<default>"~/.var/app/net.lutris.Lutris/cache/lutris"</default>
</key>
<key name="lutris-import-steam" type="b"> <key name="lutris-import-steam" type="b">
<default>false</default> <default>false</default>
</key> </key>
@@ -34,19 +40,19 @@
<key name="heroic-location" type="s"> <key name="heroic-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-import-epic" type="b"> <key name="heroic-import-epic" type="b">
<default>true</default> <default>true</default>
</key> </key>
<key name="heroic-import-gog" type="b"> <key name="heroic-import-gog" type="b">
<default>true</default> <default>true</default>
</key> </key>
<key name="heroic-import-sideload" type="b"> <key name="heroic-import-sideload" type="b">
<default>true</default> <default>true</default>
</key> </key>
<key name="bottles" type="b"> <key name="bottles" type="b">
<default>true</default> <default>true</default>
</key> </key>
<key name="bottles-location" type="s"> <key name="bottles-location" type="s">
<default>"~/.var/app/com.usebottles.bottles/data/bottles/"</default> <default>"~/.var/app/com.usebottles.bottles/data/bottles/"</default>
</key> </key>
<key name="itch" type="b"> <key name="itch" type="b">
@@ -67,7 +73,7 @@
<key name="sgdb-animated" type="b"> <key name="sgdb-animated" type="b">
<default>false</default> <default>false</default>
</key> </key>
</schema> </schema>
<schema id="hu.kramo.Cartridges.State" path="/hu/kramo/Cartridges/State/"> <schema id="hu.kramo.Cartridges.State" path="/hu/kramo/Cartridges/State/">
<key name="width" type="i"> <key name="width" type="i">
<default>1110</default> <default>1110</default>
@@ -80,11 +86,11 @@
</key> </key>
<key name="sort-mode" type="s"> <key name="sort-mode" type="s">
<choices> <choices>
<choice value="a-z"/> <choice value="a-z" />
<choice value="z-a"/> <choice value="z-a" />
<choice value="newest"/> <choice value="newest" />
<choice value="oldest"/> <choice value="oldest" />
<choice value="last_played"/> <choice value="last_played" />
</choices> </choices>
<default>"a-z"</default> <default>"a-z"</default>
</key> </key>

View File

@@ -74,21 +74,30 @@ class Importer:
# Scan sources in threads # Scan sources in threads
threads = [] threads = []
for source in self.sources: for source in self.sources:
t = Thread(target=self.__import_source, args=tuple(source,)) # fmt: skip print(f"{source.full_name}, installed: {source.is_installed}") # ! DEBUG
if not source.is_installed:
continue
t = Thread(target=self.__import_source, args=tuple([source])) # fmt: skip
threads.append(t) threads.append(t)
t.start() t.start()
for t in threads: for t in threads:
t.join() t.join()
# Save games
for game in self.games:
game.save()
self.close_dialog() self.close_dialog()
def __import_source(self, *args, **kwargs): def __import_source(self, *args, **kwargs):
"""Source import thread entry point""" """Source import thread entry point"""
# TODO error handling in source iteration # TODO error handling in source iteration
# TODO add SGDB image (move to a game manager)
source, *rest = args source, *rest = args
iterator = source.__iter__() iterator = source.__iter__()
with self.progress_lock: with self.progress_lock:
self.counts[source.id]["total"] = len(iterator) self.counts[source.id]["total"] = iterator.__len__()
for game in iterator: for game in iterator:
with self.games_lock: with self.games_lock:
self.games.add(game) self.games.add(game)
@@ -96,5 +105,3 @@ class Importer:
if not game.blacklisted: if not game.blacklisted:
self.counts[source.id]["done"] += 1 self.counts[source.id]["done"] += 1
self.update_progressbar() self.update_progressbar()
# TODO add SGDB image (move to a game manager)
exit(0)

View File

@@ -1,9 +1,8 @@
from abc import abstractmethod from abc import abstractmethod
from collections.abc import Iterable, Iterator from collections.abc import Iterable, Iterator, Sized
from enum import IntEnum, auto
class SourceIterator(Iterator): class SourceIterator(Iterator, Sized):
"""Data producer for a source of games""" """Data producer for a source of games"""
source = None source = None
@@ -67,6 +66,12 @@ class Source(Iterable):
"""The executable format used to construct game executables""" """The executable format used to construct game executables"""
pass pass
@property
@abstractmethod
def is_installed(self):
"""Whether the source is detected as installed"""
pass
@abstractmethod @abstractmethod
def __iter__(self): def __iter__(self):
"""Get the source's iterator, to use in for loops""" """Get the source's iterator, to use in for loops"""

View File

@@ -1,4 +1,4 @@
from functools import cached_property, cache from functools import cache
from sqlite3 import connect from sqlite3 import connect
from time import time from time import time
@@ -65,7 +65,6 @@ class LutrisSourceIterator(SourceIterator):
raise e raise e
# Create game # Create game
row = self.__next_row()
values = { values = {
"added": int(time()), "added": int(time()),
"hidden": row[4], "hidden": row[4],
@@ -98,8 +97,18 @@ class LutrisSource(Source):
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}"
def __init__(self, win): @property
super().__init__(win) def is_installed(self):
try:
self.location
self.cache_location
except FileNotFoundError:
return False
else:
return True
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
def __iter__(self): def __iter__(self):
return LutrisSourceIterator(source=self) return LutrisSourceIterator(source=self)
@@ -110,13 +119,13 @@ class LutrisNativeSource(LutrisSource):
variant = "native" variant = "native"
@cached_property @property
@replaced_by_schema_key("lutris-location") @replaced_by_schema_key("lutris-location")
@replaced_by_path("~/.local/share/lutris/") @replaced_by_path("~/.local/share/lutris/")
def location(self): def location(self):
raise FileNotFoundError() raise FileNotFoundError()
@cached_property @property
@replaced_by_schema_key("lutris-cache-location") @replaced_by_schema_key("lutris-cache-location")
@replaced_by_path("~/.local/share/lutris/covers") @replaced_by_path("~/.local/share/lutris/covers")
def cache_location(self): def cache_location(self):
@@ -128,13 +137,13 @@ class LutrisFlatpakSource(LutrisSource):
variant = "flatpak" variant = "flatpak"
@cached_property @property
@replaced_by_schema_key("lutris-flatpak-location") @replaced_by_schema_key("lutris-flatpak-location")
@replaced_by_path("~/.var/app/net.lutris.Lutris/data/lutris") @replaced_by_path("~/.var/app/net.lutris.Lutris/data/lutris")
def location(self): def location(self):
raise FileNotFoundError() raise FileNotFoundError()
@cached_property @property
@replaced_by_schema_key("lutris-flatpak-cache-location") @replaced_by_schema_key("lutris-flatpak-cache-location")
@replaced_by_path("~/.var/app/net.lutris.Lutris/data/lutris/covers") @replaced_by_path("~/.var/app/net.lutris.Lutris/data/lutris/covers")
def cache_location(self): def cache_location(self):

View File

@@ -149,8 +149,8 @@ class CartridgesApplication(Adw.Application):
def on_import_action(self, *_args): def on_import_action(self, *_args):
importer = Importer(self.win) importer = Importer(self.win)
if self.win.schema.get_boolean("lutris"): if self.win.schema.get_boolean("lutris"):
importer.add_source(LutrisNativeSource) importer.add_source(LutrisNativeSource(self.win))
importer.add_source(LutrisFlatpakSource) importer.add_source(LutrisFlatpakSource(self.win))
importer.import_games() importer.import_games()
def on_remove_game_action(self, *_args): def on_remove_game_action(self, *_args):

View File

@@ -19,7 +19,8 @@ from functools import wraps
def replaced_by_path(path: PathLike): # Decorator builder def replaced_by_path(path: PathLike): # Decorator builder
"""Replace the method's returned path with the override if the override exists on disk""" """Replace the method's returned path with the override
if the override exists on disk"""
def decorator(original_function): # Built decorator (closure) def decorator(original_function): # Built decorator (closure)
@wraps(original_function) @wraps(original_function)
@@ -36,7 +37,8 @@ def replaced_by_path(path: PathLike): # Decorator builder
def replaced_by_schema_key(key: str): # Decorator builder 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""" """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) def decorator(original_function): # Built decorator (closure)
@wraps(original_function) @wraps(original_function)
@@ -47,7 +49,7 @@ def replaced_by_schema_key(key: str): # Decorator builder
except Exception: except Exception:
return original_function(*args, **kwargs) return original_function(*args, **kwargs)
else: else:
return replaced_by_path(override)(*args, **kwargs) return replaced_by_path(override)(original_function)(*args, **kwargs)
return wrapper return wrapper