diff --git a/web/src/components/player/PreviewVideoPlayer.tsx b/web/src/components/player/PreviewVideoPlayer.tsx index b10a3c137..5d68f0d02 100644 --- a/web/src/components/player/PreviewVideoPlayer.tsx +++ b/web/src/components/player/PreviewVideoPlayer.tsx @@ -16,6 +16,7 @@ type PreviewVideoPlayerProps = { camera: string; timeRange: { start: number; end: number }; cameraPreviews: Preview[]; + startTime?: number; onControllerReady: (controller: PreviewVideoController) => void; onClick?: () => void; }; @@ -24,6 +25,7 @@ export default function PreviewVideoPlayer({ camera, timeRange, cameraPreviews, + startTime, onControllerReady, onClick, }: PreviewVideoPlayerProps) { @@ -128,6 +130,10 @@ export default function PreviewVideoPlayer({ } else { previewRef.current?.pause(); } + + if (previewRef.current && startTime && currentPreview) { + previewRef.current.currentTime = startTime - currentPreview.start; + } }} > {currentPreview != undefined && ( diff --git a/web/src/pages/Events.tsx b/web/src/pages/Events.tsx index 3bb199fea..0d0eae1cc 100644 --- a/web/src/pages/Events.tsx +++ b/web/src/pages/Events.tsx @@ -31,6 +31,7 @@ export default function Events() { "alert", ); const [selectedReviewId, setSelectedReviewId] = useOverlayState("review"); + const [startTime, setStartTime] = useState(); // review filter @@ -221,11 +222,13 @@ export default function Events() { if (selectedReviewId.startsWith("motion")) { const motionData = selectedReviewId.split(","); + const motionStart = parseFloat(motionData[2]); + setStartTime(motionStart); // format is motion,camera,start_time return { camera: motionData[1], severity: "significant_motion" as ReviewSeverity, - start_time: parseFloat(motionData[2]), + start_time: motionStart, allCameras: allCameras, cameraSegments: reviews.filter((seg) => allCameras.includes(seg.camera), @@ -292,6 +295,7 @@ export default function Events() { timeRange={selectedTimeRange} filter={reviewFilter} severity={severity ?? "alert"} + startTime={startTime} setSeverity={setSeverity} markItemAsReviewed={markItemAsReviewed} onOpenReview={setSelectedReviewId} diff --git a/web/src/views/events/EventView.tsx b/web/src/views/events/EventView.tsx index d801aa487..776a22d36 100644 --- a/web/src/views/events/EventView.tsx +++ b/web/src/views/events/EventView.tsx @@ -44,6 +44,7 @@ type EventViewProps = { timeRange: { before: number; after: number }; filter?: ReviewFilter; severity: ReviewSeverity; + startTime?: number; setSeverity: (severity: ReviewSeverity) => void; markItemAsReviewed: (review: ReviewSegment) => void; onOpenReview: (reviewId: string) => void; @@ -57,6 +58,7 @@ export default function EventView({ timeRange, filter, severity, + startTime, setSeverity, markItemAsReviewed, onOpenReview, @@ -262,6 +264,7 @@ export default function EventView({ reviewItems={reviewItems} relevantPreviews={relevantPreviews} timeRange={timeRange} + startTime={startTime} filter={filter} onSelectReview={onSelectReview} /> @@ -518,6 +521,7 @@ type MotionReviewProps = { }; relevantPreviews?: Preview[]; timeRange: { before: number; after: number }; + startTime?: number; filter?: ReviewFilter; onSelectReview: (data: string, ctrl: boolean) => void; }; @@ -526,6 +530,7 @@ function MotionReview({ reviewItems, relevantPreviews, timeRange, + startTime, filter, onSelectReview, }: MotionReviewProps) { @@ -579,11 +584,21 @@ function MotionReview({ [lastFullHour, timeRange], ); - const [selectedRangeIdx, setSelectedRangeIdx] = useState( - timeRangeSegments.ranges.length - 1, - ); + const initialIndex = useMemo(() => { + if (!startTime) { + return timeRangeSegments.ranges.length - 1; + } + + return timeRangeSegments.ranges.findIndex( + (seg) => seg.start <= startTime && seg.end >= startTime, + ); + // only render once + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + + const [selectedRangeIdx, setSelectedRangeIdx] = useState(initialIndex); const [currentTime, setCurrentTime] = useState( - timeRangeSegments.ranges[selectedRangeIdx].start, + startTime ?? timeRangeSegments.ranges[selectedRangeIdx].start, ); const currentTimeRange = useMemo( () => timeRangeSegments.ranges[selectedRangeIdx], @@ -642,6 +657,7 @@ function MotionReview({ className={`${grow}`} camera={camera.name} timeRange={currentTimeRange} + startTime={startTime} cameraPreviews={relevantPreviews || []} onControllerReady={(controller) => { videoPlayersRef.current[camera.name] = controller;