Reconcile playback versions after realtime reconnect

- Track realtime connection state from the video player
- Refresh watch detail versions once the session reconnects
This commit is contained in:
Silo Server Migration
2026-05-24 00:47:47 -04:00
parent 669be3a2b4
commit cc2f016464
2 changed files with 58 additions and 1 deletions
+7 -1
View File
@@ -95,6 +95,7 @@ interface VideoPlayerProps {
onPlaybackTransportReady?: (transport: PlayerPlaybackTransport | null) => void;
onReturnFromPostRoll?: () => void;
onRealtimeEvent?: (event: PlaybackRealtimeEventEnvelope) => void;
onRealtimeConnectionStateChange?: (state: "disconnected" | "connecting" | "connected") => void;
watchTogetherRoomId?: string | null;
watchTogetherConnection?: WatchTogetherRoomConnectionResult;
}
@@ -181,6 +182,7 @@ export function VideoPlayer({
onPlaybackTransportReady,
onReturnFromPostRoll,
onRealtimeEvent,
onRealtimeConnectionStateChange,
watchTogetherRoomId,
watchTogetherConnection,
}: VideoPlayerProps) {
@@ -1714,12 +1716,16 @@ export function VideoPlayer({
[handleExit, performPlayerSeek],
);
usePlaybackRealtime({
const realtime = usePlaybackRealtime({
sessionId,
onCommand: executeRealtimeCommand,
onEvent: onRealtimeEvent,
});
useEffect(() => {
onRealtimeConnectionStateChange?.(realtime.connectionState);
}, [onRealtimeConnectionStateChange, realtime.connectionState]);
// -- Postroll mini-player resize --
const [miniPlayerWidth, setMiniPlayerWidth] = useState(320);
const isDraggingRef = useRef(false);
+51
View File
@@ -99,7 +99,11 @@ export function WatchPage({
const playbackController = useWatchPlaybackController();
const chapterRefreshAttemptsRef = useRef<Set<number>>(new Set());
const handledSelectionRevisionRef = useRef<number | null>(null);
const markerRealtimeReconcileKeyRef = useRef<string | null>(null);
const [playbackVersions, setPlaybackVersions] = useState(versions);
const [realtimeConnectionState, setRealtimeConnectionState] = useState<
"disconnected" | "connecting" | "connected"
>("disconnected");
const watchTogetherConnection = useWatchTogetherRoomConnection({
roomId: watchTogetherRoomId,
roomToken: watchTogetherRoomToken,
@@ -197,6 +201,7 @@ export function WatchPage({
useEffect(() => {
chapterRefreshAttemptsRef.current.clear();
markerRealtimeReconcileKeyRef.current = null;
}, [contentId, playbackRequestKey]);
useEffect(() => {
@@ -274,6 +279,51 @@ export function WatchPage({
playbackVersions,
]);
useEffect(() => {
if (
realtimeConnectionState !== "connected" ||
!session.sessionId ||
!session.mediaFileId ||
session.loading ||
session.replacing
) {
return;
}
const activeFileId = session.mediaFileId;
const reconcileKey = `${session.sessionId}:${activeFileId}`;
if (markerRealtimeReconcileKeyRef.current === reconcileKey) {
return;
}
markerRealtimeReconcileKeyRef.current = reconcileKey;
let cancelled = false;
void queryClient
.fetchQuery({
queryKey: itemKeys.watchDetail(contentId, activeFileId, libraryId),
queryFn: () => fetchWatchDetail(contentId, activeFileId, libraryId),
staleTime: 0,
})
.then((detail) => {
if (!cancelled) {
setPlaybackVersions(detail.versions);
}
});
return () => {
cancelled = true;
};
}, [
contentId,
libraryId,
queryClient,
realtimeConnectionState,
session.loading,
session.mediaFileId,
session.replacing,
session.sessionId,
]);
const handleRealtimeEvent = useCallback(
(event: PlaybackRealtimeEventEnvelope) => {
if (event.name === "chapter_thumbnail_ready") {
@@ -427,6 +477,7 @@ export function WatchPage({
onPlaybackStateChange={onPlaybackStateChange}
onPlaybackTransportReady={onPlaybackTransportReady}
onRealtimeEvent={handleRealtimeEvent}
onRealtimeConnectionStateChange={setRealtimeConnectionState}
onExit={onExit}
onMinimize={onMinimize}
onEnded={handleEnded}