Deduplicate missing/scraped stats; show matched from latest run
- 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 <noreply@anthropic.com>
This commit is contained in:
1 parent
b394416ed7
commit
8f28d9c9ce
1 file changed
+30
-20
+30
-20
@@ -48,41 +48,51 @@ def load_recent_stats(db_path=None):
|
|||||||
try:
|
try:
|
||||||
c = conn.cursor()
|
c = conn.cursor()
|
||||||
c.execute(
|
c.execute(
|
||||||
"SELECT COUNT(*), SUM(matched_count), SUM(added_count),"
|
"SELECT COUNT(*), SUM(added_count), SUM(duplicate_count), SUM(skipped_count) FROM history"
|
||||||
" SUM(missing_count), SUM(duplicate_count), SUM(skipped_count) FROM history"
|
|
||||||
)
|
)
|
||||||
row = c.fetchone() or ()
|
row = c.fetchone() or ()
|
||||||
stats["total_updates"] = int(row[0] or 0)
|
stats["total_updates"] = int(row[0] or 0)
|
||||||
stats["total_matched"] = int(row[1] or 0)
|
stats["total_added"] = int(row[1] or 0)
|
||||||
stats["total_added"] = int(row[2] or 0)
|
stats["total_duplicates"] = int(row[2] or 0)
|
||||||
stats["total_missing"] = int(row[3] or 0)
|
stats["total_skipped"] = int(row[3] or 0)
|
||||||
stats["total_duplicates"] = int(row[4] or 0)
|
|
||||||
stats["total_skipped"] = int(row[5] or 0)
|
|
||||||
c.execute("SELECT MAX(date), MAX(CASE WHEN status='success' THEN date END) FROM history")
|
c.execute("SELECT MAX(date), MAX(CASE WHEN status='success' THEN date END) FROM history")
|
||||||
last_row = c.fetchone() or ()
|
last_row = c.fetchone() or ()
|
||||||
stats["last_attempted"] = last_row[0]
|
stats["last_attempted"] = last_row[0]
|
||||||
stats["last_success"] = last_row[1]
|
stats["last_success"] = last_row[1]
|
||||||
c.execute("SELECT scraped_songs FROM history")
|
c.execute("SELECT scraped_songs, missing_songs FROM history")
|
||||||
seen = set()
|
scraped_seen = set()
|
||||||
for (scraped_songs_json,) in c.fetchall():
|
missing_seen = set()
|
||||||
|
for scraped_songs_json, missing_songs_json in c.fetchall():
|
||||||
try:
|
try:
|
||||||
for song in json.loads(scraped_songs_json or "[]"):
|
for song in json.loads(scraped_songs_json or "[]"):
|
||||||
sname = song.get("source", "Unknown")
|
sname = song.get("source", "Unknown")
|
||||||
title = song.get("title", "?")
|
title = song.get("title", "?")
|
||||||
artist = song.get("artist", "?")
|
artist = song.get("artist", "?")
|
||||||
k = (sname, artist, title)
|
k = (artist, title)
|
||||||
if k in seen:
|
if k not in scraped_seen:
|
||||||
continue
|
scraped_seen.add(k)
|
||||||
seen.add(k)
|
stats["song_counts"].setdefault(sname, {})
|
||||||
stats["song_counts"].setdefault(sname, {})
|
dk = f"{artist} - {title}"
|
||||||
dk = f"{artist} - {title}"
|
stats["song_counts"][sname][dk] = stats["song_counts"][sname].get(dk, 0) + 1
|
||||||
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:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
# unique song count per station derived from deduped song_counts
|
|
||||||
for sname, songs in stats["song_counts"].items():
|
for sname, songs in stats["song_counts"].items():
|
||||||
stats["station_counts"][sname] = len(songs)
|
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:
|
finally:
|
||||||
conn.close()
|
conn.close()
|
||||||
return stats
|
return stats
|
||||||
@@ -433,7 +443,7 @@ tr:last-child td{border-bottom:none}tr:hover td{background:var(--sf2)}
|
|||||||
<div id="sec-overview" class="sec active">
|
<div id="sec-overview" class="sec active">
|
||||||
<div class="sg">
|
<div class="sg">
|
||||||
<div class="sc"><div class="sl">Scraped</div><div class="sv cb" id="v-sc">—</div></div>
|
<div class="sc"><div class="sl">Scraped</div><div class="sv cb" id="v-sc">—</div></div>
|
||||||
<div class="sc"><div class="sl">Matched</div><div class="sv cg" id="v-ma">—</div></div>
|
<div class="sc"><div class="sl">Matched (last run)</div><div class="sv cg" id="v-ma">—</div></div>
|
||||||
<div class="sc"><div class="sl">Added</div><div class="sv ca" id="v-ad">—</div></div>
|
<div class="sc"><div class="sl">Added</div><div class="sv ca" id="v-ad">—</div></div>
|
||||||
<div class="sc"><div class="sl">Missing</div><div class="sv cr" id="v-mi">—</div></div>
|
<div class="sc"><div class="sl">Missing</div><div class="sv cr" id="v-mi">—</div></div>
|
||||||
<div class="sc"><div class="sl">Duplicates</div><div class="sv cm" id="v-du">—</div></div>
|
<div class="sc"><div class="sl">Duplicates</div><div class="sv cm" id="v-du">—</div></div>
|
||||||
|
|||||||
Reference in new issue
Block a user