mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-02-06 11:15:21 +03:00
Add ability to delete exports from exports screen
This commit is contained in:
parent
7d0733c3e7
commit
b7e750bec6
@ -34,6 +34,7 @@ from frigate.const import (
|
||||
CACHE_DIR,
|
||||
CLIPS_DIR,
|
||||
CONFIG_DIR,
|
||||
EXPORT_DIR,
|
||||
MAX_SEGMENT_DURATION,
|
||||
RECORD_DIR,
|
||||
)
|
||||
@ -1666,6 +1667,22 @@ def export_recording(camera_name: str, start_time, end_time):
|
||||
return "Starting export of recording", 200
|
||||
|
||||
|
||||
@bp.route("/export/<file_name>", methods=["DELETE"])
|
||||
def export_delete(file_name: str):
|
||||
file = os.path.join(EXPORT_DIR, file_name)
|
||||
|
||||
if not os.path.exists(file):
|
||||
return make_response(
|
||||
jsonify(
|
||||
{"success": False, "message": f"{file_name} not found."}
|
||||
),
|
||||
404,
|
||||
)
|
||||
|
||||
os.unlink(file)
|
||||
return "Successfully deleted file", 200
|
||||
|
||||
|
||||
def imagestream(detected_frames_processor, camera_name, fps, height, draw_options):
|
||||
while True:
|
||||
# max out at specified FPS
|
||||
|
||||
@ -1,14 +1,16 @@
|
||||
import Heading from '../components/Heading';
|
||||
import { useState } from 'preact/hooks';
|
||||
import useSWR from 'swr';
|
||||
import useSWR, { mutate } from 'swr';
|
||||
import Button from '../components/Button';
|
||||
import axios from 'axios';
|
||||
import { baseUrl } from '../api/baseUrl';
|
||||
import { Fragment } from 'preact';
|
||||
import ActivityIndicator from '../components/ActivityIndicator';
|
||||
import { Play } from '../icons/Play';
|
||||
import { Delete } from '../icons/Delete';
|
||||
import LargeDialog from '../components/DialogLarge';
|
||||
import VideoPlayer from '../components/VideoPlayer';
|
||||
import Dialog from '../components/Dialog';
|
||||
|
||||
export default function Export() {
|
||||
const { data: config } = useSWR('config');
|
||||
@ -30,9 +32,10 @@ export default function Export() {
|
||||
const [endDate, setEndDate] = useState(localISODate);
|
||||
const [endTime, setEndTime] = useState('23:59');
|
||||
|
||||
// Playback States
|
||||
// Export States
|
||||
|
||||
const [selectedClip, setSelectedClip] = useState();
|
||||
const [deleteClip, setDeleteClip] = useState();
|
||||
|
||||
const onHandleExport = () => {
|
||||
if (camera == 'select') {
|
||||
@ -74,6 +77,15 @@ export default function Export() {
|
||||
});
|
||||
};
|
||||
|
||||
const onHandleDelete = (clip) => {
|
||||
axios.delete(`export/${clip}`).then((response) => {
|
||||
if (response.status == 200) {
|
||||
setDeleteClip();
|
||||
mutate();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="space-y-4 p-2 px-4 w-full">
|
||||
<Heading>Export</Heading>
|
||||
@ -84,7 +96,7 @@ export default function Export() {
|
||||
|
||||
{selectedClip && (
|
||||
<LargeDialog>
|
||||
<div className="min-w-[720px] max-w-7xl">
|
||||
<div className="max-w-7xl">
|
||||
<Heading className="p-2">Playback</Heading>
|
||||
<VideoPlayer
|
||||
options={{
|
||||
@ -114,6 +126,23 @@ export default function Export() {
|
||||
</LargeDialog>
|
||||
)}
|
||||
|
||||
{deleteClip && (
|
||||
<Dialog>
|
||||
<div className="p-4">
|
||||
<Heading size="lg">Delete Export?</Heading>
|
||||
<p className="py-4 mb-2">Confirm deletion of {deleteClip}.</p>
|
||||
</div>
|
||||
<div className="p-2 flex justify-start flex-row-reverse space-x-2">
|
||||
<Button className="ml-2" onClick={() => setDeleteClip('')} type="text">
|
||||
Close
|
||||
</Button>
|
||||
<Button className="ml-2" color="red" onClick={() => onHandleDelete(deleteClip)} type="text">
|
||||
Delete
|
||||
</Button>
|
||||
</div>
|
||||
</Dialog>
|
||||
)}
|
||||
|
||||
<div className="xl:flex justify-between">
|
||||
<div>
|
||||
<div>
|
||||
@ -184,7 +213,11 @@ export default function Export() {
|
||||
{exports && (
|
||||
<div className="p-4 bg-gray-800 xl:w-1/2">
|
||||
<Heading size="md">Exports</Heading>
|
||||
<Exports exports={exports} onSetClip={(clip) => setSelectedClip(clip)} />
|
||||
<Exports
|
||||
exports={exports}
|
||||
onSetClip={(clip) => setSelectedClip(clip)}
|
||||
onDeleteClip={(clip) => setDeleteClip(clip)}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
@ -192,7 +225,7 @@ export default function Export() {
|
||||
);
|
||||
}
|
||||
|
||||
function Exports({ exports, onSetClip }) {
|
||||
function Exports({ exports, onSetClip, onDeleteClip }) {
|
||||
return (
|
||||
<Fragment>
|
||||
{exports.map((item) => (
|
||||
@ -209,9 +242,16 @@ function Exports({ exports, onSetClip }) {
|
||||
<Button type="iconOnly" onClick={() => onSetClip(item.name)}>
|
||||
<Play className="h-6 w-6 text-green-600" />
|
||||
</Button>
|
||||
<a className="text-blue-500 hover:underline" href={`${baseUrl}exports/${item.name}`} download>
|
||||
<a
|
||||
className="text-blue-500 hover:underline overflow-hidden"
|
||||
href={`${baseUrl}exports/${item.name}`}
|
||||
download
|
||||
>
|
||||
{item.name.substring(0, item.name.length - 4)}
|
||||
</a>
|
||||
<Button className="ml-auto" type="iconOnly" onClick={() => onDeleteClip(item.name)}>
|
||||
<Delete className="h-6 w-6" stroke="#f87171" />
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user