feat(web): events dispatcher posts to /api/events on player transitions

useEventsDispatcher subscribes to player.current/state via \$effect:
on first transition to playing for a new track, POSTs play_started
and caches the id; on track-id change while a play is open, closes
the prior row as play_skipped; on natural completion (state
playing→paused with position >= duration > 0), POSTs play_ended;
on pagehide, navigator.sendBeacon fires a final play_skipped.
Stable per-tab client_id from sessionStorage.
This commit is contained in:
2026-04-26 09:42:11 -04:00
parent 599a19f780
commit b6f8a0c390
5 changed files with 289 additions and 0 deletions
+8
View File
@@ -56,3 +56,11 @@ export type SearchResponse = {
export type RadioResponse = {
tracks: TrackRef[];
};
export type EventRequest =
| { type: 'play_started'; track_id: string; client_id?: string }
| { type: 'play_ended'; play_event_id: string; duration_played_ms: number }
| { type: 'play_skipped'; play_event_id: string; position_ms: number };
export type PlayStartedResponse = { play_event_id: string; session_id: string };
export type EventOkResponse = { ok: true };