mirror of
https://github.com/blakeblackshear/frigate.git
synced 2024-11-21 19:07:46 +01:00
parent
8cddfc27fb
commit
5c609c7051
@ -28,8 +28,6 @@ function MSEPlayer({
|
||||
onPlaying,
|
||||
setFullResolution,
|
||||
}: MSEPlayerProps) {
|
||||
let connectTS: number = 0;
|
||||
|
||||
const RECONNECT_TIMEOUT: number = 30000;
|
||||
|
||||
const CODECS: string[] = [
|
||||
@ -46,6 +44,7 @@ function MSEPlayer({
|
||||
const visibilityCheck: boolean = !pip;
|
||||
|
||||
const [wsState, setWsState] = useState<number>(WebSocket.CLOSED);
|
||||
const [connectTS, setConnectTS] = useState<number>(0);
|
||||
|
||||
const videoRef = useRef<HTMLVideoElement>(null);
|
||||
const wsRef = useRef<WebSocket | null>(null);
|
||||
@ -103,14 +102,14 @@ function MSEPlayer({
|
||||
|
||||
setWsState(WebSocket.CONNECTING);
|
||||
|
||||
// TODO may need to check this later
|
||||
// eslint-disable-next-line
|
||||
connectTS = Date.now();
|
||||
setConnectTS(Date.now());
|
||||
|
||||
wsRef.current = new WebSocket(wsURL);
|
||||
wsRef.current.binaryType = "arraybuffer";
|
||||
wsRef.current.addEventListener("open", () => onOpen());
|
||||
wsRef.current.addEventListener("close", () => onClose());
|
||||
wsRef.current.addEventListener("open", onOpen);
|
||||
wsRef.current.addEventListener("close", onClose);
|
||||
// we know that these deps are correct
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [wsURL]);
|
||||
|
||||
const onDisconnect = useCallback(() => {
|
||||
@ -121,7 +120,7 @@ function MSEPlayer({
|
||||
}
|
||||
}, []);
|
||||
|
||||
const onOpen = useCallback(() => {
|
||||
const onOpen = () => {
|
||||
setWsState(WebSocket.OPEN);
|
||||
|
||||
wsRef.current?.addEventListener("message", (ev) => {
|
||||
@ -139,23 +138,25 @@ function MSEPlayer({
|
||||
onmessageRef.current = {};
|
||||
|
||||
onMse();
|
||||
// only run once
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
const onClose = useCallback(() => {
|
||||
if (wsState === WebSocket.CLOSED) return;
|
||||
};
|
||||
|
||||
const reconnect = (timeout?: number) => {
|
||||
setWsState(WebSocket.CONNECTING);
|
||||
wsRef.current = null;
|
||||
|
||||
const delay = Math.max(RECONNECT_TIMEOUT - (Date.now() - connectTS), 0);
|
||||
const delay =
|
||||
timeout ?? Math.max(RECONNECT_TIMEOUT - (Date.now() - connectTS), 0);
|
||||
|
||||
reconnectTIDRef.current = window.setTimeout(() => {
|
||||
reconnectTIDRef.current = null;
|
||||
onConnect();
|
||||
}, delay);
|
||||
}, [wsState, connectTS, onConnect]);
|
||||
};
|
||||
|
||||
const onClose = () => {
|
||||
if (wsState === WebSocket.CLOSED) return;
|
||||
reconnect();
|
||||
};
|
||||
|
||||
const onMse = () => {
|
||||
if ("ManagedMediaSource" in window) {
|
||||
@ -305,7 +306,13 @@ function MSEPlayer({
|
||||
onLoadedData={onPlaying}
|
||||
onLoadedMetadata={handleLoadedMetadata}
|
||||
muted={!audioEnabled}
|
||||
onError={onClose}
|
||||
onError={() => {
|
||||
if (wsRef.current) {
|
||||
wsRef.current.close();
|
||||
wsRef.current = null;
|
||||
reconnect(5000);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
@ -42,7 +42,7 @@ export default function MotionTuner({
|
||||
const [changedValue, setChangedValue] = useState(false);
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
|
||||
const { addMessage, clearMessages } = useContext(StatusBarMessagesContext)!;
|
||||
const { addMessage, removeMessage } = useContext(StatusBarMessagesContext)!;
|
||||
|
||||
const { send: sendMotionThreshold } = useMotionThreshold(selectedCamera);
|
||||
const { send: sendMotionContourArea } = useMotionContourArea(selectedCamera);
|
||||
@ -148,21 +148,23 @@ export default function MotionTuner({
|
||||
const onCancel = useCallback(() => {
|
||||
setMotionSettings(origMotionSettings);
|
||||
setChangedValue(false);
|
||||
clearMessages("motion_tuner");
|
||||
}, [origMotionSettings, clearMessages]);
|
||||
removeMessage("motion_tuner", `motion_tuner_${selectedCamera}`);
|
||||
}, [origMotionSettings, removeMessage, selectedCamera]);
|
||||
|
||||
useEffect(() => {
|
||||
if (changedValue) {
|
||||
addMessage(
|
||||
"motion_tuner",
|
||||
"Unsaved motion tuner changes",
|
||||
`Unsaved motion tuner changes (${selectedCamera})`,
|
||||
undefined,
|
||||
"motion_tuner",
|
||||
`motion_tuner_${selectedCamera}`,
|
||||
);
|
||||
} else {
|
||||
clearMessages("motion_tuner");
|
||||
removeMessage("motion_tuner", `motion_tuner_${selectedCamera}`);
|
||||
}
|
||||
}, [changedValue, addMessage, clearMessages]);
|
||||
// we know that these deps are correct
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [changedValue, selectedCamera]);
|
||||
|
||||
useEffect(() => {
|
||||
document.title = "Motion Tuner - Frigate";
|
||||
|
@ -26,7 +26,7 @@ import {
|
||||
toRGBColorString,
|
||||
} from "@/utils/canvasUtil";
|
||||
import { Polygon, PolygonType } from "@/types/canvas";
|
||||
import { useCallback, useMemo, useState } from "react";
|
||||
import { useCallback, useContext, useMemo, useState } from "react";
|
||||
import axios from "axios";
|
||||
import { Toaster } from "@/components/ui/sonner";
|
||||
import { toast } from "sonner";
|
||||
@ -34,6 +34,7 @@ import useSWR from "swr";
|
||||
import { FrigateConfig } from "@/types/frigateConfig";
|
||||
import { reviewQueries } from "@/utils/zoneEdutUtil";
|
||||
import IconWrapper from "../ui/icon-wrapper";
|
||||
import { StatusBarMessagesContext } from "@/context/statusbar-provider";
|
||||
|
||||
type PolygonItemProps = {
|
||||
polygon: Polygon;
|
||||
@ -57,6 +58,7 @@ export default function PolygonItem({
|
||||
const { data: config, mutate: updateConfig } =
|
||||
useSWR<FrigateConfig>("config");
|
||||
const [deleteDialogOpen, setDeleteDialogOpen] = useState(false);
|
||||
const { addMessage } = useContext(StatusBarMessagesContext)!;
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
|
||||
const cameraConfig = useMemo(() => {
|
||||
@ -198,6 +200,12 @@ export default function PolygonItem({
|
||||
const handleDelete = () => {
|
||||
setActivePolygonIndex(undefined);
|
||||
saveToConfig(polygon);
|
||||
addMessage(
|
||||
"masks_zones",
|
||||
"Restart required (masks/zones changed)",
|
||||
undefined,
|
||||
"masks_zones",
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
|
@ -29,7 +29,7 @@ type StatusBarMessagesContextValue = {
|
||||
color?: string,
|
||||
messageId?: string,
|
||||
link?: string,
|
||||
) => string;
|
||||
) => string | undefined;
|
||||
removeMessage: (key: string, messageId: string) => void;
|
||||
clearMessages: (key: string) => void;
|
||||
};
|
||||
@ -52,26 +52,51 @@ export function StatusBarMessagesProvider({
|
||||
messageId?: string,
|
||||
link?: string,
|
||||
) => {
|
||||
const id = messageId || Date.now().toString();
|
||||
const msgColor = color || "text-danger";
|
||||
setMessagesState((prevMessages) => ({
|
||||
if (!key || !message) return;
|
||||
|
||||
const id = messageId ?? Date.now().toString();
|
||||
const msgColor = color ?? "text-danger";
|
||||
|
||||
setMessagesState((prevMessages) => {
|
||||
const existingMessages = prevMessages[key] || [];
|
||||
// Check if a message with the same ID already exists
|
||||
const messageIndex = existingMessages.findIndex((msg) => msg.id === id);
|
||||
|
||||
const newMessage = { id, text: message, color: msgColor, link };
|
||||
|
||||
// If the message exists, replace it, otherwise add the new message
|
||||
let updatedMessages;
|
||||
if (messageIndex > -1) {
|
||||
updatedMessages = [
|
||||
...existingMessages.slice(0, messageIndex),
|
||||
newMessage,
|
||||
...existingMessages.slice(messageIndex + 1),
|
||||
];
|
||||
} else {
|
||||
updatedMessages = [...existingMessages, newMessage];
|
||||
}
|
||||
|
||||
return {
|
||||
...prevMessages,
|
||||
[key]: [
|
||||
...(prevMessages[key] || []),
|
||||
{ id, text: message, color: msgColor, link },
|
||||
],
|
||||
}));
|
||||
[key]: updatedMessages,
|
||||
};
|
||||
});
|
||||
|
||||
return id;
|
||||
},
|
||||
[],
|
||||
);
|
||||
|
||||
const removeMessage = useCallback((key: string, messageId: string) => {
|
||||
const removeMessage = useCallback(
|
||||
(key: string, messageId: string) => {
|
||||
if (!messages || !key || !messages[key]) return;
|
||||
setMessagesState((prevMessages) => ({
|
||||
...prevMessages,
|
||||
[key]: prevMessages[key].filter((msg) => msg.id !== messageId),
|
||||
}));
|
||||
}, []);
|
||||
},
|
||||
[messages],
|
||||
);
|
||||
|
||||
const clearMessages = useCallback((key: string) => {
|
||||
setMessagesState((prevMessages) => {
|
||||
|
Loading…
Reference in New Issue
Block a user