From 0db45ca71e992c006f9d9528f86bfde32d95e134 Mon Sep 17 00:00:00 2001 From: TrainDoctor Date: Sun, 4 Dec 2022 19:04:46 -0800 Subject: [PATCH 01/23] Update plugin_loader-prerelease.service --- dist/plugin_loader-prerelease.service | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dist/plugin_loader-prerelease.service b/dist/plugin_loader-prerelease.service index a36a2435..86190ac4 100644 --- a/dist/plugin_loader-prerelease.service +++ b/dist/plugin_loader-prerelease.service @@ -8,7 +8,8 @@ User=root Restart=always ExecStart=${HOMEBREW_FOLDER}/services/PluginLoader WorkingDirectory=${HOMEBREW_FOLDER}/services +KillSignal=SIGKILL Environment=PLUGIN_PATH=${HOMEBREW_FOLDER}/plugins Environment=LOG_LEVEL=DEBUG [Install] -WantedBy=multi-user.target \ No newline at end of file +WantedBy=multi-user.target From 3653cf56403697cabec89a0715019c8bd649c896 Mon Sep 17 00:00:00 2001 From: TrainDoctor Date: Sun, 4 Dec 2022 19:05:01 -0800 Subject: [PATCH 02/23] Update plugin_loader-release.service --- dist/plugin_loader-release.service | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dist/plugin_loader-release.service b/dist/plugin_loader-release.service index 20fbe7b8..fcb0fcce 100644 --- a/dist/plugin_loader-release.service +++ b/dist/plugin_loader-release.service @@ -8,7 +8,8 @@ User=root Restart=always ExecStart=${HOMEBREW_FOLDER}/services/PluginLoader WorkingDirectory=${HOMEBREW_FOLDER}/services +KillSignal=SIGKILL Environment=PLUGIN_PATH=${HOMEBREW_FOLDER}/plugins Environment=LOG_LEVEL=INFO [Install] -WantedBy=multi-user.target \ No newline at end of file +WantedBy=multi-user.target From a90ed38c895b6cad44d06acfc14004292ec36cab Mon Sep 17 00:00:00 2001 From: TrainDoctor Date: Sun, 4 Dec 2022 19:05:16 -0800 Subject: [PATCH 03/23] Update install_release.sh --- dist/install_release.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/dist/install_release.sh b/dist/install_release.sh index 8d52728e..58f88d97 100644 --- a/dist/install_release.sh +++ b/dist/install_release.sh @@ -40,6 +40,7 @@ User=root Restart=always ExecStart=${HOMEBREW_FOLDER}/services/PluginLoader WorkingDirectory=${HOMEBREW_FOLDER}/services +KillSignal=SIGKILL Environment=PLUGIN_PATH=${HOMEBREW_FOLDER}/plugins Environment=LOG_LEVEL=INFO [Install] From 2b9a80c151d87d6e19ad4021244614c647d273fe Mon Sep 17 00:00:00 2001 From: TrainDoctor Date: Sun, 4 Dec 2022 19:05:29 -0800 Subject: [PATCH 04/23] Update install_prerelease.sh --- dist/install_prerelease.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/dist/install_prerelease.sh b/dist/install_prerelease.sh index 18f4144d..97c78916 100644 --- a/dist/install_prerelease.sh +++ b/dist/install_prerelease.sh @@ -40,6 +40,7 @@ User=root Restart=always ExecStart=${HOMEBREW_FOLDER}/services/PluginLoader WorkingDirectory=${HOMEBREW_FOLDER}/services +KillSignal=SIGKILL Environment=PLUGIN_PATH=${HOMEBREW_FOLDER}/plugins Environment=LOG_LEVEL=DEBUG [Install] From 35e46f9ccba00892a759fd5c5dab0b6bf2bb5697 Mon Sep 17 00:00:00 2001 From: TrainDoctor Date: Wed, 7 Dec 2022 14:31:09 -0800 Subject: [PATCH 05/23] Update build.yml --- .github/workflows/build.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 733e76e0..de2ce409 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -47,10 +47,10 @@ jobs: with: node-version: 18 - - name: Set up Python 3.10.2 🐍 + - name: Set up Python 3.10.9 🐍 uses: actions/setup-python@v4 with: - python-version: "3.10.2" + python-version: "3.10.9" - name: Install Python dependencies ⬇️ run: | From 6232e3da58b3fc499da20c3021683209aa551a70 Mon Sep 17 00:00:00 2001 From: "NGnius (Graham)" Date: Wed, 7 Dec 2022 19:27:32 -0500 Subject: [PATCH 06/23] Add custom CDN support for custom stores (#269) * Add custom CDN support for custom stores * Update Python for CI --- frontend/src/store.tsx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/frontend/src/store.tsx b/frontend/src/store.tsx index 9b1c5d2e..7ed71e2a 100644 --- a/frontend/src/store.tsx +++ b/frontend/src/store.tsx @@ -10,6 +10,7 @@ export enum Store { export interface StorePluginVersion { name: string; hash: string; + artifact: string | undefined | null; } export interface StorePlugin { @@ -73,9 +74,11 @@ export async function installFromURL(url: string) { } export async function requestPluginInstall(plugin: string, selectedVer: StorePluginVersion) { + const artifactUrl = + selectedVer.artifact ?? `https://cdn.tzatzikiweeb.moe/file/steam-deck-homebrew/versions/${selectedVer.hash}.zip`; await window.DeckyPluginLoader.callServerMethod('install_plugin', { name: plugin, - artifact: `https://cdn.tzatzikiweeb.moe/file/steam-deck-homebrew/versions/${selectedVer.hash}.zip`, + artifact: artifactUrl, version: selectedVer.name, hash: selectedVer.hash, }); From ea35af2050f8a556457ee4d87bb89f0d6a673867 Mon Sep 17 00:00:00 2001 From: TrainDoctor Date: Thu, 8 Dec 2022 15:18:44 -0800 Subject: [PATCH 07/23] Update build.yml --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index de2ce409..d90bd41a 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -31,7 +31,7 @@ permissions: jobs: build: name: Build PluginLoader - runs-on: ubuntu-latest + runs-on: ubuntu-20.04 steps: - name: Print input From f73918c9023d0df92cea6feb394b633b8c881b51 Mon Sep 17 00:00:00 2001 From: jurassicplayer Date: Sat, 10 Dec 2022 15:09:21 -0800 Subject: [PATCH 08/23] feat(MoreCustomizableToasts): Allow plugin developers to customize some toast properties (#268) * Use settingsStore directly * Change toast etype, add showToast/playSound * Update DFL and rebase --- frontend/package.json | 2 +- frontend/pnpm-lock.yaml | 8 ++++---- frontend/src/toaster.tsx | 35 +++++++++++++++++++++++++++-------- 3 files changed, 32 insertions(+), 13 deletions(-) diff --git a/frontend/package.json b/frontend/package.json index 4bb4bc3a..6ca1d017 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -41,7 +41,7 @@ } }, "dependencies": { - "decky-frontend-lib": "^3.7.14", + "decky-frontend-lib": "^3.14.0", "react-file-icon": "^1.2.0", "react-icons": "^4.4.0", "react-markdown": "^8.0.3", diff --git a/frontend/pnpm-lock.yaml b/frontend/pnpm-lock.yaml index cf33748b..d2d0f7ac 100644 --- a/frontend/pnpm-lock.yaml +++ b/frontend/pnpm-lock.yaml @@ -10,7 +10,7 @@ specifiers: '@types/react-file-icon': ^1.0.1 '@types/react-router': 5.1.18 '@types/webpack': ^5.28.0 - decky-frontend-lib: ^3.7.14 + decky-frontend-lib: ^3.14.0 husky: ^8.0.1 import-sort-style-module: ^6.0.0 inquirer: ^8.2.4 @@ -30,7 +30,7 @@ specifiers: typescript: ^4.7.4 dependencies: - decky-frontend-lib: 3.7.14 + decky-frontend-lib: 3.14.0 react-file-icon: 1.2.0_wcqkhtmu7mswc6yz4uyexck3ty react-icons: 4.4.0_react@16.14.0 react-markdown: 8.0.3_vshvapmxg47tngu7tvrsqpq55u @@ -944,8 +944,8 @@ packages: dependencies: ms: 2.1.2 - /decky-frontend-lib/3.7.14: - resolution: {integrity: sha512-ShAoP3VqiwkJYukDBHsOF9fk7wYw0VaKpHw6j9WdzLxwZwBcg0J7QBNIFYP3nfA0UgEwSJVEg/22kONiplipmA==} + /decky-frontend-lib/3.14.0: + resolution: {integrity: sha512-cBGgS960ftGgpF/oDlRj02nISWq7rwKHIUzG7RJeHchLmz/M4W4OwDL2/oEYO+0WeSx/AWRHTIfLU27jdHiZYQ==} dev: false /decode-named-character-reference/1.0.2: diff --git a/frontend/src/toaster.tsx b/frontend/src/toaster.tsx index 728bbdb8..1b2e9b80 100644 --- a/frontend/src/toaster.tsx +++ b/frontend/src/toaster.tsx @@ -1,4 +1,4 @@ -import { Patch, ToastData, afterPatch, findInReactTree, sleep } from 'decky-frontend-lib'; +import { Module, Patch, ToastData, afterPatch, findInReactTree, findModuleChild, sleep } from 'decky-frontend-lib'; import { ReactNode } from 'react'; import Toast from './components/Toast'; @@ -7,6 +7,7 @@ import Logger from './logger'; declare global { interface Window { __TOASTER_INSTANCE: any; + settingsStore: any; NotificationStore: any; } } @@ -16,7 +17,7 @@ class Toaster extends Logger { // private toasterState: DeckyToasterState = new DeckyToasterState(); private node: any; private rNode: any; - private settingsModule: any; + private audioModule: any; private finishStartup?: () => void; private ready: Promise = new Promise((res) => (this.finishStartup = res)); private toasterPatch?: Patch; @@ -127,6 +128,17 @@ class Toaster extends Logger { this.rNode.stateNode.forceUpdate(); delete this.rNode.stateNode.shouldComponentUpdate; + this.audioModule = findModuleChild((m: Module) => { + if (typeof m !== 'object') return undefined; + for (let prop in m) { + try { + if (m[prop].PlayNavSound && m[prop].RegisterCallbackOnPlaySound) return m[prop]; + } catch { + return undefined; + } + } + }); + this.log('Initialized'); this.finishStartup?.(); } @@ -135,24 +147,31 @@ class Toaster extends Logger { // toast.duration = toast.duration || 5e3; // this.toasterState.addToast(toast); await this.ready; - const settings = this.settingsModule?.settings; let toastData = { nNotificationID: window.NotificationStore.m_nNextTestNotificationID++, rtCreated: Date.now(), - eType: 15, + eType: toast.eType || 11, nToastDurationMS: toast.duration || (toast.duration = 5e3), data: toast, decky: true, }; // @ts-ignore toastData.data.appid = () => 0; + if (toast.sound === undefined) toast.sound = 6; + if (toast.playSound === undefined) toast.playSound = true; + if (toast.showToast === undefined) toast.showToast = true; if ( - (settings?.bDisableAllToasts && !toast.critical) || - (settings?.bDisableToastsInGame && !toast.critical && window.NotificationStore.BIsUserInGame()) + (window.settingsStore.settings.bDisableAllToasts && !toast.critical) || + (window.settingsStore.settings.bDisableToastsInGame && + !toast.critical && + window.NotificationStore.BIsUserInGame()) ) return; - window.NotificationStore.m_rgNotificationToasts.push(toastData); - window.NotificationStore.DispatchNextToast(); + if (toast.playSound) this.audioModule?.PlayNavSound(toast.sound); + if (toast.showToast) { + window.NotificationStore.m_rgNotificationToasts.push(toastData); + window.NotificationStore.DispatchNextToast(); + } } deinit() { From 2a6bf75f0232d96a687605b121c5a2da42c7f3b1 Mon Sep 17 00:00:00 2001 From: TrainDoctor Date: Sat, 10 Dec 2022 15:26:51 -0800 Subject: [PATCH 09/23] Move back to python 3.10.2 in CI --- .github/workflows/build.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index d90bd41a..df8b03f6 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -47,10 +47,10 @@ jobs: with: node-version: 18 - - name: Set up Python 3.10.9 🐍 + - name: Set up Python 3.10.2 🐍 uses: actions/setup-python@v4 with: - python-version: "3.10.9" + python-version: "3.10.2" - name: Install Python dependencies ⬇️ run: | From 346f80beb31d1e2a95d31a5997b5a233d08e0645 Mon Sep 17 00:00:00 2001 From: AAGaming Date: Thu, 15 Dec 2022 21:16:22 -0500 Subject: [PATCH 10/23] bump DFL to fix modals, Router -> Navigation in some places --- frontend/package.json | 2 +- frontend/pnpm-lock.yaml | 8 ++++---- frontend/src/components/modals/PluginInstallModal.tsx | 4 ++-- frontend/src/components/store/PluginCard.tsx | 6 +++--- frontend/src/developer.tsx | 6 ++++-- 5 files changed, 14 insertions(+), 12 deletions(-) diff --git a/frontend/package.json b/frontend/package.json index 6ca1d017..3e45e49a 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -41,7 +41,7 @@ } }, "dependencies": { - "decky-frontend-lib": "^3.14.0", + "decky-frontend-lib": "^3.18.4", "react-file-icon": "^1.2.0", "react-icons": "^4.4.0", "react-markdown": "^8.0.3", diff --git a/frontend/pnpm-lock.yaml b/frontend/pnpm-lock.yaml index d2d0f7ac..58fa64ce 100644 --- a/frontend/pnpm-lock.yaml +++ b/frontend/pnpm-lock.yaml @@ -10,7 +10,7 @@ specifiers: '@types/react-file-icon': ^1.0.1 '@types/react-router': 5.1.18 '@types/webpack': ^5.28.0 - decky-frontend-lib: ^3.14.0 + decky-frontend-lib: ^3.18.4 husky: ^8.0.1 import-sort-style-module: ^6.0.0 inquirer: ^8.2.4 @@ -30,7 +30,7 @@ specifiers: typescript: ^4.7.4 dependencies: - decky-frontend-lib: 3.14.0 + decky-frontend-lib: 3.18.4 react-file-icon: 1.2.0_wcqkhtmu7mswc6yz4uyexck3ty react-icons: 4.4.0_react@16.14.0 react-markdown: 8.0.3_vshvapmxg47tngu7tvrsqpq55u @@ -944,8 +944,8 @@ packages: dependencies: ms: 2.1.2 - /decky-frontend-lib/3.14.0: - resolution: {integrity: sha512-cBGgS960ftGgpF/oDlRj02nISWq7rwKHIUzG7RJeHchLmz/M4W4OwDL2/oEYO+0WeSx/AWRHTIfLU27jdHiZYQ==} + /decky-frontend-lib/3.18.4: + resolution: {integrity: sha512-i3TAe3RJtT1TK0rJgW9Ek5jxMWZRCYLDvqHDylGVieUvuyI7c8X+cogz30pP4cqeGOaA1d/MxBEbhlpD3JhVvg==} dev: false /decode-named-character-reference/1.0.2: diff --git a/frontend/src/components/modals/PluginInstallModal.tsx b/frontend/src/components/modals/PluginInstallModal.tsx index 8b927523..dfddc199 100644 --- a/frontend/src/components/modals/PluginInstallModal.tsx +++ b/frontend/src/components/modals/PluginInstallModal.tsx @@ -1,4 +1,4 @@ -import { ConfirmModal, QuickAccessTab, Router, Spinner, staticClasses } from 'decky-frontend-lib'; +import { ConfirmModal, Navigation, QuickAccessTab, Spinner, staticClasses } from 'decky-frontend-lib'; import { FC, useState } from 'react'; interface PluginInstallModalProps { @@ -20,7 +20,7 @@ const PluginInstallModal: FC = ({ artifact, version, ha onOK={async () => { setLoading(true); await onOK(); - setTimeout(() => Router.OpenQuickAccessMenu(QuickAccessTab.Decky), 250); + setTimeout(() => Navigation.OpenQuickAccessMenu(QuickAccessTab.Decky), 250); setTimeout(() => window.DeckyPluginLoader.checkPluginUpdates(), 1000); }} onCancel={async () => { diff --git a/frontend/src/components/store/PluginCard.tsx b/frontend/src/components/store/PluginCard.tsx index ffa2d1f1..27f98590 100644 --- a/frontend/src/components/store/PluginCard.tsx +++ b/frontend/src/components/store/PluginCard.tsx @@ -2,8 +2,8 @@ import { DialogButton, Dropdown, Focusable, + Navigation, QuickAccessTab, - Router, SingleDropdownOption, SuspensefulImage, joinClassNames, @@ -38,8 +38,8 @@ const PluginCard: FC = ({ plugin }) => { }} onCancel={(_: CustomEvent) => { if (containerRef.current!.querySelectorAll('* :focus').length === 0) { - Router.NavigateBackOrOpenMenu(); - setTimeout(() => Router.OpenQuickAccessMenu(QuickAccessTab.Decky), 1000); + Navigation.NavigateBack(); + setTimeout(() => Navigation.OpenQuickAccessMenu(QuickAccessTab.Decky), 1000); } else { containerRef.current!.focus(); } diff --git a/frontend/src/developer.tsx b/frontend/src/developer.tsx index 3b2812fc..e4e4b335 100644 --- a/frontend/src/developer.tsx +++ b/frontend/src/developer.tsx @@ -1,4 +1,5 @@ import { + Navigation, ReactRouter, Router, fakeRenderComponent, @@ -74,13 +75,14 @@ export async function startup() { window.DFL = { findModuleChild, findModule, + Navigation, + Router, + ReactRouter, ReactUtils: { fakeRenderComponent, findInReactTree, findInTree, }, - Router, - ReactRouter, classes: { scrollClasses, staticClasses, From 0474095a40ba6cb729064654d22efd88f91958d6 Mon Sep 17 00:00:00 2001 From: Nik Date: Fri, 16 Dec 2022 15:23:04 +0100 Subject: [PATCH 11/23] Potentially fix locale issues (#284) --- backend/browser.py | 4 ++-- backend/loader.py | 6 +++--- backend/plugin.py | 10 +++++----- backend/settings.py | 8 ++++---- backend/updater.py | 8 ++++---- 5 files changed, 18 insertions(+), 18 deletions(-) diff --git a/backend/browser.py b/backend/browser.py index 69f82bdb..f6cae5d3 100644 --- a/backend/browser.py +++ b/backend/browser.py @@ -55,7 +55,7 @@ class PluginBrowser: pluginBinPath = path.join(pluginBasePath, 'bin') if access(packageJsonPath, R_OK): - with open(packageJsonPath, 'r') as f: + with open(packageJsonPath, "r", encoding="utf-8") as f: packageJson = json.load(f) if "remote_binary" in packageJson and len(packageJson["remote_binary"]) > 0: # create bin directory if needed. @@ -93,7 +93,7 @@ class PluginBrowser: def find_plugin_folder(self, name): for folder in listdir(self.plugin_path): try: - with open(path.join(self.plugin_path, folder, 'plugin.json'), 'r') as f: + with open(path.join(self.plugin_path, folder, 'plugin.json'), "r", encoding="utf-8") as f: plugin = json.load(f) if plugin['name'] == name: diff --git a/backend/loader.py b/backend/loader.py index 2eeead36..48a66a8d 100644 --- a/backend/loader.py +++ b/backend/loader.py @@ -118,7 +118,7 @@ class Loader: def handle_frontend_bundle(self, request): plugin = self.plugins[request.match_info["plugin_name"]] - with open(path.join(self.plugin_path, plugin.plugin_directory, "dist/index.js"), 'r') as bundle: + with open(path.join(self.plugin_path, plugin.plugin_directory, "dist/index.js"), "r", encoding="utf-8") as bundle: return web.Response(text=bundle.read(), content_type="application/javascript") def import_plugin(self, file, plugin_directory, refresh=False, batch=False): @@ -186,7 +186,7 @@ class Loader: """ async def load_plugin_main_view(self, request): plugin = self.plugins[request.match_info["name"]] - with open(path.join(self.plugin_path, plugin.plugin_directory, plugin.main_view_html), 'r') as template: + with open(path.join(self.plugin_path, plugin.plugin_directory, plugin.main_view_html), "r", encoding="utf-8") as template: template_data = template.read() ret = f""" @@ -202,7 +202,7 @@ class Loader: self.logger.info(path) ret = "" file_path = path.join(self.plugin_path, plugin.plugin_directory, route_path) - with open(file_path, 'r') as resource_data: + with open(file_path, "r", encoding="utf-8") as resource_data: ret = resource_data.read() return web.Response(text=ret) diff --git a/backend/plugin.py b/backend/plugin.py index a1d8394a..e21d5bde 100644 --- a/backend/plugin.py +++ b/backend/plugin.py @@ -27,9 +27,9 @@ class PluginWrapper: self.version = None - json = load(open(path.join(plugin_path, plugin_directory, "plugin.json"), "r")) + json = load(open(path.join(plugin_path, plugin_directory, "plugin.json"), "r", encoding="utf-8")) if path.isfile(path.join(plugin_path, plugin_directory, "package.json")): - package_json = load(open(path.join(plugin_path, plugin_directory, "package.json"), "r")) + package_json = load(open(path.join(plugin_path, plugin_directory, "package.json"), "r", encoding="utf-8")) self.version = package_json["version"] @@ -112,7 +112,7 @@ class PluginWrapper: d["res"] = str(e) d["success"] = False finally: - writer.write((dumps(d)+"\n").encode("utf-8")) + writer.write((dumps(d, ensure_ascii=False)+"\n").encode("utf-8")) await writer.drain() async def _open_socket_if_not_exists(self): @@ -140,7 +140,7 @@ class PluginWrapper: return async def _(self): if await self._open_socket_if_not_exists(): - self.writer.write((dumps({"stop": True})+"\n").encode("utf-8")) + self.writer.write((dumps({ "stop": True }, ensure_ascii=False)+"\n").encode("utf-8")) await self.writer.drain() self.writer.close() get_event_loop().create_task(_(self)) @@ -151,7 +151,7 @@ class PluginWrapper: async with self.method_call_lock: if await self._open_socket_if_not_exists(): self.writer.write( - (dumps({"method": method_name, "args": kwargs})+"\n").encode("utf-8")) + (dumps({ "method": method_name, "args": kwargs }, ensure_ascii=False) + "\n").encode("utf-8")) await self.writer.drain() line = bytearray() while True: diff --git a/backend/settings.py b/backend/settings.py index d2cce769..6dedcbbe 100644 --- a/backend/settings.py +++ b/backend/settings.py @@ -35,22 +35,22 @@ class SettingsManager: self.settings = {} try: - open(self.path, "x") + open(self.path, "x", encoding="utf-8") except FileExistsError as e: self.read() pass def read(self): try: - with open(self.path, "r") as file: + with open(self.path, "r", encoding="utf-8") as file: self.settings = load(file) except Exception as e: print(e) pass def commit(self): - with open(self.path, "w+") as file: - dump(self.settings, file, indent=4) + with open(self.path, "w+", encoding="utf-8") as file: + dump(self.settings, file, indent=4, ensure_ascii=False) def getSetting(self, key, default): return self.settings.get(key, default) diff --git a/backend/updater.py b/backend/updater.py index 301ca396..15a93e8a 100644 --- a/backend/updater.py +++ b/backend/updater.py @@ -32,7 +32,7 @@ class Updater: self.allRemoteVers = None try: logger.info(getcwd()) - with open(path.join(getcwd(), ".loader.version"), 'r') as version_file: + with open(path.join(getcwd(), ".loader.version"), "r", encoding="utf-8") as version_file: self.localVer = version_file.readline().replace("\n", "") except: self.localVer = False @@ -159,10 +159,10 @@ class Updater: out.write(data) except Exception as e: logger.error(f"Error at %s", exc_info=e) - with open(path.join(getcwd(), "plugin_loader.service"), 'r') as service_file: + with open(path.join(getcwd(), "plugin_loader.service"), "r", encoding="utf-8") as service_file: service_data = service_file.read() service_data = service_data.replace("${HOMEBREW_FOLDER}", "/home/"+helpers.get_user()+"/homebrew") - with open(path.join(getcwd(), "plugin_loader.service"), 'w') as service_file: + with open(path.join(getcwd(), "plugin_loader.service"), "w", encoding="utf-8") as service_file: service_file.write(service_data) logger.debug("Saved service file") @@ -191,7 +191,7 @@ class Updater: self.context.loop.create_task(tab.evaluate_js(f"window.DeckyUpdater.updateProgress({new_progress})", False, False, False)) progress = new_progress - with open(path.join(getcwd(), ".loader.version"), "w") as out: + with open(path.join(getcwd(), ".loader.version"), "w", encoding="utf-8") as out: out.write(version) call(['chmod', '+x', path.join(getcwd(), "PluginLoader")]) From c2c9d11c668112c3cf315ceb645fb5fe5f7d6d07 Mon Sep 17 00:00:00 2001 From: AAGaming Date: Wed, 28 Dec 2022 12:23:42 -0500 Subject: [PATCH 12/23] fix broken valveInternal when on a multi-user deck --- frontend/src/developer.tsx | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/frontend/src/developer.tsx b/frontend/src/developer.tsx index e4e4b335..1d6b3fb2 100644 --- a/frontend/src/developer.tsx +++ b/frontend/src/developer.tsx @@ -27,13 +27,20 @@ const logger = new Logger('DeveloperMode'); let removeSettingsObserver: () => void = () => {}; -export function setShowValveInternal(show: boolean) { - const settingsMod = findModuleChild((m) => { - if (typeof m !== 'object') return undefined; - for (let prop in m) { - if (typeof m[prop]?.settings?.bIsValveEmail !== 'undefined') return m[prop]; +export async function setShowValveInternal(show: boolean) { + let settingsMod: any; + while (!settingsMod) { + settingsMod = findModuleChild((m) => { + if (typeof m !== 'object') return undefined; + for (let prop in m) { + if (typeof m[prop]?.settings?.bIsValveEmail !== 'undefined') return m[prop]; + } + }); + if (!settingsMod) { + logger.debug('[ValveInternal] waiting for settingsMod'); + await sleep(1000); } - }); + } if (show) { removeSettingsObserver = settingsMod[ From 385552451b84f0b49312eb466342238fadaaac24 Mon Sep 17 00:00:00 2001 From: AAGaming Date: Wed, 28 Dec 2022 12:24:28 -0500 Subject: [PATCH 13/23] shut down steam instead of restarting it to avoid broken CEF debugger (gamescope will restart stean for us instead) --- backend/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/main.py b/backend/main.py index c144c13a..b6cab774 100644 --- a/backend/main.py +++ b/backend/main.py @@ -176,7 +176,7 @@ class PluginManager: # logger.debug("Closing tab: " + getattr(t, "title", "Untitled")) # await t.close() # await sleep(0.5) - await tab.evaluate_js("try{if (window.deckyHasLoaded){setTimeout(() => SteamClient.User.StartRestart(), 100)}else{window.deckyHasLoaded = true;(async()=>{try{while(!window.SP_REACT){await new Promise(r => setTimeout(r, 10))};await import('http://localhost:1337/frontend/index.js')}catch(e){console.error(e)};})();}}catch(e){console.error(e)}", False, False, False) + await tab.evaluate_js("try{if (window.deckyHasLoaded){setTimeout(() => SteamClient.User.StartShutdown(false), 100)}else{window.deckyHasLoaded = true;(async()=>{try{while(!window.SP_REACT){await new Promise(r => setTimeout(r, 10))};await import('http://localhost:1337/frontend/index.js')}catch(e){console.error(e)};})();}}catch(e){console.error(e)}", False, False, False) except: logger.info("Failed to inject JavaScript into tab\n" + format_exc()) pass From 8810a014f3e1783c9b6c1ac2d1b83a0f5c38af10 Mon Sep 17 00:00:00 2001 From: AAGaming Date: Thu, 29 Dec 2022 13:11:11 -0500 Subject: [PATCH 14/23] somehow accidentally left this in --- frontend/src/tabs-hook.tsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/frontend/src/tabs-hook.tsx b/frontend/src/tabs-hook.tsx index a518c4c9..00adf206 100644 --- a/frontend/src/tabs-hook.tsx +++ b/frontend/src/tabs-hook.tsx @@ -23,7 +23,6 @@ class TabsHook extends Logger { tabs: Tab[] = []; private qAMRoot?: any; private qamPatch?: Patch; - private unsubscribeSecurity?: () => void; constructor() { super('TabsHook'); @@ -114,7 +113,6 @@ class TabsHook extends Logger { deinit() { this.qamPatch?.unpatch(); this.qAMRoot.return.alternate.type = this.qAMRoot.return.type; - this.unsubscribeSecurity?.(); } add(tab: Tab) { From 0ffef6e4bf4d7c191bcd281cc867ca468777988a Mon Sep 17 00:00:00 2001 From: Party Wumpus <48649272+PartyWumpus@users.noreply.github.com> Date: Mon, 2 Jan 2023 16:45:42 +0000 Subject: [PATCH 15/23] Better bug report format (#312) * Add files via upload * Delete bug_report.md * Update bug_report.yml * Update bug_report.yml * Update bug_report.yml * Update bug_report.yml * Update bug_report.yml * Update bug_report.yml * Update bug_report.yml --- .github/ISSUE_TEMPLATE/bug_report.md | 36 ------------- .github/ISSUE_TEMPLATE/bug_report.yml | 73 +++++++++++++++++++++++++++ .github/ISSUE_TEMPLATE/config.yml | 5 ++ 3 files changed, 78 insertions(+), 36 deletions(-) delete mode 100644 .github/ISSUE_TEMPLATE/bug_report.md create mode 100644 .github/ISSUE_TEMPLATE/bug_report.yml create mode 100644 .github/ISSUE_TEMPLATE/config.yml diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md deleted file mode 100644 index f30d5e5e..00000000 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ /dev/null @@ -1,36 +0,0 @@ ---- -name: Bug report -about: Create a report to help us improve -title: '' -labels: bug -assignees: '' - ---- - -**Description** -[A clear and concise description of what the bug is.] - -**To Reproduce** -Steps to reproduce the behavior: -1. Go to '...' -2. Click on '....' -3. Scroll down to '....' -4. See error - -**Expected behavior** -[A clear and concise description of what you expected to happen.] - -**Screenshots** -[If applicable, add screenshots to help explain your problem.] - -**Version information** - - SteamOS Version: ``[Run ``uname -a`` and place the output here. Leave the single quotations outside.]`` - - Selected Update Channel: [Stable, Beta or Preview.] - -**Logs** -[Please reboot your deck (if possible) when attempting to recreate the issue, then run -``cd ~ && journalctl -b0 -u plugin_loader.service > backendlog.txt``. This will save the log file to ``~`` aka ``/home/deck``. Please upload the file here in place of this textblock.] - -**Additional context** -Have you modified the read-only filesystem at any point? -[Yes or No.] diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml new file mode 100644 index 00000000..bca53714 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -0,0 +1,73 @@ +name: Bug report +description: File a bug/issue +title: "[BUG] " +labels: [bug] +body: + - type: checkboxes + id: low-effort-checks + attributes: + label: Please confirm + description: Issues without all checks may be ignored/closed. + options: + - label: I have searched existing issues + - label: This issue is not a duplicate of an existing one + - label: I have checked the [common issues section in the readme file](https://github.com/SteamDeckHomebrew/decky-loader#-common-issues) + + - type: textarea + attributes: + label: Bug Report Description + description: A clear and concise description of what the bug is and if possible, the steps you used to get to the bug. If appropriate, include screenshots or videos. + placeholder: | + When I try to use ... + + Steps to reproduce the behavior: + 1. Go to '...' + 2. Click on '....' + 3. Scroll down to '....' + 4. See error + validations: + required: true + + - type: textarea + attributes: + label: Expected Behaviour + description: A brief description of the expected behavior. + placeholder: It should be ... + validations: + required: true + + - type: input + attributes: + label: SteamOS version +# description: Can be found with `uname -a` +# placeholder: "Linux steamdeck 5.13.0-valve36-1-neptune #1 SMP PREEMPT Mon, 19 Dec 2022 23:39:41 +0000 x86_64 GNU/Linux" + placeholder: "SteamOS 3.4.3 Stable" + validations: + required: true + + - type: dropdown + attributes: + label: Selected Update Channel + description: Which branch of Decky are you on? + multiple: false + options: + - Stable + - Prerelease + validations: + required: true + + - type: input + attributes: + label: Have you modified the read-only filesystem at any point? + description: Describe how here, if you haven't done anything you can leave this blank + placeholder: Yes, I've installed neofetch via pacman. + validations: + required: false + + - type: textarea + attributes: + label: Logs + description: Please reboot your deck (if possible) when attempting to recreate the issue, then run ``cd ~ && journalctl -b0 -u plugin_loader.service > deckylog.txt``. This will save the log file to ``~`` aka ``/home/deck``. Please upload the file here + placeholder: deckylog.txt + validations: + required: false diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 00000000..e64c3c24 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,5 @@ +blank_issues_enabled: true +contact_links: + - name: Steam Deck Homebrew Discord Server + url: https://discord.gg/ZU74G2NJzk + about: Please ask and answer questions here. From 3bed83697ea03d3c036a621495a278c34030f51f Mon Sep 17 00:00:00 2001 From: Party Wumpus <48649272+PartyWumpus@users.noreply.github.com> Date: Mon, 2 Jan 2023 16:46:46 +0000 Subject: [PATCH 16/23] Add cef debugging to the installer scripts (#310) * Update install_prerelease.sh * Update install_release.sh --- dist/install_prerelease.sh | 1 + dist/install_release.sh | 1 + 2 files changed, 2 insertions(+) diff --git a/dist/install_prerelease.sh b/dist/install_prerelease.sh index 97c78916..19a8ab04 100644 --- a/dist/install_prerelease.sh +++ b/dist/install_prerelease.sh @@ -11,6 +11,7 @@ HOMEBREW_FOLDER="${USER_DIR}/homebrew" rm -rf "${HOMEBREW_FOLDER}/services" sudo -u $SUDO_USER mkdir -p "${HOMEBREW_FOLDER}/services" sudo -u $SUDO_USER mkdir -p "${HOMEBREW_FOLDER}/plugins" +touch "${USER_DIR}/.steam/steam/.cef-enable-remote-debugging" # Download latest release and install it RELEASE=$(curl -s 'https://api.github.com/repos/SteamDeckHomebrew/decky-loader/releases' | jq -r "first(.[] | select(.prerelease == "true"))") diff --git a/dist/install_release.sh b/dist/install_release.sh index 58f88d97..36bc3247 100644 --- a/dist/install_release.sh +++ b/dist/install_release.sh @@ -11,6 +11,7 @@ HOMEBREW_FOLDER="${USER_DIR}/homebrew" rm -rf "${HOMEBREW_FOLDER}/services" sudo -u $SUDO_USER mkdir -p "${HOMEBREW_FOLDER}/services" sudo -u $SUDO_USER mkdir -p "${HOMEBREW_FOLDER}/plugins" +touch "${USER_DIR}/.steam/steam/.cef-enable-remote-debugging" # Download latest release and install it RELEASE=$(curl -s 'https://api.github.com/repos/SteamDeckHomebrew/decky-loader/releases' | jq -r "first(.[] | select(.prerelease == "false"))") From 80b6115f6fa98d4da03b3586894aeb5926f2a297 Mon Sep 17 00:00:00 2001 From: Party Wumpus <48649272+PartyWumpus@users.noreply.github.com> Date: Mon, 2 Jan 2023 16:52:11 +0000 Subject: [PATCH 17/23] User Friendlier Installer (#297) * Add files via upload * Rename EasierInstallScript.sh to user_install_script.sh * Add files via upload * change so it works on deck instead of my desktop * Update decky_installer.desktop * make auto password setter work without the password * Update user_install_script.sh * make installer exit properly if user does not accept temp password * Update user_install_script.sh * add uninstall option * Update user_install_script.sh * Update user_install_script.sh * Update user_install_script.sh * "optimisation" * Update user_install_script.sh * Add sizing to all zenity prompts * "optimization" part 2 * "Program now runs 50% faster" :) * Update user_install_script.sh * Update user_install_script.sh * Update user_install_script.sh * Change text in branch selection in installer 'Select Branch' if choosing between release and prerelease 'Select Option' if choosing between release, prerelease and uninstall * .desktop file points at where script is going to be * add comments * Change "installing" to "uninstalling" * change it to ask for "sudo/admin" password * Add secondary loading bar for download progress Shamelessly stolen (with permission) from emudeck, who stole it from a random blog No I don't know how that line works, and I don't think I want to. * Make uninstaller tell user they can exit * add default text to the download bar just in case * silence script download * silence password check --- dist/decky_installer.desktop | 8 ++ dist/user_install_script.sh | 164 +++++++++++++++++++++++++++++++++++ 2 files changed, 172 insertions(+) create mode 100644 dist/decky_installer.desktop create mode 100644 dist/user_install_script.sh diff --git a/dist/decky_installer.desktop b/dist/decky_installer.desktop new file mode 100644 index 00000000..07e3b6d5 --- /dev/null +++ b/dist/decky_installer.desktop @@ -0,0 +1,8 @@ +#!/usr/bin/env xdg-open +[Desktop Entry] +Name=Install Decky +Exec=sh -c 'curl -O --output-dir /tmp/ https://raw.githubusercontent.com/SteamDeckHomebrew/decky-loader/main/dist/user_install_script.sh 2> /dev/null && bash /tmp/user_install_script.sh' +Icon=steamdeck-gaming-return +Terminal=true +Type=Application +StartupNotify=false diff --git a/dist/user_install_script.sh b/dist/user_install_script.sh new file mode 100644 index 00000000..34dadd40 --- /dev/null +++ b/dist/user_install_script.sh @@ -0,0 +1,164 @@ +#!/bin/sh + +# if a password was set by decky, this will run when the program closes +temp_pass_cleanup() { + echo $PASS | sudo -S -k passwd -d deck +} + +# if the script is not root yet, get the password and rerun as root +if (( $EUID != 0 )); then + PASS_STATUS=$(passwd -S deck 2> /dev/null) + if [ "$PASS_STATUS" = "" ]; then + echo "Deck user not found. Continuing anyway, as it probably just means user is on a non-steamos system." + fi + + if [ "${PASS_STATUS:5:2}" = "NP" ]; then # if no password is set + if ( zenity --title="Decky Installer" --width=300 --height=200 --question --text="You appear to have not set an admin password.\nDecky can still install by temporarily setting your password to 'Decky!' and continuing, then removing it when the installer finishes\nAre you okay with that?" ); then + yes "Decky!" | passwd deck + trap temp_pass_cleanup EXIT # make sure password is removed when application closes + PASS="Decky!" + else exit 1; fi + else + # get password + FINISHED="false" + while [ "$FINISHED" != "true" ]; do + PASS=$(zenity --title="Decky Installer" --width=300 --height=100 --entry --hide-text --text="Enter your sudo/admin password") + if [[ $? -eq 1 ]] || [[ $? -eq 5 ]]; then + exit 1 + fi + if ( echo "$PASS" | sudo -S -k true ); then + FINISHED="true" + else + zenity --title="Decky Installer" --width=150 --height=40 --info --text "Incorrect Password" + fi + done + fi + + if ! [ $USER = "deck" ]; then + zenity --title="Decky Installer" --width=300 --height=100 --warning --text "You appear to not be on a deck.\nDecky should still mostly work, but you may not get full functionality." + fi + + # get user dir before rerunning as root, otherwise it'll just be 'home/root' + USER_DIR="$(getent passwd $USER | cut -d: -f6)" + HOMEBREW_FOLDER="${USER_DIR}/homebrew" + echo "$PASS" | sudo -S -k sh "$0" "$USER_DIR" "$HOMEBREW_FOLDER" # rerun script as root + exit 1 +fi + +# all code below should be run as root +USER_DIR=$1 +HOMEBREW_FOLDER=$2 + +# if decky is already installed, then also add an 'uninstall' prompt +if [[ -f "${USER_DIR}/homebrew/services/PluginLoader" ]] ; then + BRANCH=$(zenity --title="Decky Installer" --width=360 --height=170 --list --radiolist --text "Select Option:" --hide-header --column "Buttons" --column "Choice" --column "Info" TRUE "release" "(Recommended option)" FALSE "prerelease" "(May be unstable)" FALSE "uninstall decky loader" "") +else + BRANCH=$(zenity --title="Decky Installer" --width=300 --height=100 --list --radiolist --text "Select Branch:" --hide-header --column "Buttons" --column "Choice" --column "Info" TRUE "release" "(Recommended option)" FALSE "prerelease" "(May be unstable)" ) +fi +if [[ $? -eq 1 ]] || [[ $? -eq 5 ]]; then + exit 1 +fi + +# uninstall if uninstall option was selected +if [ "$BRANCH" == "uninstall decky loader" ] ; then + ( + echo "30" ; echo "# Disabling and removing services" ; + sudo systemctl disable --now plugin_loader.service > /dev/null + sudo rm -f "${USER_DIR}/.config/systemd/user/plugin_loader.service" + sudo rm -f "/etc/systemd/system/plugin_loader.service" + + echo "60" ; echo "# Removing Temporary Files" ; + rm -rf "/tmp/plugin_loader" + rm -rf "/tmp/user_install_script.sh" + + echo "90" ; echo "# Cleaning services folder" ; + sudo rm "${HOMEBREW_FOLDER}/services/PluginLoader" + echo "100" ; echo "# Uninstall finished, installer can now be closed"; + ) | + zenity --progress \ + --title="Decky Installer" \ + --width=300 --height=100 \ + --text="Uninstalling..." \ + --percentage=0 \ + --no-cancel + exit 1 +fi + +# otherwise install decky loader +( +echo "15" ; echo "# Creating file structure" ; +rm -rf "${HOMEBREW_FOLDER}/services" +sudo mkdir -p "${HOMEBREW_FOLDER}/services" +sudo mkdir -p "${HOMEBREW_FOLDER}/plugins" +touch "${USER_DIR}/.steam/steam/.cef-enable-remote-debugging" + +echo "30" ; echo "# Finding latest $BRANCH"; +if [ $BRANCH = 'prerelease' ] ; then + RELEASE=$(curl -s 'https://api.github.com/repos/SteamDeckHomebrew/decky-loader/releases' | jq -r "first(.[] | select(.prerelease == "true"))") +else + RELEASE=$(curl -s 'https://api.github.com/repos/SteamDeckHomebrew/decky-loader/releases' | jq -r "first(.[] | select(.prerelease == "false"))") +fi +read VERSION DOWNLOADURL < <(echo $(jq -r '.tag_name, .assets[].browser_download_url' <<< ${RELEASE})) + +echo "45" ; echo "# Installing version $VERSION" ; +curl -L $DOWNLOADURL -o ${HOMEBREW_FOLDER}/services/PluginLoader 2>&1 | stdbuf -oL tr '\r' '\n' | sed -u 's/^ *\([0-9][0-9]*\).*\( [0-9].*$\)/\1\n#Download Speed\:\2/' | zenity --progress --title "Downloading Decky" --text="Download Speed: 0" --width=300 --height=100 --auto-close --no-cancel 2>/dev/null +chmod +x ${HOMEBREW_FOLDER}/services/PluginLoader +echo $VERSION > ${HOMEBREW_FOLDER}/services/.loader.version + +echo "70" ; echo "# Kiling plugin_loader if it exists" ; +systemctl --user stop plugin_loader 2> /dev/null +systemctl --user disable plugin_loader 2> /dev/null +systemctl stop plugin_loader 2> /dev/null +systemctl disable plugin_loader 2> /dev/null + +echo "85" ; echo "# Setting up systemd" ; +curl -L https://raw.githubusercontent.com/SteamDeckHomebrew/decky-loader/main/dist/plugin_loader-${BRANCH}.service --output ${HOMEBREW_FOLDER}/services/plugin_loader-${BRANCH}.service +cat > "${HOMEBREW_FOLDER}/services/plugin_loader-backup.service" <<- EOM +[Unit] +Description=SteamDeck Plugin Loader +After=network-online.target +Wants=network-online.target +[Service] +Type=simple +User=root +Restart=always +ExecStart=${HOMEBREW_FOLDER}/services/PluginLoader +WorkingDirectory=${HOMEBREW_FOLDER}/services +KillSignal=SIGKILL +Environment=PLUGIN_PATH=${HOMEBREW_FOLDER}/plugins +Environment=LOG_LEVEL=INFO +[Install] +WantedBy=multi-user.target +EOM + +# if .service file doesn't exist for whatever reason, use backup file instead +if [[ -f "${HOMEBREW_FOLDER}/services/plugin_loader-${BRANCH}.service" ]]; then + printf "Grabbed latest ${BRANCH} service.\n" + sed -i -e "s|\${HOMEBREW_FOLDER}|${HOMEBREW_FOLDER}|" "${HOMEBREW_FOLDER}/services/plugin_loader-${BRANCH}.service" + cp -f "${HOMEBREW_FOLDER}/services/plugin_loader-${BRANCH}.service" "/etc/systemd/system/plugin_loader.service" +else + printf "Could not curl latest ${BRANCH} systemd service, using built-in service as a backup!\n" + rm -f "/etc/systemd/system/plugin_loader.service" + cp "${HOMEBREW_FOLDER}/services/plugin_loader-backup.service" "/etc/systemd/system/plugin_loader.service" +fi + +mkdir -p ${HOMEBREW_FOLDER}/services/.systemd +cp ${HOMEBREW_FOLDER}/services/plugin_loader-${BRANCH}.service ${HOMEBREW_FOLDER}/services/.systemd/plugin_loader-${BRANCH}.service +cp ${HOMEBREW_FOLDER}/services/plugin_loader-backup.service ${HOMEBREW_FOLDER}/services/.systemd/plugin_loader-backup.service +rm ${HOMEBREW_FOLDER}/services/plugin_loader-backup.service ${HOMEBREW_FOLDER}/services/plugin_loader-${BRANCH}.service + +systemctl daemon-reload +systemctl start plugin_loader +systemctl enable plugin_loader +echo "100" ; echo "# Install finished, installer can now be closed"; +) | +zenity --progress \ + --title="Decky Installer" \ + --width=300 --height=100 \ + --text="Installing..." \ + --percentage=0 \ + --no-cancel # not actually sure how to make the cancel work properly, so it's just not there unless someone else can figure it out + +if [ "$?" = -1 ] ; then + zenity --title="Decky Installer" --width=150 --height=70 --error --text="Download interrupted." +fi From 34af3400097bb6a729665843cb19c30fd96a5a64 Mon Sep 17 00:00:00 2001 From: TrainDoctor <traindoctor@protonmail.com> Date: Thu, 5 Jan 2023 18:50:10 -0800 Subject: [PATCH 18/23] Update config.yml --- .github/ISSUE_TEMPLATE/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index e64c3c24..87f64b7c 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -1,4 +1,4 @@ -blank_issues_enabled: true +blank_issues_enabled: false contact_links: - name: Steam Deck Homebrew Discord Server url: https://discord.gg/ZU74G2NJzk From 880b4c2f8f56ce43dcf792245fc1b3547a4e8ab2 Mon Sep 17 00:00:00 2001 From: AAGaming <aa@mail.catvibers.me> Date: Thu, 5 Jan 2023 23:00:48 -0500 Subject: [PATCH 19/23] maybe working fix for jan 05 beta (#316) --- backend/injector.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/injector.py b/backend/injector.py index ec7f0aa9..f4dfd384 100644 --- a/backend/injector.py +++ b/backend/injector.py @@ -396,7 +396,7 @@ async def get_tab_lambda(test) -> Tab: async def get_gamepadui_tab() -> Tab: tabs = await get_tabs() - tab = next((i for i in tabs if ("https://steamloopback.host/routes/" in i.url and (i.title == "Steam" or i.title == "SP"))), None) + tab = next((i for i in tabs if ("https://steamloopback.host/routes/" in i.url and (i.title == "Steam Shared Context presented by Valveβ„’" or i.title == "Steam" or i.title == "SP"))), None) if not tab: raise ValueError(f"GamepadUI Tab not found") return tab From b8fdff80933b0164096c94358ab8123722906e0d Mon Sep 17 00:00:00 2001 From: Party Wumpus <48649272+PartyWumpus@users.noreply.github.com> Date: Fri, 6 Jan 2023 17:23:05 +0000 Subject: [PATCH 20/23] Add feature requests as an issue template (#318) * Create feature_request.yml * Update feature_request.yml --- .github/ISSUE_TEMPLATE/feature_request.yml | 35 ++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/feature_request.yml diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml new file mode 100644 index 00000000..c3985545 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -0,0 +1,35 @@ +name: Feature request +description: Request a new feature (NOT A PLUGIN) +title: "[Request] <title>" +labels: [feature request] +body: + - type: checkboxes + id: low-effort-checks + attributes: + label: Please confirm + description: Issues without all checks may be ignored/closed. + options: + - label: I have searched existing issues + - label: This issue is not a duplicate of an existing one + - label: This is not a request for a plugin + + - type: textarea + attributes: + label: Feature Request Description + description: A clear and concise description of what the new feature. + placeholder: | + Decky plugins should be sortable in the quick access menu + validations: + required: true + + - type: textarea + attributes: + label: Further Description + description: A further explanation of the feature. If appropriate, include screenshots or videos. + placeholder: | + This would help make the UI clearer and easier to use as there is less clutter in the QAM. + It would also make it faster to access plugins that are used more. + + This could be implemented by adding ... + validations: + required: false From b72b32761058767d143e9ff08dc238c5ac9b777c Mon Sep 17 00:00:00 2001 From: AAGaming <aa@mail.catvibers.me> Date: Sat, 7 Jan 2023 20:33:28 -0500 Subject: [PATCH 21/23] Fix reloading UI on updates and restarting steam (#303) --- backend/main.py | 18 +++--- frontend/rollup.config.js | 27 ++++----- .../modals/filepicker/patches/library.ts | 42 ++++++++----- frontend/src/plugin-loader.tsx | 8 +-- frontend/src/steamfixes/README.md | 13 ++++ frontend/src/steamfixes/index.ts | 12 ++++ frontend/src/steamfixes/reload.ts | 14 +++++ frontend/src/steamfixes/restart.ts | 60 +++++++++++++++++++ frontend/src/tabs-hook.tsx | 1 - 9 files changed, 151 insertions(+), 44 deletions(-) create mode 100644 frontend/src/steamfixes/README.md create mode 100644 frontend/src/steamfixes/index.ts create mode 100644 frontend/src/steamfixes/reload.ts create mode 100644 frontend/src/steamfixes/restart.ts diff --git a/backend/main.py b/backend/main.py index b6cab774..b99e7df1 100644 --- a/backend/main.py +++ b/backend/main.py @@ -168,15 +168,15 @@ class PluginManager: async def inject_javascript(self, tab: Tab, first=False, request=None): logger.info("Loading Decky frontend!") try: - # if first: - # if await tab.has_global_var("deckyHasLoaded", False): - # tabs = await get_tabs() - # for t in tabs: - # if t.title != "Steam" and t.title != "SP": - # logger.debug("Closing tab: " + getattr(t, "title", "Untitled")) - # await t.close() - # await sleep(0.5) - await tab.evaluate_js("try{if (window.deckyHasLoaded){setTimeout(() => SteamClient.User.StartShutdown(false), 100)}else{window.deckyHasLoaded = true;(async()=>{try{while(!window.SP_REACT){await new Promise(r => setTimeout(r, 10))};await import('http://localhost:1337/frontend/index.js')}catch(e){console.error(e)};})();}}catch(e){console.error(e)}", False, False, False) + if first: + if await tab.has_global_var("deckyHasLoaded", False): + tabs = await get_tabs() + for t in tabs: + if not t.title or (t.title != "Steam" and t.title != "SP"): + logger.debug("Closing tab: " + getattr(t, "title", "Untitled")) + await t.close() + await sleep(0.5) + await tab.evaluate_js("try{if (window.deckyHasLoaded){setTimeout(() => location.reload(), 100)}else{window.deckyHasLoaded = true;(async()=>{try{while(!window.SP_REACT){await new Promise(r => setTimeout(r, 10))};await import('http://localhost:1337/frontend/index.js')}catch(e){console.error(e)};})();}}catch(e){console.error(e)}", False, False, False) except: logger.info("Failed to inject JavaScript into tab\n" + format_exc()) pass diff --git a/frontend/rollup.config.js b/frontend/rollup.config.js index 00487d72..fc924c36 100644 --- a/frontend/rollup.config.js +++ b/frontend/rollup.config.js @@ -1,30 +1,27 @@ import commonjs from '@rollup/plugin-commonjs'; import json from '@rollup/plugin-json'; import { nodeResolve } from '@rollup/plugin-node-resolve'; -import externalGlobals from "rollup-plugin-external-globals"; -import del from 'rollup-plugin-delete' import replace from '@rollup/plugin-replace'; import typescript from '@rollup/plugin-typescript'; import { defineConfig } from 'rollup'; +import del from 'rollup-plugin-delete'; +import externalGlobals from 'rollup-plugin-external-globals'; -const hiddenWarnings = [ - "THIS_IS_UNDEFINED", - "EVAL" -]; +const hiddenWarnings = ['THIS_IS_UNDEFINED', 'EVAL']; export default defineConfig({ input: 'src/index.tsx', plugins: [ - del({ targets: "../backend/static/*", force: true }), + del({ targets: '../backend/static/*', force: true }), commonjs(), nodeResolve(), externalGlobals({ react: 'SP_REACT', 'react-dom': 'SP_REACTDOM', // hack to shut up react-markdown - 'process': '{cwd: () => {}}', - 'path': '{dirname: () => {}, join: () => {}, basename: () => {}, extname: () => {}}', - 'url': '{fileURLToPath: (f) => f}' + process: '{cwd: () => {}}', + path: '{dirname: () => {}, join: () => {}, basename: () => {}, extname: () => {}}', + url: '{fileURLToPath: (f) => f}', }), typescript(), json(), @@ -38,11 +35,11 @@ export default defineConfig({ dir: '../backend/static', format: 'esm', chunkFileNames: (chunkInfo) => { - return 'chunk-[hash].js' - } + return 'chunk-[hash].js'; + }, }, - onwarn: function ( message, handleWarning ) { - if (hiddenWarnings.some(warning => message.code === warning)) return; + onwarn: function (message, handleWarning) { + if (hiddenWarnings.some((warning) => message.code === warning)) return; handleWarning(message); - } + }, }); diff --git a/frontend/src/components/modals/filepicker/patches/library.ts b/frontend/src/components/modals/filepicker/patches/library.ts index c9c7d53c..3abf824b 100644 --- a/frontend/src/components/modals/filepicker/patches/library.ts +++ b/frontend/src/components/modals/filepicker/patches/library.ts @@ -1,4 +1,8 @@ -import { Patch, findModuleChild, replacePatch } from 'decky-frontend-lib'; +import { Patch, findModuleChild, replacePatch, sleep } from 'decky-frontend-lib'; + +import Logger from '../../../../logger'; + +const logger = new Logger('LibraryPatch'); declare global { interface Window { @@ -10,36 +14,44 @@ declare global { let patch: Patch; function rePatch() { - // If you patch anything on SteamClient within the first few seconds of the client having loaded it will get redefined for some reason, so repatch any of these changes that occur within the first 20s of the last patch + // If you patch anything on SteamClient within the first few seconds of the client having loaded it will get redefined for some reason, so repatch any of these changes that occur with History.listen or an interval patch = replacePatch(window.SteamClient.Apps, 'PromptToChangeShortcut', async ([appid]: number[]) => { try { const details = window.appDetailsStore.GetAppDetails(appid); - console.log(details); + logger.debug('game details', details); // strShortcutStartDir const file = await window.DeckyPluginLoader.openFilePicker(details.strShortcutStartDir.replaceAll('"', '')); - console.log('user selected', file); + logger.debug('user selected', file); window.SteamClient.Apps.SetShortcutExe(appid, JSON.stringify(file.path)); const pathArr = file.path.split('/'); pathArr.pop(); const folder = pathArr.join('/'); window.SteamClient.Apps.SetShortcutStartDir(appid, JSON.stringify(folder)); } catch (e) { - console.error(e); + logger.error(e); } }); } -// TODO type and add to frontend-lib -const History = findModuleChild((m) => { - if (typeof m !== 'object') return undefined; - for (let prop in m) { - if (m[prop]?.m_history) return m[prop].m_history; - } -}); - export default async function libraryPatch() { try { rePatch(); + // TODO type and add to frontend-lib + let History: any; + + while (!History) { + History = findModuleChild((m) => { + if (typeof m !== 'object') return undefined; + for (let prop in m) { + if (m[prop]?.m_history) return m[prop].m_history; + } + }); + if (!History) { + logger.debug('Waiting 5s for history to become available.'); + await sleep(5000); + } + } + const unlisten = History.listen(() => { if (window.SteamClient.Apps.PromptToChangeShortcut !== patch.patchedFunction) { rePatch(); @@ -47,11 +59,11 @@ export default async function libraryPatch() { }); return () => { - patch.unpatch(); unlisten(); + patch.unpatch(); }; } catch (e) { - console.error('Error patching library file picker', e); + logger.error('Error patching library file picker', e); } return () => {}; } diff --git a/frontend/src/plugin-loader.tsx b/frontend/src/plugin-loader.tsx index 381d7954..c37e168c 100644 --- a/frontend/src/plugin-loader.tsx +++ b/frontend/src/plugin-loader.tsx @@ -21,6 +21,7 @@ import WithSuspense from './components/WithSuspense'; import Logger from './logger'; import { Plugin } from './plugin'; import RouterHook from './router-hook'; +import { deinitSteamFixes, initSteamFixes } from './steamfixes'; import { checkForUpdates } from './store'; import TabsHook from './tabs-hook'; import OldTabsHook from './tabs-hook.old'; @@ -33,10 +34,6 @@ const SettingsPage = lazy(() => import('./components/settings')); const FilePicker = lazy(() => import('./components/modals/filepicker')); -declare global { - interface Window {} -} - class PluginLoader extends Logger { private plugins: Plugin[] = []; private tabsHook: TabsHook | OldTabsHook = document.title == 'SP' ? new OldTabsHook() : new TabsHook(); @@ -92,6 +89,8 @@ class PluginLoader extends Logger { ); }); + initSteamFixes(); + initFilepickerPatches(); this.updateVersion(); @@ -184,6 +183,7 @@ class PluginLoader extends Logger { public deinit() { this.routerHook.removeRoute('/decky/store'); this.routerHook.removeRoute('/decky/settings'); + deinitSteamFixes(); deinitFilepickerPatches(); this.focusWorkaroundPatch?.unpatch(); } diff --git a/frontend/src/steamfixes/README.md b/frontend/src/steamfixes/README.md new file mode 100644 index 00000000..97098889 --- /dev/null +++ b/frontend/src/steamfixes/README.md @@ -0,0 +1,13 @@ +## What's this? + +`steamfixes` contains various fixes and workaround for things Valve has broken that cause Decky issues. + +## Current fixes: + +- StartRestart() -> StartShutdown(false) override: + + StartRestart() breaks CEF debugging, StartShutdown(false) doesn't. We can safely replace StartRestart() with StartShutdown(false) as gamescope-session will automatically restart the steam client anyway if it shuts down, bypassing the broken restart codepath. Added 12/29/2022 + +- ExecuteSteamURL UI reload fix: + + Starting sometime in November 2022, Valve broke reloading the Steam UI pages via location.reload, as it won't properly start the UI. We can manually trigger UI startup if we detect no active input contexts by calling `SteamClient.URL.ExecuteSteamURL("steam://open/settings/")` Added 12/29/2022 diff --git a/frontend/src/steamfixes/index.ts b/frontend/src/steamfixes/index.ts new file mode 100644 index 00000000..988f3bd7 --- /dev/null +++ b/frontend/src/steamfixes/index.ts @@ -0,0 +1,12 @@ +import reloadFix from './reload'; +import restartFix from './restart'; +let fixes: Function[] = []; + +export function deinitSteamFixes() { + fixes.forEach((deinit) => deinit()); +} + +export async function initSteamFixes() { + fixes.push(reloadFix()); + fixes.push(await restartFix()); +} diff --git a/frontend/src/steamfixes/reload.ts b/frontend/src/steamfixes/reload.ts new file mode 100644 index 00000000..e31f78fc --- /dev/null +++ b/frontend/src/steamfixes/reload.ts @@ -0,0 +1,14 @@ +import Logger from '../logger'; + +const logger = new Logger('ReloadSteamFix'); + +export default function reloadFix() { + // Hack to unbreak the ui when reloading it + if (window.FocusNavController?.m_rgAllContexts?.length == 0) { + SteamClient.URL.ExecuteSteamURL('steam://open/settings'); + logger.log('Applied UI reload fix.'); + } + + // This steamfix does not need to deinit. + return () => {}; +} diff --git a/frontend/src/steamfixes/restart.ts b/frontend/src/steamfixes/restart.ts new file mode 100644 index 00000000..467efd6a --- /dev/null +++ b/frontend/src/steamfixes/restart.ts @@ -0,0 +1,60 @@ +import { Patch, findModuleChild, replacePatch, sleep } from 'decky-frontend-lib'; + +import Logger from '../logger'; + +const logger = new Logger('RestartSteamFix'); + +declare global { + interface Window { + SteamClient: any; + appDetailsStore: any; + } +} + +let patch: Patch; + +function rePatch() { + // If you patch anything on SteamClient within the first few seconds of the client having loaded it will get redefined for some reason, so repatch any of these changes that occur with History.listen or an interval + patch = replacePatch(window.SteamClient.User, 'StartRestart', () => SteamClient.User.StartShutdown(false)); +} + +export default async function restartFix() { + try { + rePatch(); + // TODO type and add to frontend-lib + let History: any; + + while (!History) { + History = findModuleChild((m) => { + if (typeof m !== 'object') return undefined; + for (let prop in m) { + if (m[prop]?.m_history) return m[prop].m_history; + } + }); + if (!History) { + logger.debug('Waiting 5s for history to become available.'); + await sleep(5000); + } + } + + function repatchIfNeeded() { + if (window.SteamClient.User.StartRestart !== patch.patchedFunction) { + rePatch(); + } + } + + const unlisten = History.listen(repatchIfNeeded); + + // Just in case + setTimeout(repatchIfNeeded, 5000); + setTimeout(repatchIfNeeded, 10000); + + return () => { + unlisten(); + patch.unpatch(); + }; + } catch (e) { + logger.error('Error patching StartRestart', e); + } + return () => {}; +} diff --git a/frontend/src/tabs-hook.tsx b/frontend/src/tabs-hook.tsx index 00adf206..d9c76ca6 100644 --- a/frontend/src/tabs-hook.tsx +++ b/frontend/src/tabs-hook.tsx @@ -7,7 +7,6 @@ import Logger from './logger'; declare global { interface Window { __TABS_HOOK_INSTANCE: any; - securitystore: any; } } From e92b66068aaa3f43e65e187e09f0982c798e960a Mon Sep 17 00:00:00 2001 From: Party Wumpus <48649272+PartyWumpus@users.noreply.github.com> Date: Sun, 8 Jan 2023 21:16:44 +0000 Subject: [PATCH 22/23] Use the new installer in the readme instructions (#324) --- .github/workflows/build.yml | 8 ++++++-- README.md | 25 +++++++++++++------------ dist/install_prerelease.sh | 3 ++- dist/install_release.sh | 3 ++- dist/user_install_script.sh | 3 ++- docs/images/download_button.png | Bin 0 -> 11118 bytes 6 files changed, 25 insertions(+), 17 deletions(-) create mode 100644 docs/images/download_button.png diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index df8b03f6..6e548411 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -161,7 +161,9 @@ jobs: with: name: Prerelease ${{ steps.ready_tag.outputs.tag_name }} tag_name: ${{ steps.ready_tag.outputs.tag_name }} - files: ./dist/PluginLoader + files: | + ./dist/PluginLoader + ${{ github.workspace }}/dist/decky_installer.desktop prerelease: false generate_release_notes: true @@ -248,6 +250,8 @@ jobs: with: name: Prerelease ${{ steps.ready_tag.outputs.tag_name }} tag_name: ${{ steps.ready_tag.outputs.tag_name }} - files: ./dist/PluginLoader + files: | + ./dist/PluginLoader + ${{ github.workspace }}/dist/decky_installer.desktop prerelease: true generate_release_notes: true diff --git a/README.md b/README.md index d05209d5..3208887c 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,8 @@ <a name="logo" href="https://deckbrew.xyz/"><img src="https://deckbrew.xyz/logo.png" alt="Deckbrew logo" width="200"></a> <br> Decky Loader + <br> + <a name="logo" href="https://github.com/SteamDeckHomebrew/decky-loader/releases/latest/download/decky_installer.desktop"><img src="./docs/images/download_button.png" alt="Download decky" width="350"></a> </h1> <p align="center"> @@ -36,11 +38,7 @@ For more information about Decky Loader as well as documentation and development - If you are using any software that uses port 1337 or 8080, please change its port to something else or uninstall it. ## πŸ’Ύ Installation - -1. Press the <img src="./docs/images/light/steam.svg#gh-dark-mode-only" height=16><img src="./docs/images/dark/steam.svg#gh-light-mode-only" height=16> button and open the Settings menu. -1. Navigate to the System menu and scroll to the System Settings. Toggle "Enable Developer Mode" so it is enabled. -1. Navigate to the Developer menu and scroll to Miscellaneous. Toggle "CEF Remote Debugging" so it is enabled. -1. Select "Restart Now" to apply your changes. +- This installation can be done without an admin/sudo password set. 1. Prepare a mouse and keyboard if possible. - Keyboards and mice can be connected to the Steam Deck via USB-C or Bluetooth. - Many Bluetooth keyboard and mouse apps are available for iOS and Android. @@ -48,24 +46,27 @@ For more information about Decky Loader as well as documentation and development - If you have no other options, use the right trackpad as a mouse and press <img src="./docs/images/light/steam.svg#gh-dark-mode-only" height=16><img src="./docs/images/dark/steam.svg#gh-light-mode-only" height=16>+<img src="./docs/images/light/x.svg#gh-dark-mode-only" height=16><img src="./docs/images/dark/x.svg#gh-light-mode-only" height=16> to open the on-screen keyboard as needed. 1. Press the <img src="./docs/images/light/steam.svg#gh-dark-mode-only" height=16><img src="./docs/images/dark/steam.svg#gh-light-mode-only" height=16> button and open the Power menu. 1. Select "Switch to Desktop". -1. Open the Konsole app and enter the command `passwd`. You can skip this step if you have already created a sudo password using this command. ([YouTube Guide](https://www.youtube.com/watch?v=1vOMYGj22rQ)) -1. You will be prompted to create a password. Your text will not be visible. After you press enter, you will need to type your password again to confirm. -1. Choose the version of Decky Loader you want to install and paste the following command into the Konsole app. +1. Navigate to this Github page on a browser of your choice. +1. Press the 'Download' button at the top of the page. +1. Run the downloaded file by clicking on it in Dolphin (the file manager). +1. Either type your admin password or allow Decky to temporarily set your password to `Decky!` +1. Choose the version of Decky Loader you want to install. - **Latest Release** Intended for most users. This is the latest stable version of Decky Loader. - `curl -L https://github.com/SteamDeckHomebrew/decky-loader/raw/main/dist/install_release.sh | sh` - **Latest Pre-Release** - Intended for plugin developers. Pre-releases are unlikely to be fully stable but contain the latest changes. For more information on plugin development, please consult [the wiki page](https://deckbrew.xyz/en/loader-dev/development). - `curl -L https://github.com/SteamDeckHomebrew/decky-loader/raw/main/dist/install_prerelease.sh | sh` + Intended for plugin developers. Pre-releases are unlikely to be fully stable but contain the latest changes. For more information on plugin development, please consult [the wiki page](https://deckbrew.xyz/en/loader-dev/development). 1. Open the Return to Gaming Mode shortcut on your desktop. +- There is also a fast install for those who can use Konsole. Run `curl -L https://github.com/SteamDeckHomebrew/decky-loader/raw/main/dist/install_release.sh | sh` and type your password when prompted. + ### πŸ‘‹ Uninstallation We are sorry to see you go! If you are considering uninstalling because you are having issues, please consider [opening an issue](https://github.com/SteamDeckHomebrew/decky-loader/issues) or [joining our Discord](https://discord.gg/ZU74G2NJzk) so we can help you and other users. 1. Press the <img src="./docs/images/light/steam.svg#gh-dark-mode-only" height=16><img src="./docs/images/dark/steam.svg#gh-light-mode-only" height=16> button and open the Power menu. 1. Select "Switch to Desktop". -1. Open the Konsole app and run `curl -L https://github.com/SteamDeckHomebrew/decky-loader/raw/main/dist/uninstall.sh | sh`. +1. Run the installer file again, and select `uninstall decky loader` +- There is also a fast uninstall for those who can use Konsole. Run `curl -L https://github.com/SteamDeckHomebrew/decky-loader/raw/main/dist/uninstall.sh | sh` and type your password when prompted. ## πŸš€ Getting Started diff --git a/dist/install_prerelease.sh b/dist/install_prerelease.sh index 19a8ab04..d38f0d5b 100644 --- a/dist/install_prerelease.sh +++ b/dist/install_prerelease.sh @@ -15,7 +15,8 @@ touch "${USER_DIR}/.steam/steam/.cef-enable-remote-debugging" # Download latest release and install it RELEASE=$(curl -s 'https://api.github.com/repos/SteamDeckHomebrew/decky-loader/releases' | jq -r "first(.[] | select(.prerelease == "true"))") -read VERSION DOWNLOADURL < <(echo $(jq -r '.tag_name, .assets[].browser_download_url' <<< ${RELEASE})) +VERSION=$(jq -r '.tag_name' <<< ${RELEASE} ) +DOWNLOADURL=$(jq -r '.assets[].browser_download_url | select(endswith("PluginLoader"))' <<< ${RELEASE}) printf "Installing version %s...\n" "${VERSION}" curl -L $DOWNLOADURL --output ${HOMEBREW_FOLDER}/services/PluginLoader diff --git a/dist/install_release.sh b/dist/install_release.sh index 36bc3247..57150f2f 100644 --- a/dist/install_release.sh +++ b/dist/install_release.sh @@ -15,7 +15,8 @@ touch "${USER_DIR}/.steam/steam/.cef-enable-remote-debugging" # Download latest release and install it RELEASE=$(curl -s 'https://api.github.com/repos/SteamDeckHomebrew/decky-loader/releases' | jq -r "first(.[] | select(.prerelease == "false"))") -read VERSION DOWNLOADURL < <(echo $(jq -r '.tag_name, .assets[].browser_download_url' <<< ${RELEASE})) +VERSION=$(jq -r '.tag_name' <<< ${RELEASE} ) +DOWNLOADURL=$(jq -r '.assets[].browser_download_url | select(endswith("PluginLoader"))' <<< ${RELEASE}) printf "Installing version %s...\n" "${VERSION}" curl -L $DOWNLOADURL --output ${HOMEBREW_FOLDER}/services/PluginLoader diff --git a/dist/user_install_script.sh b/dist/user_install_script.sh index 34dadd40..21f0f2f4 100644 --- a/dist/user_install_script.sh +++ b/dist/user_install_script.sh @@ -98,7 +98,8 @@ if [ $BRANCH = 'prerelease' ] ; then else RELEASE=$(curl -s 'https://api.github.com/repos/SteamDeckHomebrew/decky-loader/releases' | jq -r "first(.[] | select(.prerelease == "false"))") fi -read VERSION DOWNLOADURL < <(echo $(jq -r '.tag_name, .assets[].browser_download_url' <<< ${RELEASE})) +VERSION=$(jq -r '.tag_name' <<< ${RELEASE} ) +DOWNLOADURL=$(jq -r '.assets[].browser_download_url | select(endswith("PluginLoader"))' <<< ${RELEASE}) echo "45" ; echo "# Installing version $VERSION" ; curl -L $DOWNLOADURL -o ${HOMEBREW_FOLDER}/services/PluginLoader 2>&1 | stdbuf -oL tr '\r' '\n' | sed -u 's/^ *\([0-9][0-9]*\).*\( [0-9].*$\)/\1\n#Download Speed\:\2/' | zenity --progress --title "Downloading Decky" --text="Download Speed: 0" --width=300 --height=100 --auto-close --no-cancel 2>/dev/null diff --git a/docs/images/download_button.png b/docs/images/download_button.png new file mode 100644 index 0000000000000000000000000000000000000000..d02d8699c3dc1711f6e7fb17c3aa307cd61029be GIT binary patch literal 11118 zcmdU#Raab1u!eCb5MXeEO9m%sa1X8n46eZ~NN{%zHn=;32X}XuV8K1OI~=}qe#N=i zd+qL<TD!ZdR#m-ExU!-&CK@ps3=9mW%r^;D7#LXa`?oy`()(Mg==b{jhMlFjxU!{* z2@DKFoJ(B0oR|?_D0#i|$d3}yyzcHiQA#u_i_avwG<_Jg+SiYOd&g!?R7*^4;-HX{ z!m8Z2oIg4B6etlCc@^zdv^%bqXtD>*ZFd6CYghako-A78e6&?}W8xjkGgRGv=3EVX zHJv8i-4u3vTM?BkLA{hM1C#mcasv0``m0A@rF=OG84Vp#CK<{!a3Gc_wn^#<cR`^^ zHUgi$sE%h%MK*QRlsNClcjN;*<^SZxNmi!`3Z`-^*44z%U-sbkta(+IbMCWu_N4;L zndCmjeTh&EqJR~kVfZZ*gX1%dxCAy|H(hO%P!Wh|0|70zhJFF6l;&!k6=W16v*PKc z`~N<@dH*{+ES36c4&z~fx$T5;{G<#e9ylvCnw#jlg<A-QbTW9Rz2LVm&$JD0Ec=h9 zLm<3<P(24>s3Ws}vdxe3LryQ<E)k57(_H)Z8t9(jz7qB-#K0LjRGN+DrZQTXaK!=u zJr)yqzW`K+Z(t`F7#8aP9$2?RVOJO!3K$s)QFS-{6FpRCJ!$vX^*rxJreSECjQ)<` z#9ld_9Hyy>97CcwI;yoC>gQl_4~x-UT3gHIneTzhq-d5{zi{EeQ6%5;`#!|L*O1xQ z;*Z8NS^stwtWY|;$^Lof{qyv1^QdPUz2M;l>Cpk${`C3F`q;~Uw*Bh^vIt$cpM(e% z#m8SL-w<fvaA5yGEmJ~K?)Qu`%^OFa@_6#Pp3aMjeL1|QEs$P6P&w>4O(_XU=fnDP z;+#uTZUi#C#ynnlK4ZKt?pw@-K0Nz%zORJu&+YxPVTA{Mo=n~bCwF*W_#o25p@<G0 zYT4aq-#B*EM!6G<Ar(WjyVe|uou6I8ciHD9ORK0x^Yq8Q__Tb&cM<ba2S>@*Gbv;R zz-DTeV(Iz9L+~Gx8dN5UcNoRTxTHR~aNLjt#;$QgUl&%ayW+p-+gzwz9oedl-h@&M z86fzc|D+Izc9ZhzmdRcx{~+QJ;T1~l3B<9e8smx5u?Yp*Pws86mt?LIIK6&Lko{9u zbt@UWp{ZGI@LQIi`@kJ7(gQXMtuICRHUL$%)()?niWL^oIM;NQL95;NyW|kihn`mM zlK-<73q%G8=0W>Y5XMZ$LQe~=8`tmtQ6sN9+>#n3ACbcI;XsHI*M6W+hpY2xka0iu zF+DR4$y|C&AikDWJFs4`A6ipHDA6zw9ROgQ)bEZ+l4NrBL}b+eR8O_RpcQwC5s{K_ zC^@1!fI4_tl$ia^{g#o@OpJ|)A|X|C&i2Iv@2JJSH@uUdxmM_^nTf-Hq=2%Tb=k1c z(DE1O==?+k0JTh~Oe9FYQQaQ}%zhNru%-1iC=V@Ycvb@wU)`U9Pj-bD4=WUiO*_jB zqR{;$zF?T0RknTsx?~v+Lit7uWz^!}(hMgC5I6pl0E8t-w@;BGQpv^?5oY3rS-9Jk zz<uN}Ir*^xl^mKLagYOq#UDa|DWw7iyjt^352C-D`DX+6H?LHO;}us1!B1?Nd<5$L zLl>si%FNttK_e!~jinmTOjYB`h{h`e492l4h~b9rc2^4mRThQuF1dz>qFm|f{v=fa z5=d=oYr*mW!ZuzS&;}=-O(&0ySXybo;s7u+&AP3^qP@ZtSH0R!x(FAv(Ll=cz{yj7 z|G~A4S&G0;$L`+=cWi>D|H_ZQJ6B&p8%WfR?u$OwOV^-D?YcEkEh>Z7^t+XHt;WD5 zg^qVC4mH=<ppBxp)jh{sXGa|zVS}TADmT?>54GXbNN&0>x)~(_rXzJ814ruqT1=k} zb`Yfiyx_+?vQ6AVv_&7A)kl$De*)M#^0=3bN;7w*VW3a-k?J(%bvQF)6<pkp*=Qj4 z3io*X=wnc_vb*ITh@!!EEW8Kr3F`{b=@H?;p<KT!XFzwBV;)a{MeTq^ya-ODlI|5N zLc@S`L}JFJZngX>g=2xBqzv4lH!71UkxkS!VoYW)d!}3Z%9r>#1IKhA<v-N9H}M*k zxf%=9TaTN<K))QQZ9X|%0<l>}H(>&_+z%xIVYcbLDkgC~>WJibnpvAP%N;k92_6K9 zJeC>}SCIJKJ}T_s%XhN}FiaZz=aQS>My9Ll`28r<v*1A#>X5RGV`BhHk~AG>WD`8` zDvfSdc+6DnSL@nm+|;5b3aX<xMKgElVc>Kfj%?f25-Om}RFS95kj~a9TW?4mc7Z<- zJYGO5Hy@98a+oJ?rKqyeS05v^`3LkO(sNeOls2X>v!+rj+td@J)}n%l%G0$6%VUHY zJfbE}zbyF|hjB6sh|M_4cbsqGu2_SnN*5~*prN+5aaU43Gv%n=yCh=$493CYrnTfQ zg&Q}nL$_wAjYCfbhIyJV_5r^kLeS%Y)kSV&>i!{zro+l3Ycg>!+_SZ91*S69whNXG zrEm)Xr?|K^{{}SItvtd7@Juw&LC=wZs9h1z<TvDkFV03PrXt~m+MZB}SO}J4{k#;k zI{!TZSY1yzAB_-aVos@sSVTg<qq1EP8smx{oT(`~6D<9#I!uSD?;(_u8ezq!f=FfN zkqN|(DE#WU6wHOkI{Au(pmMn-_miXwPNnu6->@>`PIHNHJbmq_Lv4+oKYA_PeUk09 zdOIJp`o{(Jse+40KolLe8LJK>W(*(QyT@Qmw-ju&$rTjjMLEmKtCV=kDB>FUb~D3^ z<#J#QXl-4vvqBCI3KDn~9bCO=*fP)VH{gaSl9-Bd>yt-WH2jA;42IPG>kIAMDLHU$ zaC6b@?z@nh_C9!@?H+bk1mCvEp@ug`vBw2i8}0S@rVv1L9ybCVqolC7y80(y*(k^A z#ySrD=nrJyk3&S28kT&yei2zow<-$R7`8gRZE^PgZgZF+YNJ3Xpp!LPa?^B@vn^0q z;pJmW3=N~6JIiWGKx+NKJ*QwPxS19;i2zG`Vov<T;DlRWg`-|(ZUicln6b#KG8nN6 zix78NS7Uj~voA9zOq7A6m+Z`>1OyYb$A?}&H%Ph`_g8eNxxHMlbsZ7(oZGC@9NT9| z1Rn{&=&6sEAA^L|TURU+J}2KrS*j`jIx7IZa7Iq=@Mga!n4n%8Rm5w+zD6?b*Lj|} zGjlNj4VCohs0X00$~aa;_Esjo)C8D)5g+eT&smd)_I(C*DeSTW8d#H!-n(=@)y?jf ztG`+E?k_1a{7dGusX**$Mf&$l9MzOJ!=xU`IH9)nV@UU*qFz(I)l0=-1}dlGk`n#n z-SvW94%q$;lFuta=lqS61}Zb9ztFJuBJc7EX=xq@f`Y%dcjR?p#dgqRt?4Ae8oaJ! zM=9_Pvb*M?Nqk6bN-}bSe-G^zknnrn+yjX;21_H37gTt3f;|Ca1zu1Y+xJjVMP@AP zDzzONM)Rc4G#%f)(^svnWCHVKI$8>#8F*8ZV)2^;_+3>XSaxL?UDDPZ8!Z5-5_{-G zP_3@8*YmzO+oss`@_b|iVMPfX&&iMU|NNZpZ8LFDfBxY%SPEc~#Zq)9o)4iCGCC_* zso^Jh5Sac3&>C!5b_dYR^1YNqWmjYec=~(_z!D@0XrSCaT}T=YJg-Q<G{&#_+yY>a zMx+Z2mMzDM=$vO_@!#4aVf!w`BI(8H0$(-59TD+yiLKVA_<lc_I4No$lw$-$Q#4pS zyH|{e=Stpn%ZmeciEWeWOw8anM!q!&Vl=*)5>Du*abMpdTh$s)5(~X4*@tQM1F`ws z@Hs$+Il6ONhynZT;+h5Tq4XnzkO80L@E0ocr#I2UNnMo0jB@l}dteASUAg=N#dWmQ zW<n>af3mO!%0p_)gzrY0u3Ni16(#TJCA`B+i_M}|94Y`2c1Xn48i(w#6{%Nwf&D{g z1$kgDd+<!P9Be068N{>{Lf?|T`6aXcj|*kJ)SI_fs{nF^eSaDC+v6j>5z4R?zq@<0 zC<E)fsicviAzTPjbj-0(HWrZaY8!HZ(DMD-IclKyVs{6@Xf%dHOAmz5PrD>?8JoAR zD}98W@#;-*{WBD&XF4TStLq=vXXh!xe_t|%e{F^WbQlc}i+(WZreUQv^MZ}nYW&#= zZOHs$@=vCGD|te&Soz!m2mw9}s|^^k+#r$D8LA=R2$Jwfl)PfE=^H~(_3>+?4&~h3 z_Tu+qadtkaZ0>;`2}N-W99-}cb|!{+lN0tpOnvu|wK?Tij#Gx-9Ixh&3sF#*L;7^= zf-9=u74h}LeiRcZcH}W#ot=D0So+x{$hLBl*se^dJr^;hO_GMe2N7Eoe>;m&?3PkY zoP4DzgQgX1-Y$&XE&*O2Lmd+ob+(MVIYHRb5*ug29XJtJcoR(>-WVPC774bYm0$?` z+jT!?hyZKnG`z6ep4YLxhCZTaWvL(5YBTWlugN+;=3q=dPM#{;L12~F$>qHP@zK*} zoP8&mT9Kz+MUc*!7Wz_&#ZsNq9f#XlC{NFHAi+i<d1k;cJEmNXNy5fAx+2>~`=Ctn zMU16j@E<rKN4{&Wo1SU!&cKOA)~2#=Qa<=hoknC#%~pWK6Kz<3oBi#VUh~$R!&c<n zx3B<Ts?R2lLgmjRt-1F_(a(cIUbGToxKmGk(5bh4ahNaHcSXVXR5k7%-SkSFswa|; zY4Hp=vjE`f;7F{Je9l?<blZ}Stryr`y?cCq>3pmm-~g=%0R8(YA?YwUA$C8#4>Woz zBOM+2D1N6kYw`SKrJfVa2m3`@9^AJAMVH^T)iXFi=_<OBybvg8dJGW-NN<~k+lY$R z9SA)<*g6af9yOyuCOWTL0O!M1dYGww_KHVtBRGX70A7uh1j<HUlC`%f@~%_i<}v;5 zvPl+gO*EdjRsBVm^`wo#@SgBDmepE3SAl9|h;HjZQUI+n8n=2^jPC<QdHWr4MpP8C z=CKAoA85Dw;_#^)P`-@htB;@f(yy=ei1l-jj-Q)W9Po?dc{a;|1%}m~00mUrMv%Do zQl2-SurKCDRet-7cU&>kya)xJywu*QoAvgdvGx;ylA{KIq*kPXKUt!Bhujcke>_)P zyKuiA$ksFPz+m~>5dD4YMR#bije=^%WTJOx*+#_EoJ}=wxu3771@0w>d&QzzlSmJ< zfHM#y<v4O1W0knDCBf~AntjX_y=-42oI?VOsN)cY9>W#bBm4>u9S|mRT~@r=@t$<m z;}Pf63B>I>>@Jw~^bpQoEieV%vIlWz@)gxZHT3EJ-bAP8nidLyv0>o}kaACk5D5=I z!PfQ})U_Z0e`<=+?Jdj<VA&x0vccF3hx{?bkhZRZYnh>DeqmEyK+Qja$NrQBL+<MF zon0~LXf*fwQuf^Zu<E=_={Tfx4cl43b8gD+6X;hszRe9axqp<Z$-Uncdja{HO~|3X z4LWck<AgD1Bjl#!<BRh7X$9N7m9D#12Qn#j&>EZi*M$5U+<!F>abO@A<hb}=fh;AZ zQ3=i1sn?PaAX9|d>j(AbvV6wqYP4fzXIT8LmvFw})IRk?W>b`Fp~AaL+GzBW>3$EH z(NHFCrX76H`V`%o+(Z9~AIrp~uTyh<lOFz!0SNwjQZlj+1jp0ECk@f5_q5g3w_sbX zA8)oafGU7~@;kWo&U?pxj9Qu%%t40LypX$dYl02UN$ws774F3N5eczJ!8;p2sQq+l z*r=T@YG{_dNQ_3~j2>#;aNYjzWD-0Zgrw(O`n8~tWD-XrvT!9rg!OXzFB@f(`k2=1 zh3i6{uM@;g&b9E%`oD`!dI%kMdq&N3Z~E2P{!aB?h=ZEOF?JLeR)1oayRF~4RV+L& zMNd6h3CiC@Yc(PukN&G#|E^rU*@0arbk77_bZQYuG9J-xCxm!EeHzm4M8IGD*(+}p zB}ksHSJY-S>=Dj_&B0qIrnTNFfnIgi|GPnbq-(VR?eACwrbw?HbJq(Go`?@*4YcoB zyfLfv6aHabu9!u>D_dy(1AKl9y*MB6uW*aqM;>3zbsA@^1GAG7DmybTO=vXq$~Xc- z!$IEWE!F78v!aZ|MH2PLfD8x@O#juthg0Jx<8injeLm)!>5t8a+EeiPFN(+Jp_;?q zN##9{DY(__?uW@3@-0#j!e4aAe4^-leG3kKfX_>8y#qeLCNYh$UdGwV6mHF}2|vw1 z6j8n~GkXcsU*3A9=u91%wCU+H??t9Ip;aB02JR=)z{gNucxGX*FD(8JO>(Ep_~hbk zA6Q#FnDI{kB>9?pp`{7EnGo{LjFFKij3;mOv<oYjYyCL_qE^8vgt2bb#mHP&$WA`L zS0A5GRNh-uZj7&v@KFk8?t7;U()~|s#NG)}0#^%@cLN8o<Izz+VRCWXF<x(Iw=1vo zH1YC5)(}zWzG=GEORys3Rr2vNU889Qdb4Y0VvVxqQ7pU`#cVOG%?!h1t6Z)U-(vyG z&5haYLrr}2xbdcM#myjpYcvz0={s$Bf0d>XsW(bNq`+%cseiv3!yio|?oy(w^NXrl zL93WLwgcA0yM-%LEe$=1r!u-RSkRA+i}S;5$u*A5_|uwSI1AZizo&zH72PM0@<pg7 zam1O&r3<0`6g@-Mv8DQfp6^qJNqxo#iYY`xzm&v|gqWnvLX7v{*8O(Uj@EYz*Di{k z#`bjcON7&=#Rb0QL|Od8;fgn-?SRE+A6hJxQ=vJTo_rF@2>r3$`c_xItspgG$ghgj zR+qG8qBMuqJsh&>){qx~p{3$)2f`pvPB;v$hcfI&p}AU(yl~&x>whKxop#ulKKFGJ zt7j-@0yVjU&3=k@HXqDKRBg4u(VIW$<Jz+!X#}z(Y$yHa<1=%9BYXX+TJAc<*=de9 zBH>Trf^#Gv7Ec|VmbpGvjUjraHtriR;HLF@mfCT2;U5yhW!Iw4IGax!7ZJ+#<W$F^ zzKW2(rTGjz^><VUNYb@jmi#6SCslfwHMSf;x7#L+jCVWBgoebVDueTf(~9Pi2D|Mp zX)zO6wTcXcNSD1JaQ(GJJNK%Fo;V~2nWv@YbLTR1BC`LVjvG*L)5x4TTBACwyAMvO zU(s*xN(#D&d)3gjH81BXDq|C5KCQB@Zr>FACevQybG2NhRuT`RrqM9Q@k0_iqQqHk z>m9?<1{OqeL8lfgGW&Ryc3tHGH{^Pi@T6g>PHlbQV)G1z=e+~2gf7x5oh=3#n<Alh zYl209`KODS0nL%GTq<RL>OsG)LO<sLQtLX#EaKV%y`XC4a4liDQPSOC1>CyiynBr- zj<Wocc1P~|;-i^gN~@!E{*?Msk6<xR4_r~#pdQcwSJGvZR^P@;OtIRQjj%;q?c!LE zx!V^}D~hf0sCcQHGv@}x=Tu3K$R!xR3fKvl5maSly2z^_7DAoN0tHrFiuiMDIG1tZ zE)#T$<dsF8Sw{_2{XW4T^hiCh{yx<R(qyRw<M99b)!BkqORz8ci`0z*7g;TE42QZf z(f<>QKpDl)%o!zZv`h=766Wo}m8ORZuYAkV`R5$^ML4Bqhtx;6$`Uw^bJ^N)c$*Y) zO6*Cvul08%JY#Ou`kVcUWPe?+g>ux0epG05Bn(ca%_rK(h++$yi|Z7h-b%LGW%BXB zsT~~2X*-trVB585ySww`BFb}L3{A8aiEvjeB+U_KF<4vHFFkxG=JbD9>dTy)yOl}_ zkJw*G4b!0H#b@FMR_DeTX{y6An-c=cicE*sos>6mXh*F{Y92LLJBa>xn-c7((@4AD zbKKvmNd-@5yI+cBGlRPR*q4nj1&^W`yicPhL=2>`XjrEaQGYVnnx*K6Ah;H}Z(B&l zEqNEFXN=`R>X%Z2|B4pU;@~^R4}Mw1n4@%F%ER3>lgX<fRruW5tBkZlsP9SwRA&At zq#;*46+f@)ssZz7t451?cUz`bHo}-U5*a(sO#xw)OPh<*A0*fqma2+aFg2#TZDkB6 zh<sow4X{{O$Xg-G<d{NEN)9XZxDj4Q)Hz*Gs0*l{)#<xSQk?C*9W+yb+~#<;jHvkH zd>Dk6nL+$=U<wi5B@?LzX5IJCglpA!Q*M99ZdFq%uahW&QxzH&S!AA4%;{tzx=qvV z8SQXZzVKw0B&goCSh6~#0fKEUg*kCT{zT?0H_O-DbLY2eZ1YK8*p+j)+Fh_sSCC#c zF86&2tmF_Z8~Rdo-zTnuNP|3@EyY(CqqaJ9VfMBE{wD<3g?94zsL!xk)AOtGOpE{e zr2|oH+?#Fs3&t!>49pU5)Rt*sL;jW^SM|R&>+MPK0FVu{tnZq%>SS02k(WCVRU1Q* zqWJK?CexI&f1Q!POvKcnMk5Aa;Yj<t_>lztTB58bwy@GBVZob}>tUuAQyP#W+v!3| z<Ez33#~Ls?XMQED2E9y^fqno5SuPQFQ^Jzbl{ZMvN4<<4vEXqwOUhb9t(NP6^=b44 zEmm8+*)Hzc4vSI?X#5>M64RQY?o1txO8yipPZjAg&#F?^ZWl3?5Wy%W9Y0)CIYwBU zO4Kk$=w1LL>okn{(8TRa1Q>lv@Wl8kLV&!R#Qjj>*$VS@M4eDtf8{v{SCOhl-JioQ zKBXf5m*7IITR4kDG#5$a+?Wv^_tWoyWa`Nl>tIJzkEY-ZV^sknPD%Olkd9v+f9XkP zBIn`J?MT%0Ei$B$rRogXpPNeP8Ad3Ou|(7>)XQgW58$D+Tc9qMYZO*!Vc9(5uR`EY zk6CMMYC9K~AYC;?yOnSICiJ<fZUBqj7);{iIroF3GFl#W*kQS=nw__8?>*`X#ydL> z&WFrU{Sg1z%tR(ZSuJ^XRb(lS$ntHqso)S5$Jx(X-^U-)@V>^38>Tu%p*6nXqjK!E zuORP(h294?sg_bjChyY@uSYZ!1ZLHm7Z)$PW3TM#2yKH(ZIycrsEC_Ml~rk6p!HGB zU5(({P?HxW>(SuAOuBv$&`?cpmMx13MDc+lw#`QmHWAN+aNx(wF1-d*Y_Q4pVy*0Z z1<#XkCyym$ON!&1J+q5dN3x>R(m+Fb(bt<>J##;15&B~*Itwp?N26~vv(F(sdCkg^ zIrN4&?6a?WL<rPEc}*hHaXTW2Tb{;jYg(I|_6JP&c{$d@2P_&T;8Jq|TIGPXg;4Fd zh0Ak`5h)AC<!aQLB@eLwsH~hB9|ELcT|Tuk$?%`Gy(J+q*Je9MlT7-!+tS8FB8%oS z`XnK^q{pKT+CD&Zh`A)DXk$77iLB9Xk*C|#X3WjewkHktMeUT@9+!Q|%Ft=BMMd}q zV~|{GJop3SLw=`KAR#ihKpE=_7j2RPcxZby%rPoZQ-j+zoK%3JrF;fttCd{gC14DF zz)6Q|a*!QsRuop)lci9(RVVL{&Cl<NMRG)*gCBm^BPtD=)%|l6rpV+1&+juOLvVG2 zs9q+H4(vyi5z~6SD!QA>z3w0aL-|{Ti}hxfGDy1ZYi>V|hQMC#rJ_|TxbIOdMC9M1 zq4&{VD+xJy;UHa8&+XigRAi%Y*4!mBmO)FcEuiHUT!{9K49pr~x^|d5@$tZZ_7EE< zqxIha*CSm)S(GKBm`=(3Ph0k|6R!mO+?jM)QD8vw+J}ELG7&(nA5R*ixcWApgXx}z zmw7@<W=7Sge>1-$j_0Gn1@rw1jcW>`HJI!12d4zpF?<6q(X>#ilu;1m8+vb+>D~_u z_AB?@4+=dmvvIO_8y^74278gC1zYCT!dSGj*VSxt(A*R#{tUk~CXsBpKUY#BWWL<) zZ-v(iPM44;VQ$U5Rg&D$(w?;Rj}*Ftw;Jkge}DQ_1ogytd>S8Fk_S|OPgjNv@^-Uf zR<EcFICT*cY}Uq}I7iXTRqMK+SZM`xH`YtwS&qJbp)2$A5?;$!<7ys_r2I+rHixfw zVl$@pP<kXU?k5fCTMl)&ecei-e2YhZh4CT`nf{#Q_3_G)yCX6B3tdbFI>DfY$d6jZ zl*z_36Z<0@WkgdpO~dNscIz)2x#>=u=iam;l_^G=DM~Lscv+8`FD{=8W@0<6bic1V zNm4#fpXTvqOS4`Lnd7)_%Qb?!KzJaLsEcBs6E6kS?gL&xtlx7do58vOwJfCmM_qDx zsrw>!g5Uj+m1T!AqQINc)~x5Ph~Plv{1fn}%7?$tH|dnnuE*~|5oDtqWu0Ehn}U3A zI8r!AQ_McmKnjzhyL(CTwKUfCpbN{2B!h_&oW;jXPl~X{&rJ#v`m6&$3Rr`>#NY0G zOi$_j#?qn9a|kWo0PkmQhWm4nU4P$Y&2`f7%$=mbdyg|7JnH)EyaZ0tpU^hL4AJNQ zM$j~rh>Kv?UM6N_FL%C$cLBN2qh5ALq+57Crfb%ITTU*kF$b+~-#U)NZBqipZoTXZ zYS3i%@mN0@UYMT)!F=k(im;cMWdyzJcEslXpq{qIv-RLwxIX#Zil~ioGz2(x$wOh! z@9&dh)5nrmqNJw5vLb||2i^Qz9ZpB_@b9}nP}vPU@g0H=9g*=2Vh<5J`T3#Sv(w%B zuYH4;2~peG#a(x)xnfs;<Fa9$HKED+W3Jl`m6nqnSNUq|nnOa@P`@be!%HtDPuu6> zL%CP%sgZIE6sOYdxp(S$&WNz9wXH}zp@tB9C(O2=nZ)Q}HQC?51(T%jZ1u8smhcez zLarY$5-LPkB{xmRPXR51d(0{ip6(^=_=xrSo}I>I;txRinSMd^^b;-G5&}}#@bYQQ zn@bPpzhv1zsQC}K?bR;ycKE%wwSB4hwGSPgKBTWF6iD9&wrfT{RJ-Ic57@UaqW8O9 z!M0zxJfx9Q2rC|H+GF*obviZ}b3v_$Pa<dCY+Uz|@>?g|)o1#o|5Q#CA0f-jLJm59 z-~Z&UK{EhveXXZ!K66hGP$ZEpFNjIdQ+}#K-W*`nBhaklBc$H=(WZ?w6stfi3EY@k z&<|o;OYZjoSj1vxorLUVlLd4AJc~+}uoGE)t>8C#i<PIiZ6Y<slCFEZS4ino4y}vl zDqrOFM1x0G6y=sW0(Ra#HkBVM$QdnlJ{ujssazM|#5Fa}Z3Yi@F<krX(pMjM84P5H z-w+WEM!nUh>qk6xJw!F72h0d4ZKY9-lbEWt54}fK`Lq881F21FfPH6-W}Cngx`Brg ziZ&9C0qw`5yHVkj5OUH!>u<V`4!G9W7cZ;l=T2n03x!ss|M3B7|FHm{TPq9P!OYoY zpqzHowqB$PTWV~v-3%LJ1H(rcv0Ags>{$~b3t2GVE7YEsYo5FJweu@XZ{}C~6ZOy! ze-Au%(cO-^B=Z>w6#xv3MGSMoKG@nmR&7F3jM=(e;*452Th$M7nw!ri^@<=v?nAu7 z#j69xsfQB-QBIpru^mj;bh&soO%+&Q-|juJU5Q$|!hsa))b#1kISw|CkEZ81dWI{x zf7D?`_P-%?_{M8Fl%-0lAk=hjc3P5hQoC_N{;qQc2)E~d<Xsg+BnY?0_nGV{KmMrL z%hDOl#S=YpgSum$E&LVZtg{@Z(jXfhI?90wp<R--_?PAvXdbfJ--u)g6WjJ)trm+c zQa<bri!$``w_a}-tGI2KI1P0}8nB;>8pJPhl$lG4ibMl7{a4TFNyI~6s}y#TK1xUR zm?bZUU;VwXBRtXcije_O^)WSmBfDvLc-F*3^9g&f5Pti>`RGVhh0eUZFLXy*E{O$y zsivU@EBddJIX)ZV-)RqtRr=jRcOkBuv0VLqhQ9aAYm2l&VCAxh)=lnc&h-eW%Y!&- z)7!v1G%aVlxHHu88jr#o&+6EJ!u(ugJq0Gpar%&o;cG+T*<mlXNBbvPVINGqzip^+ zw27nSf6TVVBvINOFr<6}8d;+lPlKr6UUU!*yoCOmk{_=$oO!J&*D4lsW)Ac{Klm8b zp(9K3d5h7zo~DEMsz;e-Rl|mr_&u%RC;u@pL$S43gPW*|+|^vztS4(5E8-W&BI6>* z2UaT`>vTOsi_Z68=TS3jyUMwp7jM(fjbgyswjPJPY1@nz8pM-~femi*T4h3ct`H_H zwYATzt~gvfD)fP-Y*d%<78kn^Q$_;%yrX@DPc$iFiV1eCp73H`<;vcD=u--Ip2ONf z=|xS=07-q`C<4;>`zj=Pn*o~PVg=sgFGVn`C3#=iGK^u)KJ<Q*U|S8(C8Q5ydK6^8 ztpb2H2I9&7F8--L_VrC|+CF)n{#ujfF%aLch;@NiKJ?1bdH(nje8Qi5sf?<SGw<an zhQ;`8xrC`Wx;R{7$VIi9%GAQ_oav=WC;lsHp~NSy(rPFcqx()w)%2PQVJlu9WcRjy zTLrNV*SxPbQ$*+|j<0b72<OEr<9c3XeHo#sL6hBYnu8YBq9q(T{4_j)VZsj2Mm|IM zA8JdNTm}<QSn04wE|at^MA7-z5=)!~w6_~75~TZovY2rJvpG6Cv)QG3;pSe6W39`E zLSCJYYVGc2*7me!2z4!-0G&m%uKSp*n8lOvO)Q;jYU&W$m@)Xht&sUyQUNLin#Fk! z{3hJSFZ+5fIUK3Ogi$ZTYA-oVwR;ZPDc^2Wc4vpK5w=H21Hyg{|0d*$MXgYJ#}??h zzO42Syz9u5WS|Z0qB>JOaV`T6MN5s$f&Pf{dtGJ3<Jzbqw7!OMQe&k}@J+IAi2#AF zjqDEi9a=E6RD7KKxRj_J6-A}dPIwS5ZSj;MGyboHJ&x!`Moxp~)=3{9NU`1gEellm z8B^9jth{OdJ7W7Lt!&nC*%kw~O06;eKe!?^tylHmvb3OI_b7Sm{>L3&v;3)U;fHTQ z$p-;v^s{7#Qt!GM64bm+5m102Hvm*1I_bHHN|h_4AY!^=O{BX~q@%WG$-an+kM^1| zAlV;OZ^T#Wnxq4D@za_)oZ+lBT)*psH>q~sE94^Bz*z0imbe)!trPL3p$VFz9A?@| zi)GU2{k|(Ihy@wP4TG6VDq-b2q)EF(w9u_5NQhI5J0R@%?H!Fs;YQ@sM-;0m_`7Lg zun{Z*IOp~LQw-*XSouoU(r=yReIq*5f)pp(+^^-lz&aI$W|Y9iky*KHMco454V!=p zo#`_!M(38(qt=UYKiH^q1QxO`@>75RXsuO*`mVexQLXboNYN9&i6&$&oM)r9M~2Vw ztzLS_4wuRGjpu#swh|8#qGFVVsQ%n;*S$v1ArtwQDj@s0xCh#GfsnA##jg0;n-?o~ zd4Hz<?yPDKNa&!tSmyfDkrlih!{&#sNSK{L^kFAi*DW=oVn+(j<#!=)=|V$8aRiUu z8Z=&``Hpl%cWc)rA$iVeC5|~?0kP*<<`>x>uqKf}ewq`U9k+cZ#gYxQtD~1=HQFuI z1Hwt*%qu~GSgSbF3Sf78n%z6&vIho7UBe>eUh-;y%0B#P%0=sI9DjugaC5&!#>PoX z{(0Iu@1T>XG=BD+_1m=ml=#VcFG?fmoldA;#?Hl}2qV3XNmv#rLYwLK<<%<*`1@z@ z`}IUPsnc&T#5{=!*8O@GToaa>)`N#B_0C36Aw%Y;4IYCPOWXL~4|<*ZH<XklNj`C` z`5ZW8?LC)(2DwhPXs5Cw9n<Ec&Sqb;Ij{hsRxZ8E+!`8y6A(qM`~RBOl_i3>N=Jjl zMJ?7X>(EVtro8`YWF-U2)ocGT5WU(civ6~EH)n_3n(n1vjP}=XhdXwm6fQu`XOtSX zUB|8_Q|Up#e%LCL>zc3a1v^JYeSiGj3+u}W-)V*us@?w-)&|=>7?yIKcrEum1|#;7 z;0Q!Y^-uIbFpweZ+kmr)zj}2|Wr8e(xEnruv|@n3>I-XtuWZI1nVkss>kkz<;WbQ@ zt=-hv@}l<}pZ3+NGhjFyK;`1D#)pb9Kz@G%960;cYx+kv*s@r8wJl2uDVbgrpeO51 z-g*mV-=9C=3v+lO_!@NYxx9x&3^8;OdW}k#d&yLu(frQFtZ+v{LrR_&`bL~OLg>vd z84AnE+^`uVeHrM|1Rpe}Q|Seq;zyZ_REM=GTn;DEi~|dwg+uHlpl4r7ET%?+nVzEw z__~o8{Z6<g>fllA_y_-wDB?jRs)FMoY#uiOB*|aXY+r4<hzhlBum>!7I%#|<%|R=V zA-*aJC=td9M><Dap;!|;#0sV4<pK<64#BQp6CxB{C|(Vr+*8*~roy{pHWSEo>dZW! tWue?|xiSrV{r{p2|05&6Bm2K0zny;wtA>Ii-^(-@8A(NnN-@KL{{bdS1110f literal 0 HcmV?d00001 From e8b4c4a3070e4ee1e9f6c330c568d9e76e629f48 Mon Sep 17 00:00:00 2001 From: Party Wumpus <48649272+PartyWumpus@users.noreply.github.com> Date: Mon, 9 Jan 2023 18:16:20 +0000 Subject: [PATCH 23/23] Fix the download button (#330) * Remove .desktop file from build.yml * Make download button link to decky-installer repo * Point download button to the .desktop file not the .sh file woops * Delete decky_installer.desktop * Delete user_install_script.sh --- .github/workflows/build.yml | 8 +- README.md | 2 +- dist/decky_installer.desktop | 8 -- dist/user_install_script.sh | 165 ----------------------------------- 4 files changed, 3 insertions(+), 180 deletions(-) delete mode 100644 dist/decky_installer.desktop delete mode 100644 dist/user_install_script.sh diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 6e548411..df8b03f6 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -161,9 +161,7 @@ jobs: with: name: Prerelease ${{ steps.ready_tag.outputs.tag_name }} tag_name: ${{ steps.ready_tag.outputs.tag_name }} - files: | - ./dist/PluginLoader - ${{ github.workspace }}/dist/decky_installer.desktop + files: ./dist/PluginLoader prerelease: false generate_release_notes: true @@ -250,8 +248,6 @@ jobs: with: name: Prerelease ${{ steps.ready_tag.outputs.tag_name }} tag_name: ${{ steps.ready_tag.outputs.tag_name }} - files: | - ./dist/PluginLoader - ${{ github.workspace }}/dist/decky_installer.desktop + files: ./dist/PluginLoader prerelease: true generate_release_notes: true diff --git a/README.md b/README.md index 3208887c..586b4f62 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ <br> Decky Loader <br> - <a name="logo" href="https://github.com/SteamDeckHomebrew/decky-loader/releases/latest/download/decky_installer.desktop"><img src="./docs/images/download_button.png" alt="Download decky" width="350"></a> + <a name="logo" href="https://github.com/SteamDeckHomebrew/decky-installer/releases/latest/download/decky_installer.desktop"><img src="./docs/images/download_button.png" alt="Download decky" width="350"></a> </h1> <p align="center"> diff --git a/dist/decky_installer.desktop b/dist/decky_installer.desktop deleted file mode 100644 index 07e3b6d5..00000000 --- a/dist/decky_installer.desktop +++ /dev/null @@ -1,8 +0,0 @@ -#!/usr/bin/env xdg-open -[Desktop Entry] -Name=Install Decky -Exec=sh -c 'curl -O --output-dir /tmp/ https://raw.githubusercontent.com/SteamDeckHomebrew/decky-loader/main/dist/user_install_script.sh 2> /dev/null && bash /tmp/user_install_script.sh' -Icon=steamdeck-gaming-return -Terminal=true -Type=Application -StartupNotify=false diff --git a/dist/user_install_script.sh b/dist/user_install_script.sh deleted file mode 100644 index 21f0f2f4..00000000 --- a/dist/user_install_script.sh +++ /dev/null @@ -1,165 +0,0 @@ -#!/bin/sh - -# if a password was set by decky, this will run when the program closes -temp_pass_cleanup() { - echo $PASS | sudo -S -k passwd -d deck -} - -# if the script is not root yet, get the password and rerun as root -if (( $EUID != 0 )); then - PASS_STATUS=$(passwd -S deck 2> /dev/null) - if [ "$PASS_STATUS" = "" ]; then - echo "Deck user not found. Continuing anyway, as it probably just means user is on a non-steamos system." - fi - - if [ "${PASS_STATUS:5:2}" = "NP" ]; then # if no password is set - if ( zenity --title="Decky Installer" --width=300 --height=200 --question --text="You appear to have not set an admin password.\nDecky can still install by temporarily setting your password to 'Decky!' and continuing, then removing it when the installer finishes\nAre you okay with that?" ); then - yes "Decky!" | passwd deck - trap temp_pass_cleanup EXIT # make sure password is removed when application closes - PASS="Decky!" - else exit 1; fi - else - # get password - FINISHED="false" - while [ "$FINISHED" != "true" ]; do - PASS=$(zenity --title="Decky Installer" --width=300 --height=100 --entry --hide-text --text="Enter your sudo/admin password") - if [[ $? -eq 1 ]] || [[ $? -eq 5 ]]; then - exit 1 - fi - if ( echo "$PASS" | sudo -S -k true ); then - FINISHED="true" - else - zenity --title="Decky Installer" --width=150 --height=40 --info --text "Incorrect Password" - fi - done - fi - - if ! [ $USER = "deck" ]; then - zenity --title="Decky Installer" --width=300 --height=100 --warning --text "You appear to not be on a deck.\nDecky should still mostly work, but you may not get full functionality." - fi - - # get user dir before rerunning as root, otherwise it'll just be 'home/root' - USER_DIR="$(getent passwd $USER | cut -d: -f6)" - HOMEBREW_FOLDER="${USER_DIR}/homebrew" - echo "$PASS" | sudo -S -k sh "$0" "$USER_DIR" "$HOMEBREW_FOLDER" # rerun script as root - exit 1 -fi - -# all code below should be run as root -USER_DIR=$1 -HOMEBREW_FOLDER=$2 - -# if decky is already installed, then also add an 'uninstall' prompt -if [[ -f "${USER_DIR}/homebrew/services/PluginLoader" ]] ; then - BRANCH=$(zenity --title="Decky Installer" --width=360 --height=170 --list --radiolist --text "Select Option:" --hide-header --column "Buttons" --column "Choice" --column "Info" TRUE "release" "(Recommended option)" FALSE "prerelease" "(May be unstable)" FALSE "uninstall decky loader" "") -else - BRANCH=$(zenity --title="Decky Installer" --width=300 --height=100 --list --radiolist --text "Select Branch:" --hide-header --column "Buttons" --column "Choice" --column "Info" TRUE "release" "(Recommended option)" FALSE "prerelease" "(May be unstable)" ) -fi -if [[ $? -eq 1 ]] || [[ $? -eq 5 ]]; then - exit 1 -fi - -# uninstall if uninstall option was selected -if [ "$BRANCH" == "uninstall decky loader" ] ; then - ( - echo "30" ; echo "# Disabling and removing services" ; - sudo systemctl disable --now plugin_loader.service > /dev/null - sudo rm -f "${USER_DIR}/.config/systemd/user/plugin_loader.service" - sudo rm -f "/etc/systemd/system/plugin_loader.service" - - echo "60" ; echo "# Removing Temporary Files" ; - rm -rf "/tmp/plugin_loader" - rm -rf "/tmp/user_install_script.sh" - - echo "90" ; echo "# Cleaning services folder" ; - sudo rm "${HOMEBREW_FOLDER}/services/PluginLoader" - echo "100" ; echo "# Uninstall finished, installer can now be closed"; - ) | - zenity --progress \ - --title="Decky Installer" \ - --width=300 --height=100 \ - --text="Uninstalling..." \ - --percentage=0 \ - --no-cancel - exit 1 -fi - -# otherwise install decky loader -( -echo "15" ; echo "# Creating file structure" ; -rm -rf "${HOMEBREW_FOLDER}/services" -sudo mkdir -p "${HOMEBREW_FOLDER}/services" -sudo mkdir -p "${HOMEBREW_FOLDER}/plugins" -touch "${USER_DIR}/.steam/steam/.cef-enable-remote-debugging" - -echo "30" ; echo "# Finding latest $BRANCH"; -if [ $BRANCH = 'prerelease' ] ; then - RELEASE=$(curl -s 'https://api.github.com/repos/SteamDeckHomebrew/decky-loader/releases' | jq -r "first(.[] | select(.prerelease == "true"))") -else - RELEASE=$(curl -s 'https://api.github.com/repos/SteamDeckHomebrew/decky-loader/releases' | jq -r "first(.[] | select(.prerelease == "false"))") -fi -VERSION=$(jq -r '.tag_name' <<< ${RELEASE} ) -DOWNLOADURL=$(jq -r '.assets[].browser_download_url | select(endswith("PluginLoader"))' <<< ${RELEASE}) - -echo "45" ; echo "# Installing version $VERSION" ; -curl -L $DOWNLOADURL -o ${HOMEBREW_FOLDER}/services/PluginLoader 2>&1 | stdbuf -oL tr '\r' '\n' | sed -u 's/^ *\([0-9][0-9]*\).*\( [0-9].*$\)/\1\n#Download Speed\:\2/' | zenity --progress --title "Downloading Decky" --text="Download Speed: 0" --width=300 --height=100 --auto-close --no-cancel 2>/dev/null -chmod +x ${HOMEBREW_FOLDER}/services/PluginLoader -echo $VERSION > ${HOMEBREW_FOLDER}/services/.loader.version - -echo "70" ; echo "# Kiling plugin_loader if it exists" ; -systemctl --user stop plugin_loader 2> /dev/null -systemctl --user disable plugin_loader 2> /dev/null -systemctl stop plugin_loader 2> /dev/null -systemctl disable plugin_loader 2> /dev/null - -echo "85" ; echo "# Setting up systemd" ; -curl -L https://raw.githubusercontent.com/SteamDeckHomebrew/decky-loader/main/dist/plugin_loader-${BRANCH}.service --output ${HOMEBREW_FOLDER}/services/plugin_loader-${BRANCH}.service -cat > "${HOMEBREW_FOLDER}/services/plugin_loader-backup.service" <<- EOM -[Unit] -Description=SteamDeck Plugin Loader -After=network-online.target -Wants=network-online.target -[Service] -Type=simple -User=root -Restart=always -ExecStart=${HOMEBREW_FOLDER}/services/PluginLoader -WorkingDirectory=${HOMEBREW_FOLDER}/services -KillSignal=SIGKILL -Environment=PLUGIN_PATH=${HOMEBREW_FOLDER}/plugins -Environment=LOG_LEVEL=INFO -[Install] -WantedBy=multi-user.target -EOM - -# if .service file doesn't exist for whatever reason, use backup file instead -if [[ -f "${HOMEBREW_FOLDER}/services/plugin_loader-${BRANCH}.service" ]]; then - printf "Grabbed latest ${BRANCH} service.\n" - sed -i -e "s|\${HOMEBREW_FOLDER}|${HOMEBREW_FOLDER}|" "${HOMEBREW_FOLDER}/services/plugin_loader-${BRANCH}.service" - cp -f "${HOMEBREW_FOLDER}/services/plugin_loader-${BRANCH}.service" "/etc/systemd/system/plugin_loader.service" -else - printf "Could not curl latest ${BRANCH} systemd service, using built-in service as a backup!\n" - rm -f "/etc/systemd/system/plugin_loader.service" - cp "${HOMEBREW_FOLDER}/services/plugin_loader-backup.service" "/etc/systemd/system/plugin_loader.service" -fi - -mkdir -p ${HOMEBREW_FOLDER}/services/.systemd -cp ${HOMEBREW_FOLDER}/services/plugin_loader-${BRANCH}.service ${HOMEBREW_FOLDER}/services/.systemd/plugin_loader-${BRANCH}.service -cp ${HOMEBREW_FOLDER}/services/plugin_loader-backup.service ${HOMEBREW_FOLDER}/services/.systemd/plugin_loader-backup.service -rm ${HOMEBREW_FOLDER}/services/plugin_loader-backup.service ${HOMEBREW_FOLDER}/services/plugin_loader-${BRANCH}.service - -systemctl daemon-reload -systemctl start plugin_loader -systemctl enable plugin_loader -echo "100" ; echo "# Install finished, installer can now be closed"; -) | -zenity --progress \ - --title="Decky Installer" \ - --width=300 --height=100 \ - --text="Installing..." \ - --percentage=0 \ - --no-cancel # not actually sure how to make the cancel work properly, so it's just not there unless someone else can figure it out - -if [ "$?" = -1 ] ; then - zenity --title="Decky Installer" --width=150 --height=70 --error --text="Download interrupted." -fi