diff --git a/metrics_snapshot.py b/metrics_snapshot.py index 0cb79f6..ee216a9 100644 --- a/metrics_snapshot.py +++ b/metrics_snapshot.py @@ -99,7 +99,7 @@ def from_listmonk() -> int | None: print("metrics: LISTMONK_API_TOKEN not set — newsletter_subs left NULL") return None try: - total, page = 0, 1 + total, page, seen = 0, 1, 0 while True: data = _get_json( f"{LISTMONK_BASE}/api/subscribers?list_id={LISTMONK_LIST_ID}&per_page=100&page={page}", @@ -107,10 +107,25 @@ def from_listmonk() -> int | None: ) or {} payload = data.get("data") or {} rows = payload.get("results") or [] - total += sum(1 for s in rows if (s.get("status") or "") == "confirmed") + # The subscriber's own `status` is enabled/blocked; the LIST + # membership status is what means "on this list" — counting the + # former returned a silent, wrong 0. + for s in rows: + for membership in s.get("lists") or []: + if membership.get("id") == LISTMONK_LIST_ID and ( + membership.get("subscription_status") or "" + ) == "confirmed": + total += 1 + seen += len(rows) if not rows or len(rows) < 100 or page >= 20: break page += 1 + if seen == 0: + # Nothing came back at all: the endpoint or payload shape changed. + # Record "not measured" (NULL) rather than a zero that reads as + # "nobody is subscribed". + print("metrics: listmonk returned no rows — newsletter_subs left NULL") + return None return total except Exception as exc: # noqa: BLE001 - report, never guess print(f"metrics: listmonk read failed ({exc}) — newsletter_subs left NULL")