diff --git a/frigate/config.py b/frigate/config.py index 4e9d2f368..a6593e6ee 100644 --- a/frigate/config.py +++ b/frigate/config.py @@ -1277,10 +1277,19 @@ def verify_recording_retention(camera_config: CameraConfig) -> None: if ( camera_config.record.retain.days != 0 and rank_map[camera_config.record.retain.mode] - > rank_map[camera_config.record.events.retain.mode] + > rank_map[camera_config.record.alerts.retain.mode] ): logger.warning( - f"{camera_config.name}: Recording retention is configured for {camera_config.record.retain.mode} and event retention is configured for {camera_config.record.events.retain.mode}. The more restrictive retention policy will be applied." + f"{camera_config.name}: Recording retention is configured for {camera_config.record.retain.mode} and alert retention is configured for {camera_config.record.alerts.retain.mode}. The more restrictive retention policy will be applied." + ) + + if ( + camera_config.record.retain.days != 0 + and rank_map[camera_config.record.retain.mode] + > rank_map[camera_config.record.detections.retain.mode] + ): + logger.warning( + f"{camera_config.name}: Recording retention is configured for {camera_config.record.retain.mode} and detection retention is configured for {camera_config.record.detections.retain.mode}. The more restrictive retention policy will be applied." ) diff --git a/frigate/events/cleanup.py b/frigate/events/cleanup.py index 393aeea0b..e4c571be7 100644 --- a/frigate/events/cleanup.py +++ b/frigate/events/cleanup.py @@ -68,7 +68,10 @@ class EventCleanup(threading.Thread): def expire(self, media_type: EventCleanupType) -> list[str]: ## Expire events from unlisted cameras based on the global config if media_type == EventCleanupType.clips: - retain_config = self.config.record.events.retain + expire_days = max( + self.config.record.alerts.retain.days, + self.config.record.detections.retain.days, + ) file_extension = None # mp4 clips are no longer stored in /clips update_params = {"has_clip": False} else: @@ -82,7 +85,11 @@ class EventCleanup(threading.Thread): # loop over object types in db for event in distinct_labels: # get expiration time for this label - expire_days = retain_config.objects.get(event.label, retain_config.default) + if media_type == EventCleanupType.snapshots: + expire_days = retain_config.objects.get( + event.label, retain_config.default + ) + expire_after = ( datetime.datetime.now() - datetime.timedelta(days=expire_days) ).timestamp() @@ -132,7 +139,10 @@ class EventCleanup(threading.Thread): ## Expire events from cameras based on the camera config for name, camera in self.config.cameras.items(): if media_type == EventCleanupType.clips: - retain_config = camera.record.events.retain + expire_days = max( + camera.record.alerts.retain.days, + camera.record.detections.retain.days, + ) else: retain_config = camera.snapshots.retain @@ -142,9 +152,11 @@ class EventCleanup(threading.Thread): # loop over object types in db for event in distinct_labels: # get expiration time for this label - expire_days = retain_config.objects.get( - event.label, retain_config.default - ) + if media_type == EventCleanupType.snapshots: + expire_days = retain_config.objects.get( + event.label, retain_config.default + ) + expire_after = ( datetime.datetime.now() - datetime.timedelta(days=expire_days) ).timestamp() diff --git a/frigate/test/test_config.py b/frigate/test/test_config.py index f5592be19..28851da71 100644 --- a/frigate/test/test_config.py +++ b/frigate/test/test_config.py @@ -556,7 +556,7 @@ class TestConfig(unittest.TestCase): config = { "mqtt": {"host": "mqtt"}, "record": { - "events": {"retain": {"default": 20, "objects": {"person": 30}}} + "alerts": {"retain": {"days": 20 }} }, "cameras": { "back": { @@ -578,7 +578,7 @@ class TestConfig(unittest.TestCase): runtime_config = frigate_config.runtime_config() assert ( - runtime_config.cameras["back"].record.events.retain.objects["person"] == 30 + runtime_config.cameras["back"].record.alerts.retain.days == 20 ) def test_roles_listed_twice_throws_error(self): @@ -695,37 +695,6 @@ class TestConfig(unittest.TestCase): frigate_config.cameras["back"].zones["relative"].contour, ) - def test_clips_should_default_to_global_objects(self): - config = { - "mqtt": {"host": "mqtt"}, - "record": { - "events": {"retain": {"default": 20, "objects": {"person": 30}}} - }, - "objects": {"track": ["person", "dog"]}, - "cameras": { - "back": { - "ffmpeg": { - "inputs": [ - {"path": "rtsp://10.0.0.1:554/video", "roles": ["detect"]} - ] - }, - "detect": { - "height": 1080, - "width": 1920, - "fps": 5, - }, - "record": {"events": {}}, - } - }, - } - frigate_config = FrigateConfig(**config) - assert config == frigate_config.model_dump(exclude_unset=True) - - runtime_config = frigate_config.runtime_config() - back_camera = runtime_config.cameras["back"] - assert back_camera.record.events.objects is None - assert back_camera.record.events.retain.objects["person"] == 30 - def test_role_assigned_but_not_enabled(self): config = { "mqtt": {"host": "mqtt"},