mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-08-07 03:11:15 +03:00
Remove thumb from database field (#16647)
* Remove thumbnail from dict * Create thumbnail diectory * Cleanup handling of tracked object images * Make thumbnail optional * Handle cases where thumbnail is used * Expand options for thumbnail api * Fix up the does not exist condition * Remove absolute usages of thumbnails * Write thumbnails for external events * Reduce webp quality * Use webp everywhere in frontend * Formatting * Always consider all events when re-indexing * Add thumbnail deletion and cleanup path management * Cleanup imports * Rename def * Don't save thumbnail for every object * Correct event count * Use correct function * Include thumbnail in query * Remove unused * Fix requiring exception
This commit is contained in:
+13
-25
@@ -11,6 +11,7 @@ from frigate.config import FrigateConfig
|
||||
from frigate.const import CLIPS_DIR
|
||||
from frigate.db.sqlitevecq import SqliteVecQueueDatabase
|
||||
from frigate.models import Event, Timeline
|
||||
from frigate.util.path import delete_event_images
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -64,7 +65,6 @@ class EventCleanup(threading.Thread):
|
||||
def expire_snapshots(self) -> list[str]:
|
||||
## Expire events from unlisted cameras based on the global config
|
||||
retain_config = self.config.snapshots.retain
|
||||
file_extension = "jpg"
|
||||
update_params = {"has_snapshot": False}
|
||||
|
||||
distinct_labels = self.get_removed_camera_labels()
|
||||
@@ -83,6 +83,7 @@ class EventCleanup(threading.Thread):
|
||||
Event.select(
|
||||
Event.id,
|
||||
Event.camera,
|
||||
Event.thumbnail,
|
||||
)
|
||||
.where(
|
||||
Event.camera.not_in(self.camera_keys),
|
||||
@@ -94,22 +95,15 @@ class EventCleanup(threading.Thread):
|
||||
.iterator()
|
||||
)
|
||||
logger.debug(f"{len(list(expired_events))} events can be expired")
|
||||
|
||||
# delete the media from disk
|
||||
for expired in expired_events:
|
||||
media_name = f"{expired.camera}-{expired.id}"
|
||||
media_path = Path(
|
||||
f"{os.path.join(CLIPS_DIR, media_name)}.{file_extension}"
|
||||
)
|
||||
deleted = delete_event_images(expired)
|
||||
|
||||
try:
|
||||
media_path.unlink(missing_ok=True)
|
||||
if file_extension == "jpg":
|
||||
media_path = Path(
|
||||
f"{os.path.join(CLIPS_DIR, media_name)}-clean.png"
|
||||
)
|
||||
media_path.unlink(missing_ok=True)
|
||||
except OSError as e:
|
||||
logger.warning(f"Unable to delete event images: {e}")
|
||||
if not deleted:
|
||||
logger.warning(
|
||||
f"Unable to delete event images for {expired.camera}: {expired.id}"
|
||||
)
|
||||
|
||||
# update the clips attribute for the db entry
|
||||
query = Event.select(Event.id).where(
|
||||
@@ -165,6 +159,7 @@ class EventCleanup(threading.Thread):
|
||||
Event.select(
|
||||
Event.id,
|
||||
Event.camera,
|
||||
Event.thumbnail,
|
||||
)
|
||||
.where(
|
||||
Event.camera == name,
|
||||
@@ -181,19 +176,12 @@ class EventCleanup(threading.Thread):
|
||||
# so no need to delete mp4 files
|
||||
for event in expired_events:
|
||||
events_to_update.append(event.id)
|
||||
deleted = delete_event_images(event)
|
||||
|
||||
try:
|
||||
media_name = f"{event.camera}-{event.id}"
|
||||
media_path = Path(
|
||||
f"{os.path.join(CLIPS_DIR, media_name)}.{file_extension}"
|
||||
if not deleted:
|
||||
logger.warning(
|
||||
f"Unable to delete event images for {event.camera}: {event.id}"
|
||||
)
|
||||
media_path.unlink(missing_ok=True)
|
||||
media_path = Path(
|
||||
f"{os.path.join(CLIPS_DIR, media_name)}-clean.png"
|
||||
)
|
||||
media_path.unlink(missing_ok=True)
|
||||
except OSError as e:
|
||||
logger.warning(f"Unable to delete event images: {e}")
|
||||
|
||||
# update the clips attribute for the db entry
|
||||
for i in range(0, len(events_to_update), CHUNK_SIZE):
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
"""Handle external events created by the user."""
|
||||
|
||||
import base64
|
||||
import datetime
|
||||
import logging
|
||||
import os
|
||||
@@ -15,7 +14,7 @@ from numpy import ndarray
|
||||
from frigate.comms.detections_updater import DetectionPublisher, DetectionTypeEnum
|
||||
from frigate.comms.events_updater import EventUpdatePublisher
|
||||
from frigate.config import CameraConfig, FrigateConfig
|
||||
from frigate.const import CLIPS_DIR
|
||||
from frigate.const import CLIPS_DIR, THUMB_DIR
|
||||
from frigate.events.types import EventStateEnum, EventTypeEnum
|
||||
from frigate.util.image import draw_box_with_label
|
||||
|
||||
@@ -55,9 +54,7 @@ class ExternalEventProcessor:
|
||||
rand_id = "".join(random.choices(string.ascii_lowercase + string.digits, k=6))
|
||||
event_id = f"{now}-{rand_id}"
|
||||
|
||||
thumbnail = self._write_images(
|
||||
camera_config, label, event_id, draw, snapshot_frame
|
||||
)
|
||||
self._write_images(camera_config, label, event_id, draw, snapshot_frame)
|
||||
end = now + duration if duration is not None else None
|
||||
|
||||
self.event_sender.publish(
|
||||
@@ -74,7 +71,6 @@ class ExternalEventProcessor:
|
||||
"camera": camera,
|
||||
"start_time": now - camera_config.record.event_pre_capture,
|
||||
"end_time": end,
|
||||
"thumbnail": thumbnail,
|
||||
"has_clip": camera_config.record.enabled and include_recording,
|
||||
"has_snapshot": True,
|
||||
"type": source_type,
|
||||
@@ -134,9 +130,9 @@ class ExternalEventProcessor:
|
||||
event_id: str,
|
||||
draw: dict[str, any],
|
||||
img_frame: Optional[ndarray],
|
||||
) -> Optional[str]:
|
||||
) -> None:
|
||||
if img_frame is None:
|
||||
return None
|
||||
return
|
||||
|
||||
# write clean snapshot if enabled
|
||||
if camera_config.snapshots.clean_copy:
|
||||
@@ -182,8 +178,9 @@ class ExternalEventProcessor:
|
||||
# create thumbnail with max height of 175 and save
|
||||
width = int(175 * img_frame.shape[1] / img_frame.shape[0])
|
||||
thumb = cv2.resize(img_frame, dsize=(width, 175), interpolation=cv2.INTER_AREA)
|
||||
ret, jpg = cv2.imencode(".jpg", thumb)
|
||||
return base64.b64encode(jpg.tobytes()).decode("utf-8")
|
||||
cv2.imwrite(
|
||||
os.path.join(THUMB_DIR, camera_config.name, f"{event_id}.webp"), thumb
|
||||
)
|
||||
|
||||
def stop(self):
|
||||
self.event_sender.stop()
|
||||
|
||||
@@ -23,7 +23,6 @@ def should_update_db(prev_event: Event, current_event: Event) -> bool:
|
||||
if (
|
||||
prev_event["top_score"] != current_event["top_score"]
|
||||
or prev_event["entered_zones"] != current_event["entered_zones"]
|
||||
or prev_event["thumbnail"] != current_event["thumbnail"]
|
||||
or prev_event["end_time"] != current_event["end_time"]
|
||||
or prev_event["average_estimated_speed"]
|
||||
!= current_event["average_estimated_speed"]
|
||||
@@ -202,7 +201,7 @@ class EventProcessor(threading.Thread):
|
||||
Event.start_time: start_time,
|
||||
Event.end_time: end_time,
|
||||
Event.zones: list(event_data["entered_zones"]),
|
||||
Event.thumbnail: event_data["thumbnail"],
|
||||
Event.thumbnail: event_data.get("thumbnail"),
|
||||
Event.has_clip: event_data["has_clip"],
|
||||
Event.has_snapshot: event_data["has_snapshot"],
|
||||
Event.model_hash: first_detector.model.model_hash,
|
||||
@@ -258,7 +257,7 @@ class EventProcessor(threading.Thread):
|
||||
Event.camera: event_data["camera"],
|
||||
Event.start_time: event_data["start_time"],
|
||||
Event.end_time: event_data["end_time"],
|
||||
Event.thumbnail: event_data["thumbnail"],
|
||||
Event.thumbnail: event_data.get("thumbnail"),
|
||||
Event.has_clip: event_data["has_clip"],
|
||||
Event.has_snapshot: event_data["has_snapshot"],
|
||||
Event.zones: [],
|
||||
|
||||
Reference in New Issue
Block a user