Add per-user stats: play/error events + /api/stats + ?stats page

- server: 'play' event on successful stream fetch, 'error' on 404 stream
  failures; new POST /api/events for client-reported playback errors
  (only type=error accepted, fields allowlisted + length-capped)
- server: GET /api/stats?days=N — watch time from position-event pos
  deltas (<=90s cap: bigger jumps are seeks), episodes started/completed
  (>=95% of dur), days active, weekday histogram, top anime/searches,
  sub/dub split, error count
- frontend: ?stats page (cards, weekday bars, most-watched, top
  searches) + 'stats' link on home; playerFail now reports the error
- test: test_stats with synthetic viewing data (deltas, isolation, 422)
This commit is contained in:
jozamudi committed 2026-08-24 17:09:27 +00:00
1 parent 202bfa41c3
commit 2f373b9bba
4 files changed
+218 -5

No files matched your search

+13
View File
@@ -49,6 +49,19 @@ h2 { margin: 0.4rem 0; }
.bar.small { height: 4px; margin-top: .4rem; }
.grid.mini { grid-template-columns: repeat(auto-fill, minmax(140px, 170px)); }
.grid.mini .card { cursor: pointer; }
/* stats page (?stats) */
.grid.stats { grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); }
.card.stat { padding: .8rem; gap: .2rem; }
.stat-value { font-size: 1.3rem; font-weight: 700; }
.wk { display: flex; gap: .5rem; align-items: flex-end; margin: .4rem 0 .8rem; }
.wk-col { display: flex; flex-direction: column; align-items: center; gap: .2rem; }
.wk-bar { width: 26px; background: var(--acc); border-radius: 4px; }
.wk-day { font-size: .7rem; color: var(--muted); }
.stat-row { display: grid; grid-template-columns: minmax(0, 1fr) auto 90px; gap: .8rem;
align-items: center; margin: .35rem 0; }
.stat-title { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.stat-row .bar { margin-top: 0; }
.mini-info { display: flex; flex-direction: column; padding: .5rem; }
.mini-meta { font-size: .75rem; color: var(--muted); margin-top: .1rem; }
@media (max-width: 640px) {