diff --git a/web/src/components/camera/AutoUpdatingCameraImage.tsx b/web/src/components/camera/AutoUpdatingCameraImage.tsx index 43a59daa93..8e968c37d7 100644 --- a/web/src/components/camera/AutoUpdatingCameraImage.tsx +++ b/web/src/components/camera/AutoUpdatingCameraImage.tsx @@ -12,6 +12,7 @@ type AutoUpdatingCameraImageProps = { }; const MIN_LOAD_TIMEOUT_MS = 200; +const ERROR_RETRY_MS = 1000; export default function AutoUpdatingCameraImage({ camera, @@ -68,6 +69,24 @@ export default function AutoUpdatingCameraImage({ // eslint-disable-next-line react-hooks/exhaustive-deps }, [key, setFps]); + const handleError = useCallback(() => { + if (reloadInterval == -1) { + return; + } + + // the periodic cache url doesn't change between retries, so drop it + setIsCached(true); + + if (timeoutRef.current) { + clearTimeout(timeoutRef.current); + } + + timeoutRef.current = setTimeout( + () => setKey(Date.now()), + Math.max(reloadInterval, ERROR_RETRY_MS), + ); + }, [reloadInterval]); + // periodic cache to reduce loading indicator const [isCached, setIsCached] = useState(false); @@ -92,6 +111,7 @@ export default function AutoUpdatingCameraImage({ diff --git a/web/src/components/camera/CameraImage.tsx b/web/src/components/camera/CameraImage.tsx index 0ba7ea19e7..f328d77387 100644 --- a/web/src/components/camera/CameraImage.tsx +++ b/web/src/components/camera/CameraImage.tsx @@ -11,6 +11,7 @@ type CameraImageProps = { className?: string; camera: string; onload?: () => void; + onerror?: () => void; searchParams?: string; }; @@ -18,6 +19,7 @@ export default function CameraImage({ className, camera, onload, + onerror, searchParams = "", }: CameraImageProps) { const { data: config } = useSWR("config"); @@ -96,6 +98,7 @@ export default function CameraImage({ "rounded-lg md:rounded-2xl", )} onLoad={handleImageLoad} + onError={onerror} loading="lazy" /> ) : (