mirror of
https://github.com/Omni-guides/Jackify.git
synced 2026-01-17 11:37:01 +01:00
Sync from development - prepare for v0.2.0.10
This commit is contained in:
21
CHANGELOG.md
21
CHANGELOG.md
@@ -1,5 +1,26 @@
|
||||
# Jackify Changelog
|
||||
|
||||
## v0.2.0.10 - Registry & Hashing Fixes
|
||||
**Release Date:** 2025-01-04
|
||||
|
||||
### Engine Updates
|
||||
- **jackify-engine 0.4.5**: Fixed archive extraction with backslashes (including pattern matching), data directory path configuration, and removed post-download .wabbajack hash validation. Engine now auto-refreshes OAuth tokens during long installations via `NEXUS_OAUTH_INFO` environment variable.
|
||||
|
||||
### Critical Bug Fixes
|
||||
- **InstallationThread Crash**: Fixed crash during installation with error "'InstallationThread' object has no attribute 'auth_service'". Premium detection diagnostics code assumed auth_service existed but it was never passed to the thread. Affects all users when Premium detection (including false positives) is triggered.
|
||||
- **Install Start Hang**: Fixed missing `oauth_info` parameter that prevented modlist installs from starting (hung at "Starting modlist installation...")
|
||||
- **OAuth Token Auto-Refresh**: Fixed OAuth tokens expiring during long modlist installations. Jackify now refreshes tokens with 15-minute buffer before passing to engine. Engine receives full OAuth state via `NEXUS_OAUTH_INFO` environment variable, enabling automatic token refresh during multi-hour downloads. Fixes "Token has expired" errors that occurred 60 minutes into installations.
|
||||
- **ShowDotFiles Registry Format**: Fixed Wine registry format bug causing hidden files to remain hidden in prefixes. Python string escaping issue wrote single backslash instead of double backslash in `[Software\\Wine]` section header. Added auto-detection and fix for broken format from curated registry files.
|
||||
- **Dotnet4 Registry Fixes**: Confirmed universal dotnet4.x registry fixes (`*mscoree=native` and `OnlyUseLatestCLR=1`) are applied in all three workflows (Install, Configure New, Configure Existing) across both CLI and GUI interfaces
|
||||
- **Proton Path Configuration**: Fixed `proton_path` writing invalid "auto" string to config.json - now uses `null` instead, preventing jackify-engine from receiving invalid paths
|
||||
|
||||
### Improvements
|
||||
- **Wine Binary Detection**: Enhanced detection with recursive fallback search within Proton directory when expected paths don't exist (handles different Proton version structures)
|
||||
- Added Jackify version logging at workflow start
|
||||
- Fixed GUI log file rotation to only run in debug mode
|
||||
|
||||
---
|
||||
|
||||
## v0.2.0.9 - Critical Configuration Fixes
|
||||
**Release Date:** 2025-12-31
|
||||
|
||||
|
||||
@@ -5,4 +5,4 @@ This package provides both CLI and GUI interfaces for managing
|
||||
Wabbajack modlists natively on Linux systems.
|
||||
"""
|
||||
|
||||
__version__ = "0.2.0.9"
|
||||
__version__ = "0.2.0.10"
|
||||
|
||||
@@ -34,7 +34,7 @@ def _get_user_proton_version():
|
||||
# get_proton_path() returns the Install Proton path
|
||||
user_proton_path = config_handler.get_proton_path()
|
||||
|
||||
if user_proton_path == 'auto':
|
||||
if not user_proton_path or user_proton_path == 'auto':
|
||||
# Use enhanced fallback logic with GE-Proton preference
|
||||
logging.info("User selected auto-detect, using GE-Proton → Experimental → Proton precedence")
|
||||
return WineUtils.select_best_proton()
|
||||
@@ -502,10 +502,11 @@ class ModlistInstallCLI:
|
||||
print("\n" + "-" * 28)
|
||||
print(f"{COLOR_INFO}Nexus Authentication: Using API Key (Legacy){COLOR_RESET}")
|
||||
|
||||
# Get valid token/key
|
||||
api_key = auth_service.ensure_valid_auth()
|
||||
# Get valid token/key and OAuth state for engine auto-refresh
|
||||
api_key, oauth_info = auth_service.get_auth_for_engine()
|
||||
if api_key:
|
||||
self.context['nexus_api_key'] = api_key
|
||||
self.context['nexus_oauth_info'] = oauth_info # For engine auto-refresh
|
||||
else:
|
||||
# Auth expired or invalid - prompt to set up
|
||||
print(f"\n{COLOR_WARNING}Your authentication has expired or is invalid.{COLOR_RESET}")
|
||||
@@ -538,9 +539,10 @@ class ModlistInstallCLI:
|
||||
if username:
|
||||
print(f"{COLOR_INFO}Authorized as: {username}{COLOR_RESET}")
|
||||
|
||||
api_key = auth_service.ensure_valid_auth()
|
||||
api_key, oauth_info = auth_service.get_auth_for_engine()
|
||||
if api_key:
|
||||
self.context['nexus_api_key'] = api_key
|
||||
self.context['nexus_oauth_info'] = oauth_info # For engine auto-refresh
|
||||
else:
|
||||
print(f"{COLOR_ERROR}Failed to retrieve auth token after authorization.{COLOR_RESET}")
|
||||
return None
|
||||
@@ -738,6 +740,7 @@ class ModlistInstallCLI:
|
||||
modlist_arg = self.context.get('modlist_value') or self.context.get('machineid')
|
||||
machineid = self.context.get('machineid')
|
||||
api_key = self.context.get('nexus_api_key')
|
||||
oauth_info = self.context.get('nexus_oauth_info')
|
||||
|
||||
# Path to the engine binary
|
||||
engine_path = get_jackify_engine_path()
|
||||
@@ -779,24 +782,37 @@ class ModlistInstallCLI:
|
||||
# Store original environment values to restore later
|
||||
original_env_values = {
|
||||
'NEXUS_API_KEY': os.environ.get('NEXUS_API_KEY'),
|
||||
'NEXUS_OAUTH_INFO': os.environ.get('NEXUS_OAUTH_INFO'),
|
||||
'DOTNET_SYSTEM_GLOBALIZATION_INVARIANT': os.environ.get('DOTNET_SYSTEM_GLOBALIZATION_INVARIANT')
|
||||
}
|
||||
|
||||
try:
|
||||
# Temporarily modify current process's environment
|
||||
# Prefer NEXUS_OAUTH_INFO (supports auto-refresh) over NEXUS_API_KEY (legacy)
|
||||
if oauth_info:
|
||||
os.environ['NEXUS_OAUTH_INFO'] = oauth_info
|
||||
self.logger.debug(f"Set NEXUS_OAUTH_INFO for engine (supports auto-refresh)")
|
||||
# Also set NEXUS_API_KEY for backward compatibility
|
||||
if api_key:
|
||||
os.environ['NEXUS_API_KEY'] = api_key
|
||||
self.logger.debug(f"Temporarily set os.environ['NEXUS_API_KEY'] for engine call using session-provided key.")
|
||||
elif 'NEXUS_API_KEY' in os.environ: # api_key is None/empty, but a system key might exist
|
||||
self.logger.debug(f"Session API key not provided. Temporarily removing inherited NEXUS_API_KEY ('{'[REDACTED]' if os.environ.get('NEXUS_API_KEY') else 'None'}') from os.environ for engine call to ensure it is not used.")
|
||||
elif api_key:
|
||||
# No OAuth info, use API key only (no auto-refresh support)
|
||||
os.environ['NEXUS_API_KEY'] = api_key
|
||||
self.logger.debug(f"Set NEXUS_API_KEY for engine (no auto-refresh)")
|
||||
else:
|
||||
# No auth available, clear any inherited values
|
||||
if 'NEXUS_API_KEY' in os.environ:
|
||||
del os.environ['NEXUS_API_KEY']
|
||||
# If api_key is None and NEXUS_API_KEY was not in os.environ, it remains unset, which is correct.
|
||||
if 'NEXUS_OAUTH_INFO' in os.environ:
|
||||
del os.environ['NEXUS_OAUTH_INFO']
|
||||
self.logger.debug(f"No Nexus auth available, cleared inherited env vars")
|
||||
|
||||
os.environ['DOTNET_SYSTEM_GLOBALIZATION_INVARIANT'] = "1"
|
||||
self.logger.debug(f"Temporarily set os.environ['DOTNET_SYSTEM_GLOBALIZATION_INVARIANT'] = '1' for engine call.")
|
||||
|
||||
self.logger.info("Environment prepared for jackify-engine install process by modifying os.environ.")
|
||||
self.logger.debug(f"NEXUS_API_KEY in os.environ (pre-call): {'[SET]' if os.environ.get('NEXUS_API_KEY') else '[NOT SET]'}")
|
||||
self.logger.debug(f"NEXUS_OAUTH_INFO in os.environ (pre-call): {'[SET]' if os.environ.get('NEXUS_OAUTH_INFO') else '[NOT SET]'}")
|
||||
|
||||
pretty_cmd = ' '.join([f'"{arg}"' if ' ' in arg else arg for arg in cmd])
|
||||
print(f"{COLOR_INFO}Launching Jackify Install Engine with command:{COLOR_RESET} {pretty_cmd}")
|
||||
|
||||
@@ -58,6 +58,8 @@ class ConfigHandler:
|
||||
"use_winetricks_for_components": True, # DEPRECATED: Migrated to component_installation_method. Kept for backward compatibility.
|
||||
"component_installation_method": "winetricks", # "winetricks" (default) or "system_protontricks"
|
||||
"game_proton_path": None, # Proton version for game shortcuts (can be any Proton 9+), separate from install proton
|
||||
"proton_path": None, # Install Proton path (for jackify-engine) - None means auto-detect
|
||||
"proton_version": None, # Install Proton version name - None means auto-detect
|
||||
"steam_restart_strategy": "jackify", # "jackify" (default) or "nak_simple"
|
||||
"window_width": None, # Saved window width (None = use dynamic sizing)
|
||||
"window_height": None # Saved window height (None = use dynamic sizing)
|
||||
@@ -757,16 +759,20 @@ class ConfigHandler:
|
||||
Always reads fresh from disk.
|
||||
|
||||
Returns:
|
||||
str: Saved Install Proton path or 'auto' if not saved
|
||||
str: Saved Install Proton path, or None if not set (indicates auto-detect mode)
|
||||
"""
|
||||
try:
|
||||
config = self._read_config_from_disk()
|
||||
proton_path = config.get("proton_path", "auto")
|
||||
proton_path = config.get("proton_path")
|
||||
# Return None if missing/None/empty string - don't default to "auto"
|
||||
if not proton_path:
|
||||
logger.debug("proton_path not set in config - will use auto-detection")
|
||||
return None
|
||||
logger.debug(f"Retrieved fresh install proton_path from config: {proton_path}")
|
||||
return proton_path
|
||||
except Exception as e:
|
||||
logger.error(f"Error retrieving install proton_path: {e}")
|
||||
return "auto"
|
||||
return None
|
||||
|
||||
def get_game_proton_path(self):
|
||||
"""
|
||||
@@ -775,7 +781,7 @@ class ConfigHandler:
|
||||
Always reads fresh from disk.
|
||||
|
||||
Returns:
|
||||
str: Saved Game Proton path, Install Proton path, or 'auto' if not saved
|
||||
str: Saved Game Proton path, Install Proton path, or None if not saved (indicates auto-detect mode)
|
||||
"""
|
||||
try:
|
||||
config = self._read_config_from_disk()
|
||||
@@ -783,8 +789,12 @@ class ConfigHandler:
|
||||
|
||||
# If game proton not set or set to same_as_install, use install proton
|
||||
if not game_proton_path or game_proton_path == "same_as_install":
|
||||
game_proton_path = config.get("proton_path", "auto")
|
||||
game_proton_path = config.get("proton_path") # Returns None if not set
|
||||
|
||||
# Return None if missing/None/empty string
|
||||
if not game_proton_path:
|
||||
logger.debug("game_proton_path not set in config - will use auto-detection")
|
||||
return None
|
||||
logger.debug(f"Retrieved fresh game proton_path from config: {game_proton_path}")
|
||||
return game_proton_path
|
||||
except Exception as e:
|
||||
@@ -821,15 +831,20 @@ class ConfigHandler:
|
||||
logger.info(f"Auto-detected Proton: {best_proton['name']} ({proton_type})")
|
||||
self.save_config()
|
||||
else:
|
||||
# Fallback to auto-detect mode
|
||||
self.settings["proton_path"] = "auto"
|
||||
self.settings["proton_version"] = "auto"
|
||||
logger.info("No compatible Proton versions found, using auto-detect mode")
|
||||
# Set proton_path to None (will appear as null in JSON) so jackify-engine doesn't get invalid path
|
||||
# Code will auto-detect on each run when proton_path is None
|
||||
self.settings["proton_path"] = None
|
||||
self.settings["proton_version"] = None
|
||||
logger.warning("No compatible Proton versions found - proton_path set to null in config.json")
|
||||
logger.info("Jackify will auto-detect Proton on each run until a valid version is found")
|
||||
self.save_config()
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to auto-detect Proton: {e}")
|
||||
self.settings["proton_path"] = "auto"
|
||||
self.settings["proton_version"] = "auto"
|
||||
# Set proton_path to None (will appear as null in JSON)
|
||||
self.settings["proton_path"] = None
|
||||
self.settings["proton_version"] = None
|
||||
logger.warning("proton_path set to null in config.json due to auto-detection failure")
|
||||
self.save_config()
|
||||
|
||||
|
||||
@@ -105,9 +105,9 @@ class ModlistHandler:
|
||||
verbose: Boolean indicating if verbose output is desired.
|
||||
filesystem_handler: Optional FileSystemHandler instance to use instead of creating a new one.
|
||||
"""
|
||||
# Use standard logging (no file handler)
|
||||
# Use standard logging (propagate to root logger so messages appear in logs)
|
||||
self.logger = logging.getLogger(__name__)
|
||||
self.logger.propagate = False
|
||||
self.logger.propagate = True
|
||||
self.steamdeck = steamdeck
|
||||
|
||||
# DEBUG: Log ModlistHandler instantiation details for SD card path debugging
|
||||
@@ -746,15 +746,20 @@ class ModlistHandler:
|
||||
try:
|
||||
registry_success = self._apply_universal_dotnet_fixes()
|
||||
except Exception as e:
|
||||
self.logger.error(f"CRITICAL: Registry fixes failed - modlist may have .NET compatibility issues: {e}")
|
||||
error_msg = f"CRITICAL: Registry fixes failed - modlist may have .NET compatibility issues: {e}"
|
||||
self.logger.error(error_msg)
|
||||
if status_callback:
|
||||
status_callback(f"{self._get_progress_timestamp()} ERROR: {error_msg}")
|
||||
registry_success = False
|
||||
|
||||
if not registry_success:
|
||||
failure_msg = "WARNING: Universal dotnet4.x registry fixes FAILED! This modlist may experience .NET Framework compatibility issues."
|
||||
self.logger.error("=" * 80)
|
||||
self.logger.error("WARNING: Universal dotnet4.x registry fixes FAILED!")
|
||||
self.logger.error("This modlist may experience .NET Framework compatibility issues.")
|
||||
self.logger.error(failure_msg)
|
||||
self.logger.error("Consider manually setting mscoree=native in winecfg if problems occur.")
|
||||
self.logger.error("=" * 80)
|
||||
if status_callback:
|
||||
status_callback(f"{self._get_progress_timestamp()} {failure_msg}")
|
||||
# Continue but user should be aware of potential issues
|
||||
|
||||
# Step 4.6: Enable dotfiles visibility for Wine prefix
|
||||
@@ -1596,20 +1601,21 @@ class ModlistHandler:
|
||||
except Exception as e:
|
||||
self.logger.warning(f"Wineserver shutdown failed (non-critical): {e}")
|
||||
|
||||
# Registry fix 1: Set mscoree=native DLL override
|
||||
# Registry fix 1: Set *mscoree=native DLL override (asterisk for full override)
|
||||
# This tells Wine to use native .NET runtime instead of Wine's implementation
|
||||
self.logger.debug("Setting mscoree=native DLL override...")
|
||||
self.logger.debug("Setting *mscoree=native DLL override...")
|
||||
cmd1 = [
|
||||
wine_binary, 'reg', 'add',
|
||||
'HKEY_CURRENT_USER\\Software\\Wine\\DllOverrides',
|
||||
'/v', 'mscoree', '/t', 'REG_SZ', '/d', 'native', '/f'
|
||||
'/v', '*mscoree', '/t', 'REG_SZ', '/d', 'native', '/f'
|
||||
]
|
||||
|
||||
result1 = subprocess.run(cmd1, env=env, capture_output=True, text=True, errors='replace', timeout=30)
|
||||
self.logger.info(f"*mscoree registry command result: returncode={result1.returncode}, stdout={result1.stdout[:200]}, stderr={result1.stderr[:200]}")
|
||||
if result1.returncode == 0:
|
||||
self.logger.info("Successfully applied mscoree=native DLL override")
|
||||
self.logger.info("Successfully applied *mscoree=native DLL override")
|
||||
else:
|
||||
self.logger.warning(f"Failed to set mscoree DLL override: {result1.stderr}")
|
||||
self.logger.error(f"Failed to set *mscoree DLL override: returncode={result1.returncode}, stderr={result1.stderr}")
|
||||
|
||||
# Registry fix 2: Set OnlyUseLatestCLR=1
|
||||
# This prevents .NET version conflicts by using the latest CLR
|
||||
@@ -1621,10 +1627,11 @@ class ModlistHandler:
|
||||
]
|
||||
|
||||
result2 = subprocess.run(cmd2, env=env, capture_output=True, text=True, errors='replace', timeout=30)
|
||||
self.logger.info(f"OnlyUseLatestCLR registry command result: returncode={result2.returncode}, stdout={result2.stdout[:200]}, stderr={result2.stderr[:200]}")
|
||||
if result2.returncode == 0:
|
||||
self.logger.info("Successfully applied OnlyUseLatestCLR=1 registry entry")
|
||||
else:
|
||||
self.logger.warning(f"Failed to set OnlyUseLatestCLR: {result2.stderr}")
|
||||
self.logger.error(f"Failed to set OnlyUseLatestCLR: returncode={result2.returncode}, stderr={result2.stderr}")
|
||||
|
||||
# Force wineserver to flush registry changes to disk
|
||||
if wineserver_binary:
|
||||
@@ -1639,17 +1646,17 @@ class ModlistHandler:
|
||||
self.logger.info("Verifying registry entries were applied and persisted...")
|
||||
verification_passed = True
|
||||
|
||||
# Verify mscoree=native
|
||||
# Verify *mscoree=native
|
||||
verify_cmd1 = [
|
||||
wine_binary, 'reg', 'query',
|
||||
'HKEY_CURRENT_USER\\Software\\Wine\\DllOverrides',
|
||||
'/v', 'mscoree'
|
||||
'/v', '*mscoree'
|
||||
]
|
||||
verify_result1 = subprocess.run(verify_cmd1, env=env, capture_output=True, text=True, errors='replace', timeout=30)
|
||||
if verify_result1.returncode == 0 and 'native' in verify_result1.stdout:
|
||||
self.logger.info("VERIFIED: mscoree=native is set correctly")
|
||||
self.logger.info("VERIFIED: *mscoree=native is set correctly")
|
||||
else:
|
||||
self.logger.error(f"VERIFICATION FAILED: mscoree=native not found in registry. Query output: {verify_result1.stdout}")
|
||||
self.logger.error(f"VERIFICATION FAILED: *mscoree=native not found in registry. Query output: {verify_result1.stdout}")
|
||||
verification_passed = False
|
||||
|
||||
# Verify OnlyUseLatestCLR=1
|
||||
@@ -1696,10 +1703,17 @@ class ModlistHandler:
|
||||
]
|
||||
|
||||
for wine_path in wine_candidates:
|
||||
if wine_path.exists():
|
||||
if wine_path.exists() and wine_path.is_file():
|
||||
self.logger.info(f"Using Wine binary from user's configured Proton: {wine_path}")
|
||||
return str(wine_path)
|
||||
|
||||
# Wine binary not found at expected paths - search recursively in Proton directory
|
||||
self.logger.debug(f"Wine binary not found at expected paths in {proton_path}, searching recursively...")
|
||||
wine_binary = self._search_wine_in_proton_directory(proton_path)
|
||||
if wine_binary:
|
||||
self.logger.info(f"Found Wine binary via recursive search in Proton directory: {wine_binary}")
|
||||
return wine_binary
|
||||
|
||||
self.logger.warning(f"User's configured Proton path has no wine binary: {user_proton_path}")
|
||||
|
||||
# Fallback: Try to use same Steam library detection as main Proton detection
|
||||
@@ -1719,4 +1733,42 @@ class ModlistHandler:
|
||||
self.logger.error(f"Error finding Wine binary: {e}")
|
||||
return None
|
||||
|
||||
def _search_wine_in_proton_directory(self, proton_path: Path) -> Optional[str]:
|
||||
"""
|
||||
Recursively search for wine binary within a Proton directory.
|
||||
This handles cases where the directory structure might differ between Proton versions.
|
||||
|
||||
Args:
|
||||
proton_path: Path to the Proton directory to search
|
||||
|
||||
Returns:
|
||||
Path to wine binary if found, None otherwise
|
||||
"""
|
||||
try:
|
||||
if not proton_path.exists() or not proton_path.is_dir():
|
||||
return None
|
||||
|
||||
# Search for 'wine' executable (not 'wine64' or 'wine-preloader')
|
||||
# Limit search depth to avoid scanning entire filesystem
|
||||
max_depth = 5
|
||||
for root, dirs, files in os.walk(proton_path, followlinks=False):
|
||||
# Calculate depth relative to proton_path
|
||||
depth = len(Path(root).relative_to(proton_path).parts)
|
||||
if depth > max_depth:
|
||||
dirs.clear() # Don't descend further
|
||||
continue
|
||||
|
||||
# Check if 'wine' is in this directory
|
||||
if 'wine' in files:
|
||||
wine_path = Path(root) / 'wine'
|
||||
# Verify it's actually an executable file
|
||||
if wine_path.is_file() and os.access(wine_path, os.X_OK):
|
||||
self.logger.debug(f"Found wine binary at: {wine_path}")
|
||||
return str(wine_path)
|
||||
|
||||
return None
|
||||
except Exception as e:
|
||||
self.logger.debug(f"Error during recursive wine search in {proton_path}: {e}")
|
||||
return None
|
||||
|
||||
|
||||
@@ -427,10 +427,11 @@ class ModlistInstallCLI:
|
||||
print("\n" + "-" * 28)
|
||||
print(f"{COLOR_INFO}Nexus Authentication: Using API Key (Legacy){COLOR_RESET}")
|
||||
|
||||
# Get valid token/key
|
||||
api_key = auth_service.ensure_valid_auth()
|
||||
# Get valid token/key and OAuth state for engine auto-refresh
|
||||
api_key, oauth_info = auth_service.get_auth_for_engine()
|
||||
if api_key:
|
||||
self.context['nexus_api_key'] = api_key
|
||||
self.context['nexus_oauth_info'] = oauth_info # For engine auto-refresh
|
||||
else:
|
||||
# Auth expired or invalid - prompt to set up
|
||||
print(f"\n{COLOR_WARNING}Your authentication has expired or is invalid.{COLOR_RESET}")
|
||||
@@ -463,9 +464,10 @@ class ModlistInstallCLI:
|
||||
if username:
|
||||
print(f"{COLOR_INFO}Authorized as: {username}{COLOR_RESET}")
|
||||
|
||||
api_key = auth_service.ensure_valid_auth()
|
||||
api_key, oauth_info = auth_service.get_auth_for_engine()
|
||||
if api_key:
|
||||
self.context['nexus_api_key'] = api_key
|
||||
self.context['nexus_oauth_info'] = oauth_info # For engine auto-refresh
|
||||
else:
|
||||
print(f"{COLOR_ERROR}Failed to retrieve auth token after authorization.{COLOR_RESET}")
|
||||
return None
|
||||
@@ -616,6 +618,7 @@ class ModlistInstallCLI:
|
||||
modlist_arg = self.context.get('modlist_value') or self.context.get('machineid')
|
||||
machineid = self.context.get('machineid')
|
||||
api_key = self.context['nexus_api_key']
|
||||
oauth_info = self.context.get('nexus_oauth_info')
|
||||
|
||||
# Path to the engine binary
|
||||
engine_path = get_jackify_engine_path()
|
||||
@@ -675,24 +678,37 @@ class ModlistInstallCLI:
|
||||
# Store original environment values to restore later
|
||||
original_env_values = {
|
||||
'NEXUS_API_KEY': os.environ.get('NEXUS_API_KEY'),
|
||||
'NEXUS_OAUTH_INFO': os.environ.get('NEXUS_OAUTH_INFO'),
|
||||
'DOTNET_SYSTEM_GLOBALIZATION_INVARIANT': os.environ.get('DOTNET_SYSTEM_GLOBALIZATION_INVARIANT')
|
||||
}
|
||||
|
||||
try:
|
||||
# Temporarily modify current process's environment
|
||||
# Prefer NEXUS_OAUTH_INFO (supports auto-refresh) over NEXUS_API_KEY (legacy)
|
||||
if oauth_info:
|
||||
os.environ['NEXUS_OAUTH_INFO'] = oauth_info
|
||||
self.logger.debug(f"Set NEXUS_OAUTH_INFO for engine (supports auto-refresh)")
|
||||
# Also set NEXUS_API_KEY for backward compatibility
|
||||
if api_key:
|
||||
os.environ['NEXUS_API_KEY'] = api_key
|
||||
self.logger.debug(f"Temporarily set os.environ['NEXUS_API_KEY'] for engine call using session-provided key.")
|
||||
elif 'NEXUS_API_KEY' in os.environ: # api_key is None/empty, but a system key might exist
|
||||
self.logger.debug(f"Session API key not provided. Temporarily removing inherited NEXUS_API_KEY ('{'[REDACTED]' if os.environ.get('NEXUS_API_KEY') else 'None'}') from os.environ for engine call to ensure it is not used.")
|
||||
elif api_key:
|
||||
# No OAuth info, use API key only (no auto-refresh support)
|
||||
os.environ['NEXUS_API_KEY'] = api_key
|
||||
self.logger.debug(f"Set NEXUS_API_KEY for engine (no auto-refresh)")
|
||||
else:
|
||||
# No auth available, clear any inherited values
|
||||
if 'NEXUS_API_KEY' in os.environ:
|
||||
del os.environ['NEXUS_API_KEY']
|
||||
# If api_key is None and NEXUS_API_KEY was not in os.environ, it remains unset, which is correct.
|
||||
if 'NEXUS_OAUTH_INFO' in os.environ:
|
||||
del os.environ['NEXUS_OAUTH_INFO']
|
||||
self.logger.debug(f"No Nexus auth available, cleared inherited env vars")
|
||||
|
||||
os.environ['DOTNET_SYSTEM_GLOBALIZATION_INVARIANT'] = "1"
|
||||
self.logger.debug(f"Temporarily set os.environ['DOTNET_SYSTEM_GLOBALIZATION_INVARIANT'] = '1' for engine call.")
|
||||
|
||||
self.logger.info("Environment prepared for jackify-engine install process by modifying os.environ.")
|
||||
self.logger.debug(f"NEXUS_API_KEY in os.environ (pre-call): {'[SET]' if os.environ.get('NEXUS_API_KEY') else '[NOT SET]'}")
|
||||
self.logger.debug(f"NEXUS_OAUTH_INFO in os.environ (pre-call): {'[SET]' if os.environ.get('NEXUS_OAUTH_INFO') else '[NOT SET]'}")
|
||||
|
||||
pretty_cmd = ' '.join([f'"{arg}"' if ' ' in arg else arg for arg in cmd])
|
||||
print(f"{COLOR_INFO}Launching Jackify Install Engine with command:{COLOR_RESET} {pretty_cmd}")
|
||||
|
||||
@@ -596,19 +596,29 @@ class ProtontricksHandler:
|
||||
try:
|
||||
if user_reg_path.exists():
|
||||
content = user_reg_path.read_text(encoding='utf-8', errors='ignore')
|
||||
if "ShowDotFiles" not in content:
|
||||
# Check for CORRECT format with proper backslash escaping
|
||||
has_correct_format = '[Software\\\\Wine]' in content and '"ShowDotFiles"="Y"' in content
|
||||
has_broken_format = '[SoftwareWine]' in content and '"ShowDotFiles"="Y"' in content
|
||||
|
||||
if has_broken_format and not has_correct_format:
|
||||
# Fix the broken format by replacing the section header
|
||||
logger.debug(f"Found broken ShowDotFiles format in {user_reg_path}, fixing...")
|
||||
content = content.replace('[SoftwareWine]', '[Software\\\\Wine]')
|
||||
user_reg_path.write_text(content, encoding='utf-8')
|
||||
dotfiles_set_success = True
|
||||
elif not has_correct_format:
|
||||
logger.debug(f"Adding ShowDotFiles entry to {user_reg_path}")
|
||||
with open(user_reg_path, 'a', encoding='utf-8') as f:
|
||||
f.write('\n[Software\\Wine] 1603891765\n')
|
||||
f.write('\n[Software\\\\Wine] 1603891765\n')
|
||||
f.write('"ShowDotFiles"="Y"\n')
|
||||
dotfiles_set_success = True # Count file write as success too
|
||||
else:
|
||||
logger.debug("ShowDotFiles already present in user.reg")
|
||||
logger.debug("ShowDotFiles already present in correct format in user.reg")
|
||||
dotfiles_set_success = True # Already there counts as success
|
||||
else:
|
||||
logger.warning(f"user.reg not found at {user_reg_path}, creating it.")
|
||||
with open(user_reg_path, 'w', encoding='utf-8') as f:
|
||||
f.write('[Software\\Wine] 1603891765\n')
|
||||
f.write('[Software\\\\Wine] 1603891765\n')
|
||||
f.write('"ShowDotFiles"="Y"\n')
|
||||
dotfiles_set_success = True # Creating file counts as success
|
||||
except Exception as e:
|
||||
|
||||
@@ -41,8 +41,8 @@ def get_clean_subprocess_env(extra_env=None):
|
||||
"""
|
||||
Returns a copy of os.environ with bundled-runtime variables and other problematic entries removed.
|
||||
Optionally merges in extra_env dict.
|
||||
Also ensures bundled tools (lz4, unzip, etc.) are in PATH when running as AppImage.
|
||||
CRITICAL: Preserves system PATH to ensure system tools (like lz4) are available.
|
||||
Also ensures bundled tools (lz4, cabextract, winetricks) are in PATH when running as AppImage.
|
||||
CRITICAL: Preserves system PATH to ensure system utilities (wget, curl, unzip, xz, gzip, sha256sum) are available.
|
||||
"""
|
||||
from pathlib import Path
|
||||
|
||||
@@ -73,7 +73,8 @@ def get_clean_subprocess_env(extra_env=None):
|
||||
path_parts.append(sys_path)
|
||||
|
||||
# Add bundled tools directory to PATH if running as AppImage
|
||||
# This ensures lz4, unzip, xz, etc. are available to subprocesses
|
||||
# This ensures lz4, cabextract, and winetricks are available to subprocesses
|
||||
# System utilities (wget, curl, unzip, xz, gzip, sha256sum) come from system PATH
|
||||
# Note: appdir was saved before env cleanup above
|
||||
tools_dir = None
|
||||
|
||||
@@ -100,23 +101,23 @@ def get_clean_subprocess_env(extra_env=None):
|
||||
tools_dir = str(possible_dir)
|
||||
break
|
||||
|
||||
# Build final PATH: bundled tools first (if any), then original PATH with system paths
|
||||
# Build final PATH: system PATH first, then bundled tools (lz4, cabextract, winetricks)
|
||||
# System utilities (wget, curl, unzip, xz, gzip, sha256sum) are preferred from system
|
||||
final_path_parts = []
|
||||
if tools_dir and os.path.isdir(tools_dir):
|
||||
# Prepend tools directory so bundled tools take precedence
|
||||
# This is critical - bundled lz4 must come before system lz4
|
||||
final_path_parts.append(tools_dir)
|
||||
|
||||
# Add all other paths (preserving order, removing duplicates)
|
||||
# Note: AppRun already sets PATH with tools directory, but we ensure it's first
|
||||
# Add all other paths first (system utilities take precedence)
|
||||
seen = set()
|
||||
if tools_dir:
|
||||
seen.add(tools_dir) # Already added, don't add again
|
||||
for path_part in path_parts:
|
||||
if path_part and path_part not in seen:
|
||||
final_path_parts.append(path_part)
|
||||
seen.add(path_part)
|
||||
|
||||
# Then add bundled tools directory (for lz4, cabextract, winetricks)
|
||||
if tools_dir and os.path.isdir(tools_dir) and tools_dir not in seen:
|
||||
final_path_parts.append(tools_dir)
|
||||
seen.add(tools_dir)
|
||||
|
||||
|
||||
env['PATH'] = ':'.join(final_path_parts)
|
||||
|
||||
# Optionally restore LD_LIBRARY_PATH to system default if needed
|
||||
|
||||
@@ -149,7 +149,7 @@ class WinetricksHandler:
|
||||
|
||||
# If user selected a specific Proton, try that first
|
||||
wine_binary = None
|
||||
if user_proton_path != 'auto':
|
||||
if user_proton_path and user_proton_path != 'auto':
|
||||
# Check if user-selected Proton still exists
|
||||
if os.path.exists(user_proton_path):
|
||||
# Resolve symlinks to handle ~/.steam/steam -> ~/.local/share/Steam
|
||||
@@ -582,7 +582,7 @@ class WinetricksHandler:
|
||||
user_proton_path = config.get_proton_path()
|
||||
|
||||
wine_binary = None
|
||||
if user_proton_path != 'auto':
|
||||
if user_proton_path and user_proton_path != 'auto':
|
||||
if os.path.exists(user_proton_path):
|
||||
resolved_proton_path = os.path.realpath(user_proton_path)
|
||||
valve_proton_wine = os.path.join(resolved_proton_path, 'dist', 'bin', 'wine')
|
||||
@@ -594,8 +594,8 @@ class WinetricksHandler:
|
||||
wine_binary = ge_proton_wine
|
||||
|
||||
if not wine_binary:
|
||||
if user_proton_path == 'auto':
|
||||
self.logger.info("Auto-detecting Proton (user selected 'auto')")
|
||||
if not user_proton_path or user_proton_path == 'auto':
|
||||
self.logger.info("Auto-detecting Proton (user selected 'auto' or path not set)")
|
||||
best_proton = WineUtils.select_best_proton()
|
||||
if best_proton:
|
||||
wine_binary = WineUtils.find_proton_binary(best_proton['name'])
|
||||
@@ -811,7 +811,7 @@ class WinetricksHandler:
|
||||
|
||||
# If user selected a specific Proton, try that first
|
||||
wine_binary = None
|
||||
if user_proton_path != 'auto':
|
||||
if user_proton_path and user_proton_path != 'auto':
|
||||
if os.path.exists(user_proton_path):
|
||||
resolved_proton_path = os.path.realpath(user_proton_path)
|
||||
valve_proton_wine = os.path.join(resolved_proton_path, 'dist', 'bin', 'wine')
|
||||
@@ -822,10 +822,10 @@ class WinetricksHandler:
|
||||
elif os.path.exists(ge_proton_wine):
|
||||
wine_binary = ge_proton_wine
|
||||
|
||||
# Only auto-detect if user explicitly chose 'auto'
|
||||
# Only auto-detect if user explicitly chose 'auto' or path is not set
|
||||
if not wine_binary:
|
||||
if user_proton_path == 'auto':
|
||||
self.logger.info("Auto-detecting Proton (user selected 'auto')")
|
||||
if not user_proton_path or user_proton_path == 'auto':
|
||||
self.logger.info("Auto-detecting Proton (user selected 'auto' or path not set)")
|
||||
best_proton = WineUtils.select_best_proton()
|
||||
if best_proton:
|
||||
wine_binary = WineUtils.find_proton_binary(best_proton['name'])
|
||||
|
||||
@@ -71,7 +71,7 @@ class AutomatedPrefixService:
|
||||
config_handler = ConfigHandler()
|
||||
user_proton_path = config_handler.get_game_proton_path()
|
||||
|
||||
if user_proton_path == 'auto':
|
||||
if not user_proton_path or user_proton_path == 'auto':
|
||||
# Use enhanced fallback logic with GE-Proton preference
|
||||
logger.info("User selected auto-detect, using GE-Proton → Experimental → Proton precedence")
|
||||
return WineUtils.select_best_proton()
|
||||
@@ -3095,20 +3095,20 @@ echo Prefix creation complete.
|
||||
env['WINEPREFIX'] = prefix_path
|
||||
env['WINEDEBUG'] = '-all' # Suppress Wine debug output
|
||||
|
||||
# Registry fix 1: Set mscoree=native DLL override
|
||||
# Registry fix 1: Set *mscoree=native DLL override (asterisk for full override)
|
||||
# This tells Wine to use native .NET runtime instead of Wine's implementation
|
||||
logger.debug("Setting mscoree=native DLL override...")
|
||||
logger.debug("Setting *mscoree=native DLL override...")
|
||||
cmd1 = [
|
||||
wine_binary, 'reg', 'add',
|
||||
'HKEY_CURRENT_USER\\Software\\Wine\\DllOverrides',
|
||||
'/v', 'mscoree', '/t', 'REG_SZ', '/d', 'native', '/f'
|
||||
'/v', '*mscoree', '/t', 'REG_SZ', '/d', 'native', '/f'
|
||||
]
|
||||
|
||||
result1 = subprocess.run(cmd1, env=env, capture_output=True, text=True, errors='replace')
|
||||
if result1.returncode == 0:
|
||||
logger.info("Successfully applied mscoree=native DLL override")
|
||||
logger.info("Successfully applied *mscoree=native DLL override")
|
||||
else:
|
||||
logger.warning(f"Failed to set mscoree DLL override: {result1.stderr}")
|
||||
logger.warning(f"Failed to set *mscoree DLL override: {result1.stderr}")
|
||||
|
||||
# Registry fix 2: Set OnlyUseLatestCLR=1
|
||||
# This prevents .NET version conflicts by using the latest CLR
|
||||
@@ -3140,39 +3140,96 @@ echo Prefix creation complete.
|
||||
def _find_wine_binary_for_registry(self, modlist_compatdata_path: str) -> Optional[str]:
|
||||
"""Find the appropriate Wine binary for registry operations"""
|
||||
try:
|
||||
# Method 1: Try to detect from Steam's config or use Proton from compat data
|
||||
# Look for wine binary in common Proton locations
|
||||
proton_paths = [
|
||||
os.path.expanduser("~/.local/share/Steam/compatibilitytools.d"),
|
||||
os.path.expanduser("~/.steam/steam/steamapps/common")
|
||||
from ..handlers.config_handler import ConfigHandler
|
||||
from ..handlers.wine_utils import WineUtils
|
||||
|
||||
# Method 1: Use the user's configured Proton version from settings
|
||||
config_handler = ConfigHandler()
|
||||
user_proton_path = config_handler.get_game_proton_path()
|
||||
|
||||
if user_proton_path and user_proton_path != 'auto':
|
||||
# User has selected a specific Proton version
|
||||
proton_path = Path(user_proton_path).expanduser()
|
||||
|
||||
# Check for wine binary in both GE-Proton and Valve Proton structures
|
||||
wine_candidates = [
|
||||
proton_path / "files" / "bin" / "wine", # GE-Proton structure
|
||||
proton_path / "dist" / "bin" / "wine" # Valve Proton structure
|
||||
]
|
||||
|
||||
for base_path in proton_paths:
|
||||
if os.path.exists(base_path):
|
||||
for item in os.listdir(base_path):
|
||||
if 'proton' in item.lower():
|
||||
wine_path = os.path.join(base_path, item, 'files', 'bin', 'wine')
|
||||
if os.path.exists(wine_path):
|
||||
logger.debug(f"Found Wine binary: {wine_path}")
|
||||
return wine_path
|
||||
for wine_path in wine_candidates:
|
||||
if wine_path.exists() and wine_path.is_file():
|
||||
logger.info(f"Using Wine binary from user's configured Proton: {wine_path}")
|
||||
return str(wine_path)
|
||||
|
||||
# Method 2: Fallback to system wine if available
|
||||
try:
|
||||
result = subprocess.run(['which', 'wine'], capture_output=True, text=True)
|
||||
if result.returncode == 0:
|
||||
wine_path = result.stdout.strip()
|
||||
logger.debug(f"Using system Wine binary: {wine_path}")
|
||||
return wine_path
|
||||
except Exception:
|
||||
pass
|
||||
# Wine binary not found at expected paths - search recursively in Proton directory
|
||||
logger.debug(f"Wine binary not found at expected paths in {proton_path}, searching recursively...")
|
||||
wine_binary = self._search_wine_in_proton_directory(proton_path)
|
||||
if wine_binary:
|
||||
logger.info(f"Found Wine binary via recursive search in Proton directory: {wine_binary}")
|
||||
return wine_binary
|
||||
|
||||
logger.error("No suitable Wine binary found for registry operations")
|
||||
logger.warning(f"User's configured Proton path has no wine binary: {user_proton_path}")
|
||||
|
||||
# Method 2: Fallback to auto-detection using WineUtils
|
||||
best_proton = WineUtils.select_best_proton()
|
||||
if best_proton:
|
||||
wine_binary = WineUtils.find_proton_binary(best_proton['name'])
|
||||
if wine_binary:
|
||||
logger.info(f"Using Wine binary from detected Proton: {wine_binary}")
|
||||
return wine_binary
|
||||
|
||||
# NEVER fall back to system wine - it will break Proton prefixes with architecture mismatches
|
||||
logger.error("No suitable Proton Wine binary found for registry operations")
|
||||
return None
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error finding Wine binary: {e}")
|
||||
return None
|
||||
|
||||
def _search_wine_in_proton_directory(self, proton_path: Path) -> Optional[str]:
|
||||
"""
|
||||
Recursively search for wine binary within a Proton directory.
|
||||
This handles cases where the directory structure might differ between Proton versions.
|
||||
|
||||
Args:
|
||||
proton_path: Path to the Proton directory to search
|
||||
|
||||
Returns:
|
||||
Path to wine binary if found, None otherwise
|
||||
"""
|
||||
try:
|
||||
if not proton_path.exists() or not proton_path.is_dir():
|
||||
return None
|
||||
|
||||
# Search for 'wine' executable (not 'wine64' or 'wine-preloader')
|
||||
# Limit search depth to avoid scanning entire filesystem
|
||||
max_depth = 5
|
||||
for root, dirs, files in os.walk(proton_path, followlinks=False):
|
||||
# Calculate depth relative to proton_path
|
||||
try:
|
||||
depth = len(Path(root).relative_to(proton_path).parts)
|
||||
except ValueError:
|
||||
# Path is not relative to proton_path (shouldn't happen, but be safe)
|
||||
continue
|
||||
|
||||
if depth > max_depth:
|
||||
dirs.clear() # Don't descend further
|
||||
continue
|
||||
|
||||
# Check if 'wine' is in this directory
|
||||
if 'wine' in files:
|
||||
wine_path = Path(root) / 'wine'
|
||||
# Verify it's actually an executable file
|
||||
if wine_path.is_file() and os.access(wine_path, os.X_OK):
|
||||
logger.debug(f"Found wine binary at: {wine_path}")
|
||||
return str(wine_path)
|
||||
|
||||
return None
|
||||
except Exception as e:
|
||||
logger.debug(f"Error during recursive wine search in {proton_path}: {e}")
|
||||
return None
|
||||
|
||||
def _inject_game_registry_entries(self, modlist_compatdata_path: str):
|
||||
"""Detect and inject FNV/Enderal game paths and apply universal dotnet4.x compatibility fixes"""
|
||||
system_reg_path = os.path.join(modlist_compatdata_path, "pfx", "system.reg")
|
||||
|
||||
@@ -276,6 +276,7 @@ class ModlistService:
|
||||
download_dir_str = str(actual_download_path)
|
||||
|
||||
api_key = context['nexus_api_key']
|
||||
oauth_info = context.get('nexus_oauth_info')
|
||||
|
||||
# Path to the engine binary (copied from working code)
|
||||
engine_path = get_jackify_engine_path()
|
||||
@@ -302,15 +303,25 @@ class ModlistService:
|
||||
# Store original environment values (copied from working code)
|
||||
original_env_values = {
|
||||
'NEXUS_API_KEY': os.environ.get('NEXUS_API_KEY'),
|
||||
'NEXUS_OAUTH_INFO': os.environ.get('NEXUS_OAUTH_INFO'),
|
||||
'DOTNET_SYSTEM_GLOBALIZATION_INVARIANT': os.environ.get('DOTNET_SYSTEM_GLOBALIZATION_INVARIANT')
|
||||
}
|
||||
|
||||
try:
|
||||
# Environment setup (copied from working code)
|
||||
# Environment setup - prefer NEXUS_OAUTH_INFO (supports auto-refresh) over NEXUS_API_KEY
|
||||
if oauth_info:
|
||||
os.environ['NEXUS_OAUTH_INFO'] = oauth_info
|
||||
# Also set NEXUS_API_KEY for backward compatibility
|
||||
if api_key:
|
||||
os.environ['NEXUS_API_KEY'] = api_key
|
||||
elif 'NEXUS_API_KEY' in os.environ:
|
||||
elif api_key:
|
||||
os.environ['NEXUS_API_KEY'] = api_key
|
||||
else:
|
||||
# No auth available, clear any inherited values
|
||||
if 'NEXUS_API_KEY' in os.environ:
|
||||
del os.environ['NEXUS_API_KEY']
|
||||
if 'NEXUS_OAUTH_INFO' in os.environ:
|
||||
del os.environ['NEXUS_OAUTH_INFO']
|
||||
|
||||
os.environ['DOTNET_SYSTEM_GLOBALIZATION_INVARIANT'] = "1"
|
||||
|
||||
|
||||
@@ -228,16 +228,65 @@ class NexusAuthService:
|
||||
|
||||
return auth_token
|
||||
|
||||
def get_auth_for_engine(self) -> Optional[str]:
|
||||
def get_auth_for_engine(self) -> Tuple[Optional[str], Optional[str]]:
|
||||
"""
|
||||
Get authentication token for jackify-engine
|
||||
Same as ensure_valid_auth() - engine uses NEXUS_API_KEY env var for both OAuth and API keys
|
||||
(This matches upstream Wabbajack behavior)
|
||||
Get authentication for jackify-engine with auto-refresh support
|
||||
|
||||
Returns both NEXUS_API_KEY (for backward compat) and NEXUS_OAUTH_INFO (for auto-refresh).
|
||||
When NEXUS_OAUTH_INFO is provided, the engine can automatically refresh expired tokens
|
||||
during long installations.
|
||||
|
||||
Returns:
|
||||
Valid auth token to pass via NEXUS_API_KEY environment variable, or None
|
||||
Tuple of (nexus_api_key, nexus_oauth_info_json)
|
||||
- nexus_api_key: Access token or API key (for backward compat)
|
||||
- nexus_oauth_info_json: Full OAuth state JSON (for auto-refresh) or None
|
||||
"""
|
||||
return self.ensure_valid_auth()
|
||||
import json
|
||||
import time
|
||||
|
||||
# Check if using OAuth and ensure token is fresh
|
||||
if self.token_handler.has_token():
|
||||
# Refresh token if expired (15 minute buffer for long installs)
|
||||
access_token = self._get_oauth_token()
|
||||
if not access_token:
|
||||
logger.warning("OAuth token refresh failed, cannot provide auth to engine")
|
||||
return (None, None)
|
||||
|
||||
# Load the refreshed token data
|
||||
token_data = self.token_handler.load_token()
|
||||
|
||||
if token_data:
|
||||
oauth_data = token_data.get('oauth', {})
|
||||
|
||||
# Build NexusOAuthState JSON matching upstream Wabbajack format
|
||||
# This allows engine to auto-refresh tokens during long installations
|
||||
nexus_oauth_state = {
|
||||
"oauth": {
|
||||
"access_token": oauth_data.get('access_token'),
|
||||
"token_type": oauth_data.get('token_type', 'Bearer'),
|
||||
"expires_in": oauth_data.get('expires_in', 3600),
|
||||
"refresh_token": oauth_data.get('refresh_token'),
|
||||
"scope": oauth_data.get('scope', 'public openid profile'),
|
||||
"created_at": oauth_data.get('created_at', int(time.time())),
|
||||
"_received_at": token_data.get('_saved_at', int(time.time())) * 10000000 + 116444736000000000 # Convert Unix to Windows FILETIME
|
||||
},
|
||||
"api_key": ""
|
||||
}
|
||||
|
||||
nexus_oauth_json = json.dumps(nexus_oauth_state)
|
||||
access_token = oauth_data.get('access_token')
|
||||
|
||||
logger.info("Providing OAuth state to engine for auto-refresh capability")
|
||||
return (access_token, nexus_oauth_json)
|
||||
|
||||
# Fall back to API key (no auto-refresh support)
|
||||
api_key = self.api_key_service.get_saved_api_key()
|
||||
if api_key:
|
||||
logger.info("Using API key for engine (no auto-refresh)")
|
||||
return (api_key, None)
|
||||
|
||||
logger.warning("No authentication available for engine")
|
||||
return (None, None)
|
||||
|
||||
def clear_all_auth(self) -> bool:
|
||||
"""
|
||||
|
||||
BIN
jackify/engine/TestBackslashFix.dll
Normal file
BIN
jackify/engine/TestBackslashFix.dll
Normal file
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.
Binary file not shown.
@@ -7,7 +7,7 @@
|
||||
"targets": {
|
||||
".NETCoreApp,Version=v8.0": {},
|
||||
".NETCoreApp,Version=v8.0/linux-x64": {
|
||||
"jackify-engine/0.4.4": {
|
||||
"jackify-engine/0.4.5": {
|
||||
"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.4",
|
||||
"Wabbajack.Downloaders.Bethesda": "0.4.4",
|
||||
"Wabbajack.Downloaders.Dispatcher": "0.4.4",
|
||||
"Wabbajack.Hashing.xxHash64": "0.4.4",
|
||||
"Wabbajack.Networking.Discord": "0.4.4",
|
||||
"Wabbajack.Networking.GitHub": "0.4.4",
|
||||
"Wabbajack.Paths.IO": "0.4.4",
|
||||
"Wabbajack.Server.Lib": "0.4.4",
|
||||
"Wabbajack.Services.OSIntegrated": "0.4.4",
|
||||
"Wabbajack.VFS": "0.4.4",
|
||||
"Wabbajack.CLI.Builder": "0.4.5",
|
||||
"Wabbajack.Downloaders.Bethesda": "0.4.5",
|
||||
"Wabbajack.Downloaders.Dispatcher": "0.4.5",
|
||||
"Wabbajack.Hashing.xxHash64": "0.4.5",
|
||||
"Wabbajack.Networking.Discord": "0.4.5",
|
||||
"Wabbajack.Networking.GitHub": "0.4.5",
|
||||
"Wabbajack.Paths.IO": "0.4.5",
|
||||
"Wabbajack.Server.Lib": "0.4.5",
|
||||
"Wabbajack.Services.OSIntegrated": "0.4.5",
|
||||
"Wabbajack.VFS": "0.4.5",
|
||||
"MegaApiClient": "1.0.0.0",
|
||||
"runtimepack.Microsoft.NETCore.App.Runtime.linux-x64": "8.0.22"
|
||||
},
|
||||
@@ -1781,7 +1781,7 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"Wabbajack.CLI.Builder/0.4.4": {
|
||||
"Wabbajack.CLI.Builder/0.4.5": {
|
||||
"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.4"
|
||||
"Wabbajack.Paths": "0.4.5"
|
||||
},
|
||||
"runtime": {
|
||||
"Wabbajack.CLI.Builder.dll": {}
|
||||
}
|
||||
},
|
||||
"Wabbajack.Common/0.4.4": {
|
||||
"Wabbajack.Common/0.4.5": {
|
||||
"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.4",
|
||||
"Wabbajack.Networking.Http": "0.4.4",
|
||||
"Wabbajack.Paths.IO": "0.4.4"
|
||||
"Wabbajack.DTOs": "0.4.5",
|
||||
"Wabbajack.Networking.Http": "0.4.5",
|
||||
"Wabbajack.Paths.IO": "0.4.5"
|
||||
},
|
||||
"runtime": {
|
||||
"Wabbajack.Common.dll": {}
|
||||
}
|
||||
},
|
||||
"Wabbajack.Compiler/0.4.4": {
|
||||
"Wabbajack.Compiler/0.4.5": {
|
||||
"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.4",
|
||||
"Wabbajack.Installer": "0.4.4",
|
||||
"Wabbajack.VFS": "0.4.4",
|
||||
"Wabbajack.Downloaders.Dispatcher": "0.4.5",
|
||||
"Wabbajack.Installer": "0.4.5",
|
||||
"Wabbajack.VFS": "0.4.5",
|
||||
"ini-parser-netstandard": "2.5.2"
|
||||
},
|
||||
"runtime": {
|
||||
"Wabbajack.Compiler.dll": {}
|
||||
}
|
||||
},
|
||||
"Wabbajack.Compression.BSA/0.4.4": {
|
||||
"Wabbajack.Compression.BSA/0.4.5": {
|
||||
"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.4",
|
||||
"Wabbajack.DTOs": "0.4.4"
|
||||
"Wabbajack.Common": "0.4.5",
|
||||
"Wabbajack.DTOs": "0.4.5"
|
||||
},
|
||||
"runtime": {
|
||||
"Wabbajack.Compression.BSA.dll": {}
|
||||
}
|
||||
},
|
||||
"Wabbajack.Compression.Zip/0.4.4": {
|
||||
"Wabbajack.Compression.Zip/0.4.5": {
|
||||
"dependencies": {
|
||||
"Wabbajack.IO.Async": "0.4.4"
|
||||
"Wabbajack.IO.Async": "0.4.5"
|
||||
},
|
||||
"runtime": {
|
||||
"Wabbajack.Compression.Zip.dll": {}
|
||||
}
|
||||
},
|
||||
"Wabbajack.Configuration/0.4.4": {
|
||||
"Wabbajack.Configuration/0.4.5": {
|
||||
"runtime": {
|
||||
"Wabbajack.Configuration.dll": {}
|
||||
}
|
||||
},
|
||||
"Wabbajack.Downloaders.Bethesda/0.4.4": {
|
||||
"Wabbajack.Downloaders.Bethesda/0.4.5": {
|
||||
"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.4",
|
||||
"Wabbajack.Downloaders.Interfaces": "0.4.4",
|
||||
"Wabbajack.Networking.BethesdaNet": "0.4.4"
|
||||
"Wabbajack.Common": "0.4.5",
|
||||
"Wabbajack.Downloaders.Interfaces": "0.4.5",
|
||||
"Wabbajack.Networking.BethesdaNet": "0.4.5"
|
||||
},
|
||||
"runtime": {
|
||||
"Wabbajack.Downloaders.Bethesda.dll": {}
|
||||
}
|
||||
},
|
||||
"Wabbajack.Downloaders.Dispatcher/0.4.4": {
|
||||
"Wabbajack.Downloaders.Dispatcher/0.4.5": {
|
||||
"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.4",
|
||||
"Wabbajack.Downloaders.GameFile": "0.4.4",
|
||||
"Wabbajack.Downloaders.GoogleDrive": "0.4.4",
|
||||
"Wabbajack.Downloaders.Http": "0.4.4",
|
||||
"Wabbajack.Downloaders.IPS4OAuth2Downloader": "0.4.4",
|
||||
"Wabbajack.Downloaders.Interfaces": "0.4.4",
|
||||
"Wabbajack.Downloaders.Manual": "0.4.4",
|
||||
"Wabbajack.Downloaders.MediaFire": "0.4.4",
|
||||
"Wabbajack.Downloaders.Mega": "0.4.4",
|
||||
"Wabbajack.Downloaders.ModDB": "0.4.4",
|
||||
"Wabbajack.Downloaders.Nexus": "0.4.4",
|
||||
"Wabbajack.Downloaders.VerificationCache": "0.4.4",
|
||||
"Wabbajack.Downloaders.WabbajackCDN": "0.4.4",
|
||||
"Wabbajack.Networking.WabbajackClientApi": "0.4.4"
|
||||
"Wabbajack.Downloaders.Bethesda": "0.4.5",
|
||||
"Wabbajack.Downloaders.GameFile": "0.4.5",
|
||||
"Wabbajack.Downloaders.GoogleDrive": "0.4.5",
|
||||
"Wabbajack.Downloaders.Http": "0.4.5",
|
||||
"Wabbajack.Downloaders.IPS4OAuth2Downloader": "0.4.5",
|
||||
"Wabbajack.Downloaders.Interfaces": "0.4.5",
|
||||
"Wabbajack.Downloaders.Manual": "0.4.5",
|
||||
"Wabbajack.Downloaders.MediaFire": "0.4.5",
|
||||
"Wabbajack.Downloaders.Mega": "0.4.5",
|
||||
"Wabbajack.Downloaders.ModDB": "0.4.5",
|
||||
"Wabbajack.Downloaders.Nexus": "0.4.5",
|
||||
"Wabbajack.Downloaders.VerificationCache": "0.4.5",
|
||||
"Wabbajack.Downloaders.WabbajackCDN": "0.4.5",
|
||||
"Wabbajack.Networking.WabbajackClientApi": "0.4.5"
|
||||
},
|
||||
"runtime": {
|
||||
"Wabbajack.Downloaders.Dispatcher.dll": {}
|
||||
}
|
||||
},
|
||||
"Wabbajack.Downloaders.GameFile/0.4.4": {
|
||||
"Wabbajack.Downloaders.GameFile/0.4.5": {
|
||||
"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.4",
|
||||
"Wabbajack.VFS": "0.4.4"
|
||||
"Wabbajack.Downloaders.Interfaces": "0.4.5",
|
||||
"Wabbajack.VFS": "0.4.5"
|
||||
},
|
||||
"runtime": {
|
||||
"Wabbajack.Downloaders.GameFile.dll": {}
|
||||
}
|
||||
},
|
||||
"Wabbajack.Downloaders.GoogleDrive/0.4.4": {
|
||||
"Wabbajack.Downloaders.GoogleDrive/0.4.5": {
|
||||
"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.4",
|
||||
"Wabbajack.DTOs": "0.4.4",
|
||||
"Wabbajack.Downloaders.Interfaces": "0.4.4",
|
||||
"Wabbajack.Networking.Http": "0.4.4",
|
||||
"Wabbajack.Networking.Http.Interfaces": "0.4.4"
|
||||
"Wabbajack.Common": "0.4.5",
|
||||
"Wabbajack.DTOs": "0.4.5",
|
||||
"Wabbajack.Downloaders.Interfaces": "0.4.5",
|
||||
"Wabbajack.Networking.Http": "0.4.5",
|
||||
"Wabbajack.Networking.Http.Interfaces": "0.4.5"
|
||||
},
|
||||
"runtime": {
|
||||
"Wabbajack.Downloaders.GoogleDrive.dll": {}
|
||||
}
|
||||
},
|
||||
"Wabbajack.Downloaders.Http/0.4.4": {
|
||||
"Wabbajack.Downloaders.Http/0.4.5": {
|
||||
"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.4",
|
||||
"Wabbajack.DTOs": "0.4.4",
|
||||
"Wabbajack.Downloaders.Interfaces": "0.4.4",
|
||||
"Wabbajack.Networking.BethesdaNet": "0.4.4",
|
||||
"Wabbajack.Networking.Http.Interfaces": "0.4.4",
|
||||
"Wabbajack.Paths.IO": "0.4.4"
|
||||
"Wabbajack.Common": "0.4.5",
|
||||
"Wabbajack.DTOs": "0.4.5",
|
||||
"Wabbajack.Downloaders.Interfaces": "0.4.5",
|
||||
"Wabbajack.Networking.BethesdaNet": "0.4.5",
|
||||
"Wabbajack.Networking.Http.Interfaces": "0.4.5",
|
||||
"Wabbajack.Paths.IO": "0.4.5"
|
||||
},
|
||||
"runtime": {
|
||||
"Wabbajack.Downloaders.Http.dll": {}
|
||||
}
|
||||
},
|
||||
"Wabbajack.Downloaders.Interfaces/0.4.4": {
|
||||
"Wabbajack.Downloaders.Interfaces/0.4.5": {
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.DependencyInjection": "9.0.1",
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.1",
|
||||
"Wabbajack.Compression.Zip": "0.4.4",
|
||||
"Wabbajack.DTOs": "0.4.4",
|
||||
"Wabbajack.Paths.IO": "0.4.4"
|
||||
"Wabbajack.Compression.Zip": "0.4.5",
|
||||
"Wabbajack.DTOs": "0.4.5",
|
||||
"Wabbajack.Paths.IO": "0.4.5"
|
||||
},
|
||||
"runtime": {
|
||||
"Wabbajack.Downloaders.Interfaces.dll": {}
|
||||
}
|
||||
},
|
||||
"Wabbajack.Downloaders.IPS4OAuth2Downloader/0.4.4": {
|
||||
"Wabbajack.Downloaders.IPS4OAuth2Downloader/0.4.5": {
|
||||
"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.4",
|
||||
"Wabbajack.Downloaders.Interfaces": "0.4.4",
|
||||
"Wabbajack.Networking.Http": "0.4.4",
|
||||
"Wabbajack.Networking.Http.Interfaces": "0.4.4"
|
||||
"Wabbajack.Common": "0.4.5",
|
||||
"Wabbajack.Downloaders.Interfaces": "0.4.5",
|
||||
"Wabbajack.Networking.Http": "0.4.5",
|
||||
"Wabbajack.Networking.Http.Interfaces": "0.4.5"
|
||||
},
|
||||
"runtime": {
|
||||
"Wabbajack.Downloaders.IPS4OAuth2Downloader.dll": {}
|
||||
}
|
||||
},
|
||||
"Wabbajack.Downloaders.Manual/0.4.4": {
|
||||
"Wabbajack.Downloaders.Manual/0.4.5": {
|
||||
"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.4",
|
||||
"Wabbajack.Downloaders.Interfaces": "0.4.4"
|
||||
"Wabbajack.Common": "0.4.5",
|
||||
"Wabbajack.Downloaders.Interfaces": "0.4.5"
|
||||
},
|
||||
"runtime": {
|
||||
"Wabbajack.Downloaders.Manual.dll": {}
|
||||
}
|
||||
},
|
||||
"Wabbajack.Downloaders.MediaFire/0.4.4": {
|
||||
"Wabbajack.Downloaders.MediaFire/0.4.5": {
|
||||
"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.4",
|
||||
"Wabbajack.Downloaders.Interfaces": "0.4.4",
|
||||
"Wabbajack.Networking.Http.Interfaces": "0.4.4"
|
||||
"Wabbajack.Common": "0.4.5",
|
||||
"Wabbajack.Downloaders.Interfaces": "0.4.5",
|
||||
"Wabbajack.Networking.Http.Interfaces": "0.4.5"
|
||||
},
|
||||
"runtime": {
|
||||
"Wabbajack.Downloaders.MediaFire.dll": {}
|
||||
}
|
||||
},
|
||||
"Wabbajack.Downloaders.Mega/0.4.4": {
|
||||
"Wabbajack.Downloaders.Mega/0.4.5": {
|
||||
"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.4",
|
||||
"Wabbajack.Downloaders.Interfaces": "0.4.4",
|
||||
"Wabbajack.Paths.IO": "0.4.4"
|
||||
"Wabbajack.Common": "0.4.5",
|
||||
"Wabbajack.Downloaders.Interfaces": "0.4.5",
|
||||
"Wabbajack.Paths.IO": "0.4.5"
|
||||
},
|
||||
"runtime": {
|
||||
"Wabbajack.Downloaders.Mega.dll": {}
|
||||
}
|
||||
},
|
||||
"Wabbajack.Downloaders.ModDB/0.4.4": {
|
||||
"Wabbajack.Downloaders.ModDB/0.4.5": {
|
||||
"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.4",
|
||||
"Wabbajack.Downloaders.Interfaces": "0.4.4",
|
||||
"Wabbajack.Networking.Http": "0.4.4",
|
||||
"Wabbajack.Networking.Http.Interfaces": "0.4.4"
|
||||
"Wabbajack.Common": "0.4.5",
|
||||
"Wabbajack.Downloaders.Interfaces": "0.4.5",
|
||||
"Wabbajack.Networking.Http": "0.4.5",
|
||||
"Wabbajack.Networking.Http.Interfaces": "0.4.5"
|
||||
},
|
||||
"runtime": {
|
||||
"Wabbajack.Downloaders.ModDB.dll": {}
|
||||
}
|
||||
},
|
||||
"Wabbajack.Downloaders.Nexus/0.4.4": {
|
||||
"Wabbajack.Downloaders.Nexus/0.4.5": {
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.DependencyInjection": "9.0.1",
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.1",
|
||||
"Wabbajack.DTOs": "0.4.4",
|
||||
"Wabbajack.Downloaders.Interfaces": "0.4.4",
|
||||
"Wabbajack.Hashing.xxHash64": "0.4.4",
|
||||
"Wabbajack.Networking.Http": "0.4.4",
|
||||
"Wabbajack.Networking.Http.Interfaces": "0.4.4",
|
||||
"Wabbajack.Networking.NexusApi": "0.4.4",
|
||||
"Wabbajack.Paths": "0.4.4"
|
||||
"Wabbajack.DTOs": "0.4.5",
|
||||
"Wabbajack.Downloaders.Interfaces": "0.4.5",
|
||||
"Wabbajack.Hashing.xxHash64": "0.4.5",
|
||||
"Wabbajack.Networking.Http": "0.4.5",
|
||||
"Wabbajack.Networking.Http.Interfaces": "0.4.5",
|
||||
"Wabbajack.Networking.NexusApi": "0.4.5",
|
||||
"Wabbajack.Paths": "0.4.5"
|
||||
},
|
||||
"runtime": {
|
||||
"Wabbajack.Downloaders.Nexus.dll": {}
|
||||
}
|
||||
},
|
||||
"Wabbajack.Downloaders.VerificationCache/0.4.4": {
|
||||
"Wabbajack.Downloaders.VerificationCache/0.4.5": {
|
||||
"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.4",
|
||||
"Wabbajack.Paths.IO": "0.4.4"
|
||||
"Wabbajack.DTOs": "0.4.5",
|
||||
"Wabbajack.Paths.IO": "0.4.5"
|
||||
},
|
||||
"runtime": {
|
||||
"Wabbajack.Downloaders.VerificationCache.dll": {}
|
||||
}
|
||||
},
|
||||
"Wabbajack.Downloaders.WabbajackCDN/0.4.4": {
|
||||
"Wabbajack.Downloaders.WabbajackCDN/0.4.5": {
|
||||
"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.4",
|
||||
"Wabbajack.Downloaders.Interfaces": "0.4.4",
|
||||
"Wabbajack.Networking.Http": "0.4.4",
|
||||
"Wabbajack.RateLimiter": "0.4.4"
|
||||
"Wabbajack.Common": "0.4.5",
|
||||
"Wabbajack.Downloaders.Interfaces": "0.4.5",
|
||||
"Wabbajack.Networking.Http": "0.4.5",
|
||||
"Wabbajack.RateLimiter": "0.4.5"
|
||||
},
|
||||
"runtime": {
|
||||
"Wabbajack.Downloaders.WabbajackCDN.dll": {}
|
||||
}
|
||||
},
|
||||
"Wabbajack.DTOs/0.4.4": {
|
||||
"Wabbajack.DTOs/0.4.5": {
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.DependencyInjection": "9.0.1",
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.1",
|
||||
"Wabbajack.Hashing.xxHash64": "0.4.4",
|
||||
"Wabbajack.Paths": "0.4.4"
|
||||
"Wabbajack.Hashing.xxHash64": "0.4.5",
|
||||
"Wabbajack.Paths": "0.4.5"
|
||||
},
|
||||
"runtime": {
|
||||
"Wabbajack.DTOs.dll": {}
|
||||
}
|
||||
},
|
||||
"Wabbajack.FileExtractor/0.4.4": {
|
||||
"Wabbajack.FileExtractor/0.4.5": {
|
||||
"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.4",
|
||||
"Wabbajack.Compression.BSA": "0.4.4",
|
||||
"Wabbajack.Hashing.PHash": "0.4.4",
|
||||
"Wabbajack.Paths": "0.4.4"
|
||||
"Wabbajack.Common": "0.4.5",
|
||||
"Wabbajack.Compression.BSA": "0.4.5",
|
||||
"Wabbajack.Hashing.PHash": "0.4.5",
|
||||
"Wabbajack.Paths": "0.4.5"
|
||||
},
|
||||
"runtime": {
|
||||
"Wabbajack.FileExtractor.dll": {}
|
||||
}
|
||||
},
|
||||
"Wabbajack.Hashing.PHash/0.4.4": {
|
||||
"Wabbajack.Hashing.PHash/0.4.5": {
|
||||
"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.4",
|
||||
"Wabbajack.DTOs": "0.4.4",
|
||||
"Wabbajack.Paths": "0.4.4",
|
||||
"Wabbajack.Paths.IO": "0.4.4"
|
||||
"Wabbajack.Common": "0.4.5",
|
||||
"Wabbajack.DTOs": "0.4.5",
|
||||
"Wabbajack.Paths": "0.4.5",
|
||||
"Wabbajack.Paths.IO": "0.4.5"
|
||||
},
|
||||
"runtime": {
|
||||
"Wabbajack.Hashing.PHash.dll": {}
|
||||
}
|
||||
},
|
||||
"Wabbajack.Hashing.xxHash64/0.4.4": {
|
||||
"Wabbajack.Hashing.xxHash64/0.4.5": {
|
||||
"dependencies": {
|
||||
"Wabbajack.Paths": "0.4.4",
|
||||
"Wabbajack.RateLimiter": "0.4.4"
|
||||
"Wabbajack.Paths": "0.4.5",
|
||||
"Wabbajack.RateLimiter": "0.4.5"
|
||||
},
|
||||
"runtime": {
|
||||
"Wabbajack.Hashing.xxHash64.dll": {}
|
||||
}
|
||||
},
|
||||
"Wabbajack.Installer/0.4.4": {
|
||||
"Wabbajack.Installer/0.4.5": {
|
||||
"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.4",
|
||||
"Wabbajack.Downloaders.Dispatcher": "0.4.4",
|
||||
"Wabbajack.Downloaders.GameFile": "0.4.4",
|
||||
"Wabbajack.FileExtractor": "0.4.4",
|
||||
"Wabbajack.Networking.WabbajackClientApi": "0.4.4",
|
||||
"Wabbajack.Paths": "0.4.4",
|
||||
"Wabbajack.Paths.IO": "0.4.4",
|
||||
"Wabbajack.VFS": "0.4.4",
|
||||
"Wabbajack.DTOs": "0.4.5",
|
||||
"Wabbajack.Downloaders.Dispatcher": "0.4.5",
|
||||
"Wabbajack.Downloaders.GameFile": "0.4.5",
|
||||
"Wabbajack.FileExtractor": "0.4.5",
|
||||
"Wabbajack.Networking.WabbajackClientApi": "0.4.5",
|
||||
"Wabbajack.Paths": "0.4.5",
|
||||
"Wabbajack.Paths.IO": "0.4.5",
|
||||
"Wabbajack.VFS": "0.4.5",
|
||||
"ini-parser-netstandard": "2.5.2"
|
||||
},
|
||||
"runtime": {
|
||||
"Wabbajack.Installer.dll": {}
|
||||
}
|
||||
},
|
||||
"Wabbajack.IO.Async/0.4.4": {
|
||||
"Wabbajack.IO.Async/0.4.5": {
|
||||
"runtime": {
|
||||
"Wabbajack.IO.Async.dll": {}
|
||||
}
|
||||
},
|
||||
"Wabbajack.Networking.BethesdaNet/0.4.4": {
|
||||
"Wabbajack.Networking.BethesdaNet/0.4.5": {
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.DependencyInjection": "9.0.1",
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.1",
|
||||
"Wabbajack.DTOs": "0.4.4",
|
||||
"Wabbajack.Networking.Http": "0.4.4",
|
||||
"Wabbajack.Networking.Http.Interfaces": "0.4.4"
|
||||
"Wabbajack.DTOs": "0.4.5",
|
||||
"Wabbajack.Networking.Http": "0.4.5",
|
||||
"Wabbajack.Networking.Http.Interfaces": "0.4.5"
|
||||
},
|
||||
"runtime": {
|
||||
"Wabbajack.Networking.BethesdaNet.dll": {}
|
||||
}
|
||||
},
|
||||
"Wabbajack.Networking.Discord/0.4.4": {
|
||||
"Wabbajack.Networking.Discord/0.4.5": {
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.1",
|
||||
"Microsoft.Extensions.Logging.Abstractions": "9.0.1",
|
||||
"Wabbajack.Networking.Http.Interfaces": "0.4.4"
|
||||
"Wabbajack.Networking.Http.Interfaces": "0.4.5"
|
||||
},
|
||||
"runtime": {
|
||||
"Wabbajack.Networking.Discord.dll": {}
|
||||
}
|
||||
},
|
||||
"Wabbajack.Networking.GitHub/0.4.4": {
|
||||
"Wabbajack.Networking.GitHub/0.4.5": {
|
||||
"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.4",
|
||||
"Wabbajack.Networking.Http.Interfaces": "0.4.4"
|
||||
"Wabbajack.DTOs": "0.4.5",
|
||||
"Wabbajack.Networking.Http.Interfaces": "0.4.5"
|
||||
},
|
||||
"runtime": {
|
||||
"Wabbajack.Networking.GitHub.dll": {}
|
||||
}
|
||||
},
|
||||
"Wabbajack.Networking.Http/0.4.4": {
|
||||
"Wabbajack.Networking.Http/0.4.5": {
|
||||
"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.4",
|
||||
"Wabbajack.Downloaders.Interfaces": "0.4.4",
|
||||
"Wabbajack.Hashing.xxHash64": "0.4.4",
|
||||
"Wabbajack.Networking.Http.Interfaces": "0.4.4",
|
||||
"Wabbajack.Paths": "0.4.4",
|
||||
"Wabbajack.Paths.IO": "0.4.4"
|
||||
"Wabbajack.Configuration": "0.4.5",
|
||||
"Wabbajack.Downloaders.Interfaces": "0.4.5",
|
||||
"Wabbajack.Hashing.xxHash64": "0.4.5",
|
||||
"Wabbajack.Networking.Http.Interfaces": "0.4.5",
|
||||
"Wabbajack.Paths": "0.4.5",
|
||||
"Wabbajack.Paths.IO": "0.4.5"
|
||||
},
|
||||
"runtime": {
|
||||
"Wabbajack.Networking.Http.dll": {}
|
||||
}
|
||||
},
|
||||
"Wabbajack.Networking.Http.Interfaces/0.4.4": {
|
||||
"Wabbajack.Networking.Http.Interfaces/0.4.5": {
|
||||
"dependencies": {
|
||||
"Wabbajack.Hashing.xxHash64": "0.4.4"
|
||||
"Wabbajack.Hashing.xxHash64": "0.4.5"
|
||||
},
|
||||
"runtime": {
|
||||
"Wabbajack.Networking.Http.Interfaces.dll": {}
|
||||
}
|
||||
},
|
||||
"Wabbajack.Networking.NexusApi/0.4.4": {
|
||||
"Wabbajack.Networking.NexusApi/0.4.5": {
|
||||
"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.4",
|
||||
"Wabbajack.Networking.Http": "0.4.4",
|
||||
"Wabbajack.Networking.Http.Interfaces": "0.4.4",
|
||||
"Wabbajack.Networking.WabbajackClientApi": "0.4.4"
|
||||
"Wabbajack.DTOs": "0.4.5",
|
||||
"Wabbajack.Networking.Http": "0.4.5",
|
||||
"Wabbajack.Networking.Http.Interfaces": "0.4.5",
|
||||
"Wabbajack.Networking.WabbajackClientApi": "0.4.5"
|
||||
},
|
||||
"runtime": {
|
||||
"Wabbajack.Networking.NexusApi.dll": {}
|
||||
}
|
||||
},
|
||||
"Wabbajack.Networking.WabbajackClientApi/0.4.4": {
|
||||
"Wabbajack.Networking.WabbajackClientApi/0.4.5": {
|
||||
"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.4",
|
||||
"Wabbajack.DTOs": "0.4.4",
|
||||
"Wabbajack.Paths.IO": "0.4.4",
|
||||
"Wabbajack.VFS.Interfaces": "0.4.4",
|
||||
"Wabbajack.Common": "0.4.5",
|
||||
"Wabbajack.DTOs": "0.4.5",
|
||||
"Wabbajack.Paths.IO": "0.4.5",
|
||||
"Wabbajack.VFS.Interfaces": "0.4.5",
|
||||
"YamlDotNet": "16.3.0"
|
||||
},
|
||||
"runtime": {
|
||||
"Wabbajack.Networking.WabbajackClientApi.dll": {}
|
||||
}
|
||||
},
|
||||
"Wabbajack.Paths/0.4.4": {
|
||||
"Wabbajack.Paths/0.4.5": {
|
||||
"runtime": {
|
||||
"Wabbajack.Paths.dll": {}
|
||||
}
|
||||
},
|
||||
"Wabbajack.Paths.IO/0.4.4": {
|
||||
"Wabbajack.Paths.IO/0.4.5": {
|
||||
"dependencies": {
|
||||
"Wabbajack.Paths": "0.4.4",
|
||||
"Wabbajack.Paths": "0.4.5",
|
||||
"shortid": "4.0.0"
|
||||
},
|
||||
"runtime": {
|
||||
"Wabbajack.Paths.IO.dll": {}
|
||||
}
|
||||
},
|
||||
"Wabbajack.RateLimiter/0.4.4": {
|
||||
"Wabbajack.RateLimiter/0.4.5": {
|
||||
"runtime": {
|
||||
"Wabbajack.RateLimiter.dll": {}
|
||||
}
|
||||
},
|
||||
"Wabbajack.Server.Lib/0.4.4": {
|
||||
"Wabbajack.Server.Lib/0.4.5": {
|
||||
"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.4",
|
||||
"Wabbajack.Networking.Http.Interfaces": "0.4.4",
|
||||
"Wabbajack.Services.OSIntegrated": "0.4.4"
|
||||
"Wabbajack.Common": "0.4.5",
|
||||
"Wabbajack.Networking.Http.Interfaces": "0.4.5",
|
||||
"Wabbajack.Services.OSIntegrated": "0.4.5"
|
||||
},
|
||||
"runtime": {
|
||||
"Wabbajack.Server.Lib.dll": {}
|
||||
}
|
||||
},
|
||||
"Wabbajack.Services.OSIntegrated/0.4.4": {
|
||||
"Wabbajack.Services.OSIntegrated/0.4.5": {
|
||||
"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.4",
|
||||
"Wabbajack.Downloaders.Dispatcher": "0.4.4",
|
||||
"Wabbajack.Installer": "0.4.4",
|
||||
"Wabbajack.Networking.BethesdaNet": "0.4.4",
|
||||
"Wabbajack.Networking.Discord": "0.4.4",
|
||||
"Wabbajack.VFS": "0.4.4"
|
||||
"Wabbajack.Compiler": "0.4.5",
|
||||
"Wabbajack.Downloaders.Dispatcher": "0.4.5",
|
||||
"Wabbajack.Installer": "0.4.5",
|
||||
"Wabbajack.Networking.BethesdaNet": "0.4.5",
|
||||
"Wabbajack.Networking.Discord": "0.4.5",
|
||||
"Wabbajack.VFS": "0.4.5"
|
||||
},
|
||||
"runtime": {
|
||||
"Wabbajack.Services.OSIntegrated.dll": {}
|
||||
}
|
||||
},
|
||||
"Wabbajack.VFS/0.4.4": {
|
||||
"Wabbajack.VFS/0.4.5": {
|
||||
"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.4",
|
||||
"Wabbajack.FileExtractor": "0.4.4",
|
||||
"Wabbajack.Hashing.PHash": "0.4.4",
|
||||
"Wabbajack.Hashing.xxHash64": "0.4.4",
|
||||
"Wabbajack.Paths": "0.4.4",
|
||||
"Wabbajack.Paths.IO": "0.4.4",
|
||||
"Wabbajack.VFS.Interfaces": "0.4.4"
|
||||
"Wabbajack.Common": "0.4.5",
|
||||
"Wabbajack.FileExtractor": "0.4.5",
|
||||
"Wabbajack.Hashing.PHash": "0.4.5",
|
||||
"Wabbajack.Hashing.xxHash64": "0.4.5",
|
||||
"Wabbajack.Paths": "0.4.5",
|
||||
"Wabbajack.Paths.IO": "0.4.5",
|
||||
"Wabbajack.VFS.Interfaces": "0.4.5"
|
||||
},
|
||||
"runtime": {
|
||||
"Wabbajack.VFS.dll": {}
|
||||
}
|
||||
},
|
||||
"Wabbajack.VFS.Interfaces/0.4.4": {
|
||||
"Wabbajack.VFS.Interfaces/0.4.5": {
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.DependencyInjection": "9.0.1",
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.1",
|
||||
"Wabbajack.DTOs": "0.4.4",
|
||||
"Wabbajack.Hashing.xxHash64": "0.4.4",
|
||||
"Wabbajack.Paths": "0.4.4"
|
||||
"Wabbajack.DTOs": "0.4.5",
|
||||
"Wabbajack.Hashing.xxHash64": "0.4.5",
|
||||
"Wabbajack.Paths": "0.4.5"
|
||||
},
|
||||
"runtime": {
|
||||
"Wabbajack.VFS.Interfaces.dll": {}
|
||||
@@ -2332,7 +2332,7 @@
|
||||
}
|
||||
},
|
||||
"libraries": {
|
||||
"jackify-engine/0.4.4": {
|
||||
"jackify-engine/0.4.5": {
|
||||
"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.4": {
|
||||
"Wabbajack.CLI.Builder/0.4.5": {
|
||||
"type": "project",
|
||||
"serviceable": false,
|
||||
"sha512": ""
|
||||
},
|
||||
"Wabbajack.Common/0.4.4": {
|
||||
"Wabbajack.Common/0.4.5": {
|
||||
"type": "project",
|
||||
"serviceable": false,
|
||||
"sha512": ""
|
||||
},
|
||||
"Wabbajack.Compiler/0.4.4": {
|
||||
"Wabbajack.Compiler/0.4.5": {
|
||||
"type": "project",
|
||||
"serviceable": false,
|
||||
"sha512": ""
|
||||
},
|
||||
"Wabbajack.Compression.BSA/0.4.4": {
|
||||
"Wabbajack.Compression.BSA/0.4.5": {
|
||||
"type": "project",
|
||||
"serviceable": false,
|
||||
"sha512": ""
|
||||
},
|
||||
"Wabbajack.Compression.Zip/0.4.4": {
|
||||
"Wabbajack.Compression.Zip/0.4.5": {
|
||||
"type": "project",
|
||||
"serviceable": false,
|
||||
"sha512": ""
|
||||
},
|
||||
"Wabbajack.Configuration/0.4.4": {
|
||||
"Wabbajack.Configuration/0.4.5": {
|
||||
"type": "project",
|
||||
"serviceable": false,
|
||||
"sha512": ""
|
||||
},
|
||||
"Wabbajack.Downloaders.Bethesda/0.4.4": {
|
||||
"Wabbajack.Downloaders.Bethesda/0.4.5": {
|
||||
"type": "project",
|
||||
"serviceable": false,
|
||||
"sha512": ""
|
||||
},
|
||||
"Wabbajack.Downloaders.Dispatcher/0.4.4": {
|
||||
"Wabbajack.Downloaders.Dispatcher/0.4.5": {
|
||||
"type": "project",
|
||||
"serviceable": false,
|
||||
"sha512": ""
|
||||
},
|
||||
"Wabbajack.Downloaders.GameFile/0.4.4": {
|
||||
"Wabbajack.Downloaders.GameFile/0.4.5": {
|
||||
"type": "project",
|
||||
"serviceable": false,
|
||||
"sha512": ""
|
||||
},
|
||||
"Wabbajack.Downloaders.GoogleDrive/0.4.4": {
|
||||
"Wabbajack.Downloaders.GoogleDrive/0.4.5": {
|
||||
"type": "project",
|
||||
"serviceable": false,
|
||||
"sha512": ""
|
||||
},
|
||||
"Wabbajack.Downloaders.Http/0.4.4": {
|
||||
"Wabbajack.Downloaders.Http/0.4.5": {
|
||||
"type": "project",
|
||||
"serviceable": false,
|
||||
"sha512": ""
|
||||
},
|
||||
"Wabbajack.Downloaders.Interfaces/0.4.4": {
|
||||
"Wabbajack.Downloaders.Interfaces/0.4.5": {
|
||||
"type": "project",
|
||||
"serviceable": false,
|
||||
"sha512": ""
|
||||
},
|
||||
"Wabbajack.Downloaders.IPS4OAuth2Downloader/0.4.4": {
|
||||
"Wabbajack.Downloaders.IPS4OAuth2Downloader/0.4.5": {
|
||||
"type": "project",
|
||||
"serviceable": false,
|
||||
"sha512": ""
|
||||
},
|
||||
"Wabbajack.Downloaders.Manual/0.4.4": {
|
||||
"Wabbajack.Downloaders.Manual/0.4.5": {
|
||||
"type": "project",
|
||||
"serviceable": false,
|
||||
"sha512": ""
|
||||
},
|
||||
"Wabbajack.Downloaders.MediaFire/0.4.4": {
|
||||
"Wabbajack.Downloaders.MediaFire/0.4.5": {
|
||||
"type": "project",
|
||||
"serviceable": false,
|
||||
"sha512": ""
|
||||
},
|
||||
"Wabbajack.Downloaders.Mega/0.4.4": {
|
||||
"Wabbajack.Downloaders.Mega/0.4.5": {
|
||||
"type": "project",
|
||||
"serviceable": false,
|
||||
"sha512": ""
|
||||
},
|
||||
"Wabbajack.Downloaders.ModDB/0.4.4": {
|
||||
"Wabbajack.Downloaders.ModDB/0.4.5": {
|
||||
"type": "project",
|
||||
"serviceable": false,
|
||||
"sha512": ""
|
||||
},
|
||||
"Wabbajack.Downloaders.Nexus/0.4.4": {
|
||||
"Wabbajack.Downloaders.Nexus/0.4.5": {
|
||||
"type": "project",
|
||||
"serviceable": false,
|
||||
"sha512": ""
|
||||
},
|
||||
"Wabbajack.Downloaders.VerificationCache/0.4.4": {
|
||||
"Wabbajack.Downloaders.VerificationCache/0.4.5": {
|
||||
"type": "project",
|
||||
"serviceable": false,
|
||||
"sha512": ""
|
||||
},
|
||||
"Wabbajack.Downloaders.WabbajackCDN/0.4.4": {
|
||||
"Wabbajack.Downloaders.WabbajackCDN/0.4.5": {
|
||||
"type": "project",
|
||||
"serviceable": false,
|
||||
"sha512": ""
|
||||
},
|
||||
"Wabbajack.DTOs/0.4.4": {
|
||||
"Wabbajack.DTOs/0.4.5": {
|
||||
"type": "project",
|
||||
"serviceable": false,
|
||||
"sha512": ""
|
||||
},
|
||||
"Wabbajack.FileExtractor/0.4.4": {
|
||||
"Wabbajack.FileExtractor/0.4.5": {
|
||||
"type": "project",
|
||||
"serviceable": false,
|
||||
"sha512": ""
|
||||
},
|
||||
"Wabbajack.Hashing.PHash/0.4.4": {
|
||||
"Wabbajack.Hashing.PHash/0.4.5": {
|
||||
"type": "project",
|
||||
"serviceable": false,
|
||||
"sha512": ""
|
||||
},
|
||||
"Wabbajack.Hashing.xxHash64/0.4.4": {
|
||||
"Wabbajack.Hashing.xxHash64/0.4.5": {
|
||||
"type": "project",
|
||||
"serviceable": false,
|
||||
"sha512": ""
|
||||
},
|
||||
"Wabbajack.Installer/0.4.4": {
|
||||
"Wabbajack.Installer/0.4.5": {
|
||||
"type": "project",
|
||||
"serviceable": false,
|
||||
"sha512": ""
|
||||
},
|
||||
"Wabbajack.IO.Async/0.4.4": {
|
||||
"Wabbajack.IO.Async/0.4.5": {
|
||||
"type": "project",
|
||||
"serviceable": false,
|
||||
"sha512": ""
|
||||
},
|
||||
"Wabbajack.Networking.BethesdaNet/0.4.4": {
|
||||
"Wabbajack.Networking.BethesdaNet/0.4.5": {
|
||||
"type": "project",
|
||||
"serviceable": false,
|
||||
"sha512": ""
|
||||
},
|
||||
"Wabbajack.Networking.Discord/0.4.4": {
|
||||
"Wabbajack.Networking.Discord/0.4.5": {
|
||||
"type": "project",
|
||||
"serviceable": false,
|
||||
"sha512": ""
|
||||
},
|
||||
"Wabbajack.Networking.GitHub/0.4.4": {
|
||||
"Wabbajack.Networking.GitHub/0.4.5": {
|
||||
"type": "project",
|
||||
"serviceable": false,
|
||||
"sha512": ""
|
||||
},
|
||||
"Wabbajack.Networking.Http/0.4.4": {
|
||||
"Wabbajack.Networking.Http/0.4.5": {
|
||||
"type": "project",
|
||||
"serviceable": false,
|
||||
"sha512": ""
|
||||
},
|
||||
"Wabbajack.Networking.Http.Interfaces/0.4.4": {
|
||||
"Wabbajack.Networking.Http.Interfaces/0.4.5": {
|
||||
"type": "project",
|
||||
"serviceable": false,
|
||||
"sha512": ""
|
||||
},
|
||||
"Wabbajack.Networking.NexusApi/0.4.4": {
|
||||
"Wabbajack.Networking.NexusApi/0.4.5": {
|
||||
"type": "project",
|
||||
"serviceable": false,
|
||||
"sha512": ""
|
||||
},
|
||||
"Wabbajack.Networking.WabbajackClientApi/0.4.4": {
|
||||
"Wabbajack.Networking.WabbajackClientApi/0.4.5": {
|
||||
"type": "project",
|
||||
"serviceable": false,
|
||||
"sha512": ""
|
||||
},
|
||||
"Wabbajack.Paths/0.4.4": {
|
||||
"Wabbajack.Paths/0.4.5": {
|
||||
"type": "project",
|
||||
"serviceable": false,
|
||||
"sha512": ""
|
||||
},
|
||||
"Wabbajack.Paths.IO/0.4.4": {
|
||||
"Wabbajack.Paths.IO/0.4.5": {
|
||||
"type": "project",
|
||||
"serviceable": false,
|
||||
"sha512": ""
|
||||
},
|
||||
"Wabbajack.RateLimiter/0.4.4": {
|
||||
"Wabbajack.RateLimiter/0.4.5": {
|
||||
"type": "project",
|
||||
"serviceable": false,
|
||||
"sha512": ""
|
||||
},
|
||||
"Wabbajack.Server.Lib/0.4.4": {
|
||||
"Wabbajack.Server.Lib/0.4.5": {
|
||||
"type": "project",
|
||||
"serviceable": false,
|
||||
"sha512": ""
|
||||
},
|
||||
"Wabbajack.Services.OSIntegrated/0.4.4": {
|
||||
"Wabbajack.Services.OSIntegrated/0.4.5": {
|
||||
"type": "project",
|
||||
"serviceable": false,
|
||||
"sha512": ""
|
||||
},
|
||||
"Wabbajack.VFS/0.4.4": {
|
||||
"Wabbajack.VFS/0.4.5": {
|
||||
"type": "project",
|
||||
"serviceable": false,
|
||||
"sha512": ""
|
||||
},
|
||||
"Wabbajack.VFS.Interfaces/0.4.4": {
|
||||
"Wabbajack.VFS.Interfaces/0.4.5": {
|
||||
"type": "project",
|
||||
"serviceable": false,
|
||||
"sha512": ""
|
||||
|
||||
Binary file not shown.
@@ -1891,7 +1891,8 @@ def main():
|
||||
# Initialize file logging on root logger so all modules inherit it
|
||||
from jackify.shared.logging import LoggingHandler
|
||||
logging_handler = LoggingHandler()
|
||||
# Rotate log file before setting up new logger
|
||||
# Only rotate log file when debug mode is enabled
|
||||
if debug_mode:
|
||||
logging_handler.rotate_log_for_logger('jackify_gui', 'jackify-gui.log')
|
||||
root_logger = logging_handler.setup_logger('', 'jackify-gui.log', is_general=True) # Empty name = root logger
|
||||
|
||||
|
||||
@@ -639,6 +639,8 @@ class ConfigureExistingModlistScreen(QWidget):
|
||||
# Start time tracking
|
||||
self._workflow_start_time = time.time()
|
||||
|
||||
from jackify import __version__ as jackify_version
|
||||
self._safe_append_text(f"Jackify v{jackify_version}")
|
||||
self._safe_append_text("[Jackify] Starting post-install configuration...")
|
||||
|
||||
# Create configuration thread using backend service
|
||||
|
||||
@@ -921,6 +921,8 @@ class ConfigureNewModlistScreen(QWidget):
|
||||
self._safe_append_text("Steam restarted successfully.")
|
||||
|
||||
# Start configuration immediately - the CLI will handle any manual steps
|
||||
from jackify import __version__ as jackify_version
|
||||
self._safe_append_text(f"Jackify v{jackify_version}")
|
||||
self._safe_append_text("Starting modlist configuration...")
|
||||
self.configure_modlist()
|
||||
else:
|
||||
@@ -950,6 +952,8 @@ class ConfigureNewModlistScreen(QWidget):
|
||||
|
||||
def _start_automated_prefix_workflow(self, modlist_name, install_dir, mo2_exe_path, resolution):
|
||||
"""Start the automated prefix workflow using AutomatedPrefixService in a background thread"""
|
||||
from jackify import __version__ as jackify_version
|
||||
self._safe_append_text(f"Jackify v{jackify_version}")
|
||||
self._safe_append_text(f"Initializing automated Steam setup for '{modlist_name}'...")
|
||||
self._safe_append_text("Starting automated Steam shortcut creation and configuration...")
|
||||
|
||||
|
||||
@@ -1869,7 +1869,7 @@ class InstallModlistScreen(QWidget):
|
||||
downloads_dir = self.downloads_dir_edit.text().strip()
|
||||
|
||||
# Get authentication token (OAuth or API key) with automatic refresh
|
||||
api_key = self.auth_service.ensure_valid_auth()
|
||||
api_key, oauth_info = self.auth_service.get_auth_for_engine()
|
||||
if not api_key:
|
||||
self._abort_with_message(
|
||||
"warning",
|
||||
@@ -2097,7 +2097,7 @@ class InstallModlistScreen(QWidget):
|
||||
return
|
||||
|
||||
debug_print(f'DEBUG: Calling run_modlist_installer with modlist={modlist}, install_dir={install_dir}, downloads_dir={downloads_dir}, install_mode={install_mode}')
|
||||
self.run_modlist_installer(modlist, install_dir, downloads_dir, api_key, install_mode)
|
||||
self.run_modlist_installer(modlist, install_dir, downloads_dir, api_key, install_mode, oauth_info)
|
||||
except Exception as e:
|
||||
debug_print(f"DEBUG: Exception in validate_and_start_install: {e}")
|
||||
import traceback
|
||||
@@ -2108,7 +2108,7 @@ class InstallModlistScreen(QWidget):
|
||||
self.cancel_install_btn.setVisible(False)
|
||||
debug_print(f"DEBUG: Controls re-enabled in exception handler")
|
||||
|
||||
def run_modlist_installer(self, modlist, install_dir, downloads_dir, api_key, install_mode='online'):
|
||||
def run_modlist_installer(self, modlist, install_dir, downloads_dir, api_key, install_mode='online', oauth_info=None):
|
||||
debug_print('DEBUG: run_modlist_installer called - USING THREADED BACKEND WRAPPER')
|
||||
|
||||
# Rotate log file at start of each workflow run (keep 5 backups)
|
||||
@@ -2119,6 +2119,8 @@ class InstallModlistScreen(QWidget):
|
||||
|
||||
# Clear console for fresh installation output
|
||||
self.console.clear()
|
||||
from jackify import __version__ as jackify_version
|
||||
self._safe_append_text(f"Jackify v{jackify_version}")
|
||||
self._safe_append_text("Starting modlist installation with custom progress handling...")
|
||||
|
||||
# Update UI state for installation
|
||||
@@ -2136,7 +2138,7 @@ class InstallModlistScreen(QWidget):
|
||||
installation_finished = Signal(bool, str)
|
||||
premium_required_detected = Signal(str)
|
||||
|
||||
def __init__(self, modlist, install_dir, downloads_dir, api_key, modlist_name, install_mode='online', progress_state_manager=None):
|
||||
def __init__(self, modlist, install_dir, downloads_dir, api_key, modlist_name, install_mode='online', progress_state_manager=None, auth_service=None, oauth_info=None):
|
||||
super().__init__()
|
||||
self.modlist = modlist
|
||||
self.install_dir = install_dir
|
||||
@@ -2148,6 +2150,8 @@ class InstallModlistScreen(QWidget):
|
||||
self.process_manager = None
|
||||
# R&D: Progress state manager for parsing
|
||||
self.progress_state_manager = progress_state_manager
|
||||
self.auth_service = auth_service
|
||||
self.oauth_info = oauth_info
|
||||
self._premium_signal_sent = False
|
||||
# Rolling buffer for Premium detection diagnostics
|
||||
self._engine_output_buffer = []
|
||||
@@ -2196,7 +2200,10 @@ class InstallModlistScreen(QWidget):
|
||||
|
||||
# Use clean subprocess environment to prevent AppImage variable inheritance
|
||||
from jackify.backend.handlers.subprocess_utils import get_clean_subprocess_env
|
||||
env = get_clean_subprocess_env({'NEXUS_API_KEY': self.api_key})
|
||||
env_vars = {'NEXUS_API_KEY': self.api_key}
|
||||
if self.oauth_info:
|
||||
env_vars['NEXUS_OAUTH_INFO'] = self.oauth_info
|
||||
env = get_clean_subprocess_env(env_vars)
|
||||
self.process_manager = ProcessManager(cmd, env=env, text=False)
|
||||
ansi_escape = re.compile(rb'\x1b\[[0-9;?]*[ -/]*[@-~]')
|
||||
buffer = b''
|
||||
@@ -2451,7 +2458,9 @@ class InstallModlistScreen(QWidget):
|
||||
# After the InstallationThread class definition, add:
|
||||
self.install_thread = InstallationThread(
|
||||
modlist, install_dir, downloads_dir, api_key, self.modlist_name_edit.text().strip(), install_mode,
|
||||
progress_state_manager=self.progress_state_manager # R&D: Pass progress state manager
|
||||
progress_state_manager=self.progress_state_manager, # R&D: Pass progress state manager
|
||||
auth_service=self.auth_service, # Fix Issue #127: Pass auth_service for Premium detection diagnostics
|
||||
oauth_info=oauth_info # Pass OAuth state for auto-refresh
|
||||
)
|
||||
self.install_thread.output_received.connect(self.on_installation_output)
|
||||
self.install_thread.progress_received.connect(self.on_installation_progress)
|
||||
|
||||
Reference in New Issue
Block a user