This commit is contained in:
Manchik
2026-05-15 17:49:11 +03:00
parent 1da8581069
commit 96844e9aee
2 changed files with 306 additions and 0 deletions
+24
View File
@@ -0,0 +1,24 @@
@echo off
cd /d "%~dp0"
title SteamPanel Updater
chcp 65001 >nul
if exist "venv\Scripts\python.exe" (
venv\Scripts\python.exe update.py
goto :end
)
python --version >nul 2>&1
if errorlevel 1 (
echo.
echo [!] Python not found.
echo Run run.bat first to set up the environment,
echo or install Python from https://python.org
goto :end
)
python update.py
:end
echo.
pause
+282
View File
@@ -0,0 +1,282 @@
import sys
import os
import subprocess
import urllib.request
import urllib.error
import zipfile
import shutil
import hashlib
import json
import tempfile
from pathlib import Path
from datetime import datetime
GITHUB_REPO = "daimyomizukagebay61/SteamPanel"
BRANCH = "main"
ROOT = Path(__file__).parent
# dirs to never touch when copying from ZIP
PROTECTED = {"data", "data_backup", "venv", ".git", "__pycache__"}
# ── helpers ──────────────────────────────────────────────────────────────────
def get_version():
ver_file = ROOT / "version.py"
if not ver_file.exists():
return "unknown"
try:
ns = {}
exec(ver_file.read_text(encoding="utf-8"), ns)
return ns.get("VERSION", "unknown")
except Exception:
return "unknown"
def file_hash(path):
try:
return hashlib.md5(Path(path).read_bytes()).hexdigest()
except Exception:
return None
def git(*args, capture=False):
kwargs = {"cwd": str(ROOT)}
if capture:
kwargs["capture_output"] = True
kwargs["text"] = True
return subprocess.run(["git", "--no-pager"] + list(args), **kwargs)
def reinstall_requirements():
print("Installing dependencies...")
venv_pip = ROOT / "venv" / "Scripts" / "pip.exe"
if venv_pip.exists():
cmd = [str(venv_pip), "install", "-r", str(ROOT / "requirements.txt"), "-q"]
else:
cmd = [sys.executable, "-m", "pip", "install", "-r", str(ROOT / "requirements.txt"), "-q"]
subprocess.run(cmd)
hash_file = ROOT / "data" / ".req_hash"
hash_file.parent.mkdir(exist_ok=True)
hash_file.write_text(file_hash(ROOT / "requirements.txt") or "")
def rebuild_frontend():
frontend = ROOT / "frontend"
if not frontend.exists():
return
if subprocess.run(["npm", "--version"], capture_output=True).returncode != 0:
print("[!] Node.js not found — skipping frontend rebuild.")
print(" If UI looks broken: cd frontend && npm install && npm run build")
return
print("Rebuilding frontend...")
subprocess.run(["npm", "install", "--silent"], cwd=str(frontend))
subprocess.run(["npm", "run", "build"], cwd=str(frontend))
print("Frontend rebuilt.")
def download(url, dest):
req = urllib.request.Request(url, headers={"User-Agent": "SteamPanel-Updater"})
with urllib.request.urlopen(req, timeout=60) as resp:
total = int(resp.headers.get("Content-Length", 0))
done = 0
with open(dest, "wb") as f:
while True:
chunk = resp.read(65536)
if not chunk:
break
f.write(chunk)
done += len(chunk)
if total:
print(f"\r {done * 100 // total:3d}% {done / 1048576:.1f} MB", end="", flush=True)
else:
print(f"\r {done / 1048576:.1f} MB", end="", flush=True)
print()
# ── git update path ───────────────────────────────────────────────────────────
def update_via_git():
if subprocess.run(["git", "--version"], capture_output=True).returncode != 0:
print("[!] git not found. Install Git from https://git-scm.com")
return
print("Checking for updates...")
if git("fetch", "origin", BRANCH).returncode != 0:
print("[!] Failed to reach GitHub. Check your internet connection.")
return
local = git("rev-parse", "HEAD", capture=True).stdout.strip()
remote = git("rev-parse", f"origin/{BRANCH}", capture=True).stdout.strip()
if local == remote:
print("\n[+] Already up to date.")
return
print("\nNew commits:")
print("-" * 40)
git("log", f"HEAD..origin/{BRANCH}", "--oneline")
print("-" * 40)
if input("\nUpdate now? [Y/N]: ").strip().upper() != "Y":
print("Cancelled.")
return
# stash local changes so pull is clean
stash = git("stash", capture=True)
had_stash = "No local changes" not in (stash.stdout or "")
if had_stash:
print("Local changes stashed.")
# backup branch as a safety net
backup = f"backup_{datetime.now().strftime('%Y-%m-%d_%H-%M-%S')}"
git("branch", backup)
print(f"Backup branch: {backup}")
req_hash_before = file_hash(ROOT / "requirements.txt")
frontend_hash_before = file_hash(ROOT / "frontend" / "package.json")
print("Pulling updates...")
if git("pull", "origin", BRANCH).returncode != 0:
print("\n[!] Pull failed. Restoring backup branch...")
git("reset", "--hard", backup)
if had_stash:
git("stash", "pop")
return
if had_stash:
result = git("stash", "pop")
if result.returncode != 0:
print("[!] Could not restore stashed changes automatically.")
print(f" Run: git stash pop (or check: git stash list)")
new_ver = get_version()
print(f"\nUpdated: {local[:7]} -> {new_ver}")
if file_hash(ROOT / "requirements.txt") != req_hash_before:
reinstall_requirements()
if file_hash(ROOT / "frontend" / "package.json") != frontend_hash_before:
rebuild_frontend()
print(f"\n[+] Update complete! Run run.bat to start.")
# ── ZIP download path ─────────────────────────────────────────────────────────
def update_via_zip():
print("No .git folder — using GitHub release download.\n")
# fetch latest release info
api = f"https://api.github.com/repos/{GITHUB_REPO}/releases/latest"
zip_url = tag_name = None
try:
req = urllib.request.Request(api, headers={"User-Agent": "SteamPanel-Updater"})
with urllib.request.urlopen(req, timeout=10) as resp:
data = json.loads(resp.read())
zip_url = data.get("zipball_url")
tag_name = data.get("tag_name", "latest")
except urllib.error.HTTPError as e:
if e.code != 404:
print(f"[!] GitHub API error: {e}")
return
except Exception as e:
print(f"[!] Failed to reach GitHub: {e}")
return
if not zip_url:
# no releases yet — grab main branch zipball
zip_url = f"https://api.github.com/repos/{GITHUB_REPO}/zipball/{BRANCH}"
tag_name = BRANCH
current_ver = get_version()
print(f"Installed : {current_ver}")
print(f"Available : {tag_name}")
if input("\nDownload and install? [Y/N]: ").strip().upper() != "Y":
print("Cancelled.")
return
# backup data/ before touching anything
data_dir = ROOT / "data"
data_backup = ROOT / "data_backup"
if data_dir.exists():
print("Backing up data/...")
if data_backup.exists():
shutil.rmtree(data_backup)
shutil.copytree(data_dir, data_backup)
print("Backed up to data_backup/")
with tempfile.TemporaryDirectory() as tmp:
zip_path = os.path.join(tmp, "update.zip")
print("Downloading...")
try:
download(zip_url, zip_path)
except Exception as e:
print(f"[!] Download failed: {e}")
return
req_hash_before = file_hash(ROOT / "requirements.txt")
frontend_hash_before = file_hash(ROOT / "frontend" / "package.json")
print("Extracting...")
extract_dir = os.path.join(tmp, "src")
with zipfile.ZipFile(zip_path) as z:
z.extractall(extract_dir)
# GitHub always wraps in one top-level folder (reponame-sha/)
entries = os.listdir(extract_dir)
source = Path(extract_dir) / entries[0] if len(entries) == 1 else Path(extract_dir)
print("Installing...")
for item in source.iterdir():
if item.name in PROTECTED:
continue
dest = ROOT / item.name
if item.is_dir():
if dest.exists():
shutil.rmtree(dest)
shutil.copytree(item, dest)
else:
shutil.copy2(item, dest)
# safety net: restore data if something went wrong
if not data_dir.exists() and data_backup.exists():
print("Restoring data/ from backup...")
shutil.copytree(data_backup, data_dir)
if file_hash(ROOT / "requirements.txt") != req_hash_before:
reinstall_requirements()
elif not (ROOT / "data" / ".req_hash").exists():
reinstall_requirements()
if file_hash(ROOT / "frontend" / "package.json") != frontend_hash_before:
rebuild_frontend()
new_ver = get_version()
if new_ver != current_ver:
print(f"\nUpdated: {current_ver} -> {new_ver}")
print("\n[+] Update complete! Run run.bat to start.")
# ── entry point ───────────────────────────────────────────────────────────────
def main():
print()
print(" SteamPanel Updater")
print(" ==================")
print(f"\n Current version: {get_version()}\n")
if (ROOT / ".git").exists():
update_via_git()
else:
update_via_zip()
if __name__ == "__main__":
try:
main()
except KeyboardInterrupt:
print("\nCancelled.")