"Listening time this week" summed the full duration of every track whose
stream ticket was issued, so pressing play and skipping counted the whole
song. Playback is now measured on the client and reported to the API.
Backend:
- ListeningHistory gains PlayedSeconds, LastProgressAt and IsCounted
(migration TrackPlayedSeconds marks existing rows as counted).
- /tracks/{id}/stream returns a listenId; new
PUT /tracks/listens/{listenId}/progress stores the accumulated seconds,
capped by track duration and elapsed wall-clock time, monotonic and
owner-only.
- A listen counts once it reaches min(30s, 50% of the track). Weekly
stats, streak, recent history/albums, mixes and listensCount only use
counted listens; seconds sum PlayedSeconds.
- ListeningHistoryCleanupJob (daily) deletes uncounted listens older
than 8 days.
web-player:
- ListenTracker accumulates played time (seeks are ignored) and flushes
on pause, track change, ended, every 30s, and on pagehide.
- Proxy route /api/listens/[id]/progress; repeat starts a new listen per
loop.
web-player
Musify's web client: SvelteKit 2 (adapter-node), Svelte 5 runes, Tailwind 4,
TypeScript. Authentication is server-side OIDC against Zitadel (openid-client
and jose) with an encrypted session cookie; the backend is called from load
functions and form actions through a typed openapi-fetch client.
Development
npm install
npm run dev # :5173
Configuration lives in .env (template in .env.example). Bring the
infrastructure stack up first (see ../deploy/README.md)
and copy the WEB_CLIENT_ID / WEB_CLIENT_SECRET it writes to deploy/.env
into this .env once, then run the dev server.
npm run check # svelte-check — must be clean before closing a change
npm run lint # prettier --check . && eslint .
npm run format # prettier --write .
npm run build # production build into build/
npm run gen:api # regenerate src/lib/api/schema.d.ts from the running API
Production
Built and run as a container by the production stack — see
../deploy/README.md. There the same variables come from
deploy/.env.prod through compose instead of from .env.
Conventions and the design system are documented in CLAUDE.md and
in the musify-web skill.