mirror of
https://github.com/Omni-guides/Jackify.git
synced 2026-01-17 19:47:00 +01:00
Sync from development - prepare for v0.2.0.4
This commit is contained in:
22
CHANGELOG.md
22
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
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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'),
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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}")
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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}")
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
@@ -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"
|
||||
|
||||
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.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": ""
|
||||
|
||||
Binary file not shown.
@@ -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):
|
||||
|
||||
@@ -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}'")
|
||||
|
||||
@@ -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"<span style='color: #aaa;'>Download:</span> {self.metadata.sizes.downloadSizeFormatted} • "
|
||||
f"<span style='color: #aaa;'>Install:</span> {self.metadata.sizes.installSizeFormatted} • "
|
||||
f"<span style='color: #aaa;'>Total:</span> {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"<span style='color: #aaa;'>version</span> {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"<span style='color: #aaa;'>Download:</span> {self.metadata.sizes.downloadSizeFormatted} • "
|
||||
f"<span style='color: #aaa;'>Install:</span> {self.metadata.sizes.installSizeFormatted} • "
|
||||
f"<span style='color: #aaa;'>Total:</span> {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("<b style='color: #aaa; font-size: 14px;'>Description:</b>")
|
||||
@@ -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}")
|
||||
|
||||
Reference in New Issue
Block a user