diff --git a/backend/locales/en.json b/backend/locales/en.json
index 77b5d4f..45ca4bc 100644
--- a/backend/locales/en.json
+++ b/backend/locales/en.json
@@ -23,11 +23,14 @@
"Cancelling...": "Cancelling...",
"Check for updates": "Check for updates",
"Checking availability…": "Checking availability…",
+ "Checking content…": "Checking content…",
"Checking generic fix...": "Checking generic fix...",
"Checking online-fix...": "Checking online-fix...",
"Checking…": "Checking…",
"Close": "Close",
"Confirm": "Confirm",
+ "Content details =>": "Content details =>",
+ "Dlc: ": "Dlc: ",
"DLC Detected": "DLC Detected",
"DLCs are added together with the base game. To add fixes for this DLC, please go to the base game page:
{gameName}": "DLCs are added together with the base game. To add this DLC, please go to the base game page:
{gameName}",
"Discord": "Discord",
@@ -62,6 +65,7 @@
"Generic fix found!": "Generic fix found!",
"Go to Base Game": "Go to Base Game",
"Hide": "Hide",
+ "Included": "Included 🎉",
"Installing…": "Installing…",
"Join the Discord!": "Join the Discord!",
"Left click to install, Right click for SteamDB": "Left click to install, Right click for SteamDB",
@@ -75,11 +79,13 @@
"LuaTools · Menu": "LuaTools · Menu",
"LuaTools · {api}": "LuaTools · {api}",
"Manage Game": "Manage Game",
+ "Missing": "Missing ❌",
"No games found.": "No games found.",
"No generic fix": "No generic fix",
"No online-fix": "No online-fix",
"No updates available.": "No updates available.",
"Not found": "Not found",
+ "No workshop for the game": "No workshop for the game ✅",
"Online Fix": "Online Fix",
"Online Fix (Unsteam)": "Online Fix (Unsteam)",
"Online-fix found!": "Online-fix found!",
@@ -98,6 +104,7 @@
"Unknown error": "Unknown error",
"Waiting…": "Waiting…",
"Working…": "Working…",
+ "Workshop: ": "Workshop: ",
"bigpicture.mouseTip": "To use mouse mode in Steam: Guide Button + Right Joystick, click with RB",
"common.alert.ok": "OK",
"common.appName": "LuaTools",
diff --git a/backend/locales/fr.json b/backend/locales/fr.json
index 49592b1..853fcc9 100644
--- a/backend/locales/fr.json
+++ b/backend/locales/fr.json
@@ -1,195 +1,202 @@
-{
- "_meta": {
- "code": "fr",
- "name": "French",
- "nativeName": "Français",
- "credits": "Odjavel"
- },
- "strings": {
- "Add via LuaTools": "Ajouter via LuaTools",
- "Advanced": "Avancé",
- "All-In-One Fixes": "Correctifs tout-en-un",
- "Apply": "Appliquer",
- "Applying {fix}": "Application de {fix}",
- "Are you sure you want to un-fix? This will remove fix files and verify game files.": "Êtes-vous sûr de vouloir supprimer le correctif ? Cela supprimera les fichiers de correctif et vérifiera les fichiers du jeu.",
- "Are you sure?": "Êtes-vous sûr ?",
- "Back": "Retour",
- "Base Game": "Jeu de base",
- "Cancel": "Annuler",
- "Cancellation failed": "Échec de l'annulation",
- "Cancelled": "Annulé",
- "Cancelled by user": "Annulé par l'utilisateur",
- "Cancelled: {reason}": "Annulé : {reason}",
- "Cancelling...": "Annulation...",
- "Check for updates": "Vérifier les mises à jour.",
- "Checking availability…": "Vérification de la disponibilité…",
- "Checking generic fix...": "Vérification du correctif générique...",
- "Checking online-fix...": "Vérification du correctif Online-Fix...",
- "Checking…": "Vérification…",
- "Close": "Fermer",
- "Confirm": "Confirmer",
- "DLC Detected": "DLC Détecté",
- "DLCs are added together with the base game. To add fixes for this DLC, please go to the base game page:
{gameName}": "Les DLC sont ajoutés avec le jeu de base. Pour ajouter des correctifs pour ce DLC, rendez-vous sur la page du jeu de base :
{gameName}",
- "Discord": "Discord",
- "Dismiss": "Fermer",
- "Downloading...": "Téléchargement...",
- "Downloading: {percent}%": "Téléchargement : {percent}%",
- "Downloading…": "Téléchargement…",
- "Error applying fix": "Erreur lors de l'application du correctif.",
- "Error checking for fixes": "Erreur lors de la vérification des correctifs.",
- "Error starting Online Fix": "Erreur lors du démarrage des correctifs Online-Fix.",
- "Error starting un-fix": "Erreur lors du démarrage de la suppression du correctif.",
- "Error! Code: {code}": "Erreur ! Code : {code}",
- "Error, Code: {code}": "Erreur, Code : {code}",
- "Error, Timed Out": "Erreur, Délai d'attente dépassé",
- "Extracting to game folder...": "Extraction vers le dossier du jeu...",
- "Failed": "Échec",
- "Failed to cancel fix download": "Échec de l'annulation du téléchargement du correctif.",
- "Failed to check for fixes.": "Échec de la vérification des correctifs.",
- "Failed to load free APIs.": "Échec du chargement des API gratuites.",
- "Failed to start fix download": "Échec du démarrage du téléchargement du correctif.",
- "Failed to start un-fix": "Échec du démarrage de la suppression du correctif.",
- "Failed: {error}": "Échec : {error}",
- "Fetch Free API's": "Récupérer les API Gratuites.",
- "Fetching game name...": "Récupération du nom du jeu...",
- "Finishing…": "Finalisation…",
- "Fixes Menu": "Menu des correctifs",
- "Found": "Trouvé",
- "Game added!": "Jeu ajouté !",
- "Game folder": "Dossier du jeu",
- "Game install path not found": "Chemin d'installation du jeu introuvable.",
- "Generic Fix": "Correctif Générique",
- "Generic fix found!": "Correctif générique trouvé !",
- "Go to Base Game": "Aller au jeu de base",
- "Hide": "Masquer",
- "Installing…": "Installation…",
- "Join the Discord!": "Rejoignez le Discord !",
- "Left click to install, Right click for SteamDB": "Clic gauche pour installer. Clic droit pour SteamDB.",
- "Loaded free APIs: {count}": "API gratuites chargées : {count}",
- "Loading fixes...": "Chargement des correctifs...",
- "Look for Fixes": "Rechercher des correctifs",
- "LuaTools backend unavailable": "Backend LuaTools indisponible.",
- "LuaTools · AIO Fixes Menu": "LuaTools · Menu des correctifs tout-en-un",
- "LuaTools · Added Games": "LuaTools · Jeux ajoutés",
- "LuaTools · Fixes Menu": "LuaTools · Menu des correctifs",
- "LuaTools · Menu": "LuaTools · Menu",
- "LuaTools · {api}": "LuaTools · {api}",
- "Manage Game": "Gérer le jeu",
- "No games found.": "Aucun jeux trouvé.",
- "No generic fix": "Aucun correctif générique",
- "No online-fix": "Aucun correctif Online-Fix",
- "No updates available.": "Aucune mise à jour disponible.",
- "Not found": "Introuvable",
- "Online Fix": "Correctif en ligne (Online-Fix)",
- "Online Fix (Unsteam)": "Correctif en ligne (Unsteam)",
- "Online-fix found!": "Online-Fix trouvé !",
- "Only possible thanks to {name} 💜": "Possible uniquement grâce à {name} 💜",
- "Processing package…": "Traitement du paquet…",
- "Remove via LuaTools": "Retirer via LuaTools",
- "Removed {count} files. Running Steam verification...": "{count} fichiers supprimés. Exécution de la vérification Steam...",
- "Removing fix files...": "Suppression des fichiers de correctif...",
- "Restart Steam": "Redémarrer Steam",
- "Restart Steam now?": "Redémarrer Steam maintenant ?",
- "Settings": "Paramètres",
- "Skipped": "Ignoré",
- "Un-Fix (verify game)": "Supprimer le correctif (vérifier le jeu)",
- "Un-Fixing game": "Suppression du correctif du jeu.",
- "Unknown Game": "Jeu Inconnu",
- "Unknown error": "Erreur inconnue",
- "Waiting…": "En attente…",
- "Working…": "Travail en cours…",
- "bigpicture.mouseTip": "Pour utiliser le mode souris dans Steam : Bouton Guide + Joystick droit, clic avec RB",
- "common.alert.ok": "OK",
- "common.appName": "LuaTools",
- "common.error.unsupportedOption": "Type d'option non pris en charge : {type}",
- "common.status.error": "Erreur",
- "common.status.loading": "Chargement...",
- "common.status.success": "Succès",
- "common.translationMissing": "Traduction manquante",
- "common.warning": "Avertissement",
- "disclaimer.inputLabel": "tapez \"Je Comprends\" dans la case ci-dessous pour continuer",
- "disclaimer.inputPlaceholder": "Je Comprends",
- "disclaimer.line1": "LuaTools n'est affilié d'aucune façon à Millennium",
- "disclaimer.line2": "Millennium ne vous offrira PAS de support pour ce plugin sur leur serveur discord",
- "disclaimer.line3": "Vous serez BANNI des serveurs LuaTools et Millennium si vous allez sur leur discord demander de l'aide",
- "disclaimer.title": "Avis Important",
- "gameStatus.denuvo": "Denuvo",
- "gameStatus.needsFixes": "Correctif disponible",
- "gameStatus.playable": "Jouable",
- "gameStatus.unplayable": "Injouable",
- "menu.advancedLabel": "Avancé",
- "menu.checkForUpdates": "Vérifier les mises à jour",
- "menu.discord": "Discord",
- "menu.error.getPath": "Erreur lors de la récupération du chemin du jeu.",
- "menu.error.noAppId": "Impossible de déterminer l'AppID du jeu.",
- "menu.error.noInstall": "Impossible de trouver l'installation du jeu.",
- "menu.error.notInstalled": "Jeu non installé ! Ajoutez-le et installez-le d'abord :D",
- "menu.fetchFreeApis": "Récupérer les API Gratuites",
- "menu.fixesMenu": "Menu des correctifs",
- "menu.joinDiscordLabel": "Rejoignez le Discord !",
- "menu.manageGameLabel": "Gérer le Jeu",
- "menu.remove.confirm": "Retirer LuaTools pour ce jeu ?",
- "menu.remove.failure": "Échec du retrait de LuaTools.",
- "menu.remove.success": "LuaTools retiré pour cette application.",
- "menu.removeLuaTools": "Retirer via LuaTools",
- "menu.settings": "Paramètres",
- "menu.title": "LuaTools · Menu",
- "settings.close": "Fermer",
- "settings.donateKeys.description": "Faire don des clés de décryptage pour les jeux, aide tout le monde !",
- "settings.donateKeys.label": "Faire don de clés",
- "settings.donateKeys.no": "Non",
- "settings.donateKeys.yes": "Oui",
- "settings.empty": "Aucun paramètre disponible pour le moment.",
- "settings.error": "Échec du chargement des paramètres.",
- "settings.general": "Général",
- "settings.generalDescription": "Préférences globales de LuaTools.",
- "settings.installedFixes.date": "Installé :",
- "settings.installedFixes.delete": "Supprimer",
- "settings.installedFixes.deleteConfirm": "Êtes-vous sûr de vouloir supprimer ce correctif ? Cela supprimera les fichiers du correctif et exécutera la vérification Steam.",
- "settings.installedFixes.deleteError": "Échec de la suppression du correctif.",
- "settings.installedFixes.deleteSuccess": "Correctif supprimé avec succès !",
- "settings.installedFixes.deleting": "Suppression du correctif...",
- "settings.installedFixes.empty": "Aucun correctif installé pour le moment.",
- "settings.installedFixes.error": "Échec du chargement des correctifs installés.",
- "settings.installedFixes.files": "{count} fichiers",
- "settings.installedFixes.loading": "Recherche de correctifs installés...",
- "settings.installedFixes.title": "Correctifs Installés",
- "settings.installedFixes.type": "Type :",
- "settings.installedLua.delete": "Supprimer",
- "settings.installedLua.deleteConfirm": "Supprimer via LuaTools pour ce jeu ?",
- "settings.installedLua.deleteError": "Échec de la suppression via LuaTools.",
- "settings.installedLua.deleteSuccess": "Supprimé via LuaTools avec succès !",
- "settings.installedLua.deleting": "Suppression via LuaTools...",
- "settings.installedLua.disabled": "Désactivé",
- "settings.installedLua.empty": "Aucun script Lua installé pour le moment.",
- "settings.installedLua.error": "Échec du chargement des scripts Lua installés.",
- "settings.installedLua.loading": "Recherche de scripts Lua installés...",
- "settings.installedLua.modified": "Modifié :",
- "settings.installedLua.title": "Jeux via LuaTools",
- "settings.installedLua.unknownInfo": "Les jeux affichant 'Jeu inconnu' ont été installés depuis des sources externes (pas via LuaTools).",
- "settings.language.description": "Choisissez la langue utilisée par LuaTools.",
- "settings.language.label": "Langue",
- "settings.language.option.en": "Anglais",
- "settings.language.option.pt-BR": "Portugais Brésilien",
- "settings.loading": "Chargement des paramètres...",
- "settings.noChanges": "Aucune modification à enregistrer.",
- "settings.refresh": "Actualiser",
- "settings.refreshing": "Actualisation...",
- "settings.save": "Enregistrer les paramètres",
- "settings.saveError": "Échec de l'enregistrement des paramètres.",
- "settings.saveSuccess": "Paramètres enregistrés avec succès.",
- "settings.saving": "Enregistrement...",
- "settings.search.clear": "Effacer la recherche",
- "settings.search.noResults": "Aucun résultat trouvé",
- "settings.search.placeholder": "Rechercher paramètres, jeux, correctifs...",
- "settings.theme.description": "Choisissez le thème de couleur pour l'interface LuaTools.",
- "settings.theme.label": "Thème",
- "settings.title": "LuaTools · Paramètres",
- "settings.unsaved": "Modifications non enregistrées",
- "{fix} applied successfully!": "{fix} appliqué avec succès !",
- "settings.useSteamLanguage.label": "Utiliser la langue de Steam",
- "settings.useSteamLanguage.description": "Utiliser la langue du client Steam au lieu de celle de LuaTools.",
- "settings.useSteamLanguage.yes": "Oui",
- "settings.useSteamLanguage.no": "Non"
- }
-}
+{
+ "_meta": {
+ "code": "fr",
+ "name": "French",
+ "nativeName": "Français",
+ "credits": "Odjavel"
+ },
+ "strings": {
+ "Add via LuaTools": "Ajouter via LuaTools",
+ "Advanced": "Avancé",
+ "All-In-One Fixes": "Correctifs tout-en-un",
+ "Apply": "Appliquer",
+ "Applying {fix}": "Application de {fix}",
+ "Are you sure you want to un-fix? This will remove fix files and verify game files.": "Êtes-vous sûr de vouloir supprimer le correctif ? Cela supprimera les fichiers de correctif et vérifiera les fichiers du jeu.",
+ "Are you sure?": "Êtes-vous sûr ?",
+ "Back": "Retour",
+ "Base Game": "Jeu de base",
+ "Cancel": "Annuler",
+ "Cancellation failed": "Échec de l'annulation",
+ "Cancelled": "Annulé",
+ "Cancelled by user": "Annulé par l'utilisateur",
+ "Cancelled: {reason}": "Annulé : {reason}",
+ "Cancelling...": "Annulation...",
+ "Check for updates": "Vérifier les mises à jour.",
+ "Checking availability…": "Vérification de la disponibilité…",
+ "Checking content…": "Vérification du contenu…",
+ "Checking generic fix...": "Vérification du correctif générique...",
+ "Checking online-fix...": "Vérification du correctif Online-Fix...",
+ "Checking…": "Vérification…",
+ "Close": "Fermer",
+ "Confirm": "Confirmer",
+ "Content details =>": "Détails du contenu =>",
+ "DLC Detected": "DLC Détecté",
+ "DLCs are added together with the base game. To add fixes for this DLC, please go to the base game page:
{gameName}": "Les DLC sont ajoutés avec le jeu de base. Pour ajouter des correctifs pour ce DLC, rendez-vous sur la page du jeu de base :
{gameName}",
+ "Discord": "Discord",
+ "Dismiss": "Fermer",
+ "Dlc: ": "Dlc",
+ "Downloading...": "Téléchargement...",
+ "Downloading: {percent}%": "Téléchargement : {percent}%",
+ "Downloading…": "Téléchargement…",
+ "Error applying fix": "Erreur lors de l'application du correctif.",
+ "Error checking for fixes": "Erreur lors de la vérification des correctifs.",
+ "Error starting Online Fix": "Erreur lors du démarrage des correctifs Online-Fix.",
+ "Error starting un-fix": "Erreur lors du démarrage de la suppression du correctif.",
+ "Error! Code: {code}": "Erreur ! Code : {code}",
+ "Error, Code: {code}": "Erreur, Code : {code}",
+ "Error, Timed Out": "Erreur, Délai d'attente dépassé",
+ "Extracting to game folder...": "Extraction vers le dossier du jeu...",
+ "Failed": "Échec",
+ "Failed to cancel fix download": "Échec de l'annulation du téléchargement du correctif.",
+ "Failed to check for fixes.": "Échec de la vérification des correctifs.",
+ "Failed to load free APIs.": "Échec du chargement des API gratuites.",
+ "Failed to start fix download": "Échec du démarrage du téléchargement du correctif.",
+ "Failed to start un-fix": "Échec du démarrage de la suppression du correctif.",
+ "Failed: {error}": "Échec : {error}",
+ "Fetch Free API's": "Récupérer les API Gratuites.",
+ "Fetching game name...": "Récupération du nom du jeu...",
+ "Finishing…": "Finalisation…",
+ "Fixes Menu": "Menu des correctifs",
+ "Found": "Trouvé",
+ "Game added!": "Jeu ajouté !",
+ "Game folder": "Dossier du jeu",
+ "Game install path not found": "Chemin d'installation du jeu introuvable.",
+ "Generic Fix": "Correctif Générique",
+ "Generic fix found!": "Correctif générique trouvé !",
+ "Go to Base Game": "Aller au jeu de base",
+ "Hide": "Masquer",
+ "Included": "Inclus 🎉",
+ "Installing…": "Installation…",
+ "Join the Discord!": "Rejoignez le Discord !",
+ "Left click to install, Right click for SteamDB": "Clic gauche pour installer. Clic droit pour SteamDB.",
+ "Loaded free APIs: {count}": "API gratuites chargées : {count}",
+ "Loading fixes...": "Chargement des correctifs...",
+ "Look for Fixes": "Rechercher des correctifs",
+ "LuaTools backend unavailable": "Backend LuaTools indisponible.",
+ "LuaTools · AIO Fixes Menu": "LuaTools · Menu des correctifs tout-en-un",
+ "LuaTools · Added Games": "LuaTools · Jeux ajoutés",
+ "LuaTools · Fixes Menu": "LuaTools · Menu des correctifs",
+ "LuaTools · Menu": "LuaTools · Menu",
+ "LuaTools · {api}": "LuaTools · {api}",
+ "Manage Game": "Gérer le jeu",
+ "Missing": "Manquant ❌",
+ "No games found.": "Aucun jeux trouvé.",
+ "No generic fix": "Aucun correctif générique",
+ "No online-fix": "Aucun correctif Online-Fix",
+ "No updates available.": "Aucune mise à jour disponible.",
+ "Not found": "Introuvable",
+ "No workshop for the game": "Pas de workshop pour le jeu ✅",
+ "Online Fix": "Correctif en ligne (Online-Fix)",
+ "Online Fix (Unsteam)": "Correctif en ligne (Unsteam)",
+ "Online-fix found!": "Online-Fix trouvé !",
+ "Only possible thanks to {name} 💜": "Possible uniquement grâce à {name} 💜",
+ "Processing package…": "Traitement du paquet…",
+ "Remove via LuaTools": "Retirer via LuaTools",
+ "Removed {count} files. Running Steam verification...": "{count} fichiers supprimés. Exécution de la vérification Steam...",
+ "Removing fix files...": "Suppression des fichiers de correctif...",
+ "Restart Steam": "Redémarrer Steam",
+ "Restart Steam now?": "Redémarrer Steam maintenant ?",
+ "Settings": "Paramètres",
+ "Skipped": "Ignoré",
+ "Un-Fix (verify game)": "Supprimer le correctif (vérifier le jeu)",
+ "Un-Fixing game": "Suppression du correctif du jeu.",
+ "Unknown Game": "Jeu Inconnu",
+ "Unknown error": "Erreur inconnue",
+ "Waiting…": "En attente…",
+ "Working…": "Travail en cours…",
+ "Workshop: ": "Workshop:",
+ "bigpicture.mouseTip": "Pour utiliser le mode souris dans Steam : Bouton Guide + Joystick droit, clic avec RB",
+ "common.alert.ok": "OK",
+ "common.appName": "LuaTools",
+ "common.error.unsupportedOption": "Type d'option non pris en charge : {type}",
+ "common.status.error": "Erreur",
+ "common.status.loading": "Chargement...",
+ "common.status.success": "Succès",
+ "common.translationMissing": "Traduction manquante",
+ "common.warning": "Avertissement",
+ "disclaimer.inputLabel": "tapez \"Je Comprends\" dans la case ci-dessous pour continuer",
+ "disclaimer.inputPlaceholder": "Je Comprends",
+ "disclaimer.line1": "LuaTools n'est affilié d'aucune façon à Millennium",
+ "disclaimer.line2": "Millennium ne vous offrira PAS de support pour ce plugin sur leur serveur discord",
+ "disclaimer.line3": "Vous serez BANNI des serveurs LuaTools et Millennium si vous allez sur leur discord demander de l'aide",
+ "disclaimer.title": "Avis Important",
+ "gameStatus.denuvo": "Denuvo",
+ "gameStatus.needsFixes": "Correctif disponible",
+ "gameStatus.playable": "Jouable",
+ "gameStatus.unplayable": "Injouable",
+ "menu.advancedLabel": "Avancé",
+ "menu.checkForUpdates": "Vérifier les mises à jour",
+ "menu.discord": "Discord",
+ "menu.error.getPath": "Erreur lors de la récupération du chemin du jeu.",
+ "menu.error.noAppId": "Impossible de déterminer l'AppID du jeu.",
+ "menu.error.noInstall": "Impossible de trouver l'installation du jeu.",
+ "menu.error.notInstalled": "Jeu non installé ! Ajoutez-le et installez-le d'abord :D",
+ "menu.fetchFreeApis": "Récupérer les API Gratuites",
+ "menu.fixesMenu": "Menu des correctifs",
+ "menu.joinDiscordLabel": "Rejoignez le Discord !",
+ "menu.manageGameLabel": "Gérer le Jeu",
+ "menu.remove.confirm": "Retirer LuaTools pour ce jeu ?",
+ "menu.remove.failure": "Échec du retrait de LuaTools.",
+ "menu.remove.success": "LuaTools retiré pour cette application.",
+ "menu.removeLuaTools": "Retirer via LuaTools",
+ "menu.settings": "Paramètres",
+ "menu.title": "LuaTools · Menu",
+ "settings.close": "Fermer",
+ "settings.donateKeys.description": "Faire don des clés de décryptage pour les jeux, aide tout le monde !",
+ "settings.donateKeys.label": "Faire don de clés",
+ "settings.donateKeys.no": "Non",
+ "settings.donateKeys.yes": "Oui",
+ "settings.empty": "Aucun paramètre disponible pour le moment.",
+ "settings.error": "Échec du chargement des paramètres.",
+ "settings.general": "Général",
+ "settings.generalDescription": "Préférences globales de LuaTools.",
+ "settings.installedFixes.date": "Installé :",
+ "settings.installedFixes.delete": "Supprimer",
+ "settings.installedFixes.deleteConfirm": "Êtes-vous sûr de vouloir supprimer ce correctif ? Cela supprimera les fichiers du correctif et exécutera la vérification Steam.",
+ "settings.installedFixes.deleteError": "Échec de la suppression du correctif.",
+ "settings.installedFixes.deleteSuccess": "Correctif supprimé avec succès !",
+ "settings.installedFixes.deleting": "Suppression du correctif...",
+ "settings.installedFixes.empty": "Aucun correctif installé pour le moment.",
+ "settings.installedFixes.error": "Échec du chargement des correctifs installés.",
+ "settings.installedFixes.files": "{count} fichiers",
+ "settings.installedFixes.loading": "Recherche de correctifs installés...",
+ "settings.installedFixes.title": "Correctifs Installés",
+ "settings.installedFixes.type": "Type :",
+ "settings.installedLua.delete": "Supprimer",
+ "settings.installedLua.deleteConfirm": "Supprimer via LuaTools pour ce jeu ?",
+ "settings.installedLua.deleteError": "Échec de la suppression via LuaTools.",
+ "settings.installedLua.deleteSuccess": "Supprimé via LuaTools avec succès !",
+ "settings.installedLua.deleting": "Suppression via LuaTools...",
+ "settings.installedLua.disabled": "Désactivé",
+ "settings.installedLua.empty": "Aucun script Lua installé pour le moment.",
+ "settings.installedLua.error": "Échec du chargement des scripts Lua installés.",
+ "settings.installedLua.loading": "Recherche de scripts Lua installés...",
+ "settings.installedLua.modified": "Modifié :",
+ "settings.installedLua.title": "Jeux via LuaTools",
+ "settings.installedLua.unknownInfo": "Les jeux affichant 'Jeu inconnu' ont été installés depuis des sources externes (pas via LuaTools).",
+ "settings.language.description": "Choisissez la langue utilisée par LuaTools.",
+ "settings.language.label": "Langue",
+ "settings.language.option.en": "Anglais",
+ "settings.language.option.pt-BR": "Portugais Brésilien",
+ "settings.loading": "Chargement des paramètres...",
+ "settings.noChanges": "Aucune modification à enregistrer.",
+ "settings.refresh": "Actualiser",
+ "settings.refreshing": "Actualisation...",
+ "settings.save": "Enregistrer les paramètres",
+ "settings.saveError": "Échec de l'enregistrement des paramètres.",
+ "settings.saveSuccess": "Paramètres enregistrés avec succès.",
+ "settings.saving": "Enregistrement...",
+ "settings.search.clear": "Effacer la recherche",
+ "settings.search.noResults": "Aucun résultat trouvé",
+ "settings.search.placeholder": "Rechercher paramètres, jeux, correctifs...",
+ "settings.theme.description": "Choisissez le thème de couleur pour l'interface LuaTools.",
+ "settings.theme.label": "Thème",
+ "settings.title": "LuaTools · Paramètres",
+ "settings.unsaved": "Modifications non enregistrées",
+ "settings.useSteamLanguage.description": "Utiliser la langue du client Steam au lieu de celle de LuaTools.",
+ "settings.useSteamLanguage.label": "Utiliser la langue de Steam",
+ "settings.useSteamLanguage.no": "Non",
+ "settings.useSteamLanguage.yes": "Oui",
+ "{fix} applied successfully!": "{fix} appliqué avec succès !"
+ }
+}
\ No newline at end of file
diff --git a/backend/main.py b/backend/main.py
index 0ec693f..2460d82 100644
--- a/backend/main.py
+++ b/backend/main.py
@@ -1,481 +1,481 @@
-import json
-import os
-import shutil
-import sys
-import webbrowser
-
-from typing import Any
-
-import Millennium # type: ignore
-import PluginUtils # type: ignore
-
-from api_manifest import (
- fetch_free_apis_now as api_fetch_free_apis_now,
- get_api_list as api_get_api_list,
- get_init_apis_message as api_get_init_message,
- init_apis as api_init_apis,
- store_last_message,
-)
-from auto_update import (
- apply_pending_update_if_any,
- check_for_updates_now as auto_check_for_updates_now,
- restart_steam as auto_restart_steam,
- start_auto_update_background_check,
-)
-from config import WEBKIT_DIR_NAME, WEB_UI_ICON_FILE, WEB_UI_JS_FILE
-from downloads import (
- cancel_add_via_luatools,
- delete_luatools_for_app,
- dismiss_loaded_apps,
- get_add_status,
- get_icon_data_url,
- get_installed_lua_scripts,
- has_luatools_for_app,
- get_games_database,
- init_applist,
- read_loaded_apps,
- start_add_via_luatools,
-)
-from fixes import (
- apply_game_fix,
- cancel_apply_fix,
- check_for_fixes,
- get_apply_fix_status,
- get_installed_fixes,
- get_unfix_status,
- unfix_game,
-)
-from utils import ensure_temp_download_dir
-from http_client import close_http_client, ensure_http_client
-from logger import logger as shared_logger
-from paths import get_plugin_dir, public_path
-from settings.manager import (
- apply_settings_changes,
- get_available_locales,
- get_settings_payload,
- get_translation_map,
- init_settings,
-)
-from steam_utils import detect_steam_install_path, get_game_install_path_response, open_game_folder
-
-logger = shared_logger
-
-
-def GetPluginDir() -> str: # Legacy API used by the frontend
- return get_plugin_dir()
-
-
-class Logger:
- @staticmethod
- def log(message: str) -> str:
- shared_logger.log(f"[Frontend] {message}")
- return json.dumps({"success": True})
-
- @staticmethod
- def warn(message: str) -> str:
- shared_logger.warn(f"[Frontend] {message}")
- return json.dumps({"success": True})
-
- @staticmethod
- def error(message: str) -> str:
- shared_logger.error(f"[Frontend] {message}")
- return json.dumps({"success": True})
-
-
-def _steam_ui_path() -> str:
- return os.path.join(Millennium.steam_path(), "steamui", WEBKIT_DIR_NAME)
-
-
-def _copy_webkit_files() -> None:
- plugin_dir = get_plugin_dir()
- steam_ui_path = _steam_ui_path()
- os.makedirs(steam_ui_path, exist_ok=True)
-
- js_src = public_path(WEB_UI_JS_FILE)
- js_dst = os.path.join(steam_ui_path, WEB_UI_JS_FILE)
- logger.log(f"Copying LuaTools web UI from {js_src} to {js_dst}")
- try:
- shutil.copy(js_src, js_dst)
- except Exception as exc:
- logger.error(f"Failed to copy LuaTools web UI: {exc}")
-
- icon_src = public_path(WEB_UI_ICON_FILE)
- icon_dst = os.path.join(steam_ui_path, WEB_UI_ICON_FILE)
- if os.path.exists(icon_src):
- try:
- shutil.copy(icon_src, icon_dst)
- logger.log(f"Copied LuaTools icon to {icon_dst}")
- except Exception as exc:
- logger.error(f"Failed to copy LuaTools icon: {exc}")
- else:
- logger.warn(f"LuaTools icon not found at {icon_src}")
-
- # Copy theme CSS files
- themes_src = os.path.join(plugin_dir, "public", "themes")
- themes_dst = os.path.join(steam_ui_path, "themes")
- if os.path.exists(themes_src):
- try:
- os.makedirs(themes_dst, exist_ok=True)
- for filename in os.listdir(themes_src):
- if filename.endswith(".css"):
- theme_src = os.path.join(themes_src, filename)
- theme_dst = os.path.join(themes_dst, filename)
- shutil.copy(theme_src, theme_dst)
- logger.log(f"Copied theme file {filename} to {theme_dst}")
- except Exception as exc:
- logger.warn(f"Failed to copy theme files: {exc}")
-
-
-def _inject_webkit_files() -> None:
- js_path = os.path.join(WEBKIT_DIR_NAME, WEB_UI_JS_FILE)
- Millennium.add_browser_js(js_path)
- logger.log(f"LuaTools injected web UI: {js_path}")
-
-
-def InitApis(contentScriptQuery: str = "") -> str:
- return api_init_apis(contentScriptQuery)
-
-
-def GetInitApisMessage(contentScriptQuery: str = "") -> str:
- return api_get_init_message(contentScriptQuery)
-
-
-def FetchFreeApisNow(contentScriptQuery: str = "") -> str:
- return api_fetch_free_apis_now(contentScriptQuery)
-
-
-def CheckForUpdatesNow(contentScriptQuery: str = "") -> str:
- result = auto_check_for_updates_now()
- return json.dumps(result)
-
-
-def RestartSteam(contentScriptQuery: str = "") -> str:
- success = auto_restart_steam()
- if success:
- return json.dumps({"success": True})
- return json.dumps({"success": False, "error": "Failed to restart Steam"})
-
-
-def HasLuaToolsForApp(appid: int, contentScriptQuery: str = "") -> str:
- return has_luatools_for_app(appid)
-
-
-def StartAddViaLuaTools(appid: int, contentScriptQuery: str = "") -> str:
- return start_add_via_luatools(appid)
-
-
-def GetAddViaLuaToolsStatus(appid: int, contentScriptQuery: str = "") -> str:
- return get_add_status(appid)
-
-
-def GetApiList(contentScriptQuery: str = "") -> str:
- return api_get_api_list(contentScriptQuery)
-
-
-def CancelAddViaLuaTools(appid: int, contentScriptQuery: str = "") -> str:
- return cancel_add_via_luatools(appid)
-
-
-def GetIconDataUrl(contentScriptQuery: str = "") -> str:
- return get_icon_data_url()
-
-
-def GetGamesDatabase(contentScriptQuery: str = "") -> str:
- return get_games_database()
-
-
-def ReadLoadedApps(contentScriptQuery: str = "") -> str:
- return read_loaded_apps()
-
-
-def DismissLoadedApps(contentScriptQuery: str = "") -> str:
- return dismiss_loaded_apps()
-
-
-def DeleteLuaToolsForApp(appid: int, contentScriptQuery: str = "") -> str:
- return delete_luatools_for_app(appid)
-
-
-def CheckForFixes(appid: int, contentScriptQuery: str = "") -> str:
- return check_for_fixes(appid)
-
-
-def ApplyGameFix(appid: int, downloadUrl: str, installPath: str, fixType: str = "", gameName: str = "", contentScriptQuery: str = "") -> str:
- return apply_game_fix(appid, downloadUrl, installPath, fixType, gameName)
-
-
-def GetApplyFixStatus(appid: int, contentScriptQuery: str = "") -> str:
- return get_apply_fix_status(appid)
-
-
-def CancelApplyFix(appid: int, contentScriptQuery: str = "") -> str:
- return cancel_apply_fix(appid)
-
-
-def UnFixGame(appid: int, installPath: str = "", fixDate: str = "", contentScriptQuery: str = "") -> str:
- return unfix_game(appid, installPath, fixDate)
-
-
-def GetUnfixStatus(appid: int, contentScriptQuery: str = "") -> str:
- return get_unfix_status(appid)
-
-
-def GetInstalledFixes(contentScriptQuery: str = "") -> str:
- return get_installed_fixes()
-
-
-def GetInstalledLuaScripts(contentScriptQuery: str = "") -> str:
- return get_installed_lua_scripts()
-
-
-def GetGameInstallPath(appid: int, contentScriptQuery: str = "") -> str:
- result = get_game_install_path_response(appid)
- return json.dumps(result)
-
-
-def OpenGameFolder(path: str, contentScriptQuery: str = "") -> str:
- success = open_game_folder(path)
- if success:
- return json.dumps({"success": True})
- return json.dumps({"success": False, "error": "Failed to open path"})
-
-
-def OpenExternalUrl(url: str, contentScriptQuery: str = "") -> str:
- try:
- value = str(url or "").strip()
- if not (value.startswith("http://") or value.startswith("https://")):
- return json.dumps({"success": False, "error": "Invalid URL"})
- if sys.platform.startswith("win"):
- try:
- os.startfile(value) # type: ignore[attr-defined]
- except Exception:
- webbrowser.open(value)
- else:
- webbrowser.open(value)
- return json.dumps({"success": True})
- except Exception as exc:
- logger.warn(f"LuaTools: OpenExternalUrl failed: {exc}")
- return json.dumps({"success": False, "error": str(exc)})
-
-
-def GetSettingsConfig(contentScriptQuery: str = "") -> str:
- try:
- payload = get_settings_payload()
- response = {
- "success": True,
- "schemaVersion": payload.get("version"),
- "schema": payload.get("schema", []),
- "values": payload.get("values", {}),
- "language": payload.get("language"),
- "locales": payload.get("locales", []),
- "translations": payload.get("translations", {}),
- }
- return json.dumps(response)
- except Exception as exc:
- logger.warn(f"LuaTools: GetSettingsConfig failed: {exc}")
- return json.dumps({"success": False, "error": str(exc)})
-
-
-def GetThemes(contentScriptQuery: str = "") -> str:
- """Return the full themes palette list for the frontend."""
- try:
- themes_path = os.path.join(get_plugin_dir(), 'public', 'themes', 'themes.json')
- if os.path.exists(themes_path):
- try:
- with open(themes_path, 'r', encoding='utf-8') as fh:
- data = json.load(fh)
- return json.dumps({"success": True, "themes": data})
- except Exception as exc:
- logger.warn(f"LuaTools: Failed to read themes.json: {exc}")
- return json.dumps({"success": False, "error": "Failed to read themes.json"})
- else:
- return json.dumps({"success": True, "themes": []})
- except Exception as exc:
- logger.warn(f"LuaTools: GetThemes failed: {exc}")
- return json.dumps({"success": False, "error": str(exc)})
-
-
-def ApplySettingsChanges(
- _contentScriptQuery: str = "", changes: Any = None, **kwargs: Any
-) -> str:
- try:
- if "changes" in kwargs and changes is None:
- changes = kwargs["changes"]
- if changes is None:
- changes = kwargs
-
- try:
- logger.log(
- "LuaTools: ApplySettingsChanges raw argument "
- f"type={type(changes)} value={changes!r}"
- )
- logger.log(f"LuaTools: ApplySettingsChanges kwargs: {kwargs}")
- except Exception:
- pass
-
- payload: Any = None
-
- if isinstance(changes, str) and changes:
- try:
- payload = json.loads(changes)
- except Exception:
- logger.warn("LuaTools: Failed to parse changes string payload")
- return json.dumps({"success": False, "error": "Invalid JSON payload"})
- else:
- # When a full payload dict was sent as JSON, unwrap keys we expect.
- if isinstance(payload, dict) and "changes" in payload:
- payload = payload.get("changes")
- elif isinstance(payload, dict) and "changesJson" in payload and isinstance(payload["changesJson"], str):
- try:
- payload = json.loads(payload["changesJson"])
- except Exception:
- logger.warn("LuaTools: Failed to parse changesJson string inside payload")
- return json.dumps({"success": False, "error": "Invalid JSON payload"})
- elif isinstance(changes, dict) and changes:
- # When the bridge passes a dict argument directly.
- if "changesJson" in changes and isinstance(changes["changesJson"], str):
- try:
- payload = json.loads(changes["changesJson"])
- except Exception:
- logger.warn("LuaTools: Failed to parse changesJson payload from dict")
- return json.dumps({"success": False, "error": "Invalid JSON payload"})
- elif "changes" in changes:
- payload = changes.get("changes")
- else:
- payload = changes
- else:
- # Look for JSON payload inside kwargs.
- changes_json = kwargs.get("changesJson")
- if isinstance(changes_json, dict):
- payload = changes_json
- elif isinstance(changes_json, str) and changes_json:
- try:
- payload = json.loads(changes_json)
- except Exception:
- logger.warn("LuaTools: Failed to parse changesJson payload")
- return json.dumps({"success": False, "error": "Invalid JSON payload"})
- else:
- payload = changes
-
- if payload is None:
- payload = {}
- elif not isinstance(payload, dict):
- logger.warn(f"LuaTools: Parsed payload is not a dict: {payload!r}")
- return json.dumps({"success": False, "error": "Invalid payload format"})
-
- try:
- logger.log(f"LuaTools: ApplySettingsChanges received payload: {payload}")
- except Exception:
- pass
-
- result = apply_settings_changes(payload)
- try:
- logger.log(f"LuaTools: ApplySettingsChanges result: {result}")
- except Exception:
- pass
- response = json.dumps(result)
- try:
- logger.log(f"LuaTools: ApplySettingsChanges response json: {response}")
- except Exception:
- pass
- return response
- except Exception as exc:
- logger.warn(f"LuaTools: ApplySettingsChanges failed: {exc}")
- return json.dumps({"success": False, "error": str(exc)})
-
-
-def GetAvailableLocales(contentScriptQuery: str = "") -> str:
- try:
- locales = get_available_locales()
- return json.dumps({"success": True, "locales": locales})
- except Exception as exc:
- logger.warn(f"LuaTools: GetAvailableLocales failed: {exc}")
- return json.dumps({"success": False, "error": str(exc)})
-
-
-def GetTranslations(contentScriptQuery: str = "", language: str = "", **kwargs: Any) -> str:
- try:
- if not language and "language" in kwargs:
- language = kwargs["language"]
- bundle = get_translation_map(language)
- bundle["success"] = True
- return json.dumps(bundle)
- except Exception as exc:
- logger.warn(f"LuaTools: GetTranslations failed: {exc}")
- return json.dumps({"success": False, "error": str(exc)})
-
-
-def GetAvailableThemes(contentScriptQuery: str = "") -> str:
- """Return list of available theme CSS files."""
- try:
- themes_dir = os.path.join(get_plugin_dir(), "public", "themes")
- themes = []
- if os.path.exists(themes_dir):
- for filename in os.listdir(themes_dir):
- if filename.endswith(".css"):
- theme_name = filename[:-4] # Remove .css extension
- # Capitalize first letter for display
- display_name = theme_name.capitalize()
- themes.append({"value": theme_name, "label": display_name})
- # Sort themes, but put 'original' first
- themes.sort(key=lambda x: (x["value"] != "original", x["label"]))
- return json.dumps({"success": True, "themes": themes})
- except Exception as exc:
- logger.warn(f"LuaTools: GetAvailableThemes failed: {exc}")
- return json.dumps({"success": False, "error": str(exc), "themes": []})
-
-
-class Plugin:
- def _front_end_loaded(self):
- _copy_webkit_files()
-
- def _load(self):
- logger.log(f"bootstrapping LuaTools plugin, millennium {Millennium.version()}")
-
- try:
- detect_steam_install_path()
- except Exception as exc:
- logger.warn(f"LuaTools: steam path detection failed: {exc}")
-
- ensure_http_client("InitApis")
- ensure_temp_download_dir()
-
- try:
- init_settings()
- except Exception as exc:
- logger.warn(f"LuaTools: settings initialization failed: {exc}")
-
- try:
- message = apply_pending_update_if_any()
- if message:
- store_last_message(message)
- except Exception as exc:
- logger.warn(f"AutoUpdate: apply pending failed: {exc}")
-
- try:
- init_applist()
- except Exception as exc:
- logger.warn(f"LuaTools: Applist initialization failed: {exc}")
-
- _copy_webkit_files()
- _inject_webkit_files()
-
- try:
- result = InitApis("boot")
- logger.log(f"InitApis (boot) return: {result}")
- except Exception as exc:
- logger.error(f"InitApis (boot) failed: {exc}")
-
- try:
- start_auto_update_background_check()
- except Exception as exc:
- logger.warn(f"AutoUpdate: start background check failed: {exc}")
-
- Millennium.ready()
-
- def _unload(self):
- logger.log("unloading")
- close_http_client("InitApis")
-
-
-plugin = Plugin()
+import json
+import os
+import shutil
+import sys
+import webbrowser
+
+from typing import Any
+
+import Millennium # type: ignore
+import PluginUtils # type: ignore
+
+from api_manifest import (
+ fetch_free_apis_now as api_fetch_free_apis_now,
+ get_api_list as api_get_api_list,
+ get_init_apis_message as api_get_init_message,
+ init_apis as api_init_apis,
+ store_last_message,
+)
+from auto_update import (
+ apply_pending_update_if_any,
+ check_for_updates_now as auto_check_for_updates_now,
+ restart_steam as auto_restart_steam,
+ start_auto_update_background_check,
+)
+from config import WEBKIT_DIR_NAME, WEB_UI_ICON_FILE, WEB_UI_JS_FILE
+from downloads import (
+ cancel_add_via_luatools,
+ delete_luatools_for_app,
+ dismiss_loaded_apps,
+ get_add_status,
+ get_icon_data_url,
+ get_installed_lua_scripts,
+ has_luatools_for_app,
+ get_games_database,
+ init_applist,
+ read_loaded_apps,
+ start_add_via_luatools,
+)
+from fixes import (
+ apply_game_fix,
+ cancel_apply_fix,
+ check_for_fixes,
+ get_apply_fix_status,
+ get_installed_fixes,
+ get_unfix_status,
+ unfix_game,
+)
+from utils import ensure_temp_download_dir
+from http_client import close_http_client, ensure_http_client
+from logger import logger as shared_logger
+from paths import get_plugin_dir, public_path
+from settings.manager import (
+ apply_settings_changes,
+ get_available_locales,
+ get_settings_payload,
+ get_translation_map,
+ init_settings,
+)
+from steam_utils import detect_steam_install_path, get_game_install_path_response, open_game_folder
+
+logger = shared_logger
+
+
+def GetPluginDir() -> str: # Legacy API used by the frontend
+ return get_plugin_dir()
+
+
+class Logger:
+ @staticmethod
+ def log(message: str) -> str:
+ shared_logger.log(f"[Frontend] {message}")
+ return json.dumps({"success": True})
+
+ @staticmethod
+ def warn(message: str) -> str:
+ shared_logger.warn(f"[Frontend] {message}")
+ return json.dumps({"success": True})
+
+ @staticmethod
+ def error(message: str) -> str:
+ shared_logger.error(f"[Frontend] {message}")
+ return json.dumps({"success": True})
+
+
+def _steam_ui_path() -> str:
+ return os.path.join(Millennium.steam_path(), "steamui", WEBKIT_DIR_NAME)
+
+
+def _copy_webkit_files() -> None:
+ plugin_dir = get_plugin_dir()
+ steam_ui_path = _steam_ui_path()
+ os.makedirs(steam_ui_path, exist_ok=True)
+
+ js_src = public_path(WEB_UI_JS_FILE)
+ js_dst = os.path.join(steam_ui_path, WEB_UI_JS_FILE)
+ logger.log(f"Copying LuaTools web UI from {js_src} to {js_dst}")
+ try:
+ shutil.copy(js_src, js_dst)
+ except Exception as exc:
+ logger.error(f"Failed to copy LuaTools web UI: {exc}")
+
+ icon_src = public_path(WEB_UI_ICON_FILE)
+ icon_dst = os.path.join(steam_ui_path, WEB_UI_ICON_FILE)
+ if os.path.exists(icon_src):
+ try:
+ shutil.copy(icon_src, icon_dst)
+ logger.log(f"Copied LuaTools icon to {icon_dst}")
+ except Exception as exc:
+ logger.error(f"Failed to copy LuaTools icon: {exc}")
+ else:
+ logger.warn(f"LuaTools icon not found at {icon_src}")
+
+ # Copy theme CSS files
+ themes_src = os.path.join(plugin_dir, "public", "themes")
+ themes_dst = os.path.join(steam_ui_path, "themes")
+ if os.path.exists(themes_src):
+ try:
+ os.makedirs(themes_dst, exist_ok=True)
+ for filename in os.listdir(themes_src):
+ if filename.endswith(".css"):
+ theme_src = os.path.join(themes_src, filename)
+ theme_dst = os.path.join(themes_dst, filename)
+ shutil.copy(theme_src, theme_dst)
+ logger.log(f"Copied theme file {filename} to {theme_dst}")
+ except Exception as exc:
+ logger.warn(f"Failed to copy theme files: {exc}")
+
+
+def _inject_webkit_files() -> None:
+ js_path = os.path.join(WEBKIT_DIR_NAME, WEB_UI_JS_FILE)
+ Millennium.add_browser_js(js_path)
+ logger.log(f"LuaTools injected web UI: {js_path}")
+
+
+def InitApis(contentScriptQuery: str = "") -> str:
+ return api_init_apis(contentScriptQuery)
+
+
+def GetInitApisMessage(contentScriptQuery: str = "") -> str:
+ return api_get_init_message(contentScriptQuery)
+
+
+def FetchFreeApisNow(contentScriptQuery: str = "") -> str:
+ return api_fetch_free_apis_now(contentScriptQuery)
+
+
+def CheckForUpdatesNow(contentScriptQuery: str = "") -> str:
+ result = auto_check_for_updates_now()
+ return json.dumps(result)
+
+
+def RestartSteam(contentScriptQuery: str = "") -> str:
+ success = auto_restart_steam()
+ if success:
+ return json.dumps({"success": True})
+ return json.dumps({"success": False, "error": "Failed to restart Steam"})
+
+
+def HasLuaToolsForApp(appid: int, contentScriptQuery: str = "") -> str:
+ return has_luatools_for_app(appid)
+
+
+def StartAddViaLuaTools(appid: int, contentScriptQuery: str = "") -> str:
+ return start_add_via_luatools(appid)
+
+
+def GetAddViaLuaToolsStatus(appid: int, contentScriptQuery: str = "") -> str:
+ return get_add_status(appid)
+
+
+def GetApiList(contentScriptQuery: str = "") -> str:
+ return api_get_api_list(contentScriptQuery)
+
+
+def CancelAddViaLuaTools(appid: int, contentScriptQuery: str = "") -> str:
+ return cancel_add_via_luatools(appid)
+
+
+def GetIconDataUrl(contentScriptQuery: str = "") -> str:
+ return get_icon_data_url()
+
+
+def GetGamesDatabase(contentScriptQuery: str = "") -> str:
+ return get_games_database()
+
+
+def ReadLoadedApps(contentScriptQuery: str = "") -> str:
+ return read_loaded_apps()
+
+
+def DismissLoadedApps(contentScriptQuery: str = "") -> str:
+ return dismiss_loaded_apps()
+
+
+def DeleteLuaToolsForApp(appid: int, contentScriptQuery: str = "") -> str:
+ return delete_luatools_for_app(appid)
+
+
+def CheckForFixes(appid: int, contentScriptQuery: str = "") -> str:
+ return check_for_fixes(appid)
+
+
+def ApplyGameFix(appid: int, downloadUrl: str, installPath: str, fixType: str = "", gameName: str = "", contentScriptQuery: str = "") -> str:
+ return apply_game_fix(appid, downloadUrl, installPath, fixType, gameName)
+
+
+def GetApplyFixStatus(appid: int, contentScriptQuery: str = "") -> str:
+ return get_apply_fix_status(appid)
+
+
+def CancelApplyFix(appid: int, contentScriptQuery: str = "") -> str:
+ return cancel_apply_fix(appid)
+
+
+def UnFixGame(appid: int, installPath: str = "", fixDate: str = "", contentScriptQuery: str = "") -> str:
+ return unfix_game(appid, installPath, fixDate)
+
+
+def GetUnfixStatus(appid: int, contentScriptQuery: str = "") -> str:
+ return get_unfix_status(appid)
+
+
+def GetInstalledFixes(contentScriptQuery: str = "") -> str:
+ return get_installed_fixes()
+
+
+def GetInstalledLuaScripts(contentScriptQuery: str = "") -> str:
+ return get_installed_lua_scripts()
+
+
+def GetGameInstallPath(appid: int, contentScriptQuery: str = "") -> str:
+ result = get_game_install_path_response(appid)
+ return json.dumps(result)
+
+
+def OpenGameFolder(path: str, contentScriptQuery: str = "") -> str:
+ success = open_game_folder(path)
+ if success:
+ return json.dumps({"success": True})
+ return json.dumps({"success": False, "error": "Failed to open path"})
+
+
+def OpenExternalUrl(url: str, contentScriptQuery: str = "") -> str:
+ try:
+ value = str(url or "").strip()
+ if not (value.startswith("http://") or value.startswith("https://")):
+ return json.dumps({"success": False, "error": "Invalid URL"})
+ if sys.platform.startswith("win"):
+ try:
+ os.startfile(value) # type: ignore[attr-defined]
+ except Exception:
+ webbrowser.open(value)
+ else:
+ webbrowser.open(value)
+ return json.dumps({"success": True})
+ except Exception as exc:
+ logger.warn(f"LuaTools: OpenExternalUrl failed: {exc}")
+ return json.dumps({"success": False, "error": str(exc)})
+
+
+def GetSettingsConfig(contentScriptQuery: str = "") -> str:
+ try:
+ payload = get_settings_payload()
+ response = {
+ "success": True,
+ "schemaVersion": payload.get("version"),
+ "schema": payload.get("schema", []),
+ "values": payload.get("values", {}),
+ "language": payload.get("language"),
+ "locales": payload.get("locales", []),
+ "translations": payload.get("translations", {}),
+ }
+ return json.dumps(response)
+ except Exception as exc:
+ logger.warn(f"LuaTools: GetSettingsConfig failed: {exc}")
+ return json.dumps({"success": False, "error": str(exc)})
+
+
+def GetThemes(contentScriptQuery: str = "") -> str:
+ """Return the full themes palette list for the frontend."""
+ try:
+ themes_path = os.path.join(get_plugin_dir(), 'public', 'themes', 'themes.json')
+ if os.path.exists(themes_path):
+ try:
+ with open(themes_path, 'r', encoding='utf-8') as fh:
+ data = json.load(fh)
+ return json.dumps({"success": True, "themes": data})
+ except Exception as exc:
+ logger.warn(f"LuaTools: Failed to read themes.json: {exc}")
+ return json.dumps({"success": False, "error": "Failed to read themes.json"})
+ else:
+ return json.dumps({"success": True, "themes": []})
+ except Exception as exc:
+ logger.warn(f"LuaTools: GetThemes failed: {exc}")
+ return json.dumps({"success": False, "error": str(exc)})
+
+
+def ApplySettingsChanges(
+ _contentScriptQuery: str = "", changes: Any = None, **kwargs: Any
+) -> str:
+ try:
+ if "changes" in kwargs and changes is None:
+ changes = kwargs["changes"]
+ if changes is None:
+ changes = kwargs
+
+ try:
+ logger.log(
+ "LuaTools: ApplySettingsChanges raw argument "
+ f"type={type(changes)} value={changes!r}"
+ )
+ logger.log(f"LuaTools: ApplySettingsChanges kwargs: {kwargs}")
+ except Exception:
+ pass
+
+ payload: Any = None
+
+ if isinstance(changes, str) and changes:
+ try:
+ payload = json.loads(changes)
+ except Exception:
+ logger.warn("LuaTools: Failed to parse changes string payload")
+ return json.dumps({"success": False, "error": "Invalid JSON payload"})
+ else:
+ # When a full payload dict was sent as JSON, unwrap keys we expect.
+ if isinstance(payload, dict) and "changes" in payload:
+ payload = payload.get("changes")
+ elif isinstance(payload, dict) and "changesJson" in payload and isinstance(payload["changesJson"], str):
+ try:
+ payload = json.loads(payload["changesJson"])
+ except Exception:
+ logger.warn("LuaTools: Failed to parse changesJson string inside payload")
+ return json.dumps({"success": False, "error": "Invalid JSON payload"})
+ elif isinstance(changes, dict) and changes:
+ # When the bridge passes a dict argument directly.
+ if "changesJson" in changes and isinstance(changes["changesJson"], str):
+ try:
+ payload = json.loads(changes["changesJson"])
+ except Exception:
+ logger.warn("LuaTools: Failed to parse changesJson payload from dict")
+ return json.dumps({"success": False, "error": "Invalid JSON payload"})
+ elif "changes" in changes:
+ payload = changes.get("changes")
+ else:
+ payload = changes
+ else:
+ # Look for JSON payload inside kwargs.
+ changes_json = kwargs.get("changesJson")
+ if isinstance(changes_json, dict):
+ payload = changes_json
+ elif isinstance(changes_json, str) and changes_json:
+ try:
+ payload = json.loads(changes_json)
+ except Exception:
+ logger.warn("LuaTools: Failed to parse changesJson payload")
+ return json.dumps({"success": False, "error": "Invalid JSON payload"})
+ else:
+ payload = changes
+
+ if payload is None:
+ payload = {}
+ elif not isinstance(payload, dict):
+ logger.warn(f"LuaTools: Parsed payload is not a dict: {payload!r}")
+ return json.dumps({"success": False, "error": "Invalid payload format"})
+
+ try:
+ logger.log(f"LuaTools: ApplySettingsChanges received payload: {payload}")
+ except Exception:
+ pass
+
+ result = apply_settings_changes(payload)
+ try:
+ logger.log(f"LuaTools: ApplySettingsChanges result: {result}")
+ except Exception:
+ pass
+ response = json.dumps(result)
+ try:
+ logger.log(f"LuaTools: ApplySettingsChanges response json: {response}")
+ except Exception:
+ pass
+ return response
+ except Exception as exc:
+ logger.warn(f"LuaTools: ApplySettingsChanges failed: {exc}")
+ return json.dumps({"success": False, "error": str(exc)})
+
+
+def GetAvailableLocales(contentScriptQuery: str = "") -> str:
+ try:
+ locales = get_available_locales()
+ return json.dumps({"success": True, "locales": locales})
+ except Exception as exc:
+ logger.warn(f"LuaTools: GetAvailableLocales failed: {exc}")
+ return json.dumps({"success": False, "error": str(exc)})
+
+
+def GetTranslations(contentScriptQuery: str = "", language: str = "", **kwargs: Any) -> str:
+ try:
+ if not language and "language" in kwargs:
+ language = kwargs["language"]
+ bundle = get_translation_map(language)
+ bundle["success"] = True
+ return json.dumps(bundle)
+ except Exception as exc:
+ logger.warn(f"LuaTools: GetTranslations failed: {exc}")
+ return json.dumps({"success": False, "error": str(exc)})
+
+
+def GetAvailableThemes(contentScriptQuery: str = "") -> str:
+ """Return list of available theme CSS files."""
+ try:
+ themes_dir = os.path.join(get_plugin_dir(), "public", "themes")
+ themes = []
+ if os.path.exists(themes_dir):
+ for filename in os.listdir(themes_dir):
+ if filename.endswith(".css"):
+ theme_name = filename[:-4] # Remove .css extension
+ # Capitalize first letter for display
+ display_name = theme_name.capitalize()
+ themes.append({"value": theme_name, "label": display_name})
+ # Sort themes, but put 'original' first
+ themes.sort(key=lambda x: (x["value"] != "original", x["label"]))
+ return json.dumps({"success": True, "themes": themes})
+ except Exception as exc:
+ logger.warn(f"LuaTools: GetAvailableThemes failed: {exc}")
+ return json.dumps({"success": False, "error": str(exc), "themes": []})
+
+
+class Plugin:
+ def _front_end_loaded(self):
+ _copy_webkit_files()
+
+ def _load(self):
+ logger.log(f"bootstrapping LuaTools plugin, millennium {Millennium.version()}")
+
+ try:
+ detect_steam_install_path()
+ except Exception as exc:
+ logger.warn(f"LuaTools: steam path detection failed: {exc}")
+
+ ensure_http_client("InitApis")
+ ensure_temp_download_dir()
+
+ try:
+ init_settings()
+ except Exception as exc:
+ logger.warn(f"LuaTools: settings initialization failed: {exc}")
+
+ try:
+ message = apply_pending_update_if_any()
+ if message:
+ store_last_message(message)
+ except Exception as exc:
+ logger.warn(f"AutoUpdate: apply pending failed: {exc}")
+
+ try:
+ init_applist()
+ except Exception as exc:
+ logger.warn(f"LuaTools: Applist initialization failed: {exc}")
+
+ _copy_webkit_files()
+ _inject_webkit_files()
+
+ try:
+ result = InitApis("boot")
+ logger.log(f"InitApis (boot) return: {result}")
+ except Exception as exc:
+ logger.error(f"InitApis (boot) failed: {exc}")
+
+ try:
+ start_auto_update_background_check()
+ except Exception as exc:
+ logger.warn(f"AutoUpdate: start background check failed: {exc}")
+
+ Millennium.ready()
+
+ def _unload(self):
+ logger.log("unloading")
+ close_http_client("InitApis")
+
+
+plugin = Plugin()
diff --git a/public/luatools.js b/public/luatools.js
index 1ab029d..c00d791 100644
--- a/public/luatools.js
+++ b/public/luatools.js
@@ -5252,42 +5252,33 @@
startPolling(appid);
};
- // First check if it's a DLC
- fetch('https://store.steampowered.com/api/appdetails?appids=' + appid + '&filters=basic')
- .then(function (res) {
- return res.json();
- })
- .then(function (data) {
- if (data && data[appid] && data[appid].success && data[appid].data) {
- const info = data[appid].data;
- if (info.type === 'dlc' && info.fullgame && info.fullgame.appid) {
- showDlcWarning(appid, info.fullgame.appid, info.fullgame.name);
- return;
- }
- }
+ // Check if this is a dlc
+ const isdlc = !!document.querySelector(".game_area_dlc_bubble");
+ const parentdiv = document.querySelector('.glance_details a[href*="/app/"]')
- // Not a DLC (or failed to check), proceed with database check
- return fetchGamesDatabase().then(function (db) {
- try {
- const key = String(appid);
- const gameData = db && db[key] ? db[key] : null;
- if (gameData && gameData.playable === 0) {
- // warning modal
- showLuaToolsPlayableWarning('This game may not work, support for it wont be given in our discord', function () {
- continueWithAdd();
- }, function () { });
- } else {
+ if (isdlc && parentdiv) {
+ const id = parseInt(parentdiv.href.match(/app\/(\d+)\//)?.[1] ?? "")
+ const name = parentdiv.innerText ?? "name not found";
+
+ showDlcWarning(appid, id, name);
+ } else {
+ // Not a dlc (or failed) ? Then continue normally
+ return fetchGamesDatabase().then(function (db) {
+ try {
+ const gameData = db?.[String(appid)] ?? null;
+ if (gameData?.playable === 0) {
+ // warning modal
+ showLuaToolsPlayableWarning('This game may not work, support for it wont be given in our discord', function () {
continueWithAdd();
- }
- } catch (_) {
+ }, function () { });
+ } else {
continueWithAdd();
}
- });
- })
- .catch(function (err) {
- backendLog('LuaTools: DLC check failed: ' + err);
- continueWithAdd();
+ } catch (_) {
+ continueWithAdd();
+ }
});
+ }
}
} catch (_) { }
}
@@ -5444,10 +5435,11 @@
if (st.status === 'downloading') status.textContent = lt('Downloading…');
if (st.status === 'processing') status.textContent = lt('Processing package…');
if (st.status === 'installing') status.textContent = lt('Installing…');
- if (st.status === 'done') status.textContent = lt('Finishing…');
+ if (st.status === 'checking content') status.textContent = lt('Checking content…');
+ // if (st.status === 'done') status.textContent = lt('Finishing…');
if (st.status === 'failed') status.textContent = lt('Failed');
}
- if (st.status === 'downloading' || st.status === 'processing' || st.status === 'installing') {
+ if (["downloading", "processing", "installing"].includes(st.status)) {
// reveal progress UI (if overlay visible)
if (wrap && wrap.style.display === 'none') wrap.style.display = 'block';
if (progressInfo && progressInfo.style.display === 'none') {
@@ -5484,17 +5476,13 @@
const cancelBtn = overlay ? overlay.querySelector('.luatools-cancel-btn') : null;
if (cancelBtn && st.status === 'downloading') cancelBtn.style.display = '';
}
- if (st.status === 'done') {
+
+ if (["checking content", "done"].includes(st.status)) {
// Update popup if visible
if (title) title.textContent = t('common.appName', 'LuaTools');
if (bar) bar.style.width = '100%';
if (percent) percent.textContent = '100%';
- if (status) status.textContent = lt('Game added!');
- // Hide Cancel button and update Hide to Close
- const cancelBtn = overlay ? overlay.querySelector('.luatools-cancel-btn') : null;
- if (cancelBtn) cancelBtn.style.display = 'none';
- const hideBtn = overlay ? overlay.querySelector('.luatools-hide-btn') : null;
- if (hideBtn) hideBtn.innerHTML = '' + lt('Close') + '';
+
// hide progress visuals after a short beat
if (wrap || progressInfo) {
setTimeout(function () {
@@ -5502,6 +5490,44 @@
if (progressInfo) progressInfo.style.display = 'none';
}, 300);
}
+
+ // Hide Cancel button
+ const cancelBtn = overlay ? overlay.querySelector('.luatools-cancel-btn') : null;
+ if (cancelBtn) cancelBtn.style.display = 'none';
+ }
+
+ if (st.status === 'done') {
+ // Update popup if visible
+ if (status) {
+ const result = st.contentCheckResult;
+
+ if (!result) return status.innerText = lt('Game added!');
+
+ // \u00A0 is a white space (unless it's automatically trimmed)
+ const status_content = [
+ lt("Game added!"),
+ lt("Content details =>"),
+ `\u00A0\u00A0• ${lt("Workshop: ")}${lt(result.workshop)}`,
+ ]
+
+ if (result.dlc.missing.length || result.dlc.included.length) {
+ status_content.push(`\u00A0\u00A0• ${lt("Dlc: ")}`)
+
+ if (result.dlc.included.length > 0) {
+ status_content.push(`\u00A0\u00A0\u00A0\u00A0◦ ${lt("Included")}: ${result.dlc.included.length}`)
+ }
+ if (result.dlc.missing.length > 0) {
+ status_content.push(`\u00A0\u00A0\u00A0\u00A0◦ ${lt("Missing")}: ${result.dlc.missing.length} (${result.dlc.missing.join(', ')})`)
+ }
+ }
+
+ status.style.whiteSpace = "pre-line";
+ status.innerText = status_content.join('\n');
+ }
+
+ // Update Hide button to Close
+ const hideBtn = overlay ? overlay.querySelector('.luatools-hide-btn') : null;
+ if (hideBtn) hideBtn.innerHTML = '' + lt('Close') + '';
done = true;
clearInterval(timer);
runState.inProgress = false;
@@ -5782,4 +5808,4 @@
// Note: The gamepad back handler is configured in the gamepad system at the top of this file
// It already handles all overlay types automatically using OVERLAY_SELECTOR_STRING
-})();
\ No newline at end of file
+})();