mirror of
				https://github.com/blakeblackshear/frigate.git
				synced 2025-10-27 10:52:11 +01:00 
			
		
		
		
	Various bugfixes and improvements (#11624)
* various bugfixes and improvements * add separator * no separator
This commit is contained in:
		
							parent
							
								
									3dd401f57a
								
							
						
					
					
						commit
						f1c0422d5e
					
				@ -131,13 +131,16 @@ export default function MotionMaskEditPane({
 | 
			
		||||
 | 
			
		||||
    axios
 | 
			
		||||
      .put(`config/set?${queryString}`, {
 | 
			
		||||
        requires_restart: 1,
 | 
			
		||||
        requires_restart: 0,
 | 
			
		||||
      })
 | 
			
		||||
      .then((res) => {
 | 
			
		||||
        if (res.status === 200) {
 | 
			
		||||
          toast.success(`${polygon.name || "Motion Mask"} has been saved.`, {
 | 
			
		||||
            position: "top-center",
 | 
			
		||||
          });
 | 
			
		||||
          toast.success(
 | 
			
		||||
            `${polygon.name || "Motion Mask"} has been saved. Restart Frigate to apply changes.`,
 | 
			
		||||
            {
 | 
			
		||||
              position: "top-center",
 | 
			
		||||
            },
 | 
			
		||||
          );
 | 
			
		||||
          updateConfig();
 | 
			
		||||
        } else {
 | 
			
		||||
          toast.error(`Failed to save config changes: ${res.statusText}`, {
 | 
			
		||||
 | 
			
		||||
@ -189,13 +189,16 @@ export default function ObjectMaskEditPane({
 | 
			
		||||
 | 
			
		||||
      axios
 | 
			
		||||
        .put(`config/set?${queryString}`, {
 | 
			
		||||
          requires_restart: 1,
 | 
			
		||||
          requires_restart: 0,
 | 
			
		||||
        })
 | 
			
		||||
        .then((res) => {
 | 
			
		||||
          if (res.status === 200) {
 | 
			
		||||
            toast.success(`${polygon.name || "Object Mask"} has been saved.`, {
 | 
			
		||||
              position: "top-center",
 | 
			
		||||
            });
 | 
			
		||||
            toast.success(
 | 
			
		||||
              `${polygon.name || "Object Mask"} has been saved. Restart Frigate to apply changes.`,
 | 
			
		||||
              {
 | 
			
		||||
                position: "top-center",
 | 
			
		||||
              },
 | 
			
		||||
            );
 | 
			
		||||
            updateConfig();
 | 
			
		||||
          } else {
 | 
			
		||||
            toast.error(`Failed to save config changes: ${res.statusText}`, {
 | 
			
		||||
 | 
			
		||||
@ -197,7 +197,7 @@ export default function ZoneEditPane({
 | 
			
		||||
          await axios.put(
 | 
			
		||||
            `config/set?cameras.${polygon.camera}.zones.${polygon.name}${renameAlertQueries}${renameDetectionQueries}`,
 | 
			
		||||
            {
 | 
			
		||||
              requires_restart: 1,
 | 
			
		||||
              requires_restart: 0,
 | 
			
		||||
            },
 | 
			
		||||
          );
 | 
			
		||||
 | 
			
		||||
@ -257,13 +257,16 @@ export default function ZoneEditPane({
 | 
			
		||||
      axios
 | 
			
		||||
        .put(
 | 
			
		||||
          `config/set?cameras.${polygon?.camera}.zones.${zoneName}.coordinates=${coordinates}${inertiaQuery}${loiteringTimeQuery}${objectQueries}${alertQueries}${detectionQueries}`,
 | 
			
		||||
          { requires_restart: 1 },
 | 
			
		||||
          { requires_restart: 0 },
 | 
			
		||||
        )
 | 
			
		||||
        .then((res) => {
 | 
			
		||||
          if (res.status === 200) {
 | 
			
		||||
            toast.success(`Zone (${zoneName}) has been saved.`, {
 | 
			
		||||
              position: "top-center",
 | 
			
		||||
            });
 | 
			
		||||
            toast.success(
 | 
			
		||||
              `Zone (${zoneName}) has been saved. Restart Frigate to apply changes.`,
 | 
			
		||||
              {
 | 
			
		||||
                position: "top-center",
 | 
			
		||||
              },
 | 
			
		||||
            );
 | 
			
		||||
            updateConfig();
 | 
			
		||||
          } else {
 | 
			
		||||
            toast.error(`Failed to save config changes: ${res.statusText}`, {
 | 
			
		||||
 | 
			
		||||
@ -7,6 +7,7 @@ import { MinimapBounds, Tick, Timestamp } from "./segment-metadata";
 | 
			
		||||
import { useMotionSegmentUtils } from "@/hooks/use-motion-segment-utils";
 | 
			
		||||
import { isDesktop, isMobile } from "react-device-detect";
 | 
			
		||||
import useTapUtils from "@/hooks/use-tap-utils";
 | 
			
		||||
import { cn } from "@/lib/utils";
 | 
			
		||||
 | 
			
		||||
type MotionSegmentProps = {
 | 
			
		||||
  events: ReviewSegment[];
 | 
			
		||||
@ -170,7 +171,16 @@ export function MotionSegment({
 | 
			
		||||
        <div
 | 
			
		||||
          key={segmentKey}
 | 
			
		||||
          data-segment-id={segmentKey}
 | 
			
		||||
          className={`segment ${firstHalfSegmentWidth > 0 || secondHalfSegmentWidth > 0 ? "has-data" : ""} ${segmentClasses}  bg-gradient-to-r ${severityColorsBg[severity[0]]}`}
 | 
			
		||||
          className={cn(
 | 
			
		||||
            "segment",
 | 
			
		||||
            {
 | 
			
		||||
              "has-data":
 | 
			
		||||
                firstHalfSegmentWidth > 0 || secondHalfSegmentWidth > 0,
 | 
			
		||||
            },
 | 
			
		||||
            segmentClasses,
 | 
			
		||||
            severity[0] && "bg-gradient-to-r",
 | 
			
		||||
            severity[0] && severityColorsBg[severity[0]],
 | 
			
		||||
          )}
 | 
			
		||||
          onClick={segmentClick}
 | 
			
		||||
          onTouchEnd={(event) => handleTouchStart(event, segmentClick)}
 | 
			
		||||
        >
 | 
			
		||||
@ -210,7 +220,14 @@ export function MotionSegment({
 | 
			
		||||
                <div
 | 
			
		||||
                  key={`${segmentKey}_motion_data_1`}
 | 
			
		||||
                  data-motion-value={secondHalfSegmentWidth}
 | 
			
		||||
                  className={`${isDesktop && animationClassesSecondHalf} h-[2px] rounded-full bg-motion_review`}
 | 
			
		||||
                  className={cn(
 | 
			
		||||
                    isDesktop && animationClassesSecondHalf,
 | 
			
		||||
                    "h-[2px]",
 | 
			
		||||
                    "rounded-full",
 | 
			
		||||
                    secondHalfSegmentWidth
 | 
			
		||||
                      ? "bg-motion_review"
 | 
			
		||||
                      : "bg-muted-foreground",
 | 
			
		||||
                  )}
 | 
			
		||||
                  style={{
 | 
			
		||||
                    width: secondHalfSegmentWidth || 1,
 | 
			
		||||
                  }}
 | 
			
		||||
@ -223,7 +240,14 @@ export function MotionSegment({
 | 
			
		||||
                <div
 | 
			
		||||
                  key={`${segmentKey}_motion_data_2`}
 | 
			
		||||
                  data-motion-value={firstHalfSegmentWidth}
 | 
			
		||||
                  className={`${isDesktop && animationClassesFirstHalf} h-[2px] rounded-full bg-motion_review`}
 | 
			
		||||
                  className={cn(
 | 
			
		||||
                    isDesktop && animationClassesFirstHalf,
 | 
			
		||||
                    "h-[2px]",
 | 
			
		||||
                    "rounded-full",
 | 
			
		||||
                    firstHalfSegmentWidth
 | 
			
		||||
                      ? "bg-motion_review"
 | 
			
		||||
                      : "bg-muted-foreground",
 | 
			
		||||
                  )}
 | 
			
		||||
                  style={{
 | 
			
		||||
                    width: firstHalfSegmentWidth || 1,
 | 
			
		||||
                  }}
 | 
			
		||||
 | 
			
		||||
@ -267,14 +267,27 @@ export default function DraggableGridLayout({
 | 
			
		||||
  const [{ width: containerWidth, height: containerHeight }] =
 | 
			
		||||
    useResizeObserver(gridContainerRef);
 | 
			
		||||
 | 
			
		||||
  const scrollBarWidth = useMemo(() => {
 | 
			
		||||
    if (containerWidth && containerHeight && containerRef.current) {
 | 
			
		||||
      return (
 | 
			
		||||
        containerRef.current.offsetWidth - containerRef.current.clientWidth
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
    return 0;
 | 
			
		||||
  }, [containerRef, containerHeight, containerWidth]);
 | 
			
		||||
 | 
			
		||||
  const availableWidth = useMemo(
 | 
			
		||||
    () => (scrollBarWidth ? containerWidth + scrollBarWidth : containerWidth),
 | 
			
		||||
    [containerWidth, scrollBarWidth],
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
  const hasScrollbar = useMemo(() => {
 | 
			
		||||
    return (
 | 
			
		||||
      containerHeight &&
 | 
			
		||||
      containerRef.current &&
 | 
			
		||||
      containerRef.current.offsetHeight <
 | 
			
		||||
        (gridContainerRef.current?.scrollHeight ?? 0)
 | 
			
		||||
    );
 | 
			
		||||
  }, [containerRef, gridContainerRef, containerHeight]);
 | 
			
		||||
    if (containerHeight && containerRef.current) {
 | 
			
		||||
      return (
 | 
			
		||||
        containerRef.current.offsetHeight < containerRef.current.scrollHeight
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
  }, [containerRef, containerHeight]);
 | 
			
		||||
 | 
			
		||||
  // fullscreen state
 | 
			
		||||
 | 
			
		||||
@ -295,13 +308,13 @@ export default function DraggableGridLayout({
 | 
			
		||||
    // subtract container margin, 1 camera takes up at least 4 rows
 | 
			
		||||
    // account for additional margin on bottom of each row
 | 
			
		||||
    return (
 | 
			
		||||
      ((containerWidth ?? window.innerWidth) - 2 * marginValue) /
 | 
			
		||||
      ((availableWidth ?? window.innerWidth) - 2 * marginValue) /
 | 
			
		||||
        12 /
 | 
			
		||||
        aspectRatio -
 | 
			
		||||
      marginValue +
 | 
			
		||||
      marginValue / 4
 | 
			
		||||
    );
 | 
			
		||||
  }, [containerWidth, marginValue]);
 | 
			
		||||
  }, [availableWidth, marginValue]);
 | 
			
		||||
 | 
			
		||||
  const handleResize: ItemCallback = (
 | 
			
		||||
    _: Layout[],
 | 
			
		||||
@ -312,7 +325,7 @@ export default function DraggableGridLayout({
 | 
			
		||||
    const heightDiff = layoutItem.h - oldLayoutItem.h;
 | 
			
		||||
    const widthDiff = layoutItem.w - oldLayoutItem.w;
 | 
			
		||||
    const changeCoef = oldLayoutItem.w / oldLayoutItem.h;
 | 
			
		||||
    if (Math.abs(heightDiff) < Math.abs(widthDiff)) {
 | 
			
		||||
    if (Math.abs(heightDiff) < Math.abs(widthDiff) || layoutItem.w == 12) {
 | 
			
		||||
      layoutItem.h = layoutItem.w / changeCoef;
 | 
			
		||||
      placeholder.h = layoutItem.w / changeCoef;
 | 
			
		||||
    } else {
 | 
			
		||||
@ -545,6 +558,7 @@ const BirdseyeLivePlayerGridItem = React.forwardRef<
 | 
			
		||||
          birdseyeConfig={birdseyeConfig}
 | 
			
		||||
          liveMode={liveMode}
 | 
			
		||||
          onClick={onClick}
 | 
			
		||||
          containerRef={ref as React.RefObject<HTMLDivElement>}
 | 
			
		||||
        />
 | 
			
		||||
        {children}
 | 
			
		||||
      </div>
 | 
			
		||||
@ -603,6 +617,7 @@ const LivePlayerGridItem = React.forwardRef<
 | 
			
		||||
          cameraConfig={cameraConfig}
 | 
			
		||||
          preferredLiveMode={preferredLiveMode}
 | 
			
		||||
          onClick={onClick}
 | 
			
		||||
          containerRef={ref as React.RefObject<HTMLDivElement>}
 | 
			
		||||
        />
 | 
			
		||||
        {children}
 | 
			
		||||
      </div>
 | 
			
		||||
 | 
			
		||||
@ -42,12 +42,24 @@ export default function LiveBirdseyeView() {
 | 
			
		||||
    return config.birdseye.width / config.birdseye.height;
 | 
			
		||||
  }, [config]);
 | 
			
		||||
 | 
			
		||||
  const windowAspectRatio = useMemo(() => {
 | 
			
		||||
    return windowWidth / windowHeight;
 | 
			
		||||
  }, [windowWidth, windowHeight]);
 | 
			
		||||
 | 
			
		||||
  const containerAspectRatio = useMemo(() => {
 | 
			
		||||
    if (!containerRef.current) {
 | 
			
		||||
      return windowAspectRatio;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return containerRef.current.clientWidth / containerRef.current.clientHeight;
 | 
			
		||||
  }, [windowAspectRatio, containerRef]);
 | 
			
		||||
 | 
			
		||||
  const growClassName = useMemo(() => {
 | 
			
		||||
    if (isMobile) {
 | 
			
		||||
      if (isPortrait) {
 | 
			
		||||
        return "absolute left-2 right-2 top-[50%] -translate-y-[50%]";
 | 
			
		||||
      } else {
 | 
			
		||||
        if (cameraAspectRatio > 16 / 9) {
 | 
			
		||||
        if (cameraAspectRatio > containerAspectRatio) {
 | 
			
		||||
          return "absolute left-0 top-[50%] -translate-y-[50%]";
 | 
			
		||||
        } else {
 | 
			
		||||
          return "absolute top-2 bottom-2 left-[50%] -translate-x-[50%]";
 | 
			
		||||
@ -56,7 +68,7 @@ export default function LiveBirdseyeView() {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (fullscreen) {
 | 
			
		||||
      if (cameraAspectRatio > 16 / 9) {
 | 
			
		||||
      if (cameraAspectRatio > containerAspectRatio) {
 | 
			
		||||
        return "absolute inset-x-2 top-[50%] -translate-y-[50%]";
 | 
			
		||||
      } else {
 | 
			
		||||
        return "absolute inset-y-2 left-[50%] -translate-x-[50%]";
 | 
			
		||||
@ -64,7 +76,7 @@ export default function LiveBirdseyeView() {
 | 
			
		||||
    } else {
 | 
			
		||||
      return "absolute top-0 bottom-0 left-[50%] -translate-x-[50%]";
 | 
			
		||||
    }
 | 
			
		||||
  }, [cameraAspectRatio, fullscreen, isPortrait]);
 | 
			
		||||
  }, [cameraAspectRatio, containerAspectRatio, fullscreen, isPortrait]);
 | 
			
		||||
 | 
			
		||||
  const preferredLiveMode = useMemo(() => {
 | 
			
		||||
    if (!config || !config.birdseye.restream) {
 | 
			
		||||
@ -78,18 +90,6 @@ export default function LiveBirdseyeView() {
 | 
			
		||||
    return "mse";
 | 
			
		||||
  }, [config]);
 | 
			
		||||
 | 
			
		||||
  const windowAspectRatio = useMemo(() => {
 | 
			
		||||
    return windowWidth / windowHeight;
 | 
			
		||||
  }, [windowWidth, windowHeight]);
 | 
			
		||||
 | 
			
		||||
  const containerAspectRatio = useMemo(() => {
 | 
			
		||||
    if (!containerRef.current) {
 | 
			
		||||
      return windowAspectRatio;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return containerRef.current.clientWidth / containerRef.current.clientHeight;
 | 
			
		||||
  }, [windowAspectRatio, containerRef]);
 | 
			
		||||
 | 
			
		||||
  const aspectRatio = useMemo<number>(() => {
 | 
			
		||||
    if (isMobile || fullscreen) {
 | 
			
		||||
      return cameraAspectRatio;
 | 
			
		||||
 | 
			
		||||
@ -113,7 +113,7 @@ export default function MotionTunerView({
 | 
			
		||||
    axios
 | 
			
		||||
      .put(
 | 
			
		||||
        `config/set?cameras.${selectedCamera}.motion.threshold=${motionSettings.threshold}&cameras.${selectedCamera}.motion.contour_area=${motionSettings.contour_area}&cameras.${selectedCamera}.motion.improve_contrast=${motionSettings.improve_contrast}`,
 | 
			
		||||
        { requires_restart: 1 },
 | 
			
		||||
        { requires_restart: 0 },
 | 
			
		||||
      )
 | 
			
		||||
      .then((res) => {
 | 
			
		||||
        if (res.status === 200) {
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user