Compare commits

...

24 Commits

Author SHA1 Message Date
Devon Schneider ec907627b8 Use a conditional while loop for when the scroll root is not found. (#212)
* Changed back to a while loop for grabbing the scroll root\nAs recursive function exits before it hits 30 iterations in testing.

* Changed so if recursive limit is hit, it returns null instead of attempting to continue.

* Added log messages regarding recursion limits, as well as fixed recursion tracking.

* Removed errant return remaining from scroll root check.
2022-10-08 06:35:21 -07:00
AAGaming a3809222f9 disable file watcher until after 10 seconds 2022-10-07 22:38:20 -04:00
Party Wumpus 86dc706892 README: password typing clarification (#208)
While the video does *show* the password not appearing, he doesn't mention it.
This should reduce the occasional user confusion of passwords not appearing.
2022-10-07 09:35:59 -07:00
Eddie Dover 0e409a9f96 Add plugin description to Store PluginCard (#196)
* Add plugin description to Store PluginCard

The description for plugins is available on the web but not in the store, this attempts to fix the issue.

Unfortunately, my current env is completely Windows based so I cannot test this change locally, and setting up an Arch env in WSL2 is proving to be more time consuming than such a simple PR deserves.

* Removed prefix from description

* Apply suggestions from code review

Co-authored-by: Party Wumpus <48649272+PartyWumpus@users.noreply.github.com>

* Inline style fix.

Co-authored-by: Party Wumpus <48649272+PartyWumpus@users.noreply.github.com>

* Prettier formatting fix

* Apply suggestions from code review

Co-authored-by: Party Wumpus <48649272+PartyWumpus@users.noreply.github.com>

* Apply suggestions from code review

Co-authored-by: Party Wumpus <48649272+PartyWumpus@users.noreply.github.com>

Co-authored-by: Party Wumpus <48649272+PartyWumpus@users.noreply.github.com>
2022-10-05 14:24:02 -07:00
Devon Schneider d58001c323 Fixed an issue regarding the scroll root path (#201)
* Changed so searching for the scroll root node will look through siblings of children nodes.

* Added a missing await

Seem to have missed an await from when I was converting my proof-of-concept to an async function.

* Minor stylistic change

* Changed where program retries to find the scroll root.
2022-10-04 11:54:54 -07:00
TrainDoctor d727ba72f3 Fix outdated line about manual install 2022-10-02 10:56:06 -07:00
TrainDoctor fa028fa525 Update build.yml 2022-10-02 08:19:41 -07:00
TrainDoctor c947548064 Update build.yml 2022-10-02 08:11:00 -07:00
AAGaming 19d5527bdf ACTUALLY FIX the friends focus workaround 2022-10-02 10:29:33 -04:00
AAGaming ef51b96f08 fix styling on links in markdown 2022-10-02 10:14:51 -04:00
AAGaming 617916e8e5 actually fix focus issue on startup 2022-10-01 23:10:25 -04:00
TrainDoctor 6c4a4d0a44 Update install_release.sh 2022-10-01 19:04:05 -07:00
TrainDoctor bedcb0fb71 Update README.md 2022-10-01 18:58:59 -07:00
AAGaming 2461f52ca7 change console.log to styled log 2022-10-01 21:24:10 -04:00
AAGaming 3c00eb8cf4 fix friends menu focusing itself 2022-10-01 21:22:30 -04:00
TrainDoctor 21e1d8504a Update README.md 2022-10-01 16:17:40 -07:00
Party Wumpus ba93c4add2 Change 'PluginLoader' to 'Decky Loader' in readme (#190)
* (readme) Make store link go to beta.deckbrew + Change wording for clarification

* further change

* change line 26 to say plugin menu

* Change all 'PluginLoader' to 'Decky Loader' in readme

Seems like a reasonable change as Decky was rebranded a while ago
2022-10-01 14:41:09 -07:00
TrainDoctor 61fea41c8a Update package.json 2022-09-30 21:40:51 -07:00
TrainDoctor e40d3e4db5 Removal of legacy link 2022-09-30 21:31:19 -07:00
Lukas Senionis bbad6bf2be fix(pluginview): align icon and plugin name (#185) 2022-09-26 21:51:39 -07:00
Party Wumpus 4e04455163 (readme) Make store link go to beta.deckbrew + Change wording (#184)
* (readme) Make store link go to beta.deckbrew + Change wording for clarification

* further change

* change line 26 to say plugin menu
2022-09-25 10:04:50 -07:00
Dan Burkhardt 314292b042 updated installation steps to reflect confirmation and system reboot step (#180)
Co-authored-by: TrainDoctor <traindoctor@protonmail.com>
2022-09-21 15:05:18 -07:00
Aamir Tahir a264f36966 Add note about opening terminal to README (#176)
Quick note about how to open the terminal using the pre-installed Konsole app for users that are either new to linux or Steam Deck.
2022-09-21 14:56:45 -07:00
AAGaming 60c8c5db42 check for plugin updates after installing a plugin 2022-09-19 21:13:06 -04:00
12 changed files with 123 additions and 33 deletions
+2 -2
View File
@@ -109,7 +109,7 @@ jobs:
printf "OUT: ${OUT}\n"
elif [[ ! "$VERSION" =~ "-pre" ]]; then
printf "previous tag is a release, bumping by a patch\n"
OUT=$(semver bump minor "$VERSION")
OUT=$(semver bump patch "$VERSION")
printf "OUT: ${OUT}\n"
fi
echo "vOUT: v$OUT"
@@ -171,7 +171,7 @@ jobs:
OUT=""
if [[ ! "$VERSION" =~ "-pre" ]]; then
printf "is release, bumping minor version and prerel\n"
OUT=$(semver bump minor "$VERSION")
OUT=$(semver bump patch "$VERSION")
OUT="$OUT-pre"
OUT=$(semver bump prerel "$OUT")
printf "OUT: ${OUT}\n"
+14 -12
View File
@@ -1,29 +1,31 @@
# Plugin Loader [![Chat](https://img.shields.io/badge/chat-on%20discord-7289da.svg)](https://discord.gg/ZU74G2NJzk)
# Decky Loader [![Chat](https://img.shields.io/badge/chat-on%20discord-7289da.svg)](https://discord.gg/ZU74G2NJzk)
![Decky](https://media.discordapp.net/attachments/966017112244125756/1012466063893610506/main.jpg)
Keep an eye on the [Wiki](https://deckbrew.xyz) for more information about Plugin Loader, documentation + tools for plugin development and more.
Keep an eye on the [Wiki](https://deckbrew.xyz) for more information about Decky Loader, documentation + tools for plugin development and more.
## Installation
1. Go into the Steam Deck Settings
2. Under System -> System Settings toggle `Enable Developer Mode`
3. Scroll the sidebar all the way down and click on `Developer`
4. Under Miscellaneous, enable `CEF Remote Debugging`
5. Click on the `STEAM` button and select `Power` -> `Switch to Desktop`
6. Make sure you have a password set with the "passwd" command in terminal to install it ([YouTube Guide](https://www.youtube.com/watch?v=1vOMYGj22rQ)).
7. Open a terminal and paste the following command into it:
5. Confirm dialog and wait for system reboot
6. Click on the `STEAM` button and select `Power` -> `Switch to Desktop`
7. Make sure you have a password set with the "passwd" command in terminal to install it ([YouTube Guide](https://www.youtube.com/watch?v=1vOMYGj22rQ)).
- It will look like the password isn't typing properly. That's normal, it's a security feature (Similar to `***` when typing passwords online)
8. Open a terminal ("Konsole" is the pre-installed terminal application) and paste the following command into it:
- For the latest release:
- `curl -L https://github.com/SteamDeckHomebrew/decky-loader/raw/main/dist/install_release.sh | sh`
- For the latest pre-release:
- `curl -L https://github.com/SteamDeckHomebrew/decky-loader/raw/main/dist/install_prerelease.sh | sh`
- For testers/plugin developers:
- `curl -L https://github.com/SteamDeckHomebrew/decky-loader/raw/main/dist/install_prerelease.sh | sh`
- [Wiki Link](https://deckbrew.xyz/en/loader-dev/development)
- For the legacy version (unsupported):
- `curl -L https://github.com/SteamDeckHomebrew/decky-loader/raw/legacy/dist/install_release.sh | sh`
7. Done! Reboot back into Gaming mode and enjoy your plugins!
9. Done! Reboot back into Gaming mode and enjoy your plugins!
### Install/Uninstall Plugins
- Using the shopping bag button in the top right corner, you can go to the offical ["Plugin Store"](https://plugins.deckbrew.xyz/)
- Simply copy the plugin's folder into `~/homebrew/plugins`
- Using the shopping bag button in the top right corner of the plugin menu, you can go to the offical Plugin Store ([Web Preview](https://beta.deckbrew.xyz/)).
- Install from URL in the settings menu.
- Use the settings menu to uninstall plugins, this will not remove any files made in different directories by plugins.
### Uninstall
@@ -41,8 +43,8 @@ Keep an eye on the [Wiki](https://deckbrew.xyz) for more information about Plugi
- There is no complete plugin development documentation yet. However a good starting point is the [Plugin Template](https://github.com/SteamDeckHomebrew/decky-plugin-template) repository.
## [Contribution](https://deckbrew.xyz/en/loader-dev/development)
- Please consult the [Wiki](https://deckbrew.xyz/en/loader-dev/development) for installing development versions of PluginLoader.
- This is also useful for Plugin Developers looking to target new but unreleased versions of PluginLoader.
- Please consult the [Wiki](https://deckbrew.xyz/en/loader-dev/development) for installing development versions of Decky Loader.
- This is also useful for Plugin Developers looking to target new but unreleased versions of Decky Loader.
- [Here's how to get the Steam Deck UI on your enviroment of choice.](https://youtu.be/1IAbZte8e7E?t=112)
- (The video shows Windows usage but unless you're using Arch WSL/cygwin this script is unsupported on Windows.)
+9 -1
View File
@@ -25,7 +25,7 @@ class FileChangeHandler(RegexMatchingEventHandler):
self.logger = getLogger("file-watcher")
self.plugin_path = plugin_path
self.queue = queue
self.disabled = False
self.disabled = True
def maybe_reload(self, src_path):
if self.disabled:
@@ -70,6 +70,7 @@ class Loader:
self.logger.info(f"plugin_path: {self.plugin_path}")
self.plugins = {}
self.watcher = None
self.live_reload = live_reload
if live_reload:
self.reload_queue = Queue()
@@ -78,6 +79,7 @@ class Loader:
self.observer.schedule(self.watcher, self.plugin_path, recursive=True)
self.observer.start()
self.loop.create_task(self.handle_reloads())
self.loop.create_task(self.enable_reload_wait())
server_instance.add_routes([
web.get("/frontend/{path:.*}", self.handle_frontend_assets),
@@ -92,6 +94,12 @@ class Loader:
web.get("/steam_resource/{path:.+}", self.get_steam_resource)
])
async def enable_reload_wait(self):
if self.live_reload:
await sleep(10)
self.logger.info("Hot reload enabled")
self.watcher.disabled = False
async def handle_frontend_assets(self, request):
file = path.join(path.dirname(__file__), "static", request.match_info["path"])
+7 -2
View File
@@ -13,8 +13,13 @@ sudo -u $SUDO_USER mkdir -p "${HOMEBREW_FOLDER}/services"
sudo -u $SUDO_USER mkdir -p "${HOMEBREW_FOLDER}/plugins"
# Download latest release and install it
curl -L https://github.com/SteamDeckHomebrew/PluginLoader/releases/latest/download/PluginLoader --output "${HOMEBREW_FOLDER}/services/PluginLoader"
chmod +x "${HOMEBREW_FOLDER}/services/PluginLoader"
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}))
printf "Installing version %s...\n" "${VERSION}"
curl -L $DOWNLOADURL --output ${HOMEBREW_FOLDER}/services/PluginLoader
chmod +x ${HOMEBREW_FOLDER}/services/PluginLoader
echo $VERSION > ${HOMEBREW_FOLDER}/services/.loader.version
systemctl --user stop plugin_loader 2> /dev/null
systemctl --user disable plugin_loader 2> /dev/null
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "decky_frontend",
"version": "0.0.1",
"version": "2.1.1",
"private": true,
"license": "GPLV2",
"scripts": {
+1
View File
@@ -24,6 +24,7 @@ const Markdown: FunctionComponent<MarkdownProps> = (props) => {
aRef?.current?.click();
props.onDismiss?.();
}}
style={{ display: 'inline' }}
>
<a ref={aRef} {...nodeProps.node.properties}>
{nodeProps.children}
+2 -2
View File
@@ -32,8 +32,8 @@ const PluginView: VFC = () => {
.map(({ name, icon }) => (
<PanelSectionRow key={name}>
<ButtonItem layout="below" onClick={() => setActivePlugin(name)}>
<div style={{ display: 'flex', justifyContent: 'space-between' }}>
<div>{icon}</div>
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
{icon}
<div>{name}</div>
<NotificationBadge show={updates?.has(name)} style={{ top: '-5px', right: '-5px' }} />
</div>
@@ -21,6 +21,7 @@ const PluginInstallModal: FC<PluginInstallModalProps> = ({ artifact, version, ha
setLoading(true);
await onOK();
setTimeout(() => Router.OpenQuickAccessMenu(QuickAccessTab.Decky), 250);
setTimeout(() => window.DeckyPluginLoader.checkPluginUpdates(), 1000);
}}
onCancel={async () => {
await onCancel();
+13 -2
View File
@@ -113,8 +113,19 @@ const PluginCard: FC<PluginCardProps> = ({ plugin }) => {
}}
className="deckyStoreCardInfo"
>
<p className={joinClassNames(staticClasses.PanelSectionRow)}>
<span>Author: {plugin.author}</span>
<p className={joinClassNames(staticClasses.PanelSectionRow)} style={{ marginTop: '0px', marginLeft: '16px'}}>
<span style={{ paddingLeft: '0px' }}>Author: {plugin.author}</span>
</p>
<p
className={joinClassNames(staticClasses.PanelSectionRow)}
style={{
marginLeft: '16px',
marginTop: '0px',
marginBottom: '0px',
marginRight: '16px'
}}
>
<span style={{ paddingLeft: '0px' }}>{plugin.description}</span>
</p>
<p
className={joinClassNames('deckyStoreCardTagsContainer', staticClasses.PanelSectionRow)}
+48 -1
View File
@@ -1,4 +1,16 @@
import { ConfirmModal, ModalRoot, QuickAccessTab, Router, showModal, sleep, staticClasses } from 'decky-frontend-lib';
import {
ConfirmModal,
ModalRoot,
Patch,
QuickAccessTab,
Router,
callOriginal,
findModuleChild,
replacePatch,
showModal,
sleep,
staticClasses,
} from 'decky-frontend-lib';
import { lazy } from 'react';
import { FaPlug } from 'react-icons/fa';
@@ -39,6 +51,8 @@ class PluginLoader extends Logger {
// stores a list of plugin names which requested to be reloaded
private pluginReloadQueue: { name: string; version?: string }[] = [];
private focusWorkaroundPatch?: Patch;
constructor() {
super(PluginLoader.name);
this.log('Initialized');
@@ -83,6 +97,38 @@ class PluginLoader extends Logger {
initFilepickerPatches();
this.updateVersion();
const self = this;
try {
// TODO remove all of this once Valve fixes the bug
const focusManager = findModuleChild((m) => {
if (typeof m !== 'object') return false;
for (let prop in m) {
if (m[prop]?.prototype?.TakeFocus) return m[prop];
}
return false;
});
this.focusWorkaroundPatch = replacePatch(focusManager.prototype, 'TakeFocus', function () {
// @ts-ignore
const classList = this.m_node?.m_element.classList;
if (
// @ts-ignore
(this.m_node?.m_element && classList.contains(staticClasses.TabGroupPanel)) ||
classList.contains('FriendsListTab') ||
classList.contains('FriendsTabList') ||
classList.contains('FriendsListAndChatsSteamDeck')
) {
self.debug('Intercepted friends re-focus');
return true;
}
return callOriginal;
});
} catch (e) {
this.error('Friends focus patch failed', e);
}
}
public async updateVersion() {
@@ -167,6 +213,7 @@ class PluginLoader extends Logger {
this.routerHook.removeRoute('/decky/store');
this.routerHook.removeRoute('/decky/settings');
deinitFilepickerPatches();
this.focusWorkaroundPatch?.unpatch();
}
public unloadPlugin(name: string) {
+24 -10
View File
@@ -47,18 +47,31 @@ class TabsHook extends Logger {
const self = this;
const tree = (document.getElementById('root') as any)._reactRootContainer._internalRoot.current;
let scrollRoot: any;
let currentNode = tree;
async function findScrollRoot(currentNode: any, iters: number): Promise<any> {
if (iters >= 30) {
self.error(
'Scroll root was not found before hitting the recursion limit, a developer will need to increase the limit.',
);
return null;
}
currentNode = currentNode?.child;
if (currentNode?.type?.prototype?.RemoveSmartScrollContainer) {
self.log(`Scroll root was found in ${iters} recursion cycles`);
return currentNode;
}
if (!currentNode) return null;
if (currentNode.sibling) {
let node = await findScrollRoot(currentNode.sibling, iters + 1);
if (node !== null) return node;
}
return await findScrollRoot(currentNode, iters + 1);
}
(async () => {
let iters = 0;
scrollRoot = await findScrollRoot(tree, 0);
while (!scrollRoot) {
iters++;
currentNode = currentNode?.child;
if (iters >= 30 || !currentNode) {
iters = 0;
currentNode = tree;
await sleep(5000);
}
if (currentNode?.type?.prototype?.RemoveSmartScrollContainer) scrollRoot = currentNode;
this.log('Failed to find scroll root node, reattempting in 5 seconds');
await sleep(5000);
scrollRoot = await findScrollRoot(tree, 0);
}
let newQA: any;
let newQATabRenderer: any;
@@ -101,6 +114,7 @@ class TabsHook extends Logger {
});
this.cNode = scrollRoot;
this.cNode.stateNode.forceUpdate();
this.log('Finished initial injection');
})();
}
+1
View File
@@ -27,6 +27,7 @@ class Toaster extends Logger {
async init() {
let instance: any;
while (true) {
instance = findInReactTree(
(document.getElementById('root') as any)._reactRootContainer._internalRoot.current,