LiveProgress
Pure math for the live/DVR scrub bar. Extracted so the epoch-anchored timeshift domain — which took three iterations to stop sawtoothing as the HLS playlist refreshed — is guarded by unit tests instead of only pixel-checked on a device.
The domain grows with real time: domainMs spans [anchor .. live-edge-now], so the thumb keeps advancing while the viewer watches from behind the edge. All inputs are epoch/ms primitives; there is no Media3 or Android dependency.
Functions
True when within thresholdMs of the live edge (or duration unknown).
Growing timeshift domain: window from anchorEpochMs to the current live edge (playhead wall clock + latency), never smaller than the DVR window durationMs.
The stretch that has aged out of the DVR window, as a 0..1 fraction.