2024-01-17 12:31:04 +01:00
#!/usr/bin/env python3
2024-02-12 06:27:02 +01:00
import os , re
2024-01-17 12:31:04 +01:00
import json
import shutil
import binascii
2024-01-25 18:41:04 +01:00
import ctypes
2024-04-25 12:33:02 +02:00
import gzip
2024-01-17 12:31:04 +01:00
import zipfile
import time
import sys
import subprocess
2024-02-03 05:21:54 +01:00
import sqlite3
2024-11-05 14:35:35 +01:00
import csv
2024-01-17 12:31:04 +01:00
from urllib . request import urlopen
from urllib . request import urlretrieve
2024-08-08 12:34:47 +02:00
from urllib . parse import quote
2024-02-28 09:54:25 +01:00
from base64 import b64encode
2024-01-24 12:39:03 +01:00
import xml . etree . ElementTree as ET
2024-02-29 14:25:01 +01:00
2024-08-04 09:31:50 +02:00
# Check the value of the DBUS_SESSION_BUS_ADDRESS environment variable
dbus_address = os . environ . get ( ' DBUS_SESSION_BUS_ADDRESS ' )
if not dbus_address or not dbus_address . startswith ( ' unix:path= ' ) :
# Set the value of the DBUS_SESSION_BUS_ADDRESS environment variable
dbus_address = f ' unix:path=/run/user/ { os . getuid ( ) } /bus '
os . environ [ ' DBUS_SESSION_BUS_ADDRESS ' ] = dbus_address
2024-01-29 14:51:56 +01:00
# Path to the env_vars file
env_vars_path = f " { os . environ [ ' HOME ' ] } /.config/systemd/user/env_vars "
# Check if the env_vars file exists
if not os . path . exists ( env_vars_path ) :
print ( f " Error: { env_vars_path } does not exist. " )
sys . exit ( 1 )
# Read variables from the file
with open ( env_vars_path , ' r ' ) as f :
2024-01-17 12:31:04 +01:00
lines = f . readlines ( )
for line in lines :
if line . startswith ( ' export ' ) :
line = line [ 7 : ] # Remove 'export '
2024-02-06 10:20:00 +01:00
name , value = line . strip ( ) . split ( ' = ' , 1 )
2024-01-17 12:31:04 +01:00
os . environ [ name ] = value
2024-06-29 04:02:52 +02:00
# Store the value of separate_appids before deleting it
separate_appids = None
2024-02-09 15:23:36 +01:00
# Delete env_vars entries for Chrome shortcuts so that they're only added once
with open ( env_vars_path , ' w ' ) as f :
for line in lines :
2024-06-29 04:02:52 +02:00
if ' export separate_appids=false ' in line :
separate_appids = line . split ( ' = ' ) [ 1 ] . strip ( )
2024-02-09 15:23:36 +01:00
if line . find ( ' chromelaunchoptions ' ) == - 1 and line . find ( ' websites_str ' ) == - 1 :
f . write ( line )
2024-06-29 04:02:52 +02:00
2024-01-17 12:31:04 +01:00
# Variables from NonSteamLaunchers.sh
steamid3 = os . environ [ ' steamid3 ' ]
logged_in_home = os . environ [ ' logged_in_home ' ]
compat_tool_name = os . environ [ ' compat_tool_name ' ]
2024-02-06 10:20:00 +01:00
python_version = os . environ [ ' python_version ' ]
#Scanner Variables
2024-01-17 12:31:04 +01:00
epic_games_launcher = os . environ . get ( ' epic_games_launcher ' , ' ' )
ubisoft_connect_launcher = os . environ . get ( ' ubisoft_connect_launcher ' , ' ' )
2024-01-23 23:30:55 +01:00
ea_app_launcher = os . environ . get ( ' ea_app_launcher ' , ' ' )
2024-01-26 10:18:26 +01:00
gog_galaxy_launcher = os . environ . get ( ' gog_galaxy_launcher ' , ' ' )
2024-02-02 05:51:08 +01:00
bnet_launcher = os . environ . get ( ' bnet_launcher ' , ' ' )
2024-02-03 05:21:54 +01:00
amazon_launcher = os . environ . get ( ' amazon_launcher ' , ' ' )
2024-04-25 12:33:02 +02:00
itchio_launcher = os . environ . get ( ' itchio_launcher ' , ' ' )
2024-06-29 04:02:52 +02:00
legacy_launcher = os . environ . get ( ' legacy_launcher ' , ' ' )
2024-01-17 12:31:04 +01:00
2024-02-06 10:20:00 +01:00
#Variables of the Launchers
# Define the path of the Launchers
epicshortcutdirectory = os . environ . get ( ' epicshortcutdirectory ' )
gogshortcutdirectory = os . environ . get ( ' gogshortcutdirectory ' )
uplayshortcutdirectory = os . environ . get ( ' uplayshortcutdirectory ' )
battlenetshortcutdirectory = os . environ . get ( ' battlenetshortcutdirectory ' )
eaappshortcutdirectory = os . environ . get ( ' eaappshortcutdirectory ' )
amazonshortcutdirectory = os . environ . get ( ' amazonshortcutdirectory ' )
itchioshortcutdirectory = os . environ . get ( ' itchioshortcutdirectory ' )
legacyshortcutdirectory = os . environ . get ( ' legacyshortcutdirectory ' )
humbleshortcutdirectory = os . environ . get ( ' humbleshortcutdirectory ' )
indieshortcutdirectory = os . environ . get ( ' indieshortcutdirectory ' )
rockstarshortcutdirectory = os . environ . get ( ' rockstarshortcutdirectory ' )
glyphshortcutdirectory = os . environ . get ( ' glyphshortcutdirectory ' )
psplusshortcutdirectory = os . environ . get ( ' psplusshortcutdirectory ' )
2024-06-21 14:01:55 +02:00
vkplayshortcutdirectory = os . environ . get ( ' vkplayshortcutdirectory ' )
2024-07-03 14:04:46 +02:00
hoyoplayshortcutdirectory = os . environ . get ( ' hoyoplayshortcutfirectory ' )
2024-08-02 12:09:11 +02:00
nexonshortcutdirectory = os . environ . get ( ' nexonshortcutdirectory ' )
repaireaappshortcutdirectory = os . environ . get ( ' repaireaappshortcutdirectory ' )
2024-02-06 10:20:00 +01:00
#Streaming
chromedirectory = os . environ . get ( ' chromedirectory ' )
websites_str = os . environ . get ( ' custom_websites_str ' )
custom_websites = websites_str . split ( ' , ' ) if websites_str else [ ]
2024-01-17 12:31:04 +01:00
# Define the parent folder
2024-01-26 04:18:58 +01:00
parent_folder = f " { logged_in_home } /.config/systemd/user/Modules "
2024-02-12 06:16:50 +01:00
sys . path . insert ( 0 , os . path . expanduser ( f " { logged_in_home } /.config/systemd/user/Modules " ) )
2024-02-11 02:18:13 +01:00
print ( sys . path )
2024-01-17 12:31:04 +01:00
# Now that the requests module has been downloaded, you can import it
2024-01-26 04:18:58 +01:00
sys . path . insert ( 0 , parent_folder )
2024-01-17 12:31:04 +01:00
import requests
2024-02-10 23:28:17 +01:00
import vdf
2024-01-17 12:31:04 +01:00
from steamgrid import SteamGridDB
2024-01-26 04:18:58 +01:00
print ( sys . path )
2024-01-17 12:31:04 +01:00
2024-02-11 02:18:13 +01:00
2024-01-17 12:31:04 +01:00
#Set Up nslgamescanner.service
# Define the paths
service_path = f " { logged_in_home } /.config/systemd/user/nslgamescanner.service "
# Define the service file content
service_content = f """
[ Unit ]
Description = NSL Game Scanner
[ Service ]
ExecStart = / usr / bin / python3 ' {logged_in_home} /.config/systemd/user/NSLGameScanner.py '
Restart = always
RestartSec = 10
StartLimitBurst = 40
StartLimitInterval = 240
[ Install ]
WantedBy = default . target
"""
# Check if the service file already exists
if not os . path . exists ( service_path ) :
# Create the service file
with open ( service_path , ' w ' ) as f :
f . write ( service_content )
print ( " Service file created. " )
# Check if the service is already running
result = subprocess . run ( [ ' systemctl ' , ' --user ' , ' is-active ' , ' nslgamescanner.service ' ] , stdout = subprocess . PIPE )
if result . stdout . decode ( ' utf-8 ' ) . strip ( ) != ' active ' :
# Reload the systemd manager configuration
subprocess . run ( [ ' systemctl ' , ' --user ' , ' daemon-reload ' ] )
# Enable the service to start on boot
subprocess . run ( [ ' systemctl ' , ' --user ' , ' enable ' , ' nslgamescanner.service ' ] )
# Start the service immediately
subprocess . run ( [ ' systemctl ' , ' --user ' , ' start ' , ' nslgamescanner.service ' ] )
print ( " Service started. " )
else :
print ( " Service is already running. " )
#Code
def get_steam_shortcut_id ( exe_path , display_name ) :
2024-01-25 18:41:04 +01:00
unique_id = " " . join ( [ exe_path , display_name ] )
id_int = binascii . crc32 ( str . encode ( unique_id ) ) | 0x80000000
signed = ctypes . c_int ( id_int )
# print(f"Signed ID: {signed.value}")
return signed . value
2024-06-23 06:04:27 +02:00
2024-01-25 18:41:04 +01:00
def get_unsigned_shortcut_id ( signed_shortcut_id ) :
unsigned = ctypes . c_uint ( signed_shortcut_id )
# print(f"Unsigned ID: {unsigned.value}")
return unsigned . value
2024-01-17 12:31:04 +01:00
# Initialize an empty dictionary to serve as the cache
api_cache = { }
2024-06-23 22:02:18 +02:00
#API KEYS FOR NONSTEAMLAUNCHER USE ONLY
2024-12-11 15:20:31 +01:00
BASE_URL = ' https://nonsteamlaunchers.onrender.com/api '
2024-01-23 23:30:55 +01:00
#GLOBAL VARS
created_shortcuts = [ ]
new_shortcuts_added = False
2024-01-25 18:41:04 +01:00
shortcuts_updated = False
2024-01-23 23:30:55 +01:00
shortcut_id = None # Initialize shortcut_id
2024-02-28 09:54:25 +01:00
decky_shortcuts = { }
gridp64 = " "
grid64 = " "
logo64 = " "
hero64 = " "
2024-01-23 23:30:55 +01:00
2024-06-21 16:57:39 +02:00
2024-06-22 21:45:30 +02:00
def create_empty_shortcuts ( ) :
return { ' shortcuts ' : { } }
def write_shortcuts_to_file ( shortcuts_file , shortcuts ) :
with open ( shortcuts_file , ' wb ' ) as file :
file . write ( vdf . binary_dumps ( shortcuts ) )
os . chmod ( shortcuts_file , 0o755 )
# Define the path to the shortcuts file
shortcuts_file = f " { logged_in_home } /.steam/root/userdata/ { steamid3 } /config/shortcuts.vdf "
# Check if the file exists
if os . path . exists ( shortcuts_file ) :
# If the file is not executable, write the shortcuts dictionary and make it executable
if not os . access ( shortcuts_file , os . X_OK ) :
print ( " The file is not executable. Writing an empty shortcuts dictionary and making it executable. " )
shortcuts = create_empty_shortcuts ( )
write_shortcuts_to_file ( shortcuts_file , shortcuts )
else :
# Load the existing shortcuts
with open ( shortcuts_file , ' rb ' ) as file :
try :
shortcuts = vdf . binary_loads ( file . read ( ) )
except vdf . VDFError as e :
2024-06-23 08:44:05 +02:00
print ( f " Error reading file: { e } . The file might be corrupted or unreadable. " )
print ( " Exiting the program. Please check the shortcuts.vdf file. " )
sys . exit ( 1 )
2024-06-22 21:45:30 +02:00
else :
print ( " The shortcuts.vdf file does not exist. " )
sys . exit ( 1 )
2024-06-21 16:57:39 +02:00
2024-06-23 08:44:05 +02:00
2024-06-29 04:02:52 +02:00
2024-01-23 23:30:55 +01:00
# Open the config.vdf file
with open ( f " { logged_in_home } /.steam/root/config/config.vdf " , ' r ' ) as file :
config_data = vdf . load ( file )
2024-06-21 16:29:48 +02:00
2024-01-23 23:30:55 +01:00
def get_sgdb_art ( game_id , app_id ) :
2024-02-28 09:54:25 +01:00
global grid64
global gridp64
global logo64
global hero64
print ( f " Downloading icons artwork... " )
2024-08-08 06:29:31 +02:00
download_artwork ( game_id , " icons " , app_id )
2024-02-28 09:54:25 +01:00
print ( f " Downloading logos artwork... " )
2024-08-08 06:29:31 +02:00
logo64 = download_artwork ( game_id , " logos " , app_id )
2024-02-28 09:54:25 +01:00
print ( f " Downloading heroes artwork... " )
2024-08-08 06:29:31 +02:00
hero64 = download_artwork ( game_id , " heroes " , app_id )
2024-02-28 09:54:25 +01:00
print ( " Downloading grids artwork of size 600x900... " )
2024-08-08 06:29:31 +02:00
gridp64 = download_artwork ( game_id , " grids " , app_id , " 600x900 " )
2024-02-28 09:54:25 +01:00
print ( " Downloading grids artwork of size 920x430... " )
2024-08-08 06:29:31 +02:00
grid64 = download_artwork ( game_id , " grids " , app_id , " 920x430 " )
2024-02-17 04:26:30 +01:00
2024-08-08 06:29:31 +02:00
def download_artwork ( game_id , art_type , shortcut_id , dimensions = None ) :
if game_id is None :
print ( " Invalid game ID. Skipping download. " )
return
2024-02-17 04:26:30 +01:00
2024-01-17 12:31:04 +01:00
cache_key = ( game_id , art_type , dimensions )
if dimensions is not None :
filename = get_file_name ( art_type , shortcut_id , dimensions )
else :
filename = get_file_name ( art_type , shortcut_id )
2024-12-13 20:36:55 +01:00
2024-01-17 12:31:04 +01:00
file_path = f " { logged_in_home } /.steam/root/userdata/ { steamid3 } /config/grid/ { filename } "
2024-02-01 13:49:45 +01:00
directory = os . path . dirname ( file_path )
2024-12-13 20:36:55 +01:00
2024-02-01 13:49:45 +01:00
if not os . path . exists ( directory ) :
os . makedirs ( directory )
2024-02-17 04:26:30 +01:00
2024-12-13 20:36:55 +01:00
# Check if the file exists in the local cache
2024-01-17 12:31:04 +01:00
if os . path . exists ( file_path ) :
print ( f " Artwork for { game_id } already exists. Skipping download. " )
2024-02-28 09:54:25 +01:00
with open ( file_path , ' rb ' ) as image_file :
return b64encode ( image_file . read ( ) ) . decode ( ' utf-8 ' )
2024-01-17 12:31:04 +01:00
2024-12-13 20:36:55 +01:00
# If the file is in the cache, use that data
2024-01-17 12:31:04 +01:00
if cache_key in api_cache :
data = api_cache [ cache_key ]
else :
2024-08-02 12:09:11 +02:00
try :
2024-08-08 06:29:31 +02:00
print ( f " Game ID: { game_id } " )
url = f " { BASE_URL } / { art_type } /game/ { game_id } "
2024-08-02 12:09:11 +02:00
if dimensions :
url + = f " ?dimensions= { dimensions } "
2024-08-08 06:29:31 +02:00
print ( f " Request URL: { url } " )
response = requests . get ( url )
2024-08-02 12:09:11 +02:00
response . raise_for_status ( )
2024-01-17 12:31:04 +01:00
data = response . json ( )
2024-08-08 06:29:31 +02:00
print ( f " Response data: { data } " )
2024-01-17 12:31:04 +01:00
api_cache [ cache_key ] = data
2024-08-08 06:29:31 +02:00
except Exception as e :
2024-08-02 12:09:11 +02:00
print ( f " Error making API call: { e } " )
2024-02-17 04:26:30 +01:00
api_cache [ cache_key ] = None
return
2024-01-17 12:31:04 +01:00
2024-12-13 20:36:55 +01:00
if not data or ' data ' not in data :
2024-08-02 12:09:11 +02:00
print ( f " No data available for { game_id } . Skipping download. " )
return
2024-01-17 12:31:04 +01:00
for artwork in data [ ' data ' ] :
image_url = artwork [ ' thumb ' ]
2024-08-08 06:29:31 +02:00
print ( f " Downloading image from: { image_url } " )
2024-12-13 20:36:55 +01:00
for ext in [ ' png ' , ' ico ' ] :
try :
alt_file_path = file_path . replace ( ' .png ' , f ' . { ext } ' )
response = requests . get ( image_url , stream = True )
response . raise_for_status ( )
if response . status_code == 200 :
with open ( alt_file_path , ' wb ' ) as file :
file . write ( response . content )
print ( f " Downloaded { alt_file_path } " )
return b64encode ( response . content ) . decode ( ' utf-8 ' )
except requests . exceptions . RequestException as e :
print ( f " Error downloading image in { ext } : { e } " )
print ( f " Artwork download failed for { game_id } . Neither PNG nor ICO was available. " )
return None
2024-08-02 12:09:11 +02:00
2024-01-17 12:31:04 +01:00
def get_game_id ( game_name ) :
print ( f " Searching for game ID for: { game_name } " )
2024-08-02 12:09:11 +02:00
try :
2024-08-08 06:29:31 +02:00
encoded_game_name = quote ( game_name )
url = f " { BASE_URL } /search/ { encoded_game_name } "
print ( f " Encoded game name: { encoded_game_name } " )
print ( f " Request URL: { url } " )
response = requests . get ( url )
response . raise_for_status ( )
data = response . json ( )
print ( f " Response data: { data } " )
if data [ ' data ' ] :
game_id = data [ ' data ' ] [ 0 ] [ ' id ' ]
print ( f " Found game ID: { game_id } " )
return game_id
print ( f " No game ID found for game name: { game_name } " )
return None
except Exception as e :
2024-08-02 12:09:11 +02:00
print ( f " Error searching for game ID: { e } " )
2024-08-08 06:29:31 +02:00
return None
2024-08-02 12:09:11 +02:00
2024-01-17 12:31:04 +01:00
def get_file_name ( art_type , shortcut_id , dimensions = None ) :
singular_art_type = art_type . rstrip ( ' s ' )
if art_type == ' icons ' :
2024-12-13 20:36:55 +01:00
# Check for the existing .png file first
2024-01-17 12:31:04 +01:00
if os . path . exists ( f " { logged_in_home } /.steam/root/userdata/ { steamid3 } /config/grid/ { shortcut_id } - { singular_art_type } .png " ) :
return f " { shortcut_id } - { singular_art_type } .png "
2024-12-13 20:36:55 +01:00
# Fallback to .ico if .png doesn't exist
2024-01-17 12:31:04 +01:00
else :
return f " { shortcut_id } - { singular_art_type } .ico "
elif art_type == ' grids ' :
if dimensions == ' 600x900 ' :
return f " { shortcut_id } p.png "
else :
return f " { shortcut_id } .png "
elif art_type == ' heroes ' :
return f " { shortcut_id } _hero.png "
elif art_type == ' logos ' :
return f " { shortcut_id } _logo.png "
else :
return f " { shortcut_id } .png "
2024-12-13 20:36:55 +01:00
2024-01-17 12:31:04 +01:00
def is_match ( name1 , name2 ) :
if name1 and name2 :
return name1 . lower ( ) in name2 . lower ( ) or name2 . lower ( ) in name1 . lower ( )
else :
return False
2024-01-24 03:14:33 +01:00
2024-08-02 12:09:11 +02:00
2024-02-09 01:24:46 +01:00
# Add or update the proton compatibility settings
2024-11-05 14:35:35 +01:00
2024-02-09 10:39:43 +01:00
def add_compat_tool ( app_id , launchoptions ) :
2024-01-25 18:41:04 +01:00
if ' CompatToolMapping ' not in config_data [ ' InstallConfigStore ' ] [ ' Software ' ] [ ' Valve ' ] [ ' Steam ' ] :
config_data [ ' InstallConfigStore ' ] [ ' Software ' ] [ ' Valve ' ] [ ' Steam ' ] [ ' CompatToolMapping ' ] = { }
print ( f " CompatToolMapping key not found in config.vdf, creating. " )
2024-11-08 10:43:39 +01:00
# Combine checks for 'chrome' and 'PROTONPATH'
if ' chrome ' in launchoptions or ' PROTONPATH ' in launchoptions :
if ' PROTONPATH ' in launchoptions :
print ( " PROTONPATH found in launch options. Skipping compatibility tool update. " )
2024-11-05 14:35:35 +01:00
return False
2024-01-25 18:41:04 +01:00
elif str ( app_id ) in config_data [ ' InstallConfigStore ' ] [ ' Software ' ] [ ' Valve ' ] [ ' Steam ' ] [ ' CompatToolMapping ' ] :
config_data [ ' InstallConfigStore ' ] [ ' Software ' ] [ ' Valve ' ] [ ' Steam ' ] [ ' CompatToolMapping ' ] [ str ( app_id ) ] [ ' name ' ] = f ' { compat_tool_name } '
config_data [ ' InstallConfigStore ' ] [ ' Software ' ] [ ' Valve ' ] [ ' Steam ' ] [ ' CompatToolMapping ' ] [ str ( app_id ) ] [ ' config ' ] = ' '
config_data [ ' InstallConfigStore ' ] [ ' Software ' ] [ ' Valve ' ] [ ' Steam ' ] [ ' CompatToolMapping ' ] [ str ( app_id ) ] [ ' priority ' ] = ' 250 '
print ( f " Updated CompatToolMapping entry for appid: { app_id } " )
2024-02-28 09:54:25 +01:00
return compat_tool_name
2024-01-23 23:30:55 +01:00
else :
2024-11-05 14:35:35 +01:00
# Skip if the shortcut has already been processed by UMU
if app_id in umu_processed_shortcuts :
print ( f " CompatTool update skipped for { app_id } because it was already processed by UMU. " )
return None
2024-01-25 18:41:04 +01:00
config_data [ ' InstallConfigStore ' ] [ ' Software ' ] [ ' Valve ' ] [ ' Steam ' ] [ ' CompatToolMapping ' ] [ str ( app_id ) ] = { ' name ' : f ' { compat_tool_name } ' , ' config ' : ' ' , ' priority ' : ' 250 ' }
print ( f " Created new CompatToolMapping entry for appid: { app_id } " )
2024-02-28 09:54:25 +01:00
return compat_tool_name
2024-01-17 12:31:04 +01:00
2024-11-08 10:43:39 +01:00
2024-01-24 10:51:05 +01:00
def check_if_shortcut_exists ( shortcut_id , display_name , exe_path , start_dir , launch_options ) :
# Check if the game already exists in the shortcuts using the id
2024-01-25 18:41:04 +01:00
if any ( s . get ( ' appid ' ) == shortcut_id for s in shortcuts [ ' shortcuts ' ] . values ( ) ) :
2024-02-09 01:24:46 +01:00
print ( f " Existing shortcut found based on shortcut ID for game { display_name } . Skipping creation. " )
2024-01-24 12:39:03 +01:00
return True
2024-01-24 10:51:05 +01:00
# Check if the game already exists in the shortcuts using the fields (probably unnecessary)
if any ( s . get ( ' appname ' ) == display_name and s . get ( ' exe ' ) == exe_path and s . get ( ' StartDir ' ) == start_dir and s . get ( ' LaunchOptions ' ) == launch_options for s in shortcuts [ ' shortcuts ' ] . values ( ) ) :
2024-02-09 01:24:46 +01:00
print ( f " Existing shortcut found based on matching fields for game { display_name } . Skipping creation. " )
2024-01-24 12:39:03 +01:00
return True
2024-02-27 17:19:44 +01:00
if any ( s . get ( ' AppName ' ) == display_name and s . get ( ' Exe ' ) == exe_path and s . get ( ' StartDir ' ) == start_dir and s . get ( ' LaunchOptions ' ) == launch_options for s in shortcuts [ ' shortcuts ' ] . values ( ) ) :
print ( f " Existing shortcut found based on matching fields for game { display_name } . Skipping creation. " )
return True
2024-01-24 03:14:33 +01:00
#End of Code
2024-01-17 12:31:04 +01:00
2024-11-05 14:35:35 +01:00
2024-02-06 10:20:00 +01:00
#Start of Refactoring code from the .sh file
sys . path . insert ( 0 , os . path . expanduser ( f " { logged_in_home } /Downloads/NonSteamLaunchersInstallation/lib/python { python_version } /site-packages " ) )
print ( sys . path )
# Create an empty dictionary to store the app IDs
app_ids = { }
2024-02-09 01:24:46 +01:00
2024-07-16 09:57:46 +02:00
def get_next_available_key ( shortcuts ) :
key = 0
while str ( key ) in shortcuts [ ' shortcuts ' ] :
key + = 1
return str ( key )
2024-07-15 13:34:14 +02:00
2024-02-06 10:20:00 +01:00
def create_new_entry ( shortcutdirectory , appname , launchoptions , startingdir ) :
2024-02-09 01:24:46 +01:00
global new_shortcuts_added
global shortcuts_updated
global created_shortcuts
2024-02-28 09:54:25 +01:00
global decky_shortcuts
global grid64
global gridp64
global logo64
global hero64
2024-07-15 13:34:14 +02:00
global counter # Add this line to access the counter variable
2024-06-23 06:04:27 +02:00
2024-02-06 10:20:00 +01:00
# Check if the launcher is installed
2024-02-09 10:21:00 +01:00
if not shortcutdirectory or not appname or not launchoptions or not startingdir :
2024-02-06 10:20:00 +01:00
print ( f " { appname } is not installed. Skipping. " )
return
2024-02-09 01:24:46 +01:00
exe_path = f " { shortcutdirectory } "
2024-02-06 10:20:00 +01:00
signed_shortcut_id = get_steam_shortcut_id ( exe_path , appname )
2024-02-09 12:00:01 +01:00
unsigned_shortcut_id = get_unsigned_shortcut_id ( signed_shortcut_id )
2024-11-05 14:35:35 +01:00
# **Intercept and modify the shortcut based on UMU data**
exe_path , startingdir , launchoptions = modify_shortcut_for_umu ( appname , exe_path , launchoptions , startingdir )
# Check if the shortcut has already been processed by UMU and skip compat tool if so
if unsigned_shortcut_id in umu_processed_shortcuts :
print ( f " Skipping compatibility tool for { appname } , as it has already been processed by UMU. " )
compatTool = None # Skip adding compatibility tool
else :
compatTool = add_compat_tool ( unsigned_shortcut_id , launchoptions )
2024-06-23 06:10:03 +02:00
# Only store the app ID for specific launchers
2024-08-02 12:09:11 +02:00
if appname in [ ' Epic Games ' , ' Gog Galaxy ' , ' Ubisoft Connect ' , ' Battle.net ' , ' EA App ' , ' Amazon Games ' , ' itch.io ' , ' Legacy Games ' , ' Humble Bundle ' , ' IndieGala Client ' , ' Rockstar Games Launcher ' , ' Glyph ' , ' Playstation Plus ' , ' VK Play ' , ' HoYoPlay ' , ' Nexon Launcher ' ] :
2024-06-23 06:10:03 +02:00
app_ids [ appname ] = unsigned_shortcut_id
2024-06-23 06:04:27 +02:00
2024-02-09 01:24:46 +01:00
# Check if the game already exists in the shortcuts
2024-02-06 10:20:00 +01:00
if check_if_shortcut_exists ( signed_shortcut_id , appname , exe_path , startingdir , launchoptions ) :
2024-02-09 01:24:46 +01:00
# Check if proton needs applying or updating
2024-02-09 10:39:43 +01:00
if add_compat_tool ( unsigned_shortcut_id , launchoptions ) :
2024-02-06 10:20:00 +01:00
shortcuts_updated = True
return
2024-06-23 06:04:27 +02:00
2024-08-09 06:36:56 +02:00
# Skip artwork download for specific shortcuts
if appname not in [ ' NonSteamLaunchers ' , ' Repair EA App ' ] :
# Get artwork
game_id = get_game_id ( appname )
if game_id is not None :
get_sgdb_art ( game_id , unsigned_shortcut_id )
2024-11-05 14:35:35 +01:00
# Create a new entry for the Steam shortcut, only adding the compat tool if it's not processed by UMU
2024-02-06 10:20:00 +01:00
new_entry = {
' appid ' : str ( signed_shortcut_id ) ,
' appname ' : appname ,
' exe ' : exe_path ,
' StartDir ' : startingdir ,
' icon ' : f " { logged_in_home } /.steam/root/userdata/ { steamid3 } /config/grid/ { get_file_name ( ' icons ' , unsigned_shortcut_id ) } " ,
2024-06-23 08:30:45 +02:00
' ShortcutPath ' : " " ,
2024-02-06 10:20:00 +01:00
' LaunchOptions ' : launchoptions ,
2024-06-23 08:30:45 +02:00
' IsHidden ' : 0 ,
' AllowDesktopConfig ' : 1 ,
' AllowOverlay ' : 1 ,
' OpenVR ' : 0 ,
' Devkit ' : 0 ,
' DevkitGameID ' : " " ,
' DevkitOverrideAppID ' : 0 ,
' LastPlayTime ' : 0 ,
' FlatpakAppID ' : " " ,
' tags ' : {
' 0 ' : ' NonSteamLaunchers '
2024-06-23 06:04:27 +02:00
}
2024-02-06 10:20:00 +01:00
}
2024-11-05 14:35:35 +01:00
# Create the decky entry, only including the compatTool if not processed by UMU
2024-02-28 09:54:25 +01:00
decky_entry = {
' appname ' : appname ,
' exe ' : exe_path ,
' StartDir ' : startingdir ,
' icon ' : f " { logged_in_home } /.steam/root/userdata/ { steamid3 } /config/grid/ { get_file_name ( ' icons ' , unsigned_shortcut_id ) } " ,
' LaunchOptions ' : launchoptions ,
2024-11-05 14:35:35 +01:00
' CompatTool ' : compatTool , # This will be None if UMU has processed the shortcut
2024-02-28 12:27:24 +01:00
' WideGrid ' : grid64 ,
' Grid ' : gridp64 ,
2024-02-28 09:54:25 +01:00
' Hero ' : hero64 ,
' Logo ' : logo64 ,
}
2024-11-05 14:35:35 +01:00
2024-02-09 01:24:46 +01:00
# Add the new entry to the shortcuts dictionary and add proton
2024-07-16 09:57:46 +02:00
key = get_next_available_key ( shortcuts )
shortcuts [ ' shortcuts ' ] [ key ] = new_entry
2024-02-06 10:20:00 +01:00
print ( f " Added new entry for { appname } to shortcuts. " )
new_shortcuts_added = True
2024-02-09 01:24:46 +01:00
created_shortcuts . append ( appname )
2024-11-05 14:35:35 +01:00
# Mark it as processed by UMU (if it wasn't already processed)
if compatTool is not None :
umu_processed_shortcuts [ unsigned_shortcut_id ] = True
2024-07-16 09:57:46 +02:00
add_compat_tool ( unsigned_shortcut_id , launchoptions )
2024-07-15 13:34:14 +02:00
2024-06-23 06:04:27 +02:00
2024-11-05 14:35:35 +01:00
# UMU-related functions
umu_processed_shortcuts = { }
CSV_URL = " https://raw.githubusercontent.com/Open-Wine-Components/umu-database/main/umu-database.csv "
# Global variable to store CSV data
csv_data = [ ]
def fetch_and_parse_csv ( ) :
global csv_data
try :
response = requests . get ( CSV_URL )
response . raise_for_status ( ) # Raise an HTTPError for bad responses
csv_data = [ row for row in csv . DictReader ( response . text . splitlines ( ) ) ]
print ( " Successfully fetched and parsed CSV data. " )
except requests . exceptions . RequestException as e :
print ( f " Error fetching UMU data: { e } " )
return csv_data
def list_all_entries ( ) :
global csv_data
if not csv_data :
csv_data = fetch_and_parse_csv ( )
return csv_data
def extract_umu_id_from_launch_options ( launchoptions ) :
if ' STEAM_COMPAT_DATA_PATH= ' not in launchoptions :
return None
# EA
match = re . search ( r ' offerIds=( \ d+) ' , launchoptions )
if match :
return match . group ( 1 )
# Amazon
match = re . search ( r ' (amzn1 \ .adg \ .product \ . \ S+) ' , launchoptions )
if match :
return match . group ( 1 ) . rstrip ( " ' " )
# Epic
match = re . search ( r ' com \ .epicgames \ .launcher://apps/( \ w+)[?&] ' , launchoptions )
if match :
return match . group ( 1 ) . lower ( ) if not match . group ( 1 ) . isdigit ( ) else match . group ( 1 )
# Ubisoft
match = re . search ( r ' uplay://launch/( \ d+)/ \ d+ ' , launchoptions )
if match :
return match . group ( 1 )
# GOG
match = re . search ( r ' /gameId=( \ d+) ' , launchoptions )
if match :
return match . group ( 1 )
return None
def extract_base_path ( launchoptions ) :
match = re . search ( r ' STEAM_COMPAT_DATA_PATH= " ([^ " ]+) " ' , launchoptions )
if match :
return match . group ( 1 )
raise ValueError ( " STEAM_COMPAT_DATA_PATH not found in launch options " )
def modify_shortcut_for_umu ( appname , exe , launchoptions , startingdir ) :
# Skip processing if STEAM_COMPAT_DATA_PATH is not present
if ' STEAM_COMPAT_DATA_PATH= ' not in launchoptions :
print ( f " Launch options for { appname } do not contain STEAM_COMPAT_DATA_PATH. Skipping modification. " )
return exe , startingdir , launchoptions
codename = extract_umu_id_from_launch_options ( launchoptions )
if not codename :
print ( f " No codename found in launch options for { appname } . Trying to match appname. " )
entries = list_all_entries ( )
if not entries :
print ( f " No entries found in UMU database. Skipping modification for { appname } . " )
return exe , startingdir , launchoptions
if not codename :
for entry in entries :
if entry . get ( ' TITLE ' ) and entry [ ' TITLE ' ] . lower ( ) == appname . lower ( ) :
codename = entry [ ' CODENAME ' ]
break
if codename :
for entry in entries :
if entry [ ' CODENAME ' ] == codename :
umu_id = entry [ ' UMU_ID ' ] . replace ( " umu- " , " " ) # Remove the "umu-" prefix
base_path = extract_base_path ( launchoptions )
new_exe = f ' " { logged_in_home } /bin/umu-run " { exe } '
new_start_dir = f ' " { logged_in_home } /bin/ " '
# Update only the launchoptions part for different game types
updated_launch = launchoptions
if " origin2://game/launch?offerIds= " in launchoptions :
2024-11-08 10:17:37 +01:00
updated_launch = f ' " origin2://game/launch?offerIds= { codename } " '
2024-11-05 14:35:35 +01:00
elif " amazon-games://play/amzn1.adg.product. " in launchoptions :
2024-11-08 10:17:37 +01:00
updated_launch = f " - ' amazon-games://play/ { codename } ' "
2024-11-05 14:35:35 +01:00
elif " com.epicgames.launcher://apps/ " in launchoptions :
2024-11-08 10:17:37 +01:00
updated_launch = f " - ' com.epicgames.launcher://apps/ { codename } ?action=launch&silent=true ' "
2024-11-05 14:35:35 +01:00
elif " uplay://launch/ " in launchoptions :
2024-11-08 10:17:37 +01:00
updated_launch = f ' " uplay://launch/ { codename } /0 " '
2024-11-05 14:35:35 +01:00
elif " /command=runGame /gameId= " in launchoptions :
updated_launch = f ' /command=runGame /gameId= { codename } /path= { launchoptions . split ( " /path= " ) [ 1 ] } '
new_launch_options = (
f ' STEAM_COMPAT_DATA_PATH= " { base_path } " '
f ' WINEPREFIX= " { base_path } pfx " '
f ' GAMEID= " { umu_id } " '
f ' PROTONPATH= " { logged_in_home } /.steam/root/compatibilitytools.d/ { compat_tool_name } " '
f ' %command% { updated_launch } '
)
umu_processed_shortcuts [ umu_id ] = True
return new_exe , new_start_dir , new_launch_options
print ( f " No UMU entry found for { appname } . Skipping modification. " )
return exe , startingdir , launchoptions
2024-06-23 06:04:27 +02:00
2024-02-06 10:20:00 +01:00
create_new_entry ( os . environ . get ( ' epicshortcutdirectory ' ) , ' Epic Games ' , os . environ . get ( ' epiclaunchoptions ' ) , os . environ . get ( ' epicstartingdir ' ) )
2024-09-29 07:15:52 +02:00
create_new_entry ( os . environ . get ( ' gogshortcutdirectory ' ) , ' GOG Galaxy ' , os . environ . get ( ' goglaunchoptions ' ) , os . environ . get ( ' gogstartingdir ' ) )
2024-02-06 10:20:00 +01:00
create_new_entry ( os . environ . get ( ' uplayshortcutdirectory ' ) , ' Ubisoft Connect ' , os . environ . get ( ' uplaylaunchoptions ' ) , os . environ . get ( ' uplaystartingdir ' ) )
create_new_entry ( os . environ . get ( ' battlenetshortcutdirectory ' ) , ' Battle.net ' , os . environ . get ( ' battlenetlaunchoptions ' ) , os . environ . get ( ' battlenetstartingdir ' ) )
create_new_entry ( os . environ . get ( ' eaappshortcutdirectory ' ) , ' EA App ' , os . environ . get ( ' eaapplaunchoptions ' ) , os . environ . get ( ' eaappstartingdir ' ) )
create_new_entry ( os . environ . get ( ' amazonshortcutdirectory ' ) , ' Amazon Games ' , os . environ . get ( ' amazonlaunchoptions ' ) , os . environ . get ( ' amazonstartingdir ' ) )
create_new_entry ( os . environ . get ( ' itchioshortcutdirectory ' ) , ' itch.io ' , os . environ . get ( ' itchiolaunchoptions ' ) , os . environ . get ( ' itchiostartingdir ' ) )
create_new_entry ( os . environ . get ( ' legacyshortcutdirectory ' ) , ' Legacy Games ' , os . environ . get ( ' legacylaunchoptions ' ) , os . environ . get ( ' legacystartingdir ' ) )
create_new_entry ( os . environ . get ( ' humbleshortcutdirectory ' ) , ' Humble Bundle ' , os . environ . get ( ' humblelaunchoptions ' ) , os . environ . get ( ' humblestartingdir ' ) )
create_new_entry ( os . environ . get ( ' indieshortcutdirectory ' ) , ' IndieGala Client ' , os . environ . get ( ' indielaunchoptions ' ) , os . environ . get ( ' indiestartingdir ' ) )
create_new_entry ( os . environ . get ( ' rockstarshortcutdirectory ' ) , ' Rockstar Games Launcher ' , os . environ . get ( ' rockstarlaunchoptions ' ) , os . environ . get ( ' rockstarstartingdir ' ) )
create_new_entry ( os . environ . get ( ' glyphshortcutdirectory ' ) , ' Glyph ' , os . environ . get ( ' glyphlaunchoptions ' ) , os . environ . get ( ' glyphstartingdir ' ) )
create_new_entry ( os . environ . get ( ' psplusshortcutdirectory ' ) , ' Playstation Plus ' , os . environ . get ( ' pspluslaunchoptions ' ) , os . environ . get ( ' psplusstartingdir ' ) )
2024-06-21 14:01:55 +02:00
create_new_entry ( os . environ . get ( ' vkplayshortcutdirectory ' ) , ' VK Play ' , os . environ . get ( ' vkplaylaunchoptions ' ) , os . environ . get ( ' vkplaystartingdir ' ) )
2024-07-03 14:04:46 +02:00
create_new_entry ( os . environ . get ( ' hoyoplayshortcutdirectory ' ) , ' HoYoPlay ' , os . environ . get ( ' hoyoplaylaunchoptions ' ) , os . environ . get ( ' hoyoplaystartingdir ' ) )
2024-08-02 12:09:11 +02:00
create_new_entry ( os . environ . get ( ' nexonshortcutdirectory ' ) , ' Nexon Launcher ' , os . environ . get ( ' nexonlaunchoptions ' ) , os . environ . get ( ' nexonstartingdir ' ) )
create_new_entry ( os . environ . get ( ' repaireaappshortcutdirectory ' ) , ' Repair EA App ' , os . environ . get ( ' repaireaapplaunchoptions ' ) , os . environ . get ( ' repaireaappstartingdir ' ) )
2024-02-06 10:20:00 +01:00
create_new_entry ( os . environ . get ( ' chromedirectory ' ) , ' Xbox Game Pass ' , os . environ . get ( ' xboxchromelaunchoptions ' ) , os . environ . get ( ' chrome_startdir ' ) )
create_new_entry ( os . environ . get ( ' chromedirectory ' ) , ' GeForce Now ' , os . environ . get ( ' geforcechromelaunchoptions ' ) , os . environ . get ( ' chrome_startdir ' ) )
2024-03-06 18:02:19 +01:00
create_new_entry ( os . environ . get ( ' chromedirectory ' ) , ' Netflix ' , os . environ . get ( ' netflixchromelaunchoptions ' ) , os . environ . get ( ' chrome_startdir ' ) )
2024-02-06 10:20:00 +01:00
create_new_entry ( os . environ . get ( ' chromedirectory ' ) , ' Hulu ' , os . environ . get ( ' huluchromelaunchoptions ' ) , os . environ . get ( ' chrome_startdir ' ) )
create_new_entry ( os . environ . get ( ' chromedirectory ' ) , ' Disney+ ' , os . environ . get ( ' disneychromelaunchoptions ' ) , os . environ . get ( ' chrome_startdir ' ) )
create_new_entry ( os . environ . get ( ' chromedirectory ' ) , ' Amazon Prime Video ' , os . environ . get ( ' amazonchromelaunchoptions ' ) , os . environ . get ( ' chrome_startdir ' ) )
create_new_entry ( os . environ . get ( ' chromedirectory ' ) , ' Youtube ' , os . environ . get ( ' youtubechromelaunchoptions ' ) , os . environ . get ( ' chrome_startdir ' ) )
create_new_entry ( os . environ . get ( ' chromedirectory ' ) , ' Amazon Luna ' , os . environ . get ( ' lunachromelaunchoptions ' ) , os . environ . get ( ' chrome_startdir ' ) )
create_new_entry ( os . environ . get ( ' chromedirectory ' ) , ' Twitch ' , os . environ . get ( ' twitchchromelaunchoptions ' ) , os . environ . get ( ' chrome_startdir ' ) )
2024-03-06 19:40:58 +01:00
create_new_entry ( os . environ . get ( ' chromedirectory ' ) , ' Fortnite ' , os . environ . get ( ' fortnitechromelaunchoptions ' ) , os . environ . get ( ' chrome_startdir ' ) )
2024-10-11 11:10:10 +02:00
create_new_entry ( os . environ . get ( ' chromedirectory ' ) , ' WebRcade ' , os . environ . get ( ' webrcadechromelaunchoptions ' ) , os . environ . get ( ' chrome_startdir ' ) )
create_new_entry ( os . environ . get ( ' chromedirectory ' ) , ' WebRcade Editor ' , os . environ . get ( ' webrcadeeditchromelaunchoptions ' ) , os . environ . get ( ' chrome_startdir ' ) )
2024-10-25 07:50:58 +02:00
create_new_entry ( os . environ . get ( ' chromedirectory ' ) , ' Plex ' , os . environ . get ( ' plexchromelaunchoptions ' ) , os . environ . get ( ' chrome_startdir ' ) )
create_new_entry ( os . environ . get ( ' chromedirectory ' ) , ' Apple TV+ ' , os . environ . get ( ' applechromelaunchoptions ' ) , os . environ . get ( ' chrome_startdir ' ) )
create_new_entry ( os . environ . get ( ' chromedirectory ' ) , ' Crunchyroll ' , os . environ . get ( ' crunchychromelaunchoptions ' ) , os . environ . get ( ' chrome_startdir ' ) )
2024-02-06 10:20:00 +01:00
# Iterate over each custom website
for custom_website in custom_websites :
# Check if the custom website is not an empty string
if custom_website :
# Remove any leading or trailing spaces from the custom website URL
custom_website = custom_website . strip ( )
# Remove the 'http://' or 'https://' prefix and the 'www.' prefix, if present
clean_website = custom_website . replace ( ' http:// ' , ' ' ) . replace ( ' https:// ' , ' ' ) . replace ( ' www. ' , ' ' )
# Define a regular expression pattern to extract the game name from the URL
pattern = r ' /games/([ \ w-]+) '
# Use the regular expression to search for the game name in the custom website URL
match = re . search ( pattern , custom_website )
# Check if a match was found
if match :
# Extract the game name from the match object
game_name = match . group ( 1 )
# Replace hyphens with spaces
game_name = game_name . replace ( ' - ' , ' ' )
# Capitalize the first letter of each word in the game name
game_name = game_name . title ( )
else :
# Use the entire URL as the entry name
game_name = clean_website
# Define the launch options for this website
2024-10-25 07:50:58 +02:00
chromelaunch_options = f ' run --branch=stable --arch=x86_64 --command=/app/bin/chrome --file-forwarding com.google.Chrome @@u @@ --window-size=1280,800 --force-device-scale-factor=1.00 --device-scale-factor=1.00 --start-fullscreen https:// { clean_website } / --no-first-run --enable-features=OverlayScrollbar '
2024-02-06 10:20:00 +01:00
# Call the create_new_entry function for this website
create_new_entry ( os . environ [ ' chromedirectory ' ] , game_name , chromelaunch_options , os . environ [ ' chrome_startdir ' ] )
#End of Creating Launcher Shortcuts
2024-06-29 04:02:52 +02:00
#Custom Shortcut for NSL
# Define the parameters for the new shortcut
nslshortcutdirectory = f " \" { logged_in_home } /.local/share/Steam/steamapps/compatdata/NonSteamLaunchers/ \" "
nslappname = " NonSteamLaunchers "
nsllaunchoptions = f " STEAM_COMPAT_DATA_PATH= \" { logged_in_home } /.local/share/Steam/steamapps/compatdata/NonSteamLaunchers/ \" %command% "
nslstartingdir = f " \" { logged_in_home } /.local/share/Steam/steamapps/compatdata/NonSteamLaunchers/ \" "
print ( f " nslshortcutdirectory: { nslshortcutdirectory } " ) # Debug print
print ( f " nslappname: { nslappname } " ) # Debug print
print ( f " nsllaunchoptions: { nsllaunchoptions } " ) # Debug print
# Check if separate_appids is set to 'false'
if separate_appids == ' false ' :
print ( " separate_appids is set to ' false ' . Creating new shortcut... " ) # Debug print
# Call the function to create the new shortcut and store the returned appid
appid = create_new_entry ( nslshortcutdirectory , nslappname , nsllaunchoptions , nslstartingdir )
app_ids [ nslappname ] = appid
print ( f " appid: { appid } " ) # Debug print
else :
print ( " separate_appids is not set to ' false ' . Skipping shortcut creation. " ) # Debug print
2024-02-06 10:20:00 +01:00
# Iterate over each launcher in the app_ids dictionary
for launcher_name , appid in app_ids . items ( ) :
print ( f " The app ID for { launcher_name } is { appid } " )
2024-02-09 13:02:55 +01:00
# Get the app ID for the first launcher that the user chose to install
2024-02-09 15:57:42 +01:00
if app_ids :
appid = app_ids . get ( launcher_name )
2024-06-22 13:23:54 +02:00
print ( f " App ID for the chosen launcher: { appid } " )
2024-02-09 12:27:03 +01:00
2024-06-22 13:23:54 +02:00
# Create User Friendly Symlinks for the launchers
2024-02-06 10:20:00 +01:00
# Define the path to the compatdata directory
compatdata_dir = f ' { logged_in_home } /.local/share/Steam/steamapps/compatdata '
2024-06-22 13:23:54 +02:00
print ( f " Compatdata directory: { compatdata_dir } " )
2024-02-06 10:20:00 +01:00
# Define a dictionary of original folder names
folder_names = {
' Epic Games ' : ' EpicGamesLauncher ' ,
' Gog Galaxy ' : ' GogGalaxyLauncher ' ,
' Ubisoft Connect ' : ' UplayLauncher ' ,
' Battle.net ' : ' Battle.netLauncher ' ,
' EA App ' : ' TheEAappLauncher ' ,
' Amazon Games ' : ' AmazonGamesLauncher ' ,
' itch.io ' : ' itchioLauncher ' ,
' Legacy Games ' : ' LegacyGamesLauncher ' ,
' Humble Bundle ' : ' HumbleGamesLauncher ' ,
' IndieGala Client ' : ' IndieGalaLauncher ' ,
' Rockstar Games Launcher ' : ' RockstarGamesLauncher ' ,
2024-06-22 11:29:04 +02:00
' Glyph ' : ' GlyphLauncher ' ,
2024-02-06 10:20:00 +01:00
' Playstation Plus ' : ' PlaystationPlusLauncher ' ,
' VK Play ' : ' VKPlayLauncher ' ,
2024-07-03 14:04:46 +02:00
' HoYoPlay ' : ' HoYoPlayLauncher ' ,
2024-08-02 12:09:11 +02:00
' Nexon Launcher ' : ' NexonLauncher ' ,
2024-01-17 12:31:04 +01:00
}
2024-06-29 08:39:11 +02:00
2024-02-06 10:20:00 +01:00
# Iterate over each launcher in the folder_names dictionary
for launcher_name , folder in folder_names . items ( ) :
# Define the current path of the folder
current_path = os . path . join ( compatdata_dir , folder )
2024-06-22 13:23:54 +02:00
print ( f " Current path for { launcher_name } : { current_path } " )
2024-02-06 10:20:00 +01:00
# Check if the folder exists
if os . path . exists ( current_path ) :
print ( f ' { launcher_name } : { folder } exists ' )
# Get the app ID for this launcher from the app_id_to_name dictionary
appid = app_ids . get ( launcher_name )
2024-06-22 13:23:54 +02:00
print ( f " App ID for { launcher_name } : { appid } " )
2024-01-29 05:52:48 +01:00
2024-06-22 11:24:08 +02:00
# If appid is not None, proceed with renaming and symlink creation
if appid is not None :
# Define the new path of the folder
new_path = os . path . join ( compatdata_dir , str ( appid ) )
2024-06-22 13:23:54 +02:00
print ( f " New path for { launcher_name } : { new_path } " )
2024-06-22 11:24:08 +02:00
# Check if the new path already exists
if os . path . exists ( new_path ) :
2024-06-29 10:19:24 +02:00
print ( f ' { new_path } already exists. Skipping renaming and symlinking. ' )
else :
# Rename the folder
os . rename ( current_path , new_path )
print ( f " Renamed { current_path } to { new_path } " )
# Define the path of the symbolic link
symlink_path = os . path . join ( compatdata_dir , folder )
print ( f " Symlink path for { launcher_name } : { symlink_path } " )
# Create a symbolic link to the renamed folder
os . symlink ( new_path , symlink_path )
print ( f " Created symlink at { symlink_path } to { new_path } " )
2024-06-22 10:18:04 +02:00
else :
2024-06-22 11:24:08 +02:00
print ( f ' App ID for { launcher_name } is not available yet. ' )
2024-02-06 10:20:00 +01:00
else :
print ( f ' { launcher_name } : { folder } does not exist ' )
2024-06-22 13:59:16 +02:00
2024-06-29 04:02:52 +02:00
2024-06-29 10:19:24 +02:00
2024-06-29 04:02:52 +02:00
# Define the appid for the custom shortcut
custom_app_id = 4206469918
print ( f " App ID for the custom shortcut: { custom_app_id } " )
2024-02-06 10:20:00 +01:00
# Check if the NonSteamLaunchers folder exists
2024-06-22 11:54:04 +02:00
non_steam_launchers_path = os . path . join ( compatdata_dir , ' NonSteamLaunchers ' )
2024-06-29 04:02:52 +02:00
if os . path . exists ( non_steam_launchers_path ) :
2024-06-22 13:23:54 +02:00
print ( " NonSteamLaunchers already exists at the expected path. " )
2024-02-06 10:20:00 +01:00
# Define the current path of the NonSteamLaunchers folder
current_path = os . path . join ( compatdata_dir , ' NonSteamLaunchers ' )
2024-06-22 13:23:54 +02:00
print ( f " Current path for NonSteamLaunchers: { current_path } " )
2024-02-06 10:20:00 +01:00
# Check if NonSteamLaunchers is already a symbolic link
if os . path . islink ( current_path ) :
print ( ' NonSteamLaunchers is already a symbolic link ' )
2024-06-22 12:36:57 +02:00
# Check if NonSteamLaunchers is a symlink to an appid folder
2024-06-29 04:02:52 +02:00
if os . readlink ( current_path ) != os . path . join ( compatdata_dir , str ( custom_app_id ) ) :
2024-06-22 12:36:57 +02:00
print ( ' NonSteamLaunchers is symlinked to a different folder ' )
2024-06-29 04:02:52 +02:00
# Remove the existing symbolic link
os . unlink ( current_path )
print ( f ' Removed existing symlink at { current_path } ' )
# Create a symbolic link to the correct appid folder
os . symlink ( os . path . join ( compatdata_dir , str ( custom_app_id ) ) , current_path )
print ( f ' Created new symlink at { current_path } to { os . path . join ( compatdata_dir , str ( custom_app_id ) ) } ' )
else :
print ( ' NonSteamLaunchers is already correctly symlinked ' )
2024-02-06 10:20:00 +01:00
else :
2024-06-22 13:23:54 +02:00
print ( " NonSteamLaunchers is not a symbolic link. " )
2024-06-22 12:45:57 +02:00
# Check if the current path exists
if os . path . exists ( current_path ) :
2024-06-22 13:23:54 +02:00
print ( " NonSteamLaunchers exists at the current path. " )
2024-06-22 12:45:57 +02:00
# Define the new path of the NonSteamLaunchers folder
2024-06-29 04:02:52 +02:00
new_path = os . path . join ( compatdata_dir , str ( custom_app_id ) )
2024-06-22 13:54:07 +02:00
print ( f " New path for NonSteamLaunchers: { new_path } " )
2024-02-06 10:20:00 +01:00
2024-06-22 13:36:20 +02:00
# Check if the new path already exists
if os . path . exists ( new_path ) :
print ( f ' { new_path } already exists. Skipping renaming and symlinking. ' )
else :
# Move the NonSteamLaunchers folder to the new path
shutil . move ( current_path , new_path )
print ( f " Moved NonSteamLaunchers folder to { new_path } " )
2024-02-06 10:20:00 +01:00
2024-06-22 13:36:20 +02:00
# Define the path of the symbolic link
symlink_path = os . path . join ( compatdata_dir , ' NonSteamLaunchers ' )
2024-06-22 12:45:57 +02:00
2024-06-22 13:36:20 +02:00
# Create a symbolic link to the renamed NonSteamLaunchers folder
os . symlink ( new_path , symlink_path )
print ( f " Created symlink at { symlink_path } to { new_path } " )
2024-06-22 12:45:57 +02:00
else :
print ( f " The directory { current_path } does not exist. Skipping. " )
2024-06-22 13:36:20 +02:00
2024-06-22 13:54:07 +02:00
2024-06-22 13:23:54 +02:00
#End of old refactored Code
2024-02-06 10:20:00 +01:00
2024-01-24 03:14:33 +01:00
2024-06-29 04:59:35 +02:00
# Print the existing shortcuts
print ( " Existing Shortcuts: " )
for shortcut in shortcuts [ ' shortcuts ' ] . values ( ) :
if shortcut . get ( ' appname ' ) is None :
print ( f " AppID for { shortcut . get ( ' AppName ' ) } : { shortcut . get ( ' appid ' ) } " )
else :
print ( f " AppID for { shortcut . get ( ' appname ' ) } : { shortcut . get ( ' appid ' ) } " )
2024-01-17 12:31:04 +01:00
2024-01-26 07:24:04 +01:00
2024-02-06 10:20:00 +01:00
#Scanners
2024-01-17 12:31:04 +01:00
# Epic Games Scanner
item_dir = f " { logged_in_home } /.local/share/Steam/steamapps/compatdata/ { epic_games_launcher } /pfx/drive_c/ProgramData/Epic/EpicGamesLauncher/Data/Manifests/ "
dat_file_path = f " { logged_in_home } /.local/share/Steam/steamapps/compatdata/ { epic_games_launcher } /pfx/drive_c/ProgramData/Epic/UnrealEngineLauncher/LauncherInstalled.dat "
2024-01-26 07:24:04 +01:00
if os . path . exists ( dat_file_path ) and os . path . exists ( item_dir ) :
2024-01-17 12:31:04 +01:00
with open ( dat_file_path , ' r ' ) as file :
dat_data = json . load ( file )
2024-08-19 03:20:59 +02:00
# Epic Game Scanner
2024-01-17 12:31:04 +01:00
for item_file in os . listdir ( item_dir ) :
if item_file . endswith ( ' .item ' ) :
with open ( os . path . join ( item_dir , item_file ) , ' r ' ) as file :
item_data = json . load ( file )
2024-01-21 07:43:23 +01:00
# Initialize variables
display_name = item_data [ ' DisplayName ' ]
app_name = item_data [ ' AppName ' ]
exe_path = f " \" { logged_in_home } /.local/share/Steam/steamapps/compatdata/ { epic_games_launcher } /pfx/drive_c/Program Files (x86)/Epic Games/Launcher/Portal/Binaries/Win32/EpicGamesLauncher.exe \" "
start_dir = f " \" { logged_in_home } /.local/share/Steam/steamapps/compatdata/ { epic_games_launcher } /pfx/drive_c/Program Files (x86)/Epic Games/Launcher/Portal/Binaries/Win32/ \" "
2024-11-02 07:21:36 +01:00
launch_options = f " STEAM_COMPAT_DATA_PATH= \" { logged_in_home } /.local/share/Steam/steamapps/compatdata/ { epic_games_launcher } / \" %command% - ' com.epicgames.launcher://apps/ { app_name } ?action=launch&silent=true ' "
2024-01-21 07:43:23 +01:00
2024-08-19 03:20:59 +02:00
# Check if the game is still installed and if the LaunchExecutable is valid, not content-related, and is a .exe file
if item_data [ ' LaunchExecutable ' ] . endswith ( ' .exe ' ) and " Content " not in item_data [ ' DisplayName ' ] and " Content " not in item_data [ ' InstallLocation ' ] :
for game in dat_data [ ' InstallationList ' ] :
if game [ ' AppName ' ] == item_data [ ' AppName ' ] :
create_new_entry ( exe_path , display_name , launch_options , start_dir )
2024-01-17 12:31:04 +01:00
else :
print ( " Epic Games Launcher data not found. Skipping Epic Games Scanner. " )
2024-08-19 03:20:59 +02:00
# End of the Epic Games Scanner
2024-01-17 12:31:04 +01:00
2024-01-21 07:43:23 +01:00
# Ubisoft Connect Scanner
2024-01-21 02:18:03 +01:00
def getUplayGameInfo ( folderPath , filePath ) :
# Get the game IDs from the folder
listOfFiles = os . listdir ( folderPath )
2024-01-25 18:41:04 +01:00
uplay_ids = [ re . findall ( r ' \ d+ ' , str ( entry ) ) [ 0 ] for entry in listOfFiles if re . findall ( r ' \ d+ ' , str ( entry ) ) ]
2024-01-17 12:31:04 +01:00
2024-01-21 02:18:03 +01:00
# Parse the registry file
2024-01-17 12:31:04 +01:00
game_dict = { }
2024-01-21 02:18:03 +01:00
with open ( filePath , ' r ' ) as file :
2024-01-25 18:41:04 +01:00
uplay_id = None
2024-01-21 02:18:03 +01:00
game_name = None
uplay_install_found = False
for line in file :
2024-06-19 10:26:56 +02:00
line = line . replace ( " \\ x2019 " , " ’ " )
2024-01-21 02:18:03 +01:00
if " Uplay Install " in line :
2024-01-25 18:41:04 +01:00
uplay_id = re . findall ( r ' Uplay Install ( \ d+) ' , line )
if uplay_id :
uplay_id = uplay_id [ 0 ]
2024-01-21 02:18:03 +01:00
game_name = None # Reset game_name
uplay_install_found = True
if " DisplayName " in line and uplay_install_found :
game_name = re . findall ( r ' \ " (.+?) \ " ' , line . split ( " = " ) [ 1 ] )
if game_name :
game_name = game_name [ 0 ]
uplay_install_found = False
2024-06-19 10:26:56 +02:00
if uplay_id and game_name and uplay_id in uplay_ids :
2024-01-25 18:41:04 +01:00
game_dict [ game_name ] = uplay_id
uplay_id = None # Reset uplay_id
2024-01-21 02:18:03 +01:00
game_name = None # Reset game_name
2024-01-17 12:31:04 +01:00
return game_dict
# Define your paths
2024-01-19 13:21:02 +01:00
data_folder_path = f " { logged_in_home } /.local/share/Steam/steamapps/compatdata/ { ubisoft_connect_launcher } /pfx/drive_c/Program Files (x86)/Ubisoft/Ubisoft Game Launcher/data/ "
2024-01-21 02:18:03 +01:00
registry_file_path = f " { logged_in_home } /.local/share/Steam/steamapps/compatdata/ { ubisoft_connect_launcher } /pfx/system.reg "
2024-01-17 12:31:04 +01:00
# Check if the paths exist
2024-01-21 02:37:57 +01:00
if not os . path . exists ( data_folder_path ) or not os . path . exists ( registry_file_path ) :
2024-01-17 12:31:04 +01:00
print ( " One or more paths do not exist. " )
2024-01-24 03:14:33 +01:00
print ( " Ubisoft Connect game data not found. Skipping Ubisoft Games Scanner. " )
2024-01-17 12:31:04 +01:00
else :
2024-01-21 02:18:03 +01:00
game_dict = getUplayGameInfo ( data_folder_path , registry_file_path )
2024-01-17 12:31:04 +01:00
2024-01-25 18:41:04 +01:00
for game , uplay_id in game_dict . items ( ) :
if uplay_id :
launch_options = f " STEAM_COMPAT_DATA_PATH= \" { logged_in_home } /.local/share/Steam/steamapps/compatdata/ { ubisoft_connect_launcher } / \" %command% \" uplay://launch/ { uplay_id } /0 \" "
2024-01-26 22:36:59 +01:00
exe_path = f " \" { logged_in_home } /.local/share/Steam/steamapps/compatdata/ { ubisoft_connect_launcher } /pfx/drive_c/Program Files (x86)/Ubisoft/Ubisoft Game Launcher/upc.exe \" "
start_dir = f " \" { logged_in_home } /.local/share/Steam/steamapps/compatdata/ { ubisoft_connect_launcher } /pfx/drive_c/Program Files (x86)/Ubisoft/Ubisoft Game Launcher/ \" "
2024-02-09 01:24:46 +01:00
create_new_entry ( exe_path , game , launch_options , start_dir )
2024-01-17 12:31:04 +01:00
2024-01-21 07:43:23 +01:00
# End of Ubisoft Game Scanner
2024-01-17 12:31:04 +01:00
2024-01-23 23:30:55 +01:00
# EA App Game Scanner
2024-01-24 12:39:03 +01:00
2024-10-26 00:20:16 +02:00
2024-01-24 12:39:03 +01:00
def get_ea_app_game_info ( installed_games , game_directory_path ) :
2024-01-23 23:30:55 +01:00
game_dict = { }
2024-01-24 12:39:03 +01:00
for game in installed_games :
xml_file = ET . parse ( f " { game_directory_path } { game } /__Installer/installerdata.xml " )
xml_root = xml_file . getroot ( )
ea_ids = None
2024-01-23 23:30:55 +01:00
game_name = None
2024-01-24 12:39:03 +01:00
for content_id in xml_root . iter ( ' contentID ' ) :
2024-10-26 00:20:16 +02:00
ea_ids = content_id . text
break # Exit the loop after the first ID is found
2024-01-24 12:39:03 +01:00
for game_title in xml_root . iter ( ' gameTitle ' ) :
if game_name is None :
game_name = game_title . text
continue
for game_title in xml_root . iter ( ' title ' ) :
if game_name is None :
game_name = game_title . text
continue
if game_name is None :
game_name = game
if ea_ids : # Add the game's info to the dictionary if its ID was found in the folder
game_dict [ game_name ] = ea_ids
2024-01-23 23:30:55 +01:00
return game_dict
2024-01-24 03:14:33 +01:00
game_directory_path = f " { logged_in_home } /.local/share/Steam/steamapps/compatdata/ { ea_app_launcher } /pfx/drive_c/Program Files/EA Games/ "
2024-01-23 23:30:55 +01:00
2024-01-24 12:39:03 +01:00
if not os . path . isdir ( game_directory_path ) :
2024-01-24 05:01:36 +01:00
print ( " EA App game data not found. Skipping EA App Scanner. " )
2024-01-23 23:30:55 +01:00
else :
2024-01-24 12:39:03 +01:00
installed_games = os . listdir ( game_directory_path ) # Get a list of game folders
game_dict = get_ea_app_game_info ( installed_games , game_directory_path )
for game , ea_ids in game_dict . items ( ) :
launch_options = f " STEAM_COMPAT_DATA_PATH= \" { logged_in_home } /.local/share/Steam/steamapps/compatdata/ { ea_app_launcher } / \" %command% \" origin2://game/launch?offerIds= { ea_ids } \" "
2024-01-26 22:07:44 +01:00
exe_path = f " \" { logged_in_home } /.local/share/Steam/steamapps/compatdata/ { ea_app_launcher } /pfx/drive_c/Program Files/Electronic Arts/EA Desktop/EA Desktop/EALaunchHelper.exe \" "
start_dir = f " \" { logged_in_home } /.local/share/Steam/steamapps/compatdata/ { ea_app_launcher } /pfx/drive_c/Program Files/Electronic Arts/EA Desktop/EA Desktop/ \" "
2024-02-09 01:24:46 +01:00
create_new_entry ( exe_path , game , launch_options , start_dir )
2024-01-24 12:39:03 +01:00
#End of EA App Scanner
2024-01-23 23:30:55 +01:00
2024-01-24 03:14:33 +01:00
2024-01-26 10:18:26 +01:00
2024-10-26 00:20:16 +02:00
# Gog Galaxy Scanner
2024-01-26 10:18:26 +01:00
def getGogGameInfo ( filePath ) :
# Check if the file contains any GOG entries
with open ( filePath , ' r ' ) as file :
2024-05-08 08:46:49 +02:00
if " GOG.com " not in file . read ( ) :
2024-10-26 00:24:09 +02:00
print ( " No GOG entries found in the registry file. Skipping GOG Galaxy Games Scanner. " )
2024-01-26 10:18:26 +01:00
return { }
# If GOG entries exist, parse the registry file
game_dict = { }
with open ( filePath , ' r ' ) as file :
game_id = None
game_name = None
2024-02-16 07:54:58 +01:00
exe_path = None
2024-05-05 19:12:28 +02:00
depends_on = None
launch_command = None
2024-05-08 09:57:05 +02:00
start_menu_link = None
2024-05-08 10:55:55 +02:00
gog_entry = False
2024-01-26 10:18:26 +01:00
for line in file :
2024-10-26 00:20:16 +02:00
split_line = line . split ( " = " )
if len ( split_line ) > 1 :
if " gameid " in line . lower ( ) :
game_id = re . findall ( r ' \ " (.+?) \ " ' , split_line [ 1 ] )
if game_id :
game_id = game_id [ 0 ]
if " gamename " in line . lower ( ) :
game_name = re . findall ( r ' \ " (.+?) \ " ' , split_line [ 1 ] )
if game_name :
game_name = bytes ( game_name [ 0 ] , ' utf-8 ' ) . decode ( ' unicode_escape ' )
game_name = game_name . replace ( ' !22 ' , ' ™ ' )
if " exe " in line . lower ( ) and not " unins000.exe " in line . lower ( ) :
exe_path = re . findall ( r ' \ " (.+?) \ " ' , split_line [ 1 ] )
if exe_path :
exe_path = exe_path [ 0 ] . replace ( ' \\ \\ ' , ' \\ ' )
if " dependson " in line . lower ( ) :
depends_on = re . findall ( r ' \ " (.+?) \ " ' , split_line [ 1 ] )
if depends_on :
depends_on = depends_on [ 0 ]
if " launchcommand " in line . lower ( ) :
launch_command = re . findall ( r ' \ " (.+?) \ " ' , split_line [ 1 ] )
if launch_command :
launch_command = launch_command [ 0 ]
if game_id and game_name and launch_command :
game_dict [ game_name ] = { ' id ' : game_id , ' exe ' : exe_path }
game_id = None
game_name = None
exe_path = None
depends_on = None
launch_command = None
2024-01-26 10:18:26 +01:00
return game_dict
2024-05-08 10:55:55 +02:00
2024-11-04 16:15:18 +01:00
def adjust_dosbox_launch_options ( launch_command , game_id ) :
print ( f " Adjusting launch options for command: { launch_command } " )
if " dosbox.exe " in launch_command . lower ( ) :
try :
# Find the part of the command with DOSBox.exe and its arguments
exe_part , args_part = launch_command . split ( " DOSBox.exe " , 1 )
exe_path = exe_part . strip ( ) + " DOSBox.exe "
args = args_part . strip ( )
# Form the launch options string
launch_options = f ' STEAM_COMPAT_DATA_PATH= " { logged_in_home } /.local/share/Steam/steamapps/compatdata/ { gog_galaxy_launcher } / " %command% /command=runGame /gameId= { game_id } /path= " { exe_path } " " { args } " '
return launch_options
except ValueError as e :
print ( f " Error adjusting launch options: { e } " )
return launch_command
else :
2024-11-05 01:35:30 +01:00
# For non-DOSBox games, return the original launch command without trailing spaces
launch_command = launch_command . strip ( )
2024-11-04 16:15:18 +01:00
return f ' STEAM_COMPAT_DATA_PATH= " { logged_in_home } /.local/share/Steam/steamapps/compatdata/ { gog_galaxy_launcher } / " %command% /command=runGame /gameId= { game_id } /path= " { launch_command } " '
2024-05-08 10:55:55 +02:00
2024-01-26 10:18:26 +01:00
# Define your paths
gog_games_directory = f " { logged_in_home } /.local/share/Steam/steamapps/compatdata/ { gog_galaxy_launcher } /pfx/drive_c/Program Files (x86)/GOG Galaxy/Games "
registry_file_path = f " { logged_in_home } /.local/share/Steam/steamapps/compatdata/ { gog_galaxy_launcher } /pfx/system.reg "
# Check if the paths exist
if not os . path . exists ( gog_games_directory ) or not os . path . exists ( registry_file_path ) :
print ( " One or more paths do not exist. " )
print ( " GOG Galaxy game data not found. Skipping GOG Galaxy Games Scanner. " )
else :
game_dict = getGogGameInfo ( registry_file_path )
for game , game_info in game_dict . items ( ) :
2024-05-08 07:15:15 +02:00
if game_info [ ' id ' ] :
2024-11-04 16:15:18 +01:00
# Adjust the launch options for DOSBox games
launch_options = adjust_dosbox_launch_options ( game_info [ ' exe ' ] , game_info [ ' id ' ] )
# Format the paths correctly
2024-05-08 07:15:15 +02:00
exe_path = f " \" { logged_in_home } /.local/share/Steam/steamapps/compatdata/ { gog_galaxy_launcher } /pfx/drive_c/Program Files (x86)/GOG Galaxy/GalaxyClient.exe \" "
start_dir = f " \" { logged_in_home } /.local/share/Steam/steamapps/compatdata/ { gog_galaxy_launcher } /pfx/drive_c/Program Files (x86)/GOG Galaxy/ \" "
2024-11-04 16:15:18 +01:00
# Create the new entry
2024-02-09 01:24:46 +01:00
create_new_entry ( exe_path , game , launch_options , start_dir )
2024-01-26 10:18:26 +01:00
2024-05-08 07:15:15 +02:00
# End of Gog Galaxy Scanner
2024-05-08 07:05:13 +02:00
2024-05-08 09:23:47 +02:00
2024-05-08 09:57:05 +02:00
2024-05-08 10:55:55 +02:00
2024-11-05 01:35:30 +01:00
2024-02-02 05:51:08 +01:00
#Battle.net Scanner
2024-12-04 11:48:56 +01:00
2024-02-02 05:51:08 +01:00
# Define your mapping
flavor_mapping = {
2024-12-04 11:48:56 +01:00
" RTRO " : " Blizzard Arcade Collection " ,
" D1 " : " Diablo " ,
" OSI " : " Diablo II Resurrected " ,
" D3 " : " Diablo III " ,
" Fen " : " Diablo IV " ,
" ANBS " : " Diablo Immortal (PC) " ,
" WTCG " : " Hearthstone " ,
" Hero " : " Heroes of the Storm " ,
" Pro " : " Overwatch 2 " ,
" S1 " : " StarCraft " ,
" S2 " : " StarCraft 2 " ,
" W1 " : " Warcraft: Orcs & Humans " ,
" W2 " : " Warcraft II: Battle.net Edition " ,
" W3 " : " Warcraft III: Reforged " ,
" WoW " : " World of Warcraft " ,
" WoWC " : " World of Warcraft Classic " ,
" GRY " : " Warcraft Arclight Rumble " ,
" ZEUS " : " Call of Duty: Black Ops - Cold War " ,
" VIPR " : " Call of Duty: Black Ops 4 " ,
" ODIN " : " Call of Duty: Modern Warfare " ,
" AUKS " : " Call of Duty " ,
" LAZR " : " Call of Duty: MW 2 Campaign Remastered " ,
" FORE " : " Call of Duty: Vanguard " ,
" SPOT " : " Call of Duty: Modern Warfare III " ,
" WLBY " : " Crash Bandicoot 4: It ' s About Time " ,
2024-02-02 05:51:08 +01:00
# Add more games here...
}
2024-12-04 11:48:56 +01:00
def parse_battlenet_config ( config_file_path ) :
print ( f " Opening Battle.net config file at: { config_file_path } " )
with open ( config_file_path , ' r ' ) as file :
config_data = json . load ( file )
2024-02-02 05:51:08 +01:00
2024-12-04 11:48:56 +01:00
games_info = config_data . get ( " Games " , { } )
2024-02-02 05:51:08 +01:00
game_dict = { }
2024-12-04 11:48:56 +01:00
for game_key , game_data in games_info . items ( ) :
print ( f " Processing game: { game_key } " )
if game_key == " battle_net " :
print ( " Skipping ' battle_net ' entry " )
continue
if " Resumable " not in game_data :
print ( f " Skipping { game_key } , no ' Resumable ' key found " )
continue
if game_data [ " Resumable " ] == " false " :
print ( f " Game { game_key } is not resumable, adding to game_dict " )
game_dict [ game_key ] = {
" ServerUid " : game_data . get ( " ServerUid " , " " ) ,
" LastActioned " : game_data . get ( " LastActioned " , " " )
}
print ( f " Parsed config data: { game_dict } " )
2024-02-02 05:51:08 +01:00
return game_dict
game_dict = { }
2024-12-04 11:48:56 +01:00
print ( " Detected platform: Non-Windows " )
config_file_path = f " { logged_in_home } /.local/share/Steam/steamapps/compatdata/ { bnet_launcher } /pfx/drive_c/users/steamuser/AppData/Roaming/Battle.net/Battle.net.config "
print ( f " Config file path: { config_file_path } " )
if os . path . exists ( config_file_path ) :
print ( " Battle.net config file found, parsing... " )
game_dict = parse_battlenet_config ( config_file_path )
2024-02-02 05:51:08 +01:00
else :
2024-12-04 11:48:56 +01:00
print ( " Battle.net config file not found. Skipping Battle.net Games Scanner. " )
if game_dict :
for game_key , game_info in game_dict . items ( ) :
print ( f " Processing game: { game_key } " )
if game_key == " prometheus " :
print ( " Handling ' prometheus ' as ' Pro ' " )
game_key = " Pro "
2024-12-04 14:24:57 +01:00
elif game_key == " fenris " :
print ( " Handling ' fenris ' as ' Fen ' " )
game_key = " Fen "
2024-12-04 11:48:56 +01:00
game_name = flavor_mapping . get ( game_key , " unknown " )
if game_name == " unknown " :
game_name = flavor_mapping . get ( game_key . upper ( ) , " unknown " )
print ( f " Trying uppercase for { game_key } : { game_name } " )
if game_name == " unknown " :
print ( f " Game { game_key } remains unknown, skipping... " )
continue
matched_key = next ( ( k for k , v in flavor_mapping . items ( ) if v == game_name ) , game_key )
print ( f " Matched key for { game_key } : { matched_key } " )
if game_name == " Overwatch " :
game_name = " Overwatch 2 "
print ( f " Renaming ' Overwatch ' to ' Overwatch 2 ' " )
if game_info [ ' ServerUid ' ] == " unknown " :
print ( f " Skipping game { game_key } due to unknown ServerUid " )
continue
exe_path = f ' " { logged_in_home } /.local/share/Steam/steamapps/compatdata/ { bnet_launcher } /pfx/drive_c/Program Files (x86)/Battle.net/Battle.net.exe " '
start_dir = f ' " { logged_in_home } /.local/share/Steam/steamapps/compatdata/ { bnet_launcher } /pfx/drive_c/Program Files (x86)/Battle.net/ " '
launch_options = f ' STEAM_COMPAT_DATA_PATH= " { logged_in_home } /.local/share/Steam/steamapps/compatdata/ { bnet_launcher } " %command% --exec= " launch { matched_key } " battlenet:// { matched_key } '
print ( f " Creating new entry for { game_name } with exe_path: { exe_path } " )
create_new_entry ( exe_path , game_name , launch_options , start_dir )
print ( " Battle.net Games Scanner completed. " )
2024-02-02 05:51:08 +01:00
# End of Battle.net Scanner
2024-02-03 05:21:54 +01:00
# Amazon Games Scanner
def get_sqlite_path ( ) :
# Specify the full path to the SQLite file
path = f " { logged_in_home } /.local/share/Steam/steamapps/compatdata/ { amazon_launcher } /pfx/drive_c/users/steamuser/AppData/Local/Amazon Games/Data/Games/Sql/GameInstallInfo.sqlite "
if os . path . exists ( path ) :
return path
else :
print ( f " Amazon GameInstallInfo.sqlite not found at { path } " )
return None
def get_launcher_path ( ) :
# Specify the full path to the Amazon Games launcher executable
path = f " { logged_in_home } /.local/share/Steam/steamapps/compatdata/ { amazon_launcher } /pfx/drive_c/users/steamuser/AppData/Local/Amazon Games/App/Amazon Games.exe "
if os . path . exists ( path ) :
return path
else :
print ( f " Could not find Amazon Games.exe at { path } " )
return None
def get_amazon_games ( ) :
sqllite_path = get_sqlite_path ( )
launcher_path = get_launcher_path ( )
if sqllite_path is None or launcher_path is None :
print ( " Skipping Amazon Games Scanner due to missing paths. " )
return [ ]
result = [ ]
connection = sqlite3 . connect ( sqllite_path )
cursor = connection . cursor ( )
cursor . execute ( " SELECT Id, ProductTitle FROM DbSet WHERE Installed = 1 " )
for row in cursor . fetchall ( ) :
id , title = row
result . append ( { " id " : id , " title " : title , " launcher_path " : launcher_path } )
return result
amazon_games = get_amazon_games ( )
if amazon_games :
for game in amazon_games :
# Initialize variables
display_name = game [ ' title ' ]
exe_path = f " \" { logged_in_home } /.local/share/Steam/steamapps/compatdata/ { amazon_launcher } /pfx/drive_c/users/steamuser/AppData/Local/Amazon Games/App/Amazon Games.exe \" "
start_dir = f " \" { logged_in_home } /.local/share/Steam/steamapps/compatdata/ { amazon_launcher } /pfx/drive_c/users/steamuser/AppData/Local/Amazon Games/App/ \" "
2024-11-02 07:21:36 +01:00
launch_options = f " STEAM_COMPAT_DATA_PATH= \" { logged_in_home } /.local/share/Steam/steamapps/compatdata/ { amazon_launcher } / \" %command% - ' amazon-games://play/ { game [ ' id ' ] } ' "
2024-02-09 01:24:46 +01:00
create_new_entry ( exe_path , display_name , launch_options , start_dir )
2024-02-03 05:21:54 +01:00
#End of Amazon Games Scanner
2024-02-09 01:24:46 +01:00
2024-02-28 09:54:25 +01:00
2024-11-05 09:53:10 +01:00
# Itchio Scanner
2024-11-05 08:59:31 +01:00
2024-11-05 09:53:10 +01:00
# Set up the path to the Butler database
itch_db_location = f " { logged_in_home } /.local/share/Steam/steamapps/compatdata/ { itchio_launcher } /pfx/drive_c/users/steamuser/AppData/Roaming/itch/db/butler.db "
2024-04-25 12:33:02 +02:00
2024-11-05 09:53:10 +01:00
# Check if the database path exists
if not os . path . exists ( itch_db_location ) :
2024-11-05 10:20:07 +01:00
print ( f " Path not found: { itch_db_location } . Aborting Itch.io scan... " )
2024-11-05 09:53:10 +01:00
else :
# Connect to the SQLite database
2024-11-05 08:59:31 +01:00
conn = sqlite3 . connect ( itch_db_location )
cursor = conn . cursor ( )
2024-11-05 09:53:10 +01:00
# Fetch data from the 'caves' table
2024-11-05 08:59:31 +01:00
cursor . execute ( " SELECT * FROM caves; " )
caves = cursor . fetchall ( )
2024-11-05 09:53:10 +01:00
# Fetch data from the 'games' table
2024-11-05 08:59:31 +01:00
cursor . execute ( " SELECT * FROM games; " )
games = cursor . fetchall ( )
# Create a dictionary to store game information by game_id
games_dict = { game [ 0 ] : game for game in games }
2024-11-05 09:53:10 +01:00
# List to store final Itch.io game details
itchgames = [ ]
# Match game_id between 'caves' and 'games' tables and collect relevant game details
2024-11-05 08:59:31 +01:00
for cave in caves :
game_id = cave [ 1 ]
if game_id in games_dict :
game_info = games_dict [ game_id ]
2024-11-05 10:20:07 +01:00
cave_info = json . loads ( cave [ 11 ] )
2024-11-05 09:53:10 +01:00
base_path = cave_info [ ' basePath ' ]
candidates = cave_info [ ' candidates ' ]
2024-11-05 08:59:31 +01:00
executable_path = candidates [ 0 ] [ ' path ' ]
2024-11-05 09:53:10 +01:00
# Skip games with an executable that ends with '.html' (browser games)
2024-11-05 08:59:31 +01:00
if executable_path . endswith ( ' .html ' ) :
2024-11-05 10:20:07 +01:00
print ( f " Skipping browser game: { game_info [ 2 ] } " )
2024-11-05 08:59:31 +01:00
continue
2024-04-25 12:33:02 +02:00
2024-11-05 09:53:10 +01:00
# Extract the game title
2024-11-05 08:59:31 +01:00
game_title = game_info [ 2 ]
2024-04-25 12:33:02 +02:00
2024-11-05 09:53:10 +01:00
# Append the game info (base path, executable path, game title) to the list
itchgames . append ( ( base_path , executable_path , game_title ) )
2024-04-25 12:33:02 +02:00
2024-11-05 09:53:10 +01:00
# Process each game for creating new entries
for base_path , executable , game_title in itchgames :
base_path_linux = base_path . replace ( " C: \\ " , f " { logged_in_home } /.local/share/Steam/steamapps/compatdata/ { itchio_launcher } /pfx/drive_c/ " ) . replace ( " \\ " , " / " )
exe_path = " \" " + os . path . join ( base_path_linux , executable ) . replace ( " \\ " , " / " ) + " \" "
start_dir = " \" " + base_path_linux + " \" "
launchoptions = f " STEAM_COMPAT_DATA_PATH= \" { logged_in_home } /.local/share/Steam/steamapps/compatdata/ { itchio_launcher } / \" %command% "
2024-11-05 08:59:31 +01:00
2024-11-05 09:53:10 +01:00
# Call the provided function to create a new entry for the game
create_new_entry ( exe_path , game_title , launchoptions , start_dir )
2024-04-25 12:33:02 +02:00
2024-11-05 09:53:10 +01:00
# Close the database connection
conn . close ( )
2024-11-05 08:59:31 +01:00
2024-11-05 09:53:10 +01:00
# End of Itch.io Scanner
2024-06-29 04:02:52 +02:00
2024-08-22 12:00:24 +02:00
2024-06-29 04:02:52 +02:00
#Legacy Games Scanner
legacy_dir = f " { logged_in_home } /.local/share/Steam/steamapps/compatdata/ { legacy_launcher } /pfx/drive_c/Program Files/Legacy Games/ "
2024-07-16 10:48:07 +02:00
if not os . path . exists ( legacy_dir ) :
print ( " Legacy directory not found. Skipping creation. " )
2024-06-29 04:02:52 +02:00
else :
2024-07-16 10:48:07 +02:00
user_reg_path = f " { logged_in_home } /.local/share/Steam/steamapps/compatdata/ { legacy_launcher } /pfx/user.reg "
2024-06-29 04:02:52 +02:00
with open ( user_reg_path , ' r ' ) as file :
user_reg = file . read ( )
for game_dir in os . listdir ( legacy_dir ) :
if game_dir == " Legacy Games Launcher " :
continue
print ( f " Processing game directory: { game_dir } " )
if game_dir == " 100 Doors Escape from School " :
app_info_path = f " { legacy_dir } /100 Doors Escape from School/100 Doors Escape From School_Data/app.info "
exe_path = f " { legacy_dir } /100 Doors Escape from School/100 Doors Escape From School.exe "
else :
app_info_path = os . path . join ( legacy_dir , game_dir , game_dir . replace ( " " , " " ) + " _Data " , " app.info " )
exe_path = os . path . join ( legacy_dir , game_dir , game_dir . replace ( " " , " " ) + " .exe " )
if os . path . exists ( app_info_path ) :
print ( " app.info file found. " )
with open ( app_info_path , ' r ' ) as file :
lines = file . read ( ) . split ( ' \n ' )
game_name = lines [ 1 ] . strip ( )
print ( f " Game Name: { game_name } " )
else :
print ( " No app.info file found. " )
if os . path . exists ( exe_path ) :
game_exe_reg = re . search ( r ' \ [Software \\ \\ Legacy Games \\ \\ ' + re . escape ( game_dir ) + r ' \ ].*? " GameExe " = " ([^ " ]*) " ' , user_reg , re . DOTALL | re . IGNORECASE )
if game_exe_reg and game_exe_reg . group ( 1 ) . lower ( ) == os . path . basename ( exe_path ) . lower ( ) :
print ( f " GameExe found in user.reg: { game_exe_reg . group ( 1 ) } " )
start_dir = f " { legacy_dir } { game_dir } "
launch_options = f " STEAM_COMPAT_DATA_PATH= \" { logged_in_home } /.local/share/Steam/steamapps/compatdata/ { legacy_launcher } \" %command% "
create_new_entry ( f ' " { exe_path } " ' , game_name , launch_options , f ' " { start_dir } " ' )
else :
print ( f " No matching .exe file found for game: { game_dir } " )
else :
print ( f " No .exe file found for game: { game_dir } " )
#End of the Legacy Games Scanner
2024-04-25 12:33:02 +02:00
2024-02-12 06:44:26 +01:00
# Only write back to the shortcuts.vdf and config.vdf files if new shortcuts were added or compattools changed
if new_shortcuts_added or shortcuts_updated :
print ( f " Saving new config and shortcuts files " )
conf = vdf . dumps ( config_data , pretty = True )
2024-05-02 10:43:22 +02:00
try :
with open ( f " { logged_in_home } /.steam/root/config/config.vdf " , ' w ' ) as file :
file . write ( conf )
except IOError as e :
print ( f " Error writing to config.vdf: { e } " )
try :
with open ( f " { logged_in_home } /.steam/root/userdata/ { steamid3 } /config/shortcuts.vdf " , ' wb ' ) as file :
file . write ( vdf . binary_dumps ( shortcuts ) )
except IOError as e :
print ( f " Error writing to shortcuts.vdf: { e } " )
2024-02-12 06:44:26 +01:00
# Print the created shortcuts
if created_shortcuts :
print ( " Created Shortcuts: " )
for name in created_shortcuts :
print ( name )
2024-02-28 05:12:24 +01:00
# Create the path to the output file
output_file_path = f " { logged_in_home } /.config/systemd/user/NSLGameScanner_output.log "
# Open the output file in write mode
2024-05-02 10:43:22 +02:00
try :
with open ( output_file_path , ' w ' ) as output_file :
for game in decky_shortcuts . values ( ) :
# Skip if 'appname' or 'exe' is None
if game . get ( ' appname ' ) is None or game . get ( ' exe ' ) is None :
continue
# Create a dictionary to hold the shortcut information
shortcut_info = {
' appname ' : game . get ( ' appname ' ) ,
' exe ' : game . get ( ' exe ' ) ,
' StartDir ' : game . get ( ' StartDir ' ) ,
' icon ' : game . get ( ' icon ' ) ,
' LaunchOptions ' : game . get ( ' LaunchOptions ' ) ,
' CompatTool ' : game . get ( ' CompatTool ' ) ,
' WideGrid ' : game . get ( ' WideGrid ' ) ,
' Grid ' : game . get ( ' Grid ' ) ,
' Hero ' : game . get ( ' Hero ' ) ,
' Logo ' : game . get ( ' Logo ' ) ,
}
# Print the shortcut information in JSON format
message = json . dumps ( shortcut_info )
print ( message , flush = True ) # Print to stdout
# Print the shortcut information to the output file
print ( message , file = output_file , flush = True )
except IOError as e :
print ( f " Error writing to output file: { e } " )
2024-02-17 04:40:51 +01:00
2024-02-18 15:23:09 +01:00
print ( " All finished! " )