Phase 1+2 of a self-hosted, multi-user listening archive — the basis for day/month/year stats and a yearly "Wrapped". Runs IN ADDITION to the existing Navidrome/Last.fm scrobble; never replaces it. Service (isolated, own container): - scrobble/scrobble-server.js — node:sqlite play-log (own volume), routes POST /scrobble/plays (idempotent by uuid), GET /scrobble/history (archive), DELETE /scrobble/plays?user= (test cleanup), GET /scrobble/health. Multi-user auth via Navidrome ping.view (cached) -> user not spoofable. - docker-compose: novasonic-scrobble service (node:22, port 3710) + volume; backend bumped node:20->22 (EOL); SCROBBLE_URL plumbing (entrypoint, .env.example). Capture (both platforms, offline-safe queue, idempotent batch flush): - Fires at the existing scrobbleMode counted-play moment — consistent with Last.fm, respects the user's setting (no separate 50%/4min rule). - Web: src/player/scrobbleLog.js (localStorage queue) + subsonicAuthParams() in api.js + hooks in player.js + flush init in main.js; S.cfg.scrobbleUrl. - Android: data/PlayLogClient.kt (filesDir queue, reused Ktor client) + repo.logPlay/flushPlayLog + PlayerController hook + NovaSonicApp flush + scrobbleUrl in PrefsStore/SettingsViewModel/SettingsScreen (with test button). Plan + design decisions documented in docs/scrobble-plan.md. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
13 lines
309 B
JSON
13 lines
309 B
JSON
{
|
|
"name": "novasonic-scrobble",
|
|
"private": true,
|
|
"description": "Isolated timestamped play-log service for NovaSonic (stats + Wrapped).",
|
|
"engines": { "node": ">=22" },
|
|
"scripts": {
|
|
"start": "node --experimental-sqlite scrobble-server.js"
|
|
},
|
|
"dependencies": {
|
|
"express": "^4.18.0"
|
|
}
|
|
}
|