EmuDeck/tools/vdf/add.py
Dragoon Dorise 57de96dee6 reopen Steam
2025-02-15 11:28:57 +01:00

174 lines
5.8 KiB
Python

import os
import sys
import vdf
import zlib
import shutil
import subprocess
def generate_preliminary_id(exe, appname):
"""
Genera un ID preliminar utilizando CRC32 y el bit más significativo.
Equivalente a `generatePreliminaryId` en SRM.
"""
key = exe + appname
crc_value = zlib.crc32(key.encode('utf-8')) & 0xFFFFFFFF # Aseguramos 32 bits
top = (crc_value | 0x80000000) # Establecer el bit más significativo
return (top << 32) | 0x02000000 # Combinar con 0x02000000
def generate_app_id(exe, appname):
"""
Genera el AppId completo utilizado en Big Picture Grids.
Equivalente a `generateAppId` en SRM.
"""
return str(generate_preliminary_id(exe, appname))
def generate_short_app_id(exe, appname):
"""
Genera el ShortAppId utilizado para otras grids.
Equivalente a `generateShortAppId` en SRM.
"""
long_id = generate_preliminary_id(exe, appname)
return str(long_id >> 32)
def generate_shortcut_id(exe, appname):
"""
Genera el ShortcutId utilizado en shortcuts.vdf.
Equivalente a `generateShortcutId` en SRM.
"""
long_id = generate_preliminary_id(exe, appname)
return int((long_id >> 32) - 0x100000000)
def shorten_app_id(long_id):
"""
Convierte un AppId largo a un ShortAppId.
Equivalente a `shortenAppId` en SRM.
"""
return str(int(long_id) >> 32)
def lengthen_app_id(short_id):
"""
Convierte un ShortAppId a un AppId largo.
Equivalente a `lengthenAppId` en SRM.
"""
return str((int(short_id) << 32) | 0x02000000)
def shortcutify_app_id(long_id):
"""
Convierte un AppId largo a un ShortcutAppId.
Equivalente a `shortcutifyAppId` en SRM.
"""
return int(shorten_app_id(long_id)) >> 32
def appify_shortcut_id(shortcut_id):
"""
Convierte un ShortcutAppId a un AppId largo.
Equivalente a `appifyShortcutId` en SRM.
"""
return lengthen_app_id(str(int(shortcut_id) + 0x100000000))
def copy_steam_images(grid_path, id, shortcut_id):
# Directorio de las imágenes de Steam ROM Manager
if os.name == 'nt':
src_dir = os.path.expanduser(f"~/AppData/Roaming/EmuDeck/backend/configs/steam-rom-manager/userData/img/emus/{id}")
else:
src_dir = os.path.expanduser(f"~/.config/EmuDeck/backend/configs/steam-rom-manager/userData/img/emus/{id}")
# Definir las rutas de origen y destino
images = {
"hero": (f"{src_dir}/{id}_hero.png", f"{grid_path}/{shortcut_id}_hero.jpg"),
"logo": (f"{src_dir}/{id}_logo.png", f"{grid_path}/{shortcut_id}_logo.png"),
"banner": (f"{src_dir}/{id}_banner.png", f"{grid_path}/{shortcut_id}.jpg"),
"portrait": (f"{src_dir}/{id}_portrait.png", f"{grid_path}/{shortcut_id}p.png"),
"icon": (f"{src_dir}/{id}_ico.png", f"{grid_path}/{shortcut_id}_icon.ico"),
}
# Copiar cada imagen si existe
for img_type, (src, dst) in images.items():
if os.path.exists(src):
shutil.copy(src, dst)
print(f"{img_type.capitalize()} image copied: {dst}")
else:
print(f"{img_type.capitalize()} image not found: {src}")
def add_steam_shortcut(id, name, target_path, start_dir, icon_path, steam_dir, user_id):
# Ruta del archivo shortcuts.vdf
shortcuts_path = os.path.join(user_id, "config", "shortcuts.vdf")
grid_path = os.path.join(user_id, "config", "grid")
# Leer el archivo actual
try:
with open(shortcuts_path, "rb") as f:
shortcuts_data = vdf.binary_load(f)
except FileNotFoundError:
# Crear una estructura básica si no existe el archivo
shortcuts_data = {"shortcuts": {}}
# Normalizar el nombre y la ruta para evitar duplicados por mayúsculas o espacios
normalized_name = name.strip().lower()
normalized_target = target_path.strip().lower()
# Comprobar si ya existe un acceso directo con el mismo nombre o ruta
for shortcut in shortcuts_data.get("shortcuts", {}).values():
existing_name = shortcut.get("appname", "").strip().lower()
existing_target = shortcut.get("exe", "").strip('"').strip().lower()
if existing_name == normalized_name or existing_target == normalized_target:
print(f"El acceso directo '{name}' ya existe en Steam y no se añadirá.")
return # Salir sin añadir el acceso directo
# Buscar el próximo índice disponible
existing_indices = [int(k) for k in shortcuts_data["shortcuts"].keys()]
next_index = max(existing_indices, default=-1) + 1
# Generar un AppID válido
appid = generate_short_app_id(target_path, name)
# Crear el nuevo acceso directo
shortcuts_data["shortcuts"][str(next_index)] = {
"appname": name,
"exe": f'"{target_path}"',
"StartDir": f'"{start_dir}"',
"icon": f'"{icon_path}"',
"ShortcutPath": "",
"LaunchOptions": "",
"IsHidden": 0,
"AllowDesktopConfig": 1,
"AllowOverlay": 1,
"OpenVR": 0,
"Devkit": 0,
"DevkitGameID": "",
"LastPlayTime": 0,
"tags": {"0": "favorite"},
"appid": appid # Agregar el AppID
}
# Escribir los cambios de vuelta al archivo
with open(shortcuts_path, "wb") as f:
vdf.binary_dump(shortcuts_data, f)
print(f"El acceso directo '{name}' se ha añadido correctamente con AppID {appid} en '{shortcuts_path}'")
# Crear el directorio para las imágenes si no existe
os.makedirs(grid_path, exist_ok=True)
# Copiar imágenes usando el AppID
copy_steam_images(grid_path, id, appid)
subprocess.Popen(["steam", "-silent"], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
# Llamar a la función principal
add_steam_shortcut(
id=sys.argv[1],
name=sys.argv[2],
target_path=sys.argv[3],
start_dir=sys.argv[4],
icon_path=sys.argv[5],
steam_dir=sys.argv[6],
user_id=sys.argv[7],
)