summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorxXJsonDeruloXx <danielhimebauch@gmail.com>2026-08-01 13:53:52 -0400
committerxXJsonDeruloXx <danielhimebauch@gmail.com>2026-08-01 13:53:52 -0400
commit63d758abe6318c5877e658c7a56282a7d90ede51 (patch)
treeffaa3450eee1ad5d88b1992d949a5fe623199720
parenteb51ec80231cf13accf8af156fa7a4283e2a2f88 (diff)
downloaddecky-lsfg-vk-63d758abe6318c5877e658c7a56282a7d90ede51.tar.gz
decky-lsfg-vk-63d758abe6318c5877e658c7a56282a7d90ede51.zip
feat: bundle v2 Flatpak runtime assetsagent/bundle-v2-flatpak-assets
-rw-r--r--README.md3
-rw-r--r--package.json23
-rw-r--r--py_modules/lsfg_vk/flatpak_service.py42
-rw-r--r--py_modules/lsfg_vk/plugin.py6
-rw-r--r--src/components/FlatpaksModal.tsx8
-rw-r--r--tests/test_lsfg_v2_migration.py24
6 files changed, 85 insertions, 21 deletions
diff --git a/README.md b/README.md
index a94d703..a1c233c 100644
--- a/README.md
+++ b/README.md
@@ -18,7 +18,7 @@
A Decky plugin that streamlines the installation of **lsfg-vk** ([Lossless Scaling Frame Generation Vulkan layer](https://github.com/PancakeTAS/lsfg-vk)) on Steam Deck, allowing you to use the Lossless Scaling frame generation features on Linux with a controller friendly UI in SteamOS, Bazzite, or any other Linux platform compatible with Decky Loader.
-> The v2 layer payload is currently pinned to the owner-fork prerelease [`v2.0.0-decky.1`](https://github.com/xXJSONDeruloXx/lsfg-vk/releases/tag/v2.0.0-decky.1).
+> The v2 native layer and Flatpak runtime payloads are pinned to the owner-fork prerelease [`v2.0.0-decky.2`](https://github.com/xXJSONDeruloXx/lsfg-vk/releases/tag/v2.0.0-decky.2).
## Installation
@@ -78,6 +78,7 @@ For per-game feedback and community support, please join the [decky-lsfg-vk Disc
The plugin:
- Downloads checksum-pinned x86_64 or Armada/aarch64 lsfg-vk v2 assets from the owner-fork release to `~/.local/lib/`
+- Bundles checksum-pinned lsfg-vk v2 Flatpak extensions for runtimes 23.08, 24.08, and 25.08, and installs the selected local bundle
- Configures the v2 Vulkan layer in `~/.local/share/vulkan/implicit_layer.d/`
- Migrates the existing `~/.config/lsfg-vk/conf.toml` from v1 to v2 automatically on layer update, retaining a one-time `.v1.bak` backup
- Automatically detects your Lossless Scaling DLL installation
diff --git a/package.json b/package.json
index 75bf2f7..36bf105 100644
--- a/package.json
+++ b/package.json
@@ -46,13 +46,28 @@
"remote_binary": [
{
"name": "lsfg-vk-layer-x86_64.tar.xz",
- "url": "https://github.com/xXJSONDeruloXx/lsfg-vk/releases/download/v2.0.0-decky.1/lsfg-vk-layer-x86_64.tar.xz",
- "sha256hash": "b96c60d838cd778797406bafc31e17a3698e8145248113c2bc41151b2823a6a0"
+ "url": "https://github.com/xXJSONDeruloXx/lsfg-vk/releases/download/v2.0.0-decky.2/lsfg-vk-layer-x86_64.tar.xz",
+ "sha256hash": "3bf5baaf391c6240de9978161a68aa8c9a54eff4246b79f9ea5b2ad1ec1a53a4"
},
{
"name": "lsfg-vk-layer-aarch64.tar.xz",
- "url": "https://github.com/xXJSONDeruloXx/lsfg-vk/releases/download/v2.0.0-decky.1/lsfg-vk-layer-aarch64.tar.xz",
- "sha256hash": "b1703042f50ff9470aa0b90953077949a9f144dcbd926f80fbb7e386e8393367"
+ "url": "https://github.com/xXJSONDeruloXx/lsfg-vk/releases/download/v2.0.0-decky.2/lsfg-vk-layer-aarch64.tar.xz",
+ "sha256hash": "ce08a04dc78ed1b1ca4bd03b9cf6c97ee233b0f5b2c2cc514509fae7e2eec412"
+ },
+ {
+ "name": "org.freedesktop.Platform.VulkanLayer.lsfg_vk_23.08.flatpak",
+ "url": "https://github.com/xXJSONDeruloXx/lsfg-vk/releases/download/v2.0.0-decky.2/org.freedesktop.Platform.VulkanLayer.lsfg_vk_23.08.flatpak",
+ "sha256hash": "7eff81f96b278fde6fe395c88461c55e611547bf5991d179b9145ec6f5a778b1"
+ },
+ {
+ "name": "org.freedesktop.Platform.VulkanLayer.lsfg_vk_24.08.flatpak",
+ "url": "https://github.com/xXJSONDeruloXx/lsfg-vk/releases/download/v2.0.0-decky.2/org.freedesktop.Platform.VulkanLayer.lsfg_vk_24.08.flatpak",
+ "sha256hash": "cbd663b9021c355dddec61ec51fd4388c12705f16637cadd4b45aead0e5dc427"
+ },
+ {
+ "name": "org.freedesktop.Platform.VulkanLayer.lsfg_vk_25.08.flatpak",
+ "url": "https://github.com/xXJSONDeruloXx/lsfg-vk/releases/download/v2.0.0-decky.2/org.freedesktop.Platform.VulkanLayer.lsfg_vk_25.08.flatpak",
+ "sha256hash": "615e87c03b18368ed1cca97e036f1bf54fff95fc6126aac697bb368f33281cbf"
}
],
"pnpm": {
diff --git a/py_modules/lsfg_vk/flatpak_service.py b/py_modules/lsfg_vk/flatpak_service.py
index 80dcf5d..5832cf4 100644
--- a/py_modules/lsfg_vk/flatpak_service.py
+++ b/py_modules/lsfg_vk/flatpak_service.py
@@ -9,6 +9,12 @@ from typing import Dict, Any, List, Optional
from .base_service import BaseService
from .config_schema import ConfigurationManager
+from .constants import (
+ BIN_DIR,
+ FLATPAK_23_08_FILENAME,
+ FLATPAK_24_08_FILENAME,
+ FLATPAK_25_08_FILENAME,
+)
from .types import BaseResponse
@@ -67,6 +73,21 @@ class FlatpakService(BaseService):
self.log.debug("Could not read configured DLL path for Flatpak override: %s", error)
return config_path, dll_directory
+ def _get_bundled_extension_path(self, version: str) -> Path:
+ """Return the checksum-pinned Flatpak bundle shipped with this plugin."""
+ filenames = {
+ "23.08": FLATPAK_23_08_FILENAME,
+ "24.08": FLATPAK_24_08_FILENAME,
+ "25.08": FLATPAK_25_08_FILENAME,
+ }
+ try:
+ filename = filenames[version]
+ except KeyError as error:
+ raise ValueError(f"Unsupported Flatpak runtime version: {version}") from error
+
+ plugin_dir = Path(__file__).resolve().parent.parent.parent
+ return plugin_dir / BIN_DIR / filename
+
def _remove_legacy_app_overrides(self, app_id: str) -> list[str]:
"""Remove only the v1 overrides previously created by this plugin."""
legacy_dll_path = self.user_home / ".local/share/Steam/steamapps/common/Lossless Scaling/Lossless.dll"
@@ -207,14 +228,14 @@ class FlatpakService(BaseService):
if not self.check_flatpak_available():
return self._error_response(BaseResponse, "Flatpak is not available on this system")
- if version == "23.08":
- return self._error_response(
- BaseResponse,
- "Flathub supplies the lsfg-vk v2 extension for runtimes 24.08 and 25.08; install 23.08 manually.",
- )
+ bundle_path = self._get_bundled_extension_path(version)
+ if not bundle_path.is_file():
+ error_msg = f"Bundled Flatpak extension not found at {bundle_path}; reinstall the plugin"
+ self.log.error(error_msg)
+ return self._error_response(BaseResponse, error_msg)
result = self._run_flatpak_command(
- ["install", "--user", "--noninteractive", "flathub", f"org.freedesktop.Platform.VulkanLayer.lsfgvk//{version}"],
+ ["install", "--user", "--noninteractive", str(bundle_path)],
capture_output=True, text=True
)
@@ -223,8 +244,11 @@ class FlatpakService(BaseService):
self.log.error(error_msg)
return self._error_response(BaseResponse, error_msg)
- self.log.info(f"Successfully installed lsfg-vk Flatpak extension {version}")
- return self._success_response(BaseResponse, f"lsfg-vk {version} runtime extension installed successfully")
+ self.log.info("Successfully installed bundled lsfg-vk Flatpak extension %s", version)
+ return self._success_response(
+ BaseResponse,
+ f"lsfg-vk {version} runtime extension installed successfully from the bundled asset",
+ )
except Exception as e:
error_msg = f"Error installing Flatpak extension {version}: {str(e)}"
@@ -465,4 +489,4 @@ class FlatpakService(BaseService):
error_msg = f"Error removing overrides for {app_id}: {str(e)}"
self.log.error(error_msg)
return self._error_response(FlatpakOverrideResponse, error_msg,
- app_id=app_id, operation="remove") \ No newline at end of file
+ app_id=app_id, operation="remove")
diff --git a/py_modules/lsfg_vk/plugin.py b/py_modules/lsfg_vk/plugin.py
index aefec3e..c2f22e3 100644
--- a/py_modules/lsfg_vk/plugin.py
+++ b/py_modules/lsfg_vk/plugin.py
@@ -354,7 +354,7 @@ class Plugin:
"""Check status of lsfg-vk Flatpak runtime extensions
Returns:
- FlatpakExtensionStatus dict with installation status for both runtime versions
+ FlatpakExtensionStatus dict with installation status for all supported runtime versions
"""
return self.flatpak_service.get_extension_status()
@@ -362,7 +362,7 @@ class Plugin:
"""Install lsfg-vk Flatpak runtime extension
Args:
- version: Runtime version to install ("23.08" or "24.08")
+ version: Runtime version to install ("23.08", "24.08", or "25.08")
Returns:
BaseResponse dict with success status and message/error
@@ -373,7 +373,7 @@ class Plugin:
"""Uninstall lsfg-vk Flatpak runtime extension
Args:
- version: Runtime version to uninstall ("23.08" or "24.08")
+ version: Runtime version to uninstall ("23.08", "24.08", or "25.08")
Returns:
BaseResponse dict with success status and message/error
diff --git a/src/components/FlatpaksModal.tsx b/src/components/FlatpaksModal.tsx
index 0ab715a..a6a0e85 100644
--- a/src/components/FlatpaksModal.tsx
+++ b/src/components/FlatpaksModal.tsx
@@ -175,7 +175,7 @@ export const FlatpaksModal: FC<FlatpaksModalProps> = ({ closeModal }) => {
<PanelSectionRow>
<Field
label="Runtime 23.08"
- description={extensionStatus.installed_23_08 ? "Installed (manual)" : "Manual installation only; use runtime 24.08 or 25.08 when possible"}
+ description={extensionStatus.installed_23_08 ? "Installed" : "Bundled asset ready to install"}
icon={extensionStatus.installed_23_08 ? <FaCheck style={{color: 'green'}} /> : <FaTimes style={{color: 'red'}} />}
>
<ButtonItem
@@ -194,7 +194,7 @@ export const FlatpaksModal: FC<FlatpaksModalProps> = ({ closeModal }) => {
action();
}
}}
- disabled={!extensionStatus.installed_23_08 || operationInProgress === 'install-23.08' || operationInProgress === 'uninstall-23.08'}
+ disabled={operationInProgress === 'install-23.08' || operationInProgress === 'uninstall-23.08'}
>
{operationInProgress === 'install-23.08' || operationInProgress === 'uninstall-23.08' ? (
<Spinner />
@@ -215,7 +215,7 @@ export const FlatpaksModal: FC<FlatpaksModalProps> = ({ closeModal }) => {
<PanelSectionRow>
<Field
label="Runtime 24.08"
- description={extensionStatus.installed_24_08 ? "Installed" : "Not installed"}
+ description={extensionStatus.installed_24_08 ? "Installed" : "Bundled asset ready to install"}
icon={extensionStatus.installed_24_08 ? <FaCheck style={{color: 'green'}} /> : <FaTimes style={{color: 'red'}} />}
>
<ButtonItem
@@ -255,7 +255,7 @@ export const FlatpaksModal: FC<FlatpaksModalProps> = ({ closeModal }) => {
<PanelSectionRow>
<Field
label="Runtime 25.08"
- description={extensionStatus.installed_25_08 ? "Installed" : "Not installed"}
+ description={extensionStatus.installed_25_08 ? "Installed" : "Bundled asset ready to install"}
icon={extensionStatus.installed_25_08 ? <FaCheck style={{color: 'green'}} /> : <FaTimes style={{color: 'red'}} />}
>
<ButtonItem
diff --git a/tests/test_lsfg_v2_migration.py b/tests/test_lsfg_v2_migration.py
index cb590df..bb5a0b1 100644
--- a/tests/test_lsfg_v2_migration.py
+++ b/tests/test_lsfg_v2_migration.py
@@ -207,6 +207,30 @@ class InstallerInfrastructureTests(unittest.TestCase):
class FlatpakMigrationTests(unittest.TestCase):
+ def test_install_uses_the_bundled_flatpak_asset(self):
+ from lsfg_vk.flatpak_service import FlatpakService
+
+ with tempfile.TemporaryDirectory() as directory:
+ bundle_path = Path(directory) / "org.freedesktop.Platform.VulkanLayer.lsfg_vk_23.08.flatpak"
+ bundle_path.write_bytes(b"flatpak bundle")
+
+ service = FlatpakService.__new__(FlatpakService)
+ service.log = mock.Mock()
+ service.check_flatpak_available = mock.Mock(return_value=True)
+ service._get_bundled_extension_path = mock.Mock(return_value=bundle_path)
+ service._run_flatpak_command = mock.Mock(
+ return_value=types.SimpleNamespace(returncode=0, stdout="", stderr="")
+ )
+
+ result = service.install_extension("23.08")
+
+ self.assertTrue(result["success"])
+ service._run_flatpak_command.assert_called_once_with(
+ ["install", "--user", "--noninteractive", str(bundle_path)],
+ capture_output=True,
+ text=True,
+ )
+
def test_v2_override_setup_and_removal_clean_legacy_overrides(self):
from lsfg_vk.flatpak_service import FlatpakService