The server now sends each fresh position on every poll that has one, and sends positions advanced to send time; clients count only the time since they received it. Bars realign every poll and no longer drift by however far the viewer's clock is off. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MzFywujuH9TiuXbr9vjoX8
This commit is contained in:
@@ -5,22 +5,25 @@ import { formatDuration, playbackPosition, type NowPlayingDTO } from '@musicshar
|
||||
|
||||
/** Where they are in the song. Renders nothing when the source doesn't report a position. */
|
||||
export function ProgressBar({ np }: { np: NowPlayingDTO }) {
|
||||
const [now, setNow] = useState(() => Date.now());
|
||||
const pos = playbackPosition(np, now);
|
||||
const ticking = np.isPlaying && pos !== null;
|
||||
if (!np.isPlaying || playbackPosition(np, 0) === null) return null;
|
||||
// Each fresh position from the server restarts the clock, realigning the bar.
|
||||
return <Bar key={`${np.track.id}|${np.progressMs}|${np.updatedAt}`} np={np} />;
|
||||
}
|
||||
|
||||
function Bar({ np }: { np: NowPlayingDTO }) {
|
||||
const [receivedAt] = useState(() => Date.now());
|
||||
const [now, setNow] = useState(receivedAt);
|
||||
useEffect(() => {
|
||||
if (!ticking) return;
|
||||
const id = setInterval(() => setNow(Date.now()), 1000);
|
||||
return () => clearInterval(id);
|
||||
}, [ticking]);
|
||||
}, []);
|
||||
|
||||
if (!pos || !np.isPlaying) return null;
|
||||
const pct = (pos.positionMs / pos.durationMs) * 100;
|
||||
const pos = playbackPosition(np, now - receivedAt);
|
||||
if (!pos) return null;
|
||||
return (
|
||||
<div className="progress" aria-label={`${formatDuration(pos.positionMs)} of ${formatDuration(pos.durationMs)}`}>
|
||||
<div className="progress-track">
|
||||
<div className="progress-fill" style={{ width: `${pct}%` }} />
|
||||
<div className="progress-fill" style={{ width: `${(pos.positionMs / pos.durationMs) * 100}%` }} />
|
||||
</div>
|
||||
<div className="progress-times" aria-hidden>
|
||||
<span>{formatDuration(pos.positionMs)}</span>
|
||||
|
||||
Reference in New Issue
Block a user