From d5f57c117eccff5107c9ed3c5b9fba36646a1323 Mon Sep 17 00:00:00 2001 From: Nick Mowen Date: Thu, 14 Dec 2023 08:10:01 -0700 Subject: [PATCH] Playback recording when clicking on review item --- web-new/src/components/card/HistoryCard.tsx | 7 +- .../components/card/TimelineCardPlayer.tsx | 74 +++++++++++++++++++ .../player/PreviewThumbnailPlayer.tsx | 4 + web-new/src/pages/History.tsx | 19 ++++- web-new/src/types/record.ts | 11 +++ 5 files changed, 110 insertions(+), 5 deletions(-) create mode 100644 web-new/src/components/card/TimelineCardPlayer.tsx create mode 100644 web-new/src/types/record.ts diff --git a/web-new/src/components/card/HistoryCard.tsx b/web-new/src/components/card/HistoryCard.tsx index ddf77e47f..c297aeaaa 100644 --- a/web-new/src/components/card/HistoryCard.tsx +++ b/web-new/src/components/card/HistoryCard.tsx @@ -23,12 +23,14 @@ type HistoryCardProps = { timeline: Card; relevantPreview?: Preview; shouldAutoPlay: boolean; + onClick?: () => void; }; export default function HistoryCard({ relevantPreview, timeline, shouldAutoPlay, + onClick, }: HistoryCardProps) { const { data: config } = useSWR("config"); @@ -37,7 +39,10 @@ export default function HistoryCard({ } return ( - + void; +}; + +export default function TimelinePlayerCard({ + timeline, + onDismiss, +}: TimelinePlayerCardProps) { + const { data: config } = useSWR("config"); + const apiHost = useApiHost(); + + const recordingParams = useMemo(() => { + if (!timeline) { + return {}; + } + + return { + before: timeline.entries.at(-1)!!.timestamp + 30, + after: timeline.entries.at(0)!!.timestamp, + }; + }, [timeline]); + const { data: recordings } = useSWR( + timeline ? [`${timeline.camera}/recordings`, recordingParams] : null, + { revalidateOnFocus: false } + ); + + return ( + <> + + + + + {`${timeline?.camera?.replaceAll( + "_", + " " + )} @ ${formatUnixTimestampToDateTime(timeline?.time ?? 0, { + strftime_fmt: + config?.ui?.time_format == "24hour" ? "%H:%M:%S" : "%I:%M:%S", + })}`} + + + {recordings && recordings.length > 0 && ( + + )} + + + + ); +} diff --git a/web-new/src/components/player/PreviewThumbnailPlayer.tsx b/web-new/src/components/player/PreviewThumbnailPlayer.tsx index 725e83376..3c71d73dc 100644 --- a/web-new/src/components/player/PreviewThumbnailPlayer.tsx +++ b/web-new/src/components/player/PreviewThumbnailPlayer.tsx @@ -152,6 +152,10 @@ function isCurrentHour(timestamp: number) { function getPreviewWidth(camera: string, config: FrigateConfig) { const detect = config.cameras[camera].detect; + if (detect.width / detect.height < 1.0) { + return "w-[120px]"; + } + if (detect.width / detect.height < 1.4) { return "w-[208px]"; } diff --git a/web-new/src/pages/History.tsx b/web-new/src/pages/History.tsx index f97072836..07fe83d68 100644 --- a/web-new/src/pages/History.tsx +++ b/web-new/src/pages/History.tsx @@ -7,6 +7,7 @@ import ActivityIndicator from "@/components/ui/activity-indicator"; import HistoryCard from "@/components/card/HistoryCard"; import { formatUnixTimestampToDateTime } from "@/utils/dateUtil"; import axios from "axios"; +import TimelinePlayerCard from "@/components/card/TimelineCardPlayer"; const API_LIMIT = 100; @@ -44,15 +45,17 @@ function History() { isValidating, } = useSWRInfinite(getKey, timelineFetcher); const { data: allPreviews } = useSWR( - `preview/all/start/${(timelinePages ?? [])?.at(0)?.start ?? 0}/end/${ - (timelinePages ?? [])?.at(-1)?.end ?? 0 - }`, + timelinePages + ? `preview/all/start/${timelinePages?.at(0) + ?.start}/end/${timelinePages?.at(-1)?.end}` + : null, { revalidateOnFocus: false } ); const [detailLevel, setDetailLevel] = useState<"normal" | "extra" | "full">( "normal" ); + const [playback, setPlayback] = useState(); const timelineCards: CardsData | never[] = useMemo(() => { if (!timelinePages) { @@ -161,7 +164,7 @@ function History() { [size, setSize, isValidating, isDone] ); - if (!config || !timelineCards ||timelineCards.length == 0) { + if (!config || !timelineCards || timelineCards.length == 0) { return ; } @@ -172,6 +175,11 @@ function History() { Dates and times are based on the timezone {timezone} + setPlayback(undefined)} + /> +
{Object.entries(timelineCards) .reverse() @@ -225,6 +233,9 @@ function History() { timeline={timeline} shouldAutoPlay={shouldAutoPlay} relevantPreview={relevantPreview} + onClick={() => { + setPlayback(timeline); + }} /> ); } diff --git a/web-new/src/types/record.ts b/web-new/src/types/record.ts new file mode 100644 index 000000000..20a98d886 --- /dev/null +++ b/web-new/src/types/record.ts @@ -0,0 +1,11 @@ +type Recording = { + id: string, + camera: string, + start_time: number, + end_time: number, + path: string, + segment_size: number, + motion: number, + objects: number, + dBFS: number, +} \ No newline at end of file