mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-02-15 15:45:27 +03:00
Add option to export Timelapses from History view
This commit is contained in:
parent
77ec86d31a
commit
e50a1eb905
@ -154,7 +154,7 @@ Footage can be exported from Frigate by right-clicking (desktop) or long pressin
|
||||
|
||||
### Time-lapse export
|
||||
|
||||
Time lapse exporting is available only via the [HTTP API](../integrations/api/export-recording-export-camera-name-start-start-time-end-end-time-post.api.mdx).
|
||||
Time lapse exporting is available while exporting from the History view, or via the [HTTP API](../integrations/api/export-recording-export-camera-name-start-start-time-end-end-time-post.api.mdx).
|
||||
|
||||
When exporting a time-lapse the default speed-up is 25x with 30 FPS. This means that every 25 seconds of (real-time) recording is condensed into 1 second of time-lapse video (always without audio) with a smoothness of 30 FPS.
|
||||
|
||||
|
||||
@ -11,6 +11,7 @@ import {
|
||||
import { Label } from "../ui/label";
|
||||
import { RadioGroup, RadioGroupItem } from "../ui/radio-group";
|
||||
import { Button } from "../ui/button";
|
||||
import { Checkbox } from "../ui/checkbox";
|
||||
import { ExportMode } from "@/types/filter";
|
||||
import { FaArrowDown, FaArrowRight, FaCalendarAlt } from "react-icons/fa";
|
||||
import axios from "axios";
|
||||
@ -65,6 +66,7 @@ export default function ExportDialog({
|
||||
setShowPreview,
|
||||
}: ExportDialogProps) {
|
||||
const [name, setName] = useState("");
|
||||
const [isTimelapse, setIsTimelapse] = useState(false);
|
||||
|
||||
const onStartExport = useCallback(() => {
|
||||
if (!range) {
|
||||
@ -83,7 +85,7 @@ export default function ExportDialog({
|
||||
.post(
|
||||
`export/${camera}/start/${Math.round(range.after)}/end/${Math.round(range.before)}`,
|
||||
{
|
||||
playback: "realtime",
|
||||
playback: isTimelapse ? "timelapse_25x" : "realtime",
|
||||
name,
|
||||
},
|
||||
)
|
||||
@ -96,6 +98,7 @@ export default function ExportDialog({
|
||||
setName("");
|
||||
setRange(undefined);
|
||||
setMode("none");
|
||||
setIsTimelapse(false);
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
@ -110,7 +113,7 @@ export default function ExportDialog({
|
||||
});
|
||||
}
|
||||
});
|
||||
}, [camera, name, range, setRange, setName, setMode]);
|
||||
}, [camera, name, range, isTimelapse, setRange, setName, setMode]);
|
||||
|
||||
const Overlay = isDesktop ? Dialog : Drawer;
|
||||
const Trigger = isDesktop ? DialogTrigger : DrawerTrigger;
|
||||
@ -129,13 +132,17 @@ export default function ExportDialog({
|
||||
show={mode == "timeline"}
|
||||
onPreview={() => setShowPreview(true)}
|
||||
onSave={() => onStartExport()}
|
||||
onCancel={() => setMode("none")}
|
||||
onCancel={() => {
|
||||
setMode("none");
|
||||
setIsTimelapse(false);
|
||||
}}
|
||||
/>
|
||||
<Overlay
|
||||
open={mode == "select"}
|
||||
onOpenChange={(open) => {
|
||||
if (!open) {
|
||||
setMode("none");
|
||||
setIsTimelapse(false);
|
||||
}
|
||||
}}
|
||||
>
|
||||
@ -172,11 +179,16 @@ export default function ExportDialog({
|
||||
currentTime={currentTime}
|
||||
range={range}
|
||||
name={name}
|
||||
isTimelapse={isTimelapse}
|
||||
onStartExport={onStartExport}
|
||||
setName={setName}
|
||||
setRange={setRange}
|
||||
setMode={setMode}
|
||||
onCancel={() => setMode("none")}
|
||||
setIsTimelapse={setIsTimelapse}
|
||||
onCancel={() => {
|
||||
setMode("none");
|
||||
setIsTimelapse(false);
|
||||
}}
|
||||
/>
|
||||
</Content>
|
||||
</Overlay>
|
||||
@ -189,10 +201,12 @@ type ExportContentProps = {
|
||||
currentTime: number;
|
||||
range?: TimeRange;
|
||||
name: string;
|
||||
isTimelapse: boolean;
|
||||
onStartExport: () => void;
|
||||
setName: (name: string) => void;
|
||||
setRange: (range: TimeRange | undefined) => void;
|
||||
setMode: (mode: ExportMode) => void;
|
||||
setIsTimelapse: (isTimelapse: boolean) => void;
|
||||
onCancel: () => void;
|
||||
};
|
||||
export function ExportContent({
|
||||
@ -200,10 +214,12 @@ export function ExportContent({
|
||||
currentTime,
|
||||
range,
|
||||
name,
|
||||
isTimelapse,
|
||||
onStartExport,
|
||||
setName,
|
||||
setRange,
|
||||
setMode,
|
||||
setIsTimelapse,
|
||||
onCancel,
|
||||
}: ExportContentProps) {
|
||||
const [selectedOption, setSelectedOption] = useState<ExportOption>("1");
|
||||
@ -289,6 +305,22 @@ export function ExportContent({
|
||||
setRange={setRange}
|
||||
/>
|
||||
)}
|
||||
{isDesktop && <SelectSeparator className="my-4 bg-secondary" />}
|
||||
<div className="mt-4 flex items-center gap-2">
|
||||
<Checkbox
|
||||
className={
|
||||
isTimelapse
|
||||
? "bg-selected from-selected/50 to-selected/90 text-selected"
|
||||
: "bg-secondary from-secondary/50 to-secondary/90 text-secondary"
|
||||
}
|
||||
id="timelapse"
|
||||
checked={isTimelapse}
|
||||
onCheckedChange={(checked) => setIsTimelapse(checked as boolean)}
|
||||
/>
|
||||
<Label htmlFor="timelapse" className="cursor-pointer capitalize">
|
||||
Timelapse
|
||||
</Label>
|
||||
</div>
|
||||
<Input
|
||||
className="text-md my-6"
|
||||
type="search"
|
||||
@ -319,6 +351,7 @@ export function ExportContent({
|
||||
onStartExport();
|
||||
setSelectedOption("1");
|
||||
setMode("none");
|
||||
setIsTimelapse(false);
|
||||
}
|
||||
}}
|
||||
>
|
||||
|
||||
@ -62,6 +62,7 @@ export default function MobileReviewSettingsDrawer({
|
||||
setShowExportPreview,
|
||||
}: MobileReviewSettingsDrawerProps) {
|
||||
const [drawerMode, setDrawerMode] = useState<DrawerMode>("none");
|
||||
const [isTimelapse, setIsTimelapse] = useState(false);
|
||||
|
||||
// exports
|
||||
|
||||
@ -83,7 +84,7 @@ export default function MobileReviewSettingsDrawer({
|
||||
.post(
|
||||
`export/${camera}/start/${Math.round(range.after)}/end/${Math.round(range.before)}`,
|
||||
{
|
||||
playback: "realtime",
|
||||
playback: isTimelapse ? "timelapse_25x" : "realtime",
|
||||
name,
|
||||
},
|
||||
)
|
||||
@ -96,6 +97,7 @@ export default function MobileReviewSettingsDrawer({
|
||||
setName("");
|
||||
setRange(undefined);
|
||||
setMode("none");
|
||||
setIsTimelapse(false);
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
@ -110,7 +112,7 @@ export default function MobileReviewSettingsDrawer({
|
||||
});
|
||||
}
|
||||
});
|
||||
}, [camera, name, range, setRange, setName, setMode]);
|
||||
}, [camera, name, range, isTimelapse, setRange, setName, setMode]);
|
||||
|
||||
// filters
|
||||
|
||||
@ -177,6 +179,7 @@ export default function MobileReviewSettingsDrawer({
|
||||
currentTime={currentTime}
|
||||
range={range}
|
||||
name={name}
|
||||
isTimelapse={isTimelapse}
|
||||
onStartExport={onStartExport}
|
||||
setName={setName}
|
||||
setRange={setRange}
|
||||
@ -187,10 +190,12 @@ export default function MobileReviewSettingsDrawer({
|
||||
setDrawerMode("none");
|
||||
}
|
||||
}}
|
||||
setIsTimelapse={setIsTimelapse}
|
||||
onCancel={() => {
|
||||
setMode("none");
|
||||
setRange(undefined);
|
||||
setDrawerMode("select");
|
||||
setIsTimelapse(false);
|
||||
}}
|
||||
/>
|
||||
);
|
||||
@ -289,7 +294,10 @@ export default function MobileReviewSettingsDrawer({
|
||||
className="pointer-events-none absolute left-1/2 top-8 z-50 -translate-x-1/2"
|
||||
show={mode == "timeline"}
|
||||
onSave={() => onStartExport()}
|
||||
onCancel={() => setMode("none")}
|
||||
onCancel={() => {
|
||||
setMode("none");
|
||||
setIsTimelapse(false);
|
||||
}}
|
||||
onPreview={() => setShowExportPreview(true)}
|
||||
/>
|
||||
<ExportPreviewDialog
|
||||
|
||||
Loading…
Reference in New Issue
Block a user