mirror of
https://github.com/SteamDeckHomebrew/decky-loader.git
synced 2026-07-05 09:19:53 +00:00
Compare commits
13 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 88e1e9b869 | |||
| fc0089f7a5 | |||
| d335562328 | |||
| f9624a0859 | |||
| 97bb3fa4c8 | |||
| 611245aec9 | |||
| e1807e8c75 | |||
| b94cfe32d9 | |||
| f1e679c3fb | |||
| e1b138bcbd | |||
| c6be8f6c14 | |||
| ac086cf59e | |||
| 3e120ea312 |
@@ -12,6 +12,7 @@ body:
|
|||||||
- label: I have searched existing issues
|
- label: I have searched existing issues
|
||||||
- label: This issue is not a duplicate of an existing one
|
- 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)
|
- label: I have checked the [common issues section in the readme file](https://github.com/SteamDeckHomebrew/decky-loader#-common-issues)
|
||||||
|
- label: I have attached logs to this bug report (failure to include logs will mean your issue will not be responded too).
|
||||||
|
|
||||||
- type: textarea
|
- type: textarea
|
||||||
attributes:
|
attributes:
|
||||||
@@ -70,4 +71,4 @@ body:
|
|||||||
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
|
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
|
placeholder: deckylog.txt
|
||||||
validations:
|
validations:
|
||||||
required: false
|
required: true
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ jobs:
|
|||||||
run: pnpm run build
|
run: pnpm run build
|
||||||
|
|
||||||
- name: Build Python Backend 🛠️
|
- name: Build Python Backend 🛠️
|
||||||
run: pyinstaller --noconfirm --onefile --name "PluginLoader" --add-data ./backend/static:/static --add-data ./backend/legacy:/legacy ./backend/*.py
|
run: pyinstaller --noconfirm --onefile --name "PluginLoader" --add-data ./backend/static:/static --add-data ./backend/legacy:/legacy --add-data ./plugin:/plugin ./backend/*.py
|
||||||
|
|
||||||
- name: Upload package artifact ⬆️
|
- name: Upload package artifact ⬆️
|
||||||
if: ${{ !env.ACT }}
|
if: ${{ !env.ACT }}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
<a href="https://github.com/SteamDeckHomebrew/decky-loader/stargazers"><img src="https://img.shields.io/github/stars/SteamDeckHomebrew/decky-loader" /></a>
|
<a href="https://github.com/SteamDeckHomebrew/decky-loader/stargazers"><img src="https://img.shields.io/github/stars/SteamDeckHomebrew/decky-loader" /></a>
|
||||||
<a href="https://github.com/SteamDeckHomebrew/decky-loader/commits/main"><img src="https://img.shields.io/github/last-commit/SteamDeckHomebrew/decky-loader.svg" /></a>
|
<a href="https://github.com/SteamDeckHomebrew/decky-loader/commits/main"><img src="https://img.shields.io/github/last-commit/SteamDeckHomebrew/decky-loader.svg" /></a>
|
||||||
<a href="https://github.com/SteamDeckHomebrew/decky-loader/blob/main/LICENSE"><img src="https://img.shields.io/github/license/SteamDeckHomebrew/decky-loader" /></a>
|
<a href="https://github.com/SteamDeckHomebrew/decky-loader/blob/main/LICENSE"><img src="https://img.shields.io/github/license/SteamDeckHomebrew/decky-loader" /></a>
|
||||||
<a href="https://discord.gg/ZU74G2NJzk"><img src="https://img.shields.io/discord/960281551428522045?color=%235865F2&label=discord" /></a>
|
<a href="https://deckbrew.xyz/discord"><img src="https://img.shields.io/discord/960281551428522045?color=%235865F2&label=discord" /></a>
|
||||||
<br>
|
<br>
|
||||||
<br>
|
<br>
|
||||||
<img src="https://media.discordapp.net/attachments/966017112244125756/1012466063893610506/main.jpg" alt="Decky screenshot" width="80%">
|
<img src="https://media.discordapp.net/attachments/966017112244125756/1012466063893610506/main.jpg" alt="Decky screenshot" width="80%">
|
||||||
@@ -62,7 +62,7 @@ For more information about Decky Loader as well as documentation and development
|
|||||||
|
|
||||||
### 👋 Uninstallation
|
### 👋 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.
|
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://deckbrew.xyz/discord) 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. 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. Select "Switch to Desktop".
|
||||||
@@ -84,15 +84,16 @@ Now that you have Decky Loader installed, you can start using plugins. Each plug
|
|||||||
|
|
||||||
### 🛠️ Plugin Development
|
### 🛠️ Plugin Development
|
||||||
|
|
||||||
There is no complete plugin development documentation yet. However a good starting point is the [plugin template repository](https://github.com/SteamDeckHomebrew/decky-plugin-template). Consider [joining our Discord](https://discord.gg/ZU74G2NJzk) if you have any questions.
|
There is no complete plugin development documentation yet. However a good starting point is the [plugin template repository](https://github.com/SteamDeckHomebrew/decky-plugin-template). Consider [joining our Discord](https://deckbrew.xyz/discord) if you have any questions.
|
||||||
|
|
||||||
### 🤝 Contributing
|
### 🤝 Contributing
|
||||||
|
|
||||||
Please consult [the wiki page regarding development](https://deckbrew.xyz/en/loader-dev/development) for more information on installing development versions of Decky Loader. You can also install the Steam Deck UI on a Windows or Linux computer for testing by following [this YouTube guide](https://youtu.be/1IAbZte8e7E?t=112).
|
Please consult [the wiki page regarding development](https://wiki.deckbrew.xyz/en/loader-dev/development) for more information on installing development versions of Decky Loader. You can also install the Steam Deck UI on a Windows or Linux computer for testing by following [this YouTube guide](https://youtu.be/1IAbZte8e7E?t=112).
|
||||||
|
|
||||||
1. Clone the repository using the latest commit to main before starting your PR.
|
1. Clone the repository using the latest commit to main before starting your PR.
|
||||||
1. In your clone of the repository, run these commands.
|
1. In your clone of the repository, run these commands.
|
||||||
```bash
|
```bash
|
||||||
|
cd frontend
|
||||||
pnpm i
|
pnpm i
|
||||||
pnpm run build
|
pnpm run build
|
||||||
```
|
```
|
||||||
|
|||||||
+12
-2
@@ -115,8 +115,18 @@ def mkdir_as_user(path):
|
|||||||
|
|
||||||
# Fetches the version of loader
|
# Fetches the version of loader
|
||||||
def get_loader_version() -> str:
|
def get_loader_version() -> str:
|
||||||
with open(os.path.join(os.path.dirname(sys.argv[0]), ".loader.version"), "r", encoding="utf-8") as version_file:
|
try:
|
||||||
return version_file.readline().replace("\n", "")
|
with open(os.path.join(os.getcwd(), ".loader.version"), "r", encoding="utf-8") as version_file:
|
||||||
|
return version_file.readline().strip()
|
||||||
|
except:
|
||||||
|
return "unknown"
|
||||||
|
|
||||||
|
# returns the appropriate system python paths
|
||||||
|
def get_system_pythonpaths() -> list[str]:
|
||||||
|
# run as normal normal user to also include user python paths
|
||||||
|
proc = subprocess.run(["python3", "-c", "import sys; print(':'.join(x for x in sys.path if x))"],
|
||||||
|
user=get_user_id(), env={}, capture_output=True)
|
||||||
|
return proc.stdout.decode().strip().split(":")
|
||||||
|
|
||||||
# Download Remote Binaries to local Plugin
|
# Download Remote Binaries to local Plugin
|
||||||
async def download_remote_binary_to_path(url, binHash, path) -> bool:
|
async def download_remote_binary_to_path(url, binHash, path) -> bool:
|
||||||
|
|||||||
+2
-7
@@ -6,14 +6,9 @@ from pathlib import Path
|
|||||||
from traceback import print_exc
|
from traceback import print_exc
|
||||||
|
|
||||||
from aiohttp import web
|
from aiohttp import web
|
||||||
from genericpath import exists
|
from os.path import exists
|
||||||
from watchdog.events import RegexMatchingEventHandler
|
from watchdog.events import RegexMatchingEventHandler
|
||||||
from watchdog.utils import UnsupportedLibc
|
from watchdog.observers import Observer
|
||||||
|
|
||||||
try:
|
|
||||||
from watchdog.observers.inotify import InotifyObserver as Observer
|
|
||||||
except UnsupportedLibc:
|
|
||||||
from watchdog.observers.fsevents import FSEventsObserver as Observer
|
|
||||||
|
|
||||||
from injector import get_tab, get_gamepadui_tab
|
from injector import get_tab, get_gamepadui_tab
|
||||||
from plugin import PluginWrapper
|
from plugin import PluginWrapper
|
||||||
|
|||||||
+10
-1
@@ -9,7 +9,7 @@ from logging import getLogger
|
|||||||
from traceback import format_exc
|
from traceback import format_exc
|
||||||
from os import path, setgid, setuid, environ
|
from os import path, setgid, setuid, environ
|
||||||
from signal import SIGINT, signal
|
from signal import SIGINT, signal
|
||||||
from sys import exit
|
from sys import exit, path as syspath
|
||||||
from time import time
|
from time import time
|
||||||
import helpers
|
import helpers
|
||||||
from updater import Updater
|
from updater import Updater
|
||||||
@@ -66,6 +66,7 @@ class PluginWrapper:
|
|||||||
environ["USER"] = "root" if "root" in self.flags else helpers.get_user()
|
environ["USER"] = "root" if "root" in self.flags else helpers.get_user()
|
||||||
environ["DECKY_VERSION"] = helpers.get_loader_version()
|
environ["DECKY_VERSION"] = helpers.get_loader_version()
|
||||||
environ["DECKY_USER"] = helpers.get_user()
|
environ["DECKY_USER"] = helpers.get_user()
|
||||||
|
environ["DECKY_USER_HOME"] = helpers.get_home_path()
|
||||||
environ["DECKY_HOME"] = helpers.get_homebrew_path()
|
environ["DECKY_HOME"] = helpers.get_homebrew_path()
|
||||||
environ["DECKY_PLUGIN_SETTINGS_DIR"] = path.join(environ["DECKY_HOME"], "settings", self.plugin_directory)
|
environ["DECKY_PLUGIN_SETTINGS_DIR"] = path.join(environ["DECKY_HOME"], "settings", self.plugin_directory)
|
||||||
helpers.mkdir_as_user(environ["DECKY_PLUGIN_SETTINGS_DIR"])
|
helpers.mkdir_as_user(environ["DECKY_PLUGIN_SETTINGS_DIR"])
|
||||||
@@ -77,11 +78,19 @@ class PluginWrapper:
|
|||||||
environ["DECKY_PLUGIN_NAME"] = self.name
|
environ["DECKY_PLUGIN_NAME"] = self.name
|
||||||
environ["DECKY_PLUGIN_VERSION"] = self.version
|
environ["DECKY_PLUGIN_VERSION"] = self.version
|
||||||
environ["DECKY_PLUGIN_AUTHOR"] = self.author
|
environ["DECKY_PLUGIN_AUTHOR"] = self.author
|
||||||
|
# append the loader's plugin path to the recognized python paths
|
||||||
|
syspath.append(path.realpath(path.join(path.dirname(__file__), "plugin")))
|
||||||
|
# append the plugin's `py_modules` to the recognized python paths
|
||||||
|
syspath.append(path.join(environ["DECKY_PLUGIN_DIR"], "py_modules"))
|
||||||
|
# append the system and user python paths
|
||||||
|
syspath.extend(helpers.get_system_pythonpaths())
|
||||||
spec = spec_from_file_location("_", self.file)
|
spec = spec_from_file_location("_", self.file)
|
||||||
module = module_from_spec(spec)
|
module = module_from_spec(spec)
|
||||||
spec.loader.exec_module(module)
|
spec.loader.exec_module(module)
|
||||||
self.Plugin = module.Plugin
|
self.Plugin = module.Plugin
|
||||||
|
|
||||||
|
if hasattr(self.Plugin, "_migration"):
|
||||||
|
get_event_loop().run_until_complete(self.Plugin._migration(self.Plugin))
|
||||||
if hasattr(self.Plugin, "_main"):
|
if hasattr(self.Plugin, "_main"):
|
||||||
get_event_loop().create_task(self.Plugin._main(self.Plugin))
|
get_event_loop().create_task(self.Plugin._main(self.Plugin))
|
||||||
get_event_loop().create_task(self._setup_socket())
|
get_event_loop().create_task(self._setup_socket())
|
||||||
|
|||||||
+8
-14
@@ -30,10 +30,7 @@ class Updater:
|
|||||||
}
|
}
|
||||||
self.remoteVer = None
|
self.remoteVer = None
|
||||||
self.allRemoteVers = None
|
self.allRemoteVers = None
|
||||||
try:
|
self.localVer = helpers.get_loader_version()
|
||||||
self.localVer = helpers.get_loader_version()
|
|
||||||
except:
|
|
||||||
self.localVer = False
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self.currentBranch = self.get_branch(self.context.settings)
|
self.currentBranch = self.get_branch(self.context.settings)
|
||||||
@@ -68,7 +65,7 @@ class Updater:
|
|||||||
logger.debug("current branch: %i" % ver)
|
logger.debug("current branch: %i" % ver)
|
||||||
if ver == -1:
|
if ver == -1:
|
||||||
logger.info("Current branch is not set, determining branch from version...")
|
logger.info("Current branch is not set, determining branch from version...")
|
||||||
if self.localVer.startswith("v") and self.localVer.find("-pre"):
|
if self.localVer.startswith("v") and "-pre" in self.localVer:
|
||||||
logger.info("Current version determined to be pre-release")
|
logger.info("Current version determined to be pre-release")
|
||||||
return 1
|
return 1
|
||||||
else:
|
else:
|
||||||
@@ -94,15 +91,12 @@ class Updater:
|
|||||||
return str(url)
|
return str(url)
|
||||||
|
|
||||||
async def get_version(self):
|
async def get_version(self):
|
||||||
if self.localVer:
|
return {
|
||||||
return {
|
"current": self.localVer,
|
||||||
"current": self.localVer,
|
"remote": self.remoteVer,
|
||||||
"remote": self.remoteVer,
|
"all": self.allRemoteVers,
|
||||||
"all": self.allRemoteVers,
|
"updatable": self.localVer != "unknown"
|
||||||
"updatable": self.localVer != None
|
}
|
||||||
}
|
|
||||||
else:
|
|
||||||
return {"current": "unknown", "remote": self.remoteVer, "all": self.allRemoteVers, "updatable": False}
|
|
||||||
|
|
||||||
async def check_for_updates(self):
|
async def check_for_updates(self):
|
||||||
logger.debug("checking for updates")
|
logger.debug("checking for updates")
|
||||||
|
|||||||
@@ -251,7 +251,7 @@ class Utilities:
|
|||||||
enumerable: true,
|
enumerable: true,
|
||||||
configurable: true,
|
configurable: true,
|
||||||
get: function() {
|
get: function() {
|
||||||
return FocusNavController?.m_ActiveContext?.ActiveWindow || window;
|
return (GamepadNavTree?.m_context?.m_controller || FocusNavController)?.m_ActiveContext?.ActiveWindow || window;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
""" + await res.text() + "\n}"
|
""" + await res.text() + "\n}"
|
||||||
|
|||||||
@@ -42,7 +42,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"decky-frontend-lib": "^3.18.10",
|
"decky-frontend-lib": "^3.19.1",
|
||||||
"react-file-icon": "^1.2.0",
|
"react-file-icon": "^1.2.0",
|
||||||
"react-icons": "^4.4.0",
|
"react-icons": "^4.4.0",
|
||||||
"react-markdown": "^8.0.3",
|
"react-markdown": "^8.0.3",
|
||||||
|
|||||||
Generated
+4
-4
@@ -11,7 +11,7 @@ specifiers:
|
|||||||
'@types/react-file-icon': ^1.0.1
|
'@types/react-file-icon': ^1.0.1
|
||||||
'@types/react-router': 5.1.18
|
'@types/react-router': 5.1.18
|
||||||
'@types/webpack': ^5.28.0
|
'@types/webpack': ^5.28.0
|
||||||
decky-frontend-lib: ^3.18.10
|
decky-frontend-lib: ^3.19.1
|
||||||
husky: ^8.0.1
|
husky: ^8.0.1
|
||||||
import-sort-style-module: ^6.0.0
|
import-sort-style-module: ^6.0.0
|
||||||
inquirer: ^8.2.4
|
inquirer: ^8.2.4
|
||||||
@@ -31,7 +31,7 @@ specifiers:
|
|||||||
typescript: ^4.7.4
|
typescript: ^4.7.4
|
||||||
|
|
||||||
dependencies:
|
dependencies:
|
||||||
decky-frontend-lib: 3.18.10
|
decky-frontend-lib: 3.19.1
|
||||||
react-file-icon: 1.2.0_wcqkhtmu7mswc6yz4uyexck3ty
|
react-file-icon: 1.2.0_wcqkhtmu7mswc6yz4uyexck3ty
|
||||||
react-icons: 4.4.0_react@16.14.0
|
react-icons: 4.4.0_react@16.14.0
|
||||||
react-markdown: 8.0.3_vshvapmxg47tngu7tvrsqpq55u
|
react-markdown: 8.0.3_vshvapmxg47tngu7tvrsqpq55u
|
||||||
@@ -975,8 +975,8 @@ packages:
|
|||||||
dependencies:
|
dependencies:
|
||||||
ms: 2.1.2
|
ms: 2.1.2
|
||||||
|
|
||||||
/decky-frontend-lib/3.18.10:
|
/decky-frontend-lib/3.19.1:
|
||||||
resolution: {integrity: sha512-2mgbA3sSkuwQR/FnmhXVrcW6LyTS95IuL6muJAmQCruhBvXapDtjk1TcgxqMZxFZwGD1IPnemPYxHZll6IgnZw==}
|
resolution: {integrity: sha512-hU4+EFs74MGzUCv8l1AO2+EBj9RRbnpU19Crm4u+3lbLu6d63U2GsUeQ9ssmNRcOMY1OuVZkRoZBE58soOBJ3A==}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/decode-named-character-reference/1.0.2:
|
/decode-named-character-reference/1.0.2:
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { Focusable, Router } from 'decky-frontend-lib';
|
import { Focusable, Navigation } from 'decky-frontend-lib';
|
||||||
import { FunctionComponent, useRef } from 'react';
|
import { FunctionComponent, useRef } from 'react';
|
||||||
import ReactMarkdown, { Options as ReactMarkdownOptions } from 'react-markdown';
|
import ReactMarkdown, { Options as ReactMarkdownOptions } from 'react-markdown';
|
||||||
import remarkGfm from 'remark-gfm';
|
import remarkGfm from 'remark-gfm';
|
||||||
@@ -22,7 +22,7 @@ const Markdown: FunctionComponent<MarkdownProps> = (props) => {
|
|||||||
onActivate={() => {}}
|
onActivate={() => {}}
|
||||||
onOKButton={() => {
|
onOKButton={() => {
|
||||||
props.onDismiss?.();
|
props.onDismiss?.();
|
||||||
Router.NavigateToExternalWeb(aRef.current!.href);
|
Navigation.NavigateToExternalWeb(aRef.current!.href);
|
||||||
}}
|
}}
|
||||||
style={{ display: 'inline' }}
|
style={{ display: 'inline' }}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -4,15 +4,11 @@ const QuickAccessVisibleState = createContext<boolean>(true);
|
|||||||
|
|
||||||
export const useQuickAccessVisible = () => useContext(QuickAccessVisibleState);
|
export const useQuickAccessVisible = () => useContext(QuickAccessVisibleState);
|
||||||
|
|
||||||
export const QuickAccessVisibleStateProvider: FC<{ initial: boolean; setter: ((val: boolean) => {}[]) | never[] }> = ({
|
export const QuickAccessVisibleStateProvider: FC<{ initial: boolean; tab: any }> = ({ children, initial, tab }) => {
|
||||||
children,
|
|
||||||
initial,
|
|
||||||
setter,
|
|
||||||
}) => {
|
|
||||||
const [visible, setVisible] = useState<boolean>(initial);
|
const [visible, setVisible] = useState<boolean>(initial);
|
||||||
const [prev, setPrev] = useState<boolean>(initial);
|
const [prev, setPrev] = useState<boolean>(initial);
|
||||||
// hack to use an array as a "pointer" to pass the setter up the tree
|
// HACK but i can't think of a better way to do this
|
||||||
setter[0] = setVisible;
|
tab.qAMVisibilitySetter = setVisible;
|
||||||
if (initial != prev) {
|
if (initial != prev) {
|
||||||
setPrev(initial);
|
setPrev(initial);
|
||||||
setVisible(initial);
|
setVisible(initial);
|
||||||
|
|||||||
@@ -4,13 +4,6 @@ import Logger from '../../../../logger';
|
|||||||
|
|
||||||
const logger = new Logger('LibraryPatch');
|
const logger = new Logger('LibraryPatch');
|
||||||
|
|
||||||
declare global {
|
|
||||||
interface Window {
|
|
||||||
SteamClient: any;
|
|
||||||
appDetailsStore: any;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let patch: Patch;
|
let patch: Patch;
|
||||||
|
|
||||||
function rePatch() {
|
function rePatch() {
|
||||||
@@ -20,7 +13,9 @@ function rePatch() {
|
|||||||
const details = window.appDetailsStore.GetAppDetails(appid);
|
const details = window.appDetailsStore.GetAppDetails(appid);
|
||||||
logger.debug('game details', details);
|
logger.debug('game details', details);
|
||||||
// strShortcutStartDir
|
// strShortcutStartDir
|
||||||
const file = await window.DeckyPluginLoader.openFilePicker(details.strShortcutStartDir.replaceAll('"', ''));
|
const file = await window.DeckyPluginLoader.openFilePicker(
|
||||||
|
details?.strShortcutStartDir.replaceAll('"', '') || '/',
|
||||||
|
);
|
||||||
logger.debug('user selected', file);
|
logger.debug('user selected', file);
|
||||||
window.SteamClient.Apps.SetShortcutExe(appid, JSON.stringify(file.path));
|
window.SteamClient.Apps.SetShortcutExe(appid, JSON.stringify(file.path));
|
||||||
const pathArr = file.path.split('/');
|
const pathArr = file.path.split('/');
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ export default function DeveloperSettings() {
|
|||||||
>
|
>
|
||||||
<Toggle
|
<Toggle
|
||||||
value={reactDevtoolsEnabled}
|
value={reactDevtoolsEnabled}
|
||||||
disabled={reactDevtoolsIP == ''}
|
// disabled={reactDevtoolsIP == ''}
|
||||||
onChange={(toggleValue) => {
|
onChange={(toggleValue) => {
|
||||||
setReactDevtoolsEnabled(toggleValue);
|
setReactDevtoolsEnabled(toggleValue);
|
||||||
setShouldConnectToReactDevTools(toggleValue);
|
setShouldConnectToReactDevTools(toggleValue);
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import {
|
|||||||
Focusable,
|
Focusable,
|
||||||
ProgressBarWithInfo,
|
ProgressBarWithInfo,
|
||||||
Spinner,
|
Spinner,
|
||||||
|
findSP,
|
||||||
showModal,
|
showModal,
|
||||||
} from 'decky-frontend-lib';
|
} from 'decky-frontend-lib';
|
||||||
import { useCallback } from 'react';
|
import { useCallback } from 'react';
|
||||||
@@ -14,7 +15,6 @@ import { useEffect, useState } from 'react';
|
|||||||
import { FaExclamation } from 'react-icons/fa';
|
import { FaExclamation } from 'react-icons/fa';
|
||||||
|
|
||||||
import { VerInfo, callUpdaterMethod, finishUpdate } from '../../../../updater';
|
import { VerInfo, callUpdaterMethod, finishUpdate } from '../../../../updater';
|
||||||
import { findSP } from '../../../../utils/windows';
|
|
||||||
import { useDeckyState } from '../../../DeckyState';
|
import { useDeckyState } from '../../../DeckyState';
|
||||||
import InlinePatchNotes from '../../../patchnotes/InlinePatchNotes';
|
import InlinePatchNotes from '../../../patchnotes/InlinePatchNotes';
|
||||||
import WithSuspense from '../../../WithSuspense';
|
import WithSuspense from '../../../WithSuspense';
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import Logger from '../../logger';
|
|||||||
import { StorePlugin, getPluginList } from '../../store';
|
import { StorePlugin, getPluginList } from '../../store';
|
||||||
import PluginCard from './PluginCard';
|
import PluginCard from './PluginCard';
|
||||||
|
|
||||||
const logger = new Logger('FilePicker');
|
const logger = new Logger('Store');
|
||||||
|
|
||||||
const StorePage: FC<{}> = () => {
|
const StorePage: FC<{}> = () => {
|
||||||
const [currentTabRoute, setCurrentTabRoute] = useState<string>('browse');
|
const [currentTabRoute, setCurrentTabRoute] = useState<string>('browse');
|
||||||
|
|||||||
@@ -123,11 +123,9 @@ class RouterHook extends Logger {
|
|||||||
this.wrapperPatch = afterPatch(this.gamepadWrapper, 'render', (_: any, ret: any) => {
|
this.wrapperPatch = afterPatch(this.gamepadWrapper, 'render', (_: any, ret: any) => {
|
||||||
if (ret?.props?.children?.props?.children?.length == 5 || ret?.props?.children?.props?.children?.length == 4) {
|
if (ret?.props?.children?.props?.children?.length == 5 || ret?.props?.children?.props?.children?.length == 4) {
|
||||||
const idx = ret?.props?.children?.props?.children?.length == 4 ? 1 : 2;
|
const idx = ret?.props?.children?.props?.children?.length == 4 ? 1 : 2;
|
||||||
if (
|
const potentialSettingsRootString =
|
||||||
ret.props.children.props.children[idx]?.props?.children?.[0]?.type?.type
|
ret.props.children.props.children[idx]?.props?.children?.[0]?.type?.type?.toString() || '';
|
||||||
?.toString()
|
if (potentialSettingsRootString?.includes('Settings.Root()')) {
|
||||||
?.includes('GamepadUI.Settings.Root()')
|
|
||||||
) {
|
|
||||||
if (!this.router) {
|
if (!this.router) {
|
||||||
this.router = ret.props.children.props.children[idx]?.props?.children?.[0]?.type;
|
this.router = ret.props.children.props.children[idx]?.props?.children?.[0]?.type;
|
||||||
this.routerPatch = afterPatch(this.router, 'type', (_: any, ret: any) => {
|
this.routerPatch = afterPatch(this.router, 'type', (_: any, ret: any) => {
|
||||||
|
|||||||
@@ -7,6 +7,6 @@ export function deinitSteamFixes() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function initSteamFixes() {
|
export async function initSteamFixes() {
|
||||||
fixes.push(reloadFix());
|
fixes.push(await reloadFix());
|
||||||
fixes.push(await restartFix());
|
fixes.push(await restartFix());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,17 @@
|
|||||||
|
import { getFocusNavController, sleep } from 'decky-frontend-lib';
|
||||||
|
|
||||||
import Logger from '../logger';
|
import Logger from '../logger';
|
||||||
|
|
||||||
const logger = new Logger('ReloadSteamFix');
|
const logger = new Logger('ReloadSteamFix');
|
||||||
|
|
||||||
export default function reloadFix() {
|
declare global {
|
||||||
|
var GamepadNavTree: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default async function reloadFix() {
|
||||||
// Hack to unbreak the ui when reloading it
|
// Hack to unbreak the ui when reloading it
|
||||||
if (window.FocusNavController?.m_rgAllContexts?.length == 0) {
|
await sleep(4000);
|
||||||
|
if (getFocusNavController()?.m_rgAllContexts?.length == 0) {
|
||||||
SteamClient.URL.ExecuteSteamURL('steam://open/settings');
|
SteamClient.URL.ExecuteSteamURL('steam://open/settings');
|
||||||
logger.log('Applied UI reload fix.');
|
logger.log('Applied UI reload fix.');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,13 +4,6 @@ import Logger from '../logger';
|
|||||||
|
|
||||||
const logger = new Logger('RestartSteamFix');
|
const logger = new Logger('RestartSteamFix');
|
||||||
|
|
||||||
declare global {
|
|
||||||
interface Window {
|
|
||||||
SteamClient: any;
|
|
||||||
appDetailsStore: any;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let patch: Patch;
|
let patch: Patch;
|
||||||
|
|
||||||
function rePatch() {
|
function rePatch() {
|
||||||
|
|||||||
@@ -128,22 +128,23 @@ class TabsHook extends Logger {
|
|||||||
let deckyTabAmount = existingTabs.reduce((prev: any, cur: any) => (cur.decky ? prev + 1 : prev), 0);
|
let deckyTabAmount = existingTabs.reduce((prev: any, cur: any) => (cur.decky ? prev + 1 : prev), 0);
|
||||||
if (deckyTabAmount == this.tabs.length) {
|
if (deckyTabAmount == this.tabs.length) {
|
||||||
for (let tab of existingTabs) {
|
for (let tab of existingTabs) {
|
||||||
if (tab?.decky) tab.panel.props.setter[0](visible);
|
if (tab?.decky && tab?.qAMVisibilitySetter) tab?.qAMVisibilitySetter(visible);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
for (const { title, icon, content, id } of this.tabs) {
|
for (const { title, icon, content, id } of this.tabs) {
|
||||||
existingTabs.push({
|
const tab: any = {
|
||||||
key: id,
|
key: id,
|
||||||
title,
|
title,
|
||||||
tab: icon,
|
tab: icon,
|
||||||
decky: true,
|
decky: true,
|
||||||
panel: (
|
};
|
||||||
<QuickAccessVisibleStateProvider initial={visible} setter={[]}>
|
tab.panel = (
|
||||||
{content}
|
<QuickAccessVisibleStateProvider initial={visible} tab={tab}>
|
||||||
</QuickAccessVisibleStateProvider>
|
{content}
|
||||||
),
|
</QuickAccessVisibleStateProvider>
|
||||||
});
|
);
|
||||||
|
existingTabs.push(tab);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,11 +40,14 @@ class Toaster extends Logger {
|
|||||||
let instance: any;
|
let instance: any;
|
||||||
const tree = (document.getElementById('root') as any)._reactRootContainer._internalRoot.current;
|
const tree = (document.getElementById('root') as any)._reactRootContainer._internalRoot.current;
|
||||||
const findToasterRoot = (currentNode: any, iters: number): any => {
|
const findToasterRoot = (currentNode: any, iters: number): any => {
|
||||||
if (iters >= 50) {
|
if (iters >= 65) {
|
||||||
// currently 40
|
// currently 65
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if (currentNode?.memoizedProps?.className?.startsWith?.('toastmanager_ToastPlaceholder')) {
|
if (
|
||||||
|
currentNode?.memoizedProps?.className?.startsWith?.('toastmanager_ToastPlaceholder') ||
|
||||||
|
currentNode?.memoizedProps?.className?.startsWith?.('toastmanager_ToastPopup')
|
||||||
|
) {
|
||||||
this.log(`Toaster root was found in ${iters} recursion cycles`);
|
this.log(`Toaster root was found in ${iters} recursion cycles`);
|
||||||
return currentNode;
|
return currentNode;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +0,0 @@
|
|||||||
export function findSP(): Window {
|
|
||||||
// old (SP as host)
|
|
||||||
if (document.title == 'SP') return window;
|
|
||||||
// new (SP as popup)
|
|
||||||
return FocusNavController.m_ActiveContext.m_rgGamepadNavigationTrees.find((x: any) => x.m_ID == 'root_1_').Root
|
|
||||||
.Element.ownerDocument.defaultView;
|
|
||||||
}
|
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"module": "ESNext",
|
"module": "ESNext",
|
||||||
"target": "ES2020",
|
"target": "ES2021",
|
||||||
"jsx": "react",
|
"jsx": "react",
|
||||||
"jsxFactory": "window.SP_REACT.createElement",
|
"jsxFactory": "window.SP_REACT.createElement",
|
||||||
"jsxFragmentFactory": "window.SP_REACT.Fragment",
|
"jsxFragmentFactory": "window.SP_REACT.Fragment",
|
||||||
|
|||||||
@@ -0,0 +1,201 @@
|
|||||||
|
"""
|
||||||
|
This module exposes various constants and helpers useful for decky plugins.
|
||||||
|
|
||||||
|
* Plugin's settings and configurations should be stored under `DECKY_PLUGIN_SETTINGS_DIR`.
|
||||||
|
* Plugin's runtime data should be stored under `DECKY_PLUGIN_RUNTIME_DIR`.
|
||||||
|
* Plugin's persistent log files should be stored under `DECKY_PLUGIN_LOG_DIR`.
|
||||||
|
|
||||||
|
Avoid writing outside of `DECKY_HOME`, storing under the suggested paths is strongly recommended.
|
||||||
|
|
||||||
|
Some basic migration helpers are available: `migrate_any`, `migrate_settings`, `migrate_runtime`, `migrate_logs`.
|
||||||
|
|
||||||
|
A logging facility `logger` is available which writes to the recommended location.
|
||||||
|
"""
|
||||||
|
|
||||||
|
__version__ = '0.1.0'
|
||||||
|
|
||||||
|
import os
|
||||||
|
import subprocess
|
||||||
|
import logging
|
||||||
|
|
||||||
|
"""
|
||||||
|
Constants
|
||||||
|
"""
|
||||||
|
|
||||||
|
HOME: str = os.getenv("HOME", default="")
|
||||||
|
"""
|
||||||
|
The home directory of the effective user running the process.
|
||||||
|
Environment variable: `HOME`.
|
||||||
|
If `root` was specified in the plugin's flags it will be `/root` otherwise the user whose home decky resides in.
|
||||||
|
e.g.: `/home/deck`
|
||||||
|
"""
|
||||||
|
|
||||||
|
USER: str = os.getenv("USER", default="")
|
||||||
|
"""
|
||||||
|
The effective username running the process.
|
||||||
|
Environment variable: `USER`.
|
||||||
|
It would be `root` if `root` was specified in the plugin's flags otherwise the user whose home decky resides in.
|
||||||
|
e.g.: `deck`
|
||||||
|
"""
|
||||||
|
|
||||||
|
DECKY_VERSION: str = os.getenv("DECKY_VERSION", default="")
|
||||||
|
"""
|
||||||
|
The version of the decky loader.
|
||||||
|
Environment variable: `DECKY_VERSION`.
|
||||||
|
e.g.: `v2.5.0-pre1`
|
||||||
|
"""
|
||||||
|
|
||||||
|
DECKY_USER: str = os.getenv("DECKY_USER", default="")
|
||||||
|
"""
|
||||||
|
The user whose home decky resides in.
|
||||||
|
Environment variable: `DECKY_USER`.
|
||||||
|
e.g.: `deck`
|
||||||
|
"""
|
||||||
|
|
||||||
|
DECKY_USER_HOME: str = os.getenv("DECKY_USER_HOME", default="")
|
||||||
|
"""
|
||||||
|
The home of the user where decky resides in.
|
||||||
|
Environment variable: `DECKY_USER_HOME`.
|
||||||
|
e.g.: `/home/deck`
|
||||||
|
"""
|
||||||
|
|
||||||
|
DECKY_HOME: str = os.getenv("DECKY_HOME", default="")
|
||||||
|
"""
|
||||||
|
The root of the decky folder.
|
||||||
|
Environment variable: `DECKY_HOME`.
|
||||||
|
e.g.: `/home/deck/homebrew`
|
||||||
|
"""
|
||||||
|
|
||||||
|
DECKY_PLUGIN_SETTINGS_DIR: str = os.getenv(
|
||||||
|
"DECKY_PLUGIN_SETTINGS_DIR", default="")
|
||||||
|
"""
|
||||||
|
The recommended path in which to store configuration files (created automatically).
|
||||||
|
Environment variable: `DECKY_PLUGIN_SETTINGS_DIR`.
|
||||||
|
e.g.: `/home/deck/homebrew/settings/decky-plugin-template`
|
||||||
|
"""
|
||||||
|
|
||||||
|
DECKY_PLUGIN_RUNTIME_DIR: str = os.getenv(
|
||||||
|
"DECKY_PLUGIN_RUNTIME_DIR", default="")
|
||||||
|
"""
|
||||||
|
The recommended path in which to store runtime data (created automatically).
|
||||||
|
Environment variable: `DECKY_PLUGIN_RUNTIME_DIR`.
|
||||||
|
e.g.: `/home/deck/homebrew/data/decky-plugin-template`
|
||||||
|
"""
|
||||||
|
|
||||||
|
DECKY_PLUGIN_LOG_DIR: str = os.getenv("DECKY_PLUGIN_LOG_DIR", default="")
|
||||||
|
"""
|
||||||
|
The recommended path in which to store persistent logs (created automatically).
|
||||||
|
Environment variable: `DECKY_PLUGIN_LOG_DIR`.
|
||||||
|
e.g.: `/home/deck/homebrew/logs/decky-plugin-template`
|
||||||
|
"""
|
||||||
|
|
||||||
|
DECKY_PLUGIN_DIR: str = os.getenv("DECKY_PLUGIN_DIR", default="")
|
||||||
|
"""
|
||||||
|
The root of the plugin's directory.
|
||||||
|
Environment variable: `DECKY_PLUGIN_DIR`.
|
||||||
|
e.g.: `/home/deck/homebrew/plugins/decky-plugin-template`
|
||||||
|
"""
|
||||||
|
|
||||||
|
DECKY_PLUGIN_NAME: str = os.getenv("DECKY_PLUGIN_NAME", default="")
|
||||||
|
"""
|
||||||
|
The name of the plugin as specified in the 'plugin.json'.
|
||||||
|
Environment variable: `DECKY_PLUGIN_NAME`.
|
||||||
|
e.g.: `Example Plugin`
|
||||||
|
"""
|
||||||
|
|
||||||
|
DECKY_PLUGIN_VERSION: str = os.getenv("DECKY_PLUGIN_VERSION", default="")
|
||||||
|
"""
|
||||||
|
The version of the plugin as specified in the 'package.json'.
|
||||||
|
Environment variable: `DECKY_PLUGIN_VERSION`.
|
||||||
|
e.g.: `0.0.1`
|
||||||
|
"""
|
||||||
|
|
||||||
|
DECKY_PLUGIN_AUTHOR: str = os.getenv("DECKY_PLUGIN_AUTHOR", default="")
|
||||||
|
"""
|
||||||
|
The author of the plugin as specified in the 'plugin.json'.
|
||||||
|
Environment variable: `DECKY_PLUGIN_AUTHOR`.
|
||||||
|
e.g.: `John Doe`
|
||||||
|
"""
|
||||||
|
|
||||||
|
DECKY_PLUGIN_LOG: str = os.path.join(DECKY_PLUGIN_LOG_DIR, "plugin.log")
|
||||||
|
"""
|
||||||
|
The path to the plugin's main logfile.
|
||||||
|
Environment variable: `DECKY_PLUGIN_LOG`.
|
||||||
|
e.g.: `/home/deck/homebrew/logs/decky-plugin-template/plugin.log`
|
||||||
|
"""
|
||||||
|
|
||||||
|
"""
|
||||||
|
Migration helpers
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def migrate_any(target_dir: str, *files_or_directories: str) -> dict[str, str]:
|
||||||
|
"""
|
||||||
|
Migrate files and directories to a new location and remove old locations.
|
||||||
|
Specified files will be migrated to `target_dir`.
|
||||||
|
Specified directories will have their contents recursively migrated to `target_dir`.
|
||||||
|
|
||||||
|
Returns the mapping of old -> new location.
|
||||||
|
"""
|
||||||
|
file_map: dict[str, str] = {}
|
||||||
|
for f in files_or_directories:
|
||||||
|
if not os.path.exists(f):
|
||||||
|
file_map[f] = ""
|
||||||
|
continue
|
||||||
|
if os.path.isdir(f):
|
||||||
|
src_dir = f
|
||||||
|
src_file = "."
|
||||||
|
file_map[f] = target_dir
|
||||||
|
else:
|
||||||
|
src_dir = os.path.dirname(f)
|
||||||
|
src_file = os.path.basename(f)
|
||||||
|
file_map[f] = os.path.join(target_dir, src_file)
|
||||||
|
subprocess.run(["sh", "-c", "mkdir -p \"$3\"; tar -cf - -C \"$1\" \"$2\" | tar -xf - -C \"$3\" && rm -rf \"$4\"",
|
||||||
|
"_", src_dir, src_file, target_dir, f])
|
||||||
|
return file_map
|
||||||
|
|
||||||
|
|
||||||
|
def migrate_settings(*files_or_directories: str) -> dict[str, str]:
|
||||||
|
"""
|
||||||
|
Migrate files and directories relating to plugin settings to the recommended location and remove old locations.
|
||||||
|
Specified files will be migrated to `DECKY_PLUGIN_SETTINGS_DIR`.
|
||||||
|
Specified directories will have their contents recursively migrated to `DECKY_PLUGIN_SETTINGS_DIR`.
|
||||||
|
|
||||||
|
Returns the mapping of old -> new location.
|
||||||
|
"""
|
||||||
|
return migrate_any(DECKY_PLUGIN_SETTINGS_DIR, *files_or_directories)
|
||||||
|
|
||||||
|
|
||||||
|
def migrate_runtime(*files_or_directories: str) -> dict[str, str]:
|
||||||
|
"""
|
||||||
|
Migrate files and directories relating to plugin runtime data to the recommended location and remove old locations
|
||||||
|
Specified files will be migrated to `DECKY_PLUGIN_RUNTIME_DIR`.
|
||||||
|
Specified directories will have their contents recursively migrated to `DECKY_PLUGIN_RUNTIME_DIR`.
|
||||||
|
|
||||||
|
Returns the mapping of old -> new location.
|
||||||
|
"""
|
||||||
|
return migrate_any(DECKY_PLUGIN_RUNTIME_DIR, *files_or_directories)
|
||||||
|
|
||||||
|
|
||||||
|
def migrate_logs(*files_or_directories: str) -> dict[str, str]:
|
||||||
|
"""
|
||||||
|
Migrate files and directories relating to plugin logs to the recommended location and remove old locations.
|
||||||
|
Specified files will be migrated to `DECKY_PLUGIN_LOG_DIR`.
|
||||||
|
Specified directories will have their contents recursively migrated to `DECKY_PLUGIN_LOG_DIR`.
|
||||||
|
|
||||||
|
Returns the mapping of old -> new location.
|
||||||
|
"""
|
||||||
|
return migrate_any(DECKY_PLUGIN_LOG_DIR, *files_or_directories)
|
||||||
|
|
||||||
|
|
||||||
|
"""
|
||||||
|
Logging
|
||||||
|
"""
|
||||||
|
|
||||||
|
logging.basicConfig(filename=DECKY_PLUGIN_LOG,
|
||||||
|
format='[%(asctime)s][%(levelname)s]: %(message)s',
|
||||||
|
force=True)
|
||||||
|
logger: logging.Logger = logging.getLogger()
|
||||||
|
"""The main plugin logger writing to `DECKY_PLUGIN_LOG`."""
|
||||||
|
|
||||||
|
logger.setLevel(logging.INFO)
|
||||||
@@ -0,0 +1,173 @@
|
|||||||
|
"""
|
||||||
|
This module exposes various constants and helpers useful for decky plugins.
|
||||||
|
|
||||||
|
* Plugin's settings and configurations should be stored under `DECKY_PLUGIN_SETTINGS_DIR`.
|
||||||
|
* Plugin's runtime data should be stored under `DECKY_PLUGIN_RUNTIME_DIR`.
|
||||||
|
* Plugin's persistent log files should be stored under `DECKY_PLUGIN_LOG_DIR`.
|
||||||
|
|
||||||
|
Avoid writing outside of `DECKY_HOME`, storing under the suggested paths is strongly recommended.
|
||||||
|
|
||||||
|
Some basic migration helpers are available: `migrate_any`, `migrate_settings`, `migrate_runtime`, `migrate_logs`.
|
||||||
|
|
||||||
|
A logging facility `logger` is available which writes to the recommended location.
|
||||||
|
"""
|
||||||
|
|
||||||
|
__version__ = '0.1.0'
|
||||||
|
|
||||||
|
import logging
|
||||||
|
|
||||||
|
"""
|
||||||
|
Constants
|
||||||
|
"""
|
||||||
|
|
||||||
|
HOME: str
|
||||||
|
"""
|
||||||
|
The home directory of the effective user running the process.
|
||||||
|
Environment variable: `HOME`.
|
||||||
|
If `root` was specified in the plugin's flags it will be `/root` otherwise the user whose home decky resides in.
|
||||||
|
e.g.: `/home/deck`
|
||||||
|
"""
|
||||||
|
|
||||||
|
USER: str
|
||||||
|
"""
|
||||||
|
The effective username running the process.
|
||||||
|
Environment variable: `USER`.
|
||||||
|
It would be `root` if `root` was specified in the plugin's flags otherwise the user whose home decky resides in.
|
||||||
|
e.g.: `deck`
|
||||||
|
"""
|
||||||
|
|
||||||
|
DECKY_VERSION: str
|
||||||
|
"""
|
||||||
|
The version of the decky loader.
|
||||||
|
Environment variable: `DECKY_VERSION`.
|
||||||
|
e.g.: `v2.5.0-pre1`
|
||||||
|
"""
|
||||||
|
|
||||||
|
DECKY_USER: str
|
||||||
|
"""
|
||||||
|
The user whose home decky resides in.
|
||||||
|
Environment variable: `DECKY_USER`.
|
||||||
|
e.g.: `deck`
|
||||||
|
"""
|
||||||
|
|
||||||
|
DECKY_USER_HOME: str
|
||||||
|
"""
|
||||||
|
The home of the user where decky resides in.
|
||||||
|
Environment variable: `DECKY_USER_HOME`.
|
||||||
|
e.g.: `/home/deck`
|
||||||
|
"""
|
||||||
|
|
||||||
|
DECKY_HOME: str
|
||||||
|
"""
|
||||||
|
The root of the decky folder.
|
||||||
|
Environment variable: `DECKY_HOME`.
|
||||||
|
e.g.: `/home/deck/homebrew`
|
||||||
|
"""
|
||||||
|
|
||||||
|
DECKY_PLUGIN_SETTINGS_DIR: str
|
||||||
|
"""
|
||||||
|
The recommended path in which to store configuration files (created automatically).
|
||||||
|
Environment variable: `DECKY_PLUGIN_SETTINGS_DIR`.
|
||||||
|
e.g.: `/home/deck/homebrew/settings/decky-plugin-template`
|
||||||
|
"""
|
||||||
|
|
||||||
|
DECKY_PLUGIN_RUNTIME_DIR: str
|
||||||
|
"""
|
||||||
|
The recommended path in which to store runtime data (created automatically).
|
||||||
|
Environment variable: `DECKY_PLUGIN_RUNTIME_DIR`.
|
||||||
|
e.g.: `/home/deck/homebrew/data/decky-plugin-template`
|
||||||
|
"""
|
||||||
|
|
||||||
|
DECKY_PLUGIN_LOG_DIR: str
|
||||||
|
"""
|
||||||
|
The recommended path in which to store persistent logs (created automatically).
|
||||||
|
Environment variable: `DECKY_PLUGIN_LOG_DIR`.
|
||||||
|
e.g.: `/home/deck/homebrew/logs/decky-plugin-template`
|
||||||
|
"""
|
||||||
|
|
||||||
|
DECKY_PLUGIN_DIR: str
|
||||||
|
"""
|
||||||
|
The root of the plugin's directory.
|
||||||
|
Environment variable: `DECKY_PLUGIN_DIR`.
|
||||||
|
e.g.: `/home/deck/homebrew/plugins/decky-plugin-template`
|
||||||
|
"""
|
||||||
|
|
||||||
|
DECKY_PLUGIN_NAME: str
|
||||||
|
"""
|
||||||
|
The name of the plugin as specified in the 'plugin.json'.
|
||||||
|
Environment variable: `DECKY_PLUGIN_NAME`.
|
||||||
|
e.g.: `Example Plugin`
|
||||||
|
"""
|
||||||
|
|
||||||
|
DECKY_PLUGIN_VERSION: str
|
||||||
|
"""
|
||||||
|
The version of the plugin as specified in the 'package.json'.
|
||||||
|
Environment variable: `DECKY_PLUGIN_VERSION`.
|
||||||
|
e.g.: `0.0.1`
|
||||||
|
"""
|
||||||
|
|
||||||
|
DECKY_PLUGIN_AUTHOR: str
|
||||||
|
"""
|
||||||
|
The author of the plugin as specified in the 'plugin.json'.
|
||||||
|
Environment variable: `DECKY_PLUGIN_AUTHOR`.
|
||||||
|
e.g.: `John Doe`
|
||||||
|
"""
|
||||||
|
|
||||||
|
DECKY_PLUGIN_LOG: str
|
||||||
|
"""
|
||||||
|
The path to the plugin's main logfile.
|
||||||
|
Environment variable: `DECKY_PLUGIN_LOG`.
|
||||||
|
e.g.: `/home/deck/homebrew/logs/decky-plugin-template/plugin.log`
|
||||||
|
"""
|
||||||
|
|
||||||
|
"""
|
||||||
|
Migration helpers
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def migrate_any(target_dir: str, *files_or_directories: str) -> dict[str, str]:
|
||||||
|
"""
|
||||||
|
Migrate files and directories to a new location and remove old locations.
|
||||||
|
Specified files will be migrated to `target_dir`.
|
||||||
|
Specified directories will have their contents recursively migrated to `target_dir`.
|
||||||
|
|
||||||
|
Returns the mapping of old -> new location.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def migrate_settings(*files_or_directories: str) -> dict[str, str]:
|
||||||
|
"""
|
||||||
|
Migrate files and directories relating to plugin settings to the recommended location and remove old locations.
|
||||||
|
Specified files will be migrated to `DECKY_PLUGIN_SETTINGS_DIR`.
|
||||||
|
Specified directories will have their contents recursively migrated to `DECKY_PLUGIN_SETTINGS_DIR`.
|
||||||
|
|
||||||
|
Returns the mapping of old -> new location.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def migrate_runtime(*files_or_directories: str) -> dict[str, str]:
|
||||||
|
"""
|
||||||
|
Migrate files and directories relating to plugin runtime data to the recommended location and remove old locations
|
||||||
|
Specified files will be migrated to `DECKY_PLUGIN_RUNTIME_DIR`.
|
||||||
|
Specified directories will have their contents recursively migrated to `DECKY_PLUGIN_RUNTIME_DIR`.
|
||||||
|
|
||||||
|
Returns the mapping of old -> new location.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def migrate_logs(*files_or_directories: str) -> dict[str, str]:
|
||||||
|
"""
|
||||||
|
Migrate files and directories relating to plugin logs to the recommended location and remove old locations.
|
||||||
|
Specified files will be migrated to `DECKY_PLUGIN_LOG_DIR`.
|
||||||
|
Specified directories will have their contents recursively migrated to `DECKY_PLUGIN_LOG_DIR`.
|
||||||
|
|
||||||
|
Returns the mapping of old -> new location.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
"""
|
||||||
|
Logging
|
||||||
|
"""
|
||||||
|
|
||||||
|
logger: logging.Logger
|
||||||
|
"""The main plugin logger writing to `DECKY_PLUGIN_LOG`."""
|
||||||
Reference in New Issue
Block a user