Toutes les sorties et tous les événements du Québec, un seul endroit — 7 connecteurs, fiches SSR, design Groupe KA.
1# -----------------------------------------------------------------------------2# Sorti-Ka — Agrégateur de sorties & événements (province de Québec)3# Auteur : Simon-Pierre Boucher — contact@spboucher.ai4# ingest.py : pipeline d'ingestion — exécute les connecteurs et synchronise5# la base (ajouts / mises à jour / retraits) = contenu toujours à6# jour (patron Lou-Ka : louka/ingest.py)7# -----------------------------------------------------------------------------8from __future__ import annotations910import sys11import time12import traceback1314from . import db15from .connectors import CONNECTORS161718def run(sources: list[str] | None = None) -> list[dict]:19 """Exécute l'ingestion pour toutes les sources (ou celles demandées)."""20 con = db.connect()21 results = []22 targets = sources or list(CONNECTORS.keys())23 for sid in targets:24 cls = CONNECTORS.get(sid)25 if cls is None:26 print(f"[sorti-ka] connecteur inconnu : {sid}", file=sys.stderr)27 continue28 t0 = time.time()29 print(f"[sorti-ka] sync {sid} ...")30 try:31 events = cls().fetch()32 finalized, dropped = [], 033 for ev in events:34 try:35 finalized.append(ev.finalize())36 except Exception: # un événement malformé ne bloque pas la source37 dropped += 138 stats = db.sync_source(con, sid, finalized)39 stats["seconds"] = round(time.time() - t0, 1)40 if dropped:41 stats["dropped"] = dropped42 if stats.get("alert"):43 print(f"[sorti-ka] ⚠ ALERTE {sid} : {stats['alert']}")44 print(f"[sorti-ka] {stats}")45 results.append(stats)46 except Exception as exc: # robustesse : une source ne bloque pas les autres47 db.log_failure(con, sid, f"{exc}")48 traceback.print_exc()49 results.append({"source": sid, "error": str(exc)})50 try:51 con.execute("PRAGMA optimize")52 except Exception:53 pass54 con.close()55 return results565758def watch(interval_seconds: int = 6 * 3600) -> None:59 """Boucle de rafraîchissement périodique (pseudo-webhook par sondage).6061 Cadence par défaut : 6 h — les calendriers d'événements bougent plus vite62 qu'un parc locatif, mais les sources ouvertes n'exigent pas de temps réel.63 """64 while True:65 run()66 print(f"[sorti-ka] prochaine synchro dans {interval_seconds // 60} min")67 time.sleep(interval_seconds)68