Merge remote-tracking branch 'origin/master' into dev

This commit is contained in:
Blake Blackshear
2025-09-04 06:33:22 -05:00
32 changed files with 587 additions and 448 deletions
+48 -3
View File
@@ -1,5 +1,5 @@
import { CameraConfig, FrigateConfig } from "@/types/frigateConfig";
import { useCallback, useEffect, useState } from "react";
import { useCallback, useEffect, useState, useMemo } from "react";
import useSWR from "swr";
import { LivePlayerMode, LiveStreamMetadata } from "@/types/live";
@@ -8,9 +8,54 @@ export default function useCameraLiveMode(
windowVisible: boolean,
) {
const { data: config } = useSWR<FrigateConfig>("config");
const { data: allStreamMetadata } = useSWR<{
// Get comma-separated list of restreamed stream names for SWR key
const restreamedStreamsKey = useMemo(() => {
if (!cameras || !config) return null;
const streamNames = new Set<string>();
cameras.forEach((camera) => {
const isRestreamed = Object.keys(config.go2rtc.streams || {}).includes(
Object.values(camera.live.streams)[0],
);
if (isRestreamed) {
Object.values(camera.live.streams).forEach((streamName) => {
streamNames.add(streamName);
});
}
});
return streamNames.size > 0
? Array.from(streamNames).sort().join(",")
: null;
}, [cameras, config]);
const streamsFetcher = useCallback(async (key: string) => {
const streamNames = key.split(",");
const metadata: { [key: string]: LiveStreamMetadata } = {};
await Promise.all(
streamNames.map(async (streamName) => {
try {
const response = await fetch(`/api/go2rtc/streams/${streamName}`);
if (response.ok) {
const data = await response.json();
metadata[streamName] = data;
}
} catch (error) {
// eslint-disable-next-line no-console
console.error(`Failed to fetch metadata for ${streamName}:`, error);
}
}),
);
return metadata;
}, []);
const { data: allStreamMetadata = {} } = useSWR<{
[key: string]: LiveStreamMetadata;
}>(config ? "go2rtc/streams" : null, { revalidateOnFocus: false });
}>(restreamedStreamsKey, streamsFetcher, { revalidateOnFocus: false });
const [preferredLiveModes, setPreferredLiveModes] = useState<{
[key: string]: LivePlayerMode;
+3 -3
View File
@@ -17,7 +17,7 @@ export function useVideoDimensions(
});
const videoAspectRatio = useMemo(() => {
return videoResolution.width / videoResolution.height;
return videoResolution.width / videoResolution.height || 16 / 9;
}, [videoResolution]);
const containerAspectRatio = useMemo(() => {
@@ -25,8 +25,8 @@ export function useVideoDimensions(
}, [containerWidth, containerHeight]);
const videoDimensions = useMemo(() => {
if (!containerWidth || !containerHeight || !videoAspectRatio)
return { width: "100%", height: "100%" };
if (!containerWidth || !containerHeight)
return { aspectRatio: "16 / 9", width: "100%" };
if (containerAspectRatio > videoAspectRatio) {
const height = containerHeight;
const width = height * videoAspectRatio;