Compare commits

...
Author SHA1 Message Date
Josh Hawkins a0300864ca round preview skeleton corners to match the player 2026-10-25 11:52:36 -05:00
Josh Hawkins f236b1a0c0 only log ffmpeg crashes when restarting 2026-10-25 11:46:53 -05:00
Josh Hawkins 22e478cd82 stagger the daily region grid rebuild across cameras
Every camera requested its region grid at exactly 02:00, so the requests queued up in the dispatcher and held up recording segment inserts behind them. Each camera now picks a random offset of up to an hour.
2026-10-25 11:46:53 -05:00
3 changed files with 18 additions and 11 deletions
+6 -3
View File
@@ -2,10 +2,11 @@
import logging
import queue
import random
import threading
import time
from collections import deque
from datetime import UTC, datetime
from datetime import UTC, datetime, timedelta
from multiprocessing import Queue
from multiprocessing.synchronize import Event as MpEvent
from typing import Any
@@ -255,7 +256,9 @@ def process_frames(
region_grid: list[list[dict[str, Any]]],
exit_on_empty: bool = False,
):
next_region_update = get_tomorrow_at_time(2)
# cameras share one dispatcher, so stagger the daily grid rebuilds
region_update_offset = timedelta(seconds=random.randrange(3600))
next_region_update = get_tomorrow_at_time(2) + region_update_offset
config_subscriber = CameraConfigUpdateSubscriber(
None,
{camera_config.name: camera_config},
@@ -344,7 +347,7 @@ def process_frames(
if updated_grid:
region_grid = updated_grid
next_region_update = get_tomorrow_at_time(2)
next_region_update = get_tomorrow_at_time(2) + region_update_offset
try:
if exit_on_empty:
+6 -6
View File
@@ -474,10 +474,10 @@ class CameraWatchdog(threading.Thread):
if not self.capture_thread.is_alive():
self.detect_status.send("offline", now)
self.camera_fps.value = 0
self.logger.error(
f"Ffmpeg process crashed unexpectedly for {self.config.name}."
)
if can_restart:
self.logger.error(
f"Ffmpeg process crashed unexpectedly for {self.config.name}."
)
self.reset_capture_thread(terminate=False)
last_restart_time = now
elif self.camera_fps.value >= (self.config.detect.fps + 10):
@@ -498,10 +498,10 @@ class CameraWatchdog(threading.Thread):
elif now - self.capture_thread.current_frame.value > 20:
self.detect_status.send("offline", now)
self.camera_fps.value = 0
self.logger.info(
f"No frames received from {self.config.name} in 20 seconds. Exiting ffmpeg..."
)
if can_restart:
self.logger.info(
f"No frames received from {self.config.name} in 20 seconds. Exiting ffmpeg..."
)
self.reset_capture_thread()
last_restart_time = now
else:
+6 -2
View File
@@ -332,7 +332,9 @@ function PreviewVideoPlayer({
{t("noPreviewFoundFor", { cameraName: cameraName })}
</div>
)}
{firstLoad && <Skeleton className="absolute aspect-video size-full" />}
{firstLoad && (
<Skeleton className="absolute aspect-video size-full rounded-lg md:rounded-2xl" />
)}
</div>
);
}
@@ -555,7 +557,9 @@ function PreviewFramesPlayer({
{t("noPreviewFoundFor", { cameraName: cameraName })}
</div>
)}
{firstLoad && <Skeleton className="absolute aspect-video size-full" />}
{firstLoad && (
<Skeleton className="absolute aspect-video size-full rounded-lg md:rounded-2xl" />
)}
</div>
);
}