import { h, Fragment, render } from 'preact'; import AutoUpdatingCameraImage from '../components/AutoUpdatingCameraImage'; import JSMpegPlayer from '../components/JSMpegPlayer'; import Heading from '../components/Heading'; import Link from '../components/Link'; import Switch from '../components/Switch'; import { usePersistence } from '../context'; import { useCallback, useEffect, useMemo, useRef, useState } from 'preact/hooks'; import { useApiHost, useConfig, useEvents } from '../api'; import { Tabs, TextTab } from '../components/Tabs'; import Timeline from '../components/Timeline'; import { LiveChip } from '../components/LiveChip'; import { HistoryHeader } from './HistoryHeader'; import { longToDate } from '../utils/dateUtil'; import { useSearchString } from '../hooks/useSearchString'; import { Previous } from '../icons/Previous'; import { Play } from '../icons/Play'; import { Next } from '../icons/Next'; const emptyObject = Object.freeze({}); export default function Camera({ camera }) { const apiHost = useApiHost(); const videoRef = useRef(); const { data: config } = useConfig(); const beginningOfDay = new Date().setHours(0, 0, 0) / 1000; const { searchString } = useSearchString(200, `camera=${camera}&after=${beginningOfDay}`); const { data: events } = useEvents(searchString); const [timelineEvents, setTimelineEvents] = useState(); const [hideBanner, setHideBanner] = useState(false); const [playerType, setPlayerType] = useState('live'); const cameraConfig = config?.cameras[camera]; const liveWidth = Math.round(cameraConfig.live.height * (cameraConfig.detect.width / cameraConfig.detect.height)); const [options, setOptions] = usePersistence(`${camera}-feed`, emptyObject); const [currentEvent, setCurrentEvent] = useState(); const [currentEventIndex, setCurrentEventIndex] = useState(); const [timelineOffset, setTimelineOffset] = useState(0); useEffect(() => { if (events) { setTimelineEvents([...events].reverse().filter((e) => e.end_time !== undefined)); } }, [events]); const handleSetOption = useCallback( (id, value) => { const newOptions = { ...options, [id]: value }; setOptions(newOptions); }, [options, setOptions] ); const searchParams = useMemo( () => new URLSearchParams( Object.keys(options).reduce((memo, key) => { memo.push([key, options[key] === true ? '1' : '0']); return memo; }, []) ), [options] ); const optionContent = (
Mask & Zone creator
); let renderPlayer; switch (playerType) { case 'live': renderPlayer = (
); break; case 'history': if (currentEvent) { renderPlayer = ( ); } break; case 'debug': renderPlayer = (
{optionContent}
); break; default: break; } const handleTimeUpdate = () => { const timestamp = Math.round(videoRef.current.currentTime); const offset = Math.round(timestamp); const triggerStateChange = offset !== timelineOffset; if (triggerStateChange) { setTimelineOffset(offset); } }; const handleVideoTouch = () => { setHideBanner(true); }; const handleTabChange = (index) => { if (index === 0) { setPlayerType('history'); } else if (index === 1) { setPlayerType('live'); } else if (index === 2) { setPlayerType('debug'); } }; const handleTimelineChange = (event) => { if (event !== undefined) { setCurrentEvent(event); setCurrentEventIndex(event.index); } }; const handlePlay = function () { videoRef.current.play(); }; const handlePaused = () => { setTimelineOffset(undefined); }; const handlePrevious = function () { setCurrentEventIndex((index) => index - 1); }; const handleNext = function () { setCurrentEventIndex((index) => index + 1); }; return (
{(playerType === 'live' || playerType === 'debug') && ( {camera} )}
{currentEvent && ( )} {renderPlayer}
{playerType === 'history' && (
)}
); }