mirror of
https://github.com/Omni-guides/Jackify.git
synced 2026-01-17 11:37:01 +01:00
Sync from development - prepare for v0.1.5.2
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -35,7 +35,7 @@ Thumbs.db
|
||||
docs/
|
||||
testing/
|
||||
|
||||
# PyInstaller build files (development only)
|
||||
# Build files (development only)
|
||||
*.spec
|
||||
hook-*.py
|
||||
requirements-packaging.txt
|
||||
|
||||
21
CHANGELOG.md
21
CHANGELOG.md
@@ -1,5 +1,26 @@
|
||||
# Jackify Changelog
|
||||
|
||||
## v0.1.5.2 - Proton Configuration & Engine Updates
|
||||
**Release Date:** September 30, 2025
|
||||
|
||||
### Critical Bug Fixes
|
||||
- **Fixed Proton Version Selection**: Wine component installation now properly honors user-selected Proton version from Settings dialog
|
||||
- Previously, changing from GE-Proton to Proton Experimental in settings would still use the old version for component installation
|
||||
- Fixed ConfigHandler to reload fresh configuration from disk instead of using stale cache
|
||||
- Updated all Proton path retrieval across codebase to use fresh-reading methods
|
||||
|
||||
### Engine Updates
|
||||
- **jackify-engine v0.3.16**: Updated to latest engine version with important reliability improvements
|
||||
- **Sanity Check Fallback**: Added Proton 7z.exe fallback for case sensitivity extraction failures
|
||||
- **Enhanced Error Messages**: Improved texconv/texdiag error messages to include original texture file names and conversion parameters
|
||||
|
||||
### Technical Improvements
|
||||
- Enhanced configuration system reliability for multi-instance scenarios
|
||||
- Improved error diagnostics for texture processing operations
|
||||
- Fix Qt platform plugin discovery in AppImage distribution for improved compatibility
|
||||
|
||||
---
|
||||
|
||||
## v0.1.5.1 - Bug Fixes
|
||||
**Release Date:** September 28, 2025
|
||||
|
||||
|
||||
@@ -5,4 +5,4 @@ This package provides both CLI and GUI interfaces for managing
|
||||
Wabbajack modlists natively on Linux systems.
|
||||
"""
|
||||
|
||||
__version__ = "0.1.5.1"
|
||||
__version__ = "0.1.5.2"
|
||||
|
||||
@@ -30,7 +30,7 @@ def _get_user_proton_version():
|
||||
from jackify.backend.handlers.wine_utils import WineUtils
|
||||
|
||||
config_handler = ConfigHandler()
|
||||
user_proton_path = config_handler.get('proton_path', 'auto')
|
||||
user_proton_path = config_handler.get_proton_path()
|
||||
|
||||
if user_proton_path == 'auto':
|
||||
# Use enhanced fallback logic with GE-Proton preference
|
||||
|
||||
@@ -496,6 +496,42 @@ class ConfigHandler:
|
||||
logger.error(f"Error saving modlist downloads base directory: {e}")
|
||||
return False
|
||||
|
||||
def get_proton_path(self):
|
||||
"""
|
||||
Retrieve the saved Proton path from configuration
|
||||
Always reads fresh from disk to pick up changes from Settings dialog
|
||||
|
||||
Returns:
|
||||
str: Saved Proton path or 'auto' if not saved
|
||||
"""
|
||||
try:
|
||||
# Reload config from disk to pick up changes from Settings dialog
|
||||
self._load_config()
|
||||
proton_path = self.settings.get("proton_path", "auto")
|
||||
logger.debug(f"Retrieved fresh proton_path from config: {proton_path}")
|
||||
return proton_path
|
||||
except Exception as e:
|
||||
logger.error(f"Error retrieving proton_path: {e}")
|
||||
return "auto"
|
||||
|
||||
def get_proton_version(self):
|
||||
"""
|
||||
Retrieve the saved Proton version from configuration
|
||||
Always reads fresh from disk to pick up changes from Settings dialog
|
||||
|
||||
Returns:
|
||||
str: Saved Proton version or 'auto' if not saved
|
||||
"""
|
||||
try:
|
||||
# Reload config from disk to pick up changes from Settings dialog
|
||||
self._load_config()
|
||||
proton_version = self.settings.get("proton_version", "auto")
|
||||
logger.debug(f"Retrieved fresh proton_version from config: {proton_version}")
|
||||
return proton_version
|
||||
except Exception as e:
|
||||
logger.error(f"Error retrieving proton_version: {e}")
|
||||
return "auto"
|
||||
|
||||
def _auto_detect_proton(self):
|
||||
"""Auto-detect and set best Proton version (includes GE-Proton and Valve Proton)"""
|
||||
try:
|
||||
|
||||
@@ -692,10 +692,32 @@ class ModlistHandler:
|
||||
print("Error: Could not determine wine prefix location.")
|
||||
return False
|
||||
|
||||
if not self.winetricks_handler.install_wine_components(wineprefix, self.game_var_full, specific_components=components):
|
||||
self.logger.error("Failed to install Wine components. Configuration aborted.")
|
||||
print("Error: Failed to install necessary Wine components.")
|
||||
return False # Abort on failure
|
||||
# Try winetricks first (preferred method with current fix)
|
||||
winetricks_success = False
|
||||
try:
|
||||
self.logger.info("Attempting Wine component installation using winetricks...")
|
||||
winetricks_success = self.winetricks_handler.install_wine_components(wineprefix, self.game_var_full, specific_components=components)
|
||||
if winetricks_success:
|
||||
self.logger.info("Winetricks installation completed successfully")
|
||||
except Exception as e:
|
||||
self.logger.warning(f"Winetricks installation failed with exception: {e}")
|
||||
winetricks_success = False
|
||||
|
||||
# Fallback to protontricks if winetricks failed
|
||||
if not winetricks_success:
|
||||
self.logger.warning("Winetricks failed, falling back to protontricks for Wine component installation...")
|
||||
try:
|
||||
protontricks_success = self.protontricks_handler.install_wine_components(target_appid, self.game_var_full, specific_components=components)
|
||||
if protontricks_success:
|
||||
self.logger.info("Protontricks fallback installation completed successfully")
|
||||
else:
|
||||
self.logger.error("Both winetricks and protontricks failed to install Wine components.")
|
||||
print("Error: Failed to install necessary Wine components using both winetricks and protontricks.")
|
||||
return False
|
||||
except Exception as e:
|
||||
self.logger.error(f"Protontricks fallback also failed with exception: {e}")
|
||||
print("Error: Failed to install necessary Wine components using both winetricks and protontricks.")
|
||||
return False
|
||||
self.logger.info("Step 4: Installing Wine components... Done")
|
||||
|
||||
# Step 5: Ensure permissions of Modlist directory
|
||||
|
||||
@@ -630,47 +630,64 @@ class PathHandler:
|
||||
|
||||
# Moved _find_shortcuts_vdf here from ShortcutHandler
|
||||
def _find_shortcuts_vdf(self) -> Optional[str]:
|
||||
"""Helper to find the active shortcuts.vdf file for a user.
|
||||
"""Helper to find the active shortcuts.vdf file for the current Steam user.
|
||||
|
||||
Iterates through userdata directories and returns the path to the
|
||||
first found shortcuts.vdf file.
|
||||
Uses proper multi-user detection to find the correct Steam user instead
|
||||
of just taking the first found user directory.
|
||||
|
||||
Returns:
|
||||
Optional[str]: The full path to the shortcuts.vdf file, or None if not found.
|
||||
"""
|
||||
# This implementation was moved from ShortcutHandler
|
||||
userdata_base_paths = [
|
||||
os.path.expanduser("~/.steam/steam/userdata"),
|
||||
os.path.expanduser("~/.local/share/Steam/userdata"),
|
||||
os.path.expanduser("~/.var/app/com.valvesoftware.Steam/.local/share/Steam/userdata")
|
||||
]
|
||||
found_vdf_path = None
|
||||
for base_path in userdata_base_paths:
|
||||
if not os.path.isdir(base_path):
|
||||
logger.debug(f"Userdata base path not found or not a directory: {base_path}")
|
||||
continue
|
||||
logger.debug(f"Searching for user IDs in: {base_path}")
|
||||
try:
|
||||
for item in os.listdir(base_path):
|
||||
user_path = os.path.join(base_path, item)
|
||||
if os.path.isdir(user_path) and item.isdigit():
|
||||
logger.debug(f"Checking user directory: {user_path}")
|
||||
config_path = os.path.join(user_path, "config")
|
||||
shortcuts_file = os.path.join(config_path, "shortcuts.vdf")
|
||||
if os.path.isfile(shortcuts_file):
|
||||
logger.info(f"Found shortcuts.vdf at: {shortcuts_file}")
|
||||
found_vdf_path = shortcuts_file
|
||||
break # Found it for this base path
|
||||
else:
|
||||
logger.debug(f"shortcuts.vdf not found in {config_path}")
|
||||
except OSError as e:
|
||||
logger.warning(f"Could not access directory {base_path}: {e}")
|
||||
continue # Try next base path
|
||||
if found_vdf_path:
|
||||
break # Found it in this base path
|
||||
if not found_vdf_path:
|
||||
logger.error("Could not find any shortcuts.vdf file in common Steam locations.")
|
||||
return found_vdf_path
|
||||
try:
|
||||
# Use native Steam service for proper multi-user detection
|
||||
from jackify.backend.services.native_steam_service import NativeSteamService
|
||||
steam_service = NativeSteamService()
|
||||
shortcuts_path = steam_service.get_shortcuts_vdf_path()
|
||||
|
||||
if shortcuts_path:
|
||||
logger.info(f"Found shortcuts.vdf using multi-user detection: {shortcuts_path}")
|
||||
return str(shortcuts_path)
|
||||
else:
|
||||
logger.error("Could not determine shortcuts.vdf path using multi-user detection")
|
||||
return None
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error using multi-user detection for shortcuts.vdf: {e}")
|
||||
|
||||
# Fallback to legacy behavior if multi-user detection fails
|
||||
logger.warning("Falling back to legacy shortcuts.vdf detection (first-found user)")
|
||||
userdata_base_paths = [
|
||||
os.path.expanduser("~/.steam/steam/userdata"),
|
||||
os.path.expanduser("~/.local/share/Steam/userdata"),
|
||||
os.path.expanduser("~/.var/app/com.valvesoftware.Steam/.local/share/Steam/userdata")
|
||||
]
|
||||
found_vdf_path = None
|
||||
for base_path in userdata_base_paths:
|
||||
if not os.path.isdir(base_path):
|
||||
logger.debug(f"Userdata base path not found or not a directory: {base_path}")
|
||||
continue
|
||||
logger.debug(f"Searching for user IDs in: {base_path}")
|
||||
try:
|
||||
for item in os.listdir(base_path):
|
||||
user_path = os.path.join(base_path, item)
|
||||
if os.path.isdir(user_path) and item.isdigit():
|
||||
logger.debug(f"Checking user directory: {user_path}")
|
||||
config_path = os.path.join(user_path, "config")
|
||||
shortcuts_file = os.path.join(config_path, "shortcuts.vdf")
|
||||
if os.path.isfile(shortcuts_file):
|
||||
logger.info(f"Found shortcuts.vdf at: {shortcuts_file}")
|
||||
found_vdf_path = shortcuts_file
|
||||
break # Found it for this base path
|
||||
else:
|
||||
logger.debug(f"shortcuts.vdf not found in {config_path}")
|
||||
except OSError as e:
|
||||
logger.warning(f"Could not access directory {base_path}: {e}")
|
||||
continue # Try next base path
|
||||
if found_vdf_path:
|
||||
break # Found it in this base path
|
||||
if not found_vdf_path:
|
||||
logger.error("Could not find any shortcuts.vdf file in common Steam locations.")
|
||||
return found_vdf_path
|
||||
|
||||
@staticmethod
|
||||
def find_game_install_paths(target_appids: Dict[str, str]) -> Dict[str, Path]:
|
||||
|
||||
@@ -222,8 +222,14 @@ class ValidationHandler:
|
||||
def validate_steam_shortcut(self, app_id: str) -> Tuple[bool, str]:
|
||||
"""Validate a Steam shortcut."""
|
||||
try:
|
||||
# Check if shortcuts.vdf exists
|
||||
shortcuts_path = Path.home() / '.steam' / 'steam' / 'userdata' / '75424832' / 'config' / 'shortcuts.vdf'
|
||||
# Use native Steam service to get proper shortcuts.vdf path with multi-user support
|
||||
from jackify.backend.services.native_steam_service import NativeSteamService
|
||||
steam_service = NativeSteamService()
|
||||
shortcuts_path = steam_service.get_shortcuts_vdf_path()
|
||||
|
||||
if not shortcuts_path:
|
||||
return False, "Could not determine shortcuts.vdf path (no active Steam user found)"
|
||||
|
||||
if not shortcuts_path.exists():
|
||||
return False, "shortcuts.vdf not found"
|
||||
|
||||
|
||||
@@ -709,7 +709,7 @@ class WineUtils:
|
||||
try:
|
||||
from .config_handler import ConfigHandler
|
||||
config = ConfigHandler()
|
||||
fallback_path = config.get('proton_path', 'auto')
|
||||
fallback_path = config.get_proton_path()
|
||||
if fallback_path != 'auto':
|
||||
fallback_wine_bin = Path(fallback_path) / "files/bin/wine"
|
||||
if fallback_wine_bin.is_file():
|
||||
|
||||
@@ -137,7 +137,7 @@ class WinetricksHandler:
|
||||
from ..handlers.wine_utils import WineUtils
|
||||
|
||||
config = ConfigHandler()
|
||||
user_proton_path = config.get('proton_path', 'auto')
|
||||
user_proton_path = config.get_proton_path()
|
||||
|
||||
# If user selected a specific Proton, try that first
|
||||
wine_binary = None
|
||||
@@ -181,6 +181,49 @@ class WinetricksHandler:
|
||||
env['WINE'] = str(wine_binary)
|
||||
self.logger.info(f"Using Proton wine binary for winetricks: {wine_binary}")
|
||||
|
||||
# CRITICAL: Set up protontricks-compatible environment
|
||||
proton_dist_path = os.path.dirname(os.path.dirname(wine_binary)) # e.g., /path/to/proton/dist/bin/wine -> /path/to/proton/dist
|
||||
self.logger.debug(f"Proton dist path: {proton_dist_path}")
|
||||
|
||||
# Set WINEDLLPATH like protontricks does
|
||||
env['WINEDLLPATH'] = f"{proton_dist_path}/lib64/wine:{proton_dist_path}/lib/wine"
|
||||
|
||||
# Ensure Proton bin directory is first in PATH
|
||||
env['PATH'] = f"{proton_dist_path}/bin:{env.get('PATH', '')}"
|
||||
|
||||
# Set DLL overrides exactly like protontricks
|
||||
dll_overrides = {
|
||||
"beclient": "b,n",
|
||||
"beclient_x64": "b,n",
|
||||
"dxgi": "n",
|
||||
"d3d9": "n",
|
||||
"d3d10core": "n",
|
||||
"d3d11": "n",
|
||||
"d3d12": "n",
|
||||
"d3d12core": "n",
|
||||
"nvapi": "n",
|
||||
"nvapi64": "n",
|
||||
"nvofapi64": "n",
|
||||
"nvcuda": "b"
|
||||
}
|
||||
|
||||
# Merge with existing overrides
|
||||
existing_overrides = env.get('WINEDLLOVERRIDES', '')
|
||||
if existing_overrides:
|
||||
# Parse existing overrides
|
||||
for override in existing_overrides.split(';'):
|
||||
if '=' in override:
|
||||
name, value = override.split('=', 1)
|
||||
dll_overrides[name] = value
|
||||
|
||||
env['WINEDLLOVERRIDES'] = ';'.join(f"{name}={setting}" for name, setting in dll_overrides.items())
|
||||
|
||||
# Set Wine defaults from protontricks
|
||||
env['WINE_LARGE_ADDRESS_AWARE'] = '1'
|
||||
env['DXVK_ENABLE_NVAPI'] = '1'
|
||||
|
||||
self.logger.debug(f"Set protontricks environment: WINEDLLPATH={env['WINEDLLPATH']}")
|
||||
|
||||
except Exception as e:
|
||||
self.logger.error(f"Cannot run winetricks: Failed to get Proton wine binary: {e}")
|
||||
return False
|
||||
@@ -426,7 +469,8 @@ class WinetricksHandler:
|
||||
except Exception as e:
|
||||
self.logger.warning(f"Could not read winetricks.log: {e}")
|
||||
|
||||
self.logger.error(f"✗ {component} failed (attempt {attempt}): {result.stderr.strip()[:200]}")
|
||||
self.logger.error(f"✗ {component} failed (attempt {attempt}): {result.stderr.strip()}")
|
||||
self.logger.debug(f"Full stdout for {component}: {result.stdout.strip()}")
|
||||
|
||||
except Exception as e:
|
||||
self.logger.error(f"Error installing {component} (attempt {attempt}): {e}")
|
||||
|
||||
@@ -46,7 +46,7 @@ class AutomatedPrefixService:
|
||||
from jackify.backend.handlers.wine_utils import WineUtils
|
||||
|
||||
config_handler = ConfigHandler()
|
||||
user_proton_path = config_handler.get('proton_path', 'auto')
|
||||
user_proton_path = config_handler.get_proton_path()
|
||||
|
||||
if user_proton_path == 'auto':
|
||||
# Use enhanced fallback logic with GE-Proton preference
|
||||
@@ -2705,7 +2705,7 @@ echo Prefix creation complete.
|
||||
from jackify.backend.handlers.wine_utils import WineUtils
|
||||
|
||||
config = ConfigHandler()
|
||||
user_proton_path = config.get('proton_path', 'auto')
|
||||
user_proton_path = config.get_proton_path()
|
||||
|
||||
# If user selected a specific Proton, try that first
|
||||
if user_proton_path != 'auto':
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -7,7 +7,7 @@
|
||||
"targets": {
|
||||
".NETCoreApp,Version=v8.0": {},
|
||||
".NETCoreApp,Version=v8.0/linux-x64": {
|
||||
"jackify-engine/0.3.15": {
|
||||
"jackify-engine/0.3.16": {
|
||||
"dependencies": {
|
||||
"Markdig": "0.40.0",
|
||||
"Microsoft.Extensions.Configuration.Json": "9.0.1",
|
||||
@@ -22,16 +22,16 @@
|
||||
"SixLabors.ImageSharp": "3.1.6",
|
||||
"System.CommandLine": "2.0.0-beta4.22272.1",
|
||||
"System.CommandLine.NamingConventionBinder": "2.0.0-beta4.22272.1",
|
||||
"Wabbajack.CLI.Builder": "0.3.15",
|
||||
"Wabbajack.Downloaders.Bethesda": "0.3.15",
|
||||
"Wabbajack.Downloaders.Dispatcher": "0.3.15",
|
||||
"Wabbajack.Hashing.xxHash64": "0.3.15",
|
||||
"Wabbajack.Networking.Discord": "0.3.15",
|
||||
"Wabbajack.Networking.GitHub": "0.3.15",
|
||||
"Wabbajack.Paths.IO": "0.3.15",
|
||||
"Wabbajack.Server.Lib": "0.3.15",
|
||||
"Wabbajack.Services.OSIntegrated": "0.3.15",
|
||||
"Wabbajack.VFS": "0.3.15",
|
||||
"Wabbajack.CLI.Builder": "0.3.16",
|
||||
"Wabbajack.Downloaders.Bethesda": "0.3.16",
|
||||
"Wabbajack.Downloaders.Dispatcher": "0.3.16",
|
||||
"Wabbajack.Hashing.xxHash64": "0.3.16",
|
||||
"Wabbajack.Networking.Discord": "0.3.16",
|
||||
"Wabbajack.Networking.GitHub": "0.3.16",
|
||||
"Wabbajack.Paths.IO": "0.3.16",
|
||||
"Wabbajack.Server.Lib": "0.3.16",
|
||||
"Wabbajack.Services.OSIntegrated": "0.3.16",
|
||||
"Wabbajack.VFS": "0.3.16",
|
||||
"MegaApiClient": "1.0.0.0",
|
||||
"runtimepack.Microsoft.NETCore.App.Runtime.linux-x64": "8.0.19"
|
||||
},
|
||||
@@ -1781,7 +1781,7 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"Wabbajack.CLI.Builder/0.3.15": {
|
||||
"Wabbajack.CLI.Builder/0.3.16": {
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.Configuration.Json": "9.0.1",
|
||||
"Microsoft.Extensions.DependencyInjection": "9.0.1",
|
||||
@@ -1791,109 +1791,109 @@
|
||||
"Microsoft.Extensions.Logging.Abstractions": "9.0.1",
|
||||
"System.CommandLine": "2.0.0-beta4.22272.1",
|
||||
"System.CommandLine.NamingConventionBinder": "2.0.0-beta4.22272.1",
|
||||
"Wabbajack.Paths": "0.3.15"
|
||||
"Wabbajack.Paths": "0.3.16"
|
||||
},
|
||||
"runtime": {
|
||||
"Wabbajack.CLI.Builder.dll": {}
|
||||
}
|
||||
},
|
||||
"Wabbajack.Common/0.3.15": {
|
||||
"Wabbajack.Common/0.3.16": {
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.DependencyInjection": "9.0.1",
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.1",
|
||||
"Microsoft.Extensions.Logging.Abstractions": "9.0.1",
|
||||
"System.Reactive": "6.0.1",
|
||||
"Wabbajack.DTOs": "0.3.15",
|
||||
"Wabbajack.Networking.Http": "0.3.15",
|
||||
"Wabbajack.Paths.IO": "0.3.15"
|
||||
"Wabbajack.DTOs": "0.3.16",
|
||||
"Wabbajack.Networking.Http": "0.3.16",
|
||||
"Wabbajack.Paths.IO": "0.3.16"
|
||||
},
|
||||
"runtime": {
|
||||
"Wabbajack.Common.dll": {}
|
||||
}
|
||||
},
|
||||
"Wabbajack.Compiler/0.3.15": {
|
||||
"Wabbajack.Compiler/0.3.16": {
|
||||
"dependencies": {
|
||||
"F23.StringSimilarity": "6.0.0",
|
||||
"Microsoft.Extensions.DependencyInjection": "9.0.1",
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.1",
|
||||
"Newtonsoft.Json": "13.0.3",
|
||||
"SixLabors.ImageSharp": "3.1.6",
|
||||
"Wabbajack.Downloaders.Dispatcher": "0.3.15",
|
||||
"Wabbajack.Installer": "0.3.15",
|
||||
"Wabbajack.VFS": "0.3.15",
|
||||
"Wabbajack.Downloaders.Dispatcher": "0.3.16",
|
||||
"Wabbajack.Installer": "0.3.16",
|
||||
"Wabbajack.VFS": "0.3.16",
|
||||
"ini-parser-netstandard": "2.5.2"
|
||||
},
|
||||
"runtime": {
|
||||
"Wabbajack.Compiler.dll": {}
|
||||
}
|
||||
},
|
||||
"Wabbajack.Compression.BSA/0.3.15": {
|
||||
"Wabbajack.Compression.BSA/0.3.16": {
|
||||
"dependencies": {
|
||||
"K4os.Compression.LZ4.Streams": "1.3.8",
|
||||
"Microsoft.Extensions.DependencyInjection": "9.0.1",
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.1",
|
||||
"SharpZipLib": "1.4.2",
|
||||
"Wabbajack.Common": "0.3.15",
|
||||
"Wabbajack.DTOs": "0.3.15"
|
||||
"Wabbajack.Common": "0.3.16",
|
||||
"Wabbajack.DTOs": "0.3.16"
|
||||
},
|
||||
"runtime": {
|
||||
"Wabbajack.Compression.BSA.dll": {}
|
||||
}
|
||||
},
|
||||
"Wabbajack.Compression.Zip/0.3.15": {
|
||||
"Wabbajack.Compression.Zip/0.3.16": {
|
||||
"dependencies": {
|
||||
"Wabbajack.IO.Async": "0.3.15"
|
||||
"Wabbajack.IO.Async": "0.3.16"
|
||||
},
|
||||
"runtime": {
|
||||
"Wabbajack.Compression.Zip.dll": {}
|
||||
}
|
||||
},
|
||||
"Wabbajack.Configuration/0.3.15": {
|
||||
"Wabbajack.Configuration/0.3.16": {
|
||||
"runtime": {
|
||||
"Wabbajack.Configuration.dll": {}
|
||||
}
|
||||
},
|
||||
"Wabbajack.Downloaders.Bethesda/0.3.15": {
|
||||
"Wabbajack.Downloaders.Bethesda/0.3.16": {
|
||||
"dependencies": {
|
||||
"LibAES-CTR": "1.1.0",
|
||||
"Microsoft.Extensions.DependencyInjection": "9.0.1",
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.1",
|
||||
"SharpZipLib": "1.4.2",
|
||||
"Wabbajack.Common": "0.3.15",
|
||||
"Wabbajack.Downloaders.Interfaces": "0.3.15",
|
||||
"Wabbajack.Networking.BethesdaNet": "0.3.15"
|
||||
"Wabbajack.Common": "0.3.16",
|
||||
"Wabbajack.Downloaders.Interfaces": "0.3.16",
|
||||
"Wabbajack.Networking.BethesdaNet": "0.3.16"
|
||||
},
|
||||
"runtime": {
|
||||
"Wabbajack.Downloaders.Bethesda.dll": {}
|
||||
}
|
||||
},
|
||||
"Wabbajack.Downloaders.Dispatcher/0.3.15": {
|
||||
"Wabbajack.Downloaders.Dispatcher/0.3.16": {
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.DependencyInjection": "9.0.1",
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.1",
|
||||
"Microsoft.Extensions.Logging.Abstractions": "9.0.1",
|
||||
"Newtonsoft.Json": "13.0.3",
|
||||
"SixLabors.ImageSharp": "3.1.6",
|
||||
"Wabbajack.Downloaders.Bethesda": "0.3.15",
|
||||
"Wabbajack.Downloaders.GameFile": "0.3.15",
|
||||
"Wabbajack.Downloaders.GoogleDrive": "0.3.15",
|
||||
"Wabbajack.Downloaders.Http": "0.3.15",
|
||||
"Wabbajack.Downloaders.IPS4OAuth2Downloader": "0.3.15",
|
||||
"Wabbajack.Downloaders.Interfaces": "0.3.15",
|
||||
"Wabbajack.Downloaders.Manual": "0.3.15",
|
||||
"Wabbajack.Downloaders.MediaFire": "0.3.15",
|
||||
"Wabbajack.Downloaders.Mega": "0.3.15",
|
||||
"Wabbajack.Downloaders.ModDB": "0.3.15",
|
||||
"Wabbajack.Downloaders.Nexus": "0.3.15",
|
||||
"Wabbajack.Downloaders.VerificationCache": "0.3.15",
|
||||
"Wabbajack.Downloaders.WabbajackCDN": "0.3.15",
|
||||
"Wabbajack.Networking.WabbajackClientApi": "0.3.15"
|
||||
"Wabbajack.Downloaders.Bethesda": "0.3.16",
|
||||
"Wabbajack.Downloaders.GameFile": "0.3.16",
|
||||
"Wabbajack.Downloaders.GoogleDrive": "0.3.16",
|
||||
"Wabbajack.Downloaders.Http": "0.3.16",
|
||||
"Wabbajack.Downloaders.IPS4OAuth2Downloader": "0.3.16",
|
||||
"Wabbajack.Downloaders.Interfaces": "0.3.16",
|
||||
"Wabbajack.Downloaders.Manual": "0.3.16",
|
||||
"Wabbajack.Downloaders.MediaFire": "0.3.16",
|
||||
"Wabbajack.Downloaders.Mega": "0.3.16",
|
||||
"Wabbajack.Downloaders.ModDB": "0.3.16",
|
||||
"Wabbajack.Downloaders.Nexus": "0.3.16",
|
||||
"Wabbajack.Downloaders.VerificationCache": "0.3.16",
|
||||
"Wabbajack.Downloaders.WabbajackCDN": "0.3.16",
|
||||
"Wabbajack.Networking.WabbajackClientApi": "0.3.16"
|
||||
},
|
||||
"runtime": {
|
||||
"Wabbajack.Downloaders.Dispatcher.dll": {}
|
||||
}
|
||||
},
|
||||
"Wabbajack.Downloaders.GameFile/0.3.15": {
|
||||
"Wabbajack.Downloaders.GameFile/0.3.16": {
|
||||
"dependencies": {
|
||||
"GameFinder.StoreHandlers.EADesktop": "4.5.0",
|
||||
"GameFinder.StoreHandlers.EGS": "4.5.0",
|
||||
@@ -1903,360 +1903,360 @@
|
||||
"Microsoft.Extensions.DependencyInjection": "9.0.1",
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.1",
|
||||
"SixLabors.ImageSharp": "3.1.6",
|
||||
"Wabbajack.Downloaders.Interfaces": "0.3.15",
|
||||
"Wabbajack.VFS": "0.3.15"
|
||||
"Wabbajack.Downloaders.Interfaces": "0.3.16",
|
||||
"Wabbajack.VFS": "0.3.16"
|
||||
},
|
||||
"runtime": {
|
||||
"Wabbajack.Downloaders.GameFile.dll": {}
|
||||
}
|
||||
},
|
||||
"Wabbajack.Downloaders.GoogleDrive/0.3.15": {
|
||||
"Wabbajack.Downloaders.GoogleDrive/0.3.16": {
|
||||
"dependencies": {
|
||||
"HtmlAgilityPack": "1.11.72",
|
||||
"Microsoft.AspNetCore.Http.Extensions": "2.3.0",
|
||||
"Microsoft.Extensions.DependencyInjection": "9.0.1",
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.1",
|
||||
"Microsoft.Extensions.Logging.Abstractions": "9.0.1",
|
||||
"Wabbajack.Common": "0.3.15",
|
||||
"Wabbajack.DTOs": "0.3.15",
|
||||
"Wabbajack.Downloaders.Interfaces": "0.3.15",
|
||||
"Wabbajack.Networking.Http": "0.3.15",
|
||||
"Wabbajack.Networking.Http.Interfaces": "0.3.15"
|
||||
"Wabbajack.Common": "0.3.16",
|
||||
"Wabbajack.DTOs": "0.3.16",
|
||||
"Wabbajack.Downloaders.Interfaces": "0.3.16",
|
||||
"Wabbajack.Networking.Http": "0.3.16",
|
||||
"Wabbajack.Networking.Http.Interfaces": "0.3.16"
|
||||
},
|
||||
"runtime": {
|
||||
"Wabbajack.Downloaders.GoogleDrive.dll": {}
|
||||
}
|
||||
},
|
||||
"Wabbajack.Downloaders.Http/0.3.15": {
|
||||
"Wabbajack.Downloaders.Http/0.3.16": {
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.DependencyInjection": "9.0.1",
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.1",
|
||||
"Microsoft.Extensions.Logging.Abstractions": "9.0.1",
|
||||
"Wabbajack.Common": "0.3.15",
|
||||
"Wabbajack.DTOs": "0.3.15",
|
||||
"Wabbajack.Downloaders.Interfaces": "0.3.15",
|
||||
"Wabbajack.Networking.BethesdaNet": "0.3.15",
|
||||
"Wabbajack.Networking.Http.Interfaces": "0.3.15",
|
||||
"Wabbajack.Paths.IO": "0.3.15"
|
||||
"Wabbajack.Common": "0.3.16",
|
||||
"Wabbajack.DTOs": "0.3.16",
|
||||
"Wabbajack.Downloaders.Interfaces": "0.3.16",
|
||||
"Wabbajack.Networking.BethesdaNet": "0.3.16",
|
||||
"Wabbajack.Networking.Http.Interfaces": "0.3.16",
|
||||
"Wabbajack.Paths.IO": "0.3.16"
|
||||
},
|
||||
"runtime": {
|
||||
"Wabbajack.Downloaders.Http.dll": {}
|
||||
}
|
||||
},
|
||||
"Wabbajack.Downloaders.Interfaces/0.3.15": {
|
||||
"Wabbajack.Downloaders.Interfaces/0.3.16": {
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.DependencyInjection": "9.0.1",
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.1",
|
||||
"Wabbajack.Compression.Zip": "0.3.15",
|
||||
"Wabbajack.DTOs": "0.3.15",
|
||||
"Wabbajack.Paths.IO": "0.3.15"
|
||||
"Wabbajack.Compression.Zip": "0.3.16",
|
||||
"Wabbajack.DTOs": "0.3.16",
|
||||
"Wabbajack.Paths.IO": "0.3.16"
|
||||
},
|
||||
"runtime": {
|
||||
"Wabbajack.Downloaders.Interfaces.dll": {}
|
||||
}
|
||||
},
|
||||
"Wabbajack.Downloaders.IPS4OAuth2Downloader/0.3.15": {
|
||||
"Wabbajack.Downloaders.IPS4OAuth2Downloader/0.3.16": {
|
||||
"dependencies": {
|
||||
"F23.StringSimilarity": "6.0.0",
|
||||
"Microsoft.Extensions.DependencyInjection": "9.0.1",
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.1",
|
||||
"Microsoft.Extensions.Logging.Abstractions": "9.0.1",
|
||||
"Wabbajack.Common": "0.3.15",
|
||||
"Wabbajack.Downloaders.Interfaces": "0.3.15",
|
||||
"Wabbajack.Networking.Http": "0.3.15",
|
||||
"Wabbajack.Networking.Http.Interfaces": "0.3.15"
|
||||
"Wabbajack.Common": "0.3.16",
|
||||
"Wabbajack.Downloaders.Interfaces": "0.3.16",
|
||||
"Wabbajack.Networking.Http": "0.3.16",
|
||||
"Wabbajack.Networking.Http.Interfaces": "0.3.16"
|
||||
},
|
||||
"runtime": {
|
||||
"Wabbajack.Downloaders.IPS4OAuth2Downloader.dll": {}
|
||||
}
|
||||
},
|
||||
"Wabbajack.Downloaders.Manual/0.3.15": {
|
||||
"Wabbajack.Downloaders.Manual/0.3.16": {
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.DependencyInjection": "9.0.1",
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.1",
|
||||
"Microsoft.Extensions.Logging.Abstractions": "9.0.1",
|
||||
"Wabbajack.Common": "0.3.15",
|
||||
"Wabbajack.Downloaders.Interfaces": "0.3.15"
|
||||
"Wabbajack.Common": "0.3.16",
|
||||
"Wabbajack.Downloaders.Interfaces": "0.3.16"
|
||||
},
|
||||
"runtime": {
|
||||
"Wabbajack.Downloaders.Manual.dll": {}
|
||||
}
|
||||
},
|
||||
"Wabbajack.Downloaders.MediaFire/0.3.15": {
|
||||
"Wabbajack.Downloaders.MediaFire/0.3.16": {
|
||||
"dependencies": {
|
||||
"HtmlAgilityPack": "1.11.72",
|
||||
"Microsoft.Extensions.DependencyInjection": "9.0.1",
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.1",
|
||||
"Microsoft.Extensions.Logging.Abstractions": "9.0.1",
|
||||
"Wabbajack.Common": "0.3.15",
|
||||
"Wabbajack.Downloaders.Interfaces": "0.3.15",
|
||||
"Wabbajack.Networking.Http.Interfaces": "0.3.15"
|
||||
"Wabbajack.Common": "0.3.16",
|
||||
"Wabbajack.Downloaders.Interfaces": "0.3.16",
|
||||
"Wabbajack.Networking.Http.Interfaces": "0.3.16"
|
||||
},
|
||||
"runtime": {
|
||||
"Wabbajack.Downloaders.MediaFire.dll": {}
|
||||
}
|
||||
},
|
||||
"Wabbajack.Downloaders.Mega/0.3.15": {
|
||||
"Wabbajack.Downloaders.Mega/0.3.16": {
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.DependencyInjection": "9.0.1",
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.1",
|
||||
"Microsoft.Extensions.Logging.Abstractions": "9.0.1",
|
||||
"Newtonsoft.Json": "13.0.3",
|
||||
"Wabbajack.Common": "0.3.15",
|
||||
"Wabbajack.Downloaders.Interfaces": "0.3.15",
|
||||
"Wabbajack.Paths.IO": "0.3.15"
|
||||
"Wabbajack.Common": "0.3.16",
|
||||
"Wabbajack.Downloaders.Interfaces": "0.3.16",
|
||||
"Wabbajack.Paths.IO": "0.3.16"
|
||||
},
|
||||
"runtime": {
|
||||
"Wabbajack.Downloaders.Mega.dll": {}
|
||||
}
|
||||
},
|
||||
"Wabbajack.Downloaders.ModDB/0.3.15": {
|
||||
"Wabbajack.Downloaders.ModDB/0.3.16": {
|
||||
"dependencies": {
|
||||
"HtmlAgilityPack": "1.11.72",
|
||||
"Microsoft.Extensions.DependencyInjection": "9.0.1",
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.1",
|
||||
"Microsoft.Extensions.Logging.Abstractions": "9.0.1",
|
||||
"Newtonsoft.Json": "13.0.3",
|
||||
"Wabbajack.Common": "0.3.15",
|
||||
"Wabbajack.Downloaders.Interfaces": "0.3.15",
|
||||
"Wabbajack.Networking.Http": "0.3.15",
|
||||
"Wabbajack.Networking.Http.Interfaces": "0.3.15"
|
||||
"Wabbajack.Common": "0.3.16",
|
||||
"Wabbajack.Downloaders.Interfaces": "0.3.16",
|
||||
"Wabbajack.Networking.Http": "0.3.16",
|
||||
"Wabbajack.Networking.Http.Interfaces": "0.3.16"
|
||||
},
|
||||
"runtime": {
|
||||
"Wabbajack.Downloaders.ModDB.dll": {}
|
||||
}
|
||||
},
|
||||
"Wabbajack.Downloaders.Nexus/0.3.15": {
|
||||
"Wabbajack.Downloaders.Nexus/0.3.16": {
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.DependencyInjection": "9.0.1",
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.1",
|
||||
"Wabbajack.DTOs": "0.3.15",
|
||||
"Wabbajack.Downloaders.Interfaces": "0.3.15",
|
||||
"Wabbajack.Hashing.xxHash64": "0.3.15",
|
||||
"Wabbajack.Networking.Http": "0.3.15",
|
||||
"Wabbajack.Networking.Http.Interfaces": "0.3.15",
|
||||
"Wabbajack.Networking.NexusApi": "0.3.15",
|
||||
"Wabbajack.Paths": "0.3.15"
|
||||
"Wabbajack.DTOs": "0.3.16",
|
||||
"Wabbajack.Downloaders.Interfaces": "0.3.16",
|
||||
"Wabbajack.Hashing.xxHash64": "0.3.16",
|
||||
"Wabbajack.Networking.Http": "0.3.16",
|
||||
"Wabbajack.Networking.Http.Interfaces": "0.3.16",
|
||||
"Wabbajack.Networking.NexusApi": "0.3.16",
|
||||
"Wabbajack.Paths": "0.3.16"
|
||||
},
|
||||
"runtime": {
|
||||
"Wabbajack.Downloaders.Nexus.dll": {}
|
||||
}
|
||||
},
|
||||
"Wabbajack.Downloaders.VerificationCache/0.3.15": {
|
||||
"Wabbajack.Downloaders.VerificationCache/0.3.16": {
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.DependencyInjection": "9.0.1",
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.1",
|
||||
"Microsoft.Extensions.Logging.Abstractions": "9.0.1",
|
||||
"Stub.System.Data.SQLite.Core.NetStandard": "1.0.119",
|
||||
"Wabbajack.DTOs": "0.3.15",
|
||||
"Wabbajack.Paths.IO": "0.3.15"
|
||||
"Wabbajack.DTOs": "0.3.16",
|
||||
"Wabbajack.Paths.IO": "0.3.16"
|
||||
},
|
||||
"runtime": {
|
||||
"Wabbajack.Downloaders.VerificationCache.dll": {}
|
||||
}
|
||||
},
|
||||
"Wabbajack.Downloaders.WabbajackCDN/0.3.15": {
|
||||
"Wabbajack.Downloaders.WabbajackCDN/0.3.16": {
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.DependencyInjection": "9.0.1",
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.1",
|
||||
"Microsoft.Extensions.Logging.Abstractions": "9.0.1",
|
||||
"Microsoft.Toolkit.HighPerformance": "7.1.2",
|
||||
"Wabbajack.Common": "0.3.15",
|
||||
"Wabbajack.Downloaders.Interfaces": "0.3.15",
|
||||
"Wabbajack.Networking.Http": "0.3.15",
|
||||
"Wabbajack.RateLimiter": "0.3.15"
|
||||
"Wabbajack.Common": "0.3.16",
|
||||
"Wabbajack.Downloaders.Interfaces": "0.3.16",
|
||||
"Wabbajack.Networking.Http": "0.3.16",
|
||||
"Wabbajack.RateLimiter": "0.3.16"
|
||||
},
|
||||
"runtime": {
|
||||
"Wabbajack.Downloaders.WabbajackCDN.dll": {}
|
||||
}
|
||||
},
|
||||
"Wabbajack.DTOs/0.3.15": {
|
||||
"Wabbajack.DTOs/0.3.16": {
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.DependencyInjection": "9.0.1",
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.1",
|
||||
"Wabbajack.Hashing.xxHash64": "0.3.15",
|
||||
"Wabbajack.Paths": "0.3.15"
|
||||
"Wabbajack.Hashing.xxHash64": "0.3.16",
|
||||
"Wabbajack.Paths": "0.3.16"
|
||||
},
|
||||
"runtime": {
|
||||
"Wabbajack.DTOs.dll": {}
|
||||
}
|
||||
},
|
||||
"Wabbajack.FileExtractor/0.3.15": {
|
||||
"Wabbajack.FileExtractor/0.3.16": {
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.DependencyInjection": "9.0.1",
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.1",
|
||||
"Microsoft.Extensions.Logging.Abstractions": "9.0.1",
|
||||
"OMODFramework": "3.0.1",
|
||||
"Wabbajack.Common": "0.3.15",
|
||||
"Wabbajack.Compression.BSA": "0.3.15",
|
||||
"Wabbajack.Hashing.PHash": "0.3.15",
|
||||
"Wabbajack.Paths": "0.3.15"
|
||||
"Wabbajack.Common": "0.3.16",
|
||||
"Wabbajack.Compression.BSA": "0.3.16",
|
||||
"Wabbajack.Hashing.PHash": "0.3.16",
|
||||
"Wabbajack.Paths": "0.3.16"
|
||||
},
|
||||
"runtime": {
|
||||
"Wabbajack.FileExtractor.dll": {}
|
||||
}
|
||||
},
|
||||
"Wabbajack.Hashing.PHash/0.3.15": {
|
||||
"Wabbajack.Hashing.PHash/0.3.16": {
|
||||
"dependencies": {
|
||||
"BCnEncoder.Net.ImageSharp": "1.1.1",
|
||||
"Microsoft.Extensions.DependencyInjection": "9.0.1",
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.1",
|
||||
"Shipwreck.Phash": "0.5.0",
|
||||
"SixLabors.ImageSharp": "3.1.6",
|
||||
"Wabbajack.Common": "0.3.15",
|
||||
"Wabbajack.DTOs": "0.3.15",
|
||||
"Wabbajack.Paths": "0.3.15",
|
||||
"Wabbajack.Paths.IO": "0.3.15"
|
||||
"Wabbajack.Common": "0.3.16",
|
||||
"Wabbajack.DTOs": "0.3.16",
|
||||
"Wabbajack.Paths": "0.3.16",
|
||||
"Wabbajack.Paths.IO": "0.3.16"
|
||||
},
|
||||
"runtime": {
|
||||
"Wabbajack.Hashing.PHash.dll": {}
|
||||
}
|
||||
},
|
||||
"Wabbajack.Hashing.xxHash64/0.3.15": {
|
||||
"Wabbajack.Hashing.xxHash64/0.3.16": {
|
||||
"dependencies": {
|
||||
"Wabbajack.Paths": "0.3.15",
|
||||
"Wabbajack.RateLimiter": "0.3.15"
|
||||
"Wabbajack.Paths": "0.3.16",
|
||||
"Wabbajack.RateLimiter": "0.3.16"
|
||||
},
|
||||
"runtime": {
|
||||
"Wabbajack.Hashing.xxHash64.dll": {}
|
||||
}
|
||||
},
|
||||
"Wabbajack.Installer/0.3.15": {
|
||||
"Wabbajack.Installer/0.3.16": {
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.DependencyInjection": "9.0.1",
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.1",
|
||||
"Newtonsoft.Json": "13.0.3",
|
||||
"Octopus.Octodiff": "2.0.548",
|
||||
"SixLabors.ImageSharp": "3.1.6",
|
||||
"Wabbajack.DTOs": "0.3.15",
|
||||
"Wabbajack.Downloaders.Dispatcher": "0.3.15",
|
||||
"Wabbajack.Downloaders.GameFile": "0.3.15",
|
||||
"Wabbajack.FileExtractor": "0.3.15",
|
||||
"Wabbajack.Networking.WabbajackClientApi": "0.3.15",
|
||||
"Wabbajack.Paths": "0.3.15",
|
||||
"Wabbajack.Paths.IO": "0.3.15",
|
||||
"Wabbajack.VFS": "0.3.15",
|
||||
"Wabbajack.DTOs": "0.3.16",
|
||||
"Wabbajack.Downloaders.Dispatcher": "0.3.16",
|
||||
"Wabbajack.Downloaders.GameFile": "0.3.16",
|
||||
"Wabbajack.FileExtractor": "0.3.16",
|
||||
"Wabbajack.Networking.WabbajackClientApi": "0.3.16",
|
||||
"Wabbajack.Paths": "0.3.16",
|
||||
"Wabbajack.Paths.IO": "0.3.16",
|
||||
"Wabbajack.VFS": "0.3.16",
|
||||
"ini-parser-netstandard": "2.5.2"
|
||||
},
|
||||
"runtime": {
|
||||
"Wabbajack.Installer.dll": {}
|
||||
}
|
||||
},
|
||||
"Wabbajack.IO.Async/0.3.15": {
|
||||
"Wabbajack.IO.Async/0.3.16": {
|
||||
"runtime": {
|
||||
"Wabbajack.IO.Async.dll": {}
|
||||
}
|
||||
},
|
||||
"Wabbajack.Networking.BethesdaNet/0.3.15": {
|
||||
"Wabbajack.Networking.BethesdaNet/0.3.16": {
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.DependencyInjection": "9.0.1",
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.1",
|
||||
"Wabbajack.DTOs": "0.3.15",
|
||||
"Wabbajack.Networking.Http": "0.3.15",
|
||||
"Wabbajack.Networking.Http.Interfaces": "0.3.15"
|
||||
"Wabbajack.DTOs": "0.3.16",
|
||||
"Wabbajack.Networking.Http": "0.3.16",
|
||||
"Wabbajack.Networking.Http.Interfaces": "0.3.16"
|
||||
},
|
||||
"runtime": {
|
||||
"Wabbajack.Networking.BethesdaNet.dll": {}
|
||||
}
|
||||
},
|
||||
"Wabbajack.Networking.Discord/0.3.15": {
|
||||
"Wabbajack.Networking.Discord/0.3.16": {
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.1",
|
||||
"Microsoft.Extensions.Logging.Abstractions": "9.0.1",
|
||||
"Wabbajack.Networking.Http.Interfaces": "0.3.15"
|
||||
"Wabbajack.Networking.Http.Interfaces": "0.3.16"
|
||||
},
|
||||
"runtime": {
|
||||
"Wabbajack.Networking.Discord.dll": {}
|
||||
}
|
||||
},
|
||||
"Wabbajack.Networking.GitHub/0.3.15": {
|
||||
"Wabbajack.Networking.GitHub/0.3.16": {
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.DependencyInjection": "9.0.1",
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.1",
|
||||
"Microsoft.Extensions.Logging.Abstractions": "9.0.1",
|
||||
"Octokit": "14.0.0",
|
||||
"Wabbajack.DTOs": "0.3.15",
|
||||
"Wabbajack.Networking.Http.Interfaces": "0.3.15"
|
||||
"Wabbajack.DTOs": "0.3.16",
|
||||
"Wabbajack.Networking.Http.Interfaces": "0.3.16"
|
||||
},
|
||||
"runtime": {
|
||||
"Wabbajack.Networking.GitHub.dll": {}
|
||||
}
|
||||
},
|
||||
"Wabbajack.Networking.Http/0.3.15": {
|
||||
"Wabbajack.Networking.Http/0.3.16": {
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.DependencyInjection": "9.0.1",
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.1",
|
||||
"Microsoft.Extensions.Http": "9.0.1",
|
||||
"Microsoft.Extensions.Logging": "9.0.1",
|
||||
"Wabbajack.Configuration": "0.3.15",
|
||||
"Wabbajack.Downloaders.Interfaces": "0.3.15",
|
||||
"Wabbajack.Hashing.xxHash64": "0.3.15",
|
||||
"Wabbajack.Networking.Http.Interfaces": "0.3.15",
|
||||
"Wabbajack.Paths": "0.3.15",
|
||||
"Wabbajack.Paths.IO": "0.3.15"
|
||||
"Wabbajack.Configuration": "0.3.16",
|
||||
"Wabbajack.Downloaders.Interfaces": "0.3.16",
|
||||
"Wabbajack.Hashing.xxHash64": "0.3.16",
|
||||
"Wabbajack.Networking.Http.Interfaces": "0.3.16",
|
||||
"Wabbajack.Paths": "0.3.16",
|
||||
"Wabbajack.Paths.IO": "0.3.16"
|
||||
},
|
||||
"runtime": {
|
||||
"Wabbajack.Networking.Http.dll": {}
|
||||
}
|
||||
},
|
||||
"Wabbajack.Networking.Http.Interfaces/0.3.15": {
|
||||
"Wabbajack.Networking.Http.Interfaces/0.3.16": {
|
||||
"dependencies": {
|
||||
"Wabbajack.Hashing.xxHash64": "0.3.15"
|
||||
"Wabbajack.Hashing.xxHash64": "0.3.16"
|
||||
},
|
||||
"runtime": {
|
||||
"Wabbajack.Networking.Http.Interfaces.dll": {}
|
||||
}
|
||||
},
|
||||
"Wabbajack.Networking.NexusApi/0.3.15": {
|
||||
"Wabbajack.Networking.NexusApi/0.3.16": {
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.DependencyInjection": "9.0.1",
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.1",
|
||||
"Microsoft.Extensions.Logging.Abstractions": "9.0.1",
|
||||
"Wabbajack.DTOs": "0.3.15",
|
||||
"Wabbajack.Networking.Http": "0.3.15",
|
||||
"Wabbajack.Networking.Http.Interfaces": "0.3.15",
|
||||
"Wabbajack.Networking.WabbajackClientApi": "0.3.15"
|
||||
"Wabbajack.DTOs": "0.3.16",
|
||||
"Wabbajack.Networking.Http": "0.3.16",
|
||||
"Wabbajack.Networking.Http.Interfaces": "0.3.16",
|
||||
"Wabbajack.Networking.WabbajackClientApi": "0.3.16"
|
||||
},
|
||||
"runtime": {
|
||||
"Wabbajack.Networking.NexusApi.dll": {}
|
||||
}
|
||||
},
|
||||
"Wabbajack.Networking.WabbajackClientApi/0.3.15": {
|
||||
"Wabbajack.Networking.WabbajackClientApi/0.3.16": {
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.DependencyInjection": "9.0.1",
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.1",
|
||||
"Microsoft.Extensions.Logging.Abstractions": "9.0.1",
|
||||
"Octokit": "14.0.0",
|
||||
"Wabbajack.Common": "0.3.15",
|
||||
"Wabbajack.DTOs": "0.3.15",
|
||||
"Wabbajack.Paths.IO": "0.3.15",
|
||||
"Wabbajack.VFS.Interfaces": "0.3.15",
|
||||
"Wabbajack.Common": "0.3.16",
|
||||
"Wabbajack.DTOs": "0.3.16",
|
||||
"Wabbajack.Paths.IO": "0.3.16",
|
||||
"Wabbajack.VFS.Interfaces": "0.3.16",
|
||||
"YamlDotNet": "16.3.0"
|
||||
},
|
||||
"runtime": {
|
||||
"Wabbajack.Networking.WabbajackClientApi.dll": {}
|
||||
}
|
||||
},
|
||||
"Wabbajack.Paths/0.3.15": {
|
||||
"Wabbajack.Paths/0.3.16": {
|
||||
"runtime": {
|
||||
"Wabbajack.Paths.dll": {}
|
||||
}
|
||||
},
|
||||
"Wabbajack.Paths.IO/0.3.15": {
|
||||
"Wabbajack.Paths.IO/0.3.16": {
|
||||
"dependencies": {
|
||||
"Wabbajack.Paths": "0.3.15",
|
||||
"Wabbajack.Paths": "0.3.16",
|
||||
"shortid": "4.0.0"
|
||||
},
|
||||
"runtime": {
|
||||
"Wabbajack.Paths.IO.dll": {}
|
||||
}
|
||||
},
|
||||
"Wabbajack.RateLimiter/0.3.15": {
|
||||
"Wabbajack.RateLimiter/0.3.16": {
|
||||
"runtime": {
|
||||
"Wabbajack.RateLimiter.dll": {}
|
||||
}
|
||||
},
|
||||
"Wabbajack.Server.Lib/0.3.15": {
|
||||
"Wabbajack.Server.Lib/0.3.16": {
|
||||
"dependencies": {
|
||||
"FluentFTP": "52.0.0",
|
||||
"Microsoft.Extensions.DependencyInjection": "9.0.1",
|
||||
@@ -2264,58 +2264,58 @@
|
||||
"Nettle": "3.0.0",
|
||||
"Newtonsoft.Json": "13.0.3",
|
||||
"SixLabors.ImageSharp": "3.1.6",
|
||||
"Wabbajack.Common": "0.3.15",
|
||||
"Wabbajack.Networking.Http.Interfaces": "0.3.15",
|
||||
"Wabbajack.Services.OSIntegrated": "0.3.15"
|
||||
"Wabbajack.Common": "0.3.16",
|
||||
"Wabbajack.Networking.Http.Interfaces": "0.3.16",
|
||||
"Wabbajack.Services.OSIntegrated": "0.3.16"
|
||||
},
|
||||
"runtime": {
|
||||
"Wabbajack.Server.Lib.dll": {}
|
||||
}
|
||||
},
|
||||
"Wabbajack.Services.OSIntegrated/0.3.15": {
|
||||
"Wabbajack.Services.OSIntegrated/0.3.16": {
|
||||
"dependencies": {
|
||||
"DeviceId": "6.8.0",
|
||||
"Microsoft.Extensions.DependencyInjection": "9.0.1",
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.1",
|
||||
"Newtonsoft.Json": "13.0.3",
|
||||
"SixLabors.ImageSharp": "3.1.6",
|
||||
"Wabbajack.Compiler": "0.3.15",
|
||||
"Wabbajack.Downloaders.Dispatcher": "0.3.15",
|
||||
"Wabbajack.Installer": "0.3.15",
|
||||
"Wabbajack.Networking.BethesdaNet": "0.3.15",
|
||||
"Wabbajack.Networking.Discord": "0.3.15",
|
||||
"Wabbajack.VFS": "0.3.15"
|
||||
"Wabbajack.Compiler": "0.3.16",
|
||||
"Wabbajack.Downloaders.Dispatcher": "0.3.16",
|
||||
"Wabbajack.Installer": "0.3.16",
|
||||
"Wabbajack.Networking.BethesdaNet": "0.3.16",
|
||||
"Wabbajack.Networking.Discord": "0.3.16",
|
||||
"Wabbajack.VFS": "0.3.16"
|
||||
},
|
||||
"runtime": {
|
||||
"Wabbajack.Services.OSIntegrated.dll": {}
|
||||
}
|
||||
},
|
||||
"Wabbajack.VFS/0.3.15": {
|
||||
"Wabbajack.VFS/0.3.16": {
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.DependencyInjection": "9.0.1",
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.1",
|
||||
"Microsoft.Extensions.Logging.Abstractions": "9.0.1",
|
||||
"SixLabors.ImageSharp": "3.1.6",
|
||||
"System.Data.SQLite.Core": "1.0.119",
|
||||
"Wabbajack.Common": "0.3.15",
|
||||
"Wabbajack.FileExtractor": "0.3.15",
|
||||
"Wabbajack.Hashing.PHash": "0.3.15",
|
||||
"Wabbajack.Hashing.xxHash64": "0.3.15",
|
||||
"Wabbajack.Paths": "0.3.15",
|
||||
"Wabbajack.Paths.IO": "0.3.15",
|
||||
"Wabbajack.VFS.Interfaces": "0.3.15"
|
||||
"Wabbajack.Common": "0.3.16",
|
||||
"Wabbajack.FileExtractor": "0.3.16",
|
||||
"Wabbajack.Hashing.PHash": "0.3.16",
|
||||
"Wabbajack.Hashing.xxHash64": "0.3.16",
|
||||
"Wabbajack.Paths": "0.3.16",
|
||||
"Wabbajack.Paths.IO": "0.3.16",
|
||||
"Wabbajack.VFS.Interfaces": "0.3.16"
|
||||
},
|
||||
"runtime": {
|
||||
"Wabbajack.VFS.dll": {}
|
||||
}
|
||||
},
|
||||
"Wabbajack.VFS.Interfaces/0.3.15": {
|
||||
"Wabbajack.VFS.Interfaces/0.3.16": {
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.DependencyInjection": "9.0.1",
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.1",
|
||||
"Wabbajack.DTOs": "0.3.15",
|
||||
"Wabbajack.Hashing.xxHash64": "0.3.15",
|
||||
"Wabbajack.Paths": "0.3.15"
|
||||
"Wabbajack.DTOs": "0.3.16",
|
||||
"Wabbajack.Hashing.xxHash64": "0.3.16",
|
||||
"Wabbajack.Paths": "0.3.16"
|
||||
},
|
||||
"runtime": {
|
||||
"Wabbajack.VFS.Interfaces.dll": {}
|
||||
@@ -2332,7 +2332,7 @@
|
||||
}
|
||||
},
|
||||
"libraries": {
|
||||
"jackify-engine/0.3.15": {
|
||||
"jackify-engine/0.3.16": {
|
||||
"type": "project",
|
||||
"serviceable": false,
|
||||
"sha512": ""
|
||||
@@ -3021,202 +3021,202 @@
|
||||
"path": "yamldotnet/16.3.0",
|
||||
"hashPath": "yamldotnet.16.3.0.nupkg.sha512"
|
||||
},
|
||||
"Wabbajack.CLI.Builder/0.3.15": {
|
||||
"Wabbajack.CLI.Builder/0.3.16": {
|
||||
"type": "project",
|
||||
"serviceable": false,
|
||||
"sha512": ""
|
||||
},
|
||||
"Wabbajack.Common/0.3.15": {
|
||||
"Wabbajack.Common/0.3.16": {
|
||||
"type": "project",
|
||||
"serviceable": false,
|
||||
"sha512": ""
|
||||
},
|
||||
"Wabbajack.Compiler/0.3.15": {
|
||||
"Wabbajack.Compiler/0.3.16": {
|
||||
"type": "project",
|
||||
"serviceable": false,
|
||||
"sha512": ""
|
||||
},
|
||||
"Wabbajack.Compression.BSA/0.3.15": {
|
||||
"Wabbajack.Compression.BSA/0.3.16": {
|
||||
"type": "project",
|
||||
"serviceable": false,
|
||||
"sha512": ""
|
||||
},
|
||||
"Wabbajack.Compression.Zip/0.3.15": {
|
||||
"Wabbajack.Compression.Zip/0.3.16": {
|
||||
"type": "project",
|
||||
"serviceable": false,
|
||||
"sha512": ""
|
||||
},
|
||||
"Wabbajack.Configuration/0.3.15": {
|
||||
"Wabbajack.Configuration/0.3.16": {
|
||||
"type": "project",
|
||||
"serviceable": false,
|
||||
"sha512": ""
|
||||
},
|
||||
"Wabbajack.Downloaders.Bethesda/0.3.15": {
|
||||
"Wabbajack.Downloaders.Bethesda/0.3.16": {
|
||||
"type": "project",
|
||||
"serviceable": false,
|
||||
"sha512": ""
|
||||
},
|
||||
"Wabbajack.Downloaders.Dispatcher/0.3.15": {
|
||||
"Wabbajack.Downloaders.Dispatcher/0.3.16": {
|
||||
"type": "project",
|
||||
"serviceable": false,
|
||||
"sha512": ""
|
||||
},
|
||||
"Wabbajack.Downloaders.GameFile/0.3.15": {
|
||||
"Wabbajack.Downloaders.GameFile/0.3.16": {
|
||||
"type": "project",
|
||||
"serviceable": false,
|
||||
"sha512": ""
|
||||
},
|
||||
"Wabbajack.Downloaders.GoogleDrive/0.3.15": {
|
||||
"Wabbajack.Downloaders.GoogleDrive/0.3.16": {
|
||||
"type": "project",
|
||||
"serviceable": false,
|
||||
"sha512": ""
|
||||
},
|
||||
"Wabbajack.Downloaders.Http/0.3.15": {
|
||||
"Wabbajack.Downloaders.Http/0.3.16": {
|
||||
"type": "project",
|
||||
"serviceable": false,
|
||||
"sha512": ""
|
||||
},
|
||||
"Wabbajack.Downloaders.Interfaces/0.3.15": {
|
||||
"Wabbajack.Downloaders.Interfaces/0.3.16": {
|
||||
"type": "project",
|
||||
"serviceable": false,
|
||||
"sha512": ""
|
||||
},
|
||||
"Wabbajack.Downloaders.IPS4OAuth2Downloader/0.3.15": {
|
||||
"Wabbajack.Downloaders.IPS4OAuth2Downloader/0.3.16": {
|
||||
"type": "project",
|
||||
"serviceable": false,
|
||||
"sha512": ""
|
||||
},
|
||||
"Wabbajack.Downloaders.Manual/0.3.15": {
|
||||
"Wabbajack.Downloaders.Manual/0.3.16": {
|
||||
"type": "project",
|
||||
"serviceable": false,
|
||||
"sha512": ""
|
||||
},
|
||||
"Wabbajack.Downloaders.MediaFire/0.3.15": {
|
||||
"Wabbajack.Downloaders.MediaFire/0.3.16": {
|
||||
"type": "project",
|
||||
"serviceable": false,
|
||||
"sha512": ""
|
||||
},
|
||||
"Wabbajack.Downloaders.Mega/0.3.15": {
|
||||
"Wabbajack.Downloaders.Mega/0.3.16": {
|
||||
"type": "project",
|
||||
"serviceable": false,
|
||||
"sha512": ""
|
||||
},
|
||||
"Wabbajack.Downloaders.ModDB/0.3.15": {
|
||||
"Wabbajack.Downloaders.ModDB/0.3.16": {
|
||||
"type": "project",
|
||||
"serviceable": false,
|
||||
"sha512": ""
|
||||
},
|
||||
"Wabbajack.Downloaders.Nexus/0.3.15": {
|
||||
"Wabbajack.Downloaders.Nexus/0.3.16": {
|
||||
"type": "project",
|
||||
"serviceable": false,
|
||||
"sha512": ""
|
||||
},
|
||||
"Wabbajack.Downloaders.VerificationCache/0.3.15": {
|
||||
"Wabbajack.Downloaders.VerificationCache/0.3.16": {
|
||||
"type": "project",
|
||||
"serviceable": false,
|
||||
"sha512": ""
|
||||
},
|
||||
"Wabbajack.Downloaders.WabbajackCDN/0.3.15": {
|
||||
"Wabbajack.Downloaders.WabbajackCDN/0.3.16": {
|
||||
"type": "project",
|
||||
"serviceable": false,
|
||||
"sha512": ""
|
||||
},
|
||||
"Wabbajack.DTOs/0.3.15": {
|
||||
"Wabbajack.DTOs/0.3.16": {
|
||||
"type": "project",
|
||||
"serviceable": false,
|
||||
"sha512": ""
|
||||
},
|
||||
"Wabbajack.FileExtractor/0.3.15": {
|
||||
"Wabbajack.FileExtractor/0.3.16": {
|
||||
"type": "project",
|
||||
"serviceable": false,
|
||||
"sha512": ""
|
||||
},
|
||||
"Wabbajack.Hashing.PHash/0.3.15": {
|
||||
"Wabbajack.Hashing.PHash/0.3.16": {
|
||||
"type": "project",
|
||||
"serviceable": false,
|
||||
"sha512": ""
|
||||
},
|
||||
"Wabbajack.Hashing.xxHash64/0.3.15": {
|
||||
"Wabbajack.Hashing.xxHash64/0.3.16": {
|
||||
"type": "project",
|
||||
"serviceable": false,
|
||||
"sha512": ""
|
||||
},
|
||||
"Wabbajack.Installer/0.3.15": {
|
||||
"Wabbajack.Installer/0.3.16": {
|
||||
"type": "project",
|
||||
"serviceable": false,
|
||||
"sha512": ""
|
||||
},
|
||||
"Wabbajack.IO.Async/0.3.15": {
|
||||
"Wabbajack.IO.Async/0.3.16": {
|
||||
"type": "project",
|
||||
"serviceable": false,
|
||||
"sha512": ""
|
||||
},
|
||||
"Wabbajack.Networking.BethesdaNet/0.3.15": {
|
||||
"Wabbajack.Networking.BethesdaNet/0.3.16": {
|
||||
"type": "project",
|
||||
"serviceable": false,
|
||||
"sha512": ""
|
||||
},
|
||||
"Wabbajack.Networking.Discord/0.3.15": {
|
||||
"Wabbajack.Networking.Discord/0.3.16": {
|
||||
"type": "project",
|
||||
"serviceable": false,
|
||||
"sha512": ""
|
||||
},
|
||||
"Wabbajack.Networking.GitHub/0.3.15": {
|
||||
"Wabbajack.Networking.GitHub/0.3.16": {
|
||||
"type": "project",
|
||||
"serviceable": false,
|
||||
"sha512": ""
|
||||
},
|
||||
"Wabbajack.Networking.Http/0.3.15": {
|
||||
"Wabbajack.Networking.Http/0.3.16": {
|
||||
"type": "project",
|
||||
"serviceable": false,
|
||||
"sha512": ""
|
||||
},
|
||||
"Wabbajack.Networking.Http.Interfaces/0.3.15": {
|
||||
"Wabbajack.Networking.Http.Interfaces/0.3.16": {
|
||||
"type": "project",
|
||||
"serviceable": false,
|
||||
"sha512": ""
|
||||
},
|
||||
"Wabbajack.Networking.NexusApi/0.3.15": {
|
||||
"Wabbajack.Networking.NexusApi/0.3.16": {
|
||||
"type": "project",
|
||||
"serviceable": false,
|
||||
"sha512": ""
|
||||
},
|
||||
"Wabbajack.Networking.WabbajackClientApi/0.3.15": {
|
||||
"Wabbajack.Networking.WabbajackClientApi/0.3.16": {
|
||||
"type": "project",
|
||||
"serviceable": false,
|
||||
"sha512": ""
|
||||
},
|
||||
"Wabbajack.Paths/0.3.15": {
|
||||
"Wabbajack.Paths/0.3.16": {
|
||||
"type": "project",
|
||||
"serviceable": false,
|
||||
"sha512": ""
|
||||
},
|
||||
"Wabbajack.Paths.IO/0.3.15": {
|
||||
"Wabbajack.Paths.IO/0.3.16": {
|
||||
"type": "project",
|
||||
"serviceable": false,
|
||||
"sha512": ""
|
||||
},
|
||||
"Wabbajack.RateLimiter/0.3.15": {
|
||||
"Wabbajack.RateLimiter/0.3.16": {
|
||||
"type": "project",
|
||||
"serviceable": false,
|
||||
"sha512": ""
|
||||
},
|
||||
"Wabbajack.Server.Lib/0.3.15": {
|
||||
"Wabbajack.Server.Lib/0.3.16": {
|
||||
"type": "project",
|
||||
"serviceable": false,
|
||||
"sha512": ""
|
||||
},
|
||||
"Wabbajack.Services.OSIntegrated/0.3.15": {
|
||||
"Wabbajack.Services.OSIntegrated/0.3.16": {
|
||||
"type": "project",
|
||||
"serviceable": false,
|
||||
"sha512": ""
|
||||
},
|
||||
"Wabbajack.VFS/0.3.15": {
|
||||
"Wabbajack.VFS/0.3.16": {
|
||||
"type": "project",
|
||||
"serviceable": false,
|
||||
"sha512": ""
|
||||
},
|
||||
"Wabbajack.VFS.Interfaces/0.3.15": {
|
||||
"Wabbajack.VFS.Interfaces/0.3.16": {
|
||||
"type": "project",
|
||||
"serviceable": false,
|
||||
"sha512": ""
|
||||
|
||||
Binary file not shown.
@@ -102,7 +102,7 @@ sys.path.insert(0, str(src_dir))
|
||||
|
||||
from PySide6.QtWidgets import (
|
||||
QApplication, QMainWindow, QWidget, QLabel, QVBoxLayout, QPushButton,
|
||||
QStackedWidget, QHBoxLayout, QDialog, QFormLayout, QLineEdit, QCheckBox, QSpinBox, QMessageBox, QGroupBox, QGridLayout, QFileDialog, QToolButton, QStyle, QComboBox
|
||||
QStackedWidget, QHBoxLayout, QDialog, QFormLayout, QLineEdit, QCheckBox, QSpinBox, QMessageBox, QGroupBox, QGridLayout, QFileDialog, QToolButton, QStyle, QComboBox, QTabWidget
|
||||
)
|
||||
from PySide6.QtCore import Qt, QEvent
|
||||
from PySide6.QtGui import QIcon
|
||||
@@ -167,221 +167,26 @@ class SettingsDialog(QDialog):
|
||||
self._original_debug_mode = self.config_handler.get('debug_mode', False)
|
||||
self.setWindowTitle("Settings")
|
||||
self.setModal(True)
|
||||
self.setMinimumWidth(750)
|
||||
self.setMinimumWidth(650) # Reduced width for Steam Deck compatibility
|
||||
self.setMaximumWidth(800) # Maximum width to prevent excessive stretching
|
||||
self.setStyleSheet("QDialog { background-color: #232323; color: #eee; } QPushButton:hover { background-color: #333; }")
|
||||
|
||||
main_layout = QVBoxLayout()
|
||||
self.setLayout(main_layout)
|
||||
|
||||
# --- Resource Limits Section ---
|
||||
resource_group = QGroupBox("Resource Limits")
|
||||
resource_group.setStyleSheet("QGroupBox { border: 1px solid #555; border-radius: 6px; margin-top: 8px; padding: 8px; background: #23282d; } QGroupBox:title { subcontrol-origin: margin; left: 10px; padding: 0 3px 0 3px; font-weight: bold; color: #fff; }")
|
||||
resource_layout = QGridLayout()
|
||||
resource_group.setLayout(resource_layout)
|
||||
resource_layout.setVerticalSpacing(4)
|
||||
resource_layout.setHorizontalSpacing(8)
|
||||
resource_layout.addWidget(self._bold_label("Resource"), 0, 0, 1, 1, Qt.AlignLeft)
|
||||
resource_layout.addWidget(self._bold_label("Max Tasks"), 0, 1, 1, 1, Qt.AlignLeft)
|
||||
self.resource_settings_path = os.path.expanduser("~/.config/jackify/resource_settings.json")
|
||||
self.resource_settings = self._load_json(self.resource_settings_path)
|
||||
self.resource_edits = {}
|
||||
resource_row_index = 0
|
||||
for resource_row_index, (k, v) in enumerate(self.resource_settings.items(), start=1):
|
||||
try:
|
||||
# Create resource label with optional inline checkbox for File Extractor
|
||||
if k == "File Extractor":
|
||||
# Create horizontal layout for File Extractor with inline checkbox
|
||||
resource_row = QHBoxLayout()
|
||||
resource_label = QLabel(f"{k}:", parent=self)
|
||||
resource_row.addWidget(resource_label)
|
||||
resource_row.addSpacing(10) # Add some spacing
|
||||
# Create tab widget
|
||||
self.tab_widget = QTabWidget()
|
||||
self.tab_widget.setStyleSheet("""
|
||||
QTabWidget::pane { border: 1px solid #555; background: #232323; }
|
||||
QTabBar::tab { background: #333; color: #eee; padding: 8px 16px; margin: 2px; }
|
||||
QTabBar::tab:selected { background: #555; }
|
||||
QTabBar::tab:hover { background: #444; }
|
||||
""")
|
||||
main_layout.addWidget(self.tab_widget)
|
||||
|
||||
multithreading_checkbox = QCheckBox("Multithreading (Experimental)")
|
||||
multithreading_checkbox.setChecked(v.get('_7zzMultiThread', 'off') == 'on')
|
||||
multithreading_checkbox.setToolTip("Enables multithreaded file extraction using 7-Zip. May improve extraction speed on multi-core systems but could be less stable.")
|
||||
multithreading_checkbox.setStyleSheet("color: #fff;")
|
||||
resource_row.addWidget(multithreading_checkbox)
|
||||
resource_row.addStretch() # Push checkbox to the left
|
||||
|
||||
# Add the horizontal layout to the grid
|
||||
resource_layout.addLayout(resource_row, resource_row_index, 0)
|
||||
else:
|
||||
resource_layout.addWidget(QLabel(f"{k}:", parent=self), resource_row_index, 0, 1, 1, Qt.AlignLeft)
|
||||
|
||||
max_tasks_spin = QSpinBox()
|
||||
max_tasks_spin.setMinimum(1)
|
||||
max_tasks_spin.setMaximum(128)
|
||||
max_tasks_spin.setValue(v.get('MaxTasks', 16))
|
||||
max_tasks_spin.setToolTip("Maximum number of concurrent tasks for this resource.")
|
||||
max_tasks_spin.setFixedWidth(160)
|
||||
resource_layout.addWidget(max_tasks_spin, resource_row_index, 1)
|
||||
|
||||
# Store the widgets (checkbox for File Extractor, None for others)
|
||||
if k == "File Extractor":
|
||||
self.resource_edits[k] = (multithreading_checkbox, max_tasks_spin)
|
||||
else:
|
||||
self.resource_edits[k] = (None, max_tasks_spin)
|
||||
except Exception as e:
|
||||
print(f"[ERROR] Failed to create widgets for resource '{k}': {e}")
|
||||
continue
|
||||
|
||||
# If no resources exist, show helpful message
|
||||
if not self.resource_edits:
|
||||
info_label = QLabel("Resource Limit settings will be generated once a modlist install action is performed")
|
||||
info_label.setStyleSheet("color: #aaa; font-style: italic; padding: 20px; font-size: 11pt;")
|
||||
info_label.setWordWrap(True)
|
||||
info_label.setAlignment(Qt.AlignCenter)
|
||||
info_label.setMinimumHeight(60) # Ensure enough height to prevent cutoff
|
||||
resource_layout.addWidget(info_label, 1, 0, 3, 2) # Span more rows for better space
|
||||
|
||||
# Bandwidth limiter row (only show if Downloads resource exists)
|
||||
if "Downloads" in self.resource_settings:
|
||||
downloads_throughput = self.resource_settings["Downloads"].get("MaxThroughput", 0)
|
||||
|
||||
self.bandwidth_spin = QSpinBox()
|
||||
self.bandwidth_spin.setMinimum(0)
|
||||
self.bandwidth_spin.setMaximum(1000000)
|
||||
self.bandwidth_spin.setValue(downloads_throughput)
|
||||
self.bandwidth_spin.setSuffix(" KB/s")
|
||||
self.bandwidth_spin.setFixedWidth(160)
|
||||
self.bandwidth_spin.setToolTip("Set the maximum download speed for modlist downloads. 0 = unlimited.")
|
||||
bandwidth_note = QLabel("(0 = unlimited)")
|
||||
bandwidth_note.setStyleSheet("color: #aaa; font-size: 10pt;")
|
||||
# Create horizontal layout for bandwidth row
|
||||
bandwidth_row = QHBoxLayout()
|
||||
bandwidth_row.addWidget(self.bandwidth_spin)
|
||||
bandwidth_row.addWidget(bandwidth_note)
|
||||
bandwidth_row.addStretch() # Push to the left
|
||||
|
||||
resource_layout.addWidget(QLabel("Bandwidth Limit:", parent=self), resource_row_index+1, 0, 1, 1, Qt.AlignLeft)
|
||||
resource_layout.addLayout(bandwidth_row, resource_row_index+1, 1)
|
||||
else:
|
||||
self.bandwidth_spin = None # No bandwidth UI if Downloads resource doesn't exist
|
||||
main_layout.addWidget(resource_group)
|
||||
main_layout.addSpacing(12)
|
||||
|
||||
# --- Debug & Diagnostics Section ---
|
||||
debug_group = QGroupBox("Debug & Diagnostics")
|
||||
debug_group.setStyleSheet("QGroupBox { border: 1px solid #555; border-radius: 6px; margin-top: 8px; padding: 8px; background: #23282d; } QGroupBox:title { subcontrol-origin: margin; left: 10px; padding: 0 3px 0 3px; font-weight: bold; color: #fff; }")
|
||||
debug_layout = QVBoxLayout()
|
||||
debug_group.setLayout(debug_layout)
|
||||
self.debug_checkbox = QCheckBox("Enable debug mode (requires restart)")
|
||||
# Load debug_mode from config
|
||||
self.debug_checkbox.setChecked(self.config_handler.get('debug_mode', False))
|
||||
self.debug_checkbox.setToolTip("Enable verbose debug logging. Requires Jackify restart to take effect.")
|
||||
self.debug_checkbox.setStyleSheet("color: #fff;")
|
||||
debug_layout.addWidget(self.debug_checkbox)
|
||||
main_layout.addWidget(debug_group)
|
||||
main_layout.addSpacing(12)
|
||||
|
||||
# --- Nexus API Key Section ---
|
||||
api_group = QGroupBox("Nexus API Key")
|
||||
api_group.setStyleSheet("QGroupBox { border: 1px solid #555; border-radius: 6px; margin-top: 8px; padding: 8px; background: #23282d; } QGroupBox:title { subcontrol-origin: margin; left: 10px; padding: 0 3px 0 3px; font-weight: bold; color: #fff; }")
|
||||
api_layout = QHBoxLayout()
|
||||
api_group.setLayout(api_layout)
|
||||
self.api_key_edit = QLineEdit()
|
||||
self.api_key_edit.setEchoMode(QLineEdit.Password)
|
||||
api_key = self.config_handler.get_api_key()
|
||||
if api_key:
|
||||
self.api_key_edit.setText(api_key)
|
||||
else:
|
||||
self.api_key_edit.setText("")
|
||||
self.api_key_edit.setToolTip("Your Nexus API Key (obfuscated by default, click Show to reveal)")
|
||||
# Connect for immediate saving when text changes
|
||||
self.api_key_edit.textChanged.connect(self._on_api_key_changed)
|
||||
self.api_show_btn = QToolButton()
|
||||
self.api_show_btn.setCheckable(True)
|
||||
self.api_show_btn.setIcon(QIcon.fromTheme("view-visible"))
|
||||
self.api_show_btn.setToolTip("Show or hide your API key")
|
||||
self.api_show_btn.toggled.connect(self._toggle_api_key_visibility)
|
||||
self.api_show_btn.setStyleSheet("")
|
||||
clear_api_btn = QPushButton("Clear API Key")
|
||||
clear_api_btn.clicked.connect(self._clear_api_key)
|
||||
api_layout.addWidget(QLabel("Nexus API Key:"))
|
||||
api_layout.addWidget(self.api_key_edit)
|
||||
api_layout.addWidget(self.api_show_btn)
|
||||
api_layout.addWidget(clear_api_btn)
|
||||
main_layout.addWidget(api_group)
|
||||
main_layout.addSpacing(12)
|
||||
|
||||
# --- Proton Version Section ---
|
||||
proton_group = QGroupBox("Proton Version")
|
||||
proton_group.setStyleSheet("QGroupBox { border: 1px solid #555; border-radius: 6px; margin-top: 8px; padding: 8px; background: #23282d; } QGroupBox:title { subcontrol-origin: margin; left: 10px; padding: 0 3px 0 3px; font-weight: bold; color: #fff; }")
|
||||
proton_layout = QHBoxLayout()
|
||||
proton_group.setLayout(proton_layout)
|
||||
|
||||
self.proton_dropdown = QComboBox()
|
||||
self.proton_dropdown.setToolTip("Select Proton version for shortcut creation and texture processing")
|
||||
self.proton_dropdown.setMinimumWidth(200)
|
||||
|
||||
# Populate Proton dropdown
|
||||
self._populate_proton_dropdown()
|
||||
|
||||
# Refresh button for Proton detection
|
||||
refresh_btn = QPushButton("↻")
|
||||
refresh_btn.setFixedSize(30, 30)
|
||||
refresh_btn.setToolTip("Refresh Proton version list")
|
||||
refresh_btn.clicked.connect(self._refresh_proton_dropdown)
|
||||
|
||||
proton_layout.addWidget(QLabel("Proton Version:"))
|
||||
proton_layout.addWidget(self.proton_dropdown)
|
||||
proton_layout.addWidget(refresh_btn)
|
||||
proton_layout.addStretch()
|
||||
|
||||
main_layout.addWidget(proton_group)
|
||||
main_layout.addSpacing(12)
|
||||
|
||||
# --- Directories & Paths Section ---
|
||||
dir_group = QGroupBox("Directories & Paths")
|
||||
dir_group.setStyleSheet("QGroupBox { border: 1px solid #555; border-radius: 6px; margin-top: 8px; padding: 8px; background: #23282d; } QGroupBox:title { subcontrol-origin: margin; left: 10px; padding: 0 3px 0 3px; font-weight: bold; color: #fff; }")
|
||||
dir_layout = QFormLayout()
|
||||
dir_group.setLayout(dir_layout)
|
||||
self.install_dir_edit = QLineEdit(self.config_handler.get("modlist_install_base_dir", ""))
|
||||
self.install_dir_edit.setToolTip("Default directory for modlist installations.")
|
||||
self.install_dir_btn = QPushButton()
|
||||
self.install_dir_btn.setIcon(QIcon.fromTheme("folder-open"))
|
||||
self.install_dir_btn.setToolTip("Browse for directory")
|
||||
self.install_dir_btn.setFixedWidth(32)
|
||||
self.install_dir_btn.clicked.connect(lambda: self._pick_directory(self.install_dir_edit))
|
||||
install_dir_row = QHBoxLayout()
|
||||
install_dir_row.addWidget(self.install_dir_edit)
|
||||
install_dir_row.addWidget(self.install_dir_btn)
|
||||
dir_layout.addRow(QLabel("Install Base Dir:"), install_dir_row)
|
||||
self.download_dir_edit = QLineEdit(self.config_handler.get("modlist_downloads_base_dir", ""))
|
||||
self.download_dir_edit.setToolTip("Default directory for modlist downloads.")
|
||||
self.download_dir_btn = QPushButton()
|
||||
self.download_dir_btn.setIcon(QIcon.fromTheme("folder-open"))
|
||||
self.download_dir_btn.setToolTip("Browse for directory")
|
||||
self.download_dir_btn.setFixedWidth(32)
|
||||
self.download_dir_btn.clicked.connect(lambda: self._pick_directory(self.download_dir_edit))
|
||||
download_dir_row = QHBoxLayout()
|
||||
download_dir_row.addWidget(self.download_dir_edit)
|
||||
download_dir_row.addWidget(self.download_dir_btn)
|
||||
dir_layout.addRow(QLabel("Downloads Base Dir:"), download_dir_row)
|
||||
|
||||
# Jackify Data Directory
|
||||
from jackify.shared.paths import get_jackify_data_dir
|
||||
current_jackify_dir = str(get_jackify_data_dir())
|
||||
self.jackify_data_dir_edit = QLineEdit(current_jackify_dir)
|
||||
self.jackify_data_dir_edit.setToolTip("Directory for Jackify data (logs, downloads, temp files). Default: ~/Jackify")
|
||||
self.jackify_data_dir_btn = QPushButton()
|
||||
self.jackify_data_dir_btn.setIcon(QIcon.fromTheme("folder-open"))
|
||||
self.jackify_data_dir_btn.setToolTip("Browse for directory")
|
||||
self.jackify_data_dir_btn.setFixedWidth(32)
|
||||
self.jackify_data_dir_btn.clicked.connect(lambda: self._pick_directory(self.jackify_data_dir_edit))
|
||||
jackify_data_dir_row = QHBoxLayout()
|
||||
jackify_data_dir_row.addWidget(self.jackify_data_dir_edit)
|
||||
jackify_data_dir_row.addWidget(self.jackify_data_dir_btn)
|
||||
|
||||
# Reset to default button
|
||||
reset_jackify_dir_btn = QPushButton("Reset")
|
||||
reset_jackify_dir_btn.setToolTip("Reset to default (~/ Jackify)")
|
||||
reset_jackify_dir_btn.setFixedWidth(50)
|
||||
reset_jackify_dir_btn.clicked.connect(lambda: self.jackify_data_dir_edit.setText(str(Path.home() / "Jackify")))
|
||||
jackify_data_dir_row.addWidget(reset_jackify_dir_btn)
|
||||
|
||||
dir_layout.addRow(QLabel("Jackify Data Dir:"), jackify_data_dir_row)
|
||||
main_layout.addWidget(dir_group)
|
||||
main_layout.addSpacing(12)
|
||||
# Create tabs
|
||||
self._create_general_tab()
|
||||
self._create_advanced_tab()
|
||||
|
||||
# --- Save/Close/Help Buttons ---
|
||||
btn_layout = QHBoxLayout()
|
||||
@@ -396,36 +201,224 @@ class SettingsDialog(QDialog):
|
||||
close_btn.clicked.connect(self.reject)
|
||||
btn_layout.addWidget(save_btn)
|
||||
btn_layout.addWidget(close_btn)
|
||||
|
||||
# Add error label for validation messages
|
||||
self.error_label = QLabel("")
|
||||
self.error_label.setStyleSheet("QLabel { color: #ff6b6b; }")
|
||||
main_layout.addWidget(self.error_label)
|
||||
|
||||
main_layout.addSpacing(10)
|
||||
main_layout.addLayout(btn_layout)
|
||||
|
||||
# Set tab order for accessibility
|
||||
# Get the first resource's widgets if any exist
|
||||
if self.resource_edits:
|
||||
first_resource_key = list(self.resource_edits.keys())[0]
|
||||
first_multithreading, first_max_tasks = self.resource_edits[first_resource_key]
|
||||
# Set tab order starting with the first max tasks spinner
|
||||
self.setTabOrder(first_max_tasks, self.bandwidth_spin)
|
||||
# Continue with bandwidth spinner regardless of resources
|
||||
self.setTabOrder(self.bandwidth_spin, self.debug_checkbox)
|
||||
self.setTabOrder(self.debug_checkbox, self.api_key_edit)
|
||||
self.setTabOrder(self.api_key_edit, self.api_show_btn)
|
||||
self.setTabOrder(self.api_show_btn, clear_api_btn)
|
||||
self.setTabOrder(clear_api_btn, self.install_dir_edit)
|
||||
self.setTabOrder(self.install_dir_edit, self.install_dir_btn)
|
||||
self.setTabOrder(self.install_dir_btn, self.download_dir_edit)
|
||||
self.setTabOrder(self.download_dir_edit, self.download_dir_btn)
|
||||
self.setTabOrder(self.download_dir_btn, save_btn)
|
||||
self.setTabOrder(save_btn, close_btn)
|
||||
|
||||
self.error_label = QLabel("")
|
||||
self.error_label.setStyleSheet("color: #f55; font-weight: bold;")
|
||||
main_layout.insertWidget(0, self.error_label)
|
||||
except Exception as e:
|
||||
print(f"[ERROR] Exception in SettingsDialog __init__: {e}")
|
||||
print(f"[ERROR] Exception in SettingsDialog.__init__: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
raise
|
||||
|
||||
def _create_general_tab(self):
|
||||
"""Create the General settings tab"""
|
||||
general_tab = QWidget()
|
||||
general_layout = QVBoxLayout(general_tab)
|
||||
|
||||
# --- Directory Paths Section (moved to top as most essential) ---
|
||||
dir_group = QGroupBox("Directory Paths")
|
||||
dir_group.setStyleSheet("QGroupBox { border: 1px solid #555; border-radius: 6px; margin-top: 8px; padding: 8px; background: #23282d; } QGroupBox:title { subcontrol-origin: margin; left: 10px; padding: 0 3px 0 3px; font-weight: bold; color: #fff; }")
|
||||
dir_layout = QFormLayout()
|
||||
dir_group.setLayout(dir_layout)
|
||||
self.install_dir_edit = QLineEdit(self.config_handler.get("modlist_install_base_dir", ""))
|
||||
self.install_dir_edit.setToolTip("Default directory for modlist installations.")
|
||||
self.install_dir_btn = QPushButton()
|
||||
self.install_dir_btn.setIcon(QIcon.fromTheme("folder-open"))
|
||||
self.install_dir_btn.setToolTip("Browse for directory")
|
||||
self.install_dir_btn.setFixedWidth(32)
|
||||
self.install_dir_btn.clicked.connect(lambda: self._pick_directory(self.install_dir_edit))
|
||||
install_dir_row = QHBoxLayout()
|
||||
install_dir_row.addWidget(self.install_dir_edit)
|
||||
install_dir_row.addWidget(self.install_dir_btn)
|
||||
dir_layout.addRow(QLabel("Install Base Dir:"), install_dir_row)
|
||||
self.download_dir_edit = QLineEdit(self.config_handler.get("modlist_downloads_base_dir", ""))
|
||||
self.download_dir_edit.setToolTip("Default directory for modlist downloads.")
|
||||
self.download_dir_btn = QPushButton()
|
||||
self.download_dir_btn.setIcon(QIcon.fromTheme("folder-open"))
|
||||
self.download_dir_btn.setToolTip("Browse for directory")
|
||||
self.download_dir_btn.setFixedWidth(32)
|
||||
self.download_dir_btn.clicked.connect(lambda: self._pick_directory(self.download_dir_edit))
|
||||
download_dir_row = QHBoxLayout()
|
||||
download_dir_row.addWidget(self.download_dir_edit)
|
||||
download_dir_row.addWidget(self.download_dir_btn)
|
||||
dir_layout.addRow(QLabel("Downloads Base Dir:"), download_dir_row)
|
||||
|
||||
# Jackify Data Directory
|
||||
from jackify.shared.paths import get_jackify_data_dir
|
||||
current_jackify_dir = str(get_jackify_data_dir())
|
||||
self.jackify_data_dir_edit = QLineEdit(current_jackify_dir)
|
||||
self.jackify_data_dir_edit.setToolTip("Directory for Jackify data (logs, downloads, temp files). Default: ~/Jackify")
|
||||
self.jackify_data_dir_btn = QPushButton()
|
||||
self.jackify_data_dir_btn.setIcon(QIcon.fromTheme("folder-open"))
|
||||
self.jackify_data_dir_btn.setToolTip("Browse for directory")
|
||||
self.jackify_data_dir_btn.setFixedWidth(32)
|
||||
self.jackify_data_dir_btn.clicked.connect(lambda: self._pick_directory(self.jackify_data_dir_edit))
|
||||
jackify_data_dir_row = QHBoxLayout()
|
||||
jackify_data_dir_row.addWidget(self.jackify_data_dir_edit)
|
||||
jackify_data_dir_row.addWidget(self.jackify_data_dir_btn)
|
||||
|
||||
# Reset to default button
|
||||
reset_jackify_dir_btn = QPushButton("Reset")
|
||||
reset_jackify_dir_btn.setToolTip("Reset to default (~/ Jackify)")
|
||||
reset_jackify_dir_btn.setFixedWidth(50)
|
||||
reset_jackify_dir_btn.clicked.connect(lambda: self.jackify_data_dir_edit.setText(str(Path.home() / "Jackify")))
|
||||
jackify_data_dir_row.addWidget(reset_jackify_dir_btn)
|
||||
|
||||
dir_layout.addRow(QLabel("Jackify Data Dir:"), jackify_data_dir_row)
|
||||
general_layout.addWidget(dir_group)
|
||||
general_layout.addSpacing(12)
|
||||
|
||||
# --- Nexus API Key Section ---
|
||||
api_group = QGroupBox("Nexus API Key")
|
||||
api_group.setStyleSheet("QGroupBox { border: 1px solid #555; border-radius: 6px; margin-top: 8px; padding: 8px; background: #23282d; } QGroupBox:title { subcontrol-origin: margin; left: 10px; padding: 0 3px 0 3px; font-weight: bold; color: #fff; }")
|
||||
api_layout = QHBoxLayout()
|
||||
api_group.setLayout(api_layout)
|
||||
self.api_key_edit = QLineEdit()
|
||||
self.api_key_edit.setEchoMode(QLineEdit.Password)
|
||||
api_key = self.config_handler.get_api_key()
|
||||
if api_key:
|
||||
self.api_key_edit.setText(api_key)
|
||||
else:
|
||||
self.api_key_edit.setText("")
|
||||
self.api_key_edit.setToolTip("Your Nexus API Key (obfuscated by default, click Show to reveal)")
|
||||
# Connect for immediate saving when text changes
|
||||
self.api_key_edit.textChanged.connect(self._on_api_key_changed)
|
||||
self.api_show_btn = QToolButton()
|
||||
self.api_show_btn.setCheckable(True)
|
||||
self.api_show_btn.setIcon(QIcon.fromTheme("view-visible"))
|
||||
self.api_show_btn.setToolTip("Show or hide your API key")
|
||||
self.api_show_btn.toggled.connect(self._toggle_api_key_visibility)
|
||||
self.api_show_btn.setStyleSheet("")
|
||||
clear_api_btn = QPushButton("Clear API Key")
|
||||
clear_api_btn.clicked.connect(self._clear_api_key)
|
||||
api_layout.addWidget(QLabel("Nexus API Key:"))
|
||||
api_layout.addWidget(self.api_key_edit)
|
||||
api_layout.addWidget(self.api_show_btn)
|
||||
api_layout.addWidget(clear_api_btn)
|
||||
general_layout.addWidget(api_group)
|
||||
general_layout.addSpacing(12)
|
||||
|
||||
# --- Default Proton Version Section ---
|
||||
proton_group = QGroupBox("Default Proton Version")
|
||||
proton_group.setStyleSheet("QGroupBox { border: 1px solid #555; border-radius: 6px; margin-top: 8px; padding: 8px; background: #23282d; } QGroupBox:title { subcontrol-origin: margin; left: 10px; padding: 0 3px 0 3px; font-weight: bold; color: #fff; }")
|
||||
proton_layout = QHBoxLayout()
|
||||
proton_group.setLayout(proton_layout)
|
||||
|
||||
self.proton_dropdown = QComboBox()
|
||||
self.proton_dropdown.setToolTip("Select default Proton version for shortcut creation and texture processing")
|
||||
self.proton_dropdown.setMinimumWidth(200)
|
||||
|
||||
# Populate Proton dropdown
|
||||
self._populate_proton_dropdown()
|
||||
|
||||
# Refresh button for Proton detection
|
||||
refresh_btn = QPushButton("↻")
|
||||
refresh_btn.setFixedSize(30, 30)
|
||||
refresh_btn.setToolTip("Refresh Proton version list")
|
||||
refresh_btn.clicked.connect(self._refresh_proton_dropdown)
|
||||
|
||||
proton_layout.addWidget(QLabel("Proton Version:"))
|
||||
proton_layout.addWidget(self.proton_dropdown)
|
||||
proton_layout.addWidget(refresh_btn)
|
||||
proton_layout.addStretch()
|
||||
|
||||
general_layout.addWidget(proton_group)
|
||||
general_layout.addSpacing(12)
|
||||
|
||||
# --- Enable Debug Section (moved to bottom as advanced option) ---
|
||||
debug_group = QGroupBox("Enable Debug")
|
||||
debug_group.setStyleSheet("QGroupBox { border: 1px solid #555; border-radius: 6px; margin-top: 8px; padding: 8px; background: #23282d; } QGroupBox:title { subcontrol-origin: margin; left: 10px; padding: 0 3px 0 3px; font-weight: bold; color: #fff; }")
|
||||
debug_layout = QVBoxLayout()
|
||||
debug_group.setLayout(debug_layout)
|
||||
self.debug_checkbox = QCheckBox("Enable debug mode (requires restart)")
|
||||
# Load debug_mode from config
|
||||
self.debug_checkbox.setChecked(self.config_handler.get('debug_mode', False))
|
||||
self.debug_checkbox.setToolTip("Enable verbose debug logging. Requires Jackify restart to take effect.")
|
||||
self.debug_checkbox.setStyleSheet("color: #fff;")
|
||||
debug_layout.addWidget(self.debug_checkbox)
|
||||
general_layout.addWidget(debug_group)
|
||||
general_layout.addStretch() # Add stretch to push content to top
|
||||
|
||||
self.tab_widget.addTab(general_tab, "General")
|
||||
|
||||
def _create_advanced_tab(self):
|
||||
"""Create the Advanced settings tab"""
|
||||
advanced_tab = QWidget()
|
||||
advanced_layout = QVBoxLayout(advanced_tab)
|
||||
|
||||
resource_group = QGroupBox("Resource Limits")
|
||||
resource_group.setStyleSheet("QGroupBox { border: 1px solid #555; border-radius: 6px; margin-top: 8px; padding: 8px; background: #23282d; } QGroupBox:title { subcontrol-origin: margin; left: 10px; padding: 0 3px 0 3px; font-weight: bold; color: #fff; }")
|
||||
resource_layout = QGridLayout()
|
||||
resource_group.setLayout(resource_layout)
|
||||
resource_layout.setVerticalSpacing(4)
|
||||
resource_layout.setHorizontalSpacing(8)
|
||||
resource_layout.addWidget(self._bold_label("Resource"), 0, 0, 1, 1, Qt.AlignLeft)
|
||||
resource_layout.addWidget(self._bold_label("Max Tasks"), 0, 1, 1, 1, Qt.AlignLeft)
|
||||
self.resource_settings_path = os.path.expanduser("~/.config/jackify/resource_settings.json")
|
||||
self.resource_settings = self._load_json(self.resource_settings_path)
|
||||
self.resource_edits = {}
|
||||
resource_row_index = 0
|
||||
for resource_row_index, (k, v) in enumerate(self.resource_settings.items(), start=1):
|
||||
try:
|
||||
# Create resource label
|
||||
resource_layout.addWidget(QLabel(f"{k}:", parent=self), resource_row_index, 0, 1, 1, Qt.AlignLeft)
|
||||
|
||||
max_tasks_spin = QSpinBox()
|
||||
max_tasks_spin.setMinimum(1)
|
||||
max_tasks_spin.setMaximum(128)
|
||||
max_tasks_spin.setValue(v.get('MaxTasks', 16))
|
||||
max_tasks_spin.setToolTip("Maximum number of concurrent tasks for this resource.")
|
||||
max_tasks_spin.setFixedWidth(160)
|
||||
resource_layout.addWidget(max_tasks_spin, resource_row_index, 1)
|
||||
|
||||
# Store the widgets
|
||||
self.resource_edits[k] = (None, max_tasks_spin)
|
||||
except Exception as e:
|
||||
print(f"[ERROR] Failed to create widgets for resource '{k}': {e}")
|
||||
continue
|
||||
|
||||
# If no resources exist, show helpful message
|
||||
if not self.resource_edits:
|
||||
info_label = QLabel("Resource Limit settings will be generated once a modlist install action is performed")
|
||||
info_label.setStyleSheet("color: #aaa; font-style: italic; padding: 20px; font-size: 11pt;")
|
||||
info_label.setWordWrap(True)
|
||||
info_label.setAlignment(Qt.AlignCenter)
|
||||
info_label.setMinimumHeight(60) # Ensure enough height to prevent cutoff
|
||||
resource_layout.addWidget(info_label, 1, 0, 3, 2) # Span more rows for better space
|
||||
|
||||
# Bandwidth limiter row (only show if Downloads resource exists)
|
||||
if "Downloads" in self.resource_settings:
|
||||
downloads_throughput = self.resource_settings["Downloads"].get("MaxThroughput", 0)
|
||||
|
||||
self.bandwidth_spin = QSpinBox()
|
||||
self.bandwidth_spin.setMinimum(0)
|
||||
self.bandwidth_spin.setMaximum(1000000)
|
||||
self.bandwidth_spin.setValue(downloads_throughput)
|
||||
self.bandwidth_spin.setSuffix(" KB/s")
|
||||
self.bandwidth_spin.setFixedWidth(160)
|
||||
self.bandwidth_spin.setToolTip("Set the maximum download speed for modlist downloads. 0 = unlimited.")
|
||||
bandwidth_note = QLabel("(0 = unlimited)")
|
||||
bandwidth_note.setStyleSheet("color: #aaa; font-size: 10pt;")
|
||||
# Create horizontal layout for bandwidth row
|
||||
bandwidth_row = QHBoxLayout()
|
||||
bandwidth_row.addWidget(self.bandwidth_spin)
|
||||
bandwidth_row.addWidget(bandwidth_note)
|
||||
bandwidth_row.addStretch() # Push to the left
|
||||
|
||||
resource_layout.addWidget(QLabel("Bandwidth Limit:", parent=self), resource_row_index+1, 0, 1, 1, Qt.AlignLeft)
|
||||
resource_layout.addLayout(bandwidth_row, resource_row_index+1, 1)
|
||||
else:
|
||||
self.bandwidth_spin = None # No bandwidth UI if Downloads resource doesn't exist
|
||||
|
||||
advanced_layout.addWidget(resource_group)
|
||||
advanced_layout.addStretch() # Add stretch to push content to top
|
||||
|
||||
self.tab_widget.addTab(advanced_tab, "Advanced")
|
||||
|
||||
def _toggle_api_key_visibility(self, checked):
|
||||
# Always use the same eyeball icon, only change color when toggled
|
||||
@@ -572,13 +565,6 @@ class SettingsDialog(QDialog):
|
||||
for k, (multithreading_checkbox, max_tasks_spin) in self.resource_edits.items():
|
||||
resource_data = self.resource_settings.get(k, {})
|
||||
resource_data['MaxTasks'] = max_tasks_spin.value()
|
||||
# Only add multithreading setting for File Extractor
|
||||
if k == "File Extractor" and multithreading_checkbox:
|
||||
if multithreading_checkbox.isChecked():
|
||||
resource_data['_7zzMultiThread'] = 'on'
|
||||
else:
|
||||
# Remove the setting if unchecked (don't add 'off')
|
||||
resource_data.pop('_7zzMultiThread', None)
|
||||
self.resource_settings[k] = resource_data
|
||||
|
||||
# Save bandwidth limit to Downloads resource MaxThroughput (only if bandwidth UI exists)
|
||||
|
||||
@@ -1757,6 +1757,10 @@ class InstallModlistScreen(QWidget):
|
||||
MessageService.critical(self, "Steam Restart Failed", "Failed to restart Steam automatically. Please restart Steam manually, then try again.")
|
||||
|
||||
def start_automated_prefix_workflow(self):
|
||||
# Ensure _current_resolution is always set before starting workflow
|
||||
if not hasattr(self, '_current_resolution') or self._current_resolution is None:
|
||||
resolution = self.resolution_combo.currentText() if hasattr(self, 'resolution_combo') else None
|
||||
self._current_resolution = resolution.split()[0] if resolution and resolution != "Leave unchanged" else None
|
||||
"""Start the automated prefix creation workflow"""
|
||||
try:
|
||||
# Disable controls during installation
|
||||
|
||||
@@ -222,8 +222,14 @@ class ValidationHandler:
|
||||
def validate_steam_shortcut(self, app_id: str) -> Tuple[bool, str]:
|
||||
"""Validate a Steam shortcut."""
|
||||
try:
|
||||
# Check if shortcuts.vdf exists
|
||||
shortcuts_path = Path.home() / '.steam' / 'steam' / 'userdata' / '75424832' / 'config' / 'shortcuts.vdf'
|
||||
# Use native Steam service to get proper shortcuts.vdf path with multi-user support
|
||||
from jackify.backend.services.native_steam_service import NativeSteamService
|
||||
steam_service = NativeSteamService()
|
||||
shortcuts_path = steam_service.get_shortcuts_vdf_path()
|
||||
|
||||
if not shortcuts_path:
|
||||
return False, "Could not determine shortcuts.vdf path (no active Steam user found)"
|
||||
|
||||
if not shortcuts_path.exists():
|
||||
return False, "shortcuts.vdf not found"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user