mirror of
https://github.com/SteamDeckHomebrew/decky-loader.git
synced 2026-06-13 04:05:04 +03:00
Merge branch 'main' into aa/fix-updater-reload
This commit is contained in:
@@ -23,6 +23,7 @@ csrf_token = str(uuid.uuid4())
|
||||
ssl_ctx = ssl.create_default_context(cafile=certifi.where())
|
||||
|
||||
assets_regex = re.compile("^/plugins/.*/assets/.*")
|
||||
data_regex = re.compile("^/plugins/.*/data/.*")
|
||||
dist_regex = re.compile("^/plugins/.*/dist/.*")
|
||||
frontend_regex = re.compile("^/frontend/.*")
|
||||
logger = getLogger("Main")
|
||||
@@ -45,6 +46,7 @@ async def csrf_middleware(request: Request, handler: Handler):
|
||||
str(request.rel_url.path) == "/fetch" or \
|
||||
str(request.rel_url.path) == "/ws" or \
|
||||
assets_regex.match(str(request.rel_url)) or \
|
||||
data_regex.match(str(request.rel_url)) or \
|
||||
dist_regex.match(str(request.rel_url)) or \
|
||||
frontend_regex.match(str(request.rel_url)):
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ from typing import Any, Tuple, Dict, cast
|
||||
|
||||
from aiohttp import web
|
||||
from os.path import exists
|
||||
from decky_loader.helpers import get_homebrew_path
|
||||
from watchdog.events import RegexMatchingEventHandler, FileSystemEvent
|
||||
from watchdog.observers import Observer
|
||||
|
||||
@@ -91,6 +92,7 @@ class Loader:
|
||||
web.get("/plugins/{plugin_name}/frontend_bundle", self.handle_frontend_bundle),
|
||||
web.get("/plugins/{plugin_name}/dist/{path:.*}", self.handle_plugin_dist),
|
||||
web.get("/plugins/{plugin_name}/assets/{path:.*}", self.handle_plugin_frontend_assets),
|
||||
web.get("/plugins/{plugin_name}/data/{path:.*}", self.handle_plugin_frontend_assets_from_data),
|
||||
])
|
||||
|
||||
server_instance.ws.add_route("loader/get_plugins", self.get_plugins)
|
||||
@@ -142,6 +144,13 @@ class Loader:
|
||||
|
||||
return web.FileResponse(file, headers={"Cache-Control": "no-cache"})
|
||||
|
||||
async def handle_plugin_frontend_assets_from_data(self, request: web.Request):
|
||||
plugin = self.plugins[request.match_info["plugin_name"]]
|
||||
home = get_homebrew_path()
|
||||
file = path.join(home, "data", plugin.plugin_directory, request.match_info["path"])
|
||||
|
||||
return web.FileResponse(file, headers={"Cache-Control": "no-cache"})
|
||||
|
||||
async def handle_frontend_bundle(self, request: web.Request):
|
||||
plugin = self.plugins[request.match_info["plugin_name"]]
|
||||
|
||||
@@ -216,4 +225,4 @@ class Loader:
|
||||
async def handle_plugin_backend_reload(self, plugin_name: str):
|
||||
plugin = self.plugins[plugin_name]
|
||||
|
||||
await self.reload_queue.put((plugin.file, plugin.plugin_directory))
|
||||
await self.reload_queue.put((plugin.file, plugin.plugin_directory))
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"BranchSelect": {
|
||||
"update_channel": {
|
||||
"label": "Canal de mise à jour",
|
||||
"prerelease": "Avant-première",
|
||||
"prerelease": "Préliminaire",
|
||||
"stable": "Stable",
|
||||
"testing": "Test"
|
||||
}
|
||||
@@ -52,21 +52,29 @@
|
||||
"MultiplePluginsInstallModal": {
|
||||
"confirm": "Êtes-vous sûr de vouloir apporter les modifications suivantes ?",
|
||||
"description": {
|
||||
"downgrade": "Rétrograder {{name}} en {{version}}",
|
||||
"install": "Installer {{name}} {{version}}",
|
||||
"overwrite": "Écraser {{name}} avec {{version}}",
|
||||
"reinstall": "Réinstaller {{name}} {{version}}",
|
||||
"update": "Mettre à jour {{name}} à {{version}}"
|
||||
"update": "Mettre à jour {{name}} en {{version}}"
|
||||
},
|
||||
"ok_button": {
|
||||
"idle": "Confirmer",
|
||||
"loading": "En cours"
|
||||
},
|
||||
"title": {
|
||||
"downgrade_many": "Rétrograder {{count}} plugins",
|
||||
"downgrade_one": "Rétrograder 1 plugin",
|
||||
"downgrade_other": "Rétrograder {{count}} plugins",
|
||||
"install_many": "Installer {{count}} plugins",
|
||||
"install_one": "Installer 1 plugin",
|
||||
"install_other": "Installer {{count}} plugins",
|
||||
"mixed_many": "Modifier {{count}} plugins",
|
||||
"mixed_one": "Modifier {{count}} plugin",
|
||||
"mixed_other": "Modifier {{count}} plugins",
|
||||
"overwrite_many": "Écraser {{count}} plugins",
|
||||
"overwrite_one": "Écraser 1 plugin",
|
||||
"overwrite_other": "Écraser {{count}} plugins",
|
||||
"reinstall_many": "Réinstaller {{count}} plugins",
|
||||
"reinstall_one": "Réinstaller 1 plugin",
|
||||
"reinstall_other": "Réinstaller {{count}} plugins",
|
||||
@@ -76,12 +84,22 @@
|
||||
}
|
||||
},
|
||||
"PluginCard": {
|
||||
"plugin_downgrade": "Rétrograder",
|
||||
"plugin_full_access": "Ce plugin a un accès complet à votre Steam Deck.",
|
||||
"plugin_install": "Installer",
|
||||
"plugin_no_desc": "Aucune description fournie.",
|
||||
"plugin_overwrite": "Écraser",
|
||||
"plugin_reinstall": "Réinstaller",
|
||||
"plugin_update": "Mettre à jour",
|
||||
"plugin_version_label": "Version du plugin"
|
||||
},
|
||||
"PluginInstallModal": {
|
||||
"downgrade": {
|
||||
"button_idle": "Rétrograder",
|
||||
"button_processing": "Rétrogradation",
|
||||
"desc": "Êtes-vous sûr de vouloir rétrograder {{artifact}} vers la version {{version}} ?",
|
||||
"title": "Rétrograder {{artifact}}"
|
||||
},
|
||||
"install": {
|
||||
"button_idle": "Installer",
|
||||
"button_processing": "Installation en cours",
|
||||
@@ -89,6 +107,13 @@
|
||||
"title": "Installer {{artifact}}"
|
||||
},
|
||||
"no_hash": "Ce plugin n'a pas de somme de contrôle, vous l'installez à vos risques et périls.",
|
||||
"not_installed": "(non installé)",
|
||||
"overwrite": {
|
||||
"button_idle": "Écraser",
|
||||
"button_processing": "Écrasement",
|
||||
"desc": "Êtes-vous sûr de vouloir remplacer {{artifact}} par la version {{version}} ?",
|
||||
"title": "Écraser {{artifact}}"
|
||||
},
|
||||
"reinstall": {
|
||||
"button_idle": "Réinstaller",
|
||||
"button_processing": "Réinstallation en cours",
|
||||
@@ -97,8 +122,8 @@
|
||||
},
|
||||
"update": {
|
||||
"button_idle": "Mettre à jour",
|
||||
"button_processing": "Mise à jour",
|
||||
"desc": "Êtes-vous sûr de vouloir mettre à jour {{artifact}} {{version}} ?",
|
||||
"button_processing": "Mise à jour en cours",
|
||||
"desc": "Êtes-vous sûr de vouloir mettre à jour {{artifact}} vers la version {{version}} ?",
|
||||
"title": "Mettre à jour {{artifact}}"
|
||||
}
|
||||
},
|
||||
@@ -124,7 +149,7 @@
|
||||
"decky_title": "Decky",
|
||||
"decky_update_available": "Mise à jour vers {{tag_name}} disponible !",
|
||||
"error": "Erreur",
|
||||
"plugin_error_uninstall": "Allez sur {{name}} dans le menu de Decky si vous voulez désinstaller ce plugin.",
|
||||
"plugin_error_uninstall": "Le chargement de {{name}} a provoqué une exception comme indiqué ci-dessus. Cela signifie généralement que le plugin nécessite une mise à jour pour la nouvelle version de SteamUI. Vérifiez si une mise à jour est présente ou évaluez sa suppression dans les paramètres de Decky, dans la section Plugins.",
|
||||
"plugin_load_error": {
|
||||
"message": "Erreur lors du chargement du plugin {{name}}",
|
||||
"toast": "Erreur lors du chargement de {{name}}"
|
||||
@@ -153,7 +178,7 @@
|
||||
"cef_console": {
|
||||
"button": "Ouvrir la console",
|
||||
"desc": "Ouvre la console CEF. Utile uniquement à des fins de débogage. Les éléments présentés ici sont potentiellement dangereux et ne doivent être utilisés que si vous êtes un développeur de plugins ou si vous êtes dirigé ici par un de ces développeurs.",
|
||||
"label": "CEF Console"
|
||||
"label": "Console CEF"
|
||||
},
|
||||
"header": "Autre",
|
||||
"react_devtools": {
|
||||
@@ -171,7 +196,7 @@
|
||||
},
|
||||
"valve_internal": {
|
||||
"desc1": "Active le menu développeur interne de Valve.",
|
||||
"desc2": "Ne touchez à rien dans ce menu à moins que vous ne sachiez ce qu'il fait.",
|
||||
"desc2": "Ne touchez à rien dans ce menu à moins que vous ne sachiez ce que ça fait.",
|
||||
"label": "Activer Valve Internal"
|
||||
}
|
||||
},
|
||||
@@ -187,9 +212,9 @@
|
||||
"label": "Mode développeur"
|
||||
},
|
||||
"notifications": {
|
||||
"decky_updates_label": "Mise à jour Decky disponible",
|
||||
"decky_updates_label": "Mise à jour de Decky disponible",
|
||||
"header": "Notifications",
|
||||
"plugin_updates_label": "Mises à jour du plugin disponibles"
|
||||
"plugin_updates_label": "Mises à jour des plugins disponibles"
|
||||
},
|
||||
"other": {
|
||||
"header": "Autre"
|
||||
@@ -202,9 +227,19 @@
|
||||
"developer_title": "Développeur",
|
||||
"general_title": "Général",
|
||||
"plugins_title": "Plugins",
|
||||
"testing_title": "Essai"
|
||||
"testing_title": "Expérimentations"
|
||||
},
|
||||
"Store": {
|
||||
"download_progress_info": {
|
||||
"download_remote": "Téléchargement des binaires externes",
|
||||
"download_zip": "Téléchargement du plugin",
|
||||
"increment_count": "Incrémentation du nombre de téléchargements",
|
||||
"installing_plugin": "Installation du plugin",
|
||||
"open_zip": "Ouverture du fichier zip",
|
||||
"parse_zip": "Analyse du fichier zip",
|
||||
"start": "Initialisation",
|
||||
"uninstalling_previous": "Désinstallation de la copie précédente"
|
||||
},
|
||||
"store_contrib": {
|
||||
"desc": "Si vous souhaitez contribuer au Decky Plugin Store, consultez le dépôt SteamDeckHomebrew/decky-plugin-template sur GitHub. Des informations sur le développement et la distribution sont disponibles dans le fichier README.",
|
||||
"label": "Contributions"
|
||||
@@ -237,23 +272,27 @@
|
||||
"store_testing_cta": "Pensez à tester de nouveaux plugins pour aider l'équipe Decky Loader !",
|
||||
"store_testing_warning": {
|
||||
"desc": "Vous pouvez utiliser cette chaîne de magasin pour tester des versions de plugins. Assurez-vous de laisser des commentaires sur GitHub afin que le plugin puisse être mis à jour pour tous les utilisateurs.",
|
||||
"label": "Bienvenue sur la chaîne du magasin de tests"
|
||||
"label": "Bienvenue sur le canal test de la boutique"
|
||||
}
|
||||
},
|
||||
"StoreSelect": {
|
||||
"custom_store": {
|
||||
"label": "Plugin Store personnalisé",
|
||||
"label": "Magasin personnalisé",
|
||||
"url_label": "URL"
|
||||
},
|
||||
"store_channel": {
|
||||
"custom": "Personnalisé",
|
||||
"default": "Par défaut",
|
||||
"label": "Canal du Plugin Store",
|
||||
"label": "Canal magasin",
|
||||
"testing": "Test"
|
||||
}
|
||||
},
|
||||
"Testing": {
|
||||
"download": "Télécharger"
|
||||
"download": "Télécharger",
|
||||
"error": "Erreur d'installation de la PR",
|
||||
"header": "Les versions suivantes de Decky Loader sont construites à partir de Pull Requests ouvertes par des tiers. L'équipe de Decky Loader n'a pas vérifié leur fonctionnalité ou leur sécurité, et elles peuvent être obsolètes.",
|
||||
"loading": "Chargement des Pull Requests ouvertes...",
|
||||
"start_download_toast": "Téléchargement de la PR #{{id}}"
|
||||
},
|
||||
"TitleView": {
|
||||
"decky_store_desc": "Ouvrir le magasin Decky",
|
||||
@@ -264,7 +303,7 @@
|
||||
"no_patch_notes_desc": "pas de notes de mise à jour pour cette version",
|
||||
"patch_notes_desc": "Notes de mise à jour",
|
||||
"updates": {
|
||||
"check_button": "Chercher les mises à jour",
|
||||
"check_button": "Vérifier les mises à jour",
|
||||
"checking": "Recherche",
|
||||
"cur_version": "Version actuelle: {{ver}}",
|
||||
"install_button": "Installer la mise à jour",
|
||||
|
||||
@@ -52,7 +52,9 @@
|
||||
"MultiplePluginsInstallModal": {
|
||||
"confirm": "以下の変更を加えてもよろしいですか?",
|
||||
"description": {
|
||||
"downgrade": "ダウングレード {{name}} {{version}}",
|
||||
"install": "インストール {{name}} {{version}}",
|
||||
"overwrite": "上書き {{name}} {{version}}",
|
||||
"reinstall": "再インストール {{name}} {{version}}",
|
||||
"update": "アップデート {{name}} {{version}}"
|
||||
},
|
||||
@@ -61,19 +63,31 @@
|
||||
"loading": "作業中"
|
||||
},
|
||||
"title": {
|
||||
"downgrade_other": "{{count}} 個のプラグインをダウングレード",
|
||||
"install_other": "{{count}} 個のプラグインをインストール",
|
||||
"mixed_other": "{{count}} 個のプラグインを修正",
|
||||
"overwrite_other": "{{count}} 個のプラグインを上書き",
|
||||
"reinstall_other": "{{count}} 個のプラグインを再インストール",
|
||||
"update_other": "{{count}} 個のプラグインをアップデート"
|
||||
}
|
||||
},
|
||||
"PluginCard": {
|
||||
"plugin_downgrade": "ダウングレード",
|
||||
"plugin_full_access": "このプラグインはSteam Deckの全てのアクセス権を持ちます。",
|
||||
"plugin_install": "インストール",
|
||||
"plugin_no_desc": "説明はありません。",
|
||||
"plugin_overwrite": "上書き",
|
||||
"plugin_reinstall": "再インストール",
|
||||
"plugin_update": "アップデート",
|
||||
"plugin_version_label": "プラグインバージョン"
|
||||
},
|
||||
"PluginInstallModal": {
|
||||
"downgrade": {
|
||||
"button_idle": "ダウングレード",
|
||||
"button_processing": "ダウングレード中",
|
||||
"desc": "{{artifact}}をVer {{version}} にダウングレードしてもよろしいですか?",
|
||||
"title": "{{artifact}}をダウングレード"
|
||||
},
|
||||
"install": {
|
||||
"button_idle": "インストール",
|
||||
"button_processing": "インストール中",
|
||||
@@ -81,6 +95,13 @@
|
||||
"title": "{{artifact}} をインストール"
|
||||
},
|
||||
"no_hash": "このプラグインにはハッシュがありません。ご自身の責任でインストールしてください。",
|
||||
"not_installed": "(インストールされていません)",
|
||||
"overwrite": {
|
||||
"button_idle": "上書き",
|
||||
"button_processing": "上書き中",
|
||||
"desc": "{{artifact}}をVer {{version}} に上書きしてもよろしいですか?",
|
||||
"title": "{{artifact}}を上書き"
|
||||
},
|
||||
"reinstall": {
|
||||
"button_idle": "再インストール",
|
||||
"button_processing": "再インストール中",
|
||||
@@ -90,7 +111,7 @@
|
||||
"update": {
|
||||
"button_idle": "アップデート",
|
||||
"button_processing": "アップデート中",
|
||||
"desc": "{{artifact}} {{version}} をアップデートしてもよろしいですか?",
|
||||
"desc": "{{artifact}}をVer {{version}} にアップデートしてもよろしいですか?",
|
||||
"title": "{{artifact}} をアップデート"
|
||||
}
|
||||
},
|
||||
@@ -192,6 +213,7 @@
|
||||
},
|
||||
"Store": {
|
||||
"download_progress_info": {
|
||||
"download_remote": "外部バイナリのダウンロード",
|
||||
"download_zip": "プラグインのダウンロード中",
|
||||
"increment_count": "ダウンロード数の増加",
|
||||
"installing_plugin": "プラグインのインストール中",
|
||||
|
||||
@@ -52,7 +52,9 @@
|
||||
"MultiplePluginsInstallModal": {
|
||||
"confirm": "Вы уверены, что хотите внести следующие изменения?",
|
||||
"description": {
|
||||
"downgrade": "Откатить {{name}} до {{version}}",
|
||||
"install": "Установить {{name}} {{version}}",
|
||||
"overwrite": "Заменить {{name}} на {{version}}",
|
||||
"reinstall": "Переустановить {{name}} {{version}}",
|
||||
"update": "Обновить с {{name}} на {{version}}"
|
||||
},
|
||||
@@ -61,6 +63,9 @@
|
||||
"loading": "В процессе"
|
||||
},
|
||||
"title": {
|
||||
"downgrade_few": "Откатить {{count}} плагинов",
|
||||
"downgrade_many": "Откатить {{count}} плагинов",
|
||||
"downgrade_one": "Откатить 1 плагин",
|
||||
"install_few": "Установить {{count}} плагинов",
|
||||
"install_many": "Установить {{count}} плагинов",
|
||||
"install_one": "Установить {{count}} плагин",
|
||||
@@ -76,12 +81,21 @@
|
||||
}
|
||||
},
|
||||
"PluginCard": {
|
||||
"plugin_downgrade": "Откат",
|
||||
"plugin_full_access": "Этот плагин имеет полный доступ к вашему Steam Deck.",
|
||||
"plugin_install": "Установить",
|
||||
"plugin_no_desc": "Нет описания.",
|
||||
"plugin_overwrite": "Замена",
|
||||
"plugin_reinstall": "Переустановка",
|
||||
"plugin_update": "Обновление",
|
||||
"plugin_version_label": "Версия плагина"
|
||||
},
|
||||
"PluginInstallModal": {
|
||||
"downgrade": {
|
||||
"button_idle": "Откат",
|
||||
"desc": "Вы уверенны, что хотите откатить {{artifact}} до версии {{version}}?",
|
||||
"title": "Откатить {{artifact}}"
|
||||
},
|
||||
"install": {
|
||||
"button_idle": "Установить",
|
||||
"button_processing": "Установка",
|
||||
@@ -98,7 +112,7 @@
|
||||
"update": {
|
||||
"button_idle": "Обновить",
|
||||
"button_processing": "Обновление",
|
||||
"desc": "Вы уверены, что хотите обновить {{artifact}} {{version}}?",
|
||||
"desc": "Вы уверены, что хотите обновить {{artifact}} до версии {{version}}?",
|
||||
"title": "Обновить {{artifact}}"
|
||||
}
|
||||
},
|
||||
|
||||
Generated
+751
-732
File diff suppressed because it is too large
Load Diff
@@ -14,7 +14,7 @@ include = [
|
||||
]
|
||||
|
||||
[tool.poetry.dependencies]
|
||||
python = ">=3.10,<3.14"
|
||||
python = ">=3.10,<3.13"
|
||||
|
||||
aiohttp = "^3.10.11"
|
||||
aiohttp-jinja2 = "^1.5.1"
|
||||
|
||||
@@ -7,4 +7,4 @@ export default {
|
||||
tabWidth: 2,
|
||||
endOfLine: 'auto',
|
||||
plugins: [importSort],
|
||||
}
|
||||
};
|
||||
|
||||
@@ -47,7 +47,7 @@
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@decky/ui": "^4.8.3",
|
||||
"@decky/ui": "^4.10.2",
|
||||
"compare-versions": "^6.1.1",
|
||||
"filesize": "^10.1.2",
|
||||
"i18next": "^23.11.5",
|
||||
|
||||
Generated
+5
-5
@@ -9,8 +9,8 @@ importers:
|
||||
.:
|
||||
dependencies:
|
||||
'@decky/ui':
|
||||
specifier: ^4.8.3
|
||||
version: 4.8.3
|
||||
specifier: ^4.10.2
|
||||
version: 4.10.2
|
||||
compare-versions:
|
||||
specifier: ^6.1.1
|
||||
version: 6.1.1
|
||||
@@ -218,8 +218,8 @@ packages:
|
||||
'@decky/api@1.1.1':
|
||||
resolution: {integrity: sha512-R5fkBRHBt5QIQY7Q0AlbVIhlIZ/nTzwBOoi8Rt4Go2fjFnoMKPInCJl6cPjXzimGwl2pyqKJgY6VnH6ar0XrHQ==}
|
||||
|
||||
'@decky/ui@4.8.3':
|
||||
resolution: {integrity: sha512-Y1KciazgvKqMEVBGrWFCTGOqgVi5sHbcQNoCZRMbPpcI0U3j7udl6mkfe/NBa16oRDZ03ljS41SmrAgKAAt/pA==}
|
||||
'@decky/ui@4.10.2':
|
||||
resolution: {integrity: sha512-dfY/OEI/rhG4d3Tvx4Y3TLmBrJ+nAm2RTbkoOJ3VAglql3Lu7RY2ixeDFbs21ZWWzWh/C+9dAQKjQ4lx4d1f2g==}
|
||||
|
||||
'@esbuild/aix-ppc64@0.20.2':
|
||||
resolution: {integrity: sha512-D+EBOJHXdNZcLJRBkhENNG8Wji2kgc9AZ9KiPr1JuZjsNtyHzrsfLRrY0tk2H2aoFu6RANO1y1iPPUCDYWkb5g==}
|
||||
@@ -2295,7 +2295,7 @@ snapshots:
|
||||
|
||||
'@decky/api@1.1.1': {}
|
||||
|
||||
'@decky/ui@4.8.3': {}
|
||||
'@decky/ui@4.10.2': {}
|
||||
|
||||
'@esbuild/aix-ppc64@0.20.2':
|
||||
optional: true
|
||||
|
||||
@@ -4,6 +4,8 @@ import { FunctionComponent, useEffect, useReducer, useState } from 'react';
|
||||
import { uninstallPlugin } from '../plugin';
|
||||
import { VerInfo, doRestart, doShutdown } from '../updater';
|
||||
import { ValveReactErrorInfo, getLikelyErrorSourceFromValveReactError } from '../utils/errors';
|
||||
import { useSetting } from '../utils/hooks/useSetting';
|
||||
import { UpdateBranch } from './settings/pages/general/BranchSelect';
|
||||
|
||||
interface DeckyErrorBoundaryProps {
|
||||
error: ValveReactErrorInfo;
|
||||
@@ -37,6 +39,27 @@ const DeckyErrorBoundary: FunctionComponent<DeckyErrorBoundaryProps> = ({ error,
|
||||
if (!shouldReportToValve) DeckyPluginLoader.errorBoundaryHook.temporarilyDisableReporting();
|
||||
DeckyPluginLoader.updateVersion().then(setVersionInfo);
|
||||
}, []);
|
||||
|
||||
const [selectedBranch, setSelectedBranch] = useSetting<UpdateBranch>('branch', UpdateBranch.Stable);
|
||||
const [isChecking, setIsChecking] = useState<boolean>(false);
|
||||
const [updateProgress, setUpdateProgress] = useState<number>(-1);
|
||||
const [versionToUpdateTo, setSetVersionToUpdateTo] = useState<string>('');
|
||||
|
||||
useEffect(() => {
|
||||
const a = DeckyBackend.addEventListener('updater/update_download_percentage', (percentage) => {
|
||||
setUpdateProgress(percentage);
|
||||
});
|
||||
|
||||
const b = DeckyBackend.addEventListener('updater/finish_download', () => {
|
||||
setUpdateProgress(-2);
|
||||
});
|
||||
|
||||
return () => {
|
||||
DeckyBackend.removeEventListener('updater/update_download_percentage', a);
|
||||
DeckyBackend.removeEventListener('updater/finish_download', b);
|
||||
};
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<>
|
||||
<style>
|
||||
@@ -149,6 +172,65 @@ const DeckyErrorBoundary: FunctionComponent<DeckyErrorBoundaryProps> = ({ error,
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
{
|
||||
<div style={{ display: 'block', marginBottom: '5px' }}>
|
||||
{updateProgress > -1
|
||||
? 'Update in progress... ' + updateProgress + '%'
|
||||
: updateProgress == -2
|
||||
? 'Update complete. Restarting...'
|
||||
: 'Changing your Decky Loader branch and/or \n checking for updates might help!\n'}
|
||||
{updateProgress == -1 && (
|
||||
<div style={{ height: '30px' }}>
|
||||
<select
|
||||
style={{ height: '100%' }}
|
||||
onChange={async (e) => {
|
||||
const branch = parseInt(e.target.value);
|
||||
setSelectedBranch(branch);
|
||||
setSetVersionToUpdateTo('');
|
||||
}}
|
||||
>
|
||||
<option value="0" selected={selectedBranch == UpdateBranch.Stable}>
|
||||
Stable
|
||||
</option>
|
||||
<option value="1" selected={selectedBranch == UpdateBranch.Prerelease}>
|
||||
Pre-Release
|
||||
</option>
|
||||
<option value="2" selected={selectedBranch == UpdateBranch.Testing}>
|
||||
Testing
|
||||
</option>
|
||||
</select>
|
||||
<button
|
||||
style={{ height: '100%' }}
|
||||
disabled={updateProgress != -1 || isChecking}
|
||||
onClick={async () => {
|
||||
if (versionToUpdateTo == '') {
|
||||
setIsChecking(true);
|
||||
const versionInfo = (await DeckyBackend.callable(
|
||||
'updater/check_for_updates',
|
||||
)()) as unknown as VerInfo;
|
||||
setIsChecking(false);
|
||||
if (versionInfo?.remote && versionInfo?.remote?.tag_name != versionInfo?.current) {
|
||||
setSetVersionToUpdateTo(versionInfo.remote.tag_name);
|
||||
} else {
|
||||
setSetVersionToUpdateTo('');
|
||||
}
|
||||
} else {
|
||||
DeckyBackend.callable('updater/do_update')();
|
||||
setUpdateProgress(0);
|
||||
}
|
||||
}}
|
||||
>
|
||||
{' '}
|
||||
{isChecking
|
||||
? 'Checking for updates...'
|
||||
: versionToUpdateTo != ''
|
||||
? 'Update to ' + versionToUpdateTo
|
||||
: 'Check for updates'}
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
}
|
||||
{wasCausedByPlugin && (
|
||||
<div style={{ display: 'block', marginBottom: '5px' }}>
|
||||
{'\n'}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Focusable, Navigation } from '@decky/ui';
|
||||
import { Focusable, Navigation, findClass, findClassByName } from '@decky/ui';
|
||||
import { FunctionComponent, useRef } from 'react';
|
||||
import ReactMarkdown, { Options as ReactMarkdownOptions } from 'react-markdown';
|
||||
import remarkGfm from 'remark-gfm';
|
||||
@@ -8,6 +8,9 @@ interface MarkdownProps extends ReactMarkdownOptions {
|
||||
}
|
||||
|
||||
const Markdown: FunctionComponent<MarkdownProps> = (props) => {
|
||||
const eventDetailsBodyClassName = findClassByName('EventDetailsBody') || undefined;
|
||||
const eventLinkClassName = findClass('43088', 'Link');
|
||||
|
||||
return (
|
||||
<Focusable>
|
||||
<ReactMarkdown
|
||||
@@ -25,8 +28,10 @@ const Markdown: FunctionComponent<MarkdownProps> = (props) => {
|
||||
Navigation.NavigateToExternalWeb(aRef.current!.href);
|
||||
}}
|
||||
style={{ display: 'inline' }}
|
||||
focusClassName="steam-focus"
|
||||
className={eventDetailsBodyClassName}
|
||||
>
|
||||
<a ref={aRef} {...nodeProps.node.properties}>
|
||||
<a ref={aRef} {...nodeProps.node.properties} className={eventLinkClassName}>
|
||||
{nodeProps.children}
|
||||
</a>
|
||||
</Focusable>
|
||||
|
||||
@@ -47,7 +47,7 @@ export default async function libraryPatch() {
|
||||
}
|
||||
|
||||
const unlisten = History.listen(() => {
|
||||
if (window.SteamClient.Apps.PromptToChangeShortcut !== patch.patchedFunction) {
|
||||
if ((window.SteamClient.Apps as any).PromptToChangeShortcut !== patch.patchedFunction) {
|
||||
rePatch();
|
||||
}
|
||||
});
|
||||
|
||||
@@ -72,7 +72,16 @@ export default function DeveloperSettings() {
|
||||
}
|
||||
icon={<FaLink style={{ display: 'block' }} />}
|
||||
>
|
||||
<DialogButton disabled={pluginURL.length == 0} onClick={() => installFromURL(pluginURL)}>
|
||||
<DialogButton
|
||||
disabled={pluginURL.length == 0}
|
||||
onClick={() => {
|
||||
if (/^https?:\/\//.test(pluginURL)) {
|
||||
installFromURL(pluginURL);
|
||||
} else {
|
||||
installFromURL('https://' + pluginURL);
|
||||
}
|
||||
}}
|
||||
>
|
||||
{t('SettingsDeveloperIndex.third_party_plugins.button_install')}
|
||||
</DialogButton>
|
||||
</Field>
|
||||
|
||||
@@ -1,14 +1,4 @@
|
||||
import {
|
||||
Carousel,
|
||||
DialogButton,
|
||||
Field,
|
||||
FocusRing,
|
||||
Focusable,
|
||||
ProgressBarWithInfo,
|
||||
Spinner,
|
||||
findSP,
|
||||
showModal,
|
||||
} from '@decky/ui';
|
||||
import { Carousel, DialogButton, Field, Focusable, ProgressBarWithInfo, Spinner, findSP, showModal } from '@decky/ui';
|
||||
import { Suspense, lazy, useCallback, useEffect, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { FaExclamation } from 'react-icons/fa';
|
||||
@@ -23,9 +13,31 @@ const MarkdownRenderer = lazy(() => import('../../../Markdown'));
|
||||
function PatchNotesModal({ versionInfo, closeModal }: { versionInfo: VerInfo | null; closeModal?: () => {} }) {
|
||||
const SP = findSP();
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<Focusable onCancelButton={closeModal}>
|
||||
<FocusRing>
|
||||
<>
|
||||
<style>
|
||||
{`
|
||||
.steam-focus {
|
||||
outline-offset: 3px;
|
||||
outline: 2px solid rgba(255, 255, 255, 0.6);
|
||||
animation: pulseOutline 1.2s infinite ease-in-out;
|
||||
}
|
||||
|
||||
@keyframes pulseOutline {
|
||||
0% {
|
||||
outline: 2px solid rgba(255, 255, 255, 0.6);
|
||||
}
|
||||
50% {
|
||||
outline: 2px solid rgba(255, 255, 255, 1);
|
||||
}
|
||||
100% {
|
||||
outline: 2px solid rgba(255, 255, 255, 0.6);
|
||||
}
|
||||
}`}
|
||||
</style>
|
||||
|
||||
<Focusable onCancelButton={closeModal}>
|
||||
<Carousel
|
||||
fnItemRenderer={(id: number) => (
|
||||
<Focusable
|
||||
@@ -35,7 +47,9 @@ function PatchNotesModal({ versionInfo, closeModal }: { versionInfo: VerInfo | n
|
||||
overflowY: 'scroll',
|
||||
display: 'flex',
|
||||
justifyContent: 'center',
|
||||
margin: '40px',
|
||||
margin: '30px',
|
||||
padding: '0 15px',
|
||||
backgroundColor: 'rgba(37, 40, 46, 0.5)',
|
||||
}}
|
||||
>
|
||||
<div>
|
||||
@@ -57,11 +71,11 @@ function PatchNotesModal({ versionInfo, closeModal }: { versionInfo: VerInfo | n
|
||||
nItemMarginX={0}
|
||||
initialColumn={0}
|
||||
autoFocus={true}
|
||||
fnGetColumnWidth={() => SP.innerWidth}
|
||||
fnGetColumnWidth={() => SP.innerWidth - SP.innerWidth * (10 / 100)}
|
||||
name={t('Updater.decky_updates') as string}
|
||||
/>
|
||||
</FocusRing>
|
||||
</Focusable>
|
||||
</Focusable>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { ToastNotification } from '@decky/api';
|
||||
import {
|
||||
EUIMode,
|
||||
ModalRoot,
|
||||
Navigation,
|
||||
PanelSection,
|
||||
@@ -30,7 +31,7 @@ import { HiddenPluginsService } from './hidden-plugins-service';
|
||||
import Logger from './logger';
|
||||
import { NotificationService } from './notification-service';
|
||||
import { InstallType, Plugin, PluginLoadType } from './plugin';
|
||||
import RouterHook, { UIMode } from './router-hook';
|
||||
import RouterHook from './router-hook';
|
||||
import { deinitSteamFixes, initSteamFixes } from './steamfixes';
|
||||
import { checkForPluginUpdates } from './store';
|
||||
import TabsHook from './tabs-hook';
|
||||
@@ -205,12 +206,12 @@ class PluginLoader extends Logger {
|
||||
let registration: any;
|
||||
const uiMode = await new Promise(
|
||||
(r) =>
|
||||
(registration = SteamClient.UI.RegisterForUIModeChanged((mode: UIMode) => {
|
||||
(registration = SteamClient.UI.RegisterForUIModeChanged((mode: EUIMode) => {
|
||||
r(mode);
|
||||
registration.unregister();
|
||||
})),
|
||||
);
|
||||
if (uiMode == UIMode.BigPicture) {
|
||||
if (uiMode == EUIMode.GamePad) {
|
||||
// wait for SP window to exist before loading plugins
|
||||
while (!findSP()) {
|
||||
await sleep(100);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import {
|
||||
EUIMode,
|
||||
ErrorBoundary,
|
||||
Patch,
|
||||
afterPatch,
|
||||
@@ -31,11 +32,6 @@ declare global {
|
||||
}
|
||||
}
|
||||
|
||||
export enum UIMode {
|
||||
BigPicture = 4,
|
||||
Desktop = 7,
|
||||
}
|
||||
|
||||
const isPatched = Symbol('is patched');
|
||||
|
||||
class RouterHook extends Logger {
|
||||
@@ -76,13 +72,13 @@ class RouterHook extends Logger {
|
||||
this.error('Failed to find router stack module');
|
||||
}
|
||||
|
||||
this.modeChangeRegistration = SteamClient.UI.RegisterForUIModeChanged((mode: UIMode) => {
|
||||
this.modeChangeRegistration = SteamClient.UI.RegisterForUIModeChanged((mode: EUIMode) => {
|
||||
this.debug(`UI mode changed to ${mode}`);
|
||||
if (this.patchedModes.has(mode)) return;
|
||||
this.patchedModes.add(mode);
|
||||
this.debug(`Patching router for UI mode ${mode}`);
|
||||
switch (mode) {
|
||||
case UIMode.BigPicture:
|
||||
case EUIMode.GamePad:
|
||||
this.debug('Patching gamepad router');
|
||||
this.patchGamepadRouter();
|
||||
break;
|
||||
|
||||
Regular → Executable
+18
-1
@@ -2,6 +2,13 @@
|
||||
# Usage: deckdebug.sh DECKIP:8081
|
||||
# Dependencies: websocat jq curl chromium
|
||||
|
||||
if [ "$#" -ne 1 ]; then
|
||||
echo "Error: Missing or incorrect argument." >&2
|
||||
echo "Usage: deckdebug.sh DECKIP:8081" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
||||
# https://jackson.dev/post/a-portable-nix-shell-shebang/
|
||||
if [ -z "$INSIDE_NIX_RANDOMSTRING" ] && command -v nix &> /dev/null; then
|
||||
# If the user has nix, relaunch in nix shell with dependencies added
|
||||
@@ -13,6 +20,16 @@ if [ -z "$INSIDE_NIX_RANDOMSTRING" ] && command -v nix &> /dev/null; then
|
||||
exit $?
|
||||
fi
|
||||
|
||||
required_dependencies=(websocat jq curl chromium)
|
||||
|
||||
# Check if the dependencies are installed
|
||||
for cmd in "${required_dependencies[@]}"; do
|
||||
if ! command -v "$cmd" &> /dev/null; then
|
||||
echo "Error: '$cmd' is not installed. Please install it and try again." >&2
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
chromium --remote-debugging-port=9222 &
|
||||
sleep 2
|
||||
|
||||
@@ -41,4 +58,4 @@ while :; do
|
||||
fi
|
||||
|
||||
sleep 5
|
||||
done
|
||||
done
|
||||
|
||||
Regular → Executable
Executable
+120
@@ -0,0 +1,120 @@
|
||||
#!/usr/bin/env bash
|
||||
# ./script/task.sh: Run a VSCode task from tasks.json including its dependencies.
|
||||
#
|
||||
# Usage: ./scripts/task.sh TASK_LABEL
|
||||
#
|
||||
# This script looks for .vscode/tasks.json in your workspace folder (or current directory)
|
||||
# and executes the command associated with the given task label.
|
||||
#
|
||||
# It also handles the "dependsOn" field recursively.
|
||||
#
|
||||
# Requirements: jq sed
|
||||
|
||||
# https://jackson.dev/post/a-portable-nix-shell-shebang/
|
||||
if [ -z "$INSIDE_NIX_RANDOMSTRING" ] && command -v nix &> /dev/null; then
|
||||
# If the user has nix, relaunch in nix shell with dependencies added
|
||||
INSIDE_NIX_RANDOMSTRING=1 nix shell \
|
||||
nixpkgs#jq \
|
||||
nixpkgs#gnused \
|
||||
--command "$0" "$@"
|
||||
exit $?
|
||||
fi
|
||||
|
||||
required_dependencies=(jq sed)
|
||||
|
||||
# Check if the dependencies are installed
|
||||
for cmd in "${required_dependencies[@]}"; do
|
||||
if ! command -v "$cmd" &> /dev/null; then
|
||||
echo "Error: '$cmd' is not installed. Please install it and try again." >&2
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# Use WORKSPACE_FOLDER if set; otherwise, assume current directory.
|
||||
WORKSPACE_FOLDER="${WORKSPACE_FOLDER:-$(pwd)}"
|
||||
TASKS_FILE="$WORKSPACE_FOLDER/.vscode/tasks.json"
|
||||
|
||||
if [ ! -f "$TASKS_FILE" ]; then
|
||||
echo "Error: tasks.json not found at $TASKS_FILE" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ $# -lt 1 ]; then
|
||||
echo "Usage: $0 TASK_LABEL" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Remove comment lines (lines starting with //) from the tasks file to be compliant with the JSON format.
|
||||
TASKS_JSON=$(sed '/^[[:space:]]*\/\//d' "$TASKS_FILE")
|
||||
|
||||
TASK_LABEL="$1"
|
||||
shift
|
||||
|
||||
# run_task recursively looks up the task by label,
|
||||
# runs any dependencies first, then executes its command.
|
||||
run_task() {
|
||||
local label="$1"
|
||||
echo "Looking up task: $label"
|
||||
|
||||
# Get the task object from the cleaned JSON.
|
||||
local task
|
||||
task=$(echo "$TASKS_JSON" | jq --arg label "$label" -r '.tasks[] | select(.label == $label)')
|
||||
if [ -z "$task" ]; then
|
||||
echo "Error: Task with label '$label' not found in $TASKS_FILE" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# If the task has dependencies, run them first.
|
||||
local depends
|
||||
depends=$(echo "$task" | jq -r '.dependsOn? // empty')
|
||||
if [ -n "$depends" ] && [ "$depends" != "null" ]; then
|
||||
# "dependsOn" can be an array or a string.
|
||||
if echo "$depends" | jq -e 'if type=="array" then . else empty end' >/dev/null; then
|
||||
for dep in $(echo "$depends" | jq -r '.[]'); do
|
||||
run_task "$dep"
|
||||
done
|
||||
else
|
||||
run_task "$depends"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Check if the task has either a command or script.
|
||||
local has_command has_script
|
||||
has_command=$(echo "$task" | jq -r 'has("command")')
|
||||
has_script=$(echo "$task" | jq -r 'has("script")')
|
||||
if [[ "$has_command" != "true" && "$has_script" != "true" ]]; then
|
||||
echo "Task '$label' has no command or script; skipping execution."
|
||||
return
|
||||
fi
|
||||
|
||||
# Determine the command to run:
|
||||
local cmd=""
|
||||
if echo "$task" | jq 'has("command")' | grep -q "true"; then
|
||||
cmd=$(echo "$task" | jq -r '.command')
|
||||
elif echo "$task" | jq 'has("script")' | grep -q "true"; then
|
||||
local script
|
||||
script=$(echo "$task" | jq -r '.script')
|
||||
local path
|
||||
path=$(echo "$task" | jq -r '.path // empty')
|
||||
if [ -n "$path" ]; then
|
||||
cmd="cd $path && npm run $script"
|
||||
else
|
||||
cmd="npm run $script"
|
||||
fi
|
||||
else
|
||||
echo "Error: Task '$label' does not have a command or script." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Substitute ${workspaceFolder} with the actual folder path.
|
||||
cmd="${cmd//\$\{workspaceFolder\}/$WORKSPACE_FOLDER}"
|
||||
|
||||
echo "Running task '$label': $cmd"
|
||||
# Run the task in a subshell so that directory changes don't persist.
|
||||
( eval "$cmd" )
|
||||
}
|
||||
|
||||
run_task "$TASK_LABEL"
|
||||
Reference in New Issue
Block a user