Write recording segments to cache with timezone info (#8468)

* Store recording segments with timezone info

* Don't use _

* Use different separator due to timezone
This commit is contained in:
Nicolas Mowen
2023-11-05 13:30:29 -07:00
committed by GitHub
parent 4c05ef48a7
commit 89dd114da1
4 changed files with 43 additions and 31 deletions

View File

@@ -20,6 +20,7 @@ import psutil
from frigate.config import FrigateConfig, RetainModeEnum
from frigate.const import (
CACHE_DIR,
CACHE_SEGMENT_FORMAT,
INSERT_MANY_RECORDINGS,
MAX_SEGMENT_DURATION,
RECORD_DIR,
@@ -74,15 +75,13 @@ class RecordingMaintainer(threading.Thread):
self.end_time_cache: dict[str, Tuple[datetime.datetime, float]] = {}
async def move_files(self) -> None:
cache_files = sorted(
[
d
for d in os.listdir(CACHE_DIR)
if os.path.isfile(os.path.join(CACHE_DIR, d))
and d.endswith(".mp4")
and not d.startswith("clip_")
]
)
cache_files = [
d
for d in os.listdir(CACHE_DIR)
if os.path.isfile(os.path.join(CACHE_DIR, d))
and d.endswith(".mp4")
and not d.startswith("clip_")
]
files_in_use = []
for process in psutil.process_iter():
@@ -106,8 +105,12 @@ class RecordingMaintainer(threading.Thread):
cache_path = os.path.join(CACHE_DIR, cache)
basename = os.path.splitext(cache)[0]
camera, date = basename.rsplit("-", maxsplit=1)
start_time = datetime.datetime.strptime(date, "%Y%m%d%H%M%S")
camera, date = basename.rsplit("@", maxsplit=1)
# important that start_time is utc because recordings are stored and compared in utc
start_time = datetime.datetime.strptime(
date, CACHE_SEGMENT_FORMAT
).astimezone(datetime.timezone.utc)
grouped_recordings[camera].append(
{
@@ -119,6 +122,11 @@ class RecordingMaintainer(threading.Thread):
# delete all cached files past the most recent 5
keep_count = 5
for camera in grouped_recordings.keys():
# sort based on start time
grouped_recordings[camera] = sorted(
grouped_recordings[camera], key=lambda s: s["start_time"]
)
segment_count = len(grouped_recordings[camera])
if segment_count > keep_count:
logger.warning(
@@ -218,7 +226,7 @@ class RecordingMaintainer(threading.Thread):
# if cached file's start_time is earlier than the retain days for the camera
if start_time <= (
(
datetime.datetime.now()
datetime.datetime.now().astimezone(datetime.timezone.utc)
- datetime.timedelta(
days=self.config.cameras[camera].record.retain.days
)
@@ -262,8 +270,8 @@ class RecordingMaintainer(threading.Thread):
)
retain_cutoff = datetime.datetime.fromtimestamp(
most_recently_processed_frame_time - pre_capture
).astimezone(datetime.timezone.utc)
if end_time.astimezone(datetime.timezone.utc) < retain_cutoff:
)
if end_time < retain_cutoff:
Path(cache_path).unlink(missing_ok=True)
self.end_time_cache.pop(cache_path, None)
# else retain days includes this segment
@@ -275,10 +283,11 @@ class RecordingMaintainer(threading.Thread):
)
# ensure delayed segment info does not lead to lost segments
if datetime.datetime.fromtimestamp(
most_recently_processed_frame_time
).astimezone(datetime.timezone.utc) >= end_time.astimezone(
datetime.timezone.utc
if (
datetime.datetime.fromtimestamp(
most_recently_processed_frame_time
).astimezone(datetime.timezone.utc)
>= end_time
):
record_mode = self.config.cameras[camera].record.retain.mode
return await self.move_segment(
@@ -345,18 +354,18 @@ class RecordingMaintainer(threading.Thread):
self.end_time_cache.pop(cache_path, None)
return
# directory will be in utc due to start_time being in utc
directory = os.path.join(
RECORD_DIR,
start_time.astimezone(tz=datetime.timezone.utc).strftime("%Y-%m-%d/%H"),
start_time.strftime("%Y-%m-%d/%H"),
camera,
)
if not os.path.exists(directory):
os.makedirs(directory)
file_name = (
f"{start_time.replace(tzinfo=datetime.timezone.utc).strftime('%M.%S.mp4')}"
)
# file will be in utc due to start_time being in utc
file_name = f"{start_time.strftime('%M.%S.mp4')}"
file_path = os.path.join(directory, file_name)
try: