primo commit
This commit is contained in:
@@ -0,0 +1,560 @@
|
||||
#!/usr/bin/env python3
|
||||
"""OGame Galaxy Viewer — backend Flask.
|
||||
|
||||
Servizi:
|
||||
- vista galassia/sistema (dati da world.json, aggiornato 1x/giorno)
|
||||
- import rapporti di spionaggio via API string (sr-...) con salvataggio JSON
|
||||
- consultazione rapporti per pianeta
|
||||
|
||||
Avvio: python3 app.py (sviluppo)
|
||||
Servizio systemd: ogame-galaxy.service
|
||||
"""
|
||||
import json
|
||||
import threading
|
||||
import time
|
||||
from datetime import datetime, timezone
|
||||
from pathlib import Path
|
||||
|
||||
from flask import Flask, jsonify, request, send_from_directory
|
||||
|
||||
import report_store
|
||||
import update_data
|
||||
from technames import category_name, item_name
|
||||
|
||||
BASE_DIR = Path(__file__).resolve().parent
|
||||
STATIC = BASE_DIR / "static"
|
||||
LATEST = BASE_DIR / "data" / "latest"
|
||||
|
||||
app = Flask(__name__, static_folder=str(STATIC), static_url_path="/static")
|
||||
|
||||
|
||||
@app.after_request
|
||||
def _no_cache(resp):
|
||||
# tool personale: niente cache, sempre file freschi
|
||||
if request.path.startswith("/static/") or request.path in ("/", "/rankings"):
|
||||
resp.headers["Cache-Control"] = "no-store"
|
||||
return resp
|
||||
|
||||
|
||||
# semplice rate-limit di cortesia verso il proxy (10 req/min => max 5/min qui)
|
||||
_report_lock = threading.Lock()
|
||||
|
||||
|
||||
def load_config():
|
||||
with open(BASE_DIR / "config.json", encoding="utf-8") as f:
|
||||
return json.load(f)
|
||||
|
||||
|
||||
def load_world():
|
||||
p = LATEST / "world.json"
|
||||
if not p.exists():
|
||||
return None
|
||||
with open(p, encoding="utf-8") as f:
|
||||
world = json.load(f)
|
||||
return _augment_world_with_reports(world)
|
||||
|
||||
|
||||
def _augment_world_with_reports(world):
|
||||
"""Aggiunge i pianeti noti *solo* dai rapporti di spionaggio.
|
||||
|
||||
L'API pubblica `universe.xml` viene rigenerata di rado: i pianeti dei player
|
||||
più recenti possono mancare per giorni, pur essendo visibili nei rapporti.
|
||||
Se esiste un rapporto su una coordinata assente, la aggiungiamo (marcata
|
||||
`report_only`), associando il giocatore per nome univoco, così galassia,
|
||||
finestra giocatore e classifica restano utilizzabili.
|
||||
"""
|
||||
try:
|
||||
idx = report_store._load_index()
|
||||
except Exception:
|
||||
return world
|
||||
reports = idx.get("reports", {})
|
||||
planets = world.setdefault("planets", {})
|
||||
players = world.get("players", {})
|
||||
avatar = world.setdefault("avatar", {})
|
||||
|
||||
by_name = {}
|
||||
for pid, p in players.items():
|
||||
n = (p.get("name") or "").strip().lower()
|
||||
if n:
|
||||
by_name.setdefault(n, []).append(pid)
|
||||
|
||||
def resolve(rec):
|
||||
pids = by_name.get((rec.get("defender_name") or "").strip().lower())
|
||||
return pids[0] if pids and len(pids) == 1 else None
|
||||
|
||||
# 1) pianeti (type != 3): aggiungi quelli mancanti
|
||||
for rec in reports.values():
|
||||
coords = rec.get("coords")
|
||||
if not coords or rec.get("planet_type") == 3 or coords in planets:
|
||||
continue
|
||||
pid = resolve(rec)
|
||||
if not pid:
|
||||
continue
|
||||
planets[coords] = {
|
||||
"id": f"report-{coords}",
|
||||
"player": pid,
|
||||
"name": rec.get("defender_planet_name") or "(da rapporto)",
|
||||
"coords": coords,
|
||||
"report_only": True,
|
||||
}
|
||||
avatar.setdefault(pid, coords)
|
||||
|
||||
# 2) lune (type == 3): aggancia al pianeta se presente e senza luna nota
|
||||
for rec in reports.values():
|
||||
if rec.get("planet_type") != 3:
|
||||
continue
|
||||
base = planets.get(rec.get("coords") or "")
|
||||
if base is not None and not base.get("moon"):
|
||||
base["moon"] = {
|
||||
"id": f"report-{base['coords']}#moon",
|
||||
"name": rec.get("defender_planet_name") or "Luna",
|
||||
"size": 0,
|
||||
}
|
||||
return world
|
||||
|
||||
|
||||
def fmt_ts(epoch):
|
||||
if not epoch:
|
||||
return None
|
||||
return datetime.fromtimestamp(epoch, tz=timezone.utc).strftime("%Y-%m-%d %H:%M UTC")
|
||||
|
||||
|
||||
# ---------------------------------------------------------------- pagine
|
||||
|
||||
@app.route("/")
|
||||
def index():
|
||||
return send_from_directory(STATIC, "index.html")
|
||||
|
||||
|
||||
# ---------------------------------------------------------------- API dati
|
||||
|
||||
@app.route("/api/bootstrap")
|
||||
def api_bootstrap():
|
||||
cfg = load_config()
|
||||
world = load_world()
|
||||
if not world:
|
||||
return jsonify({"ok": False, "error": "Dati non ancora scaricati."}), 503
|
||||
rep = report_store.stats(cfg)
|
||||
return jsonify({
|
||||
"ok": True,
|
||||
"server": world["server"],
|
||||
"myPlayer": {
|
||||
"id": cfg.get("my_player_id"),
|
||||
"name": cfg.get("my_player_name"),
|
||||
},
|
||||
"fetched": {k: fmt_ts(v) for k, v in world.get("fetched", {}).items()},
|
||||
"reportStats": rep,
|
||||
})
|
||||
|
||||
|
||||
@app.route("/api/galaxy")
|
||||
def api_galaxy():
|
||||
world = load_world()
|
||||
if not world:
|
||||
return jsonify({"ok": False, "error": "Dati non disponibili."}), 503
|
||||
try:
|
||||
g = int(request.args.get("g", 1))
|
||||
s = int(request.args.get("s", 1))
|
||||
except ValueError:
|
||||
return jsonify({"ok": False, "error": "Parametri g/s non validi"}), 400
|
||||
sd = world["server"]
|
||||
if not (1 <= g <= sd["galaxies"]):
|
||||
return jsonify({"ok": False, "error": f"Galassia fuori range (1-{sd['galaxies']})"}), 400
|
||||
if not (1 <= s <= sd["systems"]):
|
||||
return jsonify({"ok": False, "error": f"Sistema fuori range (1-{sd['systems']})"}), 400
|
||||
|
||||
players = world["players"]
|
||||
planets = world["planets"]
|
||||
cells = []
|
||||
idx = report_store._load_index()
|
||||
reports_idx = idx.get("reports", {})
|
||||
for pos in range(1, 16):
|
||||
cell = {"pos": pos}
|
||||
key = f"{g}:{s}:{pos}"
|
||||
planet = planets.get(key)
|
||||
if planet:
|
||||
pid = planet["player"]
|
||||
pl = players.get(pid, {})
|
||||
# eventuali rapporti su questo pianeta
|
||||
rep_ids = [r for r in idx.get("by_coords", {}).get(key, [])]
|
||||
rep_ids += [r for r in idx.get("by_coords", {}).get(key + "#moon", [])]
|
||||
reps = []
|
||||
for rid in rep_ids:
|
||||
rec = reports_idx.get(rid)
|
||||
if rec:
|
||||
reps.append({
|
||||
"sr_id": rid,
|
||||
"moon": key + "#moon" in idx.get("by_coords", {}).get(key + "#moon", []),
|
||||
"event_time": rec.get("event_time"),
|
||||
"activity": rec.get("activity"),
|
||||
})
|
||||
reps.sort(key=lambda r: r.get("event_time") or "", reverse=True)
|
||||
cell["planet"] = {
|
||||
"id": planet["id"],
|
||||
"name": planet["name"],
|
||||
"coords": planet["coords"],
|
||||
"report_only": planet.get("report_only", False),
|
||||
"mine": str(pid) == str(load_config().get("my_player_id")),
|
||||
}
|
||||
cell["player"] = {
|
||||
"id": pid,
|
||||
"name": pl.get("name", ""),
|
||||
"status": pl.get("status", ""),
|
||||
"alliance_tag": pl.get("alliance_tag", ""),
|
||||
}
|
||||
if planet.get("moon"):
|
||||
cell["moon"] = planet["moon"]
|
||||
cell["reports"] = reps
|
||||
# posizioni in classifica (generale/armamenti) del giocatore in cella
|
||||
if cell.get("player"):
|
||||
rk = (world.get("ranks") or {}).get(cell["player"]["id"], {})
|
||||
cell["player"]["rank_total"] = rk.get("total")
|
||||
cell["player"]["rank_military"] = rk.get("military")
|
||||
cells.append(cell)
|
||||
return jsonify({"ok": True, "galaxy": g, "system": s,
|
||||
"galaxies": sd["galaxies"], "systems": sd["systems"],
|
||||
"cells": cells})
|
||||
|
||||
|
||||
@app.route("/api/planet")
|
||||
def api_planet():
|
||||
"""Dettaglio pianeta: info + tutti i rapporti di spionaggio salvati."""
|
||||
world = load_world()
|
||||
g = request.args.get("g")
|
||||
s = request.args.get("s")
|
||||
p = request.args.get("p")
|
||||
if not (g and s and p):
|
||||
return jsonify({"ok": False, "error": "Parametri g/s/p richiesti"}), 400
|
||||
key = f"{g}:{s}:{p}"
|
||||
planets = world["planets"]
|
||||
planet = planets.get(key)
|
||||
if not planet:
|
||||
return jsonify({"ok": False, "error": "Pianeta non trovato in questo sistema."}), 404
|
||||
player = world["players"].get(planet["player"], {})
|
||||
rk = (world.get("ranks") or {}).get(planet["player"], {})
|
||||
player = {**player, "rank_total": rk.get("total"), "rank_military": rk.get("military")}
|
||||
ally = {}
|
||||
if player.get("alliance"):
|
||||
ally = world["alliances"].get(player["alliance"], {})
|
||||
# altri pianeti dello stesso giocatore
|
||||
others = [pl for k, pl in planets.items()
|
||||
if pl["player"] == planet["player"] and k != key]
|
||||
others.sort(key=lambda x: x["coords"])
|
||||
|
||||
# rapporti
|
||||
reports = [
|
||||
_report_view(rec, report_store.get_report(rec["sr_id"]))
|
||||
for rec in report_store.list_by_coords(key, scope="planet")
|
||||
]
|
||||
moon_reports = [
|
||||
_report_view(rec, report_store.get_report(rec["sr_id"]))
|
||||
for rec in report_store.list_by_coords(key, scope="moon")
|
||||
]
|
||||
|
||||
return jsonify({
|
||||
"ok": True,
|
||||
"planet": planet,
|
||||
"player": {**player, "alliance_name": ally.get("name", "")},
|
||||
"other_planets": others,
|
||||
"reports": reports,
|
||||
"moon_reports": moon_reports,
|
||||
})
|
||||
|
||||
|
||||
@app.route("/api/player")
|
||||
def api_player():
|
||||
"""Dettaglio giocatore: tutti i suoi pianeti + TUTTI i rapporti (pianeti e lune)."""
|
||||
world = load_world()
|
||||
if not world:
|
||||
return jsonify({"ok": False, "error": "Dati non disponibili."}), 503
|
||||
pid = request.args.get("id")
|
||||
if not pid:
|
||||
return jsonify({"ok": False, "error": "Parametro id richiesto"}), 400
|
||||
player = world["players"].get(pid)
|
||||
if not player:
|
||||
return jsonify({"ok": False, "error": "Giocatore non trovato."}), 404
|
||||
rk = (world.get("ranks") or {}).get(pid, {})
|
||||
player = {**player, "rank_total": rk.get("total"), "rank_military": rk.get("military")}
|
||||
ally = world["alliances"].get(player.get("alliance"), {}) if player.get("alliance") else {}
|
||||
|
||||
planets = [pl for pl in world["planets"].values() if pl["player"] == pid]
|
||||
planets.sort(key=lambda x: [int(n) for n in x["coords"].split(":")])
|
||||
|
||||
# tutti i rapporti del giocatore, su qualunque suo pianeta o luna
|
||||
idx = report_store._load_index()
|
||||
by = idx.get("by_coords", {})
|
||||
reports_meta = idx.get("reports", {})
|
||||
seen = set()
|
||||
reports = []
|
||||
for pl in planets:
|
||||
c = pl["coords"]
|
||||
for key in (c, f"{c}#moon"):
|
||||
for rid in by.get(key, []):
|
||||
if rid in seen:
|
||||
continue
|
||||
rec = reports_meta.get(rid)
|
||||
if rec:
|
||||
seen.add(rid)
|
||||
reports.append(_report_view(rec, report_store.get_report(rid)))
|
||||
reports.sort(key=lambda r: r.get("event_timestamp") or 0, reverse=True)
|
||||
|
||||
return jsonify({
|
||||
"ok": True,
|
||||
"player": {**player, "alliance_name": ally.get("name", "")},
|
||||
"avatar": (world.get("avatar") or {}).get(pid),
|
||||
"planets": planets,
|
||||
"reports": reports,
|
||||
})
|
||||
|
||||
|
||||
def _report_view(rec, full):
|
||||
"""Vista sintetica (senza dati grezzi pesanti) per la lista rapporti."""
|
||||
rep = (full or {}).get("report", {})
|
||||
gen = rep.get("generic", {})
|
||||
det = rep.get("details", {})
|
||||
res = det.get("resources") or {}
|
||||
return {
|
||||
"sr_id": rec["sr_id"],
|
||||
"saved_at": rec.get("saved_at"),
|
||||
"event_time": rec.get("event_time"),
|
||||
"event_timestamp": rec.get("event_timestamp"),
|
||||
"attacker_name": rec.get("attacker_name"),
|
||||
"defender_name": rec.get("defender_name"),
|
||||
"defender_planet_name": rec.get("defender_planet_name"),
|
||||
"coords": rec.get("coords"),
|
||||
"activity": rec.get("activity"),
|
||||
"loot_percentage": rec.get("loot_percentage"),
|
||||
"spy_fail_chance": gen.get("spy_fail_chance"),
|
||||
"total_ship_count": gen.get("total_ship_count"),
|
||||
"total_defense_count": gen.get("total_defense_count"),
|
||||
"resources": res,
|
||||
"failed": {k: gen.get(k) for k in
|
||||
("failed_ships", "failed_defense", "failed_buildings", "failed_research")},
|
||||
"categories": {
|
||||
"buildings": len(det.get("buildings") or []),
|
||||
"lfbuildings": len(det.get("lfbuildings") or []),
|
||||
"research": len(det.get("research") or []),
|
||||
"ships": len(det.get("ships") or []),
|
||||
"defense": len(det.get("defense") or []),
|
||||
},
|
||||
"moon": rec.get("planet_type") == 3,
|
||||
}
|
||||
|
||||
|
||||
# ---------------------------------------------------------------- rapporti
|
||||
|
||||
@app.route("/api/reports", methods=["POST"])
|
||||
def api_add_report():
|
||||
cfg = load_config()
|
||||
body = request.get_json(silent=True) or {}
|
||||
token = (body.get("token") or "").strip()
|
||||
if not token:
|
||||
return jsonify({"ok": False, "error": "Incolla l'API string del rapporto (es. sr-ar-170-...)."}), 400
|
||||
with _report_lock:
|
||||
try:
|
||||
rec, created = report_store.import_report(token, cfg)
|
||||
except ValueError as e:
|
||||
return jsonify({"ok": False, "error": str(e)}), 400
|
||||
except RuntimeError as e:
|
||||
return jsonify({"ok": False, "error": str(e)}), 502
|
||||
sr_id = rec["meta"]["sr_id"]
|
||||
full = report_store.get_report(sr_id)
|
||||
view = _report_view(rec["meta"], full)
|
||||
return jsonify({"ok": True, "created": created, "report": view,
|
||||
"coords": rec["meta"].get("coords"),
|
||||
"planet_type": rec["meta"].get("planet_type")})
|
||||
|
||||
|
||||
@app.route("/api/reports/<sr_id>")
|
||||
def api_get_report(sr_id):
|
||||
full = report_store.get_report(sr_id)
|
||||
if not full:
|
||||
return jsonify({"ok": False, "error": "Rapporto non trovato."}), 404
|
||||
idx = report_store._load_index()
|
||||
rec = idx["reports"].get(sr_id)
|
||||
return jsonify({"ok": True, "meta": rec, "data": full["report"]})
|
||||
|
||||
|
||||
@app.route("/api/reports/<sr_id>", methods=["DELETE"])
|
||||
def api_delete_report(sr_id):
|
||||
"""Elimina un rapporto di spionaggio (file + indice)."""
|
||||
if not report_store.delete_report(sr_id):
|
||||
return jsonify({"ok": False, "error": "Rapporto non trovato."}), 404
|
||||
return jsonify({"ok": True, "deleted": sr_id})
|
||||
|
||||
|
||||
@app.route("/api/refresh", methods=["POST"])
|
||||
def api_refresh():
|
||||
def _run():
|
||||
try:
|
||||
update_data.main()
|
||||
except Exception as e: # noqa
|
||||
print("refresh fallito:", e)
|
||||
threading.Thread(target=_run, daemon=True).start()
|
||||
return jsonify({"ok": True, "message": "Aggiornamento dati avviato in background."})
|
||||
|
||||
|
||||
@app.route("/rankings")
|
||||
def rankings_page():
|
||||
return send_from_directory(STATIC, "rankings.html")
|
||||
|
||||
|
||||
# mappa stato API -> gruppo di ricerca
|
||||
_STATUS_GROUPS = {
|
||||
"all": lambda st: True,
|
||||
"active": lambda st: st == "",
|
||||
"inactive": lambda st: st in ("i", "I"),
|
||||
"vacation": lambda st: st == "v",
|
||||
"vacation_inactive": lambda st: st in ("vi", "vI"),
|
||||
"admin": lambda st: st == "a",
|
||||
}
|
||||
|
||||
|
||||
@app.route("/api/rankings")
|
||||
def api_rankings():
|
||||
"""Classifiche con filtri: type=total|military|fleet, range posizione, stato, testo."""
|
||||
world = load_world()
|
||||
if not world:
|
||||
return jsonify({"ok": False, "error": "Dati non disponibili."}), 503
|
||||
rtype = request.args.get("type", "total")
|
||||
if rtype not in ("total", "military", "fleet"):
|
||||
return jsonify({"ok": False, "error": "type deve essere total, military o fleet"}), 400
|
||||
try:
|
||||
start = int(request.args.get("start", 1) or 1)
|
||||
end = int(request.args.get("end", 0) or 0)
|
||||
except ValueError:
|
||||
return jsonify({"ok": False, "error": "range non valido"}), 400
|
||||
status = request.args.get("status", "all")
|
||||
if status not in _STATUS_GROUPS:
|
||||
return jsonify({"ok": False, "error": "stato non valido"}), 400
|
||||
q = (request.args.get("q") or "").strip().lower()
|
||||
|
||||
players = world["players"]
|
||||
ranks = world.get("ranks", {})
|
||||
avatar = world.get("avatar", {})
|
||||
pcount = {}
|
||||
for pl in world["planets"].values():
|
||||
pcount[pl["player"]] = pcount.get(pl["player"], 0) + 1
|
||||
|
||||
# rapporti di spionaggio per giocatore bersaglio (pianeta + luna) e
|
||||
# coordinata del rapporto più recente (per il salto diretto dal badge)
|
||||
rcount = {}
|
||||
rcoord = {}
|
||||
ridx = report_store._load_index()
|
||||
reports_meta = ridx.get("reports", {})
|
||||
for ckey, rids in ridx.get("by_coords", {}).items():
|
||||
planet = world["planets"].get(ckey.split("#")[0])
|
||||
if not planet:
|
||||
continue
|
||||
pid = planet["player"]
|
||||
rcount[pid] = rcount.get(pid, 0) + len(rids)
|
||||
for rid in rids:
|
||||
ts = (reports_meta.get(rid) or {}).get("event_timestamp") or 0
|
||||
if pid not in rcoord or ts > rcoord[pid][1]:
|
||||
rcoord[pid] = (planet["coords"], ts)
|
||||
|
||||
# flotte conosciute (tab "Top Flotte"): per ogni coordinata (pianeta o luna)
|
||||
# si prende il rapporto più recente, poi si sommano le navi per giocatore.
|
||||
latest_by_coord = {}
|
||||
for ckey, rids in ridx.get("by_coords", {}).items():
|
||||
best = None
|
||||
for rid in rids:
|
||||
ts = (reports_meta.get(rid) or {}).get("event_timestamp") or 0
|
||||
if best is None or ts > best[0]:
|
||||
best = (ts, rid)
|
||||
if best:
|
||||
latest_by_coord[ckey] = best[1]
|
||||
pships = {}
|
||||
for ckey, rid in latest_by_coord.items():
|
||||
planet = world["planets"].get(ckey.split("#")[0])
|
||||
if not planet:
|
||||
continue
|
||||
pid = planet["player"]
|
||||
ships = (reports_meta.get(rid) or {}).get("total_ship_count") or 0
|
||||
pships[pid] = pships.get(pid, 0) + int(ships)
|
||||
|
||||
ok_status = _STATUS_GROUPS[status]
|
||||
|
||||
# --- tab "Top Flotte": solo giocatori con rapporti, ordinati per navi ---
|
||||
if rtype == "fleet":
|
||||
rows = []
|
||||
mine_id = str(load_config().get("my_player_id"))
|
||||
for pid, ships in pships.items():
|
||||
p = players.get(pid)
|
||||
if not p or not ok_status(p.get("status", "")):
|
||||
continue
|
||||
name = p.get("name", "")
|
||||
tag = p.get("alliance_tag", "")
|
||||
ally_name = p.get("alliance_name", "")
|
||||
if q and not (q in name.lower() or q in tag.lower() or q in ally_name.lower()):
|
||||
continue
|
||||
rows.append({
|
||||
"id": pid, "name": name, "status": p.get("status", ""),
|
||||
"alliance_tag": tag, "alliance_name": ally_name,
|
||||
"rank": None, "score": int(ships),
|
||||
"avatar": avatar.get(pid), "planets": pcount.get(pid, 0),
|
||||
"reports": rcount.get(pid, 0),
|
||||
"report_coords": rcoord.get(pid, (None,))[0],
|
||||
"mine": str(pid) == mine_id,
|
||||
})
|
||||
rows.sort(key=lambda r: r["score"], reverse=True)
|
||||
for i, r in enumerate(rows, 1):
|
||||
r["rank"] = i
|
||||
if start > 1 or end:
|
||||
rows = [r for r in rows
|
||||
if r["rank"] >= start and (not end or r["rank"] <= end)]
|
||||
return jsonify({"ok": True, "type": "fleet", "count": len(rows), "rows": rows})
|
||||
|
||||
rows = []
|
||||
for pid, p in players.items():
|
||||
if not ok_status(p.get("status", "")):
|
||||
continue
|
||||
name = p.get("name", "")
|
||||
tag = p.get("alliance_tag", "")
|
||||
ally_name = p.get("alliance_name", "")
|
||||
if q and not (q in name.lower() or q in tag.lower() or q in ally_name.lower()):
|
||||
continue
|
||||
rk = ranks.get(pid, {})
|
||||
rank = rk.get(rtype)
|
||||
score = rk.get(rtype + "_score")
|
||||
# filtro range posizione (solo per chi ha una posizione)
|
||||
if (start > 1 or end):
|
||||
if rank is None or rank < start or (end and rank > end):
|
||||
continue
|
||||
rows.append({
|
||||
"id": pid,
|
||||
"name": name,
|
||||
"status": p.get("status", ""),
|
||||
"alliance_tag": tag,
|
||||
"alliance_name": ally_name,
|
||||
"rank": rank,
|
||||
"score": int(score) if score is not None else None,
|
||||
"avatar": avatar.get(pid),
|
||||
"planets": pcount.get(pid, 0),
|
||||
"reports": rcount.get(pid, 0),
|
||||
"report_coords": rcoord.get(pid, (None,))[0],
|
||||
"mine": str(pid) == str(load_config().get("my_player_id")),
|
||||
})
|
||||
rows.sort(key=lambda r: (r["rank"] is None, r["rank"] or 10 ** 9))
|
||||
return jsonify({"ok": True, "type": rtype, "count": len(rows), "rows": rows})
|
||||
|
||||
|
||||
def _ensure_fresh_data():
|
||||
"""All'avvio: aggiorna se l'ultimo fetch dei players è più vecchio di refresh_hours."""
|
||||
cfg = load_config()
|
||||
world = load_world()
|
||||
stale = True
|
||||
if world:
|
||||
ft = world.get("fetched", {}).get("players") or 0
|
||||
stale = (time.time() - ft) > cfg.get("refresh_hours", 24) * 3600
|
||||
if stale:
|
||||
print("Dati datati: aggiornamento all'avvio...")
|
||||
try:
|
||||
update_data.main()
|
||||
except Exception as e:
|
||||
print("Aggiornamento iniziale fallito:", e)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
_ensure_fresh_data()
|
||||
app.run(host="0.0.0.0", port=8899, debug=False)
|
||||
Reference in New Issue
Block a user