diff options
| author | Kurt Himebauch <136133082+xXJSONDeruloXx@users.noreply.github.com> | 2026-09-05 15:33:30 -0400 |
|---|---|---|
| committer | Kurt Himebauch <136133082+xXJSONDeruloXx@users.noreply.github.com> | 2026-09-05 15:33:30 -0400 |
| commit | e64e87e9eb9e3c183ad7807dffa356f47d14e825 (patch) | |
| tree | 114373042d547b763522844b05ef91a5923e60ce | |
| parent | 4fe21381b6c694d5eb615447c4827e4921593a52 (diff) | |
| download | decky-lsfg-vk-e64e87e9eb9e3c183ad7807dffa356f47d14e825.tar.gz decky-lsfg-vk-e64e87e9eb9e3c183ad7807dffa356f47d14e825.zip | |
fix: migrate flatpak integration to v2
| -rw-r--r-- | package.json | 15 | ||||
| -rw-r--r-- | py_modules/lsfg_vk/constants.py | 2 | ||||
| -rw-r--r-- | py_modules/lsfg_vk/flatpak_service.py | 662 | ||||
| -rw-r--r-- | py_modules/lsfg_vk/plugin.py | 44 | ||||
| -rw-r--r-- | src/api/lsfgApi.ts | 1 | ||||
| -rw-r--r-- | src/components/FlatpaksModal.tsx | 40 |
6 files changed, 279 insertions, 485 deletions
diff --git a/package.json b/package.json index 7b5df97..365ad02 100644 --- a/package.json +++ b/package.json @@ -52,21 +52,6 @@ "name": "lsfg-vk-2.0.0.tar.xz", "url": "https://builds.lsfg-vk.dev/lsfg-vk-2.0.0.tar.xz", "sha256hash": "08bdbdf373a111022df87dac7aa87e3b564bb841f961552e3ca85fea12b5aa74" - }, - { - "name": "org.freedesktop.Platform.VulkanLayer.lsfg_vk_23.08.flatpak", - "url": "https://github.com/PancakeTAS/lsfg-vk/releases/download/v0.9.0/org.freedesktop.Platform.VulkanLayer.lsfg_vk_23.08.flatpak", - "sha256hash": "8381d1eff0b0786af5a0e66955521eadec783866f73b9b1aa4664c952ed601a4" - }, - { - "name": "org.freedesktop.Platform.VulkanLayer.lsfg_vk_24.08.flatpak", - "url": "https://github.com/PancakeTAS/lsfg-vk/releases/download/v0.9.0/org.freedesktop.Platform.VulkanLayer.lsfg_vk_24.08.flatpak", - "sha256hash": "70ea6d9d2a8adad63b8e5c2c3d94a636764ad4d0266ce9f37cb9dc7943d8fc3a" - }, - { - "name": "org.freedesktop.Platform.VulkanLayer.lsfg_vk_25.08.flatpak", - "url": "https://github.com/PancakeTAS/lsfg-vk/releases/download/v1.0.0/org.freedesktop.Platform.VulkanLayer.lsfg_vk_25.08.flatpak", - "sha256hash": "0651bda96751ef0f1314a5179585926a0cd354476790ca2616662c39fe6fae54" } ], "pnpm": { diff --git a/py_modules/lsfg_vk/constants.py b/py_modules/lsfg_vk/constants.py index f41b044..7bcd0dc 100644 --- a/py_modules/lsfg_vk/constants.py +++ b/py_modules/lsfg_vk/constants.py @@ -22,6 +22,6 @@ BIN_DIR = "bin" STEAM_COMMON_PATH = Path("steamapps/common/Lossless Scaling") LOSSLESS_DLL_NAME = "lsfg-vk.dll" -ENV_LSFG_DLL_PATH = "LSFG_DLL_PATH" +ENV_LSFG_DLL_PATH = "LSFGVK_DLL_PATH" ENV_XDG_DATA_HOME = "XDG_DATA_HOME" ENV_HOME = "HOME" diff --git a/py_modules/lsfg_vk/flatpak_service.py b/py_modules/lsfg_vk/flatpak_service.py index c9be0ec..7aa3cda 100644 --- a/py_modules/lsfg_vk/flatpak_service.py +++ b/py_modules/lsfg_vk/flatpak_service.py @@ -1,459 +1,321 @@ -""" -Flatpak service for managing lsfg-vk Flatpak runtime extensions. -""" - -import subprocess import os +import shutil +import subprocess from pathlib import Path -from typing import Dict, Any, List, Optional +from typing import Any, Dict, List from .base_service import BaseService -from .constants import ( - FLATPAK_23_08_FILENAME, FLATPAK_24_08_FILENAME, FLATPAK_25_08_FILENAME, BIN_DIR, CONFIG_DIR -) +from .config_schema import ConfigurationManager +from .dll_detection import DllDetectionService from .types import BaseResponse -class FlatpakExtensionStatus(BaseResponse): - """Response for Flatpak extension status""" - def __init__(self, success: bool = False, message: str = "", error: str = "", - installed_23_08: bool = False, installed_24_08: bool = False, installed_25_08: bool = False): - super().__init__(success, message, error) - self.installed_23_08 = installed_23_08 - self.installed_24_08 = installed_24_08 - self.installed_25_08 = installed_25_08 - - -class FlatpakAppInfo(BaseResponse): - """Response for Flatpak app information""" - def __init__(self, success: bool = False, message: str = "", error: str = "", - apps: List[Dict[str, Any]] = None, total_apps: int = 0): - super().__init__(success, message, error) - self.apps = apps or [] - self.total_apps = total_apps - - -class FlatpakOverrideResponse(BaseResponse): - """Response for Flatpak override operations""" - def __init__(self, success: bool = False, message: str = "", error: str = "", - app_id: str = "", operation: str = ""): - super().__init__(success, message, error) - self.app_id = app_id - self.operation = operation - - class FlatpakService(BaseService): - """Service for handling Flatpak runtime extensions and app overrides""" + EXTENSION_ID = "org.freedesktop.Platform.VulkanLayer.lsfgvk" + SUPPORTED_RUNTIMES = ("24.08", "25.08") def __init__(self, logger=None): super().__init__(logger) - self.extension_id_23_08 = "org.freedesktop.Platform.VulkanLayer.lsfgvk/x86_64/23.08" - self.extension_id_24_08 = "org.freedesktop.Platform.VulkanLayer.lsfgvk/x86_64/24.08" - self.extension_id_25_08 = "org.freedesktop.Platform.VulkanLayer.lsfgvk/x86_64/25.08" self.flatpak_command = None - def _get_clean_env(self): - """Get a clean environment without PyInstaller's bundled libraries""" + def _get_clean_env(self) -> Dict[str, str]: env = os.environ.copy() - - if 'LD_LIBRARY_PATH' in env: - del env['LD_LIBRARY_PATH'] - - standard_paths = ['/usr/bin', '/usr/local/bin', '/bin'] - current_path = env.get('PATH', '') - - path_parts = current_path.split(':') if current_path else [] - for std_path in standard_paths: - if std_path not in path_parts: - path_parts.insert(0, std_path) - - env['PATH'] = ':'.join(path_parts) - + env.pop("LD_LIBRARY_PATH", None) + path_entries = [entry for entry in env.get("PATH", "").split(":") if entry] + for entry in ("/usr/bin", "/usr/local/bin", "/bin"): + if entry not in path_entries: + path_entries.insert(0, entry) + env["PATH"] = ":".join(path_entries) return env - def _run_flatpak_command(self, args: List[str], **kwargs): - """Run flatpak command with clean environment to avoid library conflicts""" - if self.flatpak_command is None: - raise FileNotFoundError("Flatpak command not available") - - env = self._get_clean_env() - - self.log.info(f"Running flatpak with PATH: {env.get('PATH')}") - self.log.info(f"LD_LIBRARY_PATH removed: {'LD_LIBRARY_PATH' not in env}") - - return subprocess.run([self.flatpak_command] + args, env=env, **kwargs) - def check_flatpak_available(self) -> bool: - """Check if flatpak command is available and store the working command""" - self.log.info(f"PATH: {os.environ.get('PATH', 'Not set')}") - self.log.info(f"HOME: {os.environ.get('HOME', 'Not set')}") - self.log.info(f"USER: {os.environ.get('USER', 'Not set')}") - - flatpak_paths = [ - "flatpak", - "/usr/bin/flatpak", - "/var/lib/flatpak/exports/bin/flatpak", - "/home/deck/.local/bin/flatpak" - ] - - for flatpak_path in flatpak_paths: - try: - result = subprocess.run([flatpak_path, "--version"], - capture_output=True, check=True, text=True, - env=self._get_clean_env()) - self.log.info(f"Flatpak found at {flatpak_path}: {result.stdout.strip()}") - self.flatpak_command = flatpak_path - return True - except (subprocess.CalledProcessError, FileNotFoundError): - self.log.debug(f"Flatpak not found at {flatpak_path}") - continue - - self.log.error("Flatpak command not found in any known locations") - self.flatpak_command = None - return False + env = self._get_clean_env() + self.flatpak_command = shutil.which("flatpak", path=env["PATH"]) + return self.flatpak_command is not None - def get_extension_status(self) -> FlatpakExtensionStatus: - """Check if lsfg-vk Flatpak extensions are installed""" + def _run_flatpak_command(self, args: List[str], **kwargs): + if self.flatpak_command is None and not self.check_flatpak_available(): + raise FileNotFoundError("Flatpak command not available") + return subprocess.run( + [self.flatpak_command, *args], + env=self._get_clean_env(), + **kwargs, + ) + + @classmethod + def _extension_ref(cls, version: str) -> str: + return f"{cls.EXTENSION_ID}/x86_64/{version}" + + @classmethod + def _validate_runtime(cls, version: str) -> None: + if version not in cls.SUPPORTED_RUNTIMES: + raise ValueError("Unsupported Flatpak runtime") + + def get_extension_status(self) -> Dict[str, Any]: try: if not self.check_flatpak_available(): - error_msg = "Flatpak is not available on this system" - if self.flatpak_command is None: - error_msg += ". Command not found in PATH or common install locations." - self.log.error(error_msg) - return self._error_response(FlatpakExtensionStatus, - error_msg, - installed_23_08=False, installed_24_08=False, installed_25_08=False) + raise FileNotFoundError("Flatpak is not available on this system") result = self._run_flatpak_command( - ["list", "--runtime"], - capture_output=True, text=True, check=True + ["list", "--user", "--runtime", "--columns=application,arch,branch"], + capture_output=True, + text=True, + check=True, + ) + installed = { + tuple(line.split("\t")[:3]) + for line in result.stdout.splitlines() + if line.strip() + } + return self._success_response( + BaseResponse, + "Flatpak runtime status retrieved", + installed_24_08=(self.EXTENSION_ID, "x86_64", "24.08") in installed, + installed_25_08=(self.EXTENSION_ID, "x86_64", "25.08") in installed, + ) + except Exception as error: + return self._error_response( + BaseResponse, + str(error), + installed_24_08=False, + installed_25_08=False, ) - installed_runtimes = result.stdout - - base_extension_name = "org.freedesktop.Platform.VulkanLayer.lsfgvk" - installed_23_08 = False - installed_24_08 = False - installed_25_08 = False - - for line in installed_runtimes.split('\n'): - if base_extension_name in line: - if "23.08" in line: - installed_23_08 = True - elif "24.08" in line: - installed_24_08 = True - elif "25.08" in line: - installed_25_08 = True - - status_msg = [] - if installed_23_08: - status_msg.append("23.08 runtime extension installed") - if installed_24_08: - status_msg.append("24.08 runtime extension installed") - if installed_25_08: - status_msg.append("25.08 runtime extension installed") - - if not status_msg: - status_msg.append("No lsfg-vk runtime extensions installed") - - return self._success_response(FlatpakExtensionStatus, - "; ".join(status_msg), - installed_23_08=installed_23_08, - installed_24_08=installed_24_08, - installed_25_08=installed_25_08) - - except subprocess.CalledProcessError as e: - error_msg = f"Error checking Flatpak extensions: {e.stderr if e.stderr else str(e)}" - self.log.error(error_msg) - return self._error_response(FlatpakExtensionStatus, error_msg, - installed_23_08=False, installed_24_08=False, installed_25_08=False) - - def install_extension(self, version: str) -> BaseResponse: - """Install a specific version of the lsfg-vk Flatpak extension""" + def install_extension(self, version: str) -> Dict[str, Any]: try: - if version not in ["23.08", "24.08", "25.08"]: - return self._error_response(BaseResponse, "Invalid version. Must be '23.08', '24.08', or '25.08'") - + self._validate_runtime(version) if not self.check_flatpak_available(): - return self._error_response(BaseResponse, "Flatpak is not available on this system") - - plugin_dir = Path(__file__).parent.parent.parent - if version == "23.08": - filename = FLATPAK_23_08_FILENAME - elif version == "24.08": - filename = FLATPAK_24_08_FILENAME - else: - filename = FLATPAK_25_08_FILENAME - flatpak_path = plugin_dir / BIN_DIR / filename - - if not flatpak_path.exists(): - return self._error_response(BaseResponse, f"Flatpak file not found: {flatpak_path}") - + raise FileNotFoundError("Flatpak is not available on this system") result = self._run_flatpak_command( - ["install", "--user", "--noninteractive", str(flatpak_path)], - capture_output=True, text=True + [ + "install", + "--user", + "--noninteractive", + "--or-update", + "flathub", + f"{self.EXTENSION_ID}//{version}", + ], + capture_output=True, + text=True, ) - if result.returncode != 0: - error_msg = f"Failed to install Flatpak extension: {result.stderr}" - 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") - - except Exception as e: - error_msg = f"Error installing Flatpak extension {version}: {str(e)}" - self.log.error(error_msg) - return self._error_response(BaseResponse, error_msg) + raise OSError(result.stderr.strip() or "Flatpak installation failed") + return self._success_response( + BaseResponse, + f"lsfg-vk {version} runtime extension installed", + ) + except Exception as error: + return self._error_response(BaseResponse, str(error)) - def uninstall_extension(self, version: str) -> BaseResponse: - """Uninstall a specific version of the lsfg-vk Flatpak extension""" + def uninstall_extension(self, version: str) -> Dict[str, Any]: try: - if version not in ["23.08", "24.08", "25.08"]: - return self._error_response(BaseResponse, "Invalid version. Must be '23.08', '24.08', or '25.08'") - + self._validate_runtime(version) if not self.check_flatpak_available(): - return self._error_response(BaseResponse, "Flatpak is not available on this system") - - if version == "23.08": - extension_id = self.extension_id_23_08 - elif version == "24.08": - extension_id = self.extension_id_24_08 - else: - extension_id = self.extension_id_25_08 - + raise FileNotFoundError("Flatpak is not available on this system") result = self._run_flatpak_command( - ["uninstall", "--user", "--noninteractive", extension_id], - capture_output=True, text=True + ["uninstall", "--user", "--noninteractive", self._extension_ref(version)], + capture_output=True, + text=True, ) - if result.returncode != 0: - error_msg = f"Failed to uninstall Flatpak extension: {result.stderr}" - self.log.error(error_msg) - return self._error_response(BaseResponse, error_msg) - - self.log.info(f"Successfully uninstalled lsfg-vk Flatpak extension {version}") - return self._success_response(BaseResponse, f"lsfg-vk {version} runtime extension uninstalled successfully") + raise OSError(result.stderr.strip() or "Flatpak uninstall failed") + return self._success_response( + BaseResponse, + f"lsfg-vk {version} runtime extension uninstalled", + ) + except Exception as error: + return self._error_response(BaseResponse, str(error)) - except Exception as e: - error_msg = f"Error uninstalling Flatpak extension {version}: {str(e)}" - self.log.error(error_msg) - return self._error_response(BaseResponse, error_msg) + def _dll_directory(self) -> Path: + if self.config_file_path.exists(): + try: + profile_data = ConfigurationManager.parse_toml_content_multi_profile( + self.config_file_path.read_text(encoding="utf-8") + ) + dll_path = profile_data["global_config"].get("dll") + if dll_path: + return Path(dll_path).parent + except Exception: + pass + + result = DllDetectionService(self.log).check_lossless_scaling_dll() + if result.get("detected") and result.get("path"): + return Path(result["path"]).parent + return self.user_home / ".local/share/Steam/steamapps/common" + + def _override_output(self, app_id: str) -> str: + result = self._run_flatpak_command( + ["override", "--user", "--show", app_id], + capture_output=True, + text=True, + ) + return result.stdout if result.returncode == 0 else "" + + def _override_paths(self) -> Dict[str, str]: + return { + "config_dir": str(self.config_dir), + "config_file": str(self.config_file_path), + "dll_dir": str(self._dll_directory()), + "legacy_dll": str( + self.user_home + / ".local/share/Steam/steamapps/common/Lossless Scaling/Lossless.dll" + ), + "legacy_script": str(self.lsfg_launch_script_path), + } - def get_flatpak_apps(self) -> FlatpakAppInfo: - """Get list of installed Flatpak apps and their lsfg-vk override status""" + def _check_app_override_status(self, app_id: str) -> Dict[str, bool]: + output = self._override_output(app_id) + paths = self._override_paths() + return { + "filesystem": ( + paths["config_dir"] in output + and paths["dll_dir"] in output + ), + "env": f"LSFGVK_CONFIG={paths['config_file']}" in output, + } + + def get_flatpak_apps(self) -> Dict[str, Any]: try: if not self.check_flatpak_available(): - error_msg = "Flatpak is not available on this system" - if self.flatpak_command is None: - error_msg += ". Command not found in PATH or common install locations." - return self._error_response(FlatpakAppInfo, - error_msg, - apps=[], total_apps=0) - + raise FileNotFoundError("Flatpak is not available on this system") result = self._run_flatpak_command( - ["list", "--app"], - capture_output=True, text=True, check=True + ["list", "--user", "--app", "--columns=name,application"], + capture_output=True, + text=True, + check=True, ) - apps = [] - for line in result.stdout.strip().split('\n'): - if not line.strip(): + for line in result.stdout.splitlines(): + parts = line.split("\t", 1) + if len(parts) != 2: continue + status = self._check_app_override_status(parts[1]) + apps.append( + { + "app_id": parts[1], + "app_name": parts[0], + "has_filesystem_override": status["filesystem"], + "has_env_override": status["env"], + } + ) + return self._success_response( + BaseResponse, + f"Found {len(apps)} Flatpak applications", + apps=apps, + total_apps=len(apps), + ) + except Exception as error: + return self._error_response( + BaseResponse, + str(error), + apps=[], + total_apps=0, + ) - parts = line.split('\t') - if len(parts) >= 2: - app_name = parts[0].strip() - app_id = parts[1].strip() - - # Check override status - override_status = self._check_app_override_status(app_id) - - apps.append({ - "app_id": app_id, - "app_name": app_name, - "has_filesystem_override": override_status["filesystem"], - "has_env_override": override_status["env"] - }) - - return self._success_response(FlatpakAppInfo, - f"Found {len(apps)} Flatpak applications", - apps=apps, total_apps=len(apps)) - - except subprocess.CalledProcessError as e: - error_msg = f"Error getting Flatpak apps: {e.stderr if e.stderr else str(e)}" - self.log.error(error_msg) - return self._error_response(FlatpakAppInfo, error_msg, apps=[], total_apps=0) - - def _check_app_override_status(self, app_id: str) -> Dict[str, bool]: - """Check if an app has lsfg-vk overrides set""" + def set_app_override(self, app_id: str) -> Dict[str, Any]: try: + if not self.check_flatpak_available(): + raise FileNotFoundError("Flatpak is not available on this system") + paths = self._override_paths() result = self._run_flatpak_command( - ["override", "--user", "--show", app_id], - capture_output=True, text=True + [ + "override", + "--user", + f"--filesystem={paths['config_dir']}:rw", + f"--filesystem={paths['dll_dir']}:ro", + f"--env=LSFGVK_CONFIG={paths['config_file']}", + f"--nofilesystem={paths['legacy_dll']}", + f"--nofilesystem={paths['legacy_script']}", + "--unset-env=LSFG_CONFIG", + app_id, + ], + capture_output=True, + text=True, ) - if result.returncode != 0: - return {"filesystem": False, "env": False} - - output = result.stdout - home_path = os.path.expanduser("~") - config_path = f"{home_path}/.config/lsfg-vk" - dll_path = f"{home_path}/.local/share/Steam/steamapps/common/Lossless Scaling/Lossless.dll" - lsfg_path = f"{home_path}/lsfg" - - filesystem_section = "" - in_context = False - - for line in output.split('\n'): - line = line.strip() - if line == "[Context]": - in_context = True - elif line.startswith("[") and line != "[Context]": - in_context = False - elif in_context and line.startswith("filesystems="): - filesystem_section = line - break - - has_config_fs = config_path in filesystem_section - has_dll_fs = dll_path in filesystem_section - has_lsfg_fs = lsfg_path in filesystem_section - - filesystem_override = has_config_fs and has_dll_fs and has_lsfg_fs - - env_override = False - in_environment = False - - for line in output.split('\n'): - line = line.strip() - if line == "[Environment]": - in_environment = True - elif line.startswith("[") and line != "[Environment]": - in_environment = False - elif in_environment and line.startswith(f"LSFG_CONFIG={config_path}/conf.toml"): - env_override = True - break - - self.log.debug(f"Override status for {app_id}: filesystem={filesystem_override} ({has_config_fs}/{has_dll_fs}/{has_lsfg_fs}), env={env_override}") - - return {"filesystem": filesystem_override, "env": env_override} - - except Exception as e: - self.log.error(f"Error checking override status for {app_id}: {e}") - return {"filesystem": False, "env": False} + raise OSError(result.stderr.strip() or "Failed to set Flatpak overrides") + return self._success_response( + BaseResponse, + f"lsfg-vk overrides set for {app_id}", + app_id=app_id, + operation="set", + ) + except Exception as error: + return self._error_response( + BaseResponse, + str(error), + app_id=app_id, + operation="set", + ) - def set_app_override(self, app_id: str) -> FlatpakOverrideResponse: - """Set lsfg-vk overrides for a Flatpak app""" + def remove_app_override(self, app_id: str) -> Dict[str, Any]: try: if not self.check_flatpak_available(): - return self._error_response(FlatpakOverrideResponse, - "Flatpak is not available on this system", - app_id=app_id, operation="set") - - home_path = os.path.expanduser("~") - config_path = f"{home_path}/.config/lsfg-vk" - dll_path = f"{home_path}/.local/share/Steam/steamapps/common/Lossless Scaling/Lossless.dll" - lsfg_path = f"{home_path}/lsfg" - - filesystem_overrides = [ - f"--filesystem={dll_path}", - f"--filesystem={config_path}:rw", - f"--filesystem={lsfg_path}:rw" - ] - - for override in filesystem_overrides: - result = self._run_flatpak_command( - ["override", "--user", override, app_id], - capture_output=True, text=True - ) - if result.returncode != 0: - error_msg = f"Failed to set filesystem override {override}: {result.stderr}" - return self._error_response(FlatpakOverrideResponse, error_msg, - app_id=app_id, operation="set") - + raise FileNotFoundError("Flatpak is not available on this system") + paths = self._override_paths() result = self._run_flatpak_command( - ["override", "--user", f"--env=LSFG_CONFIG={config_path}/conf.toml", app_id], - capture_output=True, text=True + [ + "override", + "--user", + f"--nofilesystem={paths['config_dir']}", + f"--nofilesystem={paths['dll_dir']}", + f"--nofilesystem={paths['legacy_dll']}", + f"--nofilesystem={paths['legacy_script']}", + "--unset-env=LSFGVK_CONFIG", + "--unset-env=LSFG_CONFIG", + app_id, + ], + capture_output=True, + text=True, ) - if result.returncode != 0: - error_msg = f"Failed to set environment override: {result.stderr}" - return self._error_response(FlatpakOverrideResponse, error_msg, - app_id=app_id, operation="set") - - self.log.info(f"Successfully set lsfg-vk overrides for {app_id}") - return self._success_response(FlatpakOverrideResponse, - f"lsfg-vk overrides set for {app_id}", - app_id=app_id, operation="set") - - except Exception as e: - error_msg = f"Error setting overrides for {app_id}: {str(e)}" - self.log.error(error_msg) - return self._error_response(FlatpakOverrideResponse, error_msg, - app_id=app_id, operation="set") - - def remove_app_override(self, app_id: str) -> FlatpakOverrideResponse: - """Remove lsfg-vk overrides for a Flatpak app""" - try: - if not self.check_flatpak_available(): - return self._error_response(FlatpakOverrideResponse, - "Flatpak is not available on this system", - app_id=app_id, operation="remove") - - home_path = os.path.expanduser("~") - config_path = f"{home_path}/.config/lsfg-vk" - dll_path = f"{home_path}/.local/share/Steam/steamapps/common/Lossless Scaling/Lossless.dll" - lsfg_path = f"{home_path}/lsfg" - - reset_result = self._run_flatpak_command( - ["override", "--user", "--reset", app_id], - capture_output=True, text=True + raise OSError(result.stderr.strip() or "Failed to remove Flatpak overrides") + return self._success_response( + BaseResponse, + f"lsfg-vk overrides removed for {app_id}", + app_id=app_id, + operation="remove", + ) + except Exception as error: + return self._error_response( + BaseResponse, + str(error), + app_id=app_id, + operation="remove", ) - - if reset_result.returncode == 0: - self.log.info(f"Successfully reset all overrides for {app_id}") - return self._success_response(FlatpakOverrideResponse, - f"All overrides reset for {app_id}", - app_id=app_id, operation="remove") - - self.log.debug(f"Reset failed, trying individual removal: {reset_result.stderr}") - - filesystem_overrides = [ - f"--nofilesystem={dll_path}", - f"--nofilesystem={config_path}", - f"--nofilesystem={lsfg_path}" - ] - - removal_errors = [] - - # Remove filesystem overrides - for override in filesystem_overrides: - result = self._run_flatpak_command( - ["override", "--user", override, app_id], - capture_output=True, text=True - ) - if result.returncode != 0: - removal_errors.append(f"{override}: {result.stderr}") + def migrate_v2(self) -> None: + if not self.check_flatpak_available(): + return + + status = self.get_extension_status() + for version, key in ( + ("24.08", "installed_24_08"), + ("25.08", "installed_25_08"), + ): + if not status.get(key): + continue result = self._run_flatpak_command( - ["override", "--user", "--unset-env=LSFG_CONFIG", app_id], - capture_output=True, text=True + ["update", "--user", "--noninteractive", self._extension_ref(version)], + capture_output=True, + text=True, ) - if result.returncode != 0: - removal_errors.append(f"unset-env: {result.stderr}") - - if removal_errors: - self.log.warning(f"Some override removals had issues for {app_id}: {'; '.join(removal_errors)}") - - self.log.info(f"Completed override removal for {app_id}") - return self._success_response(FlatpakOverrideResponse, - f"lsfg-vk overrides removed for {app_id}", - app_id=app_id, operation="remove") - - except Exception as e: - 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 + self.log.warning(result.stderr.strip()) + + apps_result = self._run_flatpak_command( + ["list", "--user", "--app", "--columns=application"], + capture_output=True, + text=True, + ) + if apps_result.returncode != 0: + return + + for app_id in apps_result.stdout.splitlines(): + app_id = app_id.strip() + if not app_id: + continue + if "LSFG_CONFIG=" in self._override_output(app_id): + result = self.set_app_override(app_id) + if not result.get("success"): + self.log.warning(result.get("error")) diff --git a/py_modules/lsfg_vk/plugin.py b/py_modules/lsfg_vk/plugin.py index cb59b4f..bfb5102 100644 --- a/py_modules/lsfg_vk/plugin.py +++ b/py_modules/lsfg_vk/plugin.py @@ -440,36 +440,19 @@ class Plugin: # Clean up lsfg-vk files when the plugin is uninstalled self.installation_service.cleanup_on_uninstall() - # Also clean up flatpak extensions if they are installed try: - decky.logger.info("Checking for flatpak extensions to uninstall") - extension_status = self.flatpak_service.get_extension_status() - - if extension_status.get("success"): - if extension_status.get("installed_23_08"): - decky.logger.info("Uninstalling lsfg-vk flatpak runtime 23.08") - result = self.flatpak_service.uninstall_extension("23.08") - if result.get("success"): - decky.logger.info("Successfully uninstalled flatpak runtime 23.08") - else: - decky.logger.warning(f"Failed to uninstall flatpak runtime 23.08: {result.get('error')}") - - if extension_status.get("installed_24_08"): - decky.logger.info("Uninstalling lsfg-vk flatpak runtime 24.08") - result = self.flatpak_service.uninstall_extension("24.08") - if result.get("success"): - decky.logger.info("Successfully uninstalled flatpak runtime 24.08") - else: - decky.logger.warning(f"Failed to uninstall flatpak runtime 24.08: {result.get('error')}") - - decky.logger.info("Flatpak extension cleanup completed") - else: - decky.logger.info(f"Could not check flatpak status for cleanup: {extension_status.get('error')}") - - except Exception as e: - decky.logger.error(f"Error during flatpak cleanup: {e}") - + for version, key in ( + ("24.08", "installed_24_08"), + ("25.08", "installed_25_08"), + ): + if extension_status.get(key): + result = self.flatpak_service.uninstall_extension(version) + if not result.get("success"): + decky.logger.warning(result.get("error")) + except Exception as error: + decky.logger.error(f"Error during Flatpak cleanup: {error}") + decky.logger.info("decky-lsfg-vk plugin uninstall cleanup completed") async def _migration(self): @@ -492,4 +475,9 @@ class Plugin: os.path.join(decky.DECKY_HOME, "lossless-scaling-vk"), os.path.join(decky.DECKY_USER_HOME, ".local", "share", "decky-lossless-scaling-vk")) + try: + self.flatpak_service.migrate_v2() + except Exception as error: + decky.logger.warning(f"Flatpak v2 migration skipped: {error}") + decky.logger.info("decky-lsfg-vk plugin migrations completed") diff --git a/src/api/lsfgApi.ts b/src/api/lsfgApi.ts index 82f37c8..2c9f4a9 100644 --- a/src/api/lsfgApi.ts +++ b/src/api/lsfgApi.ts @@ -84,7 +84,6 @@ export interface FlatpakExtensionStatus { success: boolean; message: string; error?: string; - installed_23_08: boolean; installed_24_08: boolean; installed_25_08: boolean; } diff --git a/src/components/FlatpaksModal.tsx b/src/components/FlatpaksModal.tsx index 16d0369..479b919 100644 --- a/src/components/FlatpaksModal.tsx +++ b/src/components/FlatpaksModal.tsx @@ -172,46 +172,6 @@ export const FlatpaksModal: FC<FlatpaksModalProps> = ({ closeModal }) => { {extensionStatus && extensionStatus.success ? ( <> - {/* 23.08 Runtime */} - <PanelSectionRow> - <Field - label={t('FLATPAK_RUNTIME_23', 'Runtime 23.08')} - description={extensionStatus.installed_23_08 ? t('FLATPAK_INSTALLED', 'Installed') : t('FLATPAK_NOT_INSTALLED', 'Not installed')} - icon={extensionStatus.installed_23_08 ? <FaCheck style={{color: 'green'}} /> : <FaTimes style={{color: 'red'}} />} - > - <ButtonItem - layout="below" - onClick={() => { - const operation = extensionStatus.installed_23_08 ? 'uninstall' : 'install'; - const action = () => handleExtensionOperation(operation, '23.08'); - - if (operation === 'uninstall') { - confirmOperation( - action, - t('FLATPAK_UNINSTALL_TITLE', 'Uninstall Runtime Extension'), - `${t('FLATPAK_UNINSTALL_CONFIRM_PREFIX', 'Are you sure you want to uninstall the')} 23.08 ${t('FLATPAK_UNINSTALL_CONFIRM_SUFFIX', 'runtime extension?')}` - ); - } else { - action(); - } - }} - disabled={operationInProgress === 'install-23.08' || operationInProgress === 'uninstall-23.08'} - > - {operationInProgress === 'install-23.08' || operationInProgress === 'uninstall-23.08' ? ( - <Spinner /> - ) : extensionStatus.installed_23_08 ? ( - <> - <FaTrash /> {t('FLATPAK_UNINSTALL_BTN', 'Uninstall')} - </> - ) : ( - <> - <FaDownload /> {t('FLATPAK_INSTALL_BTN', 'Install')} - </> - )} - </ButtonItem> - </Field> - </PanelSectionRow> - {/* 24.08 Runtime */} <PanelSectionRow> <Field |
