Stats: GitHub-style watch-time heatmap
- api/stats gains by_day: local-date -> seconds (same watch-time heuristic as by_weekday) - ?stats renders a Mon..Sun x week grid (30d window, matches the page header) with 4 intensity levels + tooltip per cell + legend; replaces the by-weekday bar chart the heatmap subsumes - test_stats covers by_day (sums, slug-scoped, empty case)
This commit is contained in:
1 parent
7d9fab6bd9
commit
7b670cff24
4 files changed
+52
-20
No files matched your search
+9
-3
@@ -281,6 +281,7 @@ def api_stats(request: Request, days: int = Query(30, ge=1, le=365),
|
||||
# viewing; a backward jump >60s within an ep counts as a rewatch
|
||||
eps = {}
|
||||
watch_sec = [0.0] * 7 # Mon..Sun
|
||||
by_day = {} # local YYYY-MM-DD -> seconds
|
||||
for ts, payload in positions:
|
||||
e = json.loads(payload)
|
||||
k = (str(e.get("slug_id")), e.get("season_id"), e.get("ep_id"))
|
||||
@@ -299,9 +300,13 @@ def api_stats(request: Request, days: int = Query(30, ge=1, le=365),
|
||||
if e.get("total"):
|
||||
s["total"] = e["total"]
|
||||
if s["pos"] is not None and 0 < p - s["pos"] <= 90:
|
||||
s["secs"] += p - s["pos"]
|
||||
s["eng" if e.get("lang") == "eng" else "jpn"] += p - s["pos"]
|
||||
watch_sec[datetime.fromtimestamp(ts).weekday()] += p - s["pos"]
|
||||
d = p - s["pos"]
|
||||
s["secs"] += d
|
||||
s["eng" if e.get("lang") == "eng" else "jpn"] += d
|
||||
dt = datetime.fromtimestamp(ts)
|
||||
watch_sec[dt.weekday()] += d
|
||||
k = dt.strftime("%Y-%m-%d")
|
||||
by_day[k] = by_day.get(k, 0) + d
|
||||
elif s["pos"] is not None and p < s["pos"] - 60:
|
||||
s["rewinds"] += 1
|
||||
s["pos"] = p
|
||||
@@ -362,6 +367,7 @@ def api_stats(request: Request, days: int = Query(30, ge=1, le=365),
|
||||
"plays": len(plays),
|
||||
"errors": n_errors,
|
||||
"by_weekday": [int(x) for x in watch_sec], # seconds, Mon..Sun
|
||||
"by_day": {k: int(v) for k, v in by_day.items()}, # seconds per local day
|
||||
"top_anime": top,
|
||||
"top_searches": [q for q, _ in Counter(searches).most_common(5) if q],
|
||||
"sub_dub": {"jpn": plays_by_lang.get("jpn", 0), "eng": plays_by_lang.get("eng", 0)},
|
||||
|
||||
Reference in new issue
Block a user