From eefda2140e9dccd5a31f8cba2626476d48a8b3bd Mon Sep 17 00:00:00 2001 From: Uyanide Date: Thu, 2 Apr 2026 10:48:26 +0200 Subject: [PATCH] feat: better cache stats --- lrx_cli/cache.py | 43 +++++++++++++++++++++++++++++++++++++++++++ lrx_cli/cli.py | 48 ++++++++++++++++++++++++++++++++++++++++-------- pyproject.toml | 2 +- uv.lock | 2 +- 4 files changed, 85 insertions(+), 10 deletions(-) diff --git a/lrx_cli/cache.py b/lrx_cli/cache.py index ef2e79d..c8f46a4 100644 --- a/lrx_cli/cache.py +++ b/lrx_cli/cache.py @@ -441,10 +441,53 @@ class CacheEngine: "SELECT source, COUNT(*) FROM cache GROUP BY source" ).fetchall() ) + # Source × Status cross-tabulation + source_status = conn.execute( + "SELECT source, status, COUNT(*) FROM cache GROUP BY source, status" + ).fetchall() + # Confidence buckets (only for positive statuses) + confidence_rows = conn.execute( + "SELECT confidence FROM cache WHERE status IN (?, ?)", + ( + CacheStatus.SUCCESS_SYNCED.value, + CacheStatus.SUCCESS_UNSYNCED.value, + ), + ).fetchall() + + # Build source×status table: {source: {status: count}} + source_status_table: dict[str, dict[str, int]] = {} + for src, status, count in source_status: + source_status_table.setdefault(src, {})[status] = count + + # Build confidence buckets + buckets = { + "legacy (NULL)": 0, + "0-24": 0, + "25-49": 0, + "50-79": 0, + "80-99": 0, + "100": 0, + } + for (conf,) in confidence_rows: + if conf is None: + buckets["legacy (NULL)"] += 1 + elif conf >= 100: + buckets["100"] += 1 + elif conf >= 80: + buckets["80-99"] += 1 + elif conf >= 50: + buckets["50-79"] += 1 + elif conf >= 25: + buckets["25-49"] += 1 + else: + buckets["0-24"] += 1 + return { "total": total, "expired": expired, "active": total - expired, "by_status": by_status, "by_source": by_source, + "source_status": source_status_table, + "confidence_buckets": buckets, } diff --git a/lrx_cli/cli.py b/lrx_cli/cli.py index ff1ee9e..b1602de 100644 --- a/lrx_cli/cli.py +++ b/lrx_cli/cli.py @@ -354,14 +354,46 @@ def stats(): print(f"Total entries : {s['total']}") print(f"Active : {s['active']}") print(f"Expired : {s['expired']}") - if s["by_status"]: - print("\nBy status:") - for status, count in s["by_status"].items(): - print(f" {status}: {count}") - if s["by_source"]: - print("\nBy source:") - for source, count in s["by_source"].items(): - print(f" {source}: {count}") + + # Source × Status table + table = s.get("source_status", {}) + if table: + all_statuses = sorted({st for row in table.values() for st in row}) + # Short labels for column headers + short = { + "SUCCESS_SYNCED": "synced", + "SUCCESS_UNSYNCED": "unsynced", + "NOT_FOUND": "not_found", + "NETWORK_ERROR": "net_err", + } + headers = [short.get(st, st) for st in all_statuses] + sources = sorted(table.keys()) + # Column widths + src_w = max(len(src) for src in sources) + src_w = max(src_w, 6) # min width for "source" header + col_w = [max(len(h) if h else 0, 4) for h in headers] + + print( + f"\n{'source':<{src_w}} " + + " ".join(f"{h:>{w}}" for h, w in zip(headers, col_w)) + ) + print("-" * src_w + " " + " ".join("-" * w for w in col_w)) + for src in sources: + counts = [str(table[src].get(st, 0)) for st in all_statuses] + print( + f"{src:<{src_w}} " + + " ".join(f"{c:>{w}}" for c, w in zip(counts, col_w)) + ) + + # Confidence distribution (positive entries only) + buckets = s.get("confidence_buckets", {}) + non_empty = {k: v for k, v in buckets.items() if v > 0} + if non_empty: + label_w = max(len(k) for k in non_empty) + print("\nConfidence distribution (positive entries):") + for label, count in buckets.items(): + if count > 0: + print(f" {label:>{label_w}} : {count}") @cache_app.command diff --git a/pyproject.toml b/pyproject.toml index 4406265..b9772ec 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "hatchling.build" [project] name = "lrx-cli" -version = "0.3.0" +version = "0.3.1" description = "Fetch line-synced lyrics for your music player." readme = "README.md" requires-python = ">=3.13" diff --git a/uv.lock b/uv.lock index 0d0e99d..4ccaaef 100644 --- a/uv.lock +++ b/uv.lock @@ -153,7 +153,7 @@ wheels = [ [[package]] name = "lrx-cli" -version = "0.3.0" +version = "0.3.1" source = { editable = "." } dependencies = [ { name = "cyclopts" },