From 6f8074ff43536ff38d9d516225aba66be3511fcb Mon Sep 17 00:00:00 2001 From: joel Date: Mon, 20 Jul 2026 17:56:19 +0200 Subject: [PATCH] Fix updates and startup delays --- fcco_converter/config.py | 6 +++- fcco_converter/gui.py | 19 +++++++++++ fcco_converter/updater.py | 70 ++++++++++++++++++++++++--------------- 3 files changed, 67 insertions(+), 28 deletions(-) diff --git a/fcco_converter/config.py b/fcco_converter/config.py index c18713f..f8d309c 100644 --- a/fcco_converter/config.py +++ b/fcco_converter/config.py @@ -23,7 +23,11 @@ def _load_app_info(): try: # Finde config.json relativ zum Skript oder im PyInstaller Bundle if getattr(sys, "frozen", False): - base_dir = Path(sys.executable).parent + if platform.system() == "Darwin": + # Path(sys.executable) ist fcco-Converter.app/Contents/MacOS/executable + base_dir = Path(sys.executable).parent.parent.parent.parent + else: + base_dir = Path(sys.executable).parent else: base_dir = Path(__file__).parent.parent diff --git a/fcco_converter/gui.py b/fcco_converter/gui.py index ff8da02..ec9c623 100644 --- a/fcco_converter/gui.py +++ b/fcco_converter/gui.py @@ -841,6 +841,25 @@ class App(ctk.CTk): if not IS_MACOS: w.after(200, lambda: w.grab_set()) + def check_updates(self, manual=False): + import threading + + def _do_check(): + try: + has_upd, ver, url = check_for_updates() + if has_upd: + self.after(0, lambda: self._prompt_update(ver, url)) + elif manual: + self.after(0, lambda: messagebox.showinfo("Updates", "Du bist auf der neuesten Version!")) + except Exception as e: + if manual: + self.after(0, lambda: messagebox.showerror("Fehler", f"Fehler bei Update-Prüfung:\n{e}")) + + if manual: + self.after(30, self._activate) + + threading.Thread(target=_do_check, daemon=True).start() + def _save_s(self, wg, win): try: th = int(wg["threads"].get()) diff --git a/fcco_converter/updater.py b/fcco_converter/updater.py index a1d6082..3202ace 100644 --- a/fcco_converter/updater.py +++ b/fcco_converter/updater.py @@ -39,37 +39,53 @@ def _fetch_json(url: str) -> list | dict: return json.loads(resp.read().decode("utf-8")) -def check_for_updates() -> dict | None: - """Prüft, ob ein neues Release verfügbar ist. +def _parse_version(v: str) -> list[int]: + parts = [] + for p in v.lstrip("vV").split("."): + try: + parts.append(int(p)) + except ValueError: + parts.append(0) + while len(parts) < 3: + parts.append(0) + return parts + +def check_for_updates() -> tuple[bool, str, str]: + """Prüft, ob auf Gitea ein neues Release (nach SemVer) vorliegt. + Returns: - Dict mit Release-Infos (tag_name, name, body, assets) oder None. + (has_update, new_version_string, asset_download_url) """ try: - releases = _fetch_json(RELEASES_URL) - if not releases: - return None - - # Neuestes (nicht als Draft/Prerelease markiertes) Release - for release in releases: - if release.get("draft") or release.get("prerelease"): - continue - - tag = release.get("tag_name", "").lstrip("v") - if tag and tag != CURRENT_VERSION: - # Einfacher Versionsvergleich - try: - remote_parts = [int(x) for x in tag.split(".")] - local_parts = [int(x) for x in CURRENT_VERSION.split(".")] - if remote_parts > local_parts: - return release - except ValueError: - continue - break # Nur das neueste Release prüfen - - return None - except (URLError, json.JSONDecodeError, OSError): - return None + req = Request(RELEASES_URL, headers={'User-Agent': 'fcco-Updater/1.0'}) + with urlopen(req, timeout=5) as resp: + data = json.loads(resp.read().decode('utf-8')) + + if not data: + return False, "", "" + + # Gitea gibt Releases sortiert zurück, 0 = neuestes + release_info = data[0] + tag_name = release_info.get("tag_name", "") + + # Entferne eventuelles "v" Präfix + latest_version = tag_name.lstrip("vV") + + # Intelligenter Versions-Vergleich + if _parse_version(latest_version) > _parse_version(CURRENT_VERSION): + # Finde die passende Zip-Datei + expected_asset = _get_platform_asset_name() + for asset in release_info.get("assets", []): + if asset.get("name") == expected_asset: + return True, latest_version, asset.get("browser_download_url", "") + + return False, "", "" + + return False, "", "" + except Exception as e: + print(f"Update Check Error: {e}") + return False, "", "" def _get_platform_asset_name() -> str: