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]
@@ -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 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
+
to open the on-screen keyboard as needed.
1. Press the
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
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/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/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
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/main.py b/backend/main.py
index c144c13a..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.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)
+ 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/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")])
diff --git a/dist/install_prerelease.sh b/dist/install_prerelease.sh
index 18f4144d..d38f0d5b 100644
--- a/dist/install_prerelease.sh
+++ b/dist/install_prerelease.sh
@@ -11,10 +11,12 @@ 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"))")
-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
@@ -40,6 +42,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]
diff --git a/dist/install_release.sh b/dist/install_release.sh
index 8d52728e..57150f2f 100644
--- a/dist/install_release.sh
+++ b/dist/install_release.sh
@@ -11,10 +11,12 @@ 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"))")
-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
@@ -40,6 +42,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]
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
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
diff --git a/docs/images/download_button.png b/docs/images/download_button.png
new file mode 100644
index 00000000..d02d8699
Binary files /dev/null and b/docs/images/download_button.png differ
diff --git a/frontend/package.json b/frontend/package.json
index 0f8fa647..723ab173 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -41,7 +41,7 @@
}
},
"dependencies": {
- "decky-frontend-lib": "^3.7.14",
+ "decky-frontend-lib": "^3.18.4",
"i18next": "^22.0.6",
"i18next-fs-backend": "^2.0.0",
"react-file-icon": "^1.2.0",
diff --git a/frontend/pnpm-lock.yaml b/frontend/pnpm-lock.yaml
index 966166ba..089aace6 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.18.4
husky: ^8.0.1
i18next: ^22.0.6
i18next-fs-backend: ^2.0.0
@@ -33,7 +33,7 @@ specifiers:
typescript: ^4.7.4
dependencies:
- decky-frontend-lib: 3.7.14
+ decky-frontend-lib: 3.18.4
i18next: 22.0.6
i18next-fs-backend: 2.0.0
react-file-icon: 1.2.0_wcqkhtmu7mswc6yz4uyexck3ty
@@ -1082,9 +1082,8 @@ packages:
dependencies:
ms: 2.1.2
- /decky-frontend-lib/3.7.14:
- resolution:
- { integrity: sha512-ShAoP3VqiwkJYukDBHsOF9fk7wYw0VaKpHw6j9WdzLxwZwBcg0J7QBNIFYP3nfA0UgEwSJVEg/22kONiplipmA== }
+ /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