import requests from packaging import version from PyQt6.QtWidgets import QApplication from PyQt6.QtWidgets import QFileDialog, QDialog, QVBoxLayout from app.core.alert_manager import AlertManager from app.core.settings_manager import SettingsManager from app.core.language_manager import LanguageManager from app.ui.widgets.loading_bar import LoadingBar import os import sys import subprocess class UpdateManager: def __init__(self, settings_manager: SettingsManager, language_manager: LanguageManager, alert_manager: AlertManager) -> None: self.settings_manager = settings_manager self.language_manager = language_manager self.alert_manager = alert_manager self.repo_url = self.settings_manager.get_config("git_repo") self.app_name = self.settings_manager.get_config("app_name").replace(" ","_") self.app_os = self.settings_manager.get_config("app_os") self.arch = self.settings_manager.get_config("architecture") def get_latest_release_with_asset(self) -> dict: # Récupère la release la plus récente qui contient le bon fichier try: if "gitea" in self.repo_url: owner_repo = self.repo_url.split("/")[-2:] api_url = self.repo_url.replace(owner_repo[0], "api/v1/repos/" + owner_repo[0]) + "/releases" resp = requests.get(api_url) releases = resp.json() else: owner_repo = self.repo_url.split("/")[-2:] api_url = f"https://api.github.com/repos/{owner_repo[0]}/{owner_repo[1]}/releases" resp = requests.get(api_url) releases = resp.json() # Cherche le bon asset dans chaque release expected_filename = f"{self.app_name}-{self.app_os}-{self.arch}" for release in releases: for asset in release.get("assets", []): if expected_filename in asset.get("name", ""): return { "tag_name": release.get("tag_name"), "download_url": asset.get("browser_download_url") } except Exception: pass return None def check_for_update(self, parent=None) -> bool: current_version = self.settings_manager.get_config("app_version") release = self.get_latest_release_with_asset() if release and version.parse(release["tag_name"]) > version.parse(current_version): choice = self.alert_manager.show_choice( self.language_manager.get_text("update_found").replace("{latest_tag}", release["tag_name"]), parent=parent ) if choice: folder = QFileDialog.getExistingDirectory(parent, self.language_manager.get_text("choose_update_folder")) if folder: self.download(release["download_url"], release["tag_name"], folder, parent) return True return False def download(self, download_url, version, folder, parent=None): try: filename = os.path.basename(download_url).replace(".", "-" +version + ".") local_path = os.path.join(folder, filename) resp = requests.get(download_url, stream=True) total = int(resp.headers.get('content-length', 0)) # Crée une boîte de dialogue avec la barre de chargement dialog = QDialog(parent) dialog.setWindowTitle(self.language_manager.get_text("update")) layout = QVBoxLayout(dialog) loading_bar = LoadingBar(self.language_manager.get_text("downloading_update"), dialog) layout.addWidget(loading_bar) dialog.setModal(True) dialog.show() downloaded = 0 with open(local_path, "wb") as f: for chunk in resp.iter_content(chunk_size=8192): if chunk: f.write(chunk) downloaded += len(chunk) percent = int(downloaded * 100 / total) if total else 0 loading_bar.set_progress(percent) QApplication.processEvents() dialog.close() msg = self.language_manager.get_text("update_downloaded").replace("{local_path}", local_path) self.alert_manager.show_success(msg, parent=parent) # Ouvre le fichier téléchargé if sys.platform.startswith("win"): os.startfile(local_path) else: subprocess.Popen(["chmod", "+x", local_path]) subprocess.Popen([local_path]) except Exception: self.alert_manager.show_error("update_download_error", parent=parent)