Commit Graph
1749 Commits
Author SHA1 Message Date
Josh Hawkins 2455e8be79 add confirmation dialog for clearing groups and streaming settings 2026-09-24 13:27:29 -05:00
Josh Hawkins 1f5972426e fix merge conflict 2026-09-24 13:27:29 -05:00
Josh Hawkins 5ddcf96756 hide natural aspect and layout import on phones 2026-09-24 13:27:29 -05:00
Josh Hawkins e760868048 rework live dashboard grid layout and add natural mode 2026-09-24 13:26:57 -05:00
007hacky007andGitHub 40f8ba1f7f Offer the full playback rate list on Safari (#24444)
CI / AMD64 Build (push) Canceled after 0s
CI / AMD64 Smoke Test (push) Canceled after 0s
CI / ARM Build (push) Canceled after 0s
CI / Jetson Jetpack 6 (push) Canceled after 0s
CI / AMD64 Extra Build (push) Canceled after 0s
CI / ARM Extra Build (push) Canceled after 0s
CI / Synaptics Build (push) Canceled after 0s
CI / Assemble and push default build (push) Canceled after 0s
2026-09-24 10:02:06 -05:00
Josh HawkinsandGitHub 52f50a7396 Tweaks (#24418)
CI / AMD64 Build (push) Canceled after 0s
CI / AMD64 Smoke Test (push) Canceled after 0s
CI / ARM Build (push) Canceled after 0s
CI / Jetson Jetpack 6 (push) Canceled after 0s
CI / AMD64 Extra Build (push) Canceled after 0s
CI / ARM Extra Build (push) Canceled after 0s
CI / Synaptics Build (push) Canceled after 0s
CI / Assemble and push default build (push) Canceled after 0s
* don't display audio transcription provider message as health notice

* show remote provider for audio transcription in health pane

* adjust trigger and notifications messages to be consistent with the rest of the settings UI

* disable save buttons when there are no changes in config editor

* fix audio manager crash when a camera is added at runtime

The audio processor and the camera maintainer both poll the same `add` config update on their own one second timers, and the maintainer is what creates `camera_metrics[name]`. When the audio processor got there first it looked the new camera up before that entry existed, and the `KeyError` took down the whole `frigate.audio_manager` process. Whether it happens depends purely on which poll fires first, so cloning a camera from the UI fails or succeeds at random. `spawn_if_needed` now skips a camera whose metrics aren't there yet and picks it up on the next poll, the same way it already waits on a late ffmpeg update.

`AudioEventMaintainer` holds the `CameraMetrics` object now instead of indexing the manager dict on every audio chunk, which drops the IPC round trips and means a removed camera can't `KeyError` out of `detect_audio` after the maintainer pops the entry. The audio process is also registered with the watchdog, since a crash there previously left audio detection dead for every camera until a full restart, and it now receives the shared `DataProcessorMetrics` so `AudioTranscriptionRealTimeProcessor` gets the same type as the other real time processors.

* fix stationary max_frames dropping other tracked objects

When `max_frames` was set for a label, deregistering one object rebuilt norfair's list with a filter that kept an object only if it was both not the target and already on its way out, so every other healthy object of that label was dropped along with it. Any car leaving the frame took the rest of the cars with it and they came back as new tracked objects a few frames later. The filter now removes only the target, and objects that are expiring are still reaped by norfair on the next update.

* fix test

* fix skip_motion_threshold permanently disabling motion detection

The skip check returned before the two `accumulateWeighted` calls at the end of `detect`, so a skipped frame never made it into the background and setting `calibrating` there only picked a faster alpha for calls that never ran. `avg_frame` starts as an all zero image and a normally lit scene differs from black across nearly the whole frame, so the cameras I tested measure 0.84 to 0.98 against it. Any `skip_motion_threshold` below that number skips the first frame, leaves the background black, and skips every frame after it. Motion detection is dead for that camera until the setting is removed or Frigate restarts, with no motion boxes, no motion recordings, and no regions for the tracker since the detector stays calibrating.

Startup isn't the only way in. `update_mask` zeroes the background on any motion config change, and once a camera has calibrated the first IR switch or PTZ move freezes the background on the old scene, so it can't transition to the new one, which is the case the option exists for. The frame is now blended in before the early return at the same 0.2 alpha the calibrating path uses elsewhere, so a large scene change is still suppressed while the background catches up, about a second on a 5 fps camera, and then motion comes back.

* dump ffmpeg logs on every restart

The record watchdog restarted ffmpeg without flushing its `LogPipe`, so a camera whose recording segments went stale never showed a single line of ffmpeg output. The dump now happens in `start_or_restart_ffmpeg` right after the stop, which covers the stale record path, the record crash path, and the audio restart. `reset_capture_thread` and the audio `log_and_restart` fallback keep their own dumps since both pass `ffmpeg_process=None`.

* dump ffmpeg logs once per restart

The audio restart path dumped the log pipe itself before calling the helper, so the restart dump printed a second "last 100 lines" heading over an already drained deque and split the tail that `stop_ffmpeg` flushed into its own section. The heading is now only printed when there's something under it, and the audio path leaves the dump to the restart so each failure produces one section.

* keep all logpipe dumps consistent
2026-09-20 12:45:24 -06:00
Josh HawkinsandGitHub 3d08bbe520 Miscellaneous fixes (#24402)
CI / AMD64 Build (push) Canceled after 0s
CI / AMD64 Smoke Test (push) Canceled after 0s
CI / ARM Build (push) Canceled after 0s
CI / Jetson Jetpack 6 (push) Canceled after 0s
CI / AMD64 Extra Build (push) Canceled after 0s
CI / ARM Extra Build (push) Canceled after 0s
CI / Synaptics Build (push) Canceled after 0s
CI / Assemble and push default build (push) Canceled after 0s
* check for a valid frame before using its shape

With the camera offline, no preview frame, and `camera-error.jpg` missing, `latest_frame` read `frame.shape` before its `frame is None` check, so it raised `AttributeError` and answered 500 with a traceback instead of the intended "Unable to get valid frame". The check now runs first.

* fix the has_clip self-heal for events with no recordings

`vod_event` looked for a `(body, 404)` tuple, but `vod_ts` returns a `JSONResponse`, so the check never matched and an old event whose recordings are gone kept offering a clip that can't play. It now checks the response status code.

* return 403 for a snapshot or thumbnail on another camera

The broad `except Exception` handlers in `event_snapshot` and `event_thumbnail` caught the `HTTPException` from `require_camera_access`, so a restricted user asking for another camera's snapshot got a 404 instead of a 403, and for an object still being tracked the snapshot was rendered before the check ran. Both endpoints now look up the event and check access in their own block, the way the other endpoints do, so a denial propagates.

* find DST transitions to the second

`get_dst_transitions` probed the offset once every 24 hours from the start time and reported a change at the first probe after it, up to a day late, so events, review items and recordings near a transition were grouped into days with the old offset. A transition after the last daily probe wasn't found at all. The end of the range is probed too now, and a probe that sees the offset change bisects the interval to the second of the transition.

* don't run page shortcuts for keys a dialog already handled

Radix dismisses a dialog on Escape from a capture-phase keydown listener and calls `preventDefault()` without stopping propagation, so `useKeyboardListener` still ran the page's Escape shortcut: cancelling the delete dialog in the face library or a classification model also cleared the whole selection. Keys another shortcut hook handled still get through, since their listener order changes with every render.

* fix train image filtering for a class with a dash

The backend writes a class with a `-` as `_` in train file names, since it splits those names on `-`, while a dataset folder keeps the dash. Filtering the Train grid by `half-open` compared it with `half_open` and hid every attempt. Both sides are normalized the same way now.

* don't edit a chat message while a reply streams

The edit button stayed active while a reply streamed. `submitConversation` returns early while loading, but the message bubble still closed its editor, so the edit was silently lost. The edit button is hidden while a reply streams, and an editor that's already open keeps its draft with send disabled until the reply ends.

* fix restart failing under non-root

restart_frigate() called psutil.Process(1).terminate() to signal s6-svscan, but s6-svscan runs as root while frigate runs as uid 1000, so the call raised AccessDenied. That exception escaped every caller: the UI restart button dropped its websocket client, MQTT restart and Save & Restart just logged and did nothing, and the watchdog crashed its own monitoring thread on a dead detector. This catches AccessDenied and falls through to the existing SIGINT branch, which exits the process for s6 to restart it.

* show runtime overrides in the settings form

The settings form read a camera section's saved config value, but its dependent warnings (audio transcription requiring audio detection, snapshots requiring detect, etc.) read the live config instead. A runtime toggle from the live view, MQTT, or an active profile can turn a section off without touching yaml, and that override persists across restarts, so the Enable switch showed on while the warning said the feature wasn't enabled. This adds an "Overridden (Live)" badge to any field whose live value differs from what's saved, and swaps the affected warnings to runtime-specific wording when a runtime override is the actual cause instead of the config.

* fix mobile overflowing icons in system due to new health pane

* fix genai settings keeping a stale model and dropping roles after save

Switching a GenAI entry's provider left the previous provider's model selected, so saving wrote a model the new provider doesn't serve. llama.cpp can't find that model in `/v1/models`, so the backend reported every capability as false for the entry, and once the save refetched `genai/models` the roles widget stripped `transcribe` from the form on its own. The section showed unsaved changes right after saving, and saving again would have dropped the role. Switching provider now clears the model, and the roles widget only strips a role for a model or provider picked in the form, since the entry-level capability flags only describe the saved model. A selected role stays visible when the provider can't confirm it, so it can still be switched off. The llama.cpp model list also no longer repeats a model whose alias matches its id, which is what `--alias` produces.

* close onvif sessions on shutdown

`OnvifController.close()` only stopped its event loop, so the aiohttp sessions each `ONVIFCamera` holds and the `_poll_config_updates` task were left to be garbage collected during interpreter shutdown, when their warnings can no longer be logged. Every restart ended with a run of `Unclosed client session` and `Task was destroyed but it is pending!` logging errors, which only became visible once restart started exiting the process itself under non-root. `close()` now closes each camera's client and cancels the tasks on the loop before stopping it.

* fixes

* fixes
2026-09-18 07:33:23 -06:00
Nicolas MowenandGitHub 334073967b Support using GenAI for audio transcription (#24396)
CI / AMD64 Build (push) Canceled after 0s
CI / AMD64 Smoke Test (push) Canceled after 0s
CI / ARM Build (push) Canceled after 0s
CI / Jetson Jetpack 6 (push) Canceled after 0s
CI / AMD64 Extra Build (push) Canceled after 0s
CI / ARM Extra Build (push) Canceled after 0s
CI / Synaptics Build (push) Canceled after 0s
CI / Assemble and push default build (push) Canceled after 0s
* Add support for running transcription with GenAI

* Improve audio joining

* Fix GenAI model capability reporting

* Support language correctly

* Migrate existing users to keep english selected

* Fix models

* Fix tests

* Fix accepted null model

* Handle slwo providers
2026-09-17 16:34:47 -05:00
Nicolas MowenandGitHub eccd10cd94 Implement annotated frames for GenAI Review (#24379)
CI / AMD64 Build (push) Canceled after 0s
CI / AMD64 Smoke Test (push) Canceled after 0s
CI / ARM Build (push) Canceled after 0s
CI / Jetson Jetpack 6 (push) Canceled after 0s
CI / AMD64 Extra Build (push) Canceled after 0s
CI / ARM Extra Build (push) Canceled after 0s
CI / Synaptics Build (push) Canceled after 0s
CI / Assemble and push default build (push) Canceled after 0s
* Implement annotated frames mode for GenAI reviews to improve models with lacking temporal understanding

* Updates

* Improve debug sharing

* Do not number objects

* Fix assumptions

* Remove unhelpful content

* Improve object data sent as part of prompt

* Cleanup ollama dumbness

* Bind db

* Fixes

* Cleanup
2026-09-17 10:28:37 -06:00
Josh HawkinsandGitHub 10a0d5ea37 Improve UI zone operations (#24376)
CI / AMD64 Build (push) Canceled after 0s
CI / AMD64 Smoke Test (push) Canceled after 0s
CI / ARM Build (push) Canceled after 0s
CI / Jetson Jetpack 6 (push) Canceled after 0s
CI / AMD64 Extra Build (push) Canceled after 0s
CI / ARM Extra Build (push) Canceled after 0s
CI / Synaptics Build (push) Canceled after 0s
CI / Assemble and push default build (push) Canceled after 0s
* improve zone renaming

Zone rename now saves as one JSON body via config/set, moving required_zones and profile overrides instead of leaving stale references

* fixes
2026-09-16 12:07:05 -06:00
Josh HawkinsandGitHub 64d6366ac4 Live streaming tech selection (#24374)
* allow users to select live streaming technology

* fix webrtc being downgraded to mse on load

`useUserPersistence` seeds state with the default and loads asynchronously, so the first render always used `mse` instead of the saved choice, and `useWebRTCGloballyAvailable` reports `checking` until the probe settles and re-enters that state on every consumer mount, so a saved `webrtc` was rewritten to `mse` even after the probe had already passed. On Safari the MSE player then timed out and latched the jsmpeg fallback. A pending probe now counts as available, the player waits on `autoLive` until the stored preferences load, and `handleError` gates on the mode in use since the fallback flag no longer implies webrtc is untried. A rejected IndexedDB read also resolves `loaded` now, so a blocked store can't leave the player waiting forever.

* add support for configurable ICE servers in WebRTC player

* add mic error state, fix dialog overwriting saved choice and dashboard ignoring stream

* tweaks
2026-09-16 09:12:06 -05:00
Josh HawkinsandGitHub 79ca18d439 fix build warnings from tailwind, fonts, and fast refresh (#24359)
CI / AMD64 Build (push) Canceled after 0s
CI / AMD64 Smoke Test (push) Canceled after 0s
CI / ARM Build (push) Canceled after 0s
CI / Jetson Jetpack 6 (push) Canceled after 0s
CI / AMD64 Extra Build (push) Canceled after 0s
CI / ARM Extra Build (push) Canceled after 0s
CI / Synaptics Build (push) Canceled after 0s
CI / Assemble and push default build (push) Canceled after 0s
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
2026-09-15 15:33:09 -06:00
Josh HawkinsandGitHub cabdffea20 Update more web deps and reformat with updated prettier (#24358)
* 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
2026-09-15 15:18:49 -06:00
Josh HawkinsandGitHub 0c52a3175d update radix, react, konva and other web dependencies (#24354)
CI / AMD64 Build (push) Canceled after 0s
CI / AMD64 Smoke Test (push) Canceled after 0s
CI / ARM Build (push) Canceled after 0s
CI / Jetson Jetpack 6 (push) Canceled after 0s
CI / AMD64 Extra Build (push) Canceled after 0s
CI / ARM Extra Build (push) Canceled after 0s
CI / Synaptics Build (push) Canceled after 0s
CI / Assemble and push default build (push) Canceled after 0s
konva 10.5 removed the private `Node._lastPos`, so `PolygonCanvas` now reads the dragged point from `getAbsolutePosition()`, which returns the position konva just applied. monaco-yaml 5.5 takes formatter options instead of a boolean for `format`. The radix packages move together so every shared primitive stays a single copy under the `react-slot` and `compose-refs` overrides.
2026-09-15 12:39:31 -05:00
Josh HawkinsandGitHub 4c648f8147 bump copy-to-clipboard to 4.0.2 (#24353) 2026-09-15 12:03:20 -05:00
Josh HawkinsandGitHub 4100383738 Miscellaneous fixes (#24352)
* fix recordings unavailable endpoint when no params are provided

we already import the datetime class directly, so those attribute lookups raised AttributeError and the request returned 500

* reject JWTs whose role is no longer in the config

`/auth` trusted the role inside the JWT and re-signed it on refresh without checking the config, so a user whose restricted role was deleted kept a session carrying a role that isn't in `auth.roles`. The media, clip, recording, export and go2rtc checks treat a missing role the same as a role with no camera list, so that session could open every camera. `/auth` now returns 401 for a token whose role isn't configured, which sends the user back through login, and login already falls back to `viewer` for a role that's gone.

* delete the deleted camera group's layout, not the open one's

Deleting a camera group removed the layout of the group being viewed, because the dialog's delete was bound to `${activeGroup}-draggable-layout`. It also cleared the saved group, and both ran before the `config/set` request whether or not it succeeded, so deleting one group while viewing another lost the open group's layout and left the deleted group's layout behind. The deleted group's own layout is now removed after a successful save, and the saved group is only cleared when it was the open group.

* don't block API when querying PTZ info

camera_ptz_info is async but waited on the ONVIF controller's future with future.result(), blocking the API event loop for as long as a slow or unreachable ONVIF camera took to answer (including reconnect attempts), so every other async request stalled with it. Await the future with asyncio.wrap_future instead. The coroutine runs on the controller's own loop and thread, so this cannot deadlock.

* for custom exports, only allow admin users to add to existing cases

follows the existing convention where attaching an export to an existing case is admin-only on `POST /export/{camera}/...` and `POST /exports/batch`

* drop pending edits for a camera or profile that no longer exists

* match cached preview frames to their camera exactly

https://github.com/blakeblackshear/frigate/pull/22594 added a trailing `-` to the `preview_{camera}` prefix so `camera` stopped matching `camera2`'s frames, but camera names can contain `-`, so `front` still matched `front-door`'s. After a restart, `front`'s preview recorder deleted this hour's frames of a matching camera that sorted before it and added the timestamps of one that sorted after it, so ffmpeg was asked for files that don't exist and that hour's preview was lost. The offline fallback for `latest.jpg` could also return `front-door`'s frame for `front`, even to a user without access to `front-door`, and a short export could take its fallback thumbnail from the other camera. These now compare the full camera name taken from the file name.
2026-09-15 07:48:30 -05:00
Josh HawkinsandGitHub fa30a7e1ae Replace react-logviewer with virtua (#24334)
* bump react-logviewer to 6.5.5

* use virtua for UI logs
2026-09-15 05:44:04 -06:00
Nicolas MowenandGitHub 7821ecbb43 Migrate Hailo detector key and support hailo device (#24327)
* Migrate Hailo detector key and support hailo device

* Fix missing check
2026-09-14 08:23:36 -06:00
Josh HawkinsandGitHub caa6edecac Migrate web to ESLint 10 flat config (#24326)
* migrate web to eslint 10 flat config

ESLint 10 dropped `.eslintrc` support, so `.eslintrc.cjs` is replaced with `eslint.config.js` and the lint scripts no longer pass `--ext` or `--ignore-path`. typescript-eslint moves to 8, react-hooks to 7, and react-refresh to 0.5, and the unused jest and vitest-globals plugins are removed. Lint behaves as it did before: catch variables aren't checked, unused disable directives aren't reported, and rules newly added to the recommended sets are off until the code passes them. typescript-eslint 8 flags constants used only in `typeof`, so those are now exported, or replaced with a union type where the export would trip react-refresh.

* fix lint findings from the eslint 10 recommended rules

Remove the rule overrides from the flat config migration and fix what they were hiding. Unused catch bindings are dropped, 20 disable directives that suppressed nothing are removed (react-hooks 5.2 and 7.1.1 report identical exhaustive-deps findings with inline config ignored), dead initial values are dropped, short-circuit calls become if statements or optional calls, rethrown errors pass `cause`, and the disabled "No recordings" tooltip in `ReviewTimeline` is removed along with its memo and the `getRecordingAvailability` prop. The 3 react-refresh warnings for files that export contexts or classes are left for a later refactor.
2026-09-14 07:53:45 -06:00
Josh HawkinsandGitHub acc740a976 Update deps (#24324)
* update docusaurus to 3.10.2

* bump @types/node to 25.9.6 and ES2022

target ES2022, which already includes ES2020 and ES2021.String, so the lib list was also trimmed

* bump vite to 8.3.0 and vitest to 4.1.11

Swap `@vitejs/plugin-react-swc` for `@vitejs/plugin-react` and add `esbuild` as a devDependency, since `vite-plugin-monaco-editor` requires it and Vite 8 no longer ships it. `keepNames` moves to `build.rolldownOptions.output` because Vite 8 ignores the `esbuild` block. Rolldown's minifier now writes the preload helper's base path as a template literal instead of a double-quoted string, so the nginx `sub_filter` for `return"/BASE_PATH/"` stopped matching and lazy-loaded chunks and their CSS were requested from a literal `/BASE_PATH/` under Home Assistant ingress. The rule now matches the backtick form.

* bump apexcharts to 7.3.0 and react-apexcharts to 2.1.1

Under Vite 8, a default import from a CommonJS package resolves to its whole `module.exports` when `package.json` has `"type": "module"`, so react-apexcharts 1.4.1 handed React an object and every chart crashed. 2.x ships an ESM build. apexcharts 7 no longer sets `window.ApexCharts`, so the chart components now import it for `ApexCharts.exec`, and `ApexAxisChartSeries` is derived in `types/graph.ts` because it's no longer a global type.

* remove unused immer dep

* remove unused cython pin from tensorrt requirements

The pin was added alongside tensorrt 8.5.3 and cuda-python 11.8, which needed Cython to build, and both have since been dropped from this file. Nothing imports Cython at runtime, and `pip3 wheel` runs with build isolation, so any source build gets its own build dependencies. The pin only installed an unused Cython wheel into the TensorRT image.

* require node 20.19 for docs
2026-09-14 07:16:31 -06:00
Josh HawkinsandGitHub d59c28e53a Add command menu to frontend (#24256)
CI / AMD64 Build (push) Canceled after 0s
CI / AMD64 Smoke Test (push) Canceled after 0s
CI / ARM Build (push) Canceled after 0s
CI / Jetson Jetpack 6 (push) Canceled after 0s
CI / AMD64 Extra Build (push) Canceled after 0s
CI / ARM Extra Build (push) Canceled after 0s
CI / Synaptics Build (push) Canceled after 0s
CI / Assemble and push default build (push) Canceled after 0s
* add command menu to quickly jump between pages, cameras, settings, and quick actions

* access tweaks
2026-09-12 10:57:17 -06:00
Josh HawkinsandGitHub 4861a668b1 Add error boundary to frontend (#24255)
* add error boundary

on frontend errors, show a page-level recovery panel and a separate compact strip for the sidebar/status/bottombar so failures there don't take down the rest of the page

* tweaks

* fix test
2026-09-12 10:32:22 -06:00
Josh HawkinsandNicolas Mowen 7bc32fd4c9 Refactor Notices and System Health pane (#24243)
* refactor notices

* show startup message for enrichments in health pane

* tweaks
2026-09-12 07:30:04 -06:00
Josh HawkinsandNicolas Mowen e3029beba5 Report skipped detections in status bar (#24223)
* report skipped detections in the system notices pane

* revert notices and move to status bar

* shorten string
2026-09-12 07:30:04 -06:00
Nicolas Mowen f9347967eb Add ability to manually run Review Descriptions from the UI / API (#24222)
* Add ability to manually run Review Descriptions from the UI / API

* Fix not handling None type for call
2026-09-12 07:30:04 -06:00
Nicolas Mowen 82be9fff5e Support main+sub stream exports (#24193)
* Support multi resolution exports

* Fix decoder text

* Add dropdown and ability to select export stream selection

* Fix for review comments

* Fix mypy

* Cleanup wording
2026-09-12 07:30:04 -06:00
Josh HawkinsandNicolas Mowen 70ce193e09 Improve System Health pane (#24188)
* build out system health pane

* tweaks

* fixes

* fix notice link so it opens the correct camera

* tweak language
2026-09-12 07:30:04 -06:00
Josh HawkinsandNicolas Mowen 6d33b31bc6 show disk space reclaimed by media sync (#24189) 2026-09-12 07:30:04 -06:00
Josh HawkinsandNicolas Mowen d6b93301e2 Miscellaneous fixes (#24179)
* rename migration

* use ASC composite index for event camera and start_time

the planner still picks for newest-first single-camera queries but doesn't slow down full per-camera scans on a cold cache

* pause playback while the timeline range handles are up

* reduce multi camera seeded export range to 30m

allows both handlebars to fit within most desktop windows
2026-09-12 07:30:04 -06:00
Josh HawkinsandNicolas Mowen f3a31e2fb4 Add a notice registry and System Health tab (#24178)
* add a notice registry and System Health tab

Problems Frigate detects on its own (ffmpeg crash loops, stuck detectors, failed model downloads, recordings deleted before their retention period) only ever existed as log lines. This adds a `NoticeRegistry` in the main process backed by two tables, an `update_notice` IPC topic so producers in other processes can reach it through the dispatcher, an admin-only API and websocket topic, and a Health tab that lists them. Kinds declare their own mode, severity, and category in one place: state notices are resolved by their producer, event notices are dismissed by the user.

* treat a prerelease as behind its final release

* fix notices clearing early

* rename menu items and update docs

* don't resolve the update notice on a failed version lookup
2026-09-12 07:30:04 -06:00
Nicolas Mowen af60d2db48 GenAI Chat Improvements (#24173)
* Initial tool approval implementation

* Cleanups and fixes

* Improve robustness of loading case
2026-09-12 07:30:04 -06:00
Josh HawkinsandNicolas Mowen 9eef369dd0 fix latched loading spinner after cancelling a timeline selection (#24162)
isLoading and isBuffering only clear on playback progress, and scrubbing holds the player paused, so a source rebuild during a timeline selection left them set with nothing able to clear them. Cancelling made them visible as a spinner over an already-loaded frame, which stayed until the next manual seek. Leaving a scrub now clears them when the source is loaded and the element holds a frame.
2026-09-12 07:30:04 -06:00
Josh HawkinsandNicolas Mowen 53b04f44ef Fix preview players at the hour rollover (#24157)
* fix preview players at the hour rollover

* clean up
2026-09-12 07:30:04 -06:00
Josh HawkinsandNicolas Mowen e2da7aae99 Add a deny option for the proxy default role (#24145)
* backend

* frontend

* docs

* fix none default role casing and name reserved roles in the error

* reserve every casing of none as a role name
2026-09-12 07:30:04 -06:00
Josh HawkinsandNicolas Mowen 1693415375 switch nginx-vod-module to the maintained dio-az fork (#24123)
The `v1.x` line is the same muxed fMP4 code as Kaltura's 1.31 with fixes backported, so the mapping JSON, manifest routes, and ffmpeg consumers are unchanged. The `MAX_CLIPS` patch applies as-is and the HEVC workaround is rewritten for the fork's reformatted source.

`vod_hls_version 6` is now explicit because the fork replaced Kaltura's automatic version calculation with a directive that defaults to 4 and only warns when fmp4 needs 6, so playlists were being stamped `EXT-X-VERSION:4` while carrying `EXT-X-MAP`. The `error_page 502 =404` hack is gone: https://github.com/kaltura/nginx-vod-module/issues/468 is a `vod_mode remote` bug and we're `mapped`, so those 502s were really `_vod_response` returning 404 upstream. The fork maps that through now, and the hack was also turning real 5xx into "no recordings".
2026-09-12 07:30:04 -06:00
Josh HawkinsandNicolas Mowen aaf18b81b2 Fix LPR vehicle message for multiple models (#24119)
* 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
2026-09-12 07:30:04 -06:00
Josh HawkinsandNicolas Mowen 98706482f5 Add Apple compatibility switch to the camera wizard (#24115)
* add apple compatibility switch to the camera wizard

* don't require every record stream to be h265
2026-09-12 07:30:04 -06:00
Josh HawkinsandNicolas Mowen fb8ab56c41 Add onboarding wizard for new installations (#24102)
* add onboarding wizard for new users

* resolve hwaccel per camera and clarify recording retention

The hwaccel step listed every preset Frigate ships, so an Intel box was offered Raspberry Pi and Rockchip decoding, and the codec specific presets (`preset-intel-qsv-h264` vs `-h265`) were offered as global values that break as soon as two cameras use different codecs. `/hardware/hwaccel` now returns the decoding families the probed hardware can actually use, each carrying a preset per codec, and the wizard resolves the family against the detect stream codec the camera wizard already probed: one global `ffmpeg.hwaccel_args` when every camera agrees, per-camera `cameras.<name>.ffmpeg.hwaccel_args` when they don't. The global stays on `auto` in that case so cameras added later still resolve at startup. A gen13+ Intel machine keeps its QuickSync recommendation with mixed h264 and h265 cameras instead of dropping to vaapi.

The recording step's "Days to retain recordings" only wrote alert and detection retention, and the storage estimate under it assumed continuous recording. It now asks what to record in plain language, writes `record.continuous.days` to match, shows the estimate only for continuous, and drops the spinner arrows on the number input.

* clean up

* add light/dark mode icon switcher

* use yml as default config file extension when not found

* i18n tweaks

* gate the setup wizard on cameras instead of a config key

* render setup wizard steps by key

* share the setup wizard e2e helpers and mock users

* add an account step to the setup wizard

* add setup wizard account step e2e coverage

* cover the account step's restart behavior

* button consistency

* fix test

* docs

* fixes
2026-09-12 07:30:04 -06:00
Josh HawkinsandNicolas Mowen 396a2156b2 Tweaks (#24067)
* improve keyframes messages

* don't pad the labelmap with unknown

`load_labels()` prefilled 91 `unknown` entries before reading the label file, so any model with fewer than 91 classes kept that padding in `merged_labelmap` and `unknown` showed up as a selectable object type in the objects settings UI. The padding only existed so `RemoteObjectDetector.detect` could index the labelmap without a KeyError, and it didn't even cover the empty-file case or Frigate+, which never had a prefill. Both lookups now skip class ids the labelmap doesn't name and warn once per id.
2026-09-12 07:30:04 -06:00
Josh HawkinsandNicolas Mowen c9c6a923ef add recognized plate picker to lpr known plates in settings (#24059) 2026-09-12 07:30:04 -06:00
Josh HawkinsandNicolas Mowen 257a05a7e2 Add import/export for camera group layouts and per-camera streaming settings (#24025)
* add import/export for camera group layouts and streaming settings

Camera group layouts and per-camera streaming settings are stored in the browser's IndexedDB, so they are tied to a single browser on a single device. Users with more than one device have to rebuild every group layout and re-pick every camera's stream settings by hand, and clearing browser data loses the work.

Add a Backup & Restore card to Settings > UI Settings that exports these settings to a JSON file and imports that file on another device. Import shows a confirmation dialog with per-section counts, switches for layouts, streaming settings, and UI preferences, and warnings about camera groups or cameras in the file that are not on this server.

Server-side storage is deliberately avoided. These are per-device presentation settings: a layout arranged for a desktop is wrong on a tablet, and continuous full-resolution streams that are free on a wired LAN are not on a phone. An explicit file moves settings only when the user chooses to move them.

Implementation notes:

- web/src/utils/uiSettingsTransfer.ts owns a registry of transferable IndexedDB keys. Each entry records whether the key is user-namespaced, matching which persistence hook wrote it, plus a zod schema for its value.
- Only registry-known keys are ever written, and only when their value passes that schema. The file format deliberately lets unknown keys survive parsing, so this filter is what prevents a hand-edited file from writing arbitrary storage keys or out-of-range values.
- Export falls back to the legacy un-namespaced key, because the username migration runs lazily on first mount of each owning hook.
- Streaming settings merge per group rather than replacing the whole map, so groups configured only on the receiving device survive.
- Import writes storage and then reloads, because useUserPersistence reads a key only on mount and StreamingSettingsProvider would otherwise write its stale in-memory state back over the import.
- playbackBandwidthEstimate, frigate-search-history, and live-layout are excluded: the first two are measurements and user data rather than preferences, and live-layout's default is derived from the device.

* merge imported streaming settings per camera instead of per group
2026-09-12 07:30:04 -06:00
Nicolas Mowen 27a40a507b Implement UI for managing multiple models (#24023)
* Implement hardware detection and UI management

* Cleanup Frigate+ detection

* Don't count model as changed

* Fixes for audio map error

* Add descriptions

* Enforce that all model must exist

* Fix hardware picking

* Docs fixes

* WebUI cleanup

* Cleanup handling of scenes

* UI refinement

* Cleanup recommended UI

* test fixews
2026-09-12 07:30:04 -06:00
Nicolas Mowen 8fe35ace3b Refactor detector and model management (#23995)
* Refactor detector and model management

* Fix model resolution field
2026-09-12 07:30:04 -06:00
Ersa Oktavian RamadanandNicolas Mowen fd76eb6c6f Add audio labelmap grouping (#24004)
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
2026-09-12 07:30:04 -06:00
Josh HawkinsandNicolas Mowen 6ba9dd92e4 Show main and sub stream usage separately in Storage Metrics (#24015)
* backend

* frontend

* docs

* test

* report null instead of 0 for a stream with no cached bandwidth sample
2026-09-12 07:30:04 -06:00
Josh HawkinsandNicolas Mowen f4cf1e1539 Refactor birdseye activity modes as a list and add alerts/detections (#24012)
* backend

* tests

* frontend and i18n

* e2e test schema

* docs
2026-09-12 07:30:04 -06:00
Josh HawkinsandNicolas Mowen e77155a4f1 Improve History's seek startup time and recordings query performance (#24011)
* serve a segment startup ladder so seeks begin playing sooner

nginx-vod was handed one 10s segment per recording file, so every playlist start had to download and decode a full segment before the first frame. Declare real keyframe data per clip and let nginx cut short leading segments from it.

- add vod_bootstrap_segment_durations 1000/2000/4000 so each playlist starts with 1s/2s/4s segments before settling at 10s
- emit real clip-relative keyFrameDurations (plus firstKeyFrameOffset when nonzero) from the recording keyframe index; rows without an index keep the whole-clip declaration, the only safe cut without keyframe knowledge
- drop the manifest's segment_duration field, which was always inert: nginx-vod parses only camelCase segmentDuration
- rebuild the player source at the seek target, quantized to a 10s grid, so the ladder applies to every seek and seek URLs stay repeatable for nginx's mapping and response caches
- route the seek model, in-range checks, and the stale-report guard through the source window rather than the chunk range
- bridge repositioning seeks (>2s from the last played timestamp) through the preview player and hold the release anchor one commit, so neither path paints a stale frame
- clear a pending loading timer before replacing it; an orphaned timer escaped onPlaying's clearTimeout and flashed loading mid-playback

* keep recordings queries on their indexes

Several recordings queries degraded into full scans or large sorts on big databases: the planner ignored index order, or the query shape gave it nothing tight to seek on. Reshape them into bounded seeks and add the composite index the per-stream lookups need.

- index recordings on (camera, stream_type, start_time DESC) and drop the (camera, stream_type) index it supersedes
- walk the recordings summary day by day with EXISTS probes and per-camera MIN/MAX seeks, skipping ahead over empty gaps instead of bucketing every row for the requested cameras
- run the summary endpoint on the event loop rather than the threadpool
- bound the unavailable-recordings query by start_time per camera and merge the results in Python
- bound the expire query's start_time so it seeks the retention window instead of scanning a camera's whole history
- enumerate deleted cameras with one index seek each rather than a camera NOT IN (...) scan
- compute bandwidth with segment_size filtered in a CASE projection; as a WHERE predicate it baited the planner into the (camera, segment_size) index plus a full sort of the camera's history
- fall back to a 1000-segment window when the recent 100 are all zero-size, so an ingest glitch doesn't report zero bandwidth
- limit the needs_refresh count instead of counting every segment
- cover sub-only and sparse calendar days, midnight-spanning day attribution, multi-camera gap merging, deleted-camera expiry, and zero-size segment runs

* fix mypy
2026-09-12 07:30:04 -06:00
Josh HawkinsandNicolas Mowen 50e7b76eb5 Enable PTZ control setup in the Add Camera Wizard (#23444)
* add ptz controls to camera via wizard when onvif has already been probed

* i18n

* add e2e test

* backend add and remove subscriber

* tweaks

* turn on switch by default if pan and/or tilt capability is available

* fix test
2026-09-12 07:30:04 -06:00
Josh HawkinsandNicolas Mowen 1498231eb9 Add sub stream recording with adaptive quality playback (#24009)
* 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
2026-09-12 07:30:04 -06:00
Ersa Oktavian RamadanandNicolas Mowen d6a18e79aa Refactor Birdseye activity types as composable booleans (#23940)
* 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.
2026-09-12 07:30:04 -06:00