feat(scrobble): /scrobble/stats aggregation endpoint (Phase 3 backend)

Per-user listening stats via on-the-fly GROUP BY strftime (no rollup tables):
totals (plays + seconds), top artists/albums/tracks, a day/month/year time
series, and a 24h listening clock. Local-day bucketing via a tz offset.
Params exactly matched per query (node:sqlite throws on extra named params);
from defaults to all-time (avoiding the _toEpochSec(0)->now trap). Unit-verified.

Next: the web statistics view. Wrapped endpoint is Phase 4.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
HoneyandClaude Opus 4.8 committed 2026-08-07 17:09:42 +02:00
1 parent eb55184118
commit e782b75bd9
2 files changed
+72 -2

No files matched your search

+4 -2
View File
@@ -106,7 +106,7 @@ Android: [PlayerController.kt](../android/app/src/main/kotlin/com/novasonic/app/
| `GET /scrobble/history?limit=&before=` | Roh-Verlauf chronologisch = **das Archiv** | ✅ Phase 1 |
| `DELETE /scrobble/plays?user=NAME` | Zeilen eines Users löschen (Test-Cleanup) | ✅ Phase 1 |
| `GET /scrobble/health` | Liveness + Zeilen-Zahl | ✅ Phase 1 |
| `GET /scrobble/stats?range=day\|month\|year&from=&to=&tz=` | Aggregate: Top-Artists/Alben/Tracks, Summe Plays + Hörzeit, Zeit-Buckets für Charts | Phase 3 |
| `GET /scrobble/stats?from=&to=&tz=&bucket=day\|month\|year&limit=` | Aggregate: totals, Top-Artists/Alben/Tracks, Zeit-Serie (day/month/year), Hör-Uhr (byHour) | ✅ Phase 3 (Endpoint) |
| `GET /scrobble/wrapped?year=YYYY&tz=` | Fertiger Wrapped-Payload | Phase 4 |
### Routing: eigene Origin, KEIN nginx-Upstream
@@ -209,7 +209,9 @@ volumes:
Offline-Queue (Web: localStorage `ns_play_queue`; Android: `filesDir/play-queue.json`),
idempotenter Batch-Flush bei Start + `online`-Event. `SCROBBLE_URL`/`scrobbleUrl` in beiden
Settings. Web-Build + Android-`compileDebugKotlin` grün. *Ab jetzt wird real erfasst.*
3. **`/scrobble/stats`** + Web-Statistik-View (Heatmap, Monats-Balken, Top-Listen).
3. 🔨 **In Arbeit**: `/scrobble/stats` ✅ (Endpoint: totals, Top-Listen, day/month/year-Serie,
Hör-Uhr; on-the-fly `GROUP BY strftime`, tz-Offset, unit-getestet) — **noch offen: Web-Statistik-View**
(Kalender-Heatmap, Monats-Balken, Top-Listen).
4. **`/scrobble/wrapped`** + Story-Seite; Android-Stats-Screen.
5. *(optional)* ListenBrainz-Relay.