* add last time to active notices
* Stop retrying the review lookup in the explore detail menu when it 404s
* don't let a slow websocket client block publishers
A websocket client that stopped reading its socket (for example a suspended workstation with a Frigate tab open) blocked ws4py's sendall on whatever thread was publishing, including the single inter-process responder thread, so the recording maintainer and stats hung until nginx dropped the client after 5 minutes. Each client now gets its own bounded send queue and writer thread, and a client that overflows the queue is shut down. ws4py writes close and pong frames directly on its shared manager thread, bypassing the queue, so a 10s socket send timeout keeps a stalled client from pinning that thread. The jsmpeg and birdseye outputs share the class, so their unreachable send error handling is removed.
* don't let a lost object enter a zone
When the detector lost an object, the tracker kept it at its last box and every held frame still counted toward the zone's inertia. A car detected in a zone once or twice as it drove out of view could reach an inertia of 8 and be marked as entering, which sent it to GenAI and any other required zones check even though Review never showed the zone. Inertia and loitering still count on frames without a detection, but an object can only newly enter a zone on a frame where it was actually detected.
* add test
* limit retry stop to 404 only
* add docstrings
Brings the go2rtc security fixes from #24658 to dev. Dev-specific changes
in the merge:
- frigate/config/env.py stays deleted; the environment_vars protection for
GO2RTC_ALLOW_ARBITRARY_EXEC moves to apply_config_env_vars in
frigate/util/env.py, so the value never reaches os.environ
- services.py imports substitute_frigate_vars from frigate.util.env and
maps UnknownVariableError to the unknown variable message
- go2rtc stream tests patch dev's import-time exec override snapshot and
its FRIGATE_* variable sources
- test_http_media.py keeps dev's _insert_recording helper; the one added
on master replaced it and broke the dev tests
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Subtracting 15s from the buffered end left a floating point remainder, so when Firefox held exactly 15s of buffer the handler called remove() on a near-zero range that removed nothing, and each updateend called it again. The loop pegged a CPU core and kept running after the websocket closed. Trimming now requires more than 1s past the window.
When an unauthenticated user opens a deep link, carry the requested
path through the login page in a redirect query param and return to it
after a successful login instead of always going to the home page.
Only same-origin targets are honored.
Claude-Session: https://claude.ai/code/session_011CFGjgYURSRTpXBaxp1Dq7
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* fix classification wizard finding no sample images on large databases
The wizard grouped tracked objects by camera and 6 hour block, oldest first, then kept the first 100. With more than 100 groups that was always the oldest objects, which often have no snapshot or thumbnail left on disk, so no examples were generated. Shuffle the selection before truncating, and keep extracting from the remaining tracked objects until 100 usable images are found.
* add notice and system ui message when a camera isn't using go2rtc
* add docs note about privacy masks
* match index-less device strings to hardware units in the detection models picker
A config with `edgetpu:usb` was reported as hardware that wasn't found, because the picker compared device strings exactly and the probe reports the unit as `edgetpu:usb:0`. A device without an index now resolves to the first unit of that kind, so the hardware dropdown, the unit checkboxes, and the model summary all recognize it.
* don't treat unknown audio as an audio-bearing stream
A recording row with NULL has_audio (ffprobe failed and the cv2 fallback can't report audio) marked the whole stream as audio-bearing, so every confirmed video-only row on it was dropped as a glitch. A stream now counts as audio-bearing only when a row is known to carry audio.
* stage main+sub exports on disk instead of /tmp/cache
A main+sub export stages a full copy of itself before the final file is written. That copy went to /tmp/cache, so a long export outgrew the tmpfs and failed with no space left on device. Staged runs are now written to the exports directory, and startup removes any left behind by a killed export.
* address review feedback
- stage main+sub export runs in a staging subfolder of the exports directory, so media sync can't delete them mid-export and startup cleanup can't remove a finished export with a matching name or fail on an unremovable file
- run object classification example collection off the event loop
- prefer an exact hardware unit match over an index-less one, so an AMD GPU's "onnx" no longer selects the NVIDIA entry
- add tests for the classification fallback and index-less hardware matching
* serialize example collection and clean up exports when staging dir creation fails
- overlapping object example requests could delete each other's images in the shared temp and train directories, so collection now runs under a lock
- a failed makedirs for the staging directory raised past the failed-export cleanup and left the export spinning until restart, so it now fails the run through the normal cleanup path
* revert
* bump backend and frontend dependencies
Bumps every outdated dependency that passed testing, with the code changes each one needs.
- peewee 4.5 and peewee_migrate 2.3: use SqliteDatabase in place of the removed SqliteExtDatabase, and fix types for peewee's bundled stubs
- mypy 2.4.0: remove unused type ignores and add the annotations mypy 2 needs
- pandas 3.0: convert the motion activity index with as_unit("s"), because pandas 3 infers second resolution for whole-second timestamps and the old // 10**9 returned 1
- transformers 5.19: load Jina tokenizers from the saved directory with trust_remote_code off and use CLIPImageProcessor, since v5 removed CLIPFeatureExtractor and remote code pulled in torch
- tensorflow-cpu 2.21: pin protobuf to 7.36 in the TensorRT amd64 image, because the old 3.20.3 pin was installed over TensorFlow and broke its import
- pydantic 2.13 and google-genai 2.29: regenerate the API spec
- ruff 0.16: set an explicit lint select, since 0.16 widened the default rules
- react-router-dom 7: set useTransitions={false} on BrowserRouter to keep v6 update timing, which useSearchEffect relies on
- typescript 6: drop baseUrl and add node types in tsconfig
- radix: update to the latest release and remove the slot patch, which upstream now includes
- apexcharts 7.8: guard the tooltip formatter against null values
- cryptography 50, joserfc 1.7, pywebpush 2.5, openai 3.26, aiohttp, uvicorn, onvif-zeep-async, scipy, framer-motion 14, react-day-picker 10 and other minor and patch bumps
* silence httpx2 request logging
* redownload an incomplete jina tokenizer
An interrupted tokenizer download left the Hugging Face cache directory without the saved tokenizer files, and since the download is skipped whenever that directory exists, every restart failed to load the tokenizer. The Jina constructors now remove a tokenizer directory that has no tokenizer_config.json so the download runs again.
The pencil button on the desktop live grid opened the camera group edit dialog for any role, so viewers could change settings and then hit an admin-only error on save. The button now renders only for admins, matching the sidebar and mobile entry points.
* reject usernames made only of dots
A username of "." or ".." passed validation, but browsers resolve those as path segments, so requests to /users/{username} never reached the API and the user could not be deleted or edited from the UI. User creation now rejects dot-only names in both the API and the create user dialog.
* show a specific error for dot-only usernames
Entering "." or ".." in the create user dialog showed the message listing periods as allowed characters, which didn't explain the rejection. The dialog now checks for dot-only names separately and shows its own message.
* try http-flv first for reolink cameras above 5MP in the camera wizard
The wizard picked RTSP for every Reolink above 5MP and then warned that RTSP isn't recommended, telling users to enable HTTP and restart, which just produced the same result. It now tries the http-flv stream first for those cameras and falls back to RTSP when the stream doesn't probe, since only the newer models serve H.265 over enhanced FLV. The RTSP warning is skipped when the camera's resolution made RTSP a valid choice.
http-flv no longer needs go2rtc's ffmpeg module, so the compatibility mode warning for Reolink HTTP streams is removed and the docs drop the `ffmpeg:` prefix from http-flv sources that have no transcoding modifiers.
* add reolink tests
* keep using ffmpeg module
* run recording snapshot ffmpeg off the event loop
The recording snapshot and Frigate+ recording submit endpoints called get_image_from_recording inline, which is a blocking ffmpeg subprocess with no timeout, so every other request stalled until the frame was decoded. Both calls now run in asyncio.to_thread.
* fix camera info dialog overflowing on mobile
* adjust test
* revert disable save buttons when there are no changes in config editor
* pass migrated config to each step in the config migration chain
* use 150 as the default max when typing a min speed in the search filter
* fix preview export outpoint to be relative to the start of the preview file
* don't crash on invalid trusted proxy entries or non-ip forwarded hops
* translate the camera count badge in the roles table
* run every batch through the lpr recognition model
* log rejected motion and notification mqtt payloads
* log invalid addresses in x-forwarded-for
* add test
* remove unused autotracked_object_region
* remove unreachable autotracker setup call in camera maintenance
* apply onvif retry limit when initialization fails
* fix reindex progress overcounting when there are fewer events than a batch
* match the register device button aria label to its text
* reset the add profile form on cancel
* ignore case when filtering search suggestions
* tweak comment
* implement auto mode for single camera live view
* add transcoded live streams and stream ordering for auto mode
Cameras can now add lower quality live streams that go2rtc transcodes to H.264 on demand. `live.transcode` takes a source stream and a list of heights and bitrates, and each quality becomes a `{camera}_transcode_{height}p` stream. The config validator adds them to `live.streams` without moving any the user already placed, and drops them when transcoding is disabled or a height changes. `create_config.py` writes them into go2rtc's generated config at startup, and saving the config or deleting a camera syncs them through go2rtc's API, so no restart is needed. They use `#hardware`, so go2rtc picks a hardware encoder and falls back to the CPU when there isn't one.
The Live playback settings stream list can be reordered by drag, since its order is the auto ladder. Auto order sorts it by bitrate, measuring native streams through a new admin-only `/go2rtc/streams/{name}/bitrate` endpoint and using the configured bitrate for transcoded ones. A pure reorder wasn't saved before because RJSF, the settings form, and `update_yaml` all ignore map key order. Sections can now mark a map with `orderedMaps`, which sends the whole map with `replace_paths` so `config_set` rewrites it in order.
Transcoded streams aren't in `go2rtc.streams`, which only lists yaml streams, so the frontend treated them as not restreamed and fell back to jsmpeg. Every restream check now goes through `isRestreamedStream`.
Auto treated any stall with no bytes in the last 2 seconds as a dead camera and handed it to the error fallback, which went straight to jsmpeg. Heavy congestion can stop delivery completely, so congested viewers skipped every lower stream. Auto now declines only when stats show the camera offline, and a stall on a live camera steps down. The stream picker also has a Try highest quality button that sends auto back to the top stream.
* fixes