Merge pull request #20 from Bananaman/launch_rework
Improved game executable launcher, and added argument validation
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,3 +1,4 @@
|
|||||||
/subprojects/blueprint-compiler
|
/subprojects/blueprint-compiler
|
||||||
/.flatpak
|
/.flatpak
|
||||||
|
/.flatpak-builder
|
||||||
/.vscode
|
/.vscode
|
||||||
@@ -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
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
@@ -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,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -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()
|
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
@@ -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"]
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user