forked from Github/frigate
Streamline live view (#9772)
* Break out live page * Improving layouts and add chip component * Improve default camera player sizing * Improve live updating * Cleanup and fit figma * Use fixed height * Masonry layout * Fix stuff * Don't force heights * Adjust scaling * Cleanup * remove sidebar (#9731) * remove sidebar * keep sidebar on mobile for now and add icons * Fix revalidation * Cleanup * Cleanup width * Add chips for activity on cameras * Remove dashboard from header * Use Inter font (#9735) * Show still image when no activity is occurring * remove unused search params * add playing check for webrtc * Don't use grid at all for single column * Fix height on mobile * a few style updates to better match figma (#9745) * Remove active objects when they become stationary * Move to sidebar only and make settings separate component * Fix layout * Animate visibility of chips * Sidebar is full screen * Fix tall aspect ratio cameras * Fix complicated aspect logic * remove * Adjust thumbnail aspect and add text * margin on single column layout * Smaller event thumb text * Simplify basic image view * Only show the red dot when camera is recording * Improve typing for camera toggles * animate chips with react-transition-group (#9763) * don't flash when going to still image * revalidate * tooltips and active tracking outline (#9766) * tooltips * fix tooltip provider and add active tracking outline * remove unused icon * remove figma comment * Get live mode working for jsmpeg * add small gradient below timeago on event thumbnails (#9767) * Create live mode hook and make sure jsmpeg can be used * Enforce env var * Use print * Remove unstable * Add tooltips to thumbnails * Put back vite * Format * Update web/src/components/player/JSMpegPlayer.tsx --------- Co-authored-by: Josh Hawkins <32435876+hawkeye217@users.noreply.github.com> Co-authored-by: Blake Blackshear <blake@frigate.video>
This commit is contained in:
68
web/src/hooks/use-camera-activity.ts
Normal file
68
web/src/hooks/use-camera-activity.ts
Normal file
@@ -0,0 +1,68 @@
|
||||
import {
|
||||
useAudioActivity,
|
||||
useFrigateEvents,
|
||||
useMotionActivity,
|
||||
} from "@/api/ws";
|
||||
import { CameraConfig } from "@/types/frigateConfig";
|
||||
import { useEffect, useMemo, useState } from "react";
|
||||
|
||||
type useCameraActivityReturn = {
|
||||
activeTracking: boolean;
|
||||
activeMotion: boolean;
|
||||
activeAudio: boolean;
|
||||
};
|
||||
|
||||
export default function useCameraActivity(
|
||||
camera: CameraConfig
|
||||
): useCameraActivityReturn {
|
||||
const [activeObjects, setActiveObjects] = useState<string[]>([]);
|
||||
const hasActiveObjects = useMemo(
|
||||
() => activeObjects.length > 0,
|
||||
[activeObjects]
|
||||
);
|
||||
|
||||
const { payload: detectingMotion } = useMotionActivity(camera.name);
|
||||
const { payload: event } = useFrigateEvents();
|
||||
const { payload: audioRms } = useAudioActivity(camera.name);
|
||||
|
||||
useEffect(() => {
|
||||
if (!event) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.after.camera != camera.name) {
|
||||
return;
|
||||
}
|
||||
|
||||
const eventIndex = activeObjects.indexOf(event.after.id);
|
||||
|
||||
if (event.type == "end") {
|
||||
if (eventIndex != -1) {
|
||||
const newActiveObjects = [...activeObjects];
|
||||
newActiveObjects.splice(eventIndex, 1);
|
||||
setActiveObjects(newActiveObjects);
|
||||
}
|
||||
} else {
|
||||
if (eventIndex == -1) {
|
||||
// add unknown event to list if not stationary
|
||||
if (!event.after.stationary) {
|
||||
const newActiveObjects = [...activeObjects, event.after.id];
|
||||
setActiveObjects(newActiveObjects);
|
||||
}
|
||||
} else {
|
||||
// remove known event from list if it has become stationary
|
||||
if (event.after.stationary) {
|
||||
activeObjects.splice(eventIndex, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}, [event, activeObjects]);
|
||||
|
||||
return {
|
||||
activeTracking: hasActiveObjects,
|
||||
activeMotion: detectingMotion == "ON",
|
||||
activeAudio: camera.audio.enabled_in_config
|
||||
? audioRms >= camera.audio.min_volume
|
||||
: false,
|
||||
};
|
||||
}
|
||||
49
web/src/hooks/use-camera-live-mode.ts
Normal file
49
web/src/hooks/use-camera-live-mode.ts
Normal file
@@ -0,0 +1,49 @@
|
||||
import { CameraConfig, FrigateConfig } from "@/types/frigateConfig";
|
||||
import { useMemo } from "react";
|
||||
import useSWR from "swr";
|
||||
import { usePersistence } from "./use-persistence";
|
||||
import { LivePlayerMode } from "@/types/live";
|
||||
|
||||
export default function useCameraLiveMode(
|
||||
cameraConfig: CameraConfig,
|
||||
preferredMode?: string
|
||||
): LivePlayerMode {
|
||||
const { data: config } = useSWR<FrigateConfig>("config");
|
||||
|
||||
const restreamEnabled = useMemo(() => {
|
||||
if (!config) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (
|
||||
cameraConfig &&
|
||||
Object.keys(config.go2rtc.streams || {}).includes(
|
||||
cameraConfig.live.stream_name
|
||||
)
|
||||
);
|
||||
}, [config, cameraConfig]);
|
||||
const defaultLiveMode = useMemo(() => {
|
||||
if (config && cameraConfig) {
|
||||
if (restreamEnabled) {
|
||||
return cameraConfig.ui.live_mode || config?.ui.live_mode;
|
||||
}
|
||||
|
||||
return "jsmpeg";
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}, [cameraConfig, restreamEnabled]);
|
||||
const [viewSource] = usePersistence(
|
||||
`${cameraConfig.name}-source`,
|
||||
defaultLiveMode
|
||||
);
|
||||
|
||||
if (
|
||||
restreamEnabled &&
|
||||
(preferredMode == "mse" || preferredMode == "webrtc")
|
||||
) {
|
||||
return preferredMode;
|
||||
} else {
|
||||
return viewSource;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user