fix duplicated styles, move fonts to src/assets/fonts for vite to bundle (nginx already rewrites correctly), and fix fast refresh for PreviewController, auth context/provider, and statusbar context
* update date-fns, i18next, react-dropzone, react-markdown and @types/node
react-i18next 17 peers `i18next >= 26.2.0`, so the two move together. react-day-picker already depends on date-fns 4, so date-fns now dedupes to a single copy. react-dropzone 20 declares `node >=22` in `engines`, but npm only warns on Node 20 and nothing in the build needs Node 22.
* update js-yaml, @hookform/resolvers and prettier
js-yaml 5 has no default export, so `DictAsYamlField` imports `dump`, `load` and `YAMLException` by name. @hookform/resolvers 5 types `zodResolver` with the schema's input and output types separately, and fields with defaults are optional on input, so the zone and classification model forms pass both types to `useForm`. zod's range now starts at 3.25, which resolvers 5 requires.
* format with prettier 3.9
* use the camera's model for the lpr vehicle check
`FrigateConfig.model` became `models[]` in the detector refactor, so this didn't compile on 0.19. Each camera has its own detector/model pair now, so the check resolves the camera's scene with `getModelForCamera` instead of looking at every model.
* use camera config model
* fix export test
Allow audio classes to be grouped under a shared configured label.
Keep audio overrides separate from object labels and retain only the highest-scoring grouped detection.
Refs #23967
* add sub stream recording with adaptive quality playback
Optionally record a second, lower bitrate stream alongside the main
recording stream via a `record_sub` input role and `record.sub` config block, with its own retention windows.
Recordings rows now carry the stream type plus the media details needed to serve both streams from one manifest: video codec, audio presence, audio codec and rate, and a record-time keyframe index.
Playback resolves coverage across both streams and merges them into a single VOD sequence, falling back to a discontinuity manifest with per-clip init segments when the media signatures differ. The player exposes a quality selector, and an auto governor picks the stream from stall time, bandwidth, codec support, and the save-data hint.
* fix tests and i18n
* Add combined motion and object Birdseye mode
Add a motion_objects mode that keeps Birdseye active when motion is detected or a confirmed tracked object is present, including stationary objects.
Wire the mode through configuration, runtime commands, API schemas, documentation, and UI labels. Exclude false-positive trackers and add regression coverage for Birdseye activation and MQTT validation.
* Refactor Birdseye activity types as booleans
Replace combination-specific Birdseye modes with composable boolean activity types for motion, active objects, stationary objects, and continuous display.
Preserve legacy single-mode configuration and MQTT inputs, support canonical comma-separated MQTT combinations, and allow scalar YAML values to be replaced by nested settings through the config API.
* Preserve OpenVINO config translations
Regenerate the configuration translations with the OpenVINO detector schema available so the unrelated production detector labels remain intact.
* Preserve partial Birdseye mode overrides
Allow an empty activity selection with a canonical NONE MQTT state so partial camera and profile overrides can disable inherited flags without failing validation.
Add regression coverage for camera and profile inheritance, document the NONE contract, and keep the generated schema fixture scoped to Birdseye.
* Address Birdseye activity review feedback
Move scalar mode compatibility into the 0.18-1 config migration and reject empty activity selections instead of publishing a NONE state.
Pass activity signals through a frozen dataclass, preserve existing active-object tracker behavior, and require confirmed stationary objects. Revert the generic YAML mutation and cover migration, inheritance, MQTT, and activation regressions.
* Move Birdseye migration to 0.19
Use the 0.19-0 configuration revision for converting scalar Birdseye modes to composable activity flags, and update the migration regression coverage accordingly.
* Remove Birdseye migration test
Drop the dedicated config migration test as requested during review while retaining the 0.19-0 migration implementation.
* run lpr on more vehicle types by default
before, a config change to attribute_map was required
* logging tweaks
* remove arg
* use attributes for frontend check
* docs
* only check thumbnail attributes the object can have
<camera>/notifications/suspended arrives as a string over the live connection but as a number in the camera_activity snapshot, and the truthiness guard dropped the numeric 0, so a camera with notifications off rendered as active after a reload. Normalize to a string and derive isSuspended instead of storing it.
* update network requirements docs for keras weights download
* fix manual PTZ relative moves permanently stopping object detection
* document available camera set features and link profiles docs to the API
* fix stale stream name field when switching cameras
The live streams and known plates fields rendered the map key as an uncontrolled input, so switching cameras left the previous camera's stream name on screen and would rename the wrong key if that stale text was committed. Both now use a shared MapKeyInput that resyncs with the form data and commits per keystroke, except while the typed name belongs to another entry, so the section is marked modified without waiting for blur.
* widen the logger name field in the per-process log level settings
* add details to timestamp error faq
* tweak genai docs
* tweak vector language
* Combine Qwen3.5 and Qwen3.6 listings
* fix openvino yolox detector crashing on every detection
The intermediate (N, 7) array in the yolox branch shadowed the pre-allocated (20, 6) detections buffer, so writing a detection into it raised "could not broadcast input array from shape (6,) into shape (7,)" on the first frame with anything above the confidence threshold. An empty frame also returned a (0, 7) array instead of the (20, 6) buffer.
Regressed in #13794, which renamed the intermediate from dets to detections as part of a cspell cleanup. Broken since 0.15.0.
---------
Co-authored-by: Nicolas Mowen <nickmowen213@gmail.com>
* resolve saved credential sentinel to the stored api_key in the GenAI probe
* add profile faq
* center the multi-camera export time range on the current playback position
* add faq about preview restart cache
* clarify exports bulk download
* Catch faces that become empty after cropping
* don't drop batched camera add/remove config updates
TrackedObjectProcessor drained all pending camera config updates at once but handled them in a mutually exclusive if/elif on enabled/add/remove, so only one topic was processed per drain. When an add arrived in the same batch as an enabled update, the add was skipped and the new camera never got a camera state. Adding a camera reliably produced that batch: config_set now re-applies runtime overrides, which republishes an enabled update for every previously toggled camera immediately before the add, in the same request. The dashboard and camera capture still saw the camera (the maintainer does not subscribe to enabled, so it got a clean add-only batch), but object_processing did not, and disabling the camera then crashed with a KeyError on the unguarded camera_states lookup.
Handle add and remove independently instead of as exclusive branches so a batched add is no longer dropped, and guard the remove lookup so a missing state is skipped rather than raising. Drop the enabled branch entirely: it only ever set prev_enabled when it was None, but prev_enabled is seeded to a bool at camera state creation and is never None (mypy flags the body as unreachable), and the actual enable/disable transition is already driven by the disabled-state loop from config.enabled.
* Don't stay on motion search page when user cancels flow
* fix notification test button being blocked by websocket auth
* fix overflowing model names in settings genai widget
* add note about auth debugging
---------
Co-authored-by: Nicolas Mowen <nickmowen213@gmail.com>
* resolve zone friendly names against the correct camera
* Improve handling of zone names in chat prompt
* show a numeric keyboard for numeric config form fields on mobile
* Specify english only for semantic search tool when model is JinaV1
* resolve export hwaccel args global value against the correct config path
---------
Co-authored-by: Nicolas Mowen <nickmowen213@gmail.com>
* display zone names consistently using friendly_name or raw id without transformation
* enforce camera-level access on go2rtc live stream websocket endpoints
* slightly darken bg-card
* change menu label
* move snapshot retain out of advanced fields
* add new ui options for collapsibles
* backend title and description
* remove unused snapshot retention field
* update reference config
* remove further references to snapshots retain.mode
* update e2e mock data to remove deprecated fields
* remove scream audio label
scream was never mapped to anything in frigate's custom labelmap, yell is used everywhere
* document common audio labels
* deprecate ffmpeg 5
* language tweak
* add field message to recommend presets instead of manual hwaccel args
* add guidance to docs on choosing a detect fps
* refactor go2rtc docs
* clarify go2rtc language in live
* add export docs
* Move around config items to reflect reference config is now for advanced users
* Remove outdated ipv6 section
* Fix broken links
* live usage docs
* review usage docs
* history usage
* explore usage
* add usage sidebar and move related text to usage sections
* update links
* update live
* move exports to usage
* fix anchors
* Make starts of usage pages consistent
* refactor network config
* Adjustments for review
* Add AI details to history page
* describe alerts vs detections in review usage
* simplify
---------
Co-authored-by: Nicolas Mowen <nickmowen213@gmail.com>
* serialize OpenVINO inference per process to prevent concurrent-inference segfault
* clean up
* add max scaling meta to login page
* add more detect section field messages
* fix icon layout in settings field messages
* tweak edit icon color
* add ptz presets and default role widgets
* language tweaks
* fix width in triggers view
* tweak iOS PWA message in notifications settings
* deprecate ui.date_style and ui.time_style
these have been unused since date/time formatting has been pushed to i18n
* add config migrator to remove date_style and time_style
* remove date_style and time_style from reference config
* fix camera list scrolling in state classification wizard on mobile
* remove redundant per-view toasters in settings
* add variants to standardize dialog footer button layouts
* remove text-md
this class name compiles to nothing in tailwind. we used to add it to prevent iOS from zooming when focusing on an input, but that is now solved via the viewport meta in index.html
* make wizard footers consistent with dialog footers
* consistent destructive button style
remove text-white from individual buttons and add it to the variant
* add review padding to explore debug replay api calls
* add semantic search model size widget
disables model_size select with n/a text when an embeddings genai provider is selected
* regenerate zone contours and per-zone filter masks on detect resolution change
* treat null as a clear sentinel in buildOverrides so nullable field edits don't snap back
* extract replay config sheet to new component
* add validation and messages for detect settings
* unlink shm frames when camera is removed
* drop stale shm cache refs when cached segment is too small for requested shape
* skip new-object frame cache write when current_frame is unavailable
* add tests
* use setdefault when adding a new camera
Multiple subscribers in the same process each unpickle the ZMQ payload independently and would otherwise write divergent Python objects to the shared cameras dict — leaving long-lived references (e.g. CameraState.camera_config) pointing at a copy that subsequent in-place mutations like apply_section_update can never reach. setdefault collapses everyone onto the first writer's object so attribute mutations propagate to every consumer in this process.
* rebuild ffmpeg commands on detect update
Rebuild the cached ffmpeg cmd so the next process spawn picks up new resolution/fps. Running cameras keep their existing cmd (ffmpeg_cmds is only read at process startup); replay cameras are recycled by CameraMaintainer to pick up the rebuilt cmd
* drop stale shm cache refs when cached segment size doesn't match requested shape
The cached SharedMemoryFrameManager reference can point at a segment whose
size no longer matches the requested shape — the segment was unlinked and
recreated at a different size in a camera add/remove cycle. This catches
both a resolution increase (cached too small) and a decrease (cached too
large, pointing at an orphaned inode whose stale bytes would otherwise be
misinterpreted at the new shape, producing distorted/miscolored YUV frames).
After reopening, if the OS-level segment still doesn't match the requested
shape we're in a transient mid-recreate state — either the maintainer
hasn't allocated the new segment yet (size too small) or we opened a
pre-recycle segment (size too big). Either way, skip the frame and don't
cache the mismatched ref.
* recycle replay camera on detect update
* discard tracked-object state when detect resolution changes mid-session
When detect resolution changes mid-session every tracked object we hold
was localized against the old pixel grid. Their boxes no longer
correspond to anything in the new frame, and the `end` callback that
fires when their IDs disappear from the new detect process's detections
publishes those stale boxes to consumers (LPR, snapshot crop) that slice
the new frame and crash on empty arrays. Drop the tracked-object state
on a shape change so no stale boxes ever cross the CameraState boundary.
Belt-and-suspenders: also drop any incoming batch whose boxes exceed the
current detect resolution. These are in-flight queue entries from the
pre-recycle detect process that beat the new detect process to the
queue; processing them would re-introduce stale-resolution tracked
objects we just dropped above. The per-camera detect process clamps
legitimate boxes to detect.width-1 / detect.height-1, so any coord
beyond that is unambiguously stale.
* rebuild motion and object filter masks on detect resolution change
Apply the detect update first so frame_shape reflects the new resolution
before we rebuild dependents.
Motion's rasterized_mask is sized to frame_shape at construction. When
detect resolution changes we must rebuild RuntimeMotionConfig so the
mask matches the new frame size; otherwise consumers like the LPR
processor and motion detector hit a shape mismatch when they index
frames with the stale mask.
Same story for per-object filter masks — rebuild RuntimeFilterConfig at
the new frame_shape so the merged global+per-object masks they hold
match what they'll be indexed against.
* republish motion and objects on in-memory detect resize
A detect resolution change also invalidates the rasterized masks on
motion and per-object filters. apply_section_update has rebuilt them at
the new frame_shape; publish them too so other processes replace their
old values.
* add test
* frontend
* add refresh topic for camera maintainer recycle action
The maintainer's recycle branch is doing an action (recycle the camera)
in response to a section-level signal. Introduce a
CameraConfigUpdateEnum.refresh case as an explicit action signal — the
maintainer subscribes to refresh instead of detect, parallel with add
and remove. Publishers fire refresh alongside detect when a recycle is
needed; section-level subscribers keep their existing topic.
Since no main-process subscriber listens for detect anymore, the
refresh handler calls recreate_ffmpeg_cmds() explicitly so the shared
CameraConfig's ffmpeg_cmds is rebuilt before the new subprocesses
spawn.
* factor stale-resolution state drop into a CameraState method
* use monotonic clock for detector inference duration to prevent negative values from wall clock steps
* add ability to set camera's webui_url from camera management pane
* Gemini send thought signature
* Update docs
* copy face and lpr configs from source camera to replay camera
* add guard
* improve dummy camera docs
* remove version number
* fix stale field message after reverting a conditional form field
Routes field-level conditional messages through a dedicated React Context instead of merging them into uiSchema. RJSF's Form keeps state.uiSchema sticky across renders during processPendingChange (formData is updated, uiSchema is not), so a previously injected ui:messages array stays attached to a field even after the triggering condition flips back to false. Context propagation re-runs FieldTemplate directly on every provider value change, sidestepping that staleness.
* add semantic search field message to note that model_size is irrelevant when embeddings provider is selected
---------
Co-authored-by: Nicolas Mowen <nickmowen213@gmail.com>
* filter replay camera from camera selectors
* add face rec and lpr to replay configuration sheet
* add missing config topic subscriptions in embeddings maintainer
* pop replay camera from config object when stopping
* render orphaned filter entries as collapsibles instead of the Key/Value editor
* Symlink for various AI files
* change replay confg dialog to platform aware sheet
* change agents title
* fix test
* tweak collapsible
* remove camera ui section in settings
no point to having it anymore with profiles and camera management settings
* fix admin response cache leak to non-admin users via nginx proxy_cache
* add model fetcher endpoint for genai config ui
---------
Co-authored-by: Nicolas Mowen <nickmowen213@gmail.com>
* preserve user-set min_score on attribute filters instead of bumping any 0.5 value
use model_fields_set to distinguish "user explicitly set min_score" from "Pydantic applied the generic FilterConfig default of 0.5"
* add config test for attributes
* fix attributes frontend type
* add expanded hidden field context
* extend schema modification
* special case for attributes
* i18n for attributes
* handle dedicated lpr mode
* strip unrendered FilterConfig fields from attribute filter form data to fix validation errors
* 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>
* detector UI fixes
- derive detector and model from memo rather than using two drain useeffects
- sanitize save payload through sanitizeSectionData to prevent yaml validation issues
* increase display duration for restart required toasts
* mimic logic in detector section for save all button
also, increase toast duration for restart required toasts
* fixes and tweaks
- use section hidden fields for sanitization instead of duplicating code
- use parent hooks so save all, pending data, and the status dots work correctly
* add embedded mode to BaseSection so parents can host the save action
* add optional action slot to current Frigate+ model summary
* add w-full to action slot flex wrapper for explicit width contract
* i18n
* merged detectors and model settings view
* fix document title
* Embed detector form in merged settings view
* add detection model card with tabs and custom model embed
* add Frigate+ model selector with filter popover to merged page
* Add mismatch banner and gate save on detector and model compatibility
* Wire atomic save, restart toast, and undo on detectors and model page
* Clear child pending data on undo
* route merged detectors and model view in settings
* trim Frigate+ page to account-only and remove old detection model view
* basic e2e
* Fix unsaved-changes guard, custom path leak, and post-failure cache resync
* Rename to Detectors and model, float Modified badge, use ConfigMessageBanner for mismatch
* Hide Plus/Custom tabs when Frigate+ is not enabled
* Detect active Plus model via model.plus.id instead of path prefix
* Sync state back to snapshot when child form un-modifies and remount on undo
* Always require restart on save since model changes also need one
* Wrap Frigate+ model selector in SplitCardRow with label and description
* rename tab
* update docs
* sync top-level model with default detector's resolved model
when the user doesn't define a top-level `model:` block, `FrigateConfig.model` stayed at pydantic field defaults (320×320, /labelmap.txt) while the per-detector model picked up `DEFAULT_MODEL` for openvino on cpu (300×300, coco_91cl_bkgr.txt introduced in #23127), causing `RemoteObjectDetector` to fail with "buffer is too small for requested array" because the SHM was sized from the per-detector model but mapped using the top-level one. After the detector loop, copy the first detector's resolved model up to `self.model` so both sides agree on dimensions and labelmap
* revert to cpu detector by default
use openvino cpu for new configs only
* add defaults
* sync filter entries with track and listen labels
- Auto-populate `audio.filters` from `audio.listen` instead of the full audio labelmap, matching how `objects.filters` is keyed by `track` (no longer need to populate the full audio labelmap, which was added in #22630)
- Synthesize the matching filter entries in the settings form on load so each track/listen label shows its collapsible after a profile is selected, since the backend's auto-populate only runs at config init
* translate main label for lifecycle description with attribute
* reject restricted go2rtc stream sources when added via api
* add env var check function
* improve scroll handling for non-modal DropdownMenu in classification and face selection dialogs
* clean up
* fix incorrect key capitalization
* fix profile array overrides not replacing base arrays
don't use lodash merge(), it does positional merging and an empty source array doesn't override the destination, and shorter arrays leak destination elements through.
backend is unaffected, so the saved config and actual backend functionality was right
* only show audio debug tab when audio is enabled in config
* move apple_compatibility out of advanced
* remove retry_interval from UI
99% of users should never be changing this
* hide switch in optionalfieldwidget if editing a profile
* add override badges for cameras and profiles
collect shared functions into the config util and separate hooks
* Use new models endpoint info to determine modalities
* clarify language
* fix linter
---------
Co-authored-by: Nicolas Mowen <nickmowen213@gmail.com>