Skip to content
This repository was archived by the owner on Mar 24, 2026. It is now read-only.

Commit f0263e1

Browse files
committed
More fixes
1 parent 3257ebe commit f0263e1

1 file changed

Lines changed: 19 additions & 12 deletions

File tree

src/app/meetings/[id]/page.tsx

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ import { useLiveTranscripts } from "@/hooks/use-live-transcripts";
4747
import { PLATFORM_CONFIG, getDetailedStatus } from "@/types/vexa";
4848
import type { MeetingStatus, Meeting } from "@/types/vexa";
4949
import { StatusHistory } from "@/components/meetings/status-history";
50-
import { cn } from "@/lib/utils";
50+
import { cn, parseUTCTimestamp } from "@/lib/utils";
5151
import { vexaAPI } from "@/lib/api";
5252
import { toast } from "sonner";
5353
import { LanguagePicker } from "@/components/language-picker";
@@ -196,6 +196,19 @@ export default function MeetingDetailPage() {
196196

197197
const hasRecordingAudio = recordingFragments.length > 0;
198198

199+
// Derive recording session start time from transcript segments.
200+
// Any segment with both start_time (relative) and absolute_start_time gives us:
201+
// sessionStart = absolute_start_time - start_time * 1000
202+
// This is more reliable than recording.created_at (which is the DB insert time, not session start).
203+
const videoTimeBase = useMemo(() => {
204+
for (const seg of transcripts) {
205+
if (seg.absolute_start_time && seg.start_time != null) {
206+
return parseUTCTimestamp(seg.absolute_start_time).getTime() - seg.start_time * 1000;
207+
}
208+
}
209+
return null;
210+
}, [transcripts]);
211+
199212
const handlePlaybackTimeUpdate = useCallback((time: number) => {
200213
setPlaybackTime(time);
201214
setIsPlaybackActive(true);
@@ -656,17 +669,11 @@ export default function MeetingDetailPage() {
656669
// absolute timestamp so the transcript viewer can match against absolute_start_time.
657670
const playbackAbsoluteTime = useMemo((): string | null => {
658671
if (playbackTime == null || !isPlaybackActive) return null;
659-
// Video mode: currentTime is relative to meeting start (same as live audio recording).
660-
// videoRecording.createdAt is the upload time, not the meeting start — use the
661-
// first audio fragment's createdAt, or fall back to the meeting's start_time.
672+
// Video mode: use session start time derived from transcript segments.
673+
// (recording.created_at is the DB insert time, not when recording content started)
662674
if (videoRecording && !preferAudio) {
663-
const base =
664-
recordingFragments[0]?.createdAt ??
665-
currentMeeting?.start_time ??
666-
null;
667-
if (!base) return null;
668-
const fragStart = new Date(base).getTime();
669-
return new Date(fragStart + playbackTime * 1000).toISOString();
675+
if (videoTimeBase == null) return null;
676+
return new Date(videoTimeBase + playbackTime * 1000).toISOString();
670677
}
671678
if (recordingFragments.length === 0) return null;
672679
if (recordingFragments.length === 1) {
@@ -685,7 +692,7 @@ export default function MeetingDetailPage() {
685692
remaining -= fragDur;
686693
}
687694
return null;
688-
}, [playbackTime, isPlaybackActive, recordingFragments, videoRecording, preferAudio, currentMeeting]);
695+
}, [playbackTime, isPlaybackActive, recordingFragments, videoRecording, preferAudio, videoTimeBase]);
689696

690697
if (error) {
691698
return (

0 commit comments

Comments
 (0)