import { useState, useCallback, useEffect, useMemo } from "react"; import { IoIosWarning } from "react-icons/io"; import { Button } from "@/components/ui/button"; import { DialogContent, DialogHeader, DialogTitle, DialogDescription, } from "@/components/ui/dialog"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@/components/ui/select"; import { Popover, PopoverContent, PopoverTrigger, } from "@/components/ui/popover"; import { Checkbox } from "@/components/ui/checkbox"; import { Label } from "@/components/ui/label"; import { FrigateConfig, GroupStreamingSettings, StreamType, } from "@/types/frigateConfig"; import ActivityIndicator from "../indicators/activity-indicator"; import useSWR from "swr"; import { LuCheck, LuExternalLink, LuInfo, LuX } from "react-icons/lu"; import { Link } from "react-router-dom"; import { LiveStreamMetadata } from "@/types/live"; import { Trans, useTranslation } from "react-i18next"; type CameraStreamingDialogProps = { camera: string; groupStreamingSettings: GroupStreamingSettings; setGroupStreamingSettings: React.Dispatch< React.SetStateAction >; setIsDialogOpen: React.Dispatch>; onSave?: (settings: GroupStreamingSettings) => void; }; export function CameraStreamingDialog({ camera, groupStreamingSettings, setGroupStreamingSettings, setIsDialogOpen, onSave, }: CameraStreamingDialogProps) { const { t } = useTranslation(["components/camera"]); const { data: config } = useSWR("config"); const [isLoading, setIsLoading] = useState(false); const [streamName, setStreamName] = useState( Object.entries(config?.cameras[camera]?.live?.streams || {})[0]?.[1] || "", ); const [streamType, setStreamType] = useState("smart"); const [compatibilityMode, setCompatibilityMode] = useState(false); // metadata const isRestreamed = useMemo( () => config && Object.keys(config.go2rtc.streams || {}).includes(streamName ?? ""), [config, streamName], ); const { data: cameraMetadata } = useSWR( isRestreamed ? `go2rtc/streams/${streamName}` : null, { revalidateOnFocus: false, }, ); const supportsAudioOutput = useMemo(() => { if (!cameraMetadata) { return false; } return ( cameraMetadata.producers.find( (prod) => prod.medias && prod.medias.find((media) => media.includes("audio, recvonly")) != undefined, ) != undefined ); }, [cameraMetadata]); // handlers useEffect(() => { if (!config) { return; } if (groupStreamingSettings && groupStreamingSettings[camera]) { const cameraSettings = groupStreamingSettings[camera]; setStreamName(cameraSettings.streamName || ""); setStreamType(cameraSettings.streamType || "smart"); setCompatibilityMode(cameraSettings.compatibilityMode || false); } else { setStreamName( Object.entries(config?.cameras[camera]?.live?.streams || {})[0]?.[1] || "", ); setStreamType("smart"); setCompatibilityMode(false); } }, [groupStreamingSettings, camera, config]); const handleSave = useCallback(() => { setIsLoading(true); const updatedSettings = { ...groupStreamingSettings, [camera]: { streamName, streamType, compatibilityMode, playAudio: groupStreamingSettings?.[camera]?.playAudio ?? false, volume: groupStreamingSettings?.[camera]?.volume ?? 1, }, }; setGroupStreamingSettings(updatedSettings); setIsDialogOpen(false); setIsLoading(false); onSave?.(updatedSettings); }, [ groupStreamingSettings, setGroupStreamingSettings, camera, streamName, streamType, compatibilityMode, setIsDialogOpen, onSave, ]); const handleCancel = useCallback(() => { if (!config) { return; } if (groupStreamingSettings && groupStreamingSettings[camera]) { const cameraSettings = groupStreamingSettings[camera]; setStreamName(cameraSettings.streamName || ""); setStreamType(cameraSettings.streamType || "smart"); setCompatibilityMode(cameraSettings.compatibilityMode || false); } else { setStreamName( Object.entries(config?.cameras[camera]?.live?.streams || {})[0]?.[1] || "", ); setStreamType("smart"); setCompatibilityMode(false); } setIsDialogOpen(false); }, [groupStreamingSettings, camera, config, setIsDialogOpen]); if (!config) { return null; } return ( {t("group.camera.setting.title", { cameraName: camera.replaceAll("_", " "), })} group.camera.setting.desc
{!isRestreamed && (
{t("streaming.restreaming.disabled", { ns: "components/dialog", })}
{t("button.info", { ns: "common" })}
{t("streaming.restreaming.desc", { ns: "components/dialog" })}
{t("streaming.restreaming.readTheDocumentation", { ns: "components/dialog", })}
)} {isRestreamed && Object.entries(config?.cameras[camera].live.streams).length > 0 && (
)}
{streamType === "no-streaming" && (

{t("group.camera.setting.streamMethod.method.noStreaming.desc")}

)} {streamType === "smart" && (

{t( "group.camera.setting.streamMethod.method.smartStreaming.desc", )}

)} {streamType === "continuous" && ( <>

{t( "group.camera.setting.streamMethod.method.continuousStreaming.desc", )}

{t( "group.camera.setting.streamMethod.method.continuousStreaming.desc.warning", )}
)}
setCompatibilityMode(!compatibilityMode)} />

{t("group.camera.setting.compatibilityMode.desc")}

); }