Added Lutris import

This commit is contained in:
kramo
2023-03-31 15:22:45 +02:00
parent a53e49610c
commit 780fd0a09f
12 changed files with 241 additions and 10 deletions

View File

@@ -108,6 +108,30 @@ template PreferencesWindow : Adw.PreferencesWindow {
}
}
Adw.ExpanderRow lutris_expander_row {
title: _("Lutris");
show-enable-switch: true;
Adw.ActionRow {
title: _("Lutris Install Location");
subtitle: _("Directory to use when importing games");
Button lutris_file_chooser_button {
icon-name: "folder-symbolic";
valign: center;
}
}
Adw.ActionRow {
title: _("Lutris Cache Location");
subtitle: _("Directory to use when importing game covers");
Button lutris_cache_file_chooser_button {
icon-name: "folder-symbolic";
valign: center;
}
}
}
Adw.ExpanderRow heroic_expander_row {
title: _("Heroic");
show-enable-switch: true;

View File

@@ -19,6 +19,15 @@
<key name="steam-extra-dirs" type="as">
<default>[]</default>
</key>
<key name="lutris" type="b">
<default>true</default>
</key>
<key name="lutris-location" type="s">
<default>"~/.var/app/net.lutris.Lutris/data/lutris/"</default>
</key>
<key name="lutris-cache-location" type="s">
<default>"~/.var/app/net.lutris.Lutris/cache/lutris"</default>
</key>
<key name="heroic" type="b">
<default>true</default>
</key>

View File

@@ -13,9 +13,12 @@
"--talk-name=org.gtk.vfs.*",
"--filesystem=xdg-run/gvfsd",
"--filesystem=~/.steam/steam/:ro",
"--filesystem=xdg-data/lutris/:ro",
"--filesystem=xdg-cache/lutris/:ro",
"--filesystem=xdg-config/heroic/:ro",
"--filesystem=xdg-data/bottles/:ro",
"--filesystem=~/.var/app/com.valvesoftware.Steam/data/Steam/:ro",
"--filesystem=~/.var/app/net.lutris.Lutris/:ro",
"--filesystem=~/.var/app/com.heroicgameslauncher.hgl/config/heroic/:ro",
"--filesystem=~/.var/app/com.usebottles.bottles/data/bottles/:ro"
],

View File

@@ -33,6 +33,7 @@ from .create_details_window import create_details_window
from .get_games import get_games
from .heroic_parser import heroic_parser
from .importer import Importer
from .lutris_parser import lutris_parser
from .preferences import PreferencesWindow
from .save_game import save_game
from .steam_parser import steam_parser
@@ -168,6 +169,9 @@ class CartridgesApplication(Adw.Application):
if self.win.schema.get_boolean("steam"):
steam_parser(self.win)
if self.win.schema.get_boolean("lutris"):
lutris_parser(self.win)
if self.win.schema.get_boolean("heroic"):
heroic_parser(self.win)

View File

@@ -26,6 +26,7 @@ cartridges_sources = [
'utils/steam_parser.py',
'utils/heroic_parser.py',
'utils/bottles_parser.py',
'utils/lutris_parser.py',
'utils/get_games.py',
'utils/save_game.py',
'utils/save_cover.py',

View File

@@ -98,6 +98,10 @@ class PreferencesWindow(Adw.PreferencesWindow):
steam_clear_button_revealer = Gtk.Template.Child()
steam_clear_button = Gtk.Template.Child()
lutris_expander_row = Gtk.Template.Child()
lutris_file_chooser_button = Gtk.Template.Child()
lutris_cache_file_chooser_button = Gtk.Template.Child()
heroic_expander_row = Gtk.Template.Child()
heroic_file_chooser_button = Gtk.Template.Child()
heroic_epic_switch = Gtk.Template.Child()
@@ -191,6 +195,45 @@ class PreferencesWindow(Adw.PreferencesWindow):
)
self.steam_clear_button.connect("clicked", clear_steam_dirs)
# Lutris
ImportPreferences(
self,
"lutris",
"Lutris",
"lutris-location",
["pga.db"],
self.lutris_expander_row,
self.lutris_file_chooser_button,
)
def set_cache_dir(_source, result, _unused):
try:
path = self.file_chooser.select_folder_finish(result).get_path()
def response(widget, response):
if response == "choose_folder":
self.choose_folder(widget, set_cache_dir)
if not os.path.exists(os.path.join(path, "coverart")):
create_dialog(
self.parent_widget,
_("Cache Not Found"),
_("Select the Lutris cache directory."),
"choose_folder",
_("Set Location"),
).connect("response", response)
else:
self.schema.set_string(
"lutris-cache-location",
path,
)
except GLib.GError:
pass
self.lutris_cache_file_chooser_button.connect(
"clicked", self.choose_folder, set_cache_dir
)
# Heroic
ImportPreferences(
self,

View File

@@ -18,7 +18,7 @@
# SPDX-License-Identifier: GPL-3.0-or-later
import os
import time
from time import time
import yaml
@@ -53,7 +53,7 @@ def bottles_parser(parent_widget):
return
bottles_dir = os.path.expanduser(schema.get_string("bottles-location"))
current_time = int(time.time())
current_time = int(time())
with open(os.path.join(bottles_dir, "library.yml"), "r") as open_file:
data = open_file.read()

View File

@@ -20,7 +20,7 @@
import hashlib
import json
import os
import time
from time import time
def heroic_parser(parent_widget):
@@ -60,7 +60,7 @@ def heroic_parser(parent_widget):
return
heroic_dir = os.path.expanduser(schema.get_string("heroic-location"))
current_time = int(time.time())
current_time = int(time())
importer = parent_widget.importer

149
src/utils/lutris_parser.py Normal file
View File

@@ -0,0 +1,149 @@
# lutris_parser.py
#
# Copyright 2022-2023 kramo
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# SPDX-License-Identifier: GPL-3.0-or-later
import os
import shutil
from sqlite3 import connect
from time import time
def lutris_parser(parent_widget):
schema = parent_widget.schema
database_path = os.path.join(
os.path.expanduser(schema.get_string("lutris-location")), "pga.db"
)
if not os.path.isfile(database_path):
if os.path.exists(
os.path.expanduser("~/.var/app/net.lutris.Lutris/data/lutris/")
):
schema.set_string(
"lutris-location", "~/.var/app/net.lutris.Lutris/data/lutris/"
)
elif os.path.exists(
os.path.join(
os.getenv("XDG_DATA_HOME")
or os.path.expanduser(os.path.join("~", ".local", "share")),
"lutris",
)
):
schema.set_string(
"lutris-location",
os.path.join(
os.getenv("XDG_DATA_HOME")
or os.path.expanduser(os.path.join("~", ".local", "share")),
"lutris",
),
)
else:
return
cache_dir = os.path.expanduser(schema.get_string("lutris-cache-location"))
if not os.path.exists(cache_dir):
if os.path.exists(
os.path.expanduser("~/.var/app/net.lutris.Lutris/cache/lutris/")
):
schema.set_string(
"lutris-cache-location", "~/.var/app/net.lutris.Lutris/cache/lutris/"
)
elif os.path.exists(
os.path.join(
os.getenv("XDG_CACHE_HOME")
or os.path.expanduser(os.path.join("~", ".cache")),
"lutris",
)
):
schema.set_string(
"lutris-cache-location",
os.path.join(
os.getenv("XDG_CACHE_HOME")
or os.path.expanduser(os.path.join("~", ".cache")),
"lutris",
),
)
else:
return
database_path = os.path.join(
os.path.expanduser(schema.get_string("lutris-location")), "pga.db"
)
cache_dir = os.path.expanduser(schema.get_string("lutris-cache-location"))
db_cache_dir = os.path.join(
os.getenv("XDG_CACHE_HOME") or os.path.expanduser(os.path.join("~", ".cache")),
"cartridges",
"lutris",
)
os.makedirs(db_cache_dir, exist_ok=True)
shutil.copyfile(database_path, os.path.join(db_cache_dir, "pga.db"))
db_request = """
SELECT
id, name, slug, runner, hidden
FROM
'games'
WHERE
name IS NOT NULL
AND slug IS NOT NULL
AND configPath IS NOT NULL
AND installed IS TRUE
;
"""
connection = connect(os.path.join(db_cache_dir, "pga.db"))
cursor = connection.execute(db_request)
rows = cursor.fetchall()
connection.close()
if schema.get_boolean("steam"):
rows = [row for row in rows if not row[3] == "steam"]
current_time = int(time())
importer = parent_widget.importer
importer.total_queue += len(rows)
importer.queue += len(rows)
for row in rows:
values = {}
values["game_id"] = f"lutris_{row[3]}_{row[0]}"
if (
values["game_id"] in parent_widget.games
and not parent_widget.games[values["game_id"]].removed
):
importer.save_game()
continue
values["added"] = current_time
values["executable"] = ["xdg-open", f"lutris:rungameid/{row[0]}"]
values["hidden"] = row[4] == 1
values["last_played"] = 0
values["name"] = row[1]
values["source"] = f"lutris_{row[3]}"
if os.path.isfile(os.path.join(cache_dir, "coverart", f"{row[2]}.jpg")):
importer.save_cover(
values["game_id"], os.path.join(cache_dir, "coverart", f"{row[2]}.jpg")
)
importer.save_game(values)

View File

@@ -30,8 +30,7 @@ def save_cover(parent_widget, game_id, cover_path, pixbuf=None):
"covers",
)
if not os.path.exists(covers_dir):
os.makedirs(covers_dir)
os.makedirs(covers_dir, exist_ok=True)
if pixbuf is None:
pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_scale(cover_path, 400, 600, False)

View File

@@ -29,8 +29,7 @@ def save_game(game):
"games",
)
if not os.path.exists(games_dir):
os.makedirs(games_dir)
os.makedirs(games_dir, exist_ok=True)
with open(os.path.join(games_dir, f'{game["game_id"]}.json'), "w") as open_file:
open_file.write(json.dumps(game, indent=4, sort_keys=True))

View File

@@ -20,8 +20,8 @@
import json
import os
import re
import time
import urllib.request
from time import time
from gi.repository import Gio, GLib
@@ -113,7 +113,7 @@ def get_game(
def get_games_async(parent_widget, appmanifests, steam_dir, importer):
datatypes = ["appid", "name"]
current_time = int(time.time())
current_time = int(time())
# Wrap the function in another one as Gio.Task.run_in_thread does not allow for passing args
def create_func(datatypes, current_time, parent_widget, appmanifest, steam_dir):