fix open recordings from host

This commit is contained in:
NlightN22 2024-05-03 14:39:29 +07:00
parent 2f72689f4e
commit 9472c5224c
10 changed files with 103 additions and 45 deletions

View File

@ -101,7 +101,7 @@ export const proxyApi = {
) =>
instanceApi.get<RecordSummary[]>(`proxy/${hostName}/api/${cameraName}/recordings/summary`, {
params: { timezone },
timeout: 5 * 60 * 1000
timeout: 5 * 60 * 1000,
}).then(res => res.data),
// E.g. http://127.0.0.1:5000/api/events?before=1708534799&after=1708448400&camera=CameraName&has_clip=1&include_thumbnails=0&limit=5000
@ -130,7 +130,8 @@ export const proxyApi = {
limit: limit,
min_score: minScore,
max_score: maxScore,
}
},
timeout: 5 * 60 * 1000,
}).then(res => res.data),
getEventsSummary: (hostName: string, cameraName: string) =>

View File

@ -18,7 +18,7 @@ interface CameraAccordionProps {
const CameraAccordion = ({
camera
} : CameraAccordionProps ) => {
}: CameraAccordionProps) => {
const { t } = useTranslation()
const { recordingsStore: recStore } = useContext(Context)
@ -35,14 +35,22 @@ const CameraAccordion = ({
}
})
const recodItem = (record: RecordSummary) => (
<Accordion.Item key={record.day} value={record.day}>
<Accordion.Control key={record.day + 'control'}>{t('day')}: {record.day}</Accordion.Control>
<Accordion.Panel key={record.day + 'panel'}>
<DayAccordion key={record.day + 'day'} recordSummary={record} />
</Accordion.Panel>
</Accordion.Item>
)
const recodItem = (record: RecordSummary) => {
if (host) {
return (
<Accordion.Item key={record.day} value={record.day}>
<Accordion.Control key={record.day + 'control'}>{t('day')}: {record.day}</Accordion.Control>
<Accordion.Panel key={record.day + 'panel'}>
<DayAccordion
host={host}
camera={camera}
key={record.day + 'day'}
recordSummary={record} />
</Accordion.Panel>
</Accordion.Item>
)
}
}
const days = useMemo(() => {
if (recordings && camera) {

View File

@ -6,21 +6,25 @@ import { mapHostToHostname } from '../../../services/frigate.proxy/frigate.api';
import { RecordSummary } from '../../../types/record';
import { isProduction } from '../../env.const';
import DayAccordionItem from './DayAccordionItem';
import { GetCameraWHostWConfig, GetFrigateHost } from '../../../services/frigate.proxy/frigate.schema';
interface RecordingAccordionProps {
recordSummary?: RecordSummary,
recordSummary?: RecordSummary
host: GetFrigateHost
camera: GetCameraWHostWConfig
}
const DayAccordionItemMemo = React.memo(DayAccordionItem)
const DayAccordion = ({
recordSummary,
host,
camera
}: RecordingAccordionProps) => {
const { recordingsStore: recStore } = useContext(Context)
const [openedValue, setOpenedValue] = useState<string>()
const camera = recStore.filteredCamera
const hostName = mapHostToHostname(recStore.filteredHost)
const hostName = mapHostToHostname(host)
const handleOpenPlayer = useCallback((value?: string) => {
if (recStore.playedItem !== value) {
@ -32,11 +36,13 @@ const DayAccordion = ({
}, [openedValue, recStore]);
const dayItems = useMemo(() => {
if (recordSummary && recordSummary.hours.length > 0) {
if (recordSummary && recordSummary.hours.length > 0 && hostName && host) {
return recordSummary.hours.map(hour => {
const played = recordSummary.day + hour.hour === recStore.playedItem;
return (
<DayAccordionItemMemo
camera={camera}
host={host}
key={recordSummary.day + hour.hour}
recordSummary={recordSummary}
recordHour={hour}

View File

@ -12,14 +12,17 @@ import AccordionControlButton from '../buttons/AccordionControlButton';
import AccordionShareButton from '../buttons/AccordionShareButton';
import PlayControl from '../buttons/PlayControl';
import DayPanel from './DayPanel';
import { GetCameraWHostWConfig, GetFrigateHost } from '../../../services/frigate.proxy/frigate.schema';
interface DayAccordionItemProps {
recordSummary: RecordSummary,
recordHour: RecordHour,
hostName?: string,
cameraName?: string,
hostName: string,
cameraName: string,
played?: boolean,
openPlayer?: (value?: string) => void,
camera: GetCameraWHostWConfig
host: GetFrigateHost
}
const DayAccordionItem = ({
@ -28,7 +31,9 @@ const DayAccordionItem = ({
hostName,
cameraName,
played,
openPlayer
openPlayer,
camera,
host
}: DayAccordionItemProps) => {
const { t } = useTranslation()
const navigate = useNavigate()
@ -92,6 +97,8 @@ const DayAccordionItem = ({
</Flex>
</Accordion.Control>
<DayPanel
camera={camera}
host={host}
day={recordSummary.day}
hour={hour}
events={recordHour.events}

View File

@ -1,18 +1,23 @@
import { Accordion, Text } from '@mantine/core';
import { Suspense, lazy, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { GetCameraWHostWConfig, GetFrigateHost } from '../../../services/frigate.proxy/frigate.schema';
const EventsAccordion = lazy(() => import('./EventsAccordion'))
interface DayEventsAccordionProps {
day: string,
hour: string,
qty?: number,
camera: GetCameraWHostWConfig
host: GetFrigateHost
}
const DayEventsAccordion = ({
day,
hour,
qty,
camera,
host,
}: DayEventsAccordionProps) => {
const { t } = useTranslation()
const [openedItem, setOpenedItem] = useState<string>()
@ -27,7 +32,11 @@ const DayEventsAccordion = ({
<Accordion.Panel>
{openedItem === hour ?
<Suspense>
<EventsAccordion day={day} hour={hour} />
<EventsAccordion
camera={camera}
host={host}
day={day}
hour={hour} />
</Suspense>
: <></>
}

View File

@ -3,6 +3,7 @@ import VideoDownloader from '../../../widgets/VideoDownloader';
import VideoPlayer from '../players/VideoPlayer';
import DayEventsAccordion from './DayEventsAccordion';
import { useTranslation } from 'react-i18next';
import { GetCameraWHostWConfig, GetFrigateHost } from '../../../services/frigate.proxy/frigate.schema';
interface DayPanelProps {
day: string,
@ -14,6 +15,8 @@ interface DayPanelProps {
playedURL?: string,
startUnixTime: number,
endUnixTime: number,
camera: GetCameraWHostWConfig
host: GetFrigateHost
}
const DayPanel = ({
@ -26,6 +29,8 @@ const DayPanel = ({
playedURL,
startUnixTime,
endUnixTime,
camera,
host
}: DayPanelProps) => {
const { t } = useTranslation()
return (
@ -42,7 +47,12 @@ const DayPanel = ({
</Flex>
: ''}
{events > 0 ?
<DayEventsAccordion day={day} hour={hour} qty={events} />
<DayEventsAccordion
camera={camera}
host={host}
day={day}
hour={hour}
qty={events} />
:
<Center><Text>{t('notHaveEvents')}</Text></Center>
}

View File

@ -1,4 +1,4 @@
import { Button, Flex, Text } from '@mantine/core';
import { Button, Flex, Group, Text } from '@mantine/core';
import { IconExternalLink } from '@tabler/icons-react';
import { proxyApi } from '../../../services/frigate.proxy/frigate.api';
import { EventFrigate } from '../../../types/event';
@ -26,12 +26,23 @@ const EventPanel = ({
<>
{playedURL && playedURL === videoURL ? <VideoPlayer videoUrl={playedURL} /> : <></>}
<Flex w='100%' justify='space-between'>
{!hostName ? <></> :
<BlobImage
maw={200}
fit="contain"
withPlaceholder
src={proxyApi.eventThumbnailUrl(hostName, event.id)} />
<Group spacing='xs'>
<Text fw={700}>{t('camera')}:</Text>
<Text>{event.camera}</Text>
</Group>
<Group>
<Text fw={700}>{t('player.startTime')}:</Text>
<Text>{unixTimeToDate(event.start_time)}</Text>
</Group>
<Group>
<Text fw={700}>{t('player.duration')}:</Text>
<Text>{getDurationFromTimestamps(event.start_time, event.end_time)}</Text>
</Group>
{!event.data?.score ? <></> :
<Group>
<Text fw={700}>{t('player.rating')}:</Text>
<Text>{(event.data.score * 100).toFixed(2)}%</Text>
</Group>
}
<Flex direction='column' align='end' justify='center'>
{!hostName ? '' :
@ -46,13 +57,6 @@ const EventPanel = ({
</Button>
</Flex>
}
<Text mt='1rem'>{t('camera')}: {event.camera}</Text>
<Text>{t('player.object')}: {event.label}</Text>
<Text>{t('player.startTime')}: {unixTimeToDate(event.start_time)}</Text>
<Text>{t('player.duration')}: {getDurationFromTimestamps(event.start_time, event.end_time)}</Text>
{!event.data?.score? <></> :
<Text>{t('player.rating')}: {(event.data.score * 100).toFixed(2)}%</Text>
}
</Flex>
</Flex>
</>

View File

@ -4,7 +4,7 @@ import { observer } from 'mobx-react-lite';
import { useContext, useState } from 'react';
import { Context } from '../../..';
import { frigateQueryKeys, mapHostToHostname, proxyApi } from '../../../services/frigate.proxy/frigate.api';
import { getEventsQuerySchema } from '../../../services/frigate.proxy/frigate.schema';
import { GetCameraWHostWConfig, GetFrigateHost, getEventsQuerySchema } from '../../../services/frigate.proxy/frigate.schema';
import { getUnixTime } from '../../utils/dateUtil';
import RetryError from '../RetryError';
import EventsAccordionItem from './EventsAccordionItem';
@ -16,10 +16,10 @@ import EventsAccordionItem from './EventsAccordionItem';
* @param hostName proxy format, e.g hostName: localhost:4000
*/
interface EventsAccordionProps {
day?: string,
hour?: string,
cameraName?: string
hostName?: string
day: string,
hour: string,
camera: GetCameraWHostWConfig
host: GetFrigateHost
}
/**
@ -31,13 +31,13 @@ interface EventsAccordionProps {
const EventsAccordion = ({
day,
hour,
camera,
host,
}: EventsAccordionProps) => {
const { recordingsStore: recStore } = useContext(Context)
const [openedItem, setOpenedItem] = useState<string>()
const host = recStore.filteredHost
const hostName = mapHostToHostname(host)
const camera = recStore.filteredCamera
const isRequiredParams = host && camera
const { data, isPending, isError, refetch } = useQuery({

View File

@ -11,6 +11,7 @@ import { useNavigate } from 'react-router-dom';
import { routesPath } from '../../../router/routes.path';
import { proxyApi } from '../../../services/frigate.proxy/frigate.api';
import { useTranslation } from 'react-i18next';
import BlobImage from '../images/BlobImage';
interface EventsAccordionItemProps {
@ -44,7 +45,8 @@ const EventsAccordionItem = ({
const duration = getDurationFromTimestamps(event.start_time, event.end_time)
return (
<Group>
<Text>{t('player.object')}: {event.label}</Text>
<Text fw={700}>{t('player.object')}:</Text>
<Text >{event.label}</Text>
<Text>{time}</Text>
{duration ?
<Text>{duration}</Text>
@ -77,6 +79,14 @@ const EventsAccordionItem = ({
<Accordion.Item key={event.id + 'Item'} value={event.id}>
<Accordion.Control key={event.id + 'Control'}>
<Flex justify='space-between'>
{!hostName ? <></> :
<BlobImage
maw={200}
mr='1rem'
fit="contain"
withPlaceholder
src={proxyApi.eventThumbnailUrl(hostName, event.id)} />
}
{eventLabel(event)}
<Group>
<AccordionShareButton recordUrl={eventVideoURL} />

View File

@ -26,7 +26,7 @@ const SelectedDayList = ({
queryFn: async () => {
if (camera && host) {
const hostName = mapHostToHostname(host)
if (hostName){
if (hostName) {
return proxyApi.getRecordingsSummary(hostName, camera.name, getResolvedTimeZone())
}
}
@ -44,14 +44,17 @@ const SelectedDayList = ({
if (!data) return <Text>Not have response from server</Text>
const stringDay = dateToQueryString(day)
const recordingsDay = data.find(record => record.day === stringDay)
const recordingsDay = data.find(record => record.day === stringDay)
if (!recordingsDay) return <Center><Text>Not have record at {stringDay}</Text></Center>
if (!isProduction) console.log('SelectedDayList rendered')
return (
<Flex w='100%' h='100%' direction='column' align='center'>
<Text>{host.name} / {camera.name} / {stringDay}</Text>
<DayAccordion recordSummary={recordingsDay} />
<DayAccordion
host={host}
camera={camera}
recordSummary={recordingsDay} />
</Flex>
);
};