mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-02-05 18:55:23 +03:00
Refactor event and timeline cleanup
This commit is contained in:
parent
913d0e630e
commit
bd11ba357b
@ -10,7 +10,7 @@ from pathlib import Path
|
|||||||
|
|
||||||
from frigate.config import FrigateConfig
|
from frigate.config import FrigateConfig
|
||||||
from frigate.const import CLIPS_DIR
|
from frigate.const import CLIPS_DIR
|
||||||
from frigate.models import Event
|
from frigate.models import Event, Timeline
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -61,7 +61,7 @@ class EventCleanup(threading.Thread):
|
|||||||
|
|
||||||
return self.camera_labels[camera]["labels"]
|
return self.camera_labels[camera]["labels"]
|
||||||
|
|
||||||
def expire(self, media_type: EventCleanupType) -> None:
|
def expire(self, media_type: EventCleanupType) -> list[str]:
|
||||||
## Expire events from unlisted cameras based on the global config
|
## Expire events from unlisted cameras based on the global config
|
||||||
if media_type == EventCleanupType.clips:
|
if media_type == EventCleanupType.clips:
|
||||||
retain_config = self.config.record.events.retain
|
retain_config = self.config.record.events.retain
|
||||||
@ -111,6 +111,8 @@ class EventCleanup(threading.Thread):
|
|||||||
)
|
)
|
||||||
update_query.execute()
|
update_query.execute()
|
||||||
|
|
||||||
|
events_to_update = []
|
||||||
|
|
||||||
## Expire events from cameras based on the camera config
|
## Expire events from cameras based on the camera config
|
||||||
for name, camera in self.config.cameras.items():
|
for name, camera in self.config.cameras.items():
|
||||||
if media_type == EventCleanupType.clips:
|
if media_type == EventCleanupType.clips:
|
||||||
@ -142,6 +144,8 @@ class EventCleanup(threading.Thread):
|
|||||||
# only snapshots are stored in /clips
|
# only snapshots are stored in /clips
|
||||||
# so no need to delete mp4 files
|
# so no need to delete mp4 files
|
||||||
for event in expired_events:
|
for event in expired_events:
|
||||||
|
events_to_update.append(event.id)
|
||||||
|
|
||||||
if media_type == EventCleanupType.snapshots:
|
if media_type == EventCleanupType.snapshots:
|
||||||
media_name = f"{event.camera}-{event.id}"
|
media_name = f"{event.camera}-{event.id}"
|
||||||
media_path = Path(
|
media_path = Path(
|
||||||
@ -153,14 +157,9 @@ class EventCleanup(threading.Thread):
|
|||||||
)
|
)
|
||||||
media_path.unlink(missing_ok=True)
|
media_path.unlink(missing_ok=True)
|
||||||
|
|
||||||
# update the clips attribute for the db entry
|
# update the clips attribute for the db entry
|
||||||
update_query = Event.update(update_params).where(
|
Event.update(update_params).where(Event.id << events_to_update).execute()
|
||||||
Event.camera == name,
|
return events_to_update
|
||||||
Event.start_time < expire_after,
|
|
||||||
Event.label == event.label,
|
|
||||||
Event.retain_indefinitely == False,
|
|
||||||
)
|
|
||||||
update_query.execute()
|
|
||||||
|
|
||||||
def purge_duplicates(self) -> None:
|
def purge_duplicates(self) -> None:
|
||||||
duplicate_query = """with grouped_events as (
|
duplicate_query = """with grouped_events as (
|
||||||
@ -197,7 +196,13 @@ class EventCleanup(threading.Thread):
|
|||||||
def run(self) -> None:
|
def run(self) -> None:
|
||||||
# only expire events every 5 minutes
|
# only expire events every 5 minutes
|
||||||
while not self.stop_event.wait(300):
|
while not self.stop_event.wait(300):
|
||||||
self.expire(EventCleanupType.clips)
|
events_with_expired_clips = self.expire(EventCleanupType.clips)
|
||||||
|
|
||||||
|
# delete timeline entries for events that have expired recordings
|
||||||
|
Timeline.delete().where(
|
||||||
|
Timeline.source_id << events_with_expired_clips
|
||||||
|
).execute()
|
||||||
|
|
||||||
self.expire(EventCleanupType.snapshots)
|
self.expire(EventCleanupType.snapshots)
|
||||||
self.purge_duplicates()
|
self.purge_duplicates()
|
||||||
|
|
||||||
|
|||||||
@ -140,15 +140,6 @@ class RecordingCleanup(threading.Thread):
|
|||||||
Path(recording.path).unlink(missing_ok=True)
|
Path(recording.path).unlink(missing_ok=True)
|
||||||
deleted_recordings.add(recording.id)
|
deleted_recordings.add(recording.id)
|
||||||
|
|
||||||
# delete timeline entries relevant to this recording segment
|
|
||||||
Timeline.delete().where(
|
|
||||||
Timeline.timestamp.between(
|
|
||||||
recording.start_time, recording.end_time
|
|
||||||
),
|
|
||||||
Timeline.timestamp < expire_date,
|
|
||||||
Timeline.camera == camera,
|
|
||||||
).execute()
|
|
||||||
|
|
||||||
logger.debug(f"Expiring {len(deleted_recordings)} recordings")
|
logger.debug(f"Expiring {len(deleted_recordings)} recordings")
|
||||||
# delete up to 100,000 at a time
|
# delete up to 100,000 at a time
|
||||||
max_deletes = 100000
|
max_deletes = 100000
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user