Miscellaneous fixes (#23238)
CI / ARM Build (push) Waiting to run
CI / Jetson Jetpack 6 (push) Waiting to run
CI / AMD64 Extra Build (push) Blocked by required conditions
CI / ARM Extra Build (push) Blocked by required conditions
CI / Synaptics Build (push) Blocked by required conditions
CI / Assemble and push default build (push) Blocked by required conditions
CI / AMD64 Build (push) Waiting to run

* start audio transcription post processor when enabled on any camera

* Fetch embed key whenever an error occurs in case the llama server was restarted

* mypy

* add tooltips for colored dots in settings menu

* add ability to reorder cameras from management pane

* add ability to reorder birdseye

* add reordering save text to camera management view

* Include NPU in latency performance hint

* Implement turbo for NPU on object detection

* hide order fields

* drop auto-derived field paths from camera value when unset globally

* use correct field type for export hwaccel args

* add debug replay to detail actions menu

* clarify debug replay in docs

* guard get_current_frame_time against missing camera state

* Implement debug reply from export

* Refactor debug replay to use sources for dynamic playback

* Mypy

* fix debug export replay source timestamp handling

* skip replay cameras in stats immediately

* broadcast debug replay state over ws and buffer pre-OPEN sends

- push debug replay session state over the job_state ws topic so the status bar reacts instantly to start/stop without polling
- fix child-effect-before-parent-effect race in WsProvider that silently dropped initial snapshot requests on cold load

* fix debug replay test hang

---------

Co-authored-by: Nicolas Mowen <nickmowen213@gmail.com>
This commit is contained in:
Josh Hawkins
2026-05-18 22:52:40 -05:00
committed by GitHub
co-authored by Nicolas Mowen
parent d968f00500
commit 43d97acd21
28 changed files with 1176 additions and 170 deletions
@@ -15,11 +15,12 @@ class TestDebugReplayAPI(BaseTestHttp):
# Stub the factory to skip validation/threading and just record the
# name on the manager the way the real factory's mark_starting would.
def fake_start(**kwargs):
source = kwargs["source"]
kwargs["replay_manager"].mark_starting(
source_camera=kwargs["source_camera"],
source_camera=source.source_camera,
replay_camera_name="_replay_front",
start_ts=kwargs["start_ts"],
end_ts=kwargs["end_ts"],
start_ts=source.start_ts,
end_ts=source.end_ts,
)
return "job-1234"
+8
View File
@@ -71,6 +71,14 @@ class TestDebugReplayManagerSession(unittest.TestCase):
class TestDebugReplayManagerStop(unittest.TestCase):
def setUp(self) -> None:
# stop() publishes a terminal job_state via a real JobStatePublisher,
# which opens a ZMQ REQ socket and blocks on REP. No dispatcher runs
# in unit tests, so substitute a no-op publisher.
patcher = patch("frigate.debug_replay.JobStatePublisher")
patcher.start()
self.addCleanup(patcher.stop)
def test_stop_when_inactive_is_a_noop(self) -> None:
from frigate.debug_replay import DebugReplayManager
+28 -27
View File
@@ -9,6 +9,7 @@ from unittest.mock import MagicMock, patch
from frigate.debug_replay import DebugReplayManager
from frigate.jobs.debug_replay import (
DebugReplayJob,
RecordingDebugReplaySource,
cancel_debug_replay_job,
get_active_runner,
start_debug_replay_job,
@@ -99,9 +100,9 @@ class TestStartDebugReplayJob(unittest.TestCase):
def test_rejects_unknown_camera(self) -> None:
with self.assertRaises(ValueError):
start_debug_replay_job(
source_camera="missing",
start_ts=100.0,
end_ts=200.0,
source=RecordingDebugReplaySource(
source_camera="missing", start_ts=100.0, end_ts=200.0
),
frigate_config=self.frigate_config,
config_publisher=self.publisher,
replay_manager=self.manager,
@@ -110,9 +111,9 @@ class TestStartDebugReplayJob(unittest.TestCase):
def test_rejects_invalid_time_range(self) -> None:
with self.assertRaises(ValueError):
start_debug_replay_job(
source_camera="front",
start_ts=200.0,
end_ts=100.0,
source=RecordingDebugReplaySource(
source_camera="front", start_ts=200.0, end_ts=100.0
),
frigate_config=self.frigate_config,
config_publisher=self.publisher,
replay_manager=self.manager,
@@ -124,9 +125,9 @@ class TestStartDebugReplayJob(unittest.TestCase):
with patch("frigate.jobs.debug_replay.query_recordings", return_value=empty_qs):
with self.assertRaises(ValueError):
start_debug_replay_job(
source_camera="front",
start_ts=100.0,
end_ts=200.0,
source=RecordingDebugReplaySource(
source_camera="front", start_ts=100.0, end_ts=200.0
),
frigate_config=self.frigate_config,
config_publisher=self.publisher,
replay_manager=self.manager,
@@ -154,9 +155,9 @@ class TestStartDebugReplayJob(unittest.TestCase):
patch("builtins.open", unittest.mock.mock_open()),
):
job_id = start_debug_replay_job(
source_camera="front",
start_ts=100.0,
end_ts=200.0,
source=RecordingDebugReplaySource(
source_camera="front", start_ts=100.0, end_ts=200.0
),
frigate_config=self.frigate_config,
config_publisher=self.publisher,
replay_manager=self.manager,
@@ -191,9 +192,9 @@ class TestStartDebugReplayJob(unittest.TestCase):
patch("builtins.open", unittest.mock.mock_open()),
):
start_debug_replay_job(
source_camera="front",
start_ts=100.0,
end_ts=200.0,
source=RecordingDebugReplaySource(
source_camera="front", start_ts=100.0, end_ts=200.0
),
frigate_config=self.frigate_config,
config_publisher=self.publisher,
replay_manager=self.manager,
@@ -201,9 +202,9 @@ class TestStartDebugReplayJob(unittest.TestCase):
with self.assertRaises(RuntimeError):
start_debug_replay_job(
source_camera="front",
start_ts=100.0,
end_ts=200.0,
source=RecordingDebugReplaySource(
source_camera="front", start_ts=100.0, end_ts=200.0
),
frigate_config=self.frigate_config,
config_publisher=self.publisher,
replay_manager=self.manager,
@@ -269,9 +270,9 @@ class TestRunnerHappyPath(unittest.TestCase):
patch("builtins.open", unittest.mock.mock_open()),
):
start_debug_replay_job(
source_camera="front",
start_ts=100.0,
end_ts=200.0,
source=RecordingDebugReplaySource(
source_camera="front", start_ts=100.0, end_ts=200.0
),
frigate_config=self.frigate_config,
config_publisher=self.publisher,
replay_manager=self.manager,
@@ -340,9 +341,9 @@ class TestRunnerFailurePath(unittest.TestCase):
patch("builtins.open", unittest.mock.mock_open()),
):
start_debug_replay_job(
source_camera="front",
start_ts=100.0,
end_ts=200.0,
source=RecordingDebugReplaySource(
source_camera="front", start_ts=100.0, end_ts=200.0
),
frigate_config=self.frigate_config,
config_publisher=self.publisher,
replay_manager=self.manager,
@@ -418,9 +419,9 @@ class TestRunnerCancellation(unittest.TestCase):
patch("builtins.open", unittest.mock.mock_open()),
):
start_debug_replay_job(
source_camera="front",
start_ts=100.0,
end_ts=200.0,
source=RecordingDebugReplaySource(
source_camera="front", start_ts=100.0, end_ts=200.0
),
frigate_config=self.frigate_config,
config_publisher=self.publisher,
replay_manager=self.manager,
+1 -1
View File
@@ -230,7 +230,7 @@ class TestExportResolution(unittest.TestCase):
id=export_id,
camera=camera,
name=f"export-{export_id}",
date=datetime.datetime.now(),
date=int(datetime.datetime.now().timestamp()),
video_path=f"/media/frigate/exports/{filename}",
thumb_path=f"/media/frigate/exports/{filename}.jpg",
in_progress=False,