File
Blob: worker/src/client/radio/playback.ts
| 1 | import { newerRevision } from '@/shared/contracts/track.ts'; |
| 2 | import type { NowPlaying } from '@/shared/contracts/track.ts'; |
| 3 | import type { SessionState } from './session-state.ts'; |
| 4 | |
| 5 | export function acceptMetadata(previous: NowPlaying | undefined, next: NowPlaying): NowPlaying { |
| 6 | return !previous || newerRevision(next.revision, previous.revision) ? next : previous; |
| 7 | } |
| 8 | |
| 9 | /** Packets with a revision must match the current playback revision; legacy packets omit it. */ |
| 10 | export function matchesPlayback(revision: number | undefined, current?: NowPlaying): boolean { |
| 11 | return revision === undefined || revision === current?.revision; |
| 12 | } |
| 13 | |
| 14 | export function playbackView( |
| 15 | state: Pick<SessionState, 'room' | 'nowPlaying' | 'telemetry' | 'paused'>, |
| 16 | ) { |
| 17 | const { nowPlaying, room, telemetry } = state; |
| 18 | // An explicit unknown track must not fall back to stale HTTP metadata. |
| 19 | const track = (nowPlaying ? nowPlaying.track : room.track) ?? undefined; |
| 20 | const currentSample = !nowPlaying || telemetry?.playbackRevision === nowPlaying.revision; |
| 21 | return { |
| 22 | track, |
| 23 | trackCount: nowPlaying?.trackCount ?? 1, |
| 24 | position: currentSample ? (telemetry?.positionMs ?? 0) : 0, |
| 25 | duration: track?.durationMs ?? (currentSample ? (telemetry?.durationMs ?? 0) : 0), |
| 26 | paused: state.paused ?? false, |
| 27 | }; |
| 28 | } |