mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-02-01 08:45:21 +03:00
Allow deleting events and associated clips and snapshots from the event list view
This commit is contained in:
parent
5043040530
commit
1ef0d99790
@ -5,7 +5,7 @@ title: HTTP API
|
||||
|
||||
A web server is available on port 5000 with the following endpoints.
|
||||
|
||||
### `/api/<camera_name>`
|
||||
### `GET /api/<camera_name>`
|
||||
|
||||
An mjpeg stream for debugging. Keep in mind the mjpeg endpoint is for debugging only and will put additional load on the system when in use.
|
||||
|
||||
@ -24,7 +24,7 @@ Accepts the following query string parameters:
|
||||
|
||||
You can access a higher resolution mjpeg stream by appending `h=height-in-pixels` to the endpoint. For example `http://localhost:5000/back?h=1080`. You can also increase the FPS by appending `fps=frame-rate` to the URL such as `http://localhost:5000/back?fps=10` or both with `?fps=10&h=1000`.
|
||||
|
||||
### `/api/<camera_name>/<object_name>/best.jpg[?h=300&crop=1]`
|
||||
### `GET /api/<camera_name>/<object_name>/best.jpg[?h=300&crop=1]`
|
||||
|
||||
The best snapshot for any object type. It is a full resolution image by default.
|
||||
|
||||
@ -33,7 +33,7 @@ Example parameters:
|
||||
- `h=300`: resizes the image to 300 pixes tall
|
||||
- `crop=1`: crops the image to the region of the detection rather than returning the entire image
|
||||
|
||||
### `/api/<camera_name>/latest.jpg[?h=300]`
|
||||
### `GET /api/<camera_name>/latest.jpg[?h=300]`
|
||||
|
||||
The most recent frame that frigate has finished processing. It is a full resolution image by default.
|
||||
|
||||
@ -53,7 +53,7 @@ Example parameters:
|
||||
|
||||
- `h=300`: resizes the image to 300 pixes tall
|
||||
|
||||
### `/api/stats`
|
||||
### `GET /api/stats`
|
||||
|
||||
Contains some granular debug info that can be used for sensors in HomeAssistant.
|
||||
|
||||
@ -150,15 +150,15 @@ Sample response:
|
||||
}
|
||||
```
|
||||
|
||||
### `/api/config`
|
||||
### `GET /api/config`
|
||||
|
||||
A json representation of your configuration
|
||||
|
||||
### `/api/version`
|
||||
### `GET /api/version`
|
||||
|
||||
Version info
|
||||
|
||||
### `/api/events`
|
||||
### `GET /api/events`
|
||||
|
||||
Events from the database. Accepts the following query string parameters:
|
||||
|
||||
@ -174,19 +174,23 @@ Events from the database. Accepts the following query string parameters:
|
||||
| `has_clip` | int | Filter to events that have clips (0 or 1) |
|
||||
| `include_thumbnails` | int | Include thumbnails in the response (0 or 1) |
|
||||
|
||||
### `/api/events/summary`
|
||||
### `GET /api/events/summary`
|
||||
|
||||
Returns summary data for events in the database. Used by the HomeAssistant integration.
|
||||
|
||||
### `/api/events/<id>`
|
||||
### `GET /api/events/<id>`
|
||||
|
||||
Returns data for a single event.
|
||||
|
||||
### `/api/events/<id>/thumbnail.jpg`
|
||||
### `DELETE /api/events/<id>`
|
||||
|
||||
Permantly deletes the event along with any clips/snapshots.
|
||||
|
||||
### `GET /api/events/<id>/thumbnail.jpg`
|
||||
|
||||
Returns a thumbnail for the event id optimized for notifications. Works while the event is in progress and after completion. Passing `?format=android` will convert the thumbnail to 2:1 aspect ratio.
|
||||
|
||||
### `/api/events/<id>/snapshot.jpg`
|
||||
### `GET /api/events/<id>/snapshot.jpg`
|
||||
|
||||
Returns the snapshot image for the event id. Works while the event is in progress and after completion.
|
||||
|
||||
|
||||
@ -5,6 +5,7 @@ import logging
|
||||
import os
|
||||
import time
|
||||
from functools import reduce
|
||||
from pathlib import Path
|
||||
|
||||
import cv2
|
||||
import gevent
|
||||
@ -145,13 +146,32 @@ def events_summary():
|
||||
|
||||
return jsonify([e for e in groups.dicts()])
|
||||
|
||||
@bp.route('/events/<id>')
|
||||
@bp.route('/events/<id>', methods=('GET',))
|
||||
def event(id):
|
||||
try:
|
||||
return model_to_dict(Event.get(Event.id == id))
|
||||
except DoesNotExist:
|
||||
return "Event not found", 404
|
||||
|
||||
@bp.route('/events/<id>', methods=('DELETE',))
|
||||
def delete_event(id):
|
||||
try:
|
||||
event = Event.get(Event.id == id)
|
||||
except DoesNotExist:
|
||||
return "Event not found", 404
|
||||
|
||||
media_name = f"{event.camera}-{event.id}"
|
||||
if event.has_snapshot:
|
||||
media = Path(f"{os.path.join(CLIPS_DIR, media_name)}.jpg")
|
||||
media.unlink(missing_ok=True)
|
||||
if event.has_clip:
|
||||
media = Path(f"{os.path.join(CLIPS_DIR, media_name)}.mp4")
|
||||
media.unlink(missing_ok=True)
|
||||
|
||||
event.delete_instance()
|
||||
|
||||
return '', 204
|
||||
|
||||
@bp.route('/events/<id>/thumbnail.jpg')
|
||||
def event_thumbnail(id):
|
||||
format = request.args.get('format', 'ios')
|
||||
|
||||
@ -7,6 +7,8 @@ import produce from 'immer';
|
||||
import { route } from 'preact-router';
|
||||
import { useIntersectionObserver } from '../hooks';
|
||||
import { FetchStatus, useApiHost, useConfig, useEvents } from '../api';
|
||||
import Button from '../components/Button';
|
||||
import Delete from '../icons/Delete'
|
||||
import { Table, Thead, Tbody, Tfoot, Th, Tr, Td } from '../components/Table';
|
||||
import { useCallback, useEffect, useMemo, useReducer, useState } from 'preact/hooks';
|
||||
|
||||
@ -99,6 +101,18 @@ export default function Events({ path: pathname, limit = API_LIMIT } = {}) {
|
||||
[limit, pathname, setSearchString]
|
||||
);
|
||||
|
||||
const handleDelete = useCallback(
|
||||
async (eventId) => {
|
||||
// eslint-disable-next-line no-alert
|
||||
if(confirm('Are you sure you want to delete this event and any related clips and snapshots?')) {
|
||||
await fetch(`${apiHost}/api/events/${eventId}`);
|
||||
const { searchParams } = new URL(window.location);
|
||||
handleFilter(searchParams)
|
||||
}
|
||||
},
|
||||
[apiHost, handleFilter]
|
||||
);
|
||||
|
||||
const searchParams = useMemo(() => new URLSearchParams(searchString), [searchString]);
|
||||
|
||||
return (
|
||||
@ -119,6 +133,7 @@ export default function Events({ path: pathname, limit = API_LIMIT } = {}) {
|
||||
<Th>Date</Th>
|
||||
<Th>Start</Th>
|
||||
<Th>End</Th>
|
||||
<Th />
|
||||
</Tr>
|
||||
</Thead>
|
||||
<Tbody>
|
||||
@ -179,6 +194,11 @@ export default function Events({ path: pathname, limit = API_LIMIT } = {}) {
|
||||
<Td>{start.toLocaleDateString()}</Td>
|
||||
<Td>{start.toLocaleTimeString()}</Td>
|
||||
<Td>{end.toLocaleTimeString()}</Td>
|
||||
<Td>
|
||||
<Button color="red" name="Delete" onClick={() => handleDelete(id)}>
|
||||
<Delete className="w-6" />
|
||||
</Button>
|
||||
</Td>
|
||||
</Tr>
|
||||
);
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user