add update notification

This commit is contained in:
Golumpa 2026-06-23 11:45:50 +01:00
parent f3b78400d4
commit 5fac4cd9e8
8 changed files with 122 additions and 5 deletions

View file

@ -1 +1 @@
__version__ = "0.1.6"
__version__ = "0.1.7"

View file

@ -5,11 +5,13 @@ import json
from nte_history_exporter import console
from nte_history_exporter.adapters.mitmproxy_flows import decode_mitmproxy_flows
from nte_history_exporter.constants import EXPORTER_VERSION
from nte_history_exporter.decoder.boundary import annotate_groups
from nte_history_exporter.export.csv_export import write_csv
from nte_history_exporter.export.json_export import build_export_json
from nte_history_exporter.live_capture.libpcap import LibpcapUnavailable
from nte_history_exporter.live_capture.runner import export_paths, run_live_capture
from nte_history_exporter.update_check import check_for_update
def build_parser() -> argparse.ArgumentParser:
@ -38,6 +40,9 @@ def build_parser() -> argparse.ArgumentParser:
def main(argv: list[str] | None = None) -> int:
args = build_parser().parse_args(argv)
console.print_banner()
update = check_for_update(EXPORTER_VERSION)
if update:
console.print_update_available(update.current_version, update.latest_version, update.release_url)
if args.live or not args.capture_source:
try:
run_live_capture(

View file

@ -13,6 +13,7 @@ BOLD = "\x1b[1m"
DIM = "\x1b[2m"
CYAN = "\x1b[36m"
GREEN = "\x1b[32m"
RED = "\x1b[31m"
YELLOW = "\x1b[33m"
BRIGHT_WHITE = "\x1b[97m"
@ -62,7 +63,7 @@ def print_banner() -> None:
print(style(f" {GAME_NAME} pull history -> tracker JSON", DIM))
print(style(f" {REPOSITORY_URL}", DIM))
heart = "❤️" if (getattr(sys.stdout, "encoding", None) or "").lower().replace("-", "") == "utf8" else "<3"
print(style(f" Created with {heart} by Golumpa", DIM))
print(style(" Created with ", DIM) + style(heart, RED) + style(" by Golumpa", DIM))
print(rule("="))
@ -162,6 +163,14 @@ def print_problem(text: str) -> None:
print(style(f" {text}", YELLOW, BOLD))
def print_update_available(current_version: str, latest_version: str, release_url: str) -> None:
print()
print(style(f" Update available: v{current_version} -> {latest_version}", YELLOW, BOLD))
print(style(" Some banner/reward mappings may be incomplete in this version.", YELLOW))
print(style(" Updating is recommended for the most accurate export labels.", YELLOW))
print(style(f" Download when ready: {release_url}", YELLOW))
def prompt_user_uid() -> str | None:
print()
print_problem("User UID was not detected in this capture.")

View file

@ -11,7 +11,7 @@ LIMITED_CHARACTER_BANNER_NAME = "Limited Character Board"
ARC_BANNER_ID = "Arc_MiracleBox"
ARC_BANNER_NAME = "Arc Miracle Box"
EXPORTER_NAME = "nte-history-exporter"
EXPORTER_VERSION = "0.1.6"
EXPORTER_VERSION = "0.1.5"
HISTORY_REQUEST_BANNER = 4220
HISTORY_REQUEST_LENGTH = 45

View file

@ -0,0 +1,70 @@
from __future__ import annotations
import json
import re
import urllib.request
from dataclasses import dataclass
from typing import Any
LATEST_RELEASE_API_URL = "https://api.github.com/repos/Golumpa/nte-exporter/releases/latest"
RELEASES_URL = "https://github.com/Golumpa/nte-exporter/releases"
@dataclass(frozen=True)
class UpdateInfo:
current_version: str
latest_version: str
release_url: str
def check_for_update(current_version: str, *, timeout: float = 1.5) -> UpdateInfo | None:
"""Return update details when GitHub has a newer release.
Update checks are intentionally best-effort. Network errors, invalid
responses, or unusual tag names should not stop the exporter from running.
"""
try:
latest = fetch_latest_release(timeout=timeout)
except Exception:
return None
latest_version = str(latest.get("tag_name", "")).strip()
release_url = str(latest.get("html_url", "")).strip() or RELEASES_URL
if not latest_version or not is_newer_version(latest_version, current_version):
return None
return UpdateInfo(
current_version=current_version,
latest_version=latest_version,
release_url=release_url,
)
def fetch_latest_release(*, timeout: float) -> dict[str, Any]:
request = urllib.request.Request(
LATEST_RELEASE_API_URL,
headers={
"Accept": "application/vnd.github+json",
"User-Agent": "nte-history-exporter",
},
)
with urllib.request.urlopen(request, timeout=timeout) as response:
return json.loads(response.read().decode("utf-8"))
def is_newer_version(candidate: str, current: str) -> bool:
candidate_parts = _version_parts(candidate)
current_parts = _version_parts(current)
if candidate_parts is None or current_parts is None:
return False
width = max(len(candidate_parts), len(current_parts))
normalized_candidate = candidate_parts + (0,) * (width - len(candidate_parts))
normalized_current = current_parts + (0,) * (width - len(current_parts))
return normalized_candidate > normalized_current
def _version_parts(version: str) -> tuple[int, ...] | None:
match = re.fullmatch(r"v?(\d+(?:\.\d+)*)", version.strip())
if not match:
return None
return tuple(int(part) for part in match.group(1).split("."))