8 Commits

Author SHA1 Message Date
Omni
2511c9334c Sync from development - prepare for v0.2.0.8 2025-12-29 19:55:38 +00:00
Omni
5869a896a8 Sync from development - prepare for v0.2.0.7 2025-12-28 22:17:44 +00:00
Omni
99fb369d5e Sync from development - prepare for v0.2.0.6 2025-12-28 18:52:07 +00:00
Omni
a813236e51 Sync from development - prepare for v0.2.0.5 2025-12-24 21:53:12 +00:00
Omni
a7ed4b2a1e Sync from development - prepare for v0.2.0.4 2025-12-23 21:49:18 +00:00
Omni
523681a254 Sync from development - prepare for v0.2.0.3 2025-12-21 21:11:04 +00:00
Omni
abfca5268f Sync from development - prepare for v0.2.0.3 2025-12-21 21:09:38 +00:00
Omni
4de5c7f55d Sync from development - prepare for v0.2.0.2 2025-12-19 22:57:22 +00:00
250 changed files with 1395 additions and 797 deletions

View File

@@ -1,5 +1,97 @@
# Jackify Changelog
## v0.2.0.8 - Bug Fixes and Improvements
**Release Date:** 2025-12-29
### Bug Fixes
- Fixed Configure New/Existing/TTW screens missing Activity tab and progress updates
- Fixed cancel/back buttons crashing in Configure workflows
### Improvements
- Install directory now auto-appends modlist name when selected from gallery
### Known Issues
- Mod filter temporarily disabled in gallery due to technical issue (tag and game filters still work)
---
## v0.2.0.7 - Critical Auth Fix
**Release Date:** 2025-12-28
### Critical Bug Fixes
- **OAuth Token Loss**: Fixed version comparison bug that was deleting OAuth tokens every time settings were saved (affects users on v0.2.0.4+)
- Fixed internal import paths for improved stability
---
## v0.2.0.6 - Premium Detection and Engine Update
**Release Date:** 2025-12-28
**IMPORTANT:** If you are on v0.2.0.5, automatic updates will not work. You must manually download and install v0.2.0.6.
### Engine Updates
- **jackify-engine 0.4.4**: Latest engine version with improvements
### Critical Bug Fixes
- **Auto-Update System**: Fixed broken update dialog import that prevented automatic updates
- **Premium Detection**: Fixed false Premium errors caused by overly-broad detection pattern triggering on jackify-engine 0.4.3's userinfo JSON output
- **Custom Data Directory**: Fixed AppImage always creating ~/Jackify on startup, even when user configured a custom jackify_data_dir
- **Proton Auto-Selection**: Fixed auto-selection writing invalid "auto" string to config on detection failure
### Quality Improvements
- Added pre-build import validator to prevent broken imports from reaching production
---
## v0.2.0.5 - Emergency OAuth Fix
**Release Date:** 2025-12-24
### Critical Bug Fixes
- **OAuth Authentication**: Fixed regression in v0.2.0.4 that prevented OAuth token encryption/decryption, breaking Nexus authentication for users
---
## 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
### Engine Updates
- **jackify-engine 0.4.3**: Bugfix release
### UI Improvements
- **Settings Dialog**: Removed GPU disable toggle - GPU usage is now always enabled (the disable option was non-functional)
---
## v0.2.0.2 - Emergency Engine Bugfix
**Release Date:** 2025-12-18
### Engine Updates
- **jackify-engine 0.4.2**: Fixed OOM issue with jackify-engine 0.4.1 due to array size
---
## v0.2.0.1 - Critical Bugfix Release
**Release Date:** 2025-12-15

View File

@@ -5,4 +5,4 @@ This package provides both CLI and GUI interfaces for managing
Wabbajack modlists natively on Linux systems.
"""
__version__ = "0.2.0.1"
__version__ = "0.2.0.8"

View File

@@ -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'),

View File

@@ -157,7 +157,8 @@ class ConfigHandler:
# Migration: v0.0.x -> v0.2.0
# Encryption changed from cryptography (Fernet) to pycryptodome (AES-GCM)
# Old encrypted API keys cannot be decrypted, must be re-entered
if current_version < "0.2.0":
from packaging import version
if version.parse(current_version) < version.parse("0.2.0"):
# Clear old encrypted credentials
if self.settings.get("nexus_api_key"):
logger.warning("Clearing saved API key due to encryption format change")
@@ -389,6 +390,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 +420,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:

View File

@@ -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}")

View File

@@ -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:

View File

@@ -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')

View File

@@ -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

View File

@@ -205,8 +205,8 @@ class ShortcutHandler:
time.sleep(1) # Give some time for the install to complete
# Now import it
import steam_vdf
import vdf as steam_vdf
with open(shortcuts_file, 'rb') as f:
shortcuts_data = steam_vdf.load(f)

View File

@@ -48,6 +48,9 @@ def get_clean_subprocess_env(extra_env=None):
env = os.environ.copy()
# Save APPDIR before removing it (we need it to find bundled tools)
appdir = env.get('APPDIR')
# Remove AppImage-specific variables that can confuse subprocess calls
# These variables cause subprocesses to be interpreted as new AppImage launches
for key in ['APPIMAGE', 'APPDIR', 'ARGV0', 'OWD']:
@@ -57,10 +60,10 @@ def get_clean_subprocess_env(extra_env=None):
for k in list(env):
if k.startswith('_MEIPASS'):
del env[k]
# Get current PATH - ensure we preserve system paths
current_path = env.get('PATH', '')
# Ensure common system directories are in PATH if not already present
# This is critical for tools like lz4 that might be in /usr/bin, /usr/local/bin, etc.
system_paths = ['/usr/bin', '/usr/local/bin', '/bin', '/sbin', '/usr/sbin']
@@ -68,10 +71,10 @@ def get_clean_subprocess_env(extra_env=None):
for sys_path in system_paths:
if sys_path not in path_parts and os.path.isdir(sys_path):
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
appdir = env.get('APPDIR')
# Note: appdir was saved before env cleanup above
tools_dir = None
if appdir:

View File

@@ -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

View File

@@ -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}")

View File

@@ -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:

View File

@@ -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,

View File

@@ -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]

View File

@@ -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:

View File

@@ -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:

View File

@@ -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

View File

@@ -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"

View File

@@ -34,9 +34,6 @@ def is_non_premium_indicator(line: str) -> bool:
if phrase in normalized:
return True
if "nexus" in normalized and "premium" in normalized:
return True
# Manual download + Nexus URL implies premium requirement in current workflows.
if "manual download" in normalized and ("nexusmods.com" in normalized or "nexus mods" in normalized):
return True

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.

Some files were not shown because too many files have changed in this diff Show More