Seregon/PkgToolBox

Toolbox for analyzing and editing pkg application files for psp,ps3, ps4 and ps5, includes the most useful functions you might need.

Python/57.3 KB/No license
GraphicUserInterface/utils/update_checker.py
PkgToolBox / GraphicUserInterface / utils / update_checker.py
1import requests
2import json
3import os
4import re
5from PyQt5.QtWidgets import QMessageBox, QCheckBox
6from PyQt5.QtCore import QThread, pyqtSignal
7import webbrowser
8 
9class UpdateChecker(QThread):
10 update_available = pyqtSignal(str, str) # version, download_url
11 error_occurred = pyqtSignal(str)
12 
13 CURRENT_VERSION = "1.4.03" # Versione corrente
14 GITHUB_API_URL = "https://api.github.com/repos/seregonwar/PkgToolBox/releases/latest"
15 REQUEST_HEADERS = {
16 "Accept": "application/vnd.github+json",
17 "User-Agent": "PkgToolBox/" + CURRENT_VERSION,
18 }
19 
20 def __init__(self, parent=None):
21 super().__init__(parent)
22 self.parent = parent
23 
24 def run(self):
25 """Check for updates in background"""
26 try:
27 response = requests.get(self.GITHUB_API_URL, headers=self.REQUEST_HEADERS, timeout=10)
28 response.raise_for_status()
29 
30 release_info = response.json()
31 tag = str(release_info.get('tag_name', '') or '')
32 latest_version = self._normalize_version(tag)
33 
34 if not latest_version:
35 raise ValueError("Invalid tag_name in release response")
36 
37 if self._compare_versions(latest_version, self.CURRENT_VERSION) > 0:
38 download_url = release_info.get('html_url') or "https://github.com/seregonwar/PkgToolBox/releases"
39 self.update_available.emit(latest_version, download_url)
40 except Exception as e:
41 self.error_occurred.emit(str(e))
42 
43 def _normalize_version(self, tag: str) -> str:
44 """Normalize a Git tag (e.g. 'v1.4.3' or '1.4.3-beta') to numeric '1.4.3'."""
45 tag = tag.strip()
46 if tag.lower().startswith('v'):
47 tag = tag[1:]
48 # Keep only digits and dots at the start: 1.2.3 from 1.2.3-beta
49 m = re.match(r"(\d+(?:\.\d+){0,3})", tag)
50 return m.group(1) if m else ""
51 
52 def _compare_versions(self, version1, version2):
53 """Compare version strings like '1.4.3'. Returns 1, 0, -1."""
54 def parts(v):
55 return [int(p) for p in v.split('.') if p.isdigit() or p.isnumeric()]
56 
57 v1_parts = parts(version1)
58 v2_parts = parts(version2)
59 
60 max_len = max(len(v1_parts), len(v2_parts))
61 v1_parts += [0] * (max_len - len(v1_parts))
62 v2_parts += [0] * (max_len - len(v2_parts))
63 
64 for a, b in zip(v1_parts, v2_parts):
65 if a > b:
66 return 1
67 if a < b:
68 return -1
69 return 0
70 
71class UpdateDialog(QMessageBox):
72 def __init__(self, version, download_url, parent=None):
73 super().__init__(parent)
74 self.download_url = download_url
75 
76 self.setWindowTitle("Update Available")
77 self.setText(f"A new version ({version}) is available!")
78 self.setInformativeText("Would you like to download it now?")
79 self.setStandardButtons(QMessageBox.Yes | QMessageBox.No)
80 self.setDefaultButton(QMessageBox.Yes)
81 
82 # 'Don't show again' checkbox
83 dont_show_cb = QCheckBox("Don't show this again")
84 self.setCheckBox(dont_show_cb)
85 
86 self.buttonClicked.connect(self.handle_click)
87 
88 def handle_click(self, button):
89 if button == self.button(QMessageBox.Yes):
90 webbrowser.open(self.download_url)
91
92 # Salva la preferenza se selezionata
93 if self.checkBox().isChecked():
94 self.save_preference()
95 
96 def save_preference(self):
97 """Save user preference to not show update dialog"""
98 config_dir = os.path.join(os.path.expanduser("~"), ".pkgtoolbox")
99 config_file = os.path.join(config_dir, "update_preferences.json")
100
101 os.makedirs(config_dir, exist_ok=True)
102
103 with open(config_file, 'w') as f:
104 json.dump({"skip_updates": True}, f)