diff --git a/CHANGELOG.md b/CHANGELOG.md index 8f970c4..52e9ab9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,27 @@ # Jackify Changelog +## v0.2.0.4 - Bugfixes & Improvements +**Release Date:** 2025-12-23 + +### Engine Updates +- **jackify-engine 0.4.3**: Fixed case sensitivity issues, archive extraction crashes, and improved error messages + +### Bug Fixes +- Fixed modlist gallery metadata showing outdated versions (now always fetches fresh data) +- Fixed hardcoded ~/Jackify paths preventing custom data directory settings +- Fixed update check blocking GUI startup +- Improved Steam restart reliability (3-minute timeout, better error handling) +- Fixed Protontricks Flatpak installation on Steam Deck + +### Backend Changes +- GPU texture conversion now always enabled (config setting deprecated) + +### UI Improvements +- Redesigned modlist detail view to show more of hero image +- Improved gallery loading with animated feedback and faster initial load + +--- + ## v0.2.0.3 - Engine Bugfix & Settings Cleanup **Release Date:** 2025-12-21 diff --git a/jackify/__init__.py b/jackify/__init__.py index 73b8b82..03efe2a 100644 --- a/jackify/__init__.py +++ b/jackify/__init__.py @@ -5,4 +5,4 @@ This package provides both CLI and GUI interfaces for managing Wabbajack modlists natively on Linux systems. """ -__version__ = "0.2.0.3" +__version__ = "0.2.0.4" diff --git a/jackify/backend/core/modlist_operations.py b/jackify/backend/core/modlist_operations.py index 4537407..e5aac72 100644 --- a/jackify/backend/core/modlist_operations.py +++ b/jackify/backend/core/modlist_operations.py @@ -680,7 +680,8 @@ class ModlistInstallCLI: start_time = time.time() # --- BEGIN: TEE LOGGING SETUP & LOG ROTATION --- - log_dir = Path.home() / "Jackify" / "logs" + from jackify.shared.paths import get_jackify_logs_dir + log_dir = get_jackify_logs_dir() log_dir.mkdir(parents=True, exist_ok=True) workflow_log_path = log_dir / "Modlist_Install_workflow.log" # Log rotation: keep last 3 logs, 1MB each (adjust as needed) @@ -775,12 +776,6 @@ class ModlistInstallCLI: cmd.append('--debug') self.logger.info("Adding --debug flag to jackify-engine") - # Check GPU setting and add --no-gpu flag if disabled - gpu_enabled = config_handler.get('enable_gpu_texture_conversion', True) - if not gpu_enabled: - cmd.append('--no-gpu') - self.logger.info("GPU texture conversion disabled - adding --no-gpu flag to jackify-engine") - # Store original environment values to restore later original_env_values = { 'NEXUS_API_KEY': os.environ.get('NEXUS_API_KEY'), diff --git a/jackify/backend/handlers/config_handler.py b/jackify/backend/handlers/config_handler.py index 88909bd..376642a 100644 --- a/jackify/backend/handlers/config_handler.py +++ b/jackify/backend/handlers/config_handler.py @@ -389,6 +389,14 @@ class ConfigHandler: """ try: from Crypto.Cipher import AES + + # Check if MODE_GCM is available (pycryptodome has it, old pycrypto doesn't) + if not hasattr(AES, 'MODE_GCM'): + # Fallback to base64 decode if old pycrypto is installed + try: + return base64.b64decode(encrypted_key.encode('utf-8')).decode('utf-8') + except: + return None # Derive 32-byte AES key key = base64.urlsafe_b64decode(self._get_encryption_key()) @@ -411,6 +419,12 @@ class ConfigHandler: return base64.b64decode(encrypted_key.encode('utf-8')).decode('utf-8') except: return None + except AttributeError: + # Old pycrypto doesn't have MODE_GCM, fallback to base64 + try: + return base64.b64decode(encrypted_key.encode('utf-8')).decode('utf-8') + except: + return None except Exception as e: # Might be old base64-only format, try decoding try: diff --git a/jackify/backend/handlers/install_wabbajack_handler.py b/jackify/backend/handlers/install_wabbajack_handler.py index 3de05fb..721b592 100644 --- a/jackify/backend/handlers/install_wabbajack_handler.py +++ b/jackify/backend/handlers/install_wabbajack_handler.py @@ -1196,7 +1196,8 @@ class InstallWabbajackHandler: """Displays the final success message and next steps.""" # Basic log file path (assuming standard location) # TODO: Get log file path more reliably if needed - log_path = Path.home() / "Jackify" / "logs" / "jackify-cli.log" + from jackify.shared.paths import get_jackify_logs_dir + log_path = get_jackify_logs_dir() / "jackify-cli.log" print("\n───────────────────────────────────────────────────────────────────") print(f"{COLOR_INFO}Wabbajack Installation Completed Successfully!{COLOR_RESET}") diff --git a/jackify/backend/handlers/logging_handler.py b/jackify/backend/handlers/logging_handler.py index 5210e9e..8a26a86 100644 --- a/jackify/backend/handlers/logging_handler.py +++ b/jackify/backend/handlers/logging_handler.py @@ -21,7 +21,8 @@ class LoggingHandler: logger = LoggingHandler().setup_logger('install_wabbajack', 'jackify-install-wabbajack.log') """ def __init__(self): - self.log_dir = Path.home() / "Jackify" / "logs" + from jackify.shared.paths import get_jackify_logs_dir + self.log_dir = get_jackify_logs_dir() self.ensure_log_directory() def ensure_log_directory(self) -> None: diff --git a/jackify/backend/handlers/modlist_install_cli.py b/jackify/backend/handlers/modlist_install_cli.py index 753273f..eff1ecb 100644 --- a/jackify/backend/handlers/modlist_install_cli.py +++ b/jackify/backend/handlers/modlist_install_cli.py @@ -558,7 +558,8 @@ class ModlistInstallCLI: start_time = time.time() # --- BEGIN: TEE LOGGING SETUP & LOG ROTATION --- - log_dir = Path.home() / "Jackify" / "logs" + from jackify.shared.paths import get_jackify_logs_dir + log_dir = get_jackify_logs_dir() log_dir.mkdir(parents=True, exist_ok=True) workflow_log_path = log_dir / "Modlist_Install_workflow.log" # Log rotation: keep last 3 logs, 1MB each (adjust as needed) @@ -644,12 +645,6 @@ class ModlistInstallCLI: cmd.append('--debug') self.logger.info("Debug mode enabled in config - passing --debug flag to jackify-engine") - # Check GPU setting and add --no-gpu flag if disabled - gpu_enabled = config_handler.get('enable_gpu_texture_conversion', True) - if not gpu_enabled: - cmd.append('--no-gpu') - self.logger.info("GPU texture conversion disabled - passing --no-gpu flag to jackify-engine") - # Determine if this is a local .wabbajack file or an online modlist modlist_value = self.context.get('modlist_value') machineid = self.context.get('machineid') diff --git a/jackify/backend/handlers/oauth_token_handler.py b/jackify/backend/handlers/oauth_token_handler.py index 9d27d31..3408170 100644 --- a/jackify/backend/handlers/oauth_token_handler.py +++ b/jackify/backend/handlers/oauth_token_handler.py @@ -142,6 +142,11 @@ class OAuthTokenHandler: """ try: from Crypto.Cipher import AES + + # Check if MODE_GCM is available (pycryptodome has it, old pycrypto doesn't) + if not hasattr(AES, 'MODE_GCM'): + logger.error("pycryptodome required for token decryption (pycrypto doesn't support MODE_GCM)") + return None # Derive 32-byte AES key from encryption_key key = base64.urlsafe_b64decode(self._encryption_key) @@ -163,6 +168,9 @@ class OAuthTokenHandler: except ImportError: logger.error("pycryptodome package not available for token decryption") return None + except AttributeError: + logger.error("pycryptodome required for token decryption (pycrypto doesn't support MODE_GCM)") + return None except Exception as e: logger.error(f"Failed to decrypt data: {e}") return None diff --git a/jackify/backend/handlers/ttw_installer_handler.py b/jackify/backend/handlers/ttw_installer_handler.py index fe2fefe..ea0eef9 100644 --- a/jackify/backend/handlers/ttw_installer_handler.py +++ b/jackify/backend/handlers/ttw_installer_handler.py @@ -23,7 +23,8 @@ from .subprocess_utils import get_clean_subprocess_env logger = logging.getLogger(__name__) # Define default TTW_Linux_Installer paths -JACKIFY_BASE_DIR = Path.home() / "Jackify" +from jackify.shared.paths import get_jackify_data_dir +JACKIFY_BASE_DIR = get_jackify_data_dir() DEFAULT_TTW_INSTALLER_DIR = JACKIFY_BASE_DIR / "TTW_Linux_Installer" TTW_INSTALLER_EXECUTABLE_NAME = "ttw_linux_gui" # Same executable, runs in CLI mode with args diff --git a/jackify/backend/handlers/wabbajack_handler.py b/jackify/backend/handlers/wabbajack_handler.py index 69a180a..a7ac8db 100644 --- a/jackify/backend/handlers/wabbajack_handler.py +++ b/jackify/backend/handlers/wabbajack_handler.py @@ -1196,7 +1196,8 @@ class InstallWabbajackHandler: """Displays the final success message and next steps.""" # Basic log file path (assuming standard location) # TODO: Get log file path more reliably if needed - log_path = Path.home() / "Jackify" / "logs" / "jackify-cli.log" + from jackify.shared.paths import get_jackify_logs_dir + log_path = get_jackify_logs_dir() / "jackify-cli.log" print("\n───────────────────────────────────────────────────────────────────") print(f"{COLOR_INFO}Wabbajack Installation Completed Successfully!{COLOR_RESET}") diff --git a/jackify/backend/services/automated_prefix_service.py b/jackify/backend/services/automated_prefix_service.py index d2b0071..3ce5708 100644 --- a/jackify/backend/services/automated_prefix_service.py +++ b/jackify/backend/services/automated_prefix_service.py @@ -30,7 +30,8 @@ class AutomatedPrefixService: """ def __init__(self, system_info=None): - self.scripts_dir = Path.home() / "Jackify/scripts" + from jackify.shared.paths import get_jackify_data_dir + self.scripts_dir = get_jackify_data_dir() / "scripts" self.scripts_dir.mkdir(parents=True, exist_ok=True) self.system_info = system_info # Use shared timing for consistency across services @@ -749,7 +750,8 @@ echo Creating Proton prefix... timeout /t 3 /nobreak >nul echo Prefix creation complete. """ - batch_path = Path.home() / "Jackify/temp_prefix_creation.bat" + from jackify.shared.paths import get_jackify_data_dir + batch_path = get_jackify_data_dir() / "temp_prefix_creation.bat" batch_path.parent.mkdir(parents=True, exist_ok=True) with open(batch_path, 'w') as f: diff --git a/jackify/backend/services/modlist_gallery_service.py b/jackify/backend/services/modlist_gallery_service.py index 8e5336f..9106000 100644 --- a/jackify/backend/services/modlist_gallery_service.py +++ b/jackify/backend/services/modlist_gallery_service.py @@ -25,7 +25,8 @@ from jackify.shared.paths import get_jackify_data_dir class ModlistGalleryService: """Service for fetching and caching modlist metadata from jackify-engine""" - CACHE_VALIDITY_DAYS = 7 # Refresh cache after 7 days + # REMOVED: CACHE_VALIDITY_DAYS - metadata is now always fetched fresh from engine + # Images are still cached indefinitely (managed separately) # CRITICAL: Thread lock to prevent concurrent engine calls that could cause recursive spawning _engine_call_lock = threading.Lock() @@ -59,31 +60,20 @@ class ModlistGalleryService: """ Fetch modlist metadata from jackify-engine. + NOTE: Metadata is ALWAYS fetched fresh from the engine to ensure up-to-date + version numbers and sizes for frequently-updated modlists. Only images are cached. + Args: include_validation: Include validation status (slower) include_search_index: Include mod search index (slower) sort_by: Sort order (title, size, date) - force_refresh: Force refresh even if cache is valid + force_refresh: Deprecated parameter (kept for API compatibility) Returns: ModlistMetadataResponse or None if fetch fails """ - # Check cache first unless force refresh - # If include_search_index is True, check if cache has mods before using it - if not force_refresh: - cached = self._load_from_cache() - if cached and self._is_cache_valid(): - # If we need search index, check if cached data has mods - if include_search_index: - # Check if at least one modlist has mods (indicates cache was built with search index) - has_mods = any(hasattr(m, 'mods') and m.mods for m in cached.modlists) - if has_mods: - return cached # Cache has mods, use it - # Cache doesn't have mods, need to fetch fresh - else: - return cached # Don't need search index, use cache - - # Fetch fresh data from jackify-engine + # Always fetch fresh data from jackify-engine + # The engine itself is fast (~1-2 seconds) and always gets latest metadata try: metadata = self._fetch_from_engine( include_validation=include_validation, @@ -91,6 +81,7 @@ class ModlistGalleryService: sort_by=sort_by ) + # Still save to cache as a fallback for offline scenarios if metadata: self._save_to_cache(metadata) @@ -98,7 +89,8 @@ class ModlistGalleryService: except Exception as e: print(f"Error fetching modlist metadata: {e}") - # Fall back to cache if available + print("Falling back to cached metadata (may be outdated)") + # Fall back to cache if network/engine fails return self._load_from_cache() def _fetch_from_engine( @@ -253,17 +245,6 @@ class ModlistGalleryService: return result - def _is_cache_valid(self) -> bool: - """Check if cache is still valid based on age""" - if not self.METADATA_CACHE_FILE.exists(): - return False - - # Check file modification time - mtime = datetime.fromtimestamp(self.METADATA_CACHE_FILE.stat().st_mtime) - age = datetime.now() - mtime - - return age < timedelta(days=self.CACHE_VALIDITY_DAYS) - def download_images( self, game_filter: Optional[str] = None, diff --git a/jackify/backend/services/modlist_service.py b/jackify/backend/services/modlist_service.py index 7c2035c..d03c7cc 100644 --- a/jackify/backend/services/modlist_service.py +++ b/jackify/backend/services/modlist_service.py @@ -288,15 +288,6 @@ class ModlistService: # Build command (copied from working code) cmd = [engine_path, 'install', '--show-file-progress'] - # Check GPU setting - from jackify.backend.handlers.config_handler import ConfigHandler - config_handler = ConfigHandler() - gpu_enabled = config_handler.get('enable_gpu_texture_conversion', True) - logger.info(f"GPU texture conversion setting: {gpu_enabled}") - if not gpu_enabled: - cmd.append('--no-gpu') - logger.info("Added --no-gpu flag to jackify-engine command") - modlist_value = context.get('modlist_value') if modlist_value and modlist_value.endswith('.wabbajack') and os.path.isfile(modlist_value): cmd += ['-w', modlist_value] diff --git a/jackify/backend/services/native_steam_operations_service.py b/jackify/backend/services/native_steam_operations_service.py index a14b6b9..78af8bc 100644 --- a/jackify/backend/services/native_steam_operations_service.py +++ b/jackify/backend/services/native_steam_operations_service.py @@ -177,7 +177,7 @@ class NativeSteamOperationsService: # Also check additional Steam libraries via libraryfolders.vdf try: - from jackify.shared.paths import PathHandler + from jackify.backend.handlers.path_handler import PathHandler all_steam_libs = PathHandler.get_all_steam_library_paths() for lib_path in all_steam_libs: diff --git a/jackify/backend/services/protontricks_detection_service.py b/jackify/backend/services/protontricks_detection_service.py index 95e6471..8acbb2c 100644 --- a/jackify/backend/services/protontricks_detection_service.py +++ b/jackify/backend/services/protontricks_detection_service.py @@ -132,14 +132,31 @@ class ProtontricksDetectionService: logger.error(error_msg) return False, error_msg - # Install command - install_cmd = ["flatpak", "install", "-u", "-y", "--noninteractive", "flathub", "com.github.Matoking.protontricks"] + # Install command - use --user flag for user-level installation (works on Steam Deck) + # This avoids requiring system-wide installation permissions + install_cmd = ["flatpak", "install", "--user", "-y", "--noninteractive", "flathub", "com.github.Matoking.protontricks"] # Use clean environment env = handler._get_clean_subprocess_env() - # Run installation - process = subprocess.run(install_cmd, check=True, text=True, env=env, capture_output=True) + # Log the command for debugging + logger.debug(f"Running flatpak install command: {' '.join(install_cmd)}") + + # Run installation with timeout (5 minutes should be plenty) + process = subprocess.run( + install_cmd, + check=True, + text=True, + env=env, + capture_output=True, + timeout=300 # 5 minute timeout + ) + + # Log stdout/stderr for debugging (even on success, might contain useful info) + if process.stdout: + logger.debug(f"Flatpak install stdout: {process.stdout}") + if process.stderr: + logger.debug(f"Flatpak install stderr: {process.stderr}") # Clear cache to force re-detection self._cached_detection_valid = False @@ -152,13 +169,41 @@ class ProtontricksDetectionService: error_msg = "Flatpak command not found. Please install Flatpak first." logger.error(error_msg) return False, error_msg - except subprocess.CalledProcessError as e: - error_msg = f"Flatpak installation failed: {e}" + except subprocess.TimeoutExpired: + error_msg = "Flatpak installation timed out after 5 minutes. Please check your network connection and try again." logger.error(error_msg) return False, error_msg + except subprocess.CalledProcessError as e: + # Include stderr in error message for better debugging + stderr_msg = e.stderr.strip() if e.stderr else "No error details available" + stdout_msg = e.stdout.strip() if e.stdout else "" + + # Try to extract meaningful error from stderr + if stderr_msg: + # Common errors: permission denied, network issues, etc. + if "permission" in stderr_msg.lower() or "denied" in stderr_msg.lower(): + error_msg = f"Permission denied. Try running: flatpak install --user flathub com.github.Matoking.protontricks\n\nDetails: {stderr_msg}" + elif "network" in stderr_msg.lower() or "connection" in stderr_msg.lower(): + error_msg = f"Network error during installation. Check your internet connection.\n\nDetails: {stderr_msg}" + elif "already installed" in stderr_msg.lower(): + # This might actually be success - clear cache and re-detect + logger.info("Protontricks appears to already be installed (according to flatpak output)") + self._cached_detection_valid = False + return True, "Protontricks is already installed." + else: + error_msg = f"Flatpak installation failed:\n\n{stderr_msg}" + if stdout_msg: + error_msg += f"\n\nOutput: {stdout_msg}" + else: + error_msg = f"Flatpak installation failed with return code {e.returncode}." + if stdout_msg: + error_msg += f"\n\nOutput: {stdout_msg}" + + logger.error(f"Flatpak installation error: {error_msg}") + return False, error_msg except Exception as e: error_msg = f"Unexpected error during Flatpak installation: {e}" - logger.error(error_msg) + logger.error(error_msg, exc_info=True) return False, error_msg def get_installation_guidance(self) -> str: diff --git a/jackify/backend/services/steam_restart_service.py b/jackify/backend/services/steam_restart_service.py index 00b7ea7..129417b 100644 --- a/jackify/backend/services/steam_restart_service.py +++ b/jackify/backend/services/steam_restart_service.py @@ -402,14 +402,15 @@ def robust_steam_restart(progress_callback: Optional[Callable[[str], None]] = No if final_check.returncode != 0: logger.info("Steam processes successfully force terminated.") else: - report("Failed to terminate Steam processes.") - return False + # Steam might still be running, but proceed anyway - wait phase will verify + logger.warning("Steam processes may still be running after termination attempts. Proceeding to start phase...") + report("Steam shutdown incomplete, but proceeding...") else: logger.info("Steam processes successfully terminated.") except Exception as e: - logger.error(f"Error during Steam shutdown: {e}") - report("Failed to shut down Steam.") - return False + # Don't fail completely on shutdown errors - proceed to start phase + logger.warning(f"Error during Steam shutdown: {e}. Proceeding to start phase anyway...") + report("Steam shutdown had issues, but proceeding...") report("Steam closed successfully.") @@ -427,42 +428,56 @@ def robust_steam_restart(progress_callback: Optional[Callable[[str], None]] = No return False else: # All other distros: Use start_steam() which now uses -foreground to ensure GUI opens - if not start_steam( + steam_started = start_steam( is_steamdeck_flag=_is_steam_deck, is_flatpak_flag=_is_flatpak, env_override=start_env, strategy=strategy, - ): - report("Failed to start Steam.") - return False + ) + # Even if start_steam() returns False, Steam might still be starting + # Give it a chance by proceeding to wait phase + if not steam_started: + logger.warning("start_steam() returned False, but proceeding to wait phase in case Steam is starting anyway") + report("Steam start command issued, waiting for process...") # Wait for Steam to fully initialize # CRITICAL: Use steamwebhelper (actual Steam process), not "steam" (matches steam-powerbuttond, etc.) report("Waiting for Steam to fully start") - logger.info("Waiting up to 2 minutes for Steam to fully initialize...") - max_startup_wait = 120 + logger.info("Waiting up to 3 minutes (180 seconds) for Steam to fully initialize...") + max_startup_wait = 180 # Increased from 120 to 180 seconds (3 minutes) for slower systems elapsed_wait = 0 initial_wait_done = False + last_status_log = 0 # Track when we last logged status while elapsed_wait < max_startup_wait: try: + # Log status every 30 seconds so user knows we're still waiting + if elapsed_wait - last_status_log >= 30: + remaining = max_startup_wait - elapsed_wait + logger.info(f"Still waiting for Steam... ({elapsed_wait}s elapsed, {remaining}s remaining)") + if progress_callback: + progress_callback(f"Waiting for Steam... ({elapsed_wait}s / {max_startup_wait}s)") + last_status_log = elapsed_wait + # Use steamwebhelper for detection (matches shutdown logic) result = subprocess.run(['pgrep', '-f', 'steamwebhelper'], capture_output=True, timeout=10, env=start_env) if result.returncode == 0: if not initial_wait_done: - logger.info("Steam process detected. Waiting additional time for full initialization...") + logger.info(f"Steam process detected at {elapsed_wait}s. Waiting additional time for full initialization...") initial_wait_done = True time.sleep(5) elapsed_wait += 5 - if initial_wait_done and elapsed_wait >= 15: + # Require at least 20 seconds of stable detection (increased from 15) + if initial_wait_done and elapsed_wait >= 20: final_check = subprocess.run(['pgrep', '-f', 'steamwebhelper'], capture_output=True, timeout=10, env=start_env) if final_check.returncode == 0: report("Steam started successfully.") - logger.info("Steam confirmed running after wait.") + logger.info(f"Steam confirmed running after {elapsed_wait}s wait.") return True else: - logger.warning("Steam process disappeared during final initialization wait.") - break + logger.warning("Steam process disappeared during final initialization wait, continuing to wait...") + # Don't break - continue waiting in case Steam is still starting + initial_wait_done = False # Reset to allow re-detection else: logger.debug(f"Steam process not yet detected. Waiting... ({elapsed_wait + 5}s)") time.sleep(5) @@ -472,6 +487,7 @@ def robust_steam_restart(progress_callback: Optional[Callable[[str], None]] = No time.sleep(5) elapsed_wait += 5 - report("Steam did not start within timeout.") - logger.error("Steam failed to start/initialize within the allowed time.") + # Only reach here if we've waited the full duration + report(f"Steam did not start within {max_startup_wait}s timeout.") + logger.error(f"Steam failed to start/initialize within the allowed time ({elapsed_wait}s elapsed).") return False \ No newline at end of file diff --git a/jackify/backend/services/update_service.py b/jackify/backend/services/update_service.py index 4ac86c4..255ce9c 100644 --- a/jackify/backend/services/update_service.py +++ b/jackify/backend/services/update_service.py @@ -271,9 +271,9 @@ class UpdateService: total_size = int(response.headers.get('content-length', 0)) downloaded_size = 0 - # Create update directory in user's home directory - home_dir = Path.home() - update_dir = home_dir / "Jackify" / "updates" + # Create update directory in user's data directory + from jackify.shared.paths import get_jackify_data_dir + update_dir = get_jackify_data_dir() / "updates" update_dir.mkdir(parents=True, exist_ok=True) temp_file = update_dir / f"Jackify-{update_info.version}.AppImage" @@ -345,9 +345,9 @@ class UpdateService: Path to helper script, or None if creation failed """ try: - # Create update directory in user's home directory - home_dir = Path.home() - update_dir = home_dir / "Jackify" / "updates" + # Create update directory in user's data directory + from jackify.shared.paths import get_jackify_data_dir + update_dir = get_jackify_data_dir() / "updates" update_dir.mkdir(parents=True, exist_ok=True) helper_script = update_dir / "update_helper.sh" diff --git a/jackify/engine/Wabbajack.CLI.Builder.dll b/jackify/engine/Wabbajack.CLI.Builder.dll index dd0bdad..1f69963 100644 Binary files a/jackify/engine/Wabbajack.CLI.Builder.dll and b/jackify/engine/Wabbajack.CLI.Builder.dll differ diff --git a/jackify/engine/Wabbajack.Common.dll b/jackify/engine/Wabbajack.Common.dll index bb2175a..41974b6 100644 Binary files a/jackify/engine/Wabbajack.Common.dll and b/jackify/engine/Wabbajack.Common.dll differ diff --git a/jackify/engine/Wabbajack.Compiler.dll b/jackify/engine/Wabbajack.Compiler.dll index 9c80574..d59b807 100644 Binary files a/jackify/engine/Wabbajack.Compiler.dll and b/jackify/engine/Wabbajack.Compiler.dll differ diff --git a/jackify/engine/Wabbajack.Compression.BSA.dll b/jackify/engine/Wabbajack.Compression.BSA.dll index d9e2437..b0059cd 100644 Binary files a/jackify/engine/Wabbajack.Compression.BSA.dll and b/jackify/engine/Wabbajack.Compression.BSA.dll differ diff --git a/jackify/engine/Wabbajack.Compression.Zip.dll b/jackify/engine/Wabbajack.Compression.Zip.dll index 32a86e4..280bbd8 100644 Binary files a/jackify/engine/Wabbajack.Compression.Zip.dll and b/jackify/engine/Wabbajack.Compression.Zip.dll differ diff --git a/jackify/engine/Wabbajack.Configuration.dll b/jackify/engine/Wabbajack.Configuration.dll index f410728..1b03380 100644 Binary files a/jackify/engine/Wabbajack.Configuration.dll and b/jackify/engine/Wabbajack.Configuration.dll differ diff --git a/jackify/engine/Wabbajack.DTOs.dll b/jackify/engine/Wabbajack.DTOs.dll index aa323a8..fa318da 100644 Binary files a/jackify/engine/Wabbajack.DTOs.dll and b/jackify/engine/Wabbajack.DTOs.dll differ diff --git a/jackify/engine/Wabbajack.Downloaders.Bethesda.dll b/jackify/engine/Wabbajack.Downloaders.Bethesda.dll index 3a7339d..278ec4f 100644 Binary files a/jackify/engine/Wabbajack.Downloaders.Bethesda.dll and b/jackify/engine/Wabbajack.Downloaders.Bethesda.dll differ diff --git a/jackify/engine/Wabbajack.Downloaders.Dispatcher.dll b/jackify/engine/Wabbajack.Downloaders.Dispatcher.dll index 6a62f02..22a29d2 100644 Binary files a/jackify/engine/Wabbajack.Downloaders.Dispatcher.dll and b/jackify/engine/Wabbajack.Downloaders.Dispatcher.dll differ diff --git a/jackify/engine/Wabbajack.Downloaders.GameFile.dll b/jackify/engine/Wabbajack.Downloaders.GameFile.dll index 1932880..0b0d73c 100644 Binary files a/jackify/engine/Wabbajack.Downloaders.GameFile.dll and b/jackify/engine/Wabbajack.Downloaders.GameFile.dll differ diff --git a/jackify/engine/Wabbajack.Downloaders.GoogleDrive.dll b/jackify/engine/Wabbajack.Downloaders.GoogleDrive.dll index 70d086d..01c72de 100644 Binary files a/jackify/engine/Wabbajack.Downloaders.GoogleDrive.dll and b/jackify/engine/Wabbajack.Downloaders.GoogleDrive.dll differ diff --git a/jackify/engine/Wabbajack.Downloaders.Http.dll b/jackify/engine/Wabbajack.Downloaders.Http.dll index b5eb21e..d0b58f1 100644 Binary files a/jackify/engine/Wabbajack.Downloaders.Http.dll and b/jackify/engine/Wabbajack.Downloaders.Http.dll differ diff --git a/jackify/engine/Wabbajack.Downloaders.IPS4OAuth2Downloader.dll b/jackify/engine/Wabbajack.Downloaders.IPS4OAuth2Downloader.dll index c8cd94b..f262753 100644 Binary files a/jackify/engine/Wabbajack.Downloaders.IPS4OAuth2Downloader.dll and b/jackify/engine/Wabbajack.Downloaders.IPS4OAuth2Downloader.dll differ diff --git a/jackify/engine/Wabbajack.Downloaders.Interfaces.dll b/jackify/engine/Wabbajack.Downloaders.Interfaces.dll index 578b8df..e3bbf28 100644 Binary files a/jackify/engine/Wabbajack.Downloaders.Interfaces.dll and b/jackify/engine/Wabbajack.Downloaders.Interfaces.dll differ diff --git a/jackify/engine/Wabbajack.Downloaders.Manual.dll b/jackify/engine/Wabbajack.Downloaders.Manual.dll index 61b2f50..4930662 100644 Binary files a/jackify/engine/Wabbajack.Downloaders.Manual.dll and b/jackify/engine/Wabbajack.Downloaders.Manual.dll differ diff --git a/jackify/engine/Wabbajack.Downloaders.MediaFire.dll b/jackify/engine/Wabbajack.Downloaders.MediaFire.dll index 15df274..f023068 100644 Binary files a/jackify/engine/Wabbajack.Downloaders.MediaFire.dll and b/jackify/engine/Wabbajack.Downloaders.MediaFire.dll differ diff --git a/jackify/engine/Wabbajack.Downloaders.Mega.dll b/jackify/engine/Wabbajack.Downloaders.Mega.dll index c2248b8..c0b0e2e 100644 Binary files a/jackify/engine/Wabbajack.Downloaders.Mega.dll and b/jackify/engine/Wabbajack.Downloaders.Mega.dll differ diff --git a/jackify/engine/Wabbajack.Downloaders.ModDB.dll b/jackify/engine/Wabbajack.Downloaders.ModDB.dll index 22f86d1..3b3bd5b 100644 Binary files a/jackify/engine/Wabbajack.Downloaders.ModDB.dll and b/jackify/engine/Wabbajack.Downloaders.ModDB.dll differ diff --git a/jackify/engine/Wabbajack.Downloaders.Nexus.dll b/jackify/engine/Wabbajack.Downloaders.Nexus.dll index 9b08620..eef2cd0 100644 Binary files a/jackify/engine/Wabbajack.Downloaders.Nexus.dll and b/jackify/engine/Wabbajack.Downloaders.Nexus.dll differ diff --git a/jackify/engine/Wabbajack.Downloaders.VerificationCache.dll b/jackify/engine/Wabbajack.Downloaders.VerificationCache.dll index 1c03bbc..3342732 100644 Binary files a/jackify/engine/Wabbajack.Downloaders.VerificationCache.dll and b/jackify/engine/Wabbajack.Downloaders.VerificationCache.dll differ diff --git a/jackify/engine/Wabbajack.Downloaders.WabbajackCDN.dll b/jackify/engine/Wabbajack.Downloaders.WabbajackCDN.dll index 45b5662..f43f0fc 100644 Binary files a/jackify/engine/Wabbajack.Downloaders.WabbajackCDN.dll and b/jackify/engine/Wabbajack.Downloaders.WabbajackCDN.dll differ diff --git a/jackify/engine/Wabbajack.FileExtractor.dll b/jackify/engine/Wabbajack.FileExtractor.dll index 70ba299..65021c3 100644 Binary files a/jackify/engine/Wabbajack.FileExtractor.dll and b/jackify/engine/Wabbajack.FileExtractor.dll differ diff --git a/jackify/engine/Wabbajack.Hashing.PHash.dll b/jackify/engine/Wabbajack.Hashing.PHash.dll index cc29618..5e1a50b 100644 Binary files a/jackify/engine/Wabbajack.Hashing.PHash.dll and b/jackify/engine/Wabbajack.Hashing.PHash.dll differ diff --git a/jackify/engine/Wabbajack.Hashing.xxHash64.dll b/jackify/engine/Wabbajack.Hashing.xxHash64.dll index 7fd9465..3459fda 100644 Binary files a/jackify/engine/Wabbajack.Hashing.xxHash64.dll and b/jackify/engine/Wabbajack.Hashing.xxHash64.dll differ diff --git a/jackify/engine/Wabbajack.IO.Async.dll b/jackify/engine/Wabbajack.IO.Async.dll index 62c8a03..a11ff86 100644 Binary files a/jackify/engine/Wabbajack.IO.Async.dll and b/jackify/engine/Wabbajack.IO.Async.dll differ diff --git a/jackify/engine/Wabbajack.Installer.dll b/jackify/engine/Wabbajack.Installer.dll index 130bd9a..178d79b 100644 Binary files a/jackify/engine/Wabbajack.Installer.dll and b/jackify/engine/Wabbajack.Installer.dll differ diff --git a/jackify/engine/Wabbajack.Networking.BethesdaNet.dll b/jackify/engine/Wabbajack.Networking.BethesdaNet.dll index 6cde19f..98567a2 100644 Binary files a/jackify/engine/Wabbajack.Networking.BethesdaNet.dll and b/jackify/engine/Wabbajack.Networking.BethesdaNet.dll differ diff --git a/jackify/engine/Wabbajack.Networking.Discord.dll b/jackify/engine/Wabbajack.Networking.Discord.dll index f661883..94b72ae 100644 Binary files a/jackify/engine/Wabbajack.Networking.Discord.dll and b/jackify/engine/Wabbajack.Networking.Discord.dll differ diff --git a/jackify/engine/Wabbajack.Networking.GitHub.dll b/jackify/engine/Wabbajack.Networking.GitHub.dll index a54c598..58c3f34 100644 Binary files a/jackify/engine/Wabbajack.Networking.GitHub.dll and b/jackify/engine/Wabbajack.Networking.GitHub.dll differ diff --git a/jackify/engine/Wabbajack.Networking.Http.Interfaces.dll b/jackify/engine/Wabbajack.Networking.Http.Interfaces.dll index 26623c7..210ee91 100644 Binary files a/jackify/engine/Wabbajack.Networking.Http.Interfaces.dll and b/jackify/engine/Wabbajack.Networking.Http.Interfaces.dll differ diff --git a/jackify/engine/Wabbajack.Networking.Http.dll b/jackify/engine/Wabbajack.Networking.Http.dll index ad61afb..67aab08 100644 Binary files a/jackify/engine/Wabbajack.Networking.Http.dll and b/jackify/engine/Wabbajack.Networking.Http.dll differ diff --git a/jackify/engine/Wabbajack.Networking.NexusApi.dll b/jackify/engine/Wabbajack.Networking.NexusApi.dll index 9ff0b1b..e32e2a5 100644 Binary files a/jackify/engine/Wabbajack.Networking.NexusApi.dll and b/jackify/engine/Wabbajack.Networking.NexusApi.dll differ diff --git a/jackify/engine/Wabbajack.Networking.WabbajackClientApi.dll b/jackify/engine/Wabbajack.Networking.WabbajackClientApi.dll index 5e264c8..9792a3e 100644 Binary files a/jackify/engine/Wabbajack.Networking.WabbajackClientApi.dll and b/jackify/engine/Wabbajack.Networking.WabbajackClientApi.dll differ diff --git a/jackify/engine/Wabbajack.Paths.IO.dll b/jackify/engine/Wabbajack.Paths.IO.dll index 2eb02c9..ae3b1ea 100644 Binary files a/jackify/engine/Wabbajack.Paths.IO.dll and b/jackify/engine/Wabbajack.Paths.IO.dll differ diff --git a/jackify/engine/Wabbajack.Paths.dll b/jackify/engine/Wabbajack.Paths.dll index b655e96..d2ce72a 100644 Binary files a/jackify/engine/Wabbajack.Paths.dll and b/jackify/engine/Wabbajack.Paths.dll differ diff --git a/jackify/engine/Wabbajack.RateLimiter.dll b/jackify/engine/Wabbajack.RateLimiter.dll index 5fd5eba..e3c21c9 100644 Binary files a/jackify/engine/Wabbajack.RateLimiter.dll and b/jackify/engine/Wabbajack.RateLimiter.dll differ diff --git a/jackify/engine/Wabbajack.Server.Lib.dll b/jackify/engine/Wabbajack.Server.Lib.dll index 2fa36eb..75a6971 100644 Binary files a/jackify/engine/Wabbajack.Server.Lib.dll and b/jackify/engine/Wabbajack.Server.Lib.dll differ diff --git a/jackify/engine/Wabbajack.Services.OSIntegrated.dll b/jackify/engine/Wabbajack.Services.OSIntegrated.dll index 34302cb..0eef03b 100644 Binary files a/jackify/engine/Wabbajack.Services.OSIntegrated.dll and b/jackify/engine/Wabbajack.Services.OSIntegrated.dll differ diff --git a/jackify/engine/Wabbajack.VFS.Interfaces.dll b/jackify/engine/Wabbajack.VFS.Interfaces.dll index c7e2d9d..2b157bd 100644 Binary files a/jackify/engine/Wabbajack.VFS.Interfaces.dll and b/jackify/engine/Wabbajack.VFS.Interfaces.dll differ diff --git a/jackify/engine/Wabbajack.VFS.dll b/jackify/engine/Wabbajack.VFS.dll index 2c75d29..9a30b91 100644 Binary files a/jackify/engine/Wabbajack.VFS.dll and b/jackify/engine/Wabbajack.VFS.dll differ diff --git a/jackify/engine/jackify-engine.deps.json b/jackify/engine/jackify-engine.deps.json index d15ed7b..1828e00 100644 --- a/jackify/engine/jackify-engine.deps.json +++ b/jackify/engine/jackify-engine.deps.json @@ -7,7 +7,7 @@ "targets": { ".NETCoreApp,Version=v8.0": {}, ".NETCoreApp,Version=v8.0/linux-x64": { - "jackify-engine/0.4.2": { + "jackify-engine/0.4.3": { "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.4.2", - "Wabbajack.Downloaders.Bethesda": "0.4.2", - "Wabbajack.Downloaders.Dispatcher": "0.4.2", - "Wabbajack.Hashing.xxHash64": "0.4.2", - "Wabbajack.Networking.Discord": "0.4.2", - "Wabbajack.Networking.GitHub": "0.4.2", - "Wabbajack.Paths.IO": "0.4.2", - "Wabbajack.Server.Lib": "0.4.2", - "Wabbajack.Services.OSIntegrated": "0.4.2", - "Wabbajack.VFS": "0.4.2", + "Wabbajack.CLI.Builder": "0.4.3", + "Wabbajack.Downloaders.Bethesda": "0.4.3", + "Wabbajack.Downloaders.Dispatcher": "0.4.3", + "Wabbajack.Hashing.xxHash64": "0.4.3", + "Wabbajack.Networking.Discord": "0.4.3", + "Wabbajack.Networking.GitHub": "0.4.3", + "Wabbajack.Paths.IO": "0.4.3", + "Wabbajack.Server.Lib": "0.4.3", + "Wabbajack.Services.OSIntegrated": "0.4.3", + "Wabbajack.VFS": "0.4.3", "MegaApiClient": "1.0.0.0", "runtimepack.Microsoft.NETCore.App.Runtime.linux-x64": "8.0.22" }, @@ -1781,7 +1781,7 @@ } } }, - "Wabbajack.CLI.Builder/0.4.2": { + "Wabbajack.CLI.Builder/0.4.3": { "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.4.2" + "Wabbajack.Paths": "0.4.3" }, "runtime": { "Wabbajack.CLI.Builder.dll": {} } }, - "Wabbajack.Common/0.4.2": { + "Wabbajack.Common/0.4.3": { "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.4.2", - "Wabbajack.Networking.Http": "0.4.2", - "Wabbajack.Paths.IO": "0.4.2" + "Wabbajack.DTOs": "0.4.3", + "Wabbajack.Networking.Http": "0.4.3", + "Wabbajack.Paths.IO": "0.4.3" }, "runtime": { "Wabbajack.Common.dll": {} } }, - "Wabbajack.Compiler/0.4.2": { + "Wabbajack.Compiler/0.4.3": { "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.4.2", - "Wabbajack.Installer": "0.4.2", - "Wabbajack.VFS": "0.4.2", + "Wabbajack.Downloaders.Dispatcher": "0.4.3", + "Wabbajack.Installer": "0.4.3", + "Wabbajack.VFS": "0.4.3", "ini-parser-netstandard": "2.5.2" }, "runtime": { "Wabbajack.Compiler.dll": {} } }, - "Wabbajack.Compression.BSA/0.4.2": { + "Wabbajack.Compression.BSA/0.4.3": { "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.4.2", - "Wabbajack.DTOs": "0.4.2" + "Wabbajack.Common": "0.4.3", + "Wabbajack.DTOs": "0.4.3" }, "runtime": { "Wabbajack.Compression.BSA.dll": {} } }, - "Wabbajack.Compression.Zip/0.4.2": { + "Wabbajack.Compression.Zip/0.4.3": { "dependencies": { - "Wabbajack.IO.Async": "0.4.2" + "Wabbajack.IO.Async": "0.4.3" }, "runtime": { "Wabbajack.Compression.Zip.dll": {} } }, - "Wabbajack.Configuration/0.4.2": { + "Wabbajack.Configuration/0.4.3": { "runtime": { "Wabbajack.Configuration.dll": {} } }, - "Wabbajack.Downloaders.Bethesda/0.4.2": { + "Wabbajack.Downloaders.Bethesda/0.4.3": { "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.4.2", - "Wabbajack.Downloaders.Interfaces": "0.4.2", - "Wabbajack.Networking.BethesdaNet": "0.4.2" + "Wabbajack.Common": "0.4.3", + "Wabbajack.Downloaders.Interfaces": "0.4.3", + "Wabbajack.Networking.BethesdaNet": "0.4.3" }, "runtime": { "Wabbajack.Downloaders.Bethesda.dll": {} } }, - "Wabbajack.Downloaders.Dispatcher/0.4.2": { + "Wabbajack.Downloaders.Dispatcher/0.4.3": { "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.4.2", - "Wabbajack.Downloaders.GameFile": "0.4.2", - "Wabbajack.Downloaders.GoogleDrive": "0.4.2", - "Wabbajack.Downloaders.Http": "0.4.2", - "Wabbajack.Downloaders.IPS4OAuth2Downloader": "0.4.2", - "Wabbajack.Downloaders.Interfaces": "0.4.2", - "Wabbajack.Downloaders.Manual": "0.4.2", - "Wabbajack.Downloaders.MediaFire": "0.4.2", - "Wabbajack.Downloaders.Mega": "0.4.2", - "Wabbajack.Downloaders.ModDB": "0.4.2", - "Wabbajack.Downloaders.Nexus": "0.4.2", - "Wabbajack.Downloaders.VerificationCache": "0.4.2", - "Wabbajack.Downloaders.WabbajackCDN": "0.4.2", - "Wabbajack.Networking.WabbajackClientApi": "0.4.2" + "Wabbajack.Downloaders.Bethesda": "0.4.3", + "Wabbajack.Downloaders.GameFile": "0.4.3", + "Wabbajack.Downloaders.GoogleDrive": "0.4.3", + "Wabbajack.Downloaders.Http": "0.4.3", + "Wabbajack.Downloaders.IPS4OAuth2Downloader": "0.4.3", + "Wabbajack.Downloaders.Interfaces": "0.4.3", + "Wabbajack.Downloaders.Manual": "0.4.3", + "Wabbajack.Downloaders.MediaFire": "0.4.3", + "Wabbajack.Downloaders.Mega": "0.4.3", + "Wabbajack.Downloaders.ModDB": "0.4.3", + "Wabbajack.Downloaders.Nexus": "0.4.3", + "Wabbajack.Downloaders.VerificationCache": "0.4.3", + "Wabbajack.Downloaders.WabbajackCDN": "0.4.3", + "Wabbajack.Networking.WabbajackClientApi": "0.4.3" }, "runtime": { "Wabbajack.Downloaders.Dispatcher.dll": {} } }, - "Wabbajack.Downloaders.GameFile/0.4.2": { + "Wabbajack.Downloaders.GameFile/0.4.3": { "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.4.2", - "Wabbajack.VFS": "0.4.2" + "Wabbajack.Downloaders.Interfaces": "0.4.3", + "Wabbajack.VFS": "0.4.3" }, "runtime": { "Wabbajack.Downloaders.GameFile.dll": {} } }, - "Wabbajack.Downloaders.GoogleDrive/0.4.2": { + "Wabbajack.Downloaders.GoogleDrive/0.4.3": { "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.4.2", - "Wabbajack.DTOs": "0.4.2", - "Wabbajack.Downloaders.Interfaces": "0.4.2", - "Wabbajack.Networking.Http": "0.4.2", - "Wabbajack.Networking.Http.Interfaces": "0.4.2" + "Wabbajack.Common": "0.4.3", + "Wabbajack.DTOs": "0.4.3", + "Wabbajack.Downloaders.Interfaces": "0.4.3", + "Wabbajack.Networking.Http": "0.4.3", + "Wabbajack.Networking.Http.Interfaces": "0.4.3" }, "runtime": { "Wabbajack.Downloaders.GoogleDrive.dll": {} } }, - "Wabbajack.Downloaders.Http/0.4.2": { + "Wabbajack.Downloaders.Http/0.4.3": { "dependencies": { "Microsoft.Extensions.DependencyInjection": "9.0.1", "Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.1", "Microsoft.Extensions.Logging.Abstractions": "9.0.1", - "Wabbajack.Common": "0.4.2", - "Wabbajack.DTOs": "0.4.2", - "Wabbajack.Downloaders.Interfaces": "0.4.2", - "Wabbajack.Networking.BethesdaNet": "0.4.2", - "Wabbajack.Networking.Http.Interfaces": "0.4.2", - "Wabbajack.Paths.IO": "0.4.2" + "Wabbajack.Common": "0.4.3", + "Wabbajack.DTOs": "0.4.3", + "Wabbajack.Downloaders.Interfaces": "0.4.3", + "Wabbajack.Networking.BethesdaNet": "0.4.3", + "Wabbajack.Networking.Http.Interfaces": "0.4.3", + "Wabbajack.Paths.IO": "0.4.3" }, "runtime": { "Wabbajack.Downloaders.Http.dll": {} } }, - "Wabbajack.Downloaders.Interfaces/0.4.2": { + "Wabbajack.Downloaders.Interfaces/0.4.3": { "dependencies": { "Microsoft.Extensions.DependencyInjection": "9.0.1", "Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.1", - "Wabbajack.Compression.Zip": "0.4.2", - "Wabbajack.DTOs": "0.4.2", - "Wabbajack.Paths.IO": "0.4.2" + "Wabbajack.Compression.Zip": "0.4.3", + "Wabbajack.DTOs": "0.4.3", + "Wabbajack.Paths.IO": "0.4.3" }, "runtime": { "Wabbajack.Downloaders.Interfaces.dll": {} } }, - "Wabbajack.Downloaders.IPS4OAuth2Downloader/0.4.2": { + "Wabbajack.Downloaders.IPS4OAuth2Downloader/0.4.3": { "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.4.2", - "Wabbajack.Downloaders.Interfaces": "0.4.2", - "Wabbajack.Networking.Http": "0.4.2", - "Wabbajack.Networking.Http.Interfaces": "0.4.2" + "Wabbajack.Common": "0.4.3", + "Wabbajack.Downloaders.Interfaces": "0.4.3", + "Wabbajack.Networking.Http": "0.4.3", + "Wabbajack.Networking.Http.Interfaces": "0.4.3" }, "runtime": { "Wabbajack.Downloaders.IPS4OAuth2Downloader.dll": {} } }, - "Wabbajack.Downloaders.Manual/0.4.2": { + "Wabbajack.Downloaders.Manual/0.4.3": { "dependencies": { "Microsoft.Extensions.DependencyInjection": "9.0.1", "Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.1", "Microsoft.Extensions.Logging.Abstractions": "9.0.1", - "Wabbajack.Common": "0.4.2", - "Wabbajack.Downloaders.Interfaces": "0.4.2" + "Wabbajack.Common": "0.4.3", + "Wabbajack.Downloaders.Interfaces": "0.4.3" }, "runtime": { "Wabbajack.Downloaders.Manual.dll": {} } }, - "Wabbajack.Downloaders.MediaFire/0.4.2": { + "Wabbajack.Downloaders.MediaFire/0.4.3": { "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.4.2", - "Wabbajack.Downloaders.Interfaces": "0.4.2", - "Wabbajack.Networking.Http.Interfaces": "0.4.2" + "Wabbajack.Common": "0.4.3", + "Wabbajack.Downloaders.Interfaces": "0.4.3", + "Wabbajack.Networking.Http.Interfaces": "0.4.3" }, "runtime": { "Wabbajack.Downloaders.MediaFire.dll": {} } }, - "Wabbajack.Downloaders.Mega/0.4.2": { + "Wabbajack.Downloaders.Mega/0.4.3": { "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.4.2", - "Wabbajack.Downloaders.Interfaces": "0.4.2", - "Wabbajack.Paths.IO": "0.4.2" + "Wabbajack.Common": "0.4.3", + "Wabbajack.Downloaders.Interfaces": "0.4.3", + "Wabbajack.Paths.IO": "0.4.3" }, "runtime": { "Wabbajack.Downloaders.Mega.dll": {} } }, - "Wabbajack.Downloaders.ModDB/0.4.2": { + "Wabbajack.Downloaders.ModDB/0.4.3": { "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.4.2", - "Wabbajack.Downloaders.Interfaces": "0.4.2", - "Wabbajack.Networking.Http": "0.4.2", - "Wabbajack.Networking.Http.Interfaces": "0.4.2" + "Wabbajack.Common": "0.4.3", + "Wabbajack.Downloaders.Interfaces": "0.4.3", + "Wabbajack.Networking.Http": "0.4.3", + "Wabbajack.Networking.Http.Interfaces": "0.4.3" }, "runtime": { "Wabbajack.Downloaders.ModDB.dll": {} } }, - "Wabbajack.Downloaders.Nexus/0.4.2": { + "Wabbajack.Downloaders.Nexus/0.4.3": { "dependencies": { "Microsoft.Extensions.DependencyInjection": "9.0.1", "Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.1", - "Wabbajack.DTOs": "0.4.2", - "Wabbajack.Downloaders.Interfaces": "0.4.2", - "Wabbajack.Hashing.xxHash64": "0.4.2", - "Wabbajack.Networking.Http": "0.4.2", - "Wabbajack.Networking.Http.Interfaces": "0.4.2", - "Wabbajack.Networking.NexusApi": "0.4.2", - "Wabbajack.Paths": "0.4.2" + "Wabbajack.DTOs": "0.4.3", + "Wabbajack.Downloaders.Interfaces": "0.4.3", + "Wabbajack.Hashing.xxHash64": "0.4.3", + "Wabbajack.Networking.Http": "0.4.3", + "Wabbajack.Networking.Http.Interfaces": "0.4.3", + "Wabbajack.Networking.NexusApi": "0.4.3", + "Wabbajack.Paths": "0.4.3" }, "runtime": { "Wabbajack.Downloaders.Nexus.dll": {} } }, - "Wabbajack.Downloaders.VerificationCache/0.4.2": { + "Wabbajack.Downloaders.VerificationCache/0.4.3": { "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.4.2", - "Wabbajack.Paths.IO": "0.4.2" + "Wabbajack.DTOs": "0.4.3", + "Wabbajack.Paths.IO": "0.4.3" }, "runtime": { "Wabbajack.Downloaders.VerificationCache.dll": {} } }, - "Wabbajack.Downloaders.WabbajackCDN/0.4.2": { + "Wabbajack.Downloaders.WabbajackCDN/0.4.3": { "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.4.2", - "Wabbajack.Downloaders.Interfaces": "0.4.2", - "Wabbajack.Networking.Http": "0.4.2", - "Wabbajack.RateLimiter": "0.4.2" + "Wabbajack.Common": "0.4.3", + "Wabbajack.Downloaders.Interfaces": "0.4.3", + "Wabbajack.Networking.Http": "0.4.3", + "Wabbajack.RateLimiter": "0.4.3" }, "runtime": { "Wabbajack.Downloaders.WabbajackCDN.dll": {} } }, - "Wabbajack.DTOs/0.4.2": { + "Wabbajack.DTOs/0.4.3": { "dependencies": { "Microsoft.Extensions.DependencyInjection": "9.0.1", "Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.1", - "Wabbajack.Hashing.xxHash64": "0.4.2", - "Wabbajack.Paths": "0.4.2" + "Wabbajack.Hashing.xxHash64": "0.4.3", + "Wabbajack.Paths": "0.4.3" }, "runtime": { "Wabbajack.DTOs.dll": {} } }, - "Wabbajack.FileExtractor/0.4.2": { + "Wabbajack.FileExtractor/0.4.3": { "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.4.2", - "Wabbajack.Compression.BSA": "0.4.2", - "Wabbajack.Hashing.PHash": "0.4.2", - "Wabbajack.Paths": "0.4.2" + "Wabbajack.Common": "0.4.3", + "Wabbajack.Compression.BSA": "0.4.3", + "Wabbajack.Hashing.PHash": "0.4.3", + "Wabbajack.Paths": "0.4.3" }, "runtime": { "Wabbajack.FileExtractor.dll": {} } }, - "Wabbajack.Hashing.PHash/0.4.2": { + "Wabbajack.Hashing.PHash/0.4.3": { "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.4.2", - "Wabbajack.DTOs": "0.4.2", - "Wabbajack.Paths": "0.4.2", - "Wabbajack.Paths.IO": "0.4.2" + "Wabbajack.Common": "0.4.3", + "Wabbajack.DTOs": "0.4.3", + "Wabbajack.Paths": "0.4.3", + "Wabbajack.Paths.IO": "0.4.3" }, "runtime": { "Wabbajack.Hashing.PHash.dll": {} } }, - "Wabbajack.Hashing.xxHash64/0.4.2": { + "Wabbajack.Hashing.xxHash64/0.4.3": { "dependencies": { - "Wabbajack.Paths": "0.4.2", - "Wabbajack.RateLimiter": "0.4.2" + "Wabbajack.Paths": "0.4.3", + "Wabbajack.RateLimiter": "0.4.3" }, "runtime": { "Wabbajack.Hashing.xxHash64.dll": {} } }, - "Wabbajack.Installer/0.4.2": { + "Wabbajack.Installer/0.4.3": { "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.4.2", - "Wabbajack.Downloaders.Dispatcher": "0.4.2", - "Wabbajack.Downloaders.GameFile": "0.4.2", - "Wabbajack.FileExtractor": "0.4.2", - "Wabbajack.Networking.WabbajackClientApi": "0.4.2", - "Wabbajack.Paths": "0.4.2", - "Wabbajack.Paths.IO": "0.4.2", - "Wabbajack.VFS": "0.4.2", + "Wabbajack.DTOs": "0.4.3", + "Wabbajack.Downloaders.Dispatcher": "0.4.3", + "Wabbajack.Downloaders.GameFile": "0.4.3", + "Wabbajack.FileExtractor": "0.4.3", + "Wabbajack.Networking.WabbajackClientApi": "0.4.3", + "Wabbajack.Paths": "0.4.3", + "Wabbajack.Paths.IO": "0.4.3", + "Wabbajack.VFS": "0.4.3", "ini-parser-netstandard": "2.5.2" }, "runtime": { "Wabbajack.Installer.dll": {} } }, - "Wabbajack.IO.Async/0.4.2": { + "Wabbajack.IO.Async/0.4.3": { "runtime": { "Wabbajack.IO.Async.dll": {} } }, - "Wabbajack.Networking.BethesdaNet/0.4.2": { + "Wabbajack.Networking.BethesdaNet/0.4.3": { "dependencies": { "Microsoft.Extensions.DependencyInjection": "9.0.1", "Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.1", - "Wabbajack.DTOs": "0.4.2", - "Wabbajack.Networking.Http": "0.4.2", - "Wabbajack.Networking.Http.Interfaces": "0.4.2" + "Wabbajack.DTOs": "0.4.3", + "Wabbajack.Networking.Http": "0.4.3", + "Wabbajack.Networking.Http.Interfaces": "0.4.3" }, "runtime": { "Wabbajack.Networking.BethesdaNet.dll": {} } }, - "Wabbajack.Networking.Discord/0.4.2": { + "Wabbajack.Networking.Discord/0.4.3": { "dependencies": { "Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.1", "Microsoft.Extensions.Logging.Abstractions": "9.0.1", - "Wabbajack.Networking.Http.Interfaces": "0.4.2" + "Wabbajack.Networking.Http.Interfaces": "0.4.3" }, "runtime": { "Wabbajack.Networking.Discord.dll": {} } }, - "Wabbajack.Networking.GitHub/0.4.2": { + "Wabbajack.Networking.GitHub/0.4.3": { "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.4.2", - "Wabbajack.Networking.Http.Interfaces": "0.4.2" + "Wabbajack.DTOs": "0.4.3", + "Wabbajack.Networking.Http.Interfaces": "0.4.3" }, "runtime": { "Wabbajack.Networking.GitHub.dll": {} } }, - "Wabbajack.Networking.Http/0.4.2": { + "Wabbajack.Networking.Http/0.4.3": { "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.4.2", - "Wabbajack.Downloaders.Interfaces": "0.4.2", - "Wabbajack.Hashing.xxHash64": "0.4.2", - "Wabbajack.Networking.Http.Interfaces": "0.4.2", - "Wabbajack.Paths": "0.4.2", - "Wabbajack.Paths.IO": "0.4.2" + "Wabbajack.Configuration": "0.4.3", + "Wabbajack.Downloaders.Interfaces": "0.4.3", + "Wabbajack.Hashing.xxHash64": "0.4.3", + "Wabbajack.Networking.Http.Interfaces": "0.4.3", + "Wabbajack.Paths": "0.4.3", + "Wabbajack.Paths.IO": "0.4.3" }, "runtime": { "Wabbajack.Networking.Http.dll": {} } }, - "Wabbajack.Networking.Http.Interfaces/0.4.2": { + "Wabbajack.Networking.Http.Interfaces/0.4.3": { "dependencies": { - "Wabbajack.Hashing.xxHash64": "0.4.2" + "Wabbajack.Hashing.xxHash64": "0.4.3" }, "runtime": { "Wabbajack.Networking.Http.Interfaces.dll": {} } }, - "Wabbajack.Networking.NexusApi/0.4.2": { + "Wabbajack.Networking.NexusApi/0.4.3": { "dependencies": { "Microsoft.Extensions.DependencyInjection": "9.0.1", "Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.1", "Microsoft.Extensions.Logging.Abstractions": "9.0.1", - "Wabbajack.DTOs": "0.4.2", - "Wabbajack.Networking.Http": "0.4.2", - "Wabbajack.Networking.Http.Interfaces": "0.4.2", - "Wabbajack.Networking.WabbajackClientApi": "0.4.2" + "Wabbajack.DTOs": "0.4.3", + "Wabbajack.Networking.Http": "0.4.3", + "Wabbajack.Networking.Http.Interfaces": "0.4.3", + "Wabbajack.Networking.WabbajackClientApi": "0.4.3" }, "runtime": { "Wabbajack.Networking.NexusApi.dll": {} } }, - "Wabbajack.Networking.WabbajackClientApi/0.4.2": { + "Wabbajack.Networking.WabbajackClientApi/0.4.3": { "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.4.2", - "Wabbajack.DTOs": "0.4.2", - "Wabbajack.Paths.IO": "0.4.2", - "Wabbajack.VFS.Interfaces": "0.4.2", + "Wabbajack.Common": "0.4.3", + "Wabbajack.DTOs": "0.4.3", + "Wabbajack.Paths.IO": "0.4.3", + "Wabbajack.VFS.Interfaces": "0.4.3", "YamlDotNet": "16.3.0" }, "runtime": { "Wabbajack.Networking.WabbajackClientApi.dll": {} } }, - "Wabbajack.Paths/0.4.2": { + "Wabbajack.Paths/0.4.3": { "runtime": { "Wabbajack.Paths.dll": {} } }, - "Wabbajack.Paths.IO/0.4.2": { + "Wabbajack.Paths.IO/0.4.3": { "dependencies": { - "Wabbajack.Paths": "0.4.2", + "Wabbajack.Paths": "0.4.3", "shortid": "4.0.0" }, "runtime": { "Wabbajack.Paths.IO.dll": {} } }, - "Wabbajack.RateLimiter/0.4.2": { + "Wabbajack.RateLimiter/0.4.3": { "runtime": { "Wabbajack.RateLimiter.dll": {} } }, - "Wabbajack.Server.Lib/0.4.2": { + "Wabbajack.Server.Lib/0.4.3": { "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.4.2", - "Wabbajack.Networking.Http.Interfaces": "0.4.2", - "Wabbajack.Services.OSIntegrated": "0.4.2" + "Wabbajack.Common": "0.4.3", + "Wabbajack.Networking.Http.Interfaces": "0.4.3", + "Wabbajack.Services.OSIntegrated": "0.4.3" }, "runtime": { "Wabbajack.Server.Lib.dll": {} } }, - "Wabbajack.Services.OSIntegrated/0.4.2": { + "Wabbajack.Services.OSIntegrated/0.4.3": { "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.4.2", - "Wabbajack.Downloaders.Dispatcher": "0.4.2", - "Wabbajack.Installer": "0.4.2", - "Wabbajack.Networking.BethesdaNet": "0.4.2", - "Wabbajack.Networking.Discord": "0.4.2", - "Wabbajack.VFS": "0.4.2" + "Wabbajack.Compiler": "0.4.3", + "Wabbajack.Downloaders.Dispatcher": "0.4.3", + "Wabbajack.Installer": "0.4.3", + "Wabbajack.Networking.BethesdaNet": "0.4.3", + "Wabbajack.Networking.Discord": "0.4.3", + "Wabbajack.VFS": "0.4.3" }, "runtime": { "Wabbajack.Services.OSIntegrated.dll": {} } }, - "Wabbajack.VFS/0.4.2": { + "Wabbajack.VFS/0.4.3": { "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.4.2", - "Wabbajack.FileExtractor": "0.4.2", - "Wabbajack.Hashing.PHash": "0.4.2", - "Wabbajack.Hashing.xxHash64": "0.4.2", - "Wabbajack.Paths": "0.4.2", - "Wabbajack.Paths.IO": "0.4.2", - "Wabbajack.VFS.Interfaces": "0.4.2" + "Wabbajack.Common": "0.4.3", + "Wabbajack.FileExtractor": "0.4.3", + "Wabbajack.Hashing.PHash": "0.4.3", + "Wabbajack.Hashing.xxHash64": "0.4.3", + "Wabbajack.Paths": "0.4.3", + "Wabbajack.Paths.IO": "0.4.3", + "Wabbajack.VFS.Interfaces": "0.4.3" }, "runtime": { "Wabbajack.VFS.dll": {} } }, - "Wabbajack.VFS.Interfaces/0.4.2": { + "Wabbajack.VFS.Interfaces/0.4.3": { "dependencies": { "Microsoft.Extensions.DependencyInjection": "9.0.1", "Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.1", - "Wabbajack.DTOs": "0.4.2", - "Wabbajack.Hashing.xxHash64": "0.4.2", - "Wabbajack.Paths": "0.4.2" + "Wabbajack.DTOs": "0.4.3", + "Wabbajack.Hashing.xxHash64": "0.4.3", + "Wabbajack.Paths": "0.4.3" }, "runtime": { "Wabbajack.VFS.Interfaces.dll": {} @@ -2332,7 +2332,7 @@ } }, "libraries": { - "jackify-engine/0.4.2": { + "jackify-engine/0.4.3": { "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.4.2": { + "Wabbajack.CLI.Builder/0.4.3": { "type": "project", "serviceable": false, "sha512": "" }, - "Wabbajack.Common/0.4.2": { + "Wabbajack.Common/0.4.3": { "type": "project", "serviceable": false, "sha512": "" }, - "Wabbajack.Compiler/0.4.2": { + "Wabbajack.Compiler/0.4.3": { "type": "project", "serviceable": false, "sha512": "" }, - "Wabbajack.Compression.BSA/0.4.2": { + "Wabbajack.Compression.BSA/0.4.3": { "type": "project", "serviceable": false, "sha512": "" }, - "Wabbajack.Compression.Zip/0.4.2": { + "Wabbajack.Compression.Zip/0.4.3": { "type": "project", "serviceable": false, "sha512": "" }, - "Wabbajack.Configuration/0.4.2": { + "Wabbajack.Configuration/0.4.3": { "type": "project", "serviceable": false, "sha512": "" }, - "Wabbajack.Downloaders.Bethesda/0.4.2": { + "Wabbajack.Downloaders.Bethesda/0.4.3": { "type": "project", "serviceable": false, "sha512": "" }, - "Wabbajack.Downloaders.Dispatcher/0.4.2": { + "Wabbajack.Downloaders.Dispatcher/0.4.3": { "type": "project", "serviceable": false, "sha512": "" }, - "Wabbajack.Downloaders.GameFile/0.4.2": { + "Wabbajack.Downloaders.GameFile/0.4.3": { "type": "project", "serviceable": false, "sha512": "" }, - "Wabbajack.Downloaders.GoogleDrive/0.4.2": { + "Wabbajack.Downloaders.GoogleDrive/0.4.3": { "type": "project", "serviceable": false, "sha512": "" }, - "Wabbajack.Downloaders.Http/0.4.2": { + "Wabbajack.Downloaders.Http/0.4.3": { "type": "project", "serviceable": false, "sha512": "" }, - "Wabbajack.Downloaders.Interfaces/0.4.2": { + "Wabbajack.Downloaders.Interfaces/0.4.3": { "type": "project", "serviceable": false, "sha512": "" }, - "Wabbajack.Downloaders.IPS4OAuth2Downloader/0.4.2": { + "Wabbajack.Downloaders.IPS4OAuth2Downloader/0.4.3": { "type": "project", "serviceable": false, "sha512": "" }, - "Wabbajack.Downloaders.Manual/0.4.2": { + "Wabbajack.Downloaders.Manual/0.4.3": { "type": "project", "serviceable": false, "sha512": "" }, - "Wabbajack.Downloaders.MediaFire/0.4.2": { + "Wabbajack.Downloaders.MediaFire/0.4.3": { "type": "project", "serviceable": false, "sha512": "" }, - "Wabbajack.Downloaders.Mega/0.4.2": { + "Wabbajack.Downloaders.Mega/0.4.3": { "type": "project", "serviceable": false, "sha512": "" }, - "Wabbajack.Downloaders.ModDB/0.4.2": { + "Wabbajack.Downloaders.ModDB/0.4.3": { "type": "project", "serviceable": false, "sha512": "" }, - "Wabbajack.Downloaders.Nexus/0.4.2": { + "Wabbajack.Downloaders.Nexus/0.4.3": { "type": "project", "serviceable": false, "sha512": "" }, - "Wabbajack.Downloaders.VerificationCache/0.4.2": { + "Wabbajack.Downloaders.VerificationCache/0.4.3": { "type": "project", "serviceable": false, "sha512": "" }, - "Wabbajack.Downloaders.WabbajackCDN/0.4.2": { + "Wabbajack.Downloaders.WabbajackCDN/0.4.3": { "type": "project", "serviceable": false, "sha512": "" }, - "Wabbajack.DTOs/0.4.2": { + "Wabbajack.DTOs/0.4.3": { "type": "project", "serviceable": false, "sha512": "" }, - "Wabbajack.FileExtractor/0.4.2": { + "Wabbajack.FileExtractor/0.4.3": { "type": "project", "serviceable": false, "sha512": "" }, - "Wabbajack.Hashing.PHash/0.4.2": { + "Wabbajack.Hashing.PHash/0.4.3": { "type": "project", "serviceable": false, "sha512": "" }, - "Wabbajack.Hashing.xxHash64/0.4.2": { + "Wabbajack.Hashing.xxHash64/0.4.3": { "type": "project", "serviceable": false, "sha512": "" }, - "Wabbajack.Installer/0.4.2": { + "Wabbajack.Installer/0.4.3": { "type": "project", "serviceable": false, "sha512": "" }, - "Wabbajack.IO.Async/0.4.2": { + "Wabbajack.IO.Async/0.4.3": { "type": "project", "serviceable": false, "sha512": "" }, - "Wabbajack.Networking.BethesdaNet/0.4.2": { + "Wabbajack.Networking.BethesdaNet/0.4.3": { "type": "project", "serviceable": false, "sha512": "" }, - "Wabbajack.Networking.Discord/0.4.2": { + "Wabbajack.Networking.Discord/0.4.3": { "type": "project", "serviceable": false, "sha512": "" }, - "Wabbajack.Networking.GitHub/0.4.2": { + "Wabbajack.Networking.GitHub/0.4.3": { "type": "project", "serviceable": false, "sha512": "" }, - "Wabbajack.Networking.Http/0.4.2": { + "Wabbajack.Networking.Http/0.4.3": { "type": "project", "serviceable": false, "sha512": "" }, - "Wabbajack.Networking.Http.Interfaces/0.4.2": { + "Wabbajack.Networking.Http.Interfaces/0.4.3": { "type": "project", "serviceable": false, "sha512": "" }, - "Wabbajack.Networking.NexusApi/0.4.2": { + "Wabbajack.Networking.NexusApi/0.4.3": { "type": "project", "serviceable": false, "sha512": "" }, - "Wabbajack.Networking.WabbajackClientApi/0.4.2": { + "Wabbajack.Networking.WabbajackClientApi/0.4.3": { "type": "project", "serviceable": false, "sha512": "" }, - "Wabbajack.Paths/0.4.2": { + "Wabbajack.Paths/0.4.3": { "type": "project", "serviceable": false, "sha512": "" }, - "Wabbajack.Paths.IO/0.4.2": { + "Wabbajack.Paths.IO/0.4.3": { "type": "project", "serviceable": false, "sha512": "" }, - "Wabbajack.RateLimiter/0.4.2": { + "Wabbajack.RateLimiter/0.4.3": { "type": "project", "serviceable": false, "sha512": "" }, - "Wabbajack.Server.Lib/0.4.2": { + "Wabbajack.Server.Lib/0.4.3": { "type": "project", "serviceable": false, "sha512": "" }, - "Wabbajack.Services.OSIntegrated/0.4.2": { + "Wabbajack.Services.OSIntegrated/0.4.3": { "type": "project", "serviceable": false, "sha512": "" }, - "Wabbajack.VFS/0.4.2": { + "Wabbajack.VFS/0.4.3": { "type": "project", "serviceable": false, "sha512": "" }, - "Wabbajack.VFS.Interfaces/0.4.2": { + "Wabbajack.VFS.Interfaces/0.4.3": { "type": "project", "serviceable": false, "sha512": "" diff --git a/jackify/engine/jackify-engine.dll b/jackify/engine/jackify-engine.dll index 8efae9c..b06e9c6 100644 Binary files a/jackify/engine/jackify-engine.dll and b/jackify/engine/jackify-engine.dll differ diff --git a/jackify/frontends/gui/main.py b/jackify/frontends/gui/main.py index dfa3a14..fa0d350 100644 --- a/jackify/frontends/gui/main.py +++ b/jackify/frontends/gui/main.py @@ -105,7 +105,7 @@ from PySide6.QtWidgets import ( QApplication, QMainWindow, QWidget, QLabel, QVBoxLayout, QPushButton, QStackedWidget, QHBoxLayout, QDialog, QFormLayout, QLineEdit, QCheckBox, QSpinBox, QMessageBox, QGroupBox, QGridLayout, QFileDialog, QToolButton, QStyle, QComboBox, QTabWidget, QRadioButton, QButtonGroup ) -from PySide6.QtCore import Qt, QEvent, QTimer +from PySide6.QtCore import Qt, QEvent, QTimer, QThread, Signal from PySide6.QtGui import QIcon import json @@ -1533,58 +1533,42 @@ class JackifyMainWindow(QMainWindow): # Continue anyway - don't block startup on detection errors def _check_for_updates_on_startup(self): - """Check for updates on startup - SIMPLE VERSION""" + """Check for updates on startup - non-blocking background check""" try: debug_print("Checking for updates on startup...") - # Do it synchronously and simply - update_info = self.update_service.check_for_updates() - if update_info: + # Run update check in background thread to avoid blocking GUI startup + class UpdateCheckThread(QThread): + update_available = Signal(object) # Signal to pass update_info to main thread + + def __init__(self, update_service): + super().__init__() + self.update_service = update_service + + def run(self): + update_info = self.update_service.check_for_updates() + if update_info: + self.update_available.emit(update_info) + + def on_update_available(update_info): + """Handle update check result in main thread""" debug_print(f"Update available: v{update_info.version}") - # Simple QMessageBox - no complex dialogs - from PySide6.QtWidgets import QMessageBox - from PySide6.QtCore import QTimer - + # Show update dialog after a short delay to ensure GUI is fully loaded def show_update_dialog(): - try: - debug_print("Creating UpdateDialog...") - from jackify.frontends.gui.dialogs.update_dialog import UpdateDialog - dialog = UpdateDialog(update_info, self.update_service, self) - debug_print("UpdateDialog created, showing...") - dialog.show() # Non-blocking - debug_print("UpdateDialog shown successfully") - except Exception as e: - debug_print(f"UpdateDialog failed: {e}, falling back to simple dialog") - # Fallback to simple dialog - reply = QMessageBox.question( - self, - "Update Available", - f"Jackify v{update_info.version} is available.\n\nDownload and install now?", - QMessageBox.Yes | QMessageBox.No, - QMessageBox.Yes - ) - if reply == QMessageBox.Yes: - # Simple download and replace - try: - new_appimage = self.update_service.download_update(update_info) - if new_appimage: - if self.update_service.apply_update(new_appimage): - debug_print("Update applied successfully") - else: - QMessageBox.warning(self, "Update Failed", "Failed to apply update.") - else: - QMessageBox.warning(self, "Update Failed", "Failed to download update.") - except Exception as e: - QMessageBox.warning(self, "Update Failed", f"Update failed: {e}") + from ..dialogs.update_dialog import UpdateDialog + dialog = UpdateDialog(update_info, self.update_service, self) + dialog.exec() - # Use QTimer to show dialog after GUI is fully loaded QTimer.singleShot(1000, show_update_dialog) - else: - debug_print("No updates available") - + + # Start background thread + self._update_thread = UpdateCheckThread(self.update_service) + self._update_thread.update_available.connect(on_update_available) + self._update_thread.start() + except Exception as e: - debug_print(f"Error checking for updates on startup: {e}") + debug_print(f"Error setting up update check: {e}") # Continue anyway - don't block startup on update check errors def cleanup_processes(self): diff --git a/jackify/frontends/gui/screens/install_modlist.py b/jackify/frontends/gui/screens/install_modlist.py index 12c76e1..46eb6a9 100644 --- a/jackify/frontends/gui/screens/install_modlist.py +++ b/jackify/frontends/gui/screens/install_modlist.py @@ -2157,12 +2157,6 @@ class InstallModlistScreen(QWidget): cmd.append('--debug') debug_print("DEBUG: Added --debug flag to jackify-engine command") - # Check GPU setting and add --no-gpu flag if disabled - gpu_enabled = config_handler.get('enable_gpu_texture_conversion', True) - if not gpu_enabled: - cmd.append('--no-gpu') - debug_print("DEBUG: Added --no-gpu flag (GPU texture conversion disabled)") - # CRITICAL: Print the FULL command so we can see exactly what's being passed debug_print(f"DEBUG: FULL Engine command: {' '.join(cmd)}") debug_print(f"DEBUG: modlist value being passed: '{self.modlist}'") diff --git a/jackify/frontends/gui/screens/modlist_gallery.py b/jackify/frontends/gui/screens/modlist_gallery.py index e1e7b9a..6c7ebdf 100644 --- a/jackify/frontends/gui/screens/modlist_gallery.py +++ b/jackify/frontends/gui/screens/modlist_gallery.py @@ -388,6 +388,15 @@ class ModlistDetailDialog(QDialog): main_layout = QVBoxLayout() main_layout.setContentsMargins(0, 0, 0, 0) main_layout.setSpacing(0) + # --- Banner area with full-width text overlay --- + # Container so we can place a semi-opaque text panel over the banner image + banner_container = QFrame() + banner_container.setFrameShape(QFrame.NoFrame) + banner_container.setStyleSheet("background: #000; border: none;") + banner_layout = QVBoxLayout() + banner_layout.setContentsMargins(0, 0, 0, 0) + banner_layout.setSpacing(0) + banner_container.setLayout(banner_layout) # Banner image at top with 16:9 aspect ratio (like Wabbajack) self.banner_label = QLabel() @@ -396,40 +405,67 @@ class ModlistDetailDialog(QDialog): self.banner_label.setStyleSheet("background: #1a1a1a; border: none;") self.banner_label.setAlignment(Qt.AlignCenter) self.banner_label.setText("Loading image...") - main_layout.addWidget(self.banner_label) + banner_layout.addWidget(self.banner_label) - # Content area with padding + # Full-width transparent container with opaque card inside (only as wide as text) + overlay_container = QWidget() + overlay_container.setStyleSheet("background: transparent;") + overlay_layout = QHBoxLayout() + overlay_layout.setContentsMargins(24, 0, 24, 24) + overlay_layout.setSpacing(0) + overlay_container.setLayout(overlay_layout) + + # Opaque text card - only as wide as content needs (where red lines are) + self.banner_text_panel = QFrame() + self.banner_text_panel.setFrameShape(QFrame.StyledPanel) + # Opaque background, rounded corners, sized to content only + self.banner_text_panel.setStyleSheet(""" + QFrame { + background-color: rgba(0, 0, 0, 180); + border: 1px solid rgba(255, 255, 255, 30); + border-radius: 8px; + } + """) + self.banner_text_panel.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Maximum) + banner_text_layout = QVBoxLayout() + banner_text_layout.setContentsMargins(20, 12, 20, 14) + banner_text_layout.setSpacing(6) + self.banner_text_panel.setLayout(banner_text_layout) + + # Add card to container (left-aligned, rest stays transparent) + overlay_layout.addWidget(self.banner_text_panel, alignment=Qt.AlignBottom | Qt.AlignLeft) + overlay_layout.addStretch() # Push card left, rest transparent + + # Title only (badges moved to tags section below) + title = QLabel(self.metadata.title) + title.setFont(QFont("Sans", 24, QFont.Bold)) + title.setStyleSheet(f"color: {JACKIFY_COLOR_BLUE};") + title.setWordWrap(True) + banner_text_layout.addWidget(title) + + # Only sizes in overlay (minimal info on image) + if self.metadata.sizes: + sizes_text = ( + f"Download: {self.metadata.sizes.downloadSizeFormatted} • " + f"Install: {self.metadata.sizes.installSizeFormatted} • " + f"Total: {self.metadata.sizes.totalSizeFormatted}" + ) + sizes_label = QLabel(sizes_text) + sizes_label.setStyleSheet("color: #fff; font-size: 13px;") + banner_text_layout.addWidget(sizes_label) + + # Add full-width transparent container at bottom of banner + banner_layout.addWidget(overlay_container, alignment=Qt.AlignBottom) + main_layout.addWidget(banner_container) + + # Content area with padding (tags + description + bottom bar) content_widget = QWidget() content_layout = QVBoxLayout() content_layout.setContentsMargins(24, 20, 24, 20) content_layout.setSpacing(16) content_widget.setLayout(content_layout) - # Title row with status badges (UNAVAILABLE, Unofficial - Official and NSFW shown in tags) - title_row = QHBoxLayout() - title_row.setSpacing(12) - - title = QLabel(self.metadata.title) - title.setFont(QFont("Sans", 24, QFont.Bold)) - title.setStyleSheet(f"color: {JACKIFY_COLOR_BLUE};") - title.setWordWrap(True) - title_row.addWidget(title, stretch=1) - - # Status badges in title row - if not self.metadata.is_available(): - unavailable_badge = QLabel("UNAVAILABLE") - unavailable_badge.setStyleSheet("background: #666; color: white; padding: 4px 10px; font-size: 10px; font-weight: bold; border-radius: 4px;") - title_row.addWidget(unavailable_badge) - - # Show "Unofficial" badge if not official (Official is shown in tags) - if not self.metadata.official: - unofficial_badge = QLabel("Unofficial") - unofficial_badge.setStyleSheet("background: #666; color: white; padding: 4px 10px; font-size: 10px; font-weight: bold; border-radius: 4px;") - title_row.addWidget(unofficial_badge) - - content_layout.addLayout(title_row) - - # Metadata line (version, author, game) - inline like Wabbajack + # Metadata line (version, author, game) - moved below image metadata_line_parts = [] if self.metadata.version: metadata_line_parts.append(f"version {self.metadata.version}") @@ -446,13 +482,25 @@ class ModlistDetailDialog(QDialog): metadata_line.setWordWrap(True) content_layout.addWidget(metadata_line) - # Tags row (like Wabbajack) + # Tags row (includes status badges moved from overlay) + tags_layout = QHBoxLayout() + tags_layout.setSpacing(6) + tags_layout.setContentsMargins(0, 0, 0, 0) + + # Add status badges first (UNAVAILABLE, Unofficial) + if not self.metadata.is_available(): + unavailable_badge = QLabel("UNAVAILABLE") + unavailable_badge.setStyleSheet("background: #666; color: white; padding: 6px 12px; font-size: 11px; border-radius: 4px;") + tags_layout.addWidget(unavailable_badge) + + if not self.metadata.official: + unofficial_badge = QLabel("Unofficial") + unofficial_badge.setStyleSheet("background: #666; color: white; padding: 6px 12px; font-size: 11px; border-radius: 4px;") + tags_layout.addWidget(unofficial_badge) + + # Add regular tags tags_to_render = getattr(self.metadata, 'normalized_tags_display', self.metadata.tags or []) if tags_to_render: - tags_layout = QHBoxLayout() - tags_layout.setSpacing(6) - tags_layout.setContentsMargins(0, 0, 0, 0) - for tag in tags_to_render: tag_badge = QLabel(tag) # Match Wabbajack tag styling @@ -463,20 +511,9 @@ class ModlistDetailDialog(QDialog): else: tag_badge.setStyleSheet("background: #3a3a3a; color: #ccc; padding: 6px 12px; font-size: 11px; border-radius: 4px;") tags_layout.addWidget(tag_badge) - - tags_layout.addStretch() - content_layout.addLayout(tags_layout) - - # Sizes (if available) - if self.metadata.sizes: - sizes_text = ( - f"Download: {self.metadata.sizes.downloadSizeFormatted} • " - f"Install: {self.metadata.sizes.installSizeFormatted} • " - f"Total: {self.metadata.sizes.totalSizeFormatted}" - ) - sizes_label = QLabel(sizes_text) - sizes_label.setStyleSheet("color: #fff; font-size: 13px;") - content_layout.addWidget(sizes_label) + + tags_layout.addStretch() + content_layout.addLayout(tags_layout) # Description section desc_label = QLabel("Description:") @@ -486,7 +523,8 @@ class ModlistDetailDialog(QDialog): self.desc_text = QTextEdit() self.desc_text.setReadOnly(True) self.desc_text.setPlainText(self.metadata.description or "No description provided.") - self.desc_text.setFixedHeight(300) + # Compact description area; scroll when content is long + self.desc_text.setFixedHeight(120) self.desc_text.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded) self.desc_text.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.desc_text.setLineWrapMode(QTextEdit.WidgetWidth) @@ -832,8 +870,8 @@ class ModlistGalleryDialog(QDialog): main_layout.addWidget(filter_panel) # Right content area (modlist grid) - content_area = self._create_content_area() - main_layout.addWidget(content_area, stretch=1) + self.content_area = self._create_content_area() + main_layout.addWidget(self.content_area, stretch=1) self.setLayout(main_layout) @@ -934,8 +972,8 @@ class ModlistGalleryDialog(QDialog): layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(12) - # Status label (subtle, top-right) - self.status_label = QLabel("Loading modlists...") + # Status label (subtle, top-right) - hidden during initial loading (popup shows instead) + self.status_label = QLabel("") self.status_label.setStyleSheet("color: #888; font-size: 10px;") self.status_label.setAlignment(Qt.AlignRight | Qt.AlignTop) layout.addWidget(self.status_label) @@ -965,13 +1003,55 @@ class ModlistGalleryDialog(QDialog): from PySide6.QtCore import QThread, Signal from PySide6.QtGui import QFont - # Make status label more prominent during loading - self.status_label.setText("Loading modlists...") + # Hide status label during loading (popup dialog will show instead) + self.status_label.setVisible(False) + + # Show loading overlay directly in content area (simpler than separate dialog) + self._loading_overlay = QWidget(self.content_area) + self._loading_overlay.setStyleSheet(""" + QWidget { + background-color: rgba(35, 35, 35, 240); + border-radius: 8px; + } + """) + overlay_layout = QVBoxLayout() + overlay_layout.setContentsMargins(30, 20, 30, 20) + overlay_layout.setSpacing(12) + + self._loading_label = QLabel("Loading modlists") + self._loading_label.setAlignment(Qt.AlignCenter) + # Set fixed width to prevent text shifting when dots animate + # Width accommodates "Loading modlists..." (longest version) + self._loading_label.setFixedWidth(220) font = QFont() font.setPointSize(14) font.setBold(True) - self.status_label.setFont(font) - self.status_label.setStyleSheet(f"color: {JACKIFY_COLOR_BLUE}; font-size: 14px; font-weight: bold;") + self._loading_label.setFont(font) + self._loading_label.setStyleSheet(f"color: {JACKIFY_COLOR_BLUE}; font-size: 14px; font-weight: bold;") + overlay_layout.addWidget(self._loading_label) + + self._loading_overlay.setLayout(overlay_layout) + self._loading_overlay.setFixedSize(300, 120) + + # Animate dots in loading message + self._loading_dot_count = 0 + self._loading_dot_timer = QTimer() + self._loading_dot_timer.timeout.connect(self._animate_loading_dots) + self._loading_dot_timer.start(500) # Update every 500ms + + # Position overlay in center of content area + def position_overlay(): + if hasattr(self, 'content_area') and self.content_area.isVisible(): + content_width = self.content_area.width() + content_height = self.content_area.height() + x = (content_width - 300) // 2 + y = (content_height - 120) // 2 + self._loading_overlay.move(x, y) + self._loading_overlay.show() + self._loading_overlay.raise_() + + # Delay slightly to ensure content_area is laid out + QTimer.singleShot(50, position_overlay) class ModlistLoaderThread(QThread): """Background thread to load modlist metadata""" @@ -987,9 +1067,10 @@ class ModlistGalleryDialog(QDialog): start_time = time.time() # Fetch metadata (CPU-intensive work happens here in background) + # Skip search index initially for faster loading - can be loaded later if user searches metadata_response = self.gallery_service.fetch_modlist_metadata( include_validation=False, - include_search_index=True, + include_search_index=False, # Skip for faster initial load sort_by="title" ) @@ -1010,17 +1091,31 @@ class ModlistGalleryDialog(QDialog): self._loader_thread.finished.connect(self._on_modlists_loaded) self._loader_thread.start() + def _animate_loading_dots(self): + """Animate dots in loading message""" + if hasattr(self, '_loading_label') and self._loading_label: + self._loading_dot_count = (self._loading_dot_count + 1) % 4 + dots = "." * self._loading_dot_count + # Pad with spaces to keep text width constant (prevents shifting) + padding = " " * (3 - self._loading_dot_count) + self._loading_label.setText(f"Loading modlists{dots}{padding}") + def _on_modlists_loaded(self, metadata_response, error_message): """Handle modlist metadata loaded in background thread (runs in GUI thread)""" import random - from PySide6.QtCore import QTimer from PySide6.QtGui import QFont - # Restore normal status label styling - font = QFont() - font.setPointSize(10) - self.status_label.setFont(font) - self.status_label.setStyleSheet("color: #888; font-size: 10px;") + # Stop animation timer and close loading overlay + if hasattr(self, '_loading_dot_timer') and self._loading_dot_timer: + self._loading_dot_timer.stop() + self._loading_dot_timer = None + + if hasattr(self, '_loading_overlay') and self._loading_overlay: + self._loading_overlay.hide() + self._loading_overlay.deleteLater() + self._loading_overlay = None + + self.status_label.setVisible(True) if error_message: self.status_label.setText(f"Error loading modlists: {error_message}")