mirror of
https://github.com/Omni-guides/Jackify.git
synced 2026-01-17 19:47:00 +01:00
Sync from development - prepare for v0.1.1
This commit is contained in:
@@ -101,7 +101,7 @@ class AutomatedPrefixService:
|
||||
logger.info(f" Native Steam service created shortcut successfully with AppID: {app_id}")
|
||||
return True, app_id
|
||||
else:
|
||||
logger.error("❌ Native Steam service failed to create shortcut")
|
||||
logger.error("Native Steam service failed to create shortcut")
|
||||
return False, None
|
||||
|
||||
except Exception as e:
|
||||
@@ -471,7 +471,7 @@ exit"""
|
||||
logger.warning(f"Error running protontricks -l on attempt {i+1}: {e}")
|
||||
time.sleep(1)
|
||||
|
||||
logger.error(f"❌ Shortcut '{shortcut_name}' not found in protontricks after 30 seconds")
|
||||
logger.error(f"Shortcut '{shortcut_name}' not found in protontricks after 30 seconds")
|
||||
return None
|
||||
|
||||
except Exception as e:
|
||||
@@ -939,7 +939,7 @@ echo Prefix creation complete.
|
||||
except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.TimeoutExpired):
|
||||
continue
|
||||
|
||||
logger.info("ℹ️ No more processes to kill")
|
||||
logger.info("No more processes to kill")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
@@ -1296,7 +1296,7 @@ echo Prefix creation complete.
|
||||
|
||||
time.sleep(1)
|
||||
|
||||
logger.warning(f"❌ Timeout waiting for prefix completion after {timeout} seconds")
|
||||
logger.warning(f"Timeout waiting for prefix completion after {timeout} seconds")
|
||||
return False
|
||||
|
||||
except Exception as e:
|
||||
@@ -1356,7 +1356,7 @@ echo Prefix creation complete.
|
||||
if killed_count > 0:
|
||||
logger.info(f" Killed {killed_count} ModOrganizer processes")
|
||||
else:
|
||||
logger.warning("❌ No ModOrganizer processes found to kill")
|
||||
logger.warning("No ModOrganizer processes found to kill")
|
||||
|
||||
return killed_count
|
||||
|
||||
@@ -1624,11 +1624,11 @@ echo Prefix creation complete.
|
||||
|
||||
return True
|
||||
|
||||
logger.error(f"❌ Shortcut '{shortcut_name}' not found for CompatTool setting")
|
||||
logger.error(f"Shortcut '{shortcut_name}' not found for CompatTool setting")
|
||||
return False
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"❌ Error setting CompatTool on shortcut: {e}")
|
||||
logger.error(f"Error setting CompatTool on shortcut: {e}")
|
||||
return False
|
||||
|
||||
def _set_proton_on_shortcut(self, shortcut_name: str) -> bool:
|
||||
@@ -2633,7 +2633,7 @@ echo Prefix creation complete.
|
||||
logger.info(f" Proton prefix created at: {pfx}")
|
||||
return True
|
||||
else:
|
||||
logger.warning(f"⚠️ Proton prefix not found at: {pfx}")
|
||||
logger.warning(f"Proton prefix not found at: {pfx}")
|
||||
return False
|
||||
|
||||
except subprocess.TimeoutExpired:
|
||||
@@ -2735,7 +2735,7 @@ echo Prefix creation complete.
|
||||
logger.info(" Compatibility tool persists")
|
||||
return True
|
||||
else:
|
||||
logger.warning("⚠️ Compatibility tool not found")
|
||||
logger.warning("Compatibility tool not found")
|
||||
return False
|
||||
|
||||
except Exception as e:
|
||||
|
||||
@@ -228,14 +228,14 @@ class NativeSteamService:
|
||||
|
||||
# Write back to file
|
||||
if self.write_shortcuts_vdf(data):
|
||||
logger.info(f"✅ Shortcut created successfully at index {next_index}")
|
||||
logger.info(f"Shortcut created successfully at index {next_index}")
|
||||
return True, unsigned_app_id
|
||||
else:
|
||||
logger.error("❌ Failed to write shortcut to VDF")
|
||||
logger.error("Failed to write shortcut to VDF")
|
||||
return False, None
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"❌ Error creating shortcut: {e}")
|
||||
logger.error(f"Error creating shortcut: {e}")
|
||||
return False, None
|
||||
|
||||
def set_proton_version(self, app_id: int, proton_version: str = "proton_experimental") -> bool:
|
||||
@@ -320,11 +320,11 @@ class NativeSteamService:
|
||||
with open(config_path, 'w', encoding='utf-8') as f:
|
||||
f.write(new_config_text)
|
||||
|
||||
logger.info(f"✅ Successfully set Proton version '{proton_version}' for AppID {app_id} using config.vdf only (steam-conductor method)")
|
||||
logger.info(f"Successfully set Proton version '{proton_version}' for AppID {app_id} using config.vdf only (steam-conductor method)")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"❌ Error setting Proton version: {e}")
|
||||
logger.error(f"Error setting Proton version: {e}")
|
||||
return False
|
||||
|
||||
def create_shortcut_with_proton(self, app_name: str, exe_path: str, start_dir: str = None,
|
||||
@@ -351,7 +351,7 @@ class NativeSteamService:
|
||||
logger.error("Failed to set Proton version (shortcut still created)")
|
||||
return False, app_id # Shortcut exists but Proton setting failed
|
||||
|
||||
logger.info(f"✅ Complete workflow successful: '{app_name}' with '{proton_version}'")
|
||||
logger.info(f"Complete workflow successful: '{app_name}' with '{proton_version}'")
|
||||
return True, app_id
|
||||
|
||||
def list_shortcuts(self) -> Dict[str, str]:
|
||||
@@ -388,12 +388,12 @@ class NativeSteamService:
|
||||
|
||||
# Write back
|
||||
if self.write_shortcuts_vdf(data):
|
||||
logger.info(f"✅ Removed shortcut '{app_name}'")
|
||||
logger.info(f"Removed shortcut '{app_name}'")
|
||||
return True
|
||||
else:
|
||||
logger.error("❌ Failed to write updated shortcuts")
|
||||
logger.error("Failed to write updated shortcuts")
|
||||
return False
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"❌ Error removing shortcut: {e}")
|
||||
logger.error(f"Error removing shortcut: {e}")
|
||||
return False
|
||||
@@ -33,6 +33,7 @@ class UpdateInfo:
|
||||
download_url: str
|
||||
file_size: Optional[int] = None
|
||||
is_critical: bool = False
|
||||
is_delta_update: bool = False
|
||||
|
||||
|
||||
class UpdateService:
|
||||
@@ -72,24 +73,44 @@ class UpdateService:
|
||||
latest_version = release_data['tag_name'].lstrip('v')
|
||||
|
||||
if self._is_newer_version(latest_version):
|
||||
# Find AppImage asset
|
||||
# Check if this version was skipped
|
||||
if self._is_version_skipped(latest_version):
|
||||
logger.debug(f"Version {latest_version} was skipped by user")
|
||||
return None
|
||||
|
||||
# Find AppImage asset (prefer delta update if available)
|
||||
download_url = None
|
||||
file_size = None
|
||||
|
||||
# Look for delta update first (smaller download)
|
||||
for asset in release_data.get('assets', []):
|
||||
if asset['name'].endswith('.AppImage'):
|
||||
if asset['name'].endswith('.AppImage.delta') or 'delta' in asset['name'].lower():
|
||||
download_url = asset['browser_download_url']
|
||||
file_size = asset['size']
|
||||
logger.debug(f"Found delta update: {asset['name']} ({file_size} bytes)")
|
||||
break
|
||||
|
||||
# Fallback to full AppImage if no delta available
|
||||
if not download_url:
|
||||
for asset in release_data.get('assets', []):
|
||||
if asset['name'].endswith('.AppImage'):
|
||||
download_url = asset['browser_download_url']
|
||||
file_size = asset['size']
|
||||
logger.debug(f"Found full AppImage: {asset['name']} ({file_size} bytes)")
|
||||
break
|
||||
|
||||
if download_url:
|
||||
# Determine if this is a delta update
|
||||
is_delta = '.delta' in download_url or 'delta' in download_url.lower()
|
||||
|
||||
return UpdateInfo(
|
||||
version=latest_version,
|
||||
tag_name=release_data['tag_name'],
|
||||
release_date=release_data['published_at'],
|
||||
changelog=release_data.get('body', ''),
|
||||
download_url=download_url,
|
||||
file_size=file_size
|
||||
file_size=file_size,
|
||||
is_delta_update=is_delta
|
||||
)
|
||||
else:
|
||||
logger.warning(f"No AppImage found in release {latest_version}")
|
||||
@@ -123,6 +144,25 @@ class UpdateService:
|
||||
logger.warning(f"Could not parse version: {version}")
|
||||
return False
|
||||
|
||||
def _is_version_skipped(self, version: str) -> bool:
|
||||
"""
|
||||
Check if a version was skipped by the user.
|
||||
|
||||
Args:
|
||||
version: Version to check
|
||||
|
||||
Returns:
|
||||
bool: True if version was skipped, False otherwise
|
||||
"""
|
||||
try:
|
||||
from ...backend.handlers.config_handler import ConfigHandler
|
||||
config_handler = ConfigHandler()
|
||||
skipped_versions = config_handler.get('skipped_versions', [])
|
||||
return version in skipped_versions
|
||||
except Exception as e:
|
||||
logger.warning(f"Error checking skipped versions: {e}")
|
||||
return False
|
||||
|
||||
def check_for_updates_async(self, callback: Callable[[Optional[UpdateInfo]], None]) -> None:
|
||||
"""
|
||||
Check for updates in background thread.
|
||||
@@ -152,16 +192,25 @@ class UpdateService:
|
||||
logger.debug("Not running as AppImage - updates not supported")
|
||||
return False
|
||||
|
||||
appimage_path = get_appimage_path()
|
||||
if not appimage_path:
|
||||
logger.debug("AppImage path validation failed - updates not supported")
|
||||
return False
|
||||
|
||||
if not can_self_update():
|
||||
logger.debug("Cannot write to AppImage - updates not possible")
|
||||
return False
|
||||
|
||||
logger.debug(f"Self-updating enabled for AppImage: {appimage_path}")
|
||||
return True
|
||||
|
||||
def download_update(self, update_info: UpdateInfo,
|
||||
progress_callback: Optional[Callable[[int, int], None]] = None) -> Optional[Path]:
|
||||
"""
|
||||
Download update to temporary location.
|
||||
Download update using full AppImage replacement.
|
||||
|
||||
Since we can't rely on external tools being available, we use a reliable
|
||||
full replacement approach that works on all systems without dependencies.
|
||||
|
||||
Args:
|
||||
update_info: Information about the update to download
|
||||
@@ -171,7 +220,27 @@ class UpdateService:
|
||||
Path to downloaded file, or None if download failed
|
||||
"""
|
||||
try:
|
||||
logger.info(f"Downloading update {update_info.version} from {update_info.download_url}")
|
||||
logger.info(f"Downloading update {update_info.version} (full replacement)")
|
||||
return self._download_update_manual(update_info, progress_callback)
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to download update: {e}")
|
||||
return None
|
||||
|
||||
def _download_update_manual(self, update_info: UpdateInfo,
|
||||
progress_callback: Optional[Callable[[int, int], None]] = None) -> Optional[Path]:
|
||||
"""
|
||||
Fallback manual download method.
|
||||
|
||||
Args:
|
||||
update_info: Information about the update to download
|
||||
progress_callback: Optional callback for download progress
|
||||
|
||||
Returns:
|
||||
Path to downloaded file, or None if download failed
|
||||
"""
|
||||
try:
|
||||
logger.info(f"Manual download of update {update_info.version} from {update_info.download_url}")
|
||||
|
||||
response = requests.get(update_info.download_url, stream=True)
|
||||
response.raise_for_status()
|
||||
@@ -179,11 +248,12 @@ class UpdateService:
|
||||
total_size = int(response.headers.get('content-length', 0))
|
||||
downloaded_size = 0
|
||||
|
||||
# Create temporary file
|
||||
temp_dir = Path(tempfile.gettempdir()) / "jackify_updates"
|
||||
temp_dir.mkdir(exist_ok=True)
|
||||
# Create update directory in user's home directory
|
||||
home_dir = Path.home()
|
||||
update_dir = home_dir / "Jackify" / "updates"
|
||||
update_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
temp_file = temp_dir / f"Jackify-{update_info.version}.AppImage"
|
||||
temp_file = update_dir / f"Jackify-{update_info.version}.AppImage"
|
||||
|
||||
with open(temp_file, 'wb') as f:
|
||||
for chunk in response.iter_content(chunk_size=8192):
|
||||
@@ -197,11 +267,11 @@ class UpdateService:
|
||||
# Make executable
|
||||
temp_file.chmod(0o755)
|
||||
|
||||
logger.info(f"Update downloaded successfully to {temp_file}")
|
||||
logger.info(f"Manual update downloaded successfully to {temp_file}")
|
||||
return temp_file
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to download update: {e}")
|
||||
logger.error(f"Failed to download update manually: {e}")
|
||||
return None
|
||||
|
||||
def apply_update(self, new_appimage_path: Path) -> bool:
|
||||
@@ -252,10 +322,12 @@ class UpdateService:
|
||||
Path to helper script, or None if creation failed
|
||||
"""
|
||||
try:
|
||||
temp_dir = Path(tempfile.gettempdir()) / "jackify_updates"
|
||||
temp_dir.mkdir(exist_ok=True)
|
||||
# Create update directory in user's home directory
|
||||
home_dir = Path.home()
|
||||
update_dir = home_dir / "Jackify" / "updates"
|
||||
update_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
helper_script = temp_dir / "update_helper.sh"
|
||||
helper_script = update_dir / "update_helper.sh"
|
||||
|
||||
script_content = f'''#!/bin/bash
|
||||
# Jackify Update Helper Script
|
||||
|
||||
Reference in New Issue
Block a user