Compare commits
4 Commits
v2.1
...
add-import
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
927275cda9 | ||
|
|
df9f7dbca8 | ||
|
|
6c6fd29faa | ||
|
|
d252b6b97d |
@@ -18,7 +18,9 @@
|
|||||||
#
|
#
|
||||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
import json
|
||||||
import logging
|
import logging
|
||||||
|
from shutil import copytree, rmtree
|
||||||
|
|
||||||
from gi.repository import Adw, GLib, Gtk
|
from gi.repository import Adw, GLib, Gtk
|
||||||
|
|
||||||
@@ -26,8 +28,15 @@ from src import shared
|
|||||||
from src.errors.error_producer import ErrorProducer
|
from src.errors.error_producer import ErrorProducer
|
||||||
from src.errors.friendly_error import FriendlyError
|
from src.errors.friendly_error import FriendlyError
|
||||||
from src.game import Game
|
from src.game import Game
|
||||||
|
from src.importer.sources.bottles_source import BottlesSource
|
||||||
|
from src.importer.sources.flatpak_source import FlatpakSource
|
||||||
|
from src.importer.sources.heroic_source import HeroicSource
|
||||||
|
from src.importer.sources.itch_source import ItchSource
|
||||||
|
from src.importer.sources.legendary_source import LegendarySource
|
||||||
from src.importer.sources.location import UnresolvableLocationError
|
from src.importer.sources.location import UnresolvableLocationError
|
||||||
|
from src.importer.sources.lutris_source import LutrisSource
|
||||||
from src.importer.sources.source import Source
|
from src.importer.sources.source import Source
|
||||||
|
from src.importer.sources.steam_source import SteamSource
|
||||||
from src.store.managers.async_manager import AsyncManager
|
from src.store.managers.async_manager import AsyncManager
|
||||||
from src.store.pipeline import Pipeline
|
from src.store.pipeline import Pipeline
|
||||||
from src.utils.task import Task
|
from src.utils.task import Task
|
||||||
@@ -53,6 +62,20 @@ class Importer(ErrorProducer):
|
|||||||
super().__init__()
|
super().__init__()
|
||||||
self.game_pipelines = set()
|
self.game_pipelines = set()
|
||||||
self.sources = set()
|
self.sources = set()
|
||||||
|
if shared.schema.get_boolean("lutris"):
|
||||||
|
self.sources.add(LutrisSource())
|
||||||
|
if shared.schema.get_boolean("steam"):
|
||||||
|
self.sources.add(SteamSource())
|
||||||
|
if shared.schema.get_boolean("heroic"):
|
||||||
|
self.sources.add(HeroicSource())
|
||||||
|
if shared.schema.get_boolean("bottles"):
|
||||||
|
self.sources.add(BottlesSource())
|
||||||
|
if shared.schema.get_boolean("flatpak"):
|
||||||
|
self.sources.add(FlatpakSource())
|
||||||
|
if shared.schema.get_boolean("itch"):
|
||||||
|
self.sources.add(ItchSource())
|
||||||
|
if shared.schema.get_boolean("legendary"):
|
||||||
|
self.sources.add(LegendarySource())
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def n_games_added(self):
|
def n_games_added(self):
|
||||||
@@ -85,12 +108,47 @@ class Importer(ErrorProducer):
|
|||||||
and len(self.game_pipelines) == self.n_pipelines_done
|
and len(self.game_pipelines) == self.n_pipelines_done
|
||||||
)
|
)
|
||||||
|
|
||||||
def add_source(self, source):
|
def load_games_from_disk(self):
|
||||||
self.sources.add(source)
|
"""Load the games from disk"""
|
||||||
|
if shared.games_dir.is_dir():
|
||||||
|
for game_file in shared.games_dir.iterdir():
|
||||||
|
data = json.load(game_file.open())
|
||||||
|
game = Game(data)
|
||||||
|
shared.store.add_game(game, {"skip_save": True})
|
||||||
|
game.update()
|
||||||
|
|
||||||
|
def delete_backup(self):
|
||||||
|
"""Delete a a previously made backup"""
|
||||||
|
rmtree(shared.backup_games_dir, ignore_errors=True)
|
||||||
|
rmtree(shared.backup_covers_dir, ignore_errors=True)
|
||||||
|
|
||||||
|
def create_backup(self):
|
||||||
|
"""Make a games and covers backup"""
|
||||||
|
self.delete_backup()
|
||||||
|
copytree(shared.games_dir, shared.backup_games_dir)
|
||||||
|
copytree(shared.covers_dir, shared.backup_covers_dir)
|
||||||
|
|
||||||
|
def restore_backup(self):
|
||||||
|
"""Restore a previously made backup"""
|
||||||
|
|
||||||
|
# Remove games from the store and UI
|
||||||
|
for game in shared.store.games.values():
|
||||||
|
game.update_values({"removed": True})
|
||||||
|
game.update()
|
||||||
|
|
||||||
|
# Restore the disk backup
|
||||||
|
rmtree(shared.games_dir, ignore_errors=True)
|
||||||
|
rmtree(shared.covers_dir, ignore_errors=True)
|
||||||
|
shared.backup_games_dir.rename(shared.games_dir)
|
||||||
|
shared.backup_covers_dir.rename(shared.covers_dir)
|
||||||
|
|
||||||
|
# Reload games from disk
|
||||||
|
self.load_games_from_disk()
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
"""Use several Gio.Task to import games from added sources"""
|
"""Use several Gio.Task to import games from added sources"""
|
||||||
|
|
||||||
|
self.create_backup()
|
||||||
self.create_dialog()
|
self.create_dialog()
|
||||||
|
|
||||||
# Collect all errors and reset the cancellables for the managers
|
# Collect all errors and reset the cancellables for the managers
|
||||||
@@ -288,13 +346,17 @@ class Importer(ErrorProducer):
|
|||||||
"open_preferences",
|
"open_preferences",
|
||||||
"import",
|
"import",
|
||||||
)
|
)
|
||||||
|
else:
|
||||||
elif self.n_games_added == 1:
|
toast.set_button_label(_("Undo"))
|
||||||
toast.set_title(_("1 game imported"))
|
toast.connect(
|
||||||
|
"button-clicked", self.dialog_response_callback, "undo_import"
|
||||||
elif self.n_games_added > 1:
|
)
|
||||||
# The variable is the number of games
|
toast.set_title(
|
||||||
toast.set_title(_("{} games imported").format(self.n_games_added))
|
_("1 game imported")
|
||||||
|
if self.n_games_added == 1
|
||||||
|
# The variable is the number of games
|
||||||
|
else _("{} games imported").format(self.n_games_added)
|
||||||
|
)
|
||||||
|
|
||||||
shared.win.toast_overlay.add_toast(toast)
|
shared.win.toast_overlay.add_toast(toast)
|
||||||
return toast
|
return toast
|
||||||
@@ -315,5 +377,7 @@ class Importer(ErrorProducer):
|
|||||||
self.open_preferences(*args)
|
self.open_preferences(*args)
|
||||||
elif response == "open_preferences_import":
|
elif response == "open_preferences_import":
|
||||||
self.open_preferences(*args).connect("close-request", self.timeout_toast)
|
self.open_preferences(*args).connect("close-request", self.timeout_toast)
|
||||||
|
elif response == "undo_import":
|
||||||
|
self.restore_backup()
|
||||||
else:
|
else:
|
||||||
self.timeout_toast()
|
self.timeout_toast()
|
||||||
|
|||||||
52
src/main.py
52
src/main.py
@@ -17,7 +17,6 @@
|
|||||||
#
|
#
|
||||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
import json
|
|
||||||
import lzma
|
import lzma
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
@@ -31,15 +30,7 @@ from gi.repository import Adw, Gio, GLib, Gtk
|
|||||||
|
|
||||||
from src import shared
|
from src import shared
|
||||||
from src.details_window import DetailsWindow
|
from src.details_window import DetailsWindow
|
||||||
from src.game import Game
|
|
||||||
from src.importer.importer import Importer
|
from src.importer.importer import Importer
|
||||||
from src.importer.sources.bottles_source import BottlesSource
|
|
||||||
from src.importer.sources.flatpak_source import FlatpakSource
|
|
||||||
from src.importer.sources.heroic_source import HeroicSource
|
|
||||||
from src.importer.sources.itch_source import ItchSource
|
|
||||||
from src.importer.sources.legendary_source import LegendarySource
|
|
||||||
from src.importer.sources.lutris_source import LutrisSource
|
|
||||||
from src.importer.sources.steam_source import SteamSource
|
|
||||||
from src.logging.setup import log_system_info, setup_logging
|
from src.logging.setup import log_system_info, setup_logging
|
||||||
from src.preferences import PreferencesWindow
|
from src.preferences import PreferencesWindow
|
||||||
from src.store.managers.display_manager import DisplayManager
|
from src.store.managers.display_manager import DisplayManager
|
||||||
@@ -83,17 +74,16 @@ class CartridgesApplication(Adw.Application):
|
|||||||
"is-maximized", self.win, "maximized", Gio.SettingsBindFlags.DEFAULT
|
"is-maximized", self.win, "maximized", Gio.SettingsBindFlags.DEFAULT
|
||||||
)
|
)
|
||||||
|
|
||||||
# Load games from disk
|
# Add managers to the store for game imports
|
||||||
shared.store.add_manager(FileManager(), False)
|
|
||||||
shared.store.add_manager(DisplayManager())
|
shared.store.add_manager(DisplayManager())
|
||||||
self.load_games_from_disk()
|
shared.store.add_manager(FileManager())
|
||||||
|
|
||||||
# Add rest of the managers for game imports
|
|
||||||
shared.store.add_manager(LocalCoverManager())
|
shared.store.add_manager(LocalCoverManager())
|
||||||
shared.store.add_manager(SteamAPIManager())
|
shared.store.add_manager(SteamAPIManager())
|
||||||
shared.store.add_manager(OnlineCoverManager())
|
shared.store.add_manager(OnlineCoverManager())
|
||||||
shared.store.add_manager(SGDBManager())
|
shared.store.add_manager(SGDBManager())
|
||||||
shared.store.enable_manager_in_pipelines(FileManager)
|
|
||||||
|
# Load games from disk
|
||||||
|
Importer().load_games_from_disk()
|
||||||
|
|
||||||
# Create actions
|
# Create actions
|
||||||
self.create_actions(
|
self.create_actions(
|
||||||
@@ -134,13 +124,6 @@ class CartridgesApplication(Adw.Application):
|
|||||||
|
|
||||||
self.win.present()
|
self.win.present()
|
||||||
|
|
||||||
def load_games_from_disk(self):
|
|
||||||
if shared.games_dir.is_dir():
|
|
||||||
for game_file in shared.games_dir.iterdir():
|
|
||||||
data = json.load(game_file.open())
|
|
||||||
game = Game(data)
|
|
||||||
shared.store.add_game(game, {"skip_save": True})
|
|
||||||
|
|
||||||
def on_about_action(self, *_args):
|
def on_about_action(self, *_args):
|
||||||
# Get the debug info from the log files
|
# Get the debug info from the log files
|
||||||
debug_str = ""
|
debug_str = ""
|
||||||
@@ -207,30 +190,7 @@ class CartridgesApplication(Adw.Application):
|
|||||||
DetailsWindow()
|
DetailsWindow()
|
||||||
|
|
||||||
def on_import_action(self, *_args):
|
def on_import_action(self, *_args):
|
||||||
importer = Importer()
|
Importer().run()
|
||||||
|
|
||||||
if shared.schema.get_boolean("lutris"):
|
|
||||||
importer.add_source(LutrisSource())
|
|
||||||
|
|
||||||
if shared.schema.get_boolean("steam"):
|
|
||||||
importer.add_source(SteamSource())
|
|
||||||
|
|
||||||
if shared.schema.get_boolean("heroic"):
|
|
||||||
importer.add_source(HeroicSource())
|
|
||||||
|
|
||||||
if shared.schema.get_boolean("bottles"):
|
|
||||||
importer.add_source(BottlesSource())
|
|
||||||
|
|
||||||
if shared.schema.get_boolean("flatpak"):
|
|
||||||
importer.add_source(FlatpakSource())
|
|
||||||
|
|
||||||
if shared.schema.get_boolean("itch"):
|
|
||||||
importer.add_source(ItchSource())
|
|
||||||
|
|
||||||
if shared.schema.get_boolean("legendary"):
|
|
||||||
importer.add_source(LegendarySource())
|
|
||||||
|
|
||||||
importer.run()
|
|
||||||
|
|
||||||
def on_remove_game_action(self, *_args):
|
def on_remove_game_action(self, *_args):
|
||||||
self.win.active_game.remove_game()
|
self.win.active_game.remove_game()
|
||||||
|
|||||||
@@ -34,12 +34,16 @@ state_schema = Gio.Settings.new(APP_ID + ".State")
|
|||||||
home = Path.home()
|
home = Path.home()
|
||||||
data_dir = Path(GLib.get_user_data_dir())
|
data_dir = Path(GLib.get_user_data_dir())
|
||||||
config_dir = Path(GLib.get_user_config_dir())
|
config_dir = Path(GLib.get_user_config_dir())
|
||||||
cache_dir = Path(GLib.get_user_config_dir())
|
cache_dir = Path(GLib.get_user_cache_dir())
|
||||||
flatpak_dir = home / ".var" / "app"
|
flatpak_dir = home / ".var" / "app"
|
||||||
|
|
||||||
games_dir = data_dir / "cartridges" / "games"
|
games_dir = data_dir / "cartridges" / "games"
|
||||||
covers_dir = data_dir / "cartridges" / "covers"
|
covers_dir = data_dir / "cartridges" / "covers"
|
||||||
|
|
||||||
|
backup_dir = cache_dir / "cartridges" / "backup"
|
||||||
|
backup_games_dir = backup_dir / games_dir.name
|
||||||
|
backup_covers_dir = backup_dir / covers_dir.name
|
||||||
|
|
||||||
appdata_dir = Path(os.getenv("appdata") or "C:\\Users\\Default\\AppData\\Roaming")
|
appdata_dir = Path(os.getenv("appdata") or "C:\\Users\\Default\\AppData\\Roaming")
|
||||||
programfiles32_dir = Path(os.getenv("programfiles(x86)") or "C:\\Program Files (x86)")
|
programfiles32_dir = Path(os.getenv("programfiles(x86)") or "C:\\Program Files (x86)")
|
||||||
|
|
||||||
|
|||||||
@@ -17,6 +17,9 @@
|
|||||||
#
|
#
|
||||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from src import shared
|
||||||
from src.game import Game
|
from src.game import Game
|
||||||
from src.game_cover import GameCover
|
from src.game_cover import GameCover
|
||||||
from src.store.managers.manager import Manager
|
from src.store.managers.manager import Manager
|
||||||
@@ -46,27 +49,28 @@ class DisplayManager(Manager):
|
|||||||
"notify::visible", game.toggle_play, None
|
"notify::visible", game.toggle_play, None
|
||||||
)
|
)
|
||||||
game.menu_button.get_popover().connect(
|
game.menu_button.get_popover().connect(
|
||||||
"notify::visible", game.win.set_active_game, game
|
"notify::visible", shared.win.set_active_game, game
|
||||||
)
|
)
|
||||||
|
|
||||||
if game.game_id in game.win.game_covers:
|
if game.game_id in shared.win.game_covers:
|
||||||
game.game_cover = game.win.game_covers[game.game_id]
|
game.game_cover = shared.win.game_covers[game.game_id]
|
||||||
game.game_cover.add_picture(game.cover)
|
game.game_cover.add_picture(game.cover)
|
||||||
else:
|
else:
|
||||||
game.game_cover = GameCover({game.cover}, game.get_cover_path())
|
game.game_cover = GameCover({game.cover}, game.get_cover_path())
|
||||||
game.win.game_covers[game.game_id] = game.game_cover
|
shared.win.game_covers[game.game_id] = game.game_cover
|
||||||
|
|
||||||
if (
|
if (
|
||||||
game.win.stack.get_visible_child() == game.win.details_view
|
shared.win.stack.get_visible_child() == shared.win.details_view
|
||||||
and game.win.active_game == game
|
and shared.win.active_game == game
|
||||||
):
|
):
|
||||||
game.win.show_details_view(game)
|
shared.win.show_details_view(game)
|
||||||
|
|
||||||
if not game.removed and not game.blacklisted:
|
if not game.removed and not game.blacklisted:
|
||||||
|
logging.debug("Adding %s (%s) to the UI", game.name, game.game_id)
|
||||||
if game.hidden:
|
if game.hidden:
|
||||||
game.win.hidden_library.append(game)
|
shared.win.hidden_library.append(game)
|
||||||
else:
|
else:
|
||||||
game.win.library.append(game)
|
shared.win.library.append(game)
|
||||||
game.get_parent().set_focusable(False)
|
game.get_parent().set_focusable(False)
|
||||||
|
|
||||||
game.win.set_library_child()
|
shared.win.set_library_child()
|
||||||
|
|||||||
@@ -110,6 +110,7 @@ class Manager(ErrorProducer):
|
|||||||
except Exception as error: # pylint: disable=broad-exception-caught
|
except Exception as error: # pylint: disable=broad-exception-caught
|
||||||
handle_error(error)
|
handle_error(error)
|
||||||
|
|
||||||
|
logging.debug("Running %s for %s (%s)", self.name, game.name, game.game_id)
|
||||||
try_manager_logic()
|
try_manager_logic()
|
||||||
|
|
||||||
def process_game(
|
def process_game(
|
||||||
|
|||||||
Reference in New Issue
Block a user