From 8f28d9c9ce9e47b41c5a9f82605a321fadbf640d Mon Sep 17 00:00:00 2001 From: nmemmert <67961292+nmemmert@users.noreply.github.com> Date: Tue, 25 Aug 2026 13:45:10 -0400 Subject: [PATCH] Deduplicate missing/scraped stats; show matched from latest run MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - total_scraped: unique songs ever seen playing (not per-run sum) - total_missing: unique songs ever reported not in Plex library - total_matched: matched_count from most recent successful run - Added (144) stays cumulative — each add is a real playlist event Co-Authored-By: Claude Sonnet 4.6 --- journeyfm/web_service.py | 50 ++++++++++++++++++++++++---------------- 1 file changed, 30 insertions(+), 20 deletions(-) diff --git a/journeyfm/web_service.py b/journeyfm/web_service.py index 4f0cd25..e3d6dbe 100644 --- a/journeyfm/web_service.py +++ b/journeyfm/web_service.py @@ -48,41 +48,51 @@ def load_recent_stats(db_path=None): try: c = conn.cursor() c.execute( - "SELECT COUNT(*), SUM(matched_count), SUM(added_count)," - " SUM(missing_count), SUM(duplicate_count), SUM(skipped_count) FROM history" + "SELECT COUNT(*), SUM(added_count), SUM(duplicate_count), SUM(skipped_count) FROM history" ) row = c.fetchone() or () stats["total_updates"] = int(row[0] or 0) - stats["total_matched"] = int(row[1] or 0) - stats["total_added"] = int(row[2] or 0) - stats["total_missing"] = int(row[3] or 0) - stats["total_duplicates"] = int(row[4] or 0) - stats["total_skipped"] = int(row[5] or 0) + stats["total_added"] = int(row[1] or 0) + stats["total_duplicates"] = int(row[2] or 0) + stats["total_skipped"] = int(row[3] or 0) c.execute("SELECT MAX(date), MAX(CASE WHEN status='success' THEN date END) FROM history") last_row = c.fetchone() or () stats["last_attempted"] = last_row[0] stats["last_success"] = last_row[1] - c.execute("SELECT scraped_songs FROM history") - seen = set() - for (scraped_songs_json,) in c.fetchall(): + c.execute("SELECT scraped_songs, missing_songs FROM history") + scraped_seen = set() + missing_seen = set() + for scraped_songs_json, missing_songs_json in c.fetchall(): try: for song in json.loads(scraped_songs_json or "[]"): sname = song.get("source", "Unknown") title = song.get("title", "?") artist = song.get("artist", "?") - k = (sname, artist, title) - if k in seen: - continue - seen.add(k) - stats["song_counts"].setdefault(sname, {}) - dk = f"{artist} - {title}" - stats["song_counts"][sname][dk] = stats["song_counts"][sname].get(dk, 0) + 1 + k = (artist, title) + if k not in scraped_seen: + scraped_seen.add(k) + stats["song_counts"].setdefault(sname, {}) + dk = f"{artist} - {title}" + stats["song_counts"][sname][dk] = stats["song_counts"][sname].get(dk, 0) + 1 + except Exception: + pass + try: + for song in json.loads(missing_songs_json or "[]"): + artist = song.get("artist", "?") + title = song.get("title", "?") + missing_seen.add((artist, title)) except Exception: pass - # unique song count per station derived from deduped song_counts for sname, songs in stats["song_counts"].items(): stats["station_counts"][sname] = len(songs) - stats["total_scraped"] = len(seen) + stats["total_scraped"] = len(scraped_seen) + stats["total_missing"] = len(missing_seen) + # matched from most recent successful run (per-run count is accurate) + c.execute( + "SELECT matched_count FROM history WHERE status='success' ORDER BY date DESC LIMIT 1" + ) + r = c.fetchone() + stats["total_matched"] = int(r[0] or 0) if r else 0 finally: conn.close() return stats @@ -433,7 +443,7 @@ tr:last-child td{border-bottom:none}tr:hover td{background:var(--sf2)}
Scraped
—
-
Matched
—
+
Matched (last run)
—
Added
—
Missing
—
Duplicates
—