Addition Of Files

This commit is contained in:
kiyreload27
2025-12-28 17:05:14 +00:00
commit 79fa803fa2
1047 changed files with 4783 additions and 0 deletions

264
updater/update_checker.py Normal file
View File

@@ -0,0 +1,264 @@
"""
Update checker for UmamusumeCardManager
Checks GitHub Releases for new versions and handles downloading updates.
"""
import os
import sys
import tempfile
import subprocess
import requests
from typing import Optional, Callable, Tuple
# Import version info
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from version import VERSION, GITHUB_API_URL, APP_NAME
def parse_version(version_str: str) -> Tuple[int, int, int]:
"""
Parse a version string into a tuple of integers.
Handles formats like "1.0.0", "v1.0.0", "1.2.3-beta", etc.
"""
# Remove 'v' prefix if present
version_str = version_str.lstrip('v').lstrip('V')
# Remove any suffix like -beta, -rc1, etc.
if '-' in version_str:
version_str = version_str.split('-')[0]
parts = version_str.split('.')
# Ensure we have at least 3 parts
while len(parts) < 3:
parts.append('0')
try:
return (int(parts[0]), int(parts[1]), int(parts[2]))
except ValueError:
return (0, 0, 0)
def compare_versions(local: str, remote: str) -> int:
"""
Compare two version strings.
Returns:
-1 if local < remote (update available)
0 if local == remote (up to date)
1 if local > remote (local is newer)
"""
local_tuple = parse_version(local)
remote_tuple = parse_version(remote)
if local_tuple < remote_tuple:
return -1
elif local_tuple > remote_tuple:
return 1
else:
return 0
def check_for_updates() -> Optional[dict]:
"""
Check GitHub Releases for a new version.
Returns:
dict with update info if available, None if up to date or error.
{
'current_version': str,
'new_version': str,
'download_url': str,
'release_notes': str,
'html_url': str # Link to the release page
}
"""
try:
# Add a user-agent header (GitHub API requires this)
headers = {
'User-Agent': f'{APP_NAME}-Updater',
'Accept': 'application/vnd.github.v3+json'
}
response = requests.get(GITHUB_API_URL, headers=headers, timeout=10)
if response.status_code == 404:
# No releases found
print("No releases found on GitHub.")
return None
response.raise_for_status()
release_data = response.json()
remote_version = release_data.get('tag_name', '')
# Compare versions
if compare_versions(VERSION, remote_version) < 0:
# Find the Windows exe asset
download_url = None
for asset in release_data.get('assets', []):
asset_name = asset.get('name', '').lower()
if asset_name.endswith('.exe'):
download_url = asset.get('browser_download_url')
break
if not download_url:
print("No .exe asset found in the latest release.")
return None
return {
'current_version': VERSION,
'new_version': remote_version,
'download_url': download_url,
'release_notes': release_data.get('body', 'No release notes provided.'),
'html_url': release_data.get('html_url', '')
}
else:
# Already up to date
return None
except requests.exceptions.Timeout:
print("Update check timed out.")
return None
except requests.exceptions.RequestException as e:
print(f"Error checking for updates: {e}")
return None
except Exception as e:
print(f"Unexpected error during update check: {e}")
return None
def download_update(download_url: str, progress_callback: Optional[Callable[[int, int], None]] = None) -> Optional[str]:
"""
Download the update file.
Args:
download_url: URL to download the new exe from
progress_callback: Optional callback function(downloaded_bytes, total_bytes)
Returns:
Path to the downloaded file, or None if failed.
"""
try:
headers = {
'User-Agent': f'{APP_NAME}-Updater'
}
response = requests.get(download_url, headers=headers, stream=True, timeout=60)
response.raise_for_status()
# Get total file size
total_size = int(response.headers.get('content-length', 0))
# Create temp file for download
temp_dir = tempfile.gettempdir()
temp_path = os.path.join(temp_dir, f'{APP_NAME}_update.exe')
downloaded = 0
chunk_size = 8192
with open(temp_path, 'wb') as f:
for chunk in response.iter_content(chunk_size=chunk_size):
if chunk:
f.write(chunk)
downloaded += len(chunk)
if progress_callback and total_size > 0:
progress_callback(downloaded, total_size)
return temp_path
except Exception as e:
print(f"Error downloading update: {e}")
return None
def get_current_exe_path() -> str:
"""Get the path to the current running executable."""
if getattr(sys, 'frozen', False):
# Running as compiled exe
return sys.executable
else:
# Running as script
return os.path.abspath(sys.argv[0])
def apply_update(new_exe_path: str) -> bool:
"""
Apply the update by replacing the current exe with the new one.
This creates a batch script that:
1. Waits for the current process to exit
2. Replaces the old exe with the new one
3. Starts the new exe
4. Cleans up the batch script
Args:
new_exe_path: Path to the downloaded new exe
Returns:
True if the update process was started successfully.
"""
try:
current_exe = get_current_exe_path()
# If running as a script, we can't self-update
if not getattr(sys, 'frozen', False):
print("Cannot apply update when running as a script.")
print(f"New version downloaded to: {new_exe_path}")
return False
# Create a batch script to perform the update
batch_script = os.path.join(tempfile.gettempdir(), f'{APP_NAME}_updater.bat')
# Simple batch script that just waits and applies the update
# We don't auto-restart because PyInstaller temp cleanup causes DLL errors
script_content = f'''@echo off
title {APP_NAME} Updater
echo ========================================
echo {APP_NAME} Updater
echo ========================================
echo.
echo Waiting for application to close...
timeout /t 3 >nul
echo.
echo Applying update...
move /Y "{new_exe_path}" "{current_exe}"
if errorlevel 1 (
echo.
echo ERROR: Update failed!
echo Please close the application completely and try again.
pause
exit /b 1
)
echo.
echo ========================================
echo Update applied successfully!
echo ========================================
echo.
echo Please start the application manually.
echo This window will close in 5 seconds...
timeout /t 5 >nul
exit
'''
with open(batch_script, 'w') as f:
f.write(script_content)
# Start the batch script with a visible window so user can see progress
CREATE_NEW_CONSOLE = 0x00000010
subprocess.Popen(
['cmd', '/c', batch_script],
creationflags=CREATE_NEW_CONSOLE
)
return True
except Exception as e:
print(f"Error applying update: {e}")
return False
def get_current_version() -> str:
"""Get the current application version."""
return VERSION