From f32c8760d15bf4713b3f9af1384219a44322febd Mon Sep 17 00:00:00 2001 From: xXJsonDeruloXx Date: Tue, 21 Oct 2025 21:45:14 -0400 Subject: rm old comments --- main.py | 4 ---- shared_config.py | 5 ++--- src/components/Content.tsx | 14 -------------- src/components/SmartClipboardButton.tsx | 7 +------ src/config/configSchema.ts | 4 ---- src/hooks/useLsfgHooks.ts | 3 +-- src/index.tsx | 6 ------ src/utils/clipboardUtils.ts | 6 ------ 8 files changed, 4 insertions(+), 45 deletions(-) diff --git a/main.py b/main.py index 18b93f9..b4ae724 100644 --- a/main.py +++ b/main.py @@ -2,12 +2,8 @@ Main entry point for the lsfg-vk Decky Loader plugin. This file imports and exposes the Plugin class from the lsfg_vk package. -The actual implementation has been refactored into separate service modules -for better maintainability and testability. """ -# Import the refactored Plugin class from lsfg_vk import Plugin -# Re-export Plugin at module level for Decky Loader compatibility __all__ = ['Plugin'] diff --git a/shared_config.py b/shared_config.py index 5b0a45d..997717b 100644 --- a/shared_config.py +++ b/shared_config.py @@ -18,14 +18,13 @@ class ConfigFieldType(str, Enum): STRING = "string" -# Canonical configuration schema - source of truth CONFIG_SCHEMA_DEF = { "dll": { "name": "dll", "fieldType": ConfigFieldType.STRING, "default": "/games/Lossless Scaling/Lossless.dll", "description": "specify where Lossless.dll is stored", - "location": "toml" # where this field is stored/used + "location": "toml" }, "no_fp16": { @@ -81,7 +80,7 @@ CONFIG_SCHEMA_DEF = { "fieldType": ConfigFieldType.INTEGER, "default": 0, "description": "base framerate cap for DirectX games before frame multiplier", - "location": "script" # script-only field + "location": "script" }, "enable_wow64": { diff --git a/src/components/Content.tsx b/src/components/Content.tsx index 28eefa7..3dc2696 100644 --- a/src/components/Content.tsx +++ b/src/components/Content.tsx @@ -39,25 +39,20 @@ export function Content() { const { isInstalling, isUninstalling, handleInstall, handleUninstall } = useInstallationActions(); - // Reload config when installation status changes useEffect(() => { if (isInstalled) { loadLsfgConfig(); } }, [isInstalled, loadLsfgConfig]); - // Generic configuration change handler const handleConfigChange = async (fieldName: keyof ConfigurationData, value: boolean | number | string) => { - // If we have a current profile, update that profile specifically if (currentProfile) { const newConfig = { ...config, [fieldName]: value }; const result = await updateProfileConfig(currentProfile, newConfig); if (result.success) { - // Reload config to reflect the changes from the backend await loadLsfgConfig(); } } else { - // Fallback to the original method for backward compatibility await updateField(fieldName, value); } }; @@ -80,7 +75,6 @@ export function Content() { return ( - {/* Show installation components at top when not fully installed */} {!isInstalled && ( <> )} - {/* FPS multiplier controls stay above profile selection when installed */} {isInstalled && ( <> @@ -126,7 +119,6 @@ export function Content() { )} - {/* Profile Management - only show if installed */} {isInstalled && ( )} - {/* Configuration Section - only show if installed */} {isInstalled && ( )} - {/* Clipboard buttons sit beside usage info for quick access */} {isInstalled && ( <> @@ -153,10 +143,8 @@ export function Content() { )} - {/* Usage instructions - always visible for user guidance */} - {/* Nerd Stuff Button */} - {/* Flatpaks Button */} - {/* Status and uninstall sit at bottom when installed to match desired layout */} {isInstalled && ( <> { if (showSuccess) { const timer = setTimeout(() => { @@ -38,10 +37,8 @@ export function SmartClipboardButton() { const { success, verified } = await copyWithVerification(text); if (success) { - // Show success feedback in the button instead of toast setShowSuccess(true); if (!verified) { - // Copy worked but verification failed - still show success console.log('Copy verification failed but copy likely worked'); } } else { @@ -64,9 +61,7 @@ export function SmartClipboardButton() { >
{showSuccess ? ( - + ) : isLoading ? ( ("get_configuration"); private resetConfiguration = callable<[], { success: boolean; data?: ConfigurationData; error?: string }>("reset_configuration"); @@ -131,5 +128,4 @@ export class ConfigurationManager { } } -// Export singleton instance export const configManager = ConfigurationManager.getInstance(); diff --git a/src/hooks/useLsfgHooks.ts b/src/hooks/useLsfgHooks.ts index e5dea63..adc18ba 100644 --- a/src/hooks/useLsfgHooks.ts +++ b/src/hooks/useLsfgHooks.ts @@ -71,7 +71,6 @@ export function useDllDetection() { } export function useLsfgConfig() { - // Use centralized configuration for initial state const [config, setConfig] = useState(() => ConfigurationManager.getDefaults()); const loadLsfgConfig = useCallback(async () => { @@ -114,7 +113,7 @@ export function useLsfgConfig() { useEffect(() => { loadLsfgConfig(); - }, []); // Empty dependency array to prevent infinite loop + }, []); return { config, diff --git a/src/index.tsx b/src/index.tsx index bbe4cd3..36945ba 100755 --- a/src/index.tsx +++ b/src/index.tsx @@ -7,17 +7,11 @@ export default definePlugin(() => { console.log("decky-lsfg-vk plugin initializing"); return { - // The name shown in various decky menus name: "Decky LSFG-VK", - // The element displayed at the top of your plugin's menu titleView:
Decky LSFG-VK
, - // Always render to retain state when panel is toggled alwaysRender: true, - // The content of your plugin's menu content: , - // The icon displayed in the plugin list icon: , - // The function triggered when your plugin unloads onDismount() { console.log("decky-lsfg-vk unloading"); } diff --git a/src/utils/clipboardUtils.ts b/src/utils/clipboardUtils.ts index 2d480fc..8a04caa 100644 --- a/src/utils/clipboardUtils.ts +++ b/src/utils/clipboardUtils.ts @@ -7,7 +7,6 @@ * This is especially important in gaming mode where clipboard APIs may behave differently */ export async function copyToClipboard(text: string): Promise { - // Use the proven input simulation method const tempInput = document.createElement('input'); tempInput.value = text; tempInput.style.position = 'absolute'; @@ -15,18 +14,15 @@ export async function copyToClipboard(text: string): Promise { document.body.appendChild(tempInput); try { - // Focus and select the text tempInput.focus(); tempInput.select(); - // Try copying using execCommand first (most reliable in gaming mode) let copySuccess = false; try { if (document.execCommand('copy')) { copySuccess = true; } } catch (e) { - // If execCommand fails, try navigator.clipboard as fallback try { await navigator.clipboard.writeText(text); copySuccess = true; @@ -37,7 +33,6 @@ export async function copyToClipboard(text: string): Promise { return copySuccess; } finally { - // Clean up document.body.removeChild(tempInput); } } @@ -50,7 +45,6 @@ export async function verifyCopy(expectedText: string): Promise { const readBack = await navigator.clipboard.readText(); return readBack === expectedText; } catch (e) { - // Verification not available, assume success return true; } } -- cgit v1.2.3 From 450e70a16310b18ae62ec4cb74a11b23197bb529 Mon Sep 17 00:00:00 2001 From: xXJsonDeruloXx Date: Tue, 21 Oct 2025 22:04:39 -0400 Subject: rm more comments, ill recomb for myself later --- py_modules/lsfg_vk/__init__.py | 3 +- py_modules/lsfg_vk/base_service.py | 10 ++-- py_modules/lsfg_vk/config_schema_generated.py | 4 -- py_modules/lsfg_vk/configuration.py | 45 +----------------- py_modules/lsfg_vk/constants.py | 8 +--- py_modules/lsfg_vk/dll_detection.py | 15 ------ py_modules/lsfg_vk/flatpak_service.py | 34 ++------------ py_modules/lsfg_vk/installation.py | 8 ---- py_modules/lsfg_vk/plugin.py | 67 ++------------------------- 9 files changed, 13 insertions(+), 181 deletions(-) diff --git a/py_modules/lsfg_vk/__init__.py b/py_modules/lsfg_vk/__init__.py index 8343853..31c553b 100644 --- a/py_modules/lsfg_vk/__init__.py +++ b/py_modules/lsfg_vk/__init__.py @@ -5,10 +5,9 @@ This package provides services for installing and managing the lsfg-vk Vulkan layer for Lossless Scaling frame generation. """ -# Import will be available once plugin.py exists try: from .plugin import Plugin __all__ = ['Plugin'] except ImportError: - # During development, plugin may not exist yet __all__ = [] + diff --git a/py_modules/lsfg_vk/base_service.py b/py_modules/lsfg_vk/base_service.py index 9c3dec3..262e2b0 100644 --- a/py_modules/lsfg_vk/base_service.py +++ b/py_modules/lsfg_vk/base_service.py @@ -12,7 +12,6 @@ import decky from .constants import LOCAL_LIB, LOCAL_SHARE_BASE, VULKAN_LAYER_DIR, SCRIPT_NAME, CONFIG_DIR, CONFIG_FILENAME -# Generic type for response dictionaries ResponseType = TypeVar('ResponseType', bound=Dict[str, Any]) @@ -30,12 +29,11 @@ class BaseService: else: self.log = logger - # Initialize common paths using pathlib self.user_home = Path.home() self.local_lib_dir = self.user_home / LOCAL_LIB self.local_share_dir = self.user_home / VULKAN_LAYER_DIR self.lsfg_script_path = self.user_home / SCRIPT_NAME - self.lsfg_launch_script_path = self.user_home / SCRIPT_NAME # ~/lsfg launch script + self.lsfg_launch_script_path = self.user_home / SCRIPT_NAME self.config_dir = self.user_home / CONFIG_DIR self.config_file_path = self.config_dir / CONFIG_FILENAME @@ -82,13 +80,11 @@ class BaseService: OSError: If write fails """ try: - # Write directly to the file with open(path, 'w', encoding='utf-8') as f: f.write(content) - f.flush() # Ensure data is written to disk - os.fsync(f.fileno()) # Force filesystem sync + f.flush() + os.fsync(f.fileno()) - # Set permissions path.chmod(mode) self.log.info(f"Wrote to {path}") diff --git a/py_modules/lsfg_vk/config_schema_generated.py b/py_modules/lsfg_vk/config_schema_generated.py index 53e9693..3aa5f68 100644 --- a/py_modules/lsfg_vk/config_schema_generated.py +++ b/py_modules/lsfg_vk/config_schema_generated.py @@ -8,11 +8,9 @@ from enum import Enum import sys from pathlib import Path -# Import shared configuration constants sys.path.insert(0, str(Path(__file__).parent.parent.parent)) from shared_config import CONFIG_SCHEMA_DEF, ConfigFieldType -# Field name constants for type-safe access DLL = "dll" NO_FP16 = "no_fp16" MULTIPLIER = "multiplier" @@ -63,7 +61,6 @@ def get_script_parsing_logic(): key = key.strip() value = value.strip() - # Auto-generated parsing logic: if key == "DXVK_FRAME_RATE": try: script_values["dxvk_frame_rate"] = int(value) @@ -162,7 +159,6 @@ def create_config_dict(**kwargs) -> ConfigurationData: }) -# Field lists for dynamic operations TOML_FIELDS = ['dll', 'no_fp16', 'multiplier', 'flow_scale', 'performance_mode', 'hdr_mode', 'experimental_present_mode'] SCRIPT_FIELDS = ['dxvk_frame_rate', 'enable_wow64', 'disable_steamdeck_mode', 'mangohud_workaround', 'disable_vkbasalt', 'force_enable_vkbasalt', 'enable_wsi', 'enable_zink'] ALL_FIELDS = ['dll', 'no_fp16', 'multiplier', 'flow_scale', 'performance_mode', 'hdr_mode', 'experimental_present_mode', 'dxvk_frame_rate', 'enable_wow64', 'disable_steamdeck_mode', 'mangohud_workaround', 'disable_vkbasalt', 'force_enable_vkbasalt', 'enable_wsi', 'enable_zink'] diff --git a/py_modules/lsfg_vk/configuration.py b/py_modules/lsfg_vk/configuration.py index b61a06d..13fa925 100644 --- a/py_modules/lsfg_vk/configuration.py +++ b/py_modules/lsfg_vk/configuration.py @@ -22,9 +22,7 @@ class ConfigurationService(BaseService): ConfigurationResponse with current configuration or error """ try: - # Get TOML configuration (with defaults if file doesn't exist) if not self.config_file_path.exists(): - # Return default configuration with DLL detection if file doesn't exist from .dll_detection import DllDetectionService dll_service = DllDetectionService(self.log) toml_config = ConfigurationManager.get_defaults_with_dll_detection(dll_service) @@ -32,7 +30,6 @@ class ConfigurationService(BaseService): content = self.config_file_path.read_text(encoding='utf-8') toml_config = ConfigurationManager.parse_toml_content(content) - # Get script environment variables (if script exists) script_values = {} if self.lsfg_script_path.exists(): try: @@ -42,7 +39,6 @@ class ConfigurationService(BaseService): except Exception as e: self.log.warning(f"Failed to parse launch script: {str(e)}") - # Merge TOML config with script values config = ConfigurationManager.merge_config_with_script(toml_config, script_values) return self._success_response(ConfigurationResponse, config=config) @@ -54,7 +50,6 @@ class ConfigurationService(BaseService): except Exception as e: error_msg = f"Error parsing config file: {str(e)}" self.log.error(error_msg) - # Return defaults with DLL detection if parsing fails from .dll_detection import DllDetectionService dll_service = DllDetectionService(self.log) config = ConfigurationManager.get_defaults_with_dll_detection(dll_service) @@ -75,7 +70,6 @@ class ConfigurationService(BaseService): profile_data = self._get_profile_data() current_profile = profile_data["current_profile"] - # Update the current profile's config return self.update_profile_config(current_profile, config) except (OSError, IOError) as e: @@ -97,10 +91,8 @@ class ConfigurationService(BaseService): ConfigurationResponse with success status """ try: - # Create configuration from keyword arguments using generated function config = ConfigurationManager.create_config_from_args(**kwargs) - # Update using the new profile-aware method return self.update_config_from_dict(config) except (OSError, IOError) as e: @@ -124,18 +116,14 @@ class ConfigurationService(BaseService): try: profile_data = self._get_profile_data() - # Update global config (DLL path is global) profile_data["global_config"]["dll"] = dll_path - # Also update current profile's config for backward compatibility current_profile = profile_data["current_profile"] from .config_schema_generated import DLL profile_data["profiles"][current_profile][DLL] = dll_path - # Save to file self._save_profile_data(profile_data) - # Update launch script script_result = self.update_lsfg_script_from_profile_data(profile_data) if not script_result["success"]: self.log.warning(f"Failed to update launch script: {script_result['error']}") @@ -163,7 +151,6 @@ class ConfigurationService(BaseService): try: script_content = self._generate_script_content(config) - # Write the script file self._write_file(self.lsfg_script_path, script_content, 0o755) self.log.info(f"Updated lsfg launch script at {self.lsfg_script_path}") @@ -188,15 +175,11 @@ class ConfigurationService(BaseService): """ lines = [ "#!/bin/bash", - "# lsfg-vk launch script generated by decky-lossless-scaling-vk plugin", - "# This script sets up the environment for lsfg-vk to work with the plugin configuration" ] - # Use auto-generated script generation logic generate_script_lines = get_script_generation_logic() lines.extend(generate_script_lines(config)) - # Always add the LSFG_PROCESS export and execution line lines.extend([ "export LSFG_PROCESS=decky-lsfg-vk", 'exec "$@"' @@ -216,23 +199,18 @@ class ConfigurationService(BaseService): current_profile = profile_data["current_profile"] config = profile_data["profiles"].get(current_profile, ConfigurationManager.get_defaults()) - # Merge global config with profile config merged_config = dict(config) for field_name, value in profile_data["global_config"].items(): merged_config[field_name] = value lines = [ "#!/bin/bash", - "# lsfg-vk launch script generated by decky-lossless-scaling-vk plugin", f"# Current profile: {current_profile}", - "# This script sets up the environment for lsfg-vk to work with the plugin configuration" ] - # Use auto-generated script generation logic generate_script_lines = get_script_generation_logic() lines.extend(generate_script_lines(merged_config)) - # Export LSFG_PROCESS with current profile name lines.extend([ f"export LSFG_PROCESS={current_profile}", 'exec "$@"' @@ -243,7 +221,6 @@ class ConfigurationService(BaseService): def _get_profile_data(self) -> ProfileData: """Get current profile data from config file""" if not self.config_file_path.exists(): - # Return default profile structure if file doesn't exist from .dll_detection import DllDetectionService dll_service = DllDetectionService(self.log) default_config = ConfigurationManager.get_defaults_with_dll_detection(dll_service) @@ -263,13 +240,10 @@ class ConfigurationService(BaseService): """Save profile data to config file""" toml_content = ConfigurationManager.generate_toml_content_multi_profile(profile_data) - # Ensure config directory exists self.config_dir.mkdir(parents=True, exist_ok=True) - # Write the updated config directly to preserve inode for file watchers self._write_file(self.config_file_path, toml_content, 0o644) - # Profile management methods def get_profiles(self) -> ProfilesResponse: """Get list of all profiles and current profile @@ -303,14 +277,11 @@ class ConfigurationService(BaseService): try: profile_data = self._get_profile_data() - # Use current profile as source if not specified if not source_profile: source_profile = profile_data["current_profile"] - # Create the new profile new_profile_data = ConfigurationManager.create_profile(profile_data, profile_name, source_profile) - # Save to file self._save_profile_data(new_profile_data) self.log.info(f"Created profile '{profile_name}' from '{source_profile}'") @@ -340,13 +311,10 @@ class ConfigurationService(BaseService): try: profile_data = self._get_profile_data() - # Delete the profile new_profile_data = ConfigurationManager.delete_profile(profile_data, profile_name) - # Save to file self._save_profile_data(new_profile_data) - # Update launch script if current profile changed script_result = self.update_lsfg_script_from_profile_data(new_profile_data) if not script_result["success"]: self.log.warning(f"Failed to update launch script: {script_result['error']}") @@ -379,13 +347,10 @@ class ConfigurationService(BaseService): try: profile_data = self._get_profile_data() - # Rename the profile new_profile_data = ConfigurationManager.rename_profile(profile_data, old_name, new_name) - # Save to file self._save_profile_data(new_profile_data) - # Update launch script if current profile changed script_result = self.update_lsfg_script_from_profile_data(new_profile_data) if not script_result["success"]: self.log.warning(f"Failed to update launch script: {script_result['error']}") @@ -417,13 +382,10 @@ class ConfigurationService(BaseService): try: profile_data = self._get_profile_data() - # Set current profile new_profile_data = ConfigurationManager.set_current_profile(profile_data, profile_name) - # Save to file self._save_profile_data(new_profile_data) - # Update launch script with new current profile script_result = self.update_lsfg_script_from_profile_data(new_profile_data) if not script_result["success"]: self.log.warning(f"Failed to update launch script: {script_result['error']}") @@ -461,24 +423,19 @@ class ConfigurationService(BaseService): f"Profile '{profile_name}' does not exist", config=None) - # Update the profile's config - profile_data["profiles"][profile_name] = config + new_profile_data = ConfigurationManager.update_profile_config(profile_data, profile_name, config) - # Update global config fields if they're in the config for field_name in ["dll", "no_fp16"]: if field_name in config: profile_data["global_config"][field_name] = config[field_name] - # Save to file self._save_profile_data(profile_data) - # Update launch script if this is the current profile if profile_name == profile_data["current_profile"]: script_result = self.update_lsfg_script_from_profile_data(profile_data) if not script_result["success"]: self.log.warning(f"Failed to update launch script: {script_result['error']}") - # Log with dynamic field listing field_values = ", ".join(f"{k}={repr(v)}" for k, v in config.items()) self.log.info(f"Updated profile '{profile_name}' configuration: {field_values}") diff --git a/py_modules/lsfg_vk/constants.py b/py_modules/lsfg_vk/constants.py index 79d8585..3d8e44a 100644 --- a/py_modules/lsfg_vk/constants.py +++ b/py_modules/lsfg_vk/constants.py @@ -4,36 +4,30 @@ Constants for the lsfg-vk plugin. from pathlib import Path -# Directory paths LOCAL_LIB = ".local/lib" LOCAL_SHARE_BASE = ".local/share" VULKAN_LAYER_DIR = ".local/share/vulkan/implicit_layer.d" CONFIG_DIR = ".config/lsfg-vk" -# File names SCRIPT_NAME = "lsfg" CONFIG_FILENAME = "conf.toml" LIB_FILENAME = "liblsfg-vk.so" JSON_FILENAME = "VkLayer_LS_frame_generation.json" ZIP_FILENAME = "lsfg-vk_noui.zip" -# Flatpak files FLATPAK_23_08_FILENAME = "org.freedesktop.Platform.VulkanLayer.lsfg_vk_23.08.flatpak" FLATPAK_24_08_FILENAME = "org.freedesktop.Platform.VulkanLayer.lsfg_vk_24.08.flatpak" FLATPAK_25_08_FILENAME = "org.freedesktop.Platform.VulkanLayer.lsfg_vk_25.08.flatpak" -# File extensions SO_EXT = ".so" JSON_EXT = ".json" -# Directory for the zip file BIN_DIR = "bin" -# Lossless Scaling paths STEAM_COMMON_PATH = Path("steamapps/common/Lossless Scaling") LOSSLESS_DLL_NAME = "Lossless.dll" -# Environment variable names ENV_LSFG_DLL_PATH = "LSFG_DLL_PATH" ENV_XDG_DATA_HOME = "XDG_DATA_HOME" ENV_HOME = "HOME" + diff --git a/py_modules/lsfg_vk/dll_detection.py b/py_modules/lsfg_vk/dll_detection.py index e547405..f7ba444 100644 --- a/py_modules/lsfg_vk/dll_detection.py +++ b/py_modules/lsfg_vk/dll_detection.py @@ -31,27 +31,22 @@ class DllDetectionService(BaseService): DllDetectionResponse with detection status and path information """ try: - # Check environment variable first dll_path = self._check_env_dll_path() if dll_path: return dll_path - # Check XDG_DATA_HOME path xdg_path = self._check_xdg_data_home() if xdg_path: return xdg_path - # Check HOME/.local/share path home_path = self._check_home_local_share() if home_path: return home_path - # Check all Steam library folders (including SD cards) steam_libraries_path = self._check_steam_library_folders() if steam_libraries_path: return steam_libraries_path - # DLL not found in any expected location return { "detected": False, "path": None, @@ -164,25 +159,20 @@ class DllDetectionService(BaseService): """ library_paths = [] - # Try different possible Steam installation locations steam_paths = [] - # XDG_DATA_HOME path data_dir = os.getenv(ENV_XDG_DATA_HOME) if data_dir and data_dir.strip(): steam_paths.append(Path(data_dir.strip()) / "Steam") - # HOME/.local/share path (most common on Steam Deck) home_dir = os.getenv(ENV_HOME) if home_dir and home_dir.strip(): steam_paths.append(Path(home_dir.strip()) / ".local" / "share" / "Steam") for steam_path in steam_paths: if steam_path.exists(): - # Add the main Steam directory as a library library_paths.append(str(steam_path)) - # Parse libraryfolders.vdf for additional libraries vdf_path = steam_path / "steamapps" / "libraryfolders.vdf" if vdf_path.exists(): try: @@ -191,7 +181,6 @@ class DllDetectionService(BaseService): except Exception as e: self.log.warning(f"Failed to parse {vdf_path}: {str(e)}") - # Remove duplicates while preserving order seen = set() unique_paths = [] for path in library_paths: @@ -217,17 +206,13 @@ class DllDetectionService(BaseService): with open(vdf_path, 'r', encoding='utf-8', errors='ignore') as f: content = f.read() - # Look for "path" entries in the VDF file - # The format is typically: "path" "/path/to/library" path_pattern = r'"path"\s*"([^"]+)"' matches = re.findall(path_pattern, content, re.IGNORECASE) for path_match in matches: - # Convert Windows paths to Unix paths if needed path = path_match.replace('\\\\', '/').replace('\\', '/') library_path = Path(path) - # Verify the library folder exists and has a steamapps directory if library_path.exists() and (library_path / "steamapps").exists(): library_paths.append(str(library_path)) self.log.info(f"Found additional Steam library: {library_path}") diff --git a/py_modules/lsfg_vk/flatpak_service.py b/py_modules/lsfg_vk/flatpak_service.py index 0e3977f..c9be0ec 100644 --- a/py_modules/lsfg_vk/flatpak_service.py +++ b/py_modules/lsfg_vk/flatpak_service.py @@ -50,22 +50,18 @@ class FlatpakService(BaseService): 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 # Will be set when flatpak is detected + self.flatpak_command = None def _get_clean_env(self): """Get a clean environment without PyInstaller's bundled libraries""" - # Create a clean environment without PyInstaller's bundled libraries env = os.environ.copy() - # Remove LD_LIBRARY_PATH that might point to PyInstaller's bundled libs if 'LD_LIBRARY_PATH' in env: del env['LD_LIBRARY_PATH'] - # Ensure PATH includes standard binary locations standard_paths = ['/usr/bin', '/usr/local/bin', '/bin'] current_path = env.get('PATH', '') - # Add standard paths if they're not already there path_parts = current_path.split(':') if current_path else [] for std_path in standard_paths: if std_path not in path_parts: @@ -82,21 +78,17 @@ class FlatpakService(BaseService): env = self._get_clean_env() - # Log environment info for debugging 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}") - # Run the command with the clean environment 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""" - # Log environment info for debugging 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')}") - # Try common flatpak installation paths, starting with the standard command flatpak_paths = [ "flatpak", "/usr/bin/flatpak", @@ -132,7 +124,6 @@ class FlatpakService(BaseService): error_msg, installed_23_08=False, installed_24_08=False, installed_25_08=False) - # Get list of installed runtimes result = self._run_flatpak_command( ["list", "--runtime"], capture_output=True, text=True, check=True @@ -140,7 +131,6 @@ class FlatpakService(BaseService): installed_runtimes = result.stdout - # Check for all versions by looking for the base extension name and version base_extension_name = "org.freedesktop.Platform.VulkanLayer.lsfgvk" installed_23_08 = False installed_24_08 = False @@ -187,20 +177,18 @@ class FlatpakService(BaseService): if not self.check_flatpak_available(): return self._error_response(BaseResponse, "Flatpak is not available on this system") - # Get the path to the flatpak file 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: # 25.08 + 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}") - # Install the extension result = self._run_flatpak_command( ["install", "--user", "--noninteractive", str(flatpak_path)], capture_output=True, text=True @@ -232,10 +220,9 @@ class FlatpakService(BaseService): extension_id = self.extension_id_23_08 elif version == "24.08": extension_id = self.extension_id_24_08 - else: # 25.08 + else: extension_id = self.extension_id_25_08 - # Uninstall the extension result = self._run_flatpak_command( ["uninstall", "--user", "--noninteractive", extension_id], capture_output=True, text=True @@ -265,7 +252,6 @@ class FlatpakService(BaseService): error_msg, apps=[], total_apps=0) - # Get list of installed apps result = self._run_flatpak_command( ["list", "--app"], capture_output=True, text=True, check=True @@ -276,7 +262,6 @@ class FlatpakService(BaseService): if not line.strip(): continue - # Parse flatpak list output (Name\tApp ID\tVersion\tBranch\tInstallation) parts = line.split('\t') if len(parts) >= 2: app_name = parts[0].strip() @@ -318,9 +303,6 @@ class FlatpakService(BaseService): dll_path = f"{home_path}/.local/share/Steam/steamapps/common/Lossless Scaling/Lossless.dll" lsfg_path = f"{home_path}/lsfg" - # More precise checking - look for exact filesystem entries - # Flatpak output format typically shows filesystem entries like: - # filesystems=/path1;/path2;/path3 filesystem_section = "" in_context = False @@ -334,15 +316,12 @@ class FlatpakService(BaseService): filesystem_section = line break - # Check each required filesystem override has_config_fs = config_path in filesystem_section has_dll_fs = dll_path in filesystem_section has_lsfg_fs = lsfg_path in filesystem_section - # All three filesystem overrides must be present filesystem_override = has_config_fs and has_dll_fs and has_lsfg_fs - # Check for environment override in the [Environment] section env_override = False in_environment = False @@ -377,14 +356,12 @@ class FlatpakService(BaseService): dll_path = f"{home_path}/.local/share/Steam/steamapps/common/Lossless Scaling/Lossless.dll" lsfg_path = f"{home_path}/lsfg" - # Set all filesystem overrides filesystem_overrides = [ f"--filesystem={dll_path}", f"--filesystem={config_path}:rw", f"--filesystem={lsfg_path}:rw" ] - # Apply filesystem overrides for override in filesystem_overrides: result = self._run_flatpak_command( ["override", "--user", override, app_id], @@ -395,7 +372,6 @@ class FlatpakService(BaseService): return self._error_response(FlatpakOverrideResponse, error_msg, app_id=app_id, operation="set") - # Set environment override result = self._run_flatpak_command( ["override", "--user", f"--env=LSFG_CONFIG={config_path}/conf.toml", app_id], capture_output=True, text=True @@ -430,7 +406,6 @@ class FlatpakService(BaseService): dll_path = f"{home_path}/.local/share/Steam/steamapps/common/Lossless Scaling/Lossless.dll" lsfg_path = f"{home_path}/lsfg" - # First, try to reset all overrides for this app to clean slate reset_result = self._run_flatpak_command( ["override", "--user", "--reset", app_id], capture_output=True, text=True @@ -442,10 +417,8 @@ class FlatpakService(BaseService): f"All overrides reset for {app_id}", app_id=app_id, operation="remove") - # If reset fails, try individual removal (fallback) self.log.debug(f"Reset failed, trying individual removal: {reset_result.stderr}") - # Remove all filesystem overrides individually filesystem_overrides = [ f"--nofilesystem={dll_path}", f"--nofilesystem={config_path}", @@ -463,7 +436,6 @@ class FlatpakService(BaseService): if result.returncode != 0: removal_errors.append(f"{override}: {result.stderr}") - # Remove environment override result = self._run_flatpak_command( ["override", "--user", "--unset-env=LSFG_CONFIG", app_id], capture_output=True, text=True diff --git a/py_modules/lsfg_vk/installation.py b/py_modules/lsfg_vk/installation.py index a3b000f..4329d49 100644 --- a/py_modules/lsfg_vk/installation.py +++ b/py_modules/lsfg_vk/installation.py @@ -26,7 +26,6 @@ class InstallationService(BaseService): def __init__(self, logger=None): super().__init__(logger) - # File paths using constants self.lib_file = self.local_lib_dir / LIB_FILENAME self.json_file = self.local_share_dir / JSON_FILENAME @@ -37,26 +36,20 @@ class InstallationService(BaseService): InstallationResponse with success status and message/error """ try: - # Get the path to the zip file - need to go up to plugin root from py_modules/lsfg_vk/ plugin_dir = Path(__file__).parent.parent.parent zip_path = plugin_dir / BIN_DIR / ZIP_FILENAME - # Check if the zip file exists if not zip_path.exists(): error_msg = f"{ZIP_FILENAME} not found at {zip_path}" self.log.error(error_msg) return self._error_response(InstallationResponse, error_msg, message="") - # Create directories if they don't exist self._ensure_directories() - # Extract and install files self._extract_and_install_files(zip_path) - # Create the config file self._create_config_file() - # Create the lsfg launch script self._create_lsfg_launch_script() self.log.info("lsfg-vk installed successfully") @@ -67,7 +60,6 @@ class InstallationService(BaseService): self.log.error(error_msg) return self._error_response(InstallationResponse, str(e), message="") except Exception as e: - # Catch unexpected errors but log them separately error_msg = f"Unexpected error installing lsfg-vk: {str(e)}" self.log.error(error_msg) return self._error_response(InstallationResponse, str(e), message="") diff --git a/py_modules/lsfg_vk/plugin.py b/py_modules/lsfg_vk/plugin.py index 7731558..09128a1 100644 --- a/py_modules/lsfg_vk/plugin.py +++ b/py_modules/lsfg_vk/plugin.py @@ -34,13 +34,11 @@ class Plugin: def __init__(self): """Initialize the plugin with all necessary services""" - # Initialize services - they will use decky.logger by default self.installation_service = InstallationService() self.dll_detection_service = DllDetectionService() self.configuration_service = ConfigurationService() self.flatpak_service = FlatpakService() - # Installation methods async def install_lsfg_vk(self) -> Dict[str, Any]: """Install lsfg-vk by extracting the zip file to ~/.local @@ -65,7 +63,6 @@ class Plugin: """ return self.installation_service.uninstall() - # DLL detection methods async def check_lossless_scaling_dll(self) -> Dict[str, Any]: """Check if Lossless Scaling DLL is available at the expected paths @@ -85,14 +82,12 @@ class Plugin: """ result = self.dll_detection_service.check_lossless_scaling_dll() - # Convert to dict to allow modification result_dict = dict(result) - # If DLL was detected, automatically update the configuration if result.get("detected") and result.get("path"): try: dll_path = result["path"] - if dll_path: # Type guard + if dll_path: update_result = self.configuration_service.update_dll_path(dll_path) if update_result.get("success"): result_dict["config_updated"] = True @@ -113,7 +108,6 @@ class Plugin: Dict containing DLL path, SHA256 hash, and other stats """ try: - # First check if DLL is detected dll_result = self.dll_detection_service.check_lossless_scaling_dll() if not dll_result.get("detected") or not dll_result.get("path"): @@ -135,11 +129,9 @@ class Plugin: dll_path_obj = Path(dll_path) - # Calculate SHA256 hash sha256_hash = hashlib.sha256() try: with open(dll_path_obj, "rb") as f: - # Read file in chunks to handle large files efficiently for chunk in iter(lambda: f.read(4096), b""): sha256_hash.update(chunk) dll_sha256 = sha256_hash.hexdigest() @@ -167,7 +159,6 @@ class Plugin: "dll_sha256": None } - # Configuration methods async def get_lsfg_config(self) -> Dict[str, Any]: """Read current lsfg script configuration @@ -183,7 +174,6 @@ class Plugin: Dict with field names, types, defaults, and profile information """ try: - # Get profile information profiles_response = self.configuration_service.get_profiles() schema_data = { @@ -192,7 +182,6 @@ class Plugin: "defaults": ConfigurationManager.get_defaults() } - # Add profile information if available if profiles_response.get("success"): schema_data["profiles"] = profiles_response.get("profiles", []) schema_data["current_profile"] = profiles_response.get("current_profile") @@ -203,7 +192,6 @@ class Plugin: return schema_data except (ValueError, KeyError, AttributeError) as e: - # Fallback to basic schema without profile info self.configuration_service.log.warning(f"Failed to get full schema, using fallback: {e}") return { "field_names": ConfigurationManager.get_field_names(), @@ -222,10 +210,8 @@ class Plugin: Returns: ConfigurationResponse dict with success status """ - # Validate and extract configuration from the config dict validated_config = ConfigurationManager.validate_config(config) - # Use dynamic parameter passing based on schema return self.configuration_service.update_config_from_dict(validated_config) async def update_dll_path(self, dll_path: str) -> Dict[str, Any]: @@ -239,7 +225,6 @@ class Plugin: """ return self.configuration_service.update_dll_path(dll_path) - # Profile management methods async def get_profiles(self) -> Dict[str, Any]: """Get list of all profiles and current profile @@ -304,12 +289,10 @@ class Plugin: Returns: ConfigurationResponse dict with success status """ - # Validate and extract configuration from the config dict validated_config = ConfigurationManager.validate_config(config) return self.configuration_service.update_profile_config(profile_name, validated_config) - # Self-updater methods async def check_for_plugin_update(self) -> Dict[str, Any]: """Check for plugin updates by comparing current version with most recent GitHub release @@ -328,7 +311,6 @@ class Plugin: } """ try: - # Read current version from package.json package_json_path = Path(decky.DECKY_PLUGIN_DIR) / "package.json" current_version = "0.0.0" @@ -340,21 +322,16 @@ class Plugin: except Exception as e: decky.logger.warning(f"Failed to read package.json: {e}") - # Fetch most recent release from GitHub (including pre-releases) api_url = "https://api.github.com/repos/xXJSONDeruloXx/decky-lsfg-vk/releases" try: - # Create SSL context that doesn't verify certificates - # This is needed on Steam Deck where certificate verification often fails ssl_context = ssl.create_default_context() ssl_context.check_hostname = False ssl_context.verify_mode = ssl.CERT_NONE - # Use urllib to fetch all releases (sorted by most recent first) with urllib.request.urlopen(api_url, context=ssl_context) as response: releases_data = json.loads(response.read().decode('utf-8')) - # Get the most recent release (first item in the array) if not releases_data: raise Exception("No releases found") @@ -364,14 +341,12 @@ class Plugin: release_notes = release_data.get('body', '') release_date = release_data.get('published_at', '') - # Find the plugin zip download URL download_url = "" for asset in release_data.get('assets', []): if asset.get('name', '').endswith('.zip'): download_url = asset.get('browser_download_url', '') break - # Compare versions update_available = self._compare_versions(current_version, latest_version) return { @@ -412,31 +387,24 @@ class Plugin: } """ try: - # Create download path downloads_dir = Path.home() / "Downloads" downloads_dir.mkdir(exist_ok=True) download_path = downloads_dir / "decky-lsfg-vk.zip" - # Remove existing file if it exists if download_path.exists(): download_path.unlink() - # Download the file decky.logger.info(f"Downloading plugin update from {download_url}") try: - # Create SSL context that doesn't verify certificates - # This is needed on Steam Deck where certificate verification often fails ssl_context = ssl.create_default_context() ssl_context.check_hostname = False ssl_context.verify_mode = ssl.CERT_NONE - # Use urllib to download the file with SSL context with urllib.request.urlopen(download_url, context=ssl_context) as response: with open(download_path, 'wb') as f: f.write(response.read()) - # Verify the file was downloaded successfully if download_path.exists() and download_path.stat().st_size > 0: decky.logger.info(f"Plugin update downloaded successfully to {download_path}") return { @@ -473,16 +441,13 @@ class Plugin: True if latest version is newer than current version """ try: - # Remove 'v' prefix if present and split by dots current_parts = current.lstrip('v').split('.') latest_parts = latest.lstrip('v').split('.') - # Pad with zeros if needed to ensure equal length max_len = max(len(current_parts), len(latest_parts)) current_parts.extend(['0'] * (max_len - len(current_parts))) latest_parts.extend(['0'] * (max_len - len(latest_parts))) - # Compare each part numerically for i in range(max_len): try: current_num = int(current_parts[i]) @@ -492,24 +457,18 @@ class Plugin: return True elif latest_num < current_num: return False - # If equal, continue to next part except ValueError: - # If conversion fails, do string comparison if latest_parts[i] > current_parts[i]: return True elif latest_parts[i] < current_parts[i]: return False - # All parts are equal return False except (IndexError, AttributeError, TypeError) as e: - # If comparison fails, assume no update available self.configuration_service.log.warning(f"Version comparison failed: {e}") return False - # Plugin lifecycle methods - # Launch option methods async def get_launch_option(self) -> Dict[str, Any]: """Get the launch option that users need to set for their games @@ -522,7 +481,6 @@ class Plugin: "explanation": "The lsfg script is created during installation and sets up the environment for the plugin" } - # File content methods async def get_config_file_content(self) -> Dict[str, Any]: """Get the current config file content @@ -612,7 +570,6 @@ class Plugin: "error": str(e) } - # Flatpak management methods async def check_flatpak_extension_status(self) -> Dict[str, Any]: """Check status of lsfg-vk Flatpak runtime extensions @@ -673,9 +630,6 @@ class Plugin: """ return self.flatpak_service.remove_app_override(app_id) - # Decky Loader lifecycle methods - - # Lifecycle methods async def _main(self): """ Main entry point for the plugin. @@ -696,13 +650,12 @@ class Plugin: async def _uninstall(self): """ - Cleanup tasks when the plugin is uninstalled. + Called when the plugin is uninstalled. This method is called by Decky Loader when the plugin is being uninstalled. - It automatically cleans up any lsfg-vk files that were installed and - uninstalls any flatpak extensions. + Performs cleanup of plugin files and flatpak extensions. """ - decky.logger.info("decky-lsfg-vk plugin uninstalled - starting cleanup") + decky.logger.info("decky-lsfg-vk plugin being uninstalled") # Clean up lsfg-vk files when the plugin is uninstalled self.installation_service.cleanup_on_uninstall() @@ -711,11 +664,9 @@ class Plugin: try: decky.logger.info("Checking for flatpak extensions to uninstall") - # Get current extension status extension_status = self.flatpak_service.get_extension_status() if extension_status.get("success"): - # Uninstall 23.08 runtime if installed 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") @@ -724,7 +675,6 @@ class Plugin: else: decky.logger.warning(f"Failed to uninstall flatpak runtime 23.08: {result.get('error')}") - # Uninstall 24.08 runtime if installed 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") @@ -739,7 +689,6 @@ class Plugin: except Exception as e: decky.logger.error(f"Error during flatpak cleanup: {e}") - # Don't fail the uninstall if flatpak cleanup fails decky.logger.info("decky-lsfg-vk plugin uninstall cleanup completed") @@ -752,21 +701,13 @@ class Plugin: """ decky.logger.info("Running decky-lsfg-vk plugin migrations") - # Migrate logs from old location - # ~/.config/decky-lossless-scaling-vk/lossless-scaling-vk.log -> decky.DECKY_LOG_DIR/lossless-scaling-vk.log decky.migrate_logs(os.path.join(decky.DECKY_USER_HOME, ".config", "decky-lossless-scaling-vk", "lossless-scaling-vk.log")) - # Migrate settings from old locations - # ~/homebrew/settings/lossless-scaling-vk.json -> decky.DECKY_SETTINGS_DIR/lossless-scaling-vk.json - # ~/.config/decky-lossless-scaling-vk/ -> decky.DECKY_SETTINGS_DIR/ decky.migrate_settings( os.path.join(decky.DECKY_HOME, "settings", "lossless-scaling-vk.json"), os.path.join(decky.DECKY_USER_HOME, ".config", "decky-lossless-scaling-vk")) - # Migrate runtime data from old locations - # ~/homebrew/lossless-scaling-vk/ -> decky.DECKY_RUNTIME_DIR/ - # ~/.local/share/decky-lossless-scaling-vk/ -> decky.DECKY_RUNTIME_DIR/ decky.migrate_runtime( os.path.join(decky.DECKY_HOME, "lossless-scaling-vk"), os.path.join(decky.DECKY_USER_HOME, ".local", "share", "decky-lossless-scaling-vk")) -- cgit v1.2.3 From 6a4cb63fa3de3af111245fe5dd476d70775cd74f Mon Sep 17 00:00:00 2001 From: xXJsonDeruloXx Date: Tue, 21 Oct 2025 22:10:05 -0400 Subject: rm unused plugin update methods --- py_modules/lsfg_vk/plugin.py | 179 ------------------------------------------- 1 file changed, 179 deletions(-) diff --git a/py_modules/lsfg_vk/plugin.py b/py_modules/lsfg_vk/plugin.py index 09128a1..60916dd 100644 --- a/py_modules/lsfg_vk/plugin.py +++ b/py_modules/lsfg_vk/plugin.py @@ -6,10 +6,7 @@ Vulkan layer for frame generation on Steam Deck. """ import os -import json import subprocess -import urllib.request -import ssl import hashlib from typing import Dict, Any from pathlib import Path @@ -293,182 +290,6 @@ class Plugin: return self.configuration_service.update_profile_config(profile_name, validated_config) - async def check_for_plugin_update(self) -> Dict[str, Any]: - """Check for plugin updates by comparing current version with most recent GitHub release - - Checks for the most recent release including pre-releases, not just the latest stable. - - Returns: - Dict containing update information: - { - "update_available": bool, - "current_version": str, - "latest_version": str, - "release_notes": str, - "release_date": str, - "download_url": str, - "error": str (if error occurred) - } - """ - try: - package_json_path = Path(decky.DECKY_PLUGIN_DIR) / "package.json" - current_version = "0.0.0" - - if package_json_path.exists(): - try: - with open(package_json_path, 'r', encoding='utf-8') as f: - package_data = json.load(f) - current_version = package_data.get('version', '0.0.0') - except Exception as e: - decky.logger.warning(f"Failed to read package.json: {e}") - - api_url = "https://api.github.com/repos/xXJSONDeruloXx/decky-lsfg-vk/releases" - - try: - ssl_context = ssl.create_default_context() - ssl_context.check_hostname = False - ssl_context.verify_mode = ssl.CERT_NONE - - with urllib.request.urlopen(api_url, context=ssl_context) as response: - releases_data = json.loads(response.read().decode('utf-8')) - - if not releases_data: - raise Exception("No releases found") - - release_data = releases_data[0] - - latest_version = release_data.get('tag_name', '').lstrip('v') - release_notes = release_data.get('body', '') - release_date = release_data.get('published_at', '') - - download_url = "" - for asset in release_data.get('assets', []): - if asset.get('name', '').endswith('.zip'): - download_url = asset.get('browser_download_url', '') - break - - update_available = self._compare_versions(current_version, latest_version) - - return { - "success": True, - "update_available": update_available, - "current_version": current_version, - "latest_version": latest_version, - "release_notes": release_notes, - "release_date": release_date, - "download_url": download_url - } - - except Exception as e: - decky.logger.error(f"Failed to fetch release info: {e}") - return { - "success": False, - "error": f"Failed to check for updates: {str(e)}" - } - - except Exception as e: - return { - "success": False, - "error": f"Update check failed: {str(e)}" - } - - async def download_plugin_update(self, download_url: str) -> Dict[str, Any]: - """Download the plugin update zip file to ~/Downloads - - Args: - download_url: URL to download the plugin zip from - - Returns: - Dict containing download result: - { - "success": bool, - "download_path": str, - "error": str (if error occurred) - } - """ - try: - downloads_dir = Path.home() / "Downloads" - downloads_dir.mkdir(exist_ok=True) - download_path = downloads_dir / "decky-lsfg-vk.zip" - - if download_path.exists(): - download_path.unlink() - - decky.logger.info(f"Downloading plugin update from {download_url}") - - try: - ssl_context = ssl.create_default_context() - ssl_context.check_hostname = False - ssl_context.verify_mode = ssl.CERT_NONE - - with urllib.request.urlopen(download_url, context=ssl_context) as response: - with open(download_path, 'wb') as f: - f.write(response.read()) - - if download_path.exists() and download_path.stat().st_size > 0: - decky.logger.info(f"Plugin update downloaded successfully to {download_path}") - return { - "success": True, - "download_path": str(download_path) - } - else: - return { - "success": False, - "error": "Download completed but file is empty or missing" - } - - except Exception as e: - decky.logger.error(f"Download failed: {e}") - return { - "success": False, - "error": f"Download failed: {str(e)}" - } - - except Exception as e: - return { - "success": False, - "error": f"Download preparation failed: {str(e)}" - } - - def _compare_versions(self, current: str, latest: str) -> bool: - """Compare two version strings to determine if an update is available - - Args: - current: Current version string (e.g., "1.2.3") - latest: Latest version string (e.g., "1.2.4") - - Returns: - True if latest version is newer than current version - """ - try: - current_parts = current.lstrip('v').split('.') - latest_parts = latest.lstrip('v').split('.') - - max_len = max(len(current_parts), len(latest_parts)) - current_parts.extend(['0'] * (max_len - len(current_parts))) - latest_parts.extend(['0'] * (max_len - len(latest_parts))) - - for i in range(max_len): - try: - current_num = int(current_parts[i]) - latest_num = int(latest_parts[i]) - - if latest_num > current_num: - return True - elif latest_num < current_num: - return False - except ValueError: - if latest_parts[i] > current_parts[i]: - return True - elif latest_parts[i] < current_parts[i]: - return False - - return False - - except (IndexError, AttributeError, TypeError) as e: - self.configuration_service.log.warning(f"Version comparison failed: {e}") - return False - async def get_launch_option(self) -> Dict[str, Any]: """Get the launch option that users need to set for their games -- cgit v1.2.3 From 74b246f30bb6b030ad3cf1a2a993db1204f061c1 Mon Sep 17 00:00:00 2001 From: xXJsonDeruloXx Date: Tue, 21 Oct 2025 22:47:26 -0400 Subject: rm unused DLL path methods from ConfigurationService and Plugin classes --- py_modules/lsfg_vk/configuration.py | 35 ------------------------------- py_modules/lsfg_vk/plugin.py | 41 ------------------------------------- 2 files changed, 76 deletions(-) diff --git a/py_modules/lsfg_vk/configuration.py b/py_modules/lsfg_vk/configuration.py index 13fa925..332d4ef 100644 --- a/py_modules/lsfg_vk/configuration.py +++ b/py_modules/lsfg_vk/configuration.py @@ -104,41 +104,6 @@ class ConfigurationService(BaseService): self.log.error(error_msg) return self._error_response(ConfigurationResponse, str(e), config=None) - def update_dll_path(self, dll_path: str) -> ConfigurationResponse: - """Update just the DLL path in the configuration - - Args: - dll_path: Path to the Lossless.dll file - - Returns: - ConfigurationResponse with success status - """ - try: - profile_data = self._get_profile_data() - - profile_data["global_config"]["dll"] = dll_path - - current_profile = profile_data["current_profile"] - from .config_schema_generated import DLL - profile_data["profiles"][current_profile][DLL] = dll_path - - self._save_profile_data(profile_data) - - script_result = self.update_lsfg_script_from_profile_data(profile_data) - if not script_result["success"]: - self.log.warning(f"Failed to update launch script: {script_result['error']}") - - self.log.info(f"Updated DLL path in lsfg configuration: '{dll_path}'") - - return self._success_response(ConfigurationResponse, - f"DLL path updated to: {dll_path}", - config=profile_data["profiles"][current_profile]) - - except Exception as e: - error_msg = f"Error updating DLL path: {str(e)}" - self.log.error(error_msg) - return self._error_response(ConfigurationResponse, str(e), config=None) - def update_lsfg_script(self, config: ConfigurationData) -> ConfigurationResponse: """Update the ~/lsfg launch script with current configuration diff --git a/py_modules/lsfg_vk/plugin.py b/py_modules/lsfg_vk/plugin.py index 60916dd..cb59b4f 100644 --- a/py_modules/lsfg_vk/plugin.py +++ b/py_modules/lsfg_vk/plugin.py @@ -68,36 +68,6 @@ class Plugin: """ return self.dll_detection_service.check_lossless_scaling_dll() - async def check_lossless_scaling_dll_and_update_config(self) -> Dict[str, Any]: - """Check for DLL and automatically update configuration if found - - This method should only be used during installation or when explicitly - requested by the user, not for routine DLL detection checks. - - Returns: - DllDetectionResponse dict with detection status and path info - """ - result = self.dll_detection_service.check_lossless_scaling_dll() - - result_dict = dict(result) - - if result.get("detected") and result.get("path"): - try: - dll_path = result["path"] - if dll_path: - update_result = self.configuration_service.update_dll_path(dll_path) - if update_result.get("success"): - result_dict["config_updated"] = True - result_dict["message"] = f"DLL detected and configuration updated: {dll_path}" - else: - result_dict["config_updated"] = False - result_dict["message"] = f"DLL detected but config update failed: {update_result.get('error', 'Unknown error')}" - except Exception as e: - result_dict["config_updated"] = False - result_dict["message"] = f"DLL detected but config update failed: {str(e)}" - - return result_dict - async def get_dll_stats(self) -> Dict[str, Any]: """Get detailed statistics about the detected DLL @@ -211,17 +181,6 @@ class Plugin: return self.configuration_service.update_config_from_dict(validated_config) - async def update_dll_path(self, dll_path: str) -> Dict[str, Any]: - """Update the DLL path in the configuration when detected - - Args: - dll_path: Path to the detected Lossless.dll file - - Returns: - ConfigurationResponse dict with success status - """ - return self.configuration_service.update_dll_path(dll_path) - async def get_profiles(self) -> Dict[str, Any]: """Get list of all profiles and current profile -- cgit v1.2.3 From 4a6b8d3239e5ee904fa8ceead5cc2ce7707e70d6 Mon Sep 17 00:00:00 2001 From: xXJSONDeruloXx Date: Tue, 21 Oct 2025 23:14:12 -0400 Subject: chore: bump ver, add back autogen conf warnings --- package.json | 2 +- py_modules/lsfg_vk/config_schema_generated.py | 4 ++++ py_modules/lsfg_vk/configuration.py | 4 +++- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index dc45048..09f8844 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "decky-lsfg-vk", - "version": "0.12.0", + "version": "0.12.1", "description": "Use Lossless Scaling on the Steam Deck using the lsfg-vk vulkan layer", "type": "module", "scripts": { diff --git a/py_modules/lsfg_vk/config_schema_generated.py b/py_modules/lsfg_vk/config_schema_generated.py index 3aa5f68..53e9693 100644 --- a/py_modules/lsfg_vk/config_schema_generated.py +++ b/py_modules/lsfg_vk/config_schema_generated.py @@ -8,9 +8,11 @@ from enum import Enum import sys from pathlib import Path +# Import shared configuration constants sys.path.insert(0, str(Path(__file__).parent.parent.parent)) from shared_config import CONFIG_SCHEMA_DEF, ConfigFieldType +# Field name constants for type-safe access DLL = "dll" NO_FP16 = "no_fp16" MULTIPLIER = "multiplier" @@ -61,6 +63,7 @@ def get_script_parsing_logic(): key = key.strip() value = value.strip() + # Auto-generated parsing logic: if key == "DXVK_FRAME_RATE": try: script_values["dxvk_frame_rate"] = int(value) @@ -159,6 +162,7 @@ def create_config_dict(**kwargs) -> ConfigurationData: }) +# Field lists for dynamic operations TOML_FIELDS = ['dll', 'no_fp16', 'multiplier', 'flow_scale', 'performance_mode', 'hdr_mode', 'experimental_present_mode'] SCRIPT_FIELDS = ['dxvk_frame_rate', 'enable_wow64', 'disable_steamdeck_mode', 'mangohud_workaround', 'disable_vkbasalt', 'force_enable_vkbasalt', 'enable_wsi', 'enable_zink'] ALL_FIELDS = ['dll', 'no_fp16', 'multiplier', 'flow_scale', 'performance_mode', 'hdr_mode', 'experimental_present_mode', 'dxvk_frame_rate', 'enable_wow64', 'disable_steamdeck_mode', 'mangohud_workaround', 'disable_vkbasalt', 'force_enable_vkbasalt', 'enable_wsi', 'enable_zink'] diff --git a/py_modules/lsfg_vk/configuration.py b/py_modules/lsfg_vk/configuration.py index 332d4ef..8d3c034 100644 --- a/py_modules/lsfg_vk/configuration.py +++ b/py_modules/lsfg_vk/configuration.py @@ -140,6 +140,8 @@ class ConfigurationService(BaseService): """ lines = [ "#!/bin/bash", + "# lsfg-vk launch script generated by decky-lossless-scaling-vk plugin", + "# This script sets up the environment for lsfg-vk to work with the plugin configuration", ] generate_script_lines = get_script_generation_logic() @@ -388,7 +390,7 @@ class ConfigurationService(BaseService): f"Profile '{profile_name}' does not exist", config=None) - new_profile_data = ConfigurationManager.update_profile_config(profile_data, profile_name, config) + profile_data = ConfigurationManager.update_profile_config(profile_data, profile_name, config) for field_name in ["dll", "no_fp16"]: if field_name in config: -- cgit v1.2.3 From 805f714439e30122df20313f901e660c9a892dbb Mon Sep 17 00:00:00 2001 From: xXJSONDeruloXx Date: Tue, 21 Oct 2025 23:41:10 -0400 Subject: fix: profile update config ref fix and simplify ui feedback message --- py_modules/lsfg_vk/configuration.py | 4 +++- src/hooks/useInstallationActions.ts | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/py_modules/lsfg_vk/configuration.py b/py_modules/lsfg_vk/configuration.py index 8d3c034..9f8b028 100644 --- a/py_modules/lsfg_vk/configuration.py +++ b/py_modules/lsfg_vk/configuration.py @@ -390,8 +390,10 @@ class ConfigurationService(BaseService): f"Profile '{profile_name}' does not exist", config=None) - profile_data = ConfigurationManager.update_profile_config(profile_data, profile_name, config) + # Update the profile's config + profile_data["profiles"][profile_name] = config + # Update global config fields if they're in the config for field_name in ["dll", "no_fp16"]: if field_name in config: profile_data["global_config"][field_name] = config[field_name] diff --git a/src/hooks/useInstallationActions.ts b/src/hooks/useInstallationActions.ts index 18de6b5..f184145 100644 --- a/src/hooks/useInstallationActions.ts +++ b/src/hooks/useInstallationActions.ts @@ -23,7 +23,7 @@ export function useInstallationActions() { const result = await installLsfgVk(); if (result.success) { setIsInstalled(true); - setInstallationStatus("lsfg-vk installed successfully!"); + setInstallationStatus("lsfg-vk installed"); showInstallSuccessToast(); // Reload lsfg config after installation -- cgit v1.2.3 From 192716ecfd85199f2d5704314eb7873635d190e9 Mon Sep 17 00:00:00 2001 From: xXJSONDeruloXx Date: Tue, 21 Oct 2025 23:44:08 -0400 Subject: chore: rm generated schema and helper from gitignore for deployment pipeline --- .gitignore | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.gitignore b/.gitignore index c74264d..e384d9d 100644 --- a/.gitignore +++ b/.gitignore @@ -56,10 +56,10 @@ cli/ cli/* cli/decky -# generated files -py_modules/lsfg_vk/config_schema_generated.py -py_modules/lsfg_vk/configuration_helpers_generated.py -src/config/generatedConfigSchema.ts +# generated files (uncommented for now, need in git for store build deploys) +# py_modules/lsfg_vk/config_schema_generated.py +# py_modules/lsfg_vk/configuration_helpers_generated.py +# src/config/generatedConfigSchema.ts # Additional development artifacts *.pyc -- cgit v1.2.3