Merge pull request #20 from Bananaman/launch_rework

Improved game executable launcher, and added argument validation
This commit is contained in:
kramo
2023-03-24 22:42:09 +01:00
committed by GitHub
9 changed files with 38 additions and 27 deletions

1
.gitignore vendored
View File

@@ -1,3 +1,4 @@
/subprojects/blueprint-compiler /subprojects/blueprint-compiler
/.flatpak /.flatpak
/.flatpak-builder
/.vscode /.vscode

View File

@@ -95,7 +95,6 @@ def bottles_parser(parent_widget, action):
with open(os.path.join(bottles_dir, "library.yml"), "r") as open_file: with open(os.path.join(bottles_dir, "library.yml"), "r") as open_file:
data = open_file.read() data = open_file.read()
open_file.close()
library = yaml.load(data, Loader=yaml.Loader) library = yaml.load(data, Loader=yaml.Loader)
@@ -112,9 +111,10 @@ def bottles_parser(parent_widget, action):
continue continue
values["name"] = game["name"] values["name"] = game["name"]
values["executable"] = "xdg-open " + shlex.quote( values["executable"] = [
"xdg-open",
f'bottles:run/{game["bottle"]["name"]}/{game["name"]}' f'bottles:run/{game["bottle"]["name"]}/{game["name"]}'
) ]
values["hidden"] = False values["hidden"] = False
values["source"] = "bottles" values["source"] = "bottles"
values["added"] = current_time values["added"] = current_time

View File

@@ -19,6 +19,7 @@
import json import json
import os import os
import shlex
import time import time
from gi.repository import Adw, GdkPixbuf, Gio, GLib, GObject, Gtk from gi.repository import Adw, GdkPixbuf, Gio, GLib, GObject, Gtk
@@ -52,7 +53,7 @@ def create_details_window(parent_widget, game_id=None):
) )
name = Gtk.Entry.new_with_buffer(Gtk.EntryBuffer.new(games[game_id].name, -1)) name = Gtk.Entry.new_with_buffer(Gtk.EntryBuffer.new(games[game_id].name, -1))
executable = Gtk.Entry.new_with_buffer( executable = Gtk.Entry.new_with_buffer(
Gtk.EntryBuffer.new((games[game_id].executable), -1) Gtk.EntryBuffer.new(shlex.join(games[game_id].executable), -1)
) )
apply_button = Gtk.Button.new_with_label(_("Apply")) apply_button = Gtk.Button.new_with_label(_("Apply"))
@@ -201,6 +202,21 @@ def create_details_window(parent_widget, game_id=None):
final_developer = developer.get_buffer().get_text() final_developer = developer.get_buffer().get_text()
final_executable = executable.get_buffer().get_text() final_executable = executable.get_buffer().get_text()
try:
# Attempt to parse using shell parsing rules (doesn't verify executable existence).
final_executable_split = shlex.split(
final_executable, comments=False, posix=True
)
except Exception as e:
create_dialog(
window,
_("Couldn't Add Game")
if game_id is None
else _("Couldn't Apply Preferences"),
f'{_("Executable")}: {e}.', # e = Shell parsing error message. Not translatable.
)
return
if game_id is None: if game_id is None:
if final_name == "": if final_name == "":
create_dialog( create_dialog(
@@ -252,7 +268,7 @@ def create_details_window(parent_widget, game_id=None):
values["name"] = final_name values["name"] = final_name
values["developer"] = final_developer or None values["developer"] = final_developer or None
values["executable"] = final_executable values["executable"] = final_executable_split
path = os.path.join( path = os.path.join(
os.path.join( os.path.join(
@@ -267,7 +283,6 @@ def create_details_window(parent_widget, game_id=None):
if os.path.exists(path): if os.path.exists(path):
with open(path, "r") as open_file: with open(path, "r") as open_file:
data = json.loads(open_file.read()) data = json.loads(open_file.read())
open_file.close()
data.update(values) data.update(values)
save_games({game_id: data}) save_games({game_id: data})
else: else:

View File

@@ -41,6 +41,6 @@ def get_games(game_ids=None):
for game in game_files: for game in game_files:
with open(os.path.join(games_dir, game), "r") as open_file: with open(os.path.join(games_dir, game), "r") as open_file:
data = json.loads(open_file.read()) data = json.loads(open_file.read())
open_file.close() games[data["game_id"]] = data
games[data["game_id"]] = data
return games return games

View File

@@ -107,7 +107,6 @@ def heroic_parser(parent_widget, action):
os.path.join(heroic_dir, "lib-cache", "library.json"), "r" os.path.join(heroic_dir, "lib-cache", "library.json"), "r"
) as open_file: ) as open_file:
data = open_file.read() data = open_file.read()
open_file.close()
library = json.loads(data) library = json.loads(data)
try: try:
@@ -129,9 +128,9 @@ def heroic_parser(parent_widget, action):
values["name"] = game["title"] values["name"] = game["title"]
values["developer"] = game["developer"] values["developer"] = game["developer"]
values["executable"] = ( values["executable"] = (
f"start heroic://launch/{app_name}" ["start", f"heroic://launch/{app_name}"]
if os.name == "nt" if os.name == "nt"
else f"xdg-open heroic://launch/{app_name}" else ["xdg-open", f"heroic://launch/{app_name}"]
) )
values["hidden"] = False values["hidden"] = False
values["source"] = "heroic_epic" values["source"] = "heroic_epic"
@@ -160,7 +159,6 @@ def heroic_parser(parent_widget, action):
os.path.join(heroic_dir, "gog_store", "installed.json"), "r" os.path.join(heroic_dir, "gog_store", "installed.json"), "r"
) as open_file: ) as open_file:
data = open_file.read() data = open_file.read()
open_file.close()
installed = json.loads(data) installed = json.loads(data)
for item in installed["installed"]: for item in installed["installed"]:
values = {} values = {}
@@ -179,7 +177,6 @@ def heroic_parser(parent_widget, action):
os.path.join(heroic_dir, "gog_store", "library.json"), "r" os.path.join(heroic_dir, "gog_store", "library.json"), "r"
) as open_file: ) as open_file:
data = open_file.read() data = open_file.read()
open_file.close()
library = json.loads(data) library = json.loads(data)
for game in library["games"]: for game in library["games"]:
if game["app_name"] == app_name: if game["app_name"] == app_name:
@@ -195,9 +192,9 @@ def heroic_parser(parent_widget, action):
break break
values["executable"] = ( values["executable"] = (
f"start heroic://launch/{app_name}" ["start", f"heroic://launch/{app_name}"]
if os.name == "nt" if os.name == "nt"
else f"xdg-open heroic://launch/{app_name}" else ["xdg-open", f"heroic://launch/{app_name}"]
) )
values["hidden"] = False values["hidden"] = False
values["source"] = "heroic_gog" values["source"] = "heroic_gog"
@@ -214,7 +211,6 @@ def heroic_parser(parent_widget, action):
os.path.join(heroic_dir, "sideload_apps", "library.json"), "r" os.path.join(heroic_dir, "sideload_apps", "library.json"), "r"
) as open_file: ) as open_file:
data = open_file.read() data = open_file.read()
open_file.close()
library = json.loads(data) library = json.loads(data)
for item in library["games"]: for item in library["games"]:
values = {} values = {}
@@ -230,9 +226,9 @@ def heroic_parser(parent_widget, action):
values["name"] = item["title"] values["name"] = item["title"]
values["executable"] = ( values["executable"] = (
f"start heroic://launch/{app_name}" ["start", f"heroic://launch/{app_name}"]
if os.name == "nt" if os.name == "nt"
else f"xdg-open heroic://launch/{app_name}" else ["xdg-open", f"heroic://launch/{app_name}"]
) )
values["hidden"] = False values["hidden"] = False
values["source"] = "heroic_sideload" values["source"] = "heroic_sideload"

View File

@@ -18,6 +18,7 @@
# SPDX-License-Identifier: GPL-3.0-or-later # SPDX-License-Identifier: GPL-3.0-or-later
import os import os
import shlex
import subprocess import subprocess
import sys import sys
@@ -25,13 +26,14 @@ from gi.repository import Gio
def run_command(executable): def run_command(executable):
# The host environment vars are automatically passed through by Popen.
subprocess.Popen( subprocess.Popen(
[f"flatpak-spawn --host {executable}"] ["flatpak-spawn", "--host", *executable] # Flatpak
if os.getenv("FLATPAK_ID") == "hu.kramo.Cartridges" if os.getenv("FLATPAK_ID") == "hu.kramo.Cartridges"
else executable.split() else executable # Windows
if os.name == "nt" if os.name == "nt"
else [executable], else executable, # Linux/Others
shell=True, shell=False, # If true, the extra arguments would incorrectly be given to the shell instead.
start_new_session=True, start_new_session=True,
creationflags=subprocess.CREATE_NEW_PROCESS_GROUP if os.name == "nt" else 0, creationflags=subprocess.CREATE_NEW_PROCESS_GROUP if os.name == "nt" else 0,
) )

View File

@@ -35,4 +35,3 @@ def save_games(games):
for game in games: for game in games:
with open(os.path.join(games_dir, f"{game}.json"), "w") as open_file: with open(os.path.join(games_dir, f"{game}.json"), "w") as open_file:
open_file.write(json.dumps(games[game], indent=4, sort_keys=True)) open_file.write(json.dumps(games[game], indent=4, sort_keys=True))
open_file.close()

View File

@@ -49,7 +49,6 @@ def get_game(task, datatypes, current_time, parent_widget, appmanifest, steam_di
with open(appmanifest, "r") as open_file: with open(appmanifest, "r") as open_file:
data = open_file.read() data = open_file.read()
open_file.close()
for datatype in datatypes: for datatype in datatypes:
value = re.findall(f'"{datatype}"\t\t"(.*)"\n', data) value = re.findall(f'"{datatype}"\t\t"(.*)"\n', data)
values[datatype] = value[0] values[datatype] = value[0]
@@ -64,9 +63,9 @@ def get_game(task, datatypes, current_time, parent_widget, appmanifest, steam_di
return return
values["executable"] = ( values["executable"] = (
f'start steam://rungameid/{values["appid"]}' ["start", f'steam://rungameid/{values["appid"]}']
if os.name == "nt" if os.name == "nt"
else f'xdg-open steam://rungameid/{values["appid"]}' else ["xdg-open", f'steam://rungameid/{values["appid"]}']
) )
values["hidden"] = False values["hidden"] = False
values["source"] = "steam" values["source"] = "steam"

View File

@@ -36,7 +36,6 @@ def toggle_hidden(game):
with open(os.path.join(games_dir, f"{game}.json"), "r") as open_file: with open(os.path.join(games_dir, f"{game}.json"), "r") as open_file:
data = json.loads(open_file.read()) data = json.loads(open_file.read())
open_file.close()
data["hidden"] = not data["hidden"] data["hidden"] = not data["hidden"]