Compare commits

...

38 Commits
v2.0.4 ... v2.1

Author SHA1 Message Date
kramo
ca73023bc9 v2.1 2023-07-25 20:32:46 +02:00
Weblate (bot)
b8cd1fd741 Translations update from Hosted Weblate (#152)
* Translated using Weblate (Italian)

Currently translated at 100.0% (121 of 121 strings)

Co-authored-by: Giasko <dibiame@hotmail.it>
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/cartridges/cartridges/it/
Translation: Cartridges/Cartridges

* Translated using Weblate (Czech)

Currently translated at 100.0% (121 of 121 strings)

Added translation using Weblate (Czech)

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: foo expert <deferred_water346@simplelogin.com>
Translate-URL: https://hosted.weblate.org/projects/cartridges/cartridges/cs/
Translation: Cartridges/Cartridges

* Translated using Weblate (Polish)

Currently translated at 100.0% (121 of 121 strings)

Co-authored-by: Michaks <fexwex3@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/cartridges/cartridges/pl/
Translation: Cartridges/Cartridges

* Translated using Weblate (French)

Currently translated at 100.0% (121 of 121 strings)

Co-authored-by: rene-coty <irenee.thirion@e.email>
Translate-URL: https://hosted.weblate.org/projects/cartridges/cartridges/fr/
Translation: Cartridges/Cartridges

* Update translation files

Updated by "Squash Git commits" hook in Weblate.

Translation: Cartridges/Cartridges
Translate-URL: https://hosted.weblate.org/projects/cartridges/cartridges/

---------

Co-authored-by: Giasko <dibiame@hotmail.it>
Co-authored-by: foo expert <deferred_water346@simplelogin.com>
Co-authored-by: Michaks <fexwex3@gmail.com>
Co-authored-by: rene-coty <irenee.thirion@e.email>
2023-07-25 20:29:01 +02:00
kramo
26e8d6d2c6 Merge pull request #150 from kra-mo/heroic-fixes-and-improvements
Heroic fixes and improvements
2023-07-25 20:23:54 +02:00
GeoffreyCoulaud
7bcb113a33 extracted get_hidden_app_names to a method 2023-07-22 00:06:16 +02:00
GeoffreyCoulaud
fbf076660d Better heroic store file parsing 2023-07-22 00:04:02 +02:00
GeoffreyCoulaud
b1992a9466 Fix heroic legendary path detection 2023-07-21 14:39:07 +02:00
kramo
c347d9b0f4 v2.0.6 2023-07-21 09:45:18 +02:00
kramo
9cd4d7048c Don't blacklist Steam mods - #151 2023-07-21 09:39:32 +02:00
GeoffreyCoulaud
da777d3605 Permission for heroic flatpak's legendary files 2023-07-20 21:06:30 +02:00
GeoffreyCoulaud
4587720934 using cached_property for sub-source paths 2023-07-20 21:06:04 +02:00
GeoffreyCoulaud
270fa2092c Fixed heroic location candidates priority 2023-07-20 20:56:28 +02:00
kramo
82dddd1c5c Skip missing hidden key 2023-07-20 19:52:59 +02:00
kramo
3d17b5a920 Properly capitalize Pylint 2023-07-20 19:15:19 +02:00
kramo
2c67dd23ab Update contributing guidelines 2023-07-20 19:11:24 +02:00
kramo
45d1ddaa7d Add Matrix space to Readme 2023-07-20 11:56:55 +02:00
GeoffreyCoulaud
bb4870e99d Add debug message to local cover manager 2023-07-20 11:33:55 +02:00
GeoffreyCoulaud
190b446de5 More debug messages + fix sideloaded heroic games 2023-07-20 11:26:05 +02:00
GeoffreyCoulaud
52b6c47c8d More renaming to iterable + fixes to heroic 2023-07-20 10:58:23 +02:00
GeoffreyCoulaud
0df123975c Fix some syntax 2023-07-20 10:35:07 +02:00
GeoffreyCoulaud
7f576d1bd3 SourceIterator is actually just SourceIterable 2023-07-20 10:32:43 +02:00
GeoffreyCoulaud
30152cd10a simplified SourceIterator 2023-07-20 10:29:39 +02:00
GeoffreyCoulaud
2acdedf033 Added heroic import amazon to ui + fixes 2023-07-20 10:29:27 +02:00
GeoffreyCoulaud
a399113ff9 fixed typo 2023-07-19 13:12:07 +02:00
GeoffreyCoulaud
8839db272b better legendary sub-source library path detection 2023-07-19 13:00:29 +02:00
GeoffreyCoulaud
a0bfca01d6 WIP added support for heroic hidden
TODO
- Test all of that
2023-07-19 05:33:55 +02:00
GeoffreyCoulaud
0601fd5ebb Converted genexps to setcomps 2023-07-19 05:32:47 +02:00
GeoffreyCoulaud
15da65fccf WIP heroic source refactor
- Fixed installed games lookup
- Added support for amazon games

TODO
- Test (obviously)
- Consider getting hidden value
2023-07-19 05:01:17 +02:00
GeoffreyCoulaud
00ff297867 Steam source debug info on skip 2023-07-18 14:23:43 +02:00
GeoffreyCoulaud
fbb2ccec57 silence pil 2023-07-18 14:20:19 +02:00
kramo
be6338cdd4 v2.0.5 2023-07-17 09:59:47 +02:00
kramo
bb7fded0e5 Fix Windows migration 2023-07-17 09:57:09 +02:00
kramo
7d91b84a87 Merge pull request #144 from weblate/weblate-cartridges-cartridges
Translations update from Hosted Weblate
2023-07-17 09:56:09 +02:00
Hosted Weblate
3002cef448 Translated using Weblate (Polish)
Currently translated at 100.0% (121 of 121 strings)

Co-authored-by: Eryk Michalak <gnu.ewm@protonmail.com>
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/cartridges/cartridges/pl/
Translation: Cartridges/Cartridges
2023-07-16 00:51:44 +02:00
Hosted Weblate
89f6dcad19 Translated using Weblate (Portuguese (Brazil))
Currently translated at 91.7% (111 of 121 strings)

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Vítor Fernandes Almado <vfalmado@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/cartridges/cartridges/pt_BR/
Translation: Cartridges/Cartridges
2023-07-16 00:51:44 +02:00
Hosted Weblate
5c62b7ba02 Translated using Weblate (Turkish)
Currently translated at 100.0% (121 of 121 strings)

Co-authored-by: Sabri Ünal <libreajans@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/cartridges/cartridges/tr/
Translation: Cartridges/Cartridges
2023-07-16 00:51:44 +02:00
kramo
a1c5a4bdd8 Mark source names as translatable 2023-07-13 14:51:55 +02:00
kramo
6114f65204 Lowercase itch source name 2023-07-13 14:46:31 +02:00
kramo
5be70bba52 Add extra sources to desktop entry 2023-07-09 14:26:44 +02:00
28 changed files with 1017 additions and 262 deletions

View File

@@ -1,7 +1,14 @@
# Contributing # Contributing
## Code ## Code
Fork the repository, make your changes, then create a pull request.
Be sure to follow the [code style](#code-style) of the project.
### Adding a feature
[Create an issue](https://github.com/kra-mo/cartridges/issues/new) or join the [Discord](https://discord.gg/4KSFh3AmQR)/[Matrix](https://matrix.to/#/#cartridges:matrix.org) to discuss it with the maintainers. We will provide additional guidance.
### Fixing a bug
Fork the repository, make your changes, then create a pull request. Be sure to mention the GitHub issue you're fixing if one was already open.
## Translations ## Translations
### Weblate ### Weblate
@@ -17,7 +24,7 @@ The project can be translated on [Weblate](https://hosted.weblate.org/engage/car
# Building # Building
## GNOME Builder ## GNOME Builder
1. Install [GNOME Builder](https://flathub.org/apps/details/org.gnome.Builder). 1. Install [GNOME Builder](https://flathub.org/apps/org.gnome.Builder).
2. Click "Clone Repository" with `https://github.com/kra-mo/cartridges.git` as the URL. 2. Click "Clone Repository" with `https://github.com/kra-mo/cartridges.git` as the URL.
3. Click on the build button (hammer) at the top. 3. Click on the build button (hammer) at the top.
@@ -33,3 +40,23 @@ cd cartridges
meson setup build meson setup build
ninja -C build install ninja -C build install
``` ```
# Code style
All code is auto-formatted with [Black](https://github.com/psf/black) and linted with [Pylint](https://github.com/pylint-dev/pylint). Imports are sorted by [isort](https://github.com/pycqa/isort).
VSCode extensions are available for all of these and you can set them up with the following `settings.json` configuration:
```json
"python.formatting.provider": "none",
"[python]": {
"editor.defaultFormatter": "ms-python.black-formatter",
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.organizeImports": true
},
},
"isort.args":["--profile", "black"],
```
For other code editors, you can install them via `pip` and invoke them via the command line.

View File

@@ -1,30 +1,30 @@
[circle-url]: https://circle.gnome.org
[circle-image]: https://circle.gnome.org/assets/button/badge.svg
[weblate-url]: https://hosted.weblate.org/engage/cartridges/
[weblate-image]: https://hosted.weblate.org/widgets/cartridges/-/cartridges/svg-badge.svg
[discord-url]: https://discord.gg/4KSFh3AmQR
[discord-image]: https://img.shields.io/discord/1088155799299313754?color=%235865F2&label=discord&logo=discord&logoColor=%23FFFFFF&style=for-the-badge
[matrix-url]: https://matrix.to/#/#cartridges:matrix.org
[matrix-image]: https://img.shields.io/matrix/cartridges:matrix.org?label=Matrix&logo=matrix&color=%230dbd8b&style=for-the-badge
[flathub-url]: https://flathub.org/apps/hu.kramo.Cartridges
[flathub-image]: https://img.shields.io/flathub/v/hu.kramo.Cartridges?logo=flathub&style=for-the-badge
[installs-image]: https://img.shields.io/flathub/downloads/hu.kramo.Cartridges?style=for-the-badge
<div align="center"> <div align="center">
<img src="data/icons/hicolor/scalable/apps/hu.kramo.Cartridges.svg" width="128" height="128"> <img src="data/icons/hicolor/scalable/apps/hu.kramo.Cartridges.svg" width="128" height="128">
# Cartridges # Cartridges
A GTK4 + Libadwaita game launcher
[![GNOME Circle][circle-image]][circle-url] A GTK4 + Libadwaita game launcher
[![Flathub][flathub-image]][flathub-url]
[![Build status][github-actions-image]][github-actions-url]
[![Translation Status][weblate-image]][weblate-url]
[![Code style][code-style-image]][code-style-url]
[![Discord][discord-image]][discord-url]
[circle-url]: https://circle.gnome.org [![GNOME Circle][circle-image]][circle-url]
[circle-image]: https://circle.gnome.org/assets/button/badge.svg [![Translation Status][weblate-image]][weblate-url]
[github-actions-url]: https://github.com/kra-mo/cartridges
[github-actions-image]: https://github.com/kra-mo/cartridges/actions/workflows/ci.yml/badge.svg [![Flathub][flathub-image]][flathub-url]
[code-style-url]: https://github.com/psf/black [![Discord][discord-image]][discord-url]
[code-style-image]: https://img.shields.io/badge/code%20style-black-000000?style=flat [![Matrix][matrix-image]][matrix-url]
[weblate-url]: https://hosted.weblate.org/engage/cartridges/ [![Installs][installs-image]][flathub-url]
[weblate-image]: https://hosted.weblate.org/widgets/cartridges/-/cartridges/svg-badge.svg
[discord-url]: https://discord.gg/4KSFh3AmQR
[discord-image]: https://img.shields.io/discord/1088155799299313754?color=%235865F2&label=discord&logo=discord&logoColor=%23FFFFFF
[flathub-url]: https://flathub.org/apps/hu.kramo.Cartridges
[flathub-image]: https://img.shields.io/flathub/v/hu.kramo.Cartridges
<img src="data/screenshots/1.png"> <img src="data/screenshots/1.png">
</div> </div>
@@ -50,7 +50,7 @@ Cartridges is a simple game launcher written in Python using GTK4 and Libadwaita
- Searching for games on various databases - Searching for games on various databases
- Animated covers - Animated covers
For updates and questions, join our [Discord server][discord-url]! For updates and questions, join our [Discord server][discord-url] (bridged to [Matrix](https://matrix.to/#/#cartridges:matrix.org))!
# Installation # Installation

View File

@@ -174,6 +174,15 @@ template $PreferencesWindow : Adw.PreferencesWindow {
} }
} }
Adw.ActionRow {
title: _("Import Amazon Games");
activatable-widget: heroic_import_amazon_switch;
Switch heroic_import_amazon_switch {
valign: center;
}
}
Adw.ActionRow { Adw.ActionRow {
title: _("Import Sideloaded Games"); title: _("Import Sideloaded Games");
activatable-widget: heroic_import_sideload_switch; activatable-widget: heroic_import_sideload_switch;

View File

@@ -7,5 +7,5 @@ Icon=@APP_ID@
Terminal=false Terminal=false
Type=Application Type=Application
Categories=GNOME;GTK;Game; Categories=GNOME;GTK;Game;
Keywords=gaming;launcher;steam;lutris;heroic;bottles;itch; Keywords=gaming;launcher;steam;lutris;heroic;bottles;itch;flatpak;legendary;
StartupNotify=true StartupNotify=true

View File

@@ -43,6 +43,9 @@
<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-amazon" type="b">
<default>true</default>
</key>
<key name="heroic-import-sideload" type="b"> <key name="heroic-import-sideload" type="b">
<default>true</default> <default>true</default>
</key> </key>

View File

@@ -44,10 +44,10 @@
</screenshots> </screenshots>
<content_rating type="oars-1.1" /> <content_rating type="oars-1.1" />
<releases> <releases>
<release version="2.0.4" date="2023-07-09"> <release version="2.1" date="2023-07-25">
<description translatable="no"> <description translatable="no">
<ul> <ul>
<li>Fixes an issue with adding new games manually</li> <li>Added support for Amazon Games in the Heroic importer</li>
<li>Translations since 2.0</li> <li>Translations since 2.0</li>
</ul> </ul>
</description> </description>

View File

@@ -15,6 +15,7 @@
"--filesystem=~/.var/app/com.valvesoftware.Steam/data/Steam/:ro", "--filesystem=~/.var/app/com.valvesoftware.Steam/data/Steam/:ro",
"--filesystem=~/.var/app/net.lutris.Lutris/:ro", "--filesystem=~/.var/app/net.lutris.Lutris/:ro",
"--filesystem=~/.var/app/com.heroicgameslauncher.hgl/config/heroic/:ro", "--filesystem=~/.var/app/com.heroicgameslauncher.hgl/config/heroic/:ro",
"--filesystem=~/.var/app/com.heroicgameslauncher.hgl/config/legendary/:ro",
"--filesystem=~/.var/app/com.usebottles.bottles/data/bottles/:ro", "--filesystem=~/.var/app/com.usebottles.bottles/data/bottles/:ro",
"--filesystem=~/.var/app/io.itch.itch/config/itch/:ro", "--filesystem=~/.var/app/io.itch.itch/config/itch/:ro",
"--filesystem=/var/lib/flatpak:ro" "--filesystem=/var/lib/flatpak:ro"

View File

@@ -1,5 +1,5 @@
project('cartridges', project('cartridges',
version: '2.0.4', version: '2.1',
meson_version: '>= 0.59.0', meson_version: '>= 0.59.0',
default_options: [ 'warning_level=2', 'werror=false', ], default_options: [ 'warning_level=2', 'werror=false', ],
) )

View File

@@ -19,3 +19,4 @@ pl
sv sv
tr tr
el el
cs

553
po/cs.po Normal file
View File

@@ -0,0 +1,553 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR kramo
# This file is distributed under the same license as the Cartridges package.
# foo expert <deferred_water346@simplelogin.com>, 2023.
msgid ""
msgstr ""
"Project-Id-Version: Cartridges\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2023-07-05 14:36+0200\n"
"PO-Revision-Date: 2023-07-24 13:05+0000\n"
"Last-Translator: foo expert <deferred_water346@simplelogin.com>\n"
"Language-Team: Czech <https://hosted.weblate.org/projects/cartridges/"
"cartridges/cs/>\n"
"Language: cs\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n"
"X-Generator: Weblate 5.0-dev\n"
#: data/hu.kramo.Cartridges.desktop.in:3
#: data/hu.kramo.Cartridges.metainfo.xml.in:6 data/gtk/window.blp:47
#: src/main.py:162
msgid "Cartridges"
msgstr "Kazety"
#: data/hu.kramo.Cartridges.desktop.in:4
msgid "Game Launcher"
msgstr "Spouštěč her"
#: data/hu.kramo.Cartridges.desktop.in:5
#: data/hu.kramo.Cartridges.metainfo.xml.in:7
msgid "Launch all your games"
msgstr "Spusťte všechny vaše hry"
#: data/hu.kramo.Cartridges.desktop.in:11
msgid "gaming;launcher;steam;lutris;heroic;bottles;itch;"
msgstr "hraní;spouštěč;steam;lutris;heroic;láhve;itch;"
#: data/hu.kramo.Cartridges.metainfo.xml.in:9
msgid ""
"Cartridges is a simple game launcher for all of your games. It has support "
"for importing games from Steam, Lutris, Heroic and more with no login "
"necessary. You can sort and hide games or download cover art from "
"SteamGridDB."
msgstr ""
"Kazety jsou jednoduchý spouštěč pro všechny vaše hry. Podporuje importovaní "
"her ze služeb Steam, Lutris, Heroic a dalších bez nutnosti přihlášení. Hry "
"můžete třídit a skrývat nebo stahovat obálky ze služby SteamGridDB."
#: data/hu.kramo.Cartridges.metainfo.xml.in:30
msgid "Library"
msgstr "Knihovna"
#: data/hu.kramo.Cartridges.metainfo.xml.in:34 src/details_window.py:67
msgid "Edit Game Details"
msgstr "Upravit podrobnosti o hře"
#: data/hu.kramo.Cartridges.metainfo.xml.in:38 data/gtk/window.blp:71
msgid "Game Details"
msgstr "Podrobnosti o hře"
#: data/hu.kramo.Cartridges.metainfo.xml.in:42 data/gtk/window.blp:416
#: src/details_window.py:239
msgid "Preferences"
msgstr "Předvolby"
#: data/gtk/details-window.blp:25
msgid "Cancel"
msgstr "Zrušit"
#: data/gtk/details-window.blp:57
msgid "New Cover"
msgstr "Nový obal"
#: data/gtk/details-window.blp:75
msgid "Delete Cover"
msgstr "Odstranit obal"
#: data/gtk/details-window.blp:101 data/gtk/details-window.blp:106
#: data/gtk/game.blp:80
msgid "Title"
msgstr "Název"
#: data/gtk/details-window.blp:102
msgid "The title of the game"
msgstr "Název hry"
#: data/gtk/details-window.blp:112 data/gtk/details-window.blp:117
msgid "Developer"
msgstr "Vývojář"
#: data/gtk/details-window.blp:113
msgid "The developer or publisher (optional)"
msgstr "Vývojář nebo vydavatel (nepovinné)"
#: data/gtk/details-window.blp:123 data/gtk/details-window.blp:155
msgid "Executable"
msgstr "Spustitelný soubor"
#: data/gtk/details-window.blp:124
msgid "File to open or command to run when launching the game"
msgstr "Soubor nebo příkaz pro spuštění hry"
#: data/gtk/details-window.blp:130
msgid "More Info"
msgstr "Více informací"
#: data/gtk/game.blp:102 data/gtk/game.blp:121 data/gtk/window.blp:195
msgid "Edit"
msgstr "Upravit"
#: data/gtk/game.blp:107 src/window.py:171
msgid "Hide"
msgstr "Skrýt"
#: data/gtk/game.blp:112 data/gtk/game.blp:131 data/gtk/preferences.blp:56
#: data/gtk/window.blp:209
msgid "Remove"
msgstr "Odstranit"
#: data/gtk/game.blp:126 src/window.py:173
msgid "Unhide"
msgstr "Odkrýt"
#: data/gtk/help-overlay.blp:11 data/gtk/preferences.blp:9
msgid "General"
msgstr "Obecné"
#: data/gtk/help-overlay.blp:14
msgid "Quit"
msgstr "Ukončit"
#: data/gtk/help-overlay.blp:19 data/gtk/window.blp:217 data/gtk/window.blp:257
#: data/gtk/window.blp:323
msgid "Search"
msgstr "Vyhledávání"
#: data/gtk/help-overlay.blp:24
msgid "Show preferences"
msgstr "Zobrazit předvolby"
#: data/gtk/help-overlay.blp:29
msgid "Shortcuts"
msgstr "Zkratky"
#: data/gtk/help-overlay.blp:34 src/game.py:102 src/preferences.py:112
msgid "Undo"
msgstr "Zpět"
#: data/gtk/help-overlay.blp:39
msgid "Open menu"
msgstr "Otevřít nabídku"
#: data/gtk/help-overlay.blp:45
msgid "Games"
msgstr "Hry"
#: data/gtk/help-overlay.blp:48
msgid "Add new game"
msgstr "Přidat novou hru"
#: data/gtk/help-overlay.blp:53
msgid "Import games"
msgstr "Importovat hry"
#: data/gtk/help-overlay.blp:58
msgid "Show hidden games"
msgstr "Zobrazit skryté hry"
#: data/gtk/help-overlay.blp:63
msgid "Remove game"
msgstr "Odstranit hru"
#: data/gtk/preferences.blp:13 data/gtk/preferences.blp:268
msgid "Behavior"
msgstr "Chování"
#: data/gtk/preferences.blp:16
msgid "Exit After Launching Games"
msgstr "Ukončit po spuštění her"
#: data/gtk/preferences.blp:25
msgid "Cover Image Launches Game"
msgstr "Obrázek na obálce spouští hru"
#: data/gtk/preferences.blp:26
msgid "Swaps the behavior of the cover image and the play button"
msgstr "Vymění chování obrázku na obálce a tlačítka pro přehrávání"
#: data/gtk/preferences.blp:36 src/details_window.py:81
msgid "Images"
msgstr "Obrázky"
#: data/gtk/preferences.blp:39
msgid "High Quality Images"
msgstr "Vysoce kvalitní obrázky"
#: data/gtk/preferences.blp:40
msgid "Save game covers losslessly at the cost of storage"
msgstr "Ukládat obaly her bezztrátově na úkor většího místa na disku"
#: data/gtk/preferences.blp:50
msgid "Danger Zone"
msgstr "Nebezpečná zóna"
#: data/gtk/preferences.blp:53
msgid "Remove All Games"
msgstr "Odstranit všechny hry"
#: data/gtk/preferences.blp:85 data/gtk/window.blp:27 data/gtk/window.blp:442
msgid "Import"
msgstr "Import"
#: data/gtk/preferences.blp:89
msgid "Sources"
msgstr "Zdroje"
#: data/gtk/preferences.blp:92
msgid "Steam"
msgstr "Steam"
#: data/gtk/preferences.blp:96 data/gtk/preferences.blp:110
#: data/gtk/preferences.blp:151 data/gtk/preferences.blp:192
#: data/gtk/preferences.blp:206 data/gtk/preferences.blp:220
#: data/gtk/preferences.blp:234
msgid "Install Location"
msgstr "Umístění instalace"
#: data/gtk/preferences.blp:106
msgid "Lutris"
msgstr "Lutris"
#: data/gtk/preferences.blp:119
msgid "Cache Location"
msgstr "Umístění dočasných souborů"
#: data/gtk/preferences.blp:128
msgid "Import Steam Games"
msgstr "Importovat Steam hry"
#: data/gtk/preferences.blp:137
msgid "Import Flatpak Games"
msgstr "Importovat Flatpak hry"
#: data/gtk/preferences.blp:147
msgid "Heroic"
msgstr "Heroic"
#: data/gtk/preferences.blp:160
msgid "Import Epic Games"
msgstr "Importovat Epic Games hry"
#: data/gtk/preferences.blp:169
msgid "Import GOG Games"
msgstr "Importovat GOG hry"
#: data/gtk/preferences.blp:178
msgid "Import Sideloaded Games"
msgstr "Importovat ručně načtené hry"
#: data/gtk/preferences.blp:188
msgid "Bottles"
msgstr "Láhve"
#: data/gtk/preferences.blp:202
msgid "itch"
msgstr "itch"
#: data/gtk/preferences.blp:216
msgid "Legendary"
msgstr "Legendary"
#: data/gtk/preferences.blp:230
msgid "Flatpak"
msgstr "Flatpak"
#: data/gtk/preferences.blp:243
msgid "Import Game Launchers"
msgstr "Importovat spouštěče her"
#: data/gtk/preferences.blp:256
msgid "SteamGridDB"
msgstr "SteamGridDB"
#: data/gtk/preferences.blp:260
msgid "Authentication"
msgstr "Ověření"
#: data/gtk/preferences.blp:263
msgid "API Key"
msgstr "Klíč API"
#: data/gtk/preferences.blp:271
msgid "Use SteamGridDB"
msgstr "Používat SteamGridDB"
#: data/gtk/preferences.blp:272
msgid "Download images when adding or importing games"
msgstr "Stahovat obrázky při přidávání nebo importování her"
#: data/gtk/preferences.blp:281
msgid "Prefer Over Official Images"
msgstr "Upřednostnit před oficiálními obrázky"
#: data/gtk/preferences.blp:290
msgid "Prefer Animated Images"
msgstr "Upřednostnit animované obrázky"
#: data/gtk/window.blp:6 data/gtk/window.blp:14
msgid "No Games Found"
msgstr "Nebyly nalezeny žádné hry"
#: data/gtk/window.blp:7 data/gtk/window.blp:15
msgid "Try a different search."
msgstr "Zkuste hledat něco jiného."
#: data/gtk/window.blp:21
msgid "No Games"
msgstr "Žádné hry"
#: data/gtk/window.blp:22
msgid "Use the + button to add games."
msgstr "Tlačítkem + můžete přidávat hry."
#: data/gtk/window.blp:40
msgid "No Hidden Games"
msgstr "Žádné skryté hry"
#: data/gtk/window.blp:41
msgid "Games you hide will appear here."
msgstr "Hry, které skryjete, se zobrazí zde."
#: data/gtk/window.blp:64 data/gtk/window.blp:304
msgid "Back"
msgstr "Zpět"
#: data/gtk/window.blp:121
msgid "Game Title"
msgstr "Název hry"
#: data/gtk/window.blp:176
msgid "Play"
msgstr "Hrát"
#: data/gtk/window.blp:243 data/gtk/window.blp:435
msgid "Add Game"
msgstr "Přidat hru"
#: data/gtk/window.blp:250 data/gtk/window.blp:316
msgid "Main Menu"
msgstr "Hlavní nabídka"
#: data/gtk/window.blp:311
msgid "Hidden Games"
msgstr "Skryté hry"
#: data/gtk/window.blp:374
msgid "Sort"
msgstr "Třídit"
#: data/gtk/window.blp:377
msgid "A-Z"
msgstr "A-Ž"
#: data/gtk/window.blp:383
msgid "Z-A"
msgstr "Ž-A"
#: data/gtk/window.blp:389
msgid "Newest"
msgstr "Nejnovější"
#: data/gtk/window.blp:395
msgid "Oldest"
msgstr "Nejstarší"
#: data/gtk/window.blp:401
msgid "Last Played"
msgstr "Naposledy hráno"
#: data/gtk/window.blp:408
msgid "Show Hidden"
msgstr "Zobrazit Skryté"
#: data/gtk/window.blp:421
msgid "Keyboard Shortcuts"
msgstr "Klávesové zkratky"
#: data/gtk/window.blp:426
msgid "About Cartridges"
msgstr "O Kazetách"
#. Translators: Replace this with your name for it to show up in the about window
#: src/main.py:180
msgid "translator_credits"
msgstr "ooo.i.love.foo"
#. The variable is the date when the game was added
#: src/window.py:194
msgid "Added: {}"
msgstr "Přidáno: {}"
#: src/window.py:197
msgid "Never"
msgstr "Nikdy"
#. The variable is the date when the game was last played
#: src/window.py:201
msgid "Last played: {}"
msgstr "Naposledy hráno: {}"
#: src/details_window.py:72
msgid "Apply"
msgstr "Použít"
#: src/details_window.py:78
msgid "Add New Game"
msgstr "Přidat novou hru"
#: src/details_window.py:79
msgid "Confirm"
msgstr "Potvrdit"
#. Translate this string as you would translate "file"
#: src/details_window.py:92
msgid "file.txt"
msgstr "soubor.txt"
#. As in software
#: src/details_window.py:94
msgid "program"
msgstr "program"
#. Translate this string as you would translate "path to {}"
#: src/details_window.py:99 src/details_window.py:101
msgid "C:\\path\\to\\{}"
msgstr "C:\\cesta\\k\\{}"
#. Translate this string as you would translate "path to {}"
#: src/details_window.py:105 src/details_window.py:107
msgid "/path/to/{}"
msgstr "/cesta/k/{}"
#: src/details_window.py:112
msgid ""
"To launch the executable \"{}\", use the command:\n"
"\n"
"<tt>\"{}\"</tt>\n"
"\n"
"To open the file \"{}\" with the default application, use:\n"
"\n"
"<tt>{} \"{}\"</tt>\n"
"\n"
"If the path contains spaces, make sure to wrap it in double quotes!"
msgstr ""
"Chcete-li spustit spustitelný soubor \"{}\", použijte příkaz:\n"
"\n"
"<tt>\"{}\"</tt>\n"
"\n"
"Chcete-li otevřít soubor \"{}\" pomocí výchozí aplikace, použijte příkaz:\n"
"\n"
"<tt>{} \"{}\"</tt>\n"
"\n"
"Pokud cesta obsahuje mezery, nezapomeňte ji zabalit do dvojitých uvozovek!"
#: src/details_window.py:147 src/details_window.py:153
msgid "Couldn't Add Game"
msgstr "Nelze přidat hru"
#: src/details_window.py:147 src/details_window.py:181
msgid "Game title cannot be empty."
msgstr "Název hry nemůže být prázdný."
#: src/details_window.py:153 src/details_window.py:189
msgid "Executable cannot be empty."
msgstr "Spustitelný soubor nemůže být prázdný."
#: src/details_window.py:180 src/details_window.py:188
msgid "Couldn't Apply Preferences"
msgstr "Nelze použít předvolby"
#. The variable is the title of the game
#: src/game.py:138
msgid "{} launched"
msgstr "{} spuštěno"
#. The variable is the title of the game
#: src/game.py:152
msgid "{} hidden"
msgstr "{} skryto"
#: src/game.py:152
msgid "{} unhidden"
msgstr "{} odkryto"
#: src/game.py:169
msgid "{} removed"
msgstr "{} odstraněno"
#: src/preferences.py:111
msgid "All games removed"
msgstr "Všechny hry odstraněny"
#: src/preferences.py:159
msgid ""
"An API key is required to use SteamGridDB. You can generate one {}here{}."
msgstr ""
"K používání služby SteamGridDB je vyžadován klíč API. Můžete si ho "
"vygenerovat {}zde{}."
#: src/preferences.py:284
msgid "Installation Not Found"
msgstr "Instalace nebyla nalezena"
#: src/preferences.py:286
msgid "Select a valid directory."
msgstr "Vyberte platný adresář."
#: src/preferences.py:348
msgid "Invalid Directory"
msgstr "Neplatný adresář"
#. The variable is the name of the source
#: src/preferences.py:352
msgid "Select the {} cache directory."
msgstr "Vyberte adresář {} mezipaměti."
#. The variable is the name of the source
#: src/preferences.py:355
msgid "Select the {} configuration directory."
msgstr "Vyberte konfigurační adresář {}."
#. The variable is the name of the source
#: src/preferences.py:358
msgid "Select the {} data directory."
msgstr "Vyberte datový adresář {}."
#: src/preferences.py:364
msgid "Set Location"
msgstr "Nastavit umístění"
#: src/utils/create_dialog.py:25
msgid "Dismiss"
msgstr "Zahodit"
#: src/store/managers/sgdb_manager.py:47
msgid "Couldn't Authenticate SteamGridDB"
msgstr "Nelze ověřit SteamGridDB"
#: src/store/managers/sgdb_manager.py:48
msgid "Verify your API key in preferences"
msgstr "Ověřte váš klíč API v předvolbách"

View File

@@ -12,8 +12,8 @@ msgstr ""
"Project-Id-Version: cartridges\n" "Project-Id-Version: cartridges\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2023-07-05 14:36+0200\n" "POT-Creation-Date: 2023-07-05 14:36+0200\n"
"PO-Revision-Date: 2023-07-05 13:13+0000\n" "PO-Revision-Date: 2023-07-24 13:05+0000\n"
"Last-Translator: Geoffrey Coulaud <geoffrey.coulaud+github@gmail.com>\n" "Last-Translator: rene-coty <irenee.thirion@e.email>\n"
"Language-Team: French <https://hosted.weblate.org/projects/cartridges/" "Language-Team: French <https://hosted.weblate.org/projects/cartridges/"
"cartridges/fr/>\n" "cartridges/fr/>\n"
"Language: fr\n" "Language: fr\n"
@@ -27,7 +27,7 @@ msgstr ""
#: data/hu.kramo.Cartridges.metainfo.xml.in:6 data/gtk/window.blp:47 #: data/hu.kramo.Cartridges.metainfo.xml.in:6 data/gtk/window.blp:47
#: src/main.py:162 #: src/main.py:162
msgid "Cartridges" msgid "Cartridges"
msgstr "Cartridges" msgstr "Cartouches"
#: data/hu.kramo.Cartridges.desktop.in:4 #: data/hu.kramo.Cartridges.desktop.in:4
msgid "Game Launcher" msgid "Game Launcher"
@@ -49,7 +49,7 @@ msgid ""
"necessary. You can sort and hide games or download cover art from " "necessary. You can sort and hide games or download cover art from "
"SteamGridDB." "SteamGridDB."
msgstr "" msgstr ""
"Cartridges est un lanceur de jeux simple pour tous vos jeux. Il prend en " "Cartouches est un lanceur de jeux simple pour tous vos jeux. Il prend en "
"charge limportation des jeux depuis Steam, Lutris, Heroic et dautres " "charge limportation des jeux depuis Steam, Lutris, Heroic et dautres "
"encore, sans nécessiter de connexion. Vous pouvez trier et masquer les jeux " "encore, sans nécessiter de connexion. Vous pouvez trier et masquer les jeux "
"ou télécharger la pochette depuis SteamGridDB." "ou télécharger la pochette depuis SteamGridDB."
@@ -398,7 +398,7 @@ msgstr "Raccourcis clavier"
#: data/gtk/window.blp:426 #: data/gtk/window.blp:426
msgid "About Cartridges" msgid "About Cartridges"
msgstr "À propos de Cartridges" msgstr "À propos de Cartouches"
#. Translators: Replace this with your name for it to show up in the about window #. Translators: Replace this with your name for it to show up in the about window
#: src/main.py:180 #: src/main.py:180

View File

@@ -4,13 +4,14 @@
# Alessandro Iepure <alessandro.iepure@gmail.com>, 2023. # Alessandro Iepure <alessandro.iepure@gmail.com>, 2023.
# albanobattistella <albano_battistella@hotmail.com>, 2023. # albanobattistella <albano_battistella@hotmail.com>, 2023.
# kramo <contact@kramo.hu>, 2023. # kramo <contact@kramo.hu>, 2023.
# Giasko <dibiame@hotmail.it>, 2023.
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: cartridges\n" "Project-Id-Version: cartridges\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2023-07-05 14:36+0200\n" "POT-Creation-Date: 2023-07-05 14:36+0200\n"
"PO-Revision-Date: 2023-07-08 14:52+0000\n" "PO-Revision-Date: 2023-07-21 12:16+0000\n"
"Last-Translator: Alessandro Iepure <alessandro.iepure@gmail.com>\n" "Last-Translator: Giasko <dibiame@hotmail.it>\n"
"Language-Team: Italian <https://hosted.weblate.org/projects/cartridges/" "Language-Team: Italian <https://hosted.weblate.org/projects/cartridges/"
"cartridges/it/>\n" "cartridges/it/>\n"
"Language: it\n" "Language: it\n"
@@ -132,7 +133,7 @@ msgstr "Generale"
#: data/gtk/help-overlay.blp:14 #: data/gtk/help-overlay.blp:14
msgid "Quit" msgid "Quit"
msgstr "Chiudi" msgstr "Esci"
#: data/gtk/help-overlay.blp:19 data/gtk/window.blp:217 data/gtk/window.blp:257 #: data/gtk/help-overlay.blp:19 data/gtk/window.blp:217 data/gtk/window.blp:257
#: data/gtk/window.blp:323 #: data/gtk/window.blp:323
@@ -273,7 +274,7 @@ msgstr "itch"
#: data/gtk/preferences.blp:216 #: data/gtk/preferences.blp:216
msgid "Legendary" msgid "Legendary"
msgstr "Leggendario" msgstr "Legendary"
#: data/gtk/preferences.blp:230 #: data/gtk/preferences.blp:230
msgid "Flatpak" msgid "Flatpak"

View File

@@ -3,13 +3,15 @@
# This file is distributed under the same license as the Cartridges package. # This file is distributed under the same license as the Cartridges package.
# Artur Wróblewski <krypalkora1984@gmail.com>, 2023. # Artur Wróblewski <krypalkora1984@gmail.com>, 2023.
# Kshyso <Kshysio@protonmail.com>, 2023. # Kshyso <Kshysio@protonmail.com>, 2023.
# Eryk Michalak <gnu.ewm@protonmail.com>, 2023.
# Michaks <fexwex3@gmail.com>, 2023.
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: Cartridges\n" "Project-Id-Version: Cartridges\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2023-07-05 14:36+0200\n" "POT-Creation-Date: 2023-07-05 14:36+0200\n"
"PO-Revision-Date: 2023-06-10 16:48+0000\n" "PO-Revision-Date: 2023-07-24 13:05+0000\n"
"Last-Translator: Kshyso <Kshysio@protonmail.com>\n" "Last-Translator: Michaks <fexwex3@gmail.com>\n"
"Language-Team: Polish <https://hosted.weblate.org/projects/cartridges/" "Language-Team: Polish <https://hosted.weblate.org/projects/cartridges/"
"cartridges/pl/>\n" "cartridges/pl/>\n"
"Language: pl\n" "Language: pl\n"
@@ -18,13 +20,13 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 " "Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 "
"|| n%100>=20) ? 1 : 2;\n" "|| n%100>=20) ? 1 : 2;\n"
"X-Generator: Weblate 4.18-dev\n" "X-Generator: Weblate 5.0-dev\n"
#: data/hu.kramo.Cartridges.desktop.in:3 #: data/hu.kramo.Cartridges.desktop.in:3
#: data/hu.kramo.Cartridges.metainfo.xml.in:6 data/gtk/window.blp:47 #: data/hu.kramo.Cartridges.metainfo.xml.in:6 data/gtk/window.blp:47
#: src/main.py:162 #: src/main.py:162
msgid "Cartridges" msgid "Cartridges"
msgstr "Cartridges" msgstr "Kartridże"
#: data/hu.kramo.Cartridges.desktop.in:4 #: data/hu.kramo.Cartridges.desktop.in:4
msgid "Game Launcher" msgid "Game Launcher"
@@ -37,7 +39,7 @@ msgstr "Uruchom wszystkie swoje gry"
#: data/hu.kramo.Cartridges.desktop.in:11 #: data/hu.kramo.Cartridges.desktop.in:11
msgid "gaming;launcher;steam;lutris;heroic;bottles;itch;" msgid "gaming;launcher;steam;lutris;heroic;bottles;itch;"
msgstr "" msgstr "gry;gaming;launcher;steam;lutris;heroic;bottles;itch;"
#: data/hu.kramo.Cartridges.metainfo.xml.in:9 #: data/hu.kramo.Cartridges.metainfo.xml.in:9
msgid "" msgid ""
@@ -56,16 +58,16 @@ msgstr "Biblioteka"
#: data/hu.kramo.Cartridges.metainfo.xml.in:34 src/details_window.py:67 #: data/hu.kramo.Cartridges.metainfo.xml.in:34 src/details_window.py:67
msgid "Edit Game Details" msgid "Edit Game Details"
msgstr "Edytuj detale gry" msgstr "Edycja szczegółów gry"
#: data/hu.kramo.Cartridges.metainfo.xml.in:38 data/gtk/window.blp:71 #: data/hu.kramo.Cartridges.metainfo.xml.in:38 data/gtk/window.blp:71
msgid "Game Details" msgid "Game Details"
msgstr "Detale gry" msgstr "Szczegóły gry"
#: data/hu.kramo.Cartridges.metainfo.xml.in:42 data/gtk/window.blp:416 #: data/hu.kramo.Cartridges.metainfo.xml.in:42 data/gtk/window.blp:416
#: src/details_window.py:239 #: src/details_window.py:239
msgid "Preferences" msgid "Preferences"
msgstr "Ustawienia" msgstr "Preferencje"
#: data/gtk/details-window.blp:25 #: data/gtk/details-window.blp:25
msgid "Cancel" msgid "Cancel"
@@ -73,11 +75,11 @@ msgstr "Anuluj"
#: data/gtk/details-window.blp:57 #: data/gtk/details-window.blp:57
msgid "New Cover" msgid "New Cover"
msgstr "Nowa Okładka" msgstr "Nowa okładka"
#: data/gtk/details-window.blp:75 #: data/gtk/details-window.blp:75
msgid "Delete Cover" msgid "Delete Cover"
msgstr "Usuń Okładkę" msgstr "Usuń osłonę"
#: data/gtk/details-window.blp:101 data/gtk/details-window.blp:106 #: data/gtk/details-window.blp:101 data/gtk/details-window.blp:106
#: data/gtk/game.blp:80 #: data/gtk/game.blp:80
@@ -86,7 +88,7 @@ msgstr "Tytuł"
#: data/gtk/details-window.blp:102 #: data/gtk/details-window.blp:102
msgid "The title of the game" msgid "The title of the game"
msgstr "Tytuł gry" msgstr "Tytuł Gry"
#: data/gtk/details-window.blp:112 data/gtk/details-window.blp:117 #: data/gtk/details-window.blp:112 data/gtk/details-window.blp:117
msgid "Developer" msgid "Developer"
@@ -107,7 +109,7 @@ msgstr ""
#: data/gtk/details-window.blp:130 #: data/gtk/details-window.blp:130
msgid "More Info" msgid "More Info"
msgstr "" msgstr "Więcej informacji"
#: data/gtk/game.blp:102 data/gtk/game.blp:121 data/gtk/window.blp:195 #: data/gtk/game.blp:102 data/gtk/game.blp:121 data/gtk/window.blp:195
msgid "Edit" msgid "Edit"
@@ -149,7 +151,7 @@ msgstr "Skróty"
#: data/gtk/help-overlay.blp:34 src/game.py:102 src/preferences.py:112 #: data/gtk/help-overlay.blp:34 src/game.py:102 src/preferences.py:112
msgid "Undo" msgid "Undo"
msgstr "Cofnij" msgstr "Wróć"
#: data/gtk/help-overlay.blp:39 #: data/gtk/help-overlay.blp:39
msgid "Open menu" msgid "Open menu"
@@ -161,7 +163,7 @@ msgstr "Gry"
#: data/gtk/help-overlay.blp:48 #: data/gtk/help-overlay.blp:48
msgid "Add new game" msgid "Add new game"
msgstr "Dodaj nową grę" msgstr "Dodaj nową gre"
#: data/gtk/help-overlay.blp:53 #: data/gtk/help-overlay.blp:53
msgid "Import games" msgid "Import games"
@@ -185,7 +187,7 @@ msgstr "Wyjdź po uruchomieniu gry"
#: data/gtk/preferences.blp:25 #: data/gtk/preferences.blp:25
msgid "Cover Image Launches Game" msgid "Cover Image Launches Game"
msgstr "Obraz okładki startera gier" msgstr "Obraz okładki uruchamia grę"
#: data/gtk/preferences.blp:26 #: data/gtk/preferences.blp:26
msgid "Swaps the behavior of the cover image and the play button" msgid "Swaps the behavior of the cover image and the play button"
@@ -227,30 +229,24 @@ msgstr "Steam"
#: data/gtk/preferences.blp:151 data/gtk/preferences.blp:192 #: data/gtk/preferences.blp:151 data/gtk/preferences.blp:192
#: data/gtk/preferences.blp:206 data/gtk/preferences.blp:220 #: data/gtk/preferences.blp:206 data/gtk/preferences.blp:220
#: data/gtk/preferences.blp:234 #: data/gtk/preferences.blp:234
#, fuzzy
#| msgid "itch Install Location"
msgid "Install Location" msgid "Install Location"
msgstr "Położenie instalacji itch" msgstr "Lokalizacja instalacji"
#: data/gtk/preferences.blp:106 #: data/gtk/preferences.blp:106
msgid "Lutris" msgid "Lutris"
msgstr "Lutris" msgstr "Lutris"
#: data/gtk/preferences.blp:119 #: data/gtk/preferences.blp:119
#, fuzzy
#| msgid "Lutris Cache Location"
msgid "Cache Location" msgid "Cache Location"
msgstr "Lokalizacja Lutris Cache" msgstr "Lokalizacja pamięci podręcznej"
#: data/gtk/preferences.blp:128 #: data/gtk/preferences.blp:128
msgid "Import Steam Games" msgid "Import Steam Games"
msgstr "Importuj gry Steam" msgstr "Importuj gry Steam"
#: data/gtk/preferences.blp:137 #: data/gtk/preferences.blp:137
#, fuzzy
#| msgid "Import Steam Games"
msgid "Import Flatpak Games" msgid "Import Flatpak Games"
msgstr "Importuj gry Steam" msgstr "Importuj gry Flatpak"
#: data/gtk/preferences.blp:147 #: data/gtk/preferences.blp:147
msgid "Heroic" msgid "Heroic"
@@ -278,17 +274,15 @@ msgstr "itch"
#: data/gtk/preferences.blp:216 #: data/gtk/preferences.blp:216
msgid "Legendary" msgid "Legendary"
msgstr "" msgstr "Legendarne"
#: data/gtk/preferences.blp:230 #: data/gtk/preferences.blp:230
msgid "Flatpak" msgid "Flatpak"
msgstr "" msgstr "Flatpak"
#: data/gtk/preferences.blp:243 #: data/gtk/preferences.blp:243
#, fuzzy
#| msgid "Game Launcher"
msgid "Import Game Launchers" msgid "Import Game Launchers"
msgstr "Launcher Gier" msgstr "Importuj programy uruchamiające gry"
#: data/gtk/preferences.blp:256 #: data/gtk/preferences.blp:256
msgid "SteamGridDB" msgid "SteamGridDB"
@@ -344,7 +338,7 @@ msgstr "Gry, które ukryjesz, pojawią się tutaj."
#: data/gtk/window.blp:64 data/gtk/window.blp:304 #: data/gtk/window.blp:64 data/gtk/window.blp:304
msgid "Back" msgid "Back"
msgstr "Cofnij" msgstr "Powrót"
#: data/gtk/window.blp:121 #: data/gtk/window.blp:121
msgid "Game Title" msgid "Game Title"
@@ -352,7 +346,7 @@ msgstr "Tytuł gry"
#: data/gtk/window.blp:176 #: data/gtk/window.blp:176
msgid "Play" msgid "Play"
msgstr "Uruchom" msgstr "Graj"
#: data/gtk/window.blp:243 data/gtk/window.blp:435 #: data/gtk/window.blp:243 data/gtk/window.blp:435
msgid "Add Game" msgid "Add Game"
@@ -400,7 +394,7 @@ msgstr "Skróty klawiaturowe"
#: data/gtk/window.blp:426 #: data/gtk/window.blp:426
msgid "About Cartridges" msgid "About Cartridges"
msgstr "O Cartridges" msgstr "O Kartridżach"
#. Translators: Replace this with your name for it to show up in the about window #. Translators: Replace this with your name for it to show up in the about window
#: src/main.py:180 #: src/main.py:180
@@ -427,7 +421,7 @@ msgstr "Zastosuj"
#: src/details_window.py:78 #: src/details_window.py:78
msgid "Add New Game" msgid "Add New Game"
msgstr "Dodaj nową grę" msgstr "Dodaj nową Grę"
#: src/details_window.py:79 #: src/details_window.py:79
msgid "Confirm" msgid "Confirm"
@@ -521,59 +515,47 @@ msgstr ""
"{} tutaj{}." "{} tutaj{}."
#: src/preferences.py:284 #: src/preferences.py:284
#, fuzzy
#| msgid "Installation Not Found"
msgid "Installation Not Found" msgid "Installation Not Found"
msgstr "Nie znaleziono instalacji" msgstr "Nie znaleziono instalacji"
#: src/preferences.py:286 #: src/preferences.py:286
#, fuzzy
#| msgid "Select the {} data directory."
msgid "Select a valid directory." msgid "Select a valid directory."
msgstr "Wybierz {} katalog danych." msgstr "Wybierz prawidłowy katalog."
#: src/preferences.py:348 #: src/preferences.py:348
msgid "Invalid Directory" msgid "Invalid Directory"
msgstr "" msgstr "Nieprawidłowy katalog"
#. The variable is the name of the source #. The variable is the name of the source
#: src/preferences.py:352 #: src/preferences.py:352
#, fuzzy
#| msgid "Select the {} data directory."
msgid "Select the {} cache directory." msgid "Select the {} cache directory."
msgstr "Wybierz {} katalog danych." msgstr "Wybierz katalog pamięci podręcznej {}."
#. The variable is the name of the source #. The variable is the name of the source
#: src/preferences.py:355 #: src/preferences.py:355
#, fuzzy
#| msgid "Select the {} configuration directory."
msgid "Select the {} configuration directory." msgid "Select the {} configuration directory."
msgstr "Wybierz {} katalog konfiguracyjny." msgstr "Wybierz katalog konfiguracyjny {}."
#. The variable is the name of the source #. The variable is the name of the source
#: src/preferences.py:358 #: src/preferences.py:358
#, fuzzy
#| msgid "Select the {} data directory."
msgid "Select the {} data directory." msgid "Select the {} data directory."
msgstr "Wybierz {} katalog danych." msgstr "Wybierz katalog z danymi {}."
#: src/preferences.py:364 #: src/preferences.py:364
msgid "Set Location" msgid "Set Location"
msgstr "Ustaw lokacje" msgstr "Ustaw położenie"
#: src/utils/create_dialog.py:25 #: src/utils/create_dialog.py:25
msgid "Dismiss" msgid "Dismiss"
msgstr "Odrzucić" msgstr "Odrzucić"
#: src/store/managers/sgdb_manager.py:47 #: src/store/managers/sgdb_manager.py:47
#, fuzzy
#| msgid "Couldn't Connect to SteamGridDB"
msgid "Couldn't Authenticate SteamGridDB" msgid "Couldn't Authenticate SteamGridDB"
msgstr "Nie można połączyć się z SteamGridDB" msgstr "Nie można uwierzytelnić SteamGridDB"
#: src/store/managers/sgdb_manager.py:48 #: src/store/managers/sgdb_manager.py:48
msgid "Verify your API key in preferences" msgid "Verify your API key in preferences"
msgstr "" msgstr "Zweryfikuj swój klucz API w preferencjach"
#, fuzzy #, fuzzy
#~| msgid "Cache Not Found" #~| msgid "Cache Not Found"

View File

@@ -3,13 +3,14 @@
# This file is distributed under the same license as the Cartridges package. # This file is distributed under the same license as the Cartridges package.
# Henrique Machado <henriquecamposrj@gmail.com>, 2023. # Henrique Machado <henriquecamposrj@gmail.com>, 2023.
# Vinícius Gama Santos <vinny.stalck@protonmail.com>, 2023. # Vinícius Gama Santos <vinny.stalck@protonmail.com>, 2023.
# Vítor Fernandes Almado <vfalmado@gmail.com>, 2023.
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: Cartridges\n" "Project-Id-Version: Cartridges\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2023-07-05 14:36+0200\n" "POT-Creation-Date: 2023-07-05 14:36+0200\n"
"PO-Revision-Date: 2023-06-02 15:40+0000\n" "PO-Revision-Date: 2023-07-11 15:52+0000\n"
"Last-Translator: Vinícius Gama Santos <vinny.stalck@protonmail.com>\n" "Last-Translator: Vítor Fernandes Almado <vfalmado@gmail.com>\n"
"Language-Team: Portuguese (Brazil) <https://hosted.weblate.org/projects/" "Language-Team: Portuguese (Brazil) <https://hosted.weblate.org/projects/"
"cartridges/cartridges/pt_BR/>\n" "cartridges/cartridges/pt_BR/>\n"
"Language: pt_BR\n" "Language: pt_BR\n"
@@ -17,7 +18,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n > 1;\n" "Plural-Forms: nplurals=2; plural=n > 1;\n"
"X-Generator: Weblate 4.18-dev\n" "X-Generator: Weblate 5.0-dev\n"
#: data/hu.kramo.Cartridges.desktop.in:3 #: data/hu.kramo.Cartridges.desktop.in:3
#: data/hu.kramo.Cartridges.metainfo.xml.in:6 data/gtk/window.blp:47 #: data/hu.kramo.Cartridges.metainfo.xml.in:6 data/gtk/window.blp:47
@@ -277,11 +278,11 @@ msgstr "itch"
#: data/gtk/preferences.blp:216 #: data/gtk/preferences.blp:216
msgid "Legendary" msgid "Legendary"
msgstr "" msgstr "Lendário"
#: data/gtk/preferences.blp:230 #: data/gtk/preferences.blp:230
msgid "Flatpak" msgid "Flatpak"
msgstr "" msgstr "Flatpak"
#: data/gtk/preferences.blp:243 #: data/gtk/preferences.blp:243
#, fuzzy #, fuzzy
@@ -533,7 +534,7 @@ msgstr "Selecione o diretório de dados do(a) {}."
#: src/preferences.py:348 #: src/preferences.py:348
msgid "Invalid Directory" msgid "Invalid Directory"
msgstr "" msgstr "Diretório inválido"
#. The variable is the name of the source #. The variable is the name of the source
#: src/preferences.py:352 #: src/preferences.py:352
@@ -572,7 +573,7 @@ msgstr "Não foi possível conectar-se ao SteamGridDB"
#: src/store/managers/sgdb_manager.py:48 #: src/store/managers/sgdb_manager.py:48
msgid "Verify your API key in preferences" msgid "Verify your API key in preferences"
msgstr "" msgstr "Verifique sua chave API nas preferências"
#, fuzzy #, fuzzy
#~| msgid "Cache Not Found" #~| msgid "Cache Not Found"

View File

@@ -7,7 +7,7 @@ msgstr ""
"Project-Id-Version: Cartridges\n" "Project-Id-Version: Cartridges\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2023-07-05 14:36+0200\n" "POT-Creation-Date: 2023-07-05 14:36+0200\n"
"PO-Revision-Date: 2023-05-26 18:10+0000\n" "PO-Revision-Date: 2023-07-15 22:51+0000\n"
"Last-Translator: Sabri Ünal <libreajans@gmail.com>\n" "Last-Translator: Sabri Ünal <libreajans@gmail.com>\n"
"Language-Team: Turkish <https://hosted.weblate.org/projects/cartridges/" "Language-Team: Turkish <https://hosted.weblate.org/projects/cartridges/"
"cartridges/tr/>\n" "cartridges/tr/>\n"
@@ -16,7 +16,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n" "Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Weblate 4.18-dev\n" "X-Generator: Weblate 5.0-dev\n"
#: data/hu.kramo.Cartridges.desktop.in:3 #: data/hu.kramo.Cartridges.desktop.in:3
#: data/hu.kramo.Cartridges.metainfo.xml.in:6 data/gtk/window.blp:47 #: data/hu.kramo.Cartridges.metainfo.xml.in:6 data/gtk/window.blp:47
@@ -227,30 +227,24 @@ msgstr "Steam"
#: data/gtk/preferences.blp:151 data/gtk/preferences.blp:192 #: data/gtk/preferences.blp:151 data/gtk/preferences.blp:192
#: data/gtk/preferences.blp:206 data/gtk/preferences.blp:220 #: data/gtk/preferences.blp:206 data/gtk/preferences.blp:220
#: data/gtk/preferences.blp:234 #: data/gtk/preferences.blp:234
#, fuzzy
#| msgid "itch Install Location"
msgid "Install Location" msgid "Install Location"
msgstr "itch Kurulu Konumu" msgstr "Kurulu Konumu"
#: data/gtk/preferences.blp:106 #: data/gtk/preferences.blp:106
msgid "Lutris" msgid "Lutris"
msgstr "Lutris" msgstr "Lutris"
#: data/gtk/preferences.blp:119 #: data/gtk/preferences.blp:119
#, fuzzy
#| msgid "Lutris Cache Location"
msgid "Cache Location" msgid "Cache Location"
msgstr "Lutris Önbellek Konumu" msgstr "Önbellek Konumu"
#: data/gtk/preferences.blp:128 #: data/gtk/preferences.blp:128
msgid "Import Steam Games" msgid "Import Steam Games"
msgstr "Steam Oyunlarını İçe Aktar" msgstr "Steam Oyunlarını İçe Aktar"
#: data/gtk/preferences.blp:137 #: data/gtk/preferences.blp:137
#, fuzzy
#| msgid "Import Steam Games"
msgid "Import Flatpak Games" msgid "Import Flatpak Games"
msgstr "Steam Oyunlarını İçe Aktar" msgstr "Flatpak Oyunlarını İçe Aktarın"
#: data/gtk/preferences.blp:147 #: data/gtk/preferences.blp:147
msgid "Heroic" msgid "Heroic"
@@ -278,17 +272,15 @@ msgstr "itch"
#: data/gtk/preferences.blp:216 #: data/gtk/preferences.blp:216
msgid "Legendary" msgid "Legendary"
msgstr "" msgstr "Efsanevi"
#: data/gtk/preferences.blp:230 #: data/gtk/preferences.blp:230
msgid "Flatpak" msgid "Flatpak"
msgstr "" msgstr "Flatpak"
#: data/gtk/preferences.blp:243 #: data/gtk/preferences.blp:243
#, fuzzy
#| msgid "Game Launcher"
msgid "Import Game Launchers" msgid "Import Game Launchers"
msgstr "Oyun Başlatıcı" msgstr "Oyun Başlatıcıları İçe Aktar"
#: data/gtk/preferences.blp:256 #: data/gtk/preferences.blp:256
msgid "SteamGridDB" msgid "SteamGridDB"
@@ -521,39 +513,29 @@ msgstr ""
"oluşturabilirsiniz." "oluşturabilirsiniz."
#: src/preferences.py:284 #: src/preferences.py:284
#, fuzzy
#| msgid "Installation Not Found"
msgid "Installation Not Found" msgid "Installation Not Found"
msgstr "Kurulum Bulunamadı" msgstr "Kurulum Bulunamadı"
#: src/preferences.py:286 #: src/preferences.py:286
#, fuzzy
#| msgid "Select the {} data directory."
msgid "Select a valid directory." msgid "Select a valid directory."
msgstr "{} veri dizinini seç." msgstr "Geçerli bir dizin seçin."
#: src/preferences.py:348 #: src/preferences.py:348
msgid "Invalid Directory" msgid "Invalid Directory"
msgstr "" msgstr "Geçersiz Dizin"
#. The variable is the name of the source #. The variable is the name of the source
#: src/preferences.py:352 #: src/preferences.py:352
#, fuzzy
#| msgid "Select the {} data directory."
msgid "Select the {} cache directory." msgid "Select the {} cache directory."
msgstr "{} veri dizinini seç." msgstr "{} önbellek dizinini seç."
#. The variable is the name of the source #. The variable is the name of the source
#: src/preferences.py:355 #: src/preferences.py:355
#, fuzzy
#| msgid "Select the {} configuration directory."
msgid "Select the {} configuration directory." msgid "Select the {} configuration directory."
msgstr "{} yapılandırma dizinini seç." msgstr "{} yapılandırma dizinini seç."
#. The variable is the name of the source #. The variable is the name of the source
#: src/preferences.py:358 #: src/preferences.py:358
#, fuzzy
#| msgid "Select the {} data directory."
msgid "Select the {} data directory." msgid "Select the {} data directory."
msgstr "{} veri dizinini seç." msgstr "{} veri dizinini seç."
@@ -566,14 +548,12 @@ msgid "Dismiss"
msgstr "Vazgeç" msgstr "Vazgeç"
#: src/store/managers/sgdb_manager.py:47 #: src/store/managers/sgdb_manager.py:47
#, fuzzy
#| msgid "Couldn't Connect to SteamGridDB"
msgid "Couldn't Authenticate SteamGridDB" msgid "Couldn't Authenticate SteamGridDB"
msgstr "SteamGridDBʼye bağlanılamadı" msgstr "SteamGridDB Kimlik Doğrulaması Yapılamadı"
#: src/store/managers/sgdb_manager.py:48 #: src/store/managers/sgdb_manager.py:48
msgid "Verify your API key in preferences" msgid "Verify your API key in preferences"
msgstr "" msgstr "Tercihlerde API anahtarınızı doğrulayın"
#, fuzzy #, fuzzy
#~| msgid "Cache Not Found" #~| msgid "Cache Not Found"

View File

@@ -26,17 +26,13 @@ import yaml
from src import shared from src import shared
from src.game import Game from src.game import Game
from src.importer.sources.location import Location from src.importer.sources.location import Location
from src.importer.sources.source import ( from src.importer.sources.source import SourceIterable, URLExecutableSource
SourceIterationResult,
SourceIterator,
URLExecutableSource,
)
class BottlesSourceIterator(SourceIterator): class BottlesSourceIterable(SourceIterable):
source: "BottlesSource" source: "BottlesSource"
def generator_builder(self) -> SourceIterationResult: def __iter__(self):
"""Generator method producing games""" """Generator method producing games"""
data = self.source.data_location["library.yml"].read_text("utf-8") data = self.source.data_location["library.yml"].read_text("utf-8")
@@ -83,8 +79,8 @@ class BottlesSourceIterator(SourceIterator):
class BottlesSource(URLExecutableSource): class BottlesSource(URLExecutableSource):
"""Generic Bottles source""" """Generic Bottles source"""
name = "Bottles" name = _("Bottles")
iterator_class = BottlesSourceIterator iterable_class = BottlesSourceIterable
url_format = 'bottles:run/"{bottle_name}"/"{game_name}"' url_format = 'bottles:run/"{bottle_name}"/"{game_name}"'
available_on = {"linux"} available_on = {"linux"}

View File

@@ -25,13 +25,13 @@ from gi.repository import GLib, Gtk
from src import shared from src import shared
from src.game import Game from src.game import Game
from src.importer.sources.location import Location from src.importer.sources.location import Location
from src.importer.sources.source import Source, SourceIterationResult, SourceIterator from src.importer.sources.source import Source, SourceIterable
class FlatpakSourceIterator(SourceIterator): class FlatpakSourceIterable(SourceIterable):
source: "FlatpakSource" source: "FlatpakSource"
def generator_builder(self) -> SourceIterationResult: def __iter__(self):
"""Generator method producing games""" """Generator method producing games"""
added_time = int(time()) added_time = int(time())
@@ -114,8 +114,8 @@ class FlatpakSourceIterator(SourceIterator):
class FlatpakSource(Source): class FlatpakSource(Source):
"""Generic Flatpak source""" """Generic Flatpak source"""
name = "Flatpak" name = _("Flatpak")
iterator_class = FlatpakSourceIterator iterable_class = FlatpakSourceIterable
executable_format = "flatpak run {flatpak_id}" executable_format = "flatpak run {flatpak_id}"
available_on = {"linux"} available_on = {"linux"}

View File

@@ -20,21 +20,47 @@
import json import json
import logging import logging
from abc import abstractmethod
from hashlib import sha256 from hashlib import sha256
from json import JSONDecodeError from json import JSONDecodeError
from pathlib import Path
from time import time from time import time
from typing import Optional, TypedDict from typing import Iterable, Optional, TypedDict
from functools import cached_property
from src import shared from src import shared
from src.game import Game from src.game import Game
from src.importer.sources.location import Location from src.importer.sources.location import Location
from src.importer.sources.source import ( from src.importer.sources.source import (
URLExecutableSource, SourceIterable,
SourceIterationResult, SourceIterationResult,
SourceIterator, URLExecutableSource,
) )
def path_json_load(path: Path):
"""
Load JSON from the file at the given path
:raises OSError: if the file can't be opened
:raises JSONDecodeError: if the file isn't valid JSON
"""
with path.open("r", encoding="utf-8") as open_file:
return json.load(open_file)
class InvalidLibraryFileError(Exception):
pass
class InvalidInstalledFileError(Exception):
pass
class InvalidStoreFileError(Exception):
pass
class HeroicLibraryEntry(TypedDict): class HeroicLibraryEntry(TypedDict):
app_name: str app_name: str
installed: Optional[bool] installed: Optional[bool]
@@ -44,115 +70,304 @@ class HeroicLibraryEntry(TypedDict):
art_square: str art_square: str
class HeroicSubSource(TypedDict): class SubSourceIterable(Iterable):
service: str """Class representing a Heroic sub-source"""
path: tuple[str]
class HeroicSourceIterator(SourceIterator):
source: "HeroicSource" source: "HeroicSource"
source_iterable: "HeroicSourceIterable"
name: str
service: str
image_uri_params: str = ""
relative_library_path: Path
library_json_entries_key: str = "library"
sub_sources: dict[str, HeroicSubSource] = { def __init__(self, source, source_iterable) -> None:
"sideload": { self.source = source
"service": "sideload", self.source_iterable = source_iterable
"path": ("sideload_apps", "library.json"),
},
"legendary": {
"service": "epic",
"path": ("store_cache", "legendary_library.json"),
},
"gog": {
"service": "gog",
"path": ("store_cache", "gog_library.json"),
},
}
def game_from_library_entry( @cached_property
def library_path(self) -> Path:
path = self.source.config_location.root / self.relative_library_path
logging.debug("Using Heroic %s library.json path %s", self.name, path)
return path
def process_library_entry(
self, entry: HeroicLibraryEntry, added_time: int self, entry: HeroicLibraryEntry, added_time: int
) -> SourceIterationResult: ) -> SourceIterationResult:
"""Helper method used to build a Game from a Heroic library entry""" """Build a Game from a Heroic library entry"""
# Skip games that are not installed app_name = entry["app_name"]
if not entry["is_installed"]:
return None
# Build game # Build game
app_name = entry["app_name"]
runner = entry["runner"]
service = self.sub_sources[runner]["service"]
values = { values = {
"source": f"{self.source.id}_{service}", "source": f"{self.source.id}_{self.service}",
"added": added_time, "added": added_time,
"name": entry["title"], "name": entry["title"],
"developer": entry.get("developer", None), "developer": entry.get("developer", None),
"game_id": self.source.game_id_format.format( "game_id": self.source.game_id_format.format(
service=service, game_id=app_name service=self.service, game_id=app_name
), ),
"executable": self.source.executable_format.format(app_name=app_name), "executable": self.source.executable_format.format(app_name=app_name),
"hidden": self.source_iterable.is_hidden(app_name),
} }
game = Game(values) game = Game(values)
# Get the image path 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 # Filenames are derived from the URL that heroic used to get the file
uri: str = entry["art_square"] uri: str = entry["art_square"] + self.image_uri_params
if service == "epic":
uri += "?h=400&resize=1&w=300"
digest = sha256(uri.encode()).hexdigest() digest = sha256(uri.encode()).hexdigest()
image_path = self.source.config_location.root / "images-cache" / digest image_path = self.source.config_location.root / "images-cache" / digest
additional_data = {"local_image_path": image_path} additional_data = {"local_image_path": image_path}
return (game, additional_data) return (game, additional_data)
def generator_builder(self) -> SourceIterationResult: def __iter__(self):
"""
Iterate through the games with a generator
:raises InvalidLibraryFileError: on initial call if the library file is bad
"""
added_time = int(time())
try:
iterator = iter(
path_json_load(self.library_path)[self.library_json_entries_key]
)
except (OSError, JSONDecodeError, TypeError, KeyError) as error:
raise InvalidLibraryFileError(
f"Invalid {self.library_path.name}"
) from error
for entry in iterator:
try:
yield self.process_library_entry(entry, added_time)
except KeyError as error:
logging.warning(
"Skipped invalid %s game %s",
self.name,
entry.get("app_name", "UNKNOWN"),
exc_info=error,
)
continue
class StoreSubSourceIterable(SubSourceIterable):
"""
Class representing a "store" sub source.
Games can be installed or not, this class does the check accordingly.
"""
relative_installed_path: Path
installed_app_names: set[str]
@cached_property
def installed_path(self) -> Path:
path = self.source.config_location.root / self.relative_installed_path
logging.debug("Using Heroic %s installed.json path %s", self.name, path)
return path
@abstractmethod
def get_installed_app_names(self) -> set[str]:
"""
Get the sub source's installed app names as a set.
:raises InvalidInstalledFileError: if the installed file data cannot be read
Whenever possible, `__cause__` is set with the original exception
"""
def is_installed(self, app_name: str) -> bool:
return app_name in self.installed_app_names
def process_library_entry(self, entry, added_time):
# Skip games that are not installed
app_name = entry["app_name"]
if not self.is_installed(app_name):
logging.warning(
"Skipped %s game %s (%s): not installed",
self.service,
entry["title"],
app_name,
)
return None
# Process entry as normal
return super().process_library_entry(entry, added_time)
def __iter__(self):
"""
Iterate through the installed games with a generator
:raises InvalidLibraryFileError: on initial call if the library file is bad
:raises InvalidInstalledFileError: on initial call if the installed file is bad
"""
self.installed_app_names = self.get_installed_app_names()
yield from super().__iter__()
class SideloadIterable(SubSourceIterable):
name = "sideload"
service = "sideload"
relative_library_path = Path("sideload_apps") / "library.json"
library_json_entries_key = "games"
class LegendaryIterable(StoreSubSourceIterable):
name = "legendary"
service = "epic"
image_uri_params = "?h=400&resize=1&w=300"
relative_library_path = Path("store_cache") / "legendary_library.json"
# relative_installed_path = (
# Path("legendary") / "legendaryConfig" / "legendary" / "installed.json"
# )
@cached_property
def installed_path(self) -> Path:
"""
Get the right path depending on the Heroic version
TODO after heroic 2.9 has been out for a while
We should use the commented out relative_installed_path
and remove this property override.
"""
heroic_config_path = self.source.config_location.root
# Heroic >= 2.9
if (path := heroic_config_path / "legendaryConfig").is_dir():
logging.debug("Using Heroic >= 2.9 legendary file")
# Heroic <= 2.8
elif heroic_config_path.is_relative_to(shared.flatpak_dir):
# Heroic flatpak
path = shared.flatpak_dir / "com.heroicgameslauncher.hgl" / "config"
logging.debug("Using Heroic flatpak <= 2.8 legendary file")
else:
# Heroic native
logging.debug("Using Heroic native <= 2.8 legendary file")
path = Path.home() / ".config"
path = path / "legendary" / "installed.json"
logging.debug("Using Heroic %s installed.json path %s", self.name, path)
return path
def get_installed_app_names(self):
try:
return set(path_json_load(self.installed_path).keys())
except (OSError, JSONDecodeError, AttributeError) as error:
raise InvalidInstalledFileError(
f"Invalid {self.installed_path.name}"
) from error
class GogIterable(StoreSubSourceIterable):
name = "gog"
service = "gog"
library_json_entries_key = "games"
relative_library_path = Path("store_cache") / "gog_library.json"
relative_installed_path = Path("gog_store") / "installed.json"
def get_installed_app_names(self):
try:
return {
app_name
for entry in path_json_load(self.installed_path)["installed"]
if (app_name := entry.get("appName")) is not None
}
except (OSError, JSONDecodeError, KeyError, AttributeError) as error:
raise InvalidInstalledFileError(
f"Invalid {self.installed_path.name}"
) from error
class NileIterable(StoreSubSourceIterable):
name = "nile"
service = "amazon"
relative_library_path = Path("store_cache") / "nile_library.json"
relative_installed_path = Path("nile_config") / "nile" / "installed.json"
def get_installed_app_names(self):
try:
installed_json = path_json_load(self.installed_path)
return {
app_name
for entry in installed_json
if (app_name := entry.get("id")) is not None
}
except (OSError, JSONDecodeError, AttributeError) as error:
raise InvalidInstalledFileError(
f"Invalid {self.installed_path.name}"
) from error
class HeroicSourceIterable(SourceIterable):
source: "HeroicSource"
hidden_app_names: set[str] = set()
def is_hidden(self, app_name: str) -> bool:
return app_name in self.hidden_app_names
def get_hidden_app_names(self) -> set[str]:
"""Get the hidden app names from store/config.json
:raises InvalidStoreFileError: if the store is invalid for some reason
"""
try:
store = path_json_load(self.source.config_location["store_config.json"])
self.hidden_app_names = {
app_name
for game in store["games"]["hidden"]
if (app_name := game.get("appName")) is not None
}
except KeyError:
logging.warning('No ["games"]["hidden"] key in Heroic store file')
except (OSError, JSONDecodeError, TypeError) as error:
logging.error("Invalid Heroic store file", exc_info=error)
raise InvalidStoreFileError() from error
def __iter__(self):
"""Generator method producing games from all the Heroic sub-sources""" """Generator method producing games from all the Heroic sub-sources"""
for sub_source_name, sub_source in self.sub_sources.items(): self.get_hidden_app_names()
# Skip disabled sub-sources
if not shared.schema.get_boolean("heroic-import-" + sub_source["service"]): # Get games from the sub sources
for sub_source_class in (
SideloadIterable,
LegendaryIterable,
GogIterable,
NileIterable,
):
sub_source = sub_source_class(self.source, self)
if not shared.schema.get_boolean("heroic-import-" + sub_source.service):
logging.debug("Skipping Heroic %s: disabled", sub_source.service)
continue continue
# Load games from JSON
file = self.source.config_location.root.joinpath(*sub_source["path"])
try: try:
contents = json.load(file.open()) sub_source_iterable = iter(sub_source)
key = "library" if sub_source_name == "legendary" else "games" yield from sub_source_iterable
library = contents[key] except (InvalidLibraryFileError, InvalidInstalledFileError) as error:
except (JSONDecodeError, OSError, KeyError): logging.error(
# Invalid library.json file, skip it "Skipping bad Heroic sub-source %s",
logging.warning("Couldn't open Heroic file: %s", str(file)) sub_source.service,
exc_info=error,
)
continue continue
added_time = int(time())
for entry in library:
try:
result = self.game_from_library_entry(entry, added_time)
except KeyError as error:
# Skip invalid games
logging.warning(
"Invalid Heroic game skipped in %s", str(file), exc_info=error
)
continue
yield result
class HeroicSource(URLExecutableSource): class HeroicSource(URLExecutableSource):
"""Generic Heroic Games Launcher source""" """Generic Heroic Games Launcher source"""
name = "Heroic" name = _("Heroic")
iterator_class = HeroicSourceIterator iterable_class = HeroicSourceIterable
url_format = "heroic://launch/{app_name}" url_format = "heroic://launch/{app_name}"
available_on = {"linux", "win32"} available_on = {"linux", "win32"}
config_location = Location( config_location = Location(
schema_key="heroic-location", schema_key="heroic-location",
candidates=( candidates=(
shared.flatpak_dir / "com.heroicgameslauncher.hgl" / "config" / "heroic",
shared.config_dir / "heroic", shared.config_dir / "heroic",
shared.home / ".config" / "heroic", shared.home / ".config" / "heroic",
shared.flatpak_dir / "com.heroicgameslauncher.hgl" / "config" / "heroic",
shared.appdata_dir / "heroic", shared.appdata_dir / "heroic",
), ),
paths={ paths={
"config.json": (False, "config.json"), "config.json": (False, "config.json"),
"store_config.json": (False, Path("store") / "config.json"),
}, },
) )

View File

@@ -25,18 +25,14 @@ 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.location import Location from src.importer.sources.location import Location
from src.importer.sources.source import ( from src.importer.sources.source import SourceIterable, URLExecutableSource
SourceIterationResult,
SourceIterator,
URLExecutableSource,
)
from src.utils.sqlite import copy_db from src.utils.sqlite import copy_db
class ItchSourceIterator(SourceIterator): class ItchSourceIterable(SourceIterable):
source: "ItchSource" source: "ItchSource"
def generator_builder(self) -> SourceIterationResult: def __iter__(self):
"""Generator method producing games""" """Generator method producing games"""
# Query the database # Query the database
@@ -79,8 +75,8 @@ class ItchSourceIterator(SourceIterator):
class ItchSource(URLExecutableSource): class ItchSource(URLExecutableSource):
name = "Itch" name = _("itch")
iterator_class = ItchSourceIterator iterable_class = ItchSourceIterable
url_format = "itch://caves/{cave_id}/launch" url_format = "itch://caves/{cave_id}/launch"
available_on = {"linux", "win32"} available_on = {"linux", "win32"}

View File

@@ -21,15 +21,14 @@ import json
import logging import logging
from json import JSONDecodeError from json import JSONDecodeError
from time import time from time import time
from typing import Generator
from src import shared from src import shared
from src.game import Game from src.game import Game
from src.importer.sources.location import Location from src.importer.sources.location import Location
from src.importer.sources.source import Source, SourceIterationResult, SourceIterator from src.importer.sources.source import Source, SourceIterationResult, SourceIterable
class LegendarySourceIterator(SourceIterator): class LegendarySourceIterable(SourceIterable):
source: "LegendarySource" source: "LegendarySource"
def game_from_library_entry( def game_from_library_entry(
@@ -65,7 +64,7 @@ class LegendarySourceIterator(SourceIterator):
game = Game(values) game = Game(values)
return (game, data) return (game, data)
def generator_builder(self) -> Generator[SourceIterationResult, None, None]: def __iter__(self):
# Open library # Open library
file = self.source.config_location["installed.json"] file = self.source.config_location["installed.json"]
try: try:
@@ -90,11 +89,11 @@ class LegendarySourceIterator(SourceIterator):
class LegendarySource(Source): class LegendarySource(Source):
name = "Legendary" name = _("Legendary")
executable_format = "legendary launch {app_name}" executable_format = "legendary launch {app_name}"
available_on = {"linux"} available_on = {"linux"}
iterator_class = LegendarySourceIterator iterable_class = LegendarySourceIterable
config_location: Location = Location( config_location: Location = Location(
schema_key="legendary-location", schema_key="legendary-location",
candidates=( candidates=(

View File

@@ -24,18 +24,14 @@ 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.location import Location from src.importer.sources.location import Location
from src.importer.sources.source import ( from src.importer.sources.source import SourceIterable, URLExecutableSource
SourceIterationResult,
SourceIterator,
URLExecutableSource,
)
from src.utils.sqlite import copy_db from src.utils.sqlite import copy_db
class LutrisSourceIterator(SourceIterator): class LutrisSourceIterable(SourceIterable):
source: "LutrisSource" source: "LutrisSource"
def generator_builder(self) -> SourceIterationResult: def __iter__(self):
"""Generator method producing games""" """Generator method producing games"""
# Query the database # Query the database
@@ -90,8 +86,8 @@ class LutrisSourceIterator(SourceIterator):
class LutrisSource(URLExecutableSource): class LutrisSource(URLExecutableSource):
"""Generic Lutris source""" """Generic Lutris source"""
name = "Lutris" name = _("Lutris")
iterator_class = LutrisSourceIterator iterable_class = LutrisSourceIterable
url_format = "lutris:rungameid/{game_id}" url_format = "lutris:rungameid/{game_id}"
available_on = {"linux"} available_on = {"linux"}

View File

@@ -29,25 +29,16 @@ from src.importer.sources.location import Location
SourceIterationResult = None | Game | tuple[Game, tuple[Any]] SourceIterationResult = None | Game | tuple[Game, tuple[Any]]
class SourceIterator(Iterator): class SourceIterable(Iterable):
"""Data producer for a source of games""" """Data producer for a source of games"""
source: "Source" = None source: "Source" = None
generator: Generator = None
def __init__(self, source: "Source") -> None: def __init__(self, source: "Source") -> None:
super().__init__()
self.source = source self.source = source
self.generator = self.generator_builder()
def __iter__(self) -> "SourceIterator":
return self
def __next__(self) -> SourceIterationResult:
return next(self.generator)
@abstractmethod @abstractmethod
def generator_builder(self) -> Generator[SourceIterationResult, None, None]: def __iter__(self) -> Generator[SourceIterationResult, None, None]:
""" """
Method that returns a generator that produces games Method that returns a generator that produces games
* Should be implemented as a generator method * Should be implemented as a generator method
@@ -66,7 +57,7 @@ class Source(Iterable):
data_location: Optional[Location] = None data_location: Optional[Location] = None
cache_location: Optional[Location] = None cache_location: Optional[Location] = None
config_location: Optional[Location] = None config_location: Optional[Location] = None
iterator_class: type[SourceIterator] iterable_class: type[SourceIterable]
@property @property
def full_name(self) -> str: def full_name(self) -> str:
@@ -98,7 +89,7 @@ class Source(Iterable):
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"""
def __iter__(self) -> SourceIterator: def __iter__(self) -> Generator[SourceIterationResult, None, None]:
""" """
Get an iterator for the source Get an iterator for the source
:raises UnresolvableLocationError: Not iterable if any of the locations are unresolvable :raises UnresolvableLocationError: Not iterable if any of the locations are unresolvable
@@ -108,7 +99,7 @@ class Source(Iterable):
if location is None: if location is None:
continue continue
location.resolve() location.resolve()
return self.iterator_class(self) return iter(self.iterable_class(self))
# pylint: disable=abstract-method # pylint: disable=abstract-method

View File

@@ -18,6 +18,7 @@
# #
# SPDX-License-Identifier: GPL-3.0-or-later # SPDX-License-Identifier: GPL-3.0-or-later
import logging
import re import re
from pathlib import Path from pathlib import Path
from time import time from time import time
@@ -25,16 +26,12 @@ from typing import Iterable
from src import shared from src import shared
from src.game import Game from src.game import Game
from src.importer.sources.source import (
SourceIterationResult,
SourceIterator,
URLExecutableSource,
)
from src.utils.steam import SteamFileHelper, SteamInvalidManifestError
from src.importer.sources.location import Location from src.importer.sources.location import Location
from src.importer.sources.source import SourceIterable, URLExecutableSource
from src.utils.steam import SteamFileHelper, SteamInvalidManifestError
class SteamSourceIterator(SourceIterator): class SteamSourceIterable(SourceIterable):
source: "SteamSource" source: "SteamSource"
def get_manifest_dirs(self) -> Iterable[Path]: def get_manifest_dirs(self) -> Iterable[Path]:
@@ -62,7 +59,7 @@ class SteamSourceIterator(SourceIterator):
) )
return manifests return manifests
def generator_builder(self) -> SourceIterationResult: def __iter__(self):
"""Generator method producing games""" """Generator method producing games"""
appid_cache = set() appid_cache = set()
manifests = self.get_manifests() manifests = self.get_manifests()
@@ -74,17 +71,20 @@ class SteamSourceIterator(SourceIterator):
steam = SteamFileHelper() steam = SteamFileHelper()
try: try:
local_data = steam.get_manifest_data(manifest) local_data = steam.get_manifest_data(manifest)
except (OSError, SteamInvalidManifestError): except (OSError, SteamInvalidManifestError) as error:
logging.debug("Couldn't load appmanifest %s", manifest, exc_info=error)
continue continue
# Skip non installed games # Skip non installed games
installed_mask = 4 installed_mask = 4
if not int(local_data["stateflags"]) & installed_mask: if not int(local_data["stateflags"]) & installed_mask:
logging.debug("Skipped %s: not installed", manifest)
continue continue
# Skip duplicate appids # Skip duplicate appids
appid = local_data["appid"] appid = local_data["appid"]
if appid in appid_cache: if appid in appid_cache:
logging.debug("Skipped %s: appid already seen during import", manifest)
continue continue
appid_cache.add(appid) appid_cache.add(appid)
@@ -110,9 +110,9 @@ class SteamSourceIterator(SourceIterator):
class SteamSource(URLExecutableSource): class SteamSource(URLExecutableSource):
name = "Steam" name = _("Steam")
available_on = {"linux", "win32"} available_on = {"linux", "win32"}
iterator_class = SteamSourceIterator iterable_class = SteamSourceIterable
url_format = "steam://rungameid/{game_id}" url_format = "steam://rungameid/{game_id}"
data_location = Location( data_location = Location(

View File

@@ -73,7 +73,7 @@ def setup_logging():
"PIL": { "PIL": {
"handlers": ["lib_console_handler", "file_handler"], "handlers": ["lib_console_handler", "file_handler"],
"propagate": False, "propagate": False,
"level": "NOTSET", "level": "WARNING",
}, },
"urllib3": { "urllib3": {
"handlers": ["lib_console_handler", "file_handler"], "handlers": ["lib_console_handler", "file_handler"],

View File

@@ -68,6 +68,7 @@ class PreferencesWindow(Adw.PreferencesWindow):
heroic_config_file_chooser_button = Gtk.Template.Child() heroic_config_file_chooser_button = Gtk.Template.Child()
heroic_import_epic_switch = Gtk.Template.Child() heroic_import_epic_switch = Gtk.Template.Child()
heroic_import_gog_switch = Gtk.Template.Child() heroic_import_gog_switch = Gtk.Template.Child()
heroic_import_amazon_switch = Gtk.Template.Child()
heroic_import_sideload_switch = Gtk.Template.Child() heroic_import_sideload_switch = Gtk.Template.Child()
bottles_expander_row = Gtk.Template.Child() bottles_expander_row = Gtk.Template.Child()
@@ -181,6 +182,7 @@ class PreferencesWindow(Adw.PreferencesWindow):
"lutris-import-flatpak", "lutris-import-flatpak",
"heroic-import-epic", "heroic-import-epic",
"heroic-import-gog", "heroic-import-gog",
"heroic-import-amazon",
"heroic-import-sideload", "heroic-import-sideload",
"flatpak-import-launchers", "flatpak-import-launchers",
"sgdb", "sgdb",

View File

@@ -18,6 +18,8 @@
# #
# SPDX-License-Identifier: GPL-3.0-or-later # SPDX-License-Identifier: GPL-3.0-or-later
import logging
from gi.repository import GdkPixbuf from gi.repository import GdkPixbuf
from src import shared from src import shared
@@ -35,6 +37,7 @@ class LocalCoverManager(Manager):
def manager_logic(self, game: Game, additional_data: dict) -> None: def manager_logic(self, game: Game, additional_data: dict) -> None:
if image_path := additional_data.get("local_image_path"): if image_path := additional_data.get("local_image_path"):
if not image_path.is_file(): if not image_path.is_file():
logging.error("Local image path is not a file: %s", image_path)
return return
save_cover(game.game_id, resize_cover(image_path)) save_cover(game.game_id, resize_cover(image_path))
elif icon_path := additional_data.get("local_icon_path"): elif icon_path := additional_data.get("local_icon_path"):

View File

@@ -61,9 +61,9 @@ def migrate_files_v1_to_v2():
logging.info("Migrating data dir %s", str(old_data_dir)) logging.info("Migrating data dir %s", str(old_data_dir))
# Create the current data dir if needed # Create new directories
if not shared.data_dir.is_dir(): shared.games_dir.mkdir(parents=True, exist_ok=True)
shared.data_dir.mkdir(parents=True) shared.covers_dir.mkdir(parents=True, exist_ok=True)
old_game_paths = set(old_games_dir.glob("*.json")) old_game_paths = set(old_games_dir.glob("*.json"))
old_imported_game_paths = set( old_imported_game_paths = set(

View File

@@ -142,8 +142,7 @@ class SteamAPIHelper:
raise SteamGameNotFoundError() raise SteamGameNotFoundError()
# Handle appid is not a game # Handle appid is not a game
game_types = ("game", "demo") if data["data"]["type"] not in {"game", "demo", "mod"}:
if data["data"]["type"] not in game_types:
logging.debug("Appid %s is not a game", appid) logging.debug("Appid %s is not a game", appid)
raise SteamNotAGameError() raise SteamNotAGameError()