mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-04-03 13:54:55 +03:00
Snapshot: guard against repeated download clicks
This commit is contained in:
parent
84c18365cc
commit
9e563823ac
@ -231,6 +231,7 @@ export default function HlsVideoPlayer({
|
||||
const [mobileCtrlTimeout, setMobileCtrlTimeout] = useState<NodeJS.Timeout>();
|
||||
const [controls, setControls] = useState(isMobile);
|
||||
const [controlsOpen, setControlsOpen] = useState(false);
|
||||
const [isSnapshotLoading, setIsSnapshotLoading] = useState(false);
|
||||
const [zoomScale, setZoomScale] = useState(1.0);
|
||||
const [videoDimensions, setVideoDimensions] = useState<{
|
||||
width: number;
|
||||
@ -277,27 +278,44 @@ export default function HlsVideoPlayer({
|
||||
}, [videoRef, inpointOffset]);
|
||||
|
||||
const handleSnapshot = useCallback(async () => {
|
||||
const frameTime = getVideoTime();
|
||||
const result = await grabVideoSnapshot(videoRef.current);
|
||||
|
||||
if (result.success) {
|
||||
downloadSnapshot(
|
||||
result.data.dataUrl,
|
||||
generateSnapshotFilename(
|
||||
camera ?? "recording",
|
||||
currentTime ?? frameTime,
|
||||
config?.ui?.timezone,
|
||||
),
|
||||
);
|
||||
toast.success(t("snapshot.downloadStarted", { ns: "views/live" }), {
|
||||
position: "top-center",
|
||||
});
|
||||
} else {
|
||||
toast.error(t("snapshot.captureFailed", { ns: "views/live" }), {
|
||||
position: "top-center",
|
||||
});
|
||||
if (isSnapshotLoading) {
|
||||
return;
|
||||
}
|
||||
}, [camera, config?.ui?.timezone, currentTime, getVideoTime, t, videoRef]);
|
||||
|
||||
setIsSnapshotLoading(true);
|
||||
try {
|
||||
const frameTime = getVideoTime();
|
||||
const result = await grabVideoSnapshot(videoRef.current);
|
||||
|
||||
if (result.success) {
|
||||
downloadSnapshot(
|
||||
result.data.dataUrl,
|
||||
generateSnapshotFilename(
|
||||
camera ?? "recording",
|
||||
currentTime ?? frameTime,
|
||||
config?.ui?.timezone,
|
||||
),
|
||||
);
|
||||
toast.success(t("snapshot.downloadStarted", { ns: "views/live" }), {
|
||||
position: "top-center",
|
||||
});
|
||||
} else {
|
||||
toast.error(t("snapshot.captureFailed", { ns: "views/live" }), {
|
||||
position: "top-center",
|
||||
});
|
||||
}
|
||||
} finally {
|
||||
setIsSnapshotLoading(false);
|
||||
}
|
||||
}, [
|
||||
camera,
|
||||
config?.ui?.timezone,
|
||||
currentTime,
|
||||
getVideoTime,
|
||||
isSnapshotLoading,
|
||||
t,
|
||||
videoRef,
|
||||
]);
|
||||
const onSnapshot = camera ? handleSnapshot : undefined;
|
||||
|
||||
return (
|
||||
@ -365,6 +383,7 @@ export default function HlsVideoPlayer({
|
||||
}
|
||||
}}
|
||||
onSnapshot={onSnapshot}
|
||||
snapshotLoading={isSnapshotLoading}
|
||||
snapshotTitle={t("snapshot.takeSnapshot", { ns: "views/live" })}
|
||||
fullscreen={fullscreen}
|
||||
toggleFullscreen={toggleFullscreen}
|
||||
|
||||
@ -75,6 +75,7 @@ type VideoControlsProps = {
|
||||
onSetPlaybackRate: (rate: number) => void;
|
||||
onUploadFrame?: () => void;
|
||||
onSnapshot?: () => void;
|
||||
snapshotLoading?: boolean;
|
||||
snapshotTitle?: string;
|
||||
toggleFullscreen?: () => void;
|
||||
containerRef?: React.MutableRefObject<HTMLDivElement | null>;
|
||||
@ -98,6 +99,7 @@ export default function VideoControls({
|
||||
onSetPlaybackRate,
|
||||
onUploadFrame,
|
||||
onSnapshot,
|
||||
snapshotLoading = false,
|
||||
snapshotTitle,
|
||||
toggleFullscreen,
|
||||
containerRef,
|
||||
@ -302,10 +304,17 @@ export default function VideoControls({
|
||||
{features.snapshot && onSnapshot && (
|
||||
<TbCameraDown
|
||||
aria-label={snapshotTitle}
|
||||
className="size-5 cursor-pointer"
|
||||
aria-disabled={snapshotLoading}
|
||||
className={cn(
|
||||
"size-5",
|
||||
snapshotLoading ? "cursor-not-allowed opacity-50" : "cursor-pointer",
|
||||
)}
|
||||
title={snapshotTitle}
|
||||
onClick={(e: React.MouseEvent<SVGElement>) => {
|
||||
e.stopPropagation();
|
||||
if (snapshotLoading) {
|
||||
return;
|
||||
}
|
||||
onSnapshot();
|
||||
}}
|
||||
/>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user