Compare commits
12 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dad3dcafb7 | ||
|
|
c6ef2ea0b4 | ||
|
|
e4d9f8ba45 | ||
|
|
87a4319360 | ||
|
|
dc232e1e43 | ||
|
|
39be891452 | ||
|
|
c3cad7c793 | ||
|
|
2952322759 | ||
|
|
653bc8668c | ||
|
|
1a23851000 | ||
|
|
560d1cd273 | ||
|
|
dc0d7304f1 |
4
.github/workflows/ci.yml
vendored
4
.github/workflows/ci.yml
vendored
@@ -51,10 +51,10 @@ jobs:
|
||||
timeout 2 cartridges; [ "$?" -eq "124" ]
|
||||
|
||||
- name: Inno Setup
|
||||
run: iscc ".\_build\Cartridges.iss"
|
||||
run: iscc ".\_build\windows\Cartridges.iss"
|
||||
|
||||
- name: Upload Artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: Windows Installer
|
||||
path: _build/Output/Cartridges Setup.exe
|
||||
path: _build/windows/Output/Cartridges Setup.exe
|
||||
@@ -14,7 +14,7 @@
|
||||
<default>true</default>
|
||||
</key>
|
||||
<key name="steam-location" type="s">
|
||||
<default>"~/.steam/"</default>
|
||||
<default>"~/.steam/steam"</default>
|
||||
</key>
|
||||
<key name="lutris" type="b">
|
||||
<default>true</default>
|
||||
|
||||
@@ -44,6 +44,13 @@
|
||||
</screenshots>
|
||||
<content_rating type="oars-1.1" />
|
||||
<releases>
|
||||
<release version="2.0.2" date="2023-07-08">
|
||||
<description translatable="no">
|
||||
<ul>
|
||||
<li>Fixes an issue with internal data storage</li>
|
||||
</ul>
|
||||
</description>
|
||||
</release>
|
||||
<release version="2.0" date="2023-07-05">
|
||||
<description translatable="no">
|
||||
<p>After months of work, Cartridges 2.0 is here:</p>
|
||||
|
||||
@@ -28,8 +28,7 @@
|
||||
"/share/man",
|
||||
"/share/pkgconfig",
|
||||
"*.la",
|
||||
"*.a",
|
||||
"Cartridges.iss"
|
||||
"*.a"
|
||||
],
|
||||
"modules" : [
|
||||
{
|
||||
|
||||
12
meson.build
12
meson.build
@@ -1,5 +1,5 @@
|
||||
project('cartridges',
|
||||
version: '2.0',
|
||||
version: '2.0.2',
|
||||
meson_version: '>= 0.59.0',
|
||||
default_options: [ 'warning_level=2', 'werror=false', ],
|
||||
)
|
||||
@@ -33,13 +33,9 @@ subdir('data')
|
||||
subdir('src')
|
||||
subdir('po')
|
||||
|
||||
configure_file(
|
||||
input: './windows/Cartridges.iss.in',
|
||||
output: 'Cartridges.iss',
|
||||
configuration: conf,
|
||||
install: true,
|
||||
install_dir: '.'
|
||||
)
|
||||
if host_machine.system() == 'windows'
|
||||
subdir('windows')
|
||||
endif
|
||||
|
||||
gnome.post_install(
|
||||
glib_compile_schemas: true,
|
||||
|
||||
@@ -155,9 +155,10 @@ class DetailsWindow(Adw.Window):
|
||||
return
|
||||
|
||||
# Increment the number after the game id (eg. imported_1, imported_2)
|
||||
source_id = "imported"
|
||||
numbers = [0]
|
||||
game_id: str
|
||||
for game_id in shared.store.games:
|
||||
for game_id in shared.source_games[source_id]:
|
||||
prefix = "imported_"
|
||||
if not game_id.startswith(prefix):
|
||||
continue
|
||||
@@ -168,7 +169,7 @@ class DetailsWindow(Adw.Window):
|
||||
{
|
||||
"game_id": f"imported_{game_number}",
|
||||
"hidden": False,
|
||||
"source": "imported",
|
||||
"source": source_id,
|
||||
"added": int(time()),
|
||||
}
|
||||
)
|
||||
|
||||
@@ -91,6 +91,8 @@ class Importer(ErrorProducer):
|
||||
def run(self):
|
||||
"""Use several Gio.Task to import games from added sources"""
|
||||
|
||||
shared.win.get_application().lookup_action("import").set_enabled(False)
|
||||
|
||||
self.create_dialog()
|
||||
|
||||
# Collect all errors and reset the cancellables for the managers
|
||||
@@ -221,6 +223,7 @@ class Importer(ErrorProducer):
|
||||
self.import_dialog.close()
|
||||
self.summary_toast = self.create_summary_toast()
|
||||
self.create_error_dialog()
|
||||
shared.win.get_application().lookup_action("import").set_enabled(True)
|
||||
|
||||
def create_error_dialog(self):
|
||||
"""Dialog containing all errors raised by importers"""
|
||||
|
||||
@@ -81,7 +81,7 @@ class HeroicSourceIterator(SourceIterator):
|
||||
runner = entry["runner"]
|
||||
service = self.sub_sources[runner]["service"]
|
||||
values = {
|
||||
"source": self.source.id,
|
||||
"source": f"{self.source.id}_{service}",
|
||||
"added": added_time,
|
||||
"name": entry["title"],
|
||||
"developer": entry.get("developer", None),
|
||||
@@ -159,4 +159,4 @@ class HeroicSource(URLExecutableSource):
|
||||
@property
|
||||
def game_id_format(self) -> str:
|
||||
"""The string format used to construct game IDs"""
|
||||
return self.name.lower() + "_{service}_{game_id}"
|
||||
return self.id + "_{service}_{game_id}"
|
||||
|
||||
@@ -118,9 +118,9 @@ class SteamSource(URLExecutableSource):
|
||||
data_location = Location(
|
||||
schema_key="steam-location",
|
||||
candidates=(
|
||||
shared.flatpak_dir / "com.valvesoftware.Steam" / "data" / "Steam",
|
||||
shared.home / ".steam" / "steam",
|
||||
shared.data_dir / "Steam",
|
||||
shared.home / ".steam",
|
||||
shared.flatpak_dir / "com.valvesoftware.Steam" / "data" / "Steam",
|
||||
shared.programfiles32_dir / "Steam",
|
||||
),
|
||||
paths={
|
||||
|
||||
@@ -93,7 +93,7 @@ class CartridgesApplication(Adw.Application):
|
||||
shared.store.add_manager(SteamAPIManager())
|
||||
shared.store.add_manager(OnlineCoverManager())
|
||||
shared.store.add_manager(SGDBManager())
|
||||
shared.store.enable_manager_in_pipelines(FileManager)
|
||||
shared.store.toggle_manager_in_pipelines(FileManager, True)
|
||||
|
||||
# Create actions
|
||||
self.create_actions(
|
||||
@@ -179,6 +179,7 @@ class CartridgesApplication(Adw.Application):
|
||||
# Translators: Replace this with your name for it to show up in the about window
|
||||
translator_credits=_("translator_credits"),
|
||||
debug_info=debug_str,
|
||||
debug_info_filename="cartridges.log",
|
||||
)
|
||||
about.present()
|
||||
|
||||
|
||||
@@ -214,10 +214,9 @@ class PreferencesWindow(Adw.PreferencesWindow):
|
||||
self.toast.dismiss()
|
||||
|
||||
def remove_all_games(self, *_args):
|
||||
for game in shared.store.games.values():
|
||||
for game in shared.store:
|
||||
if not game.removed:
|
||||
self.removed_games.add(game)
|
||||
|
||||
game.removed = True
|
||||
game.save()
|
||||
game.update()
|
||||
|
||||
@@ -34,7 +34,7 @@ state_schema = Gio.Settings.new(APP_ID + ".State")
|
||||
home = Path.home()
|
||||
data_dir = Path(GLib.get_user_data_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"
|
||||
|
||||
games_dir = data_dir / "cartridges" / "games"
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
import logging
|
||||
from typing import MutableMapping, Generator, Any
|
||||
|
||||
from src import shared
|
||||
from src.game import Game
|
||||
@@ -31,24 +32,59 @@ class Store:
|
||||
managers: dict[type[Manager], Manager]
|
||||
pipeline_managers: set[Manager]
|
||||
pipelines: dict[str, Pipeline]
|
||||
games: dict[str, Game]
|
||||
source_games: MutableMapping[str, MutableMapping[str, Game]]
|
||||
|
||||
def __init__(self) -> None:
|
||||
self.managers = {}
|
||||
self.pipeline_managers = set()
|
||||
self.pipelines = {}
|
||||
self.games = {}
|
||||
self.source_games = {}
|
||||
|
||||
def __contains__(self, obj: object) -> bool:
|
||||
"""Check if the game is present in the store with the `in` keyword"""
|
||||
if not isinstance(obj, Game):
|
||||
return False
|
||||
if not (source_mapping := self.source_games.get(obj.source)):
|
||||
return False
|
||||
return obj.game_id in source_mapping
|
||||
|
||||
def __iter__(self) -> Generator[Game, None, None]:
|
||||
"""Iterate through the games in the store with `for ... in`"""
|
||||
for _source_id, games_mapping in self.source_games.items():
|
||||
for _game_id, game in games_mapping.items():
|
||||
yield game
|
||||
|
||||
def __len__(self) -> int:
|
||||
"""Get the number of games in the store with the `len` builtin"""
|
||||
return sum(len(source_mapping) for source_mapping in self.source_games)
|
||||
|
||||
def __getitem__(self, game_id: str) -> Game:
|
||||
"""Get a game by its id with `store["game_id_goes_here"]`"""
|
||||
for game in iter(self):
|
||||
if game.game_id == game_id:
|
||||
return game
|
||||
raise KeyError("Game not found in store")
|
||||
|
||||
def get(self, game_id: str, default: Any = None) -> Game | Any:
|
||||
"""Get a game by its ID, with a fallback if not found"""
|
||||
try:
|
||||
game = self[game_id]
|
||||
return game
|
||||
except KeyError:
|
||||
return default
|
||||
|
||||
def add_manager(self, manager: Manager, in_pipeline=True):
|
||||
"""Add a manager to the store"""
|
||||
manager_type = type(manager)
|
||||
self.managers[manager_type] = manager
|
||||
if in_pipeline:
|
||||
self.enable_manager_in_pipelines(manager_type)
|
||||
self.toggle_manager_in_pipelines(manager_type, in_pipeline)
|
||||
|
||||
def enable_manager_in_pipelines(self, manager_type: type[Manager]):
|
||||
"""Make a manager run in new pipelines"""
|
||||
self.pipeline_managers.add(self.managers[manager_type])
|
||||
def toggle_manager_in_pipelines(self, manager_type: type[Manager], enable: bool):
|
||||
"""Change if a manager should run in new pipelines"""
|
||||
if enable:
|
||||
self.pipeline_managers.add(self.managers[manager_type])
|
||||
else:
|
||||
self.pipeline_managers.discard(self.managers[manager_type])
|
||||
|
||||
def cleanup_game(self, game: Game) -> None:
|
||||
"""Remove a game's files"""
|
||||
@@ -74,7 +110,7 @@ class Store:
|
||||
return None
|
||||
|
||||
# Handle game duplicates
|
||||
stored_game = self.games.get(game.game_id)
|
||||
stored_game = self.get(game.game_id)
|
||||
if not stored_game:
|
||||
# New game, do as normal
|
||||
logging.debug("New store game %s (%s)", game.name, game.game_id)
|
||||
@@ -96,11 +132,15 @@ class Store:
|
||||
for signal in manager.signals:
|
||||
game.connect(signal, manager.execute_resilient_manager_logic)
|
||||
|
||||
# Add the game to the store
|
||||
if not game.source in self.source_games:
|
||||
self.source_games[game.source] = {}
|
||||
self.source_games[game.source][game.game_id] = game
|
||||
|
||||
# Run the pipeline for the game
|
||||
if not run_pipeline:
|
||||
return None
|
||||
pipeline = Pipeline(game, additional_data, self.pipeline_managers)
|
||||
self.games[game.game_id] = game
|
||||
self.pipelines[game.game_id] = pipeline
|
||||
pipeline.advance()
|
||||
return pipeline
|
||||
|
||||
@@ -117,7 +117,7 @@ class CartridgesWindow(Adw.ApplicationWindow):
|
||||
def set_library_child(self):
|
||||
child, hidden_child = self.notice_empty, self.hidden_notice_empty
|
||||
|
||||
for game in shared.store.games.values():
|
||||
for game in shared.store:
|
||||
if game.removed or game.blacklisted:
|
||||
continue
|
||||
if game.hidden:
|
||||
|
||||
@@ -15,10 +15,10 @@ AppSupportURL=https://github.com/kra-mo/cartridges/issues
|
||||
AppUpdatesURL={#MyAppURL}
|
||||
DefaultDirName={autopf64}\{#MyAppName}
|
||||
DisableProgramGroupPage=yes
|
||||
LicenseFile=..\LICENSE
|
||||
LicenseFile=..\..\LICENSE
|
||||
PrivilegesRequiredOverridesAllowed=dialog
|
||||
OutputBaseFilename=Cartridges Setup
|
||||
SetupIconFile=..\windows\icon.ico
|
||||
SetupIconFile=..\..\windows\icon.ico
|
||||
Compression=lzma
|
||||
SolidCompression=yes
|
||||
WizardStyle=modern
|
||||
@@ -50,7 +50,7 @@ Source: "D:\a\_temp\msys64\ucrt64\share\glib-2.0\*"; DestDir: "{app}\share\glib-
|
||||
Source: "D:\a\_temp\msys64\ucrt64\share\gtk-4.0\*"; DestDir: "{app}\share\gtk-4.0"; Flags: recursesubdirs ignoreversion
|
||||
Source: "D:\a\_temp\msys64\ucrt64\share\locale\*"; DestDir: "{app}\share\locale"; Flags: recursesubdirs ignoreversion
|
||||
|
||||
Source: "..\windows\icon.ico"; DestDir: "{app}"; Flags: recursesubdirs ignoreversion
|
||||
Source: "..\..\windows\icon.ico"; DestDir: "{app}"; Flags: recursesubdirs ignoreversion
|
||||
|
||||
[Icons]
|
||||
Name: "{autoprograms}\{#MyAppName}"; Filename: "{app}\bin\{#MyAppExeName}"; Parameters: """{app}\bin\cartridges"""; IconFilename: "{app}\icon.ico"
|
||||
|
||||
7
windows/meson.build
Normal file
7
windows/meson.build
Normal file
@@ -0,0 +1,7 @@
|
||||
configure_file(
|
||||
input: './Cartridges.iss.in',
|
||||
output: 'Cartridges.iss',
|
||||
configuration: conf,
|
||||
install: true,
|
||||
install_dir: '.'
|
||||
)
|
||||
Reference in New Issue
Block a user