* 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
Currently translated at 100.0% (759 of 759 strings)
Translated using Weblate (Turkish)
Currently translated at 100.0% (1374 of 1374 strings)
Translated using Weblate (Turkish)
Currently translated at 100.0% (1374 of 1374 strings)
Translated using Weblate (Turkish)
Currently translated at 100.0% (759 of 759 strings)
Translated using Weblate (Turkish)
Currently translated at 100.0% (508 of 508 strings)
Translated using Weblate (Turkish)
Currently translated at 100.0% (141 of 141 strings)
Translated using Weblate (Turkish)
Currently translated at 99.7% (1370 of 1374 strings)
Translated using Weblate (Turkish)
Currently translated at 100.0% (119 of 119 strings)
Translated using Weblate (Turkish)
Currently translated at 100.0% (145 of 145 strings)
Translated using Weblate (Turkish)
Currently translated at 100.0% (10 of 10 strings)
Translated using Weblate (Turkish)
Currently translated at 100.0% (265 of 265 strings)
Translated using Weblate (Turkish)
Currently translated at 100.0% (759 of 759 strings)
Translated using Weblate (Turkish)
Currently translated at 100.0% (508 of 508 strings)
Translated using Weblate (Turkish)
Currently translated at 100.0% (277 of 277 strings)
Translated using Weblate (Turkish)
Currently translated at 99.4% (1366 of 1374 strings)
Translated using Weblate (Turkish)
Currently translated at 100.0% (119 of 119 strings)
Translated using Weblate (Turkish)
Currently translated at 100.0% (145 of 145 strings)
Translated using Weblate (Turkish)
Currently translated at 100.0% (10 of 10 strings)
Translated using Weblate (Turkish)
Currently translated at 100.0% (265 of 265 strings)
Translated using Weblate (Turkish)
Currently translated at 100.0% (46 of 46 strings)
Translated using Weblate (Turkish)
Currently translated at 100.0% (62 of 62 strings)
Translated using Weblate (Turkish)
Currently translated at 100.0% (66 of 66 strings)
Translated using Weblate (Turkish)
Currently translated at 100.0% (759 of 759 strings)
Translated using Weblate (Turkish)
Currently translated at 100.0% (508 of 508 strings)
Translated using Weblate (Turkish)
Currently translated at 100.0% (141 of 141 strings)
Translated using Weblate (Turkish)
Currently translated at 100.0% (277 of 277 strings)
Translated using Weblate (Turkish)
Currently translated at 100.0% (1366 of 1366 strings)
Translated using Weblate (Turkish)
Currently translated at 100.0% (49 of 49 strings)
Translated using Weblate (Turkish)
Currently translated at 100.0% (6 of 6 strings)
Translated using Weblate (Turkish)
Currently translated at 100.0% (119 of 119 strings)
Translated using Weblate (Turkish)
Currently translated at 100.0% (60 of 60 strings)
Translated using Weblate (Turkish)
Currently translated at 100.0% (87 of 87 strings)
Translated using Weblate (Turkish)
Currently translated at 100.0% (145 of 145 strings)
Translated using Weblate (Turkish)
Currently translated at 100.0% (68 of 68 strings)
Translated using Weblate (Turkish)
Currently translated at 100.0% (10 of 10 strings)
Translated using Weblate (Turkish)
Currently translated at 100.0% (50 of 50 strings)
Translated using Weblate (Turkish)
Currently translated at 100.0% (264 of 264 strings)
Translated using Weblate (Turkish)
Currently translated at 100.0% (46 of 46 strings)
Translated using Weblate (Turkish)
Currently translated at 100.0% (62 of 62 strings)
Translated using Weblate (Turkish)
Currently translated at 100.0% (24 of 24 strings)
Translated using Weblate (Turkish)
Currently translated at 100.0% (25 of 25 strings)
Translated using Weblate (Turkish)
Currently translated at 100.0% (759 of 759 strings)
Translated using Weblate (Turkish)
Currently translated at 100.0% (508 of 508 strings)
Translated using Weblate (Turkish)
Currently translated at 100.0% (141 of 141 strings)
Translated using Weblate (Turkish)
Currently translated at 100.0% (277 of 277 strings)
Translated using Weblate (Turkish)
Currently translated at 100.0% (1366 of 1366 strings)
Translated using Weblate (Turkish)
Currently translated at 100.0% (119 of 119 strings)
Translated using Weblate (Turkish)
Currently translated at 100.0% (60 of 60 strings)
Translated using Weblate (Turkish)
Currently translated at 100.0% (145 of 145 strings)
Translated using Weblate (Turkish)
Currently translated at 100.0% (129 of 129 strings)
Translated using Weblate (Turkish)
Currently translated at 100.0% (35 of 35 strings)
Translated using Weblate (Turkish)
Currently translated at 100.0% (2 of 2 strings)
Translated using Weblate (Turkish)
Currently translated at 100.0% (74 of 74 strings)
Translated using Weblate (Turkish)
Currently translated at 100.0% (118 of 118 strings)
Translated using Weblate (Turkish)
Currently translated at 100.0% (50 of 50 strings)
Translated using Weblate (Turkish)
Currently translated at 100.0% (10 of 10 strings)
Translated using Weblate (Turkish)
Currently translated at 100.0% (500 of 500 strings)
Translated using Weblate (Turkish)
Currently translated at 100.0% (264 of 264 strings)
Update translation files
Updated by "Cleanup translation files" add-on in Weblate.
Translated using Weblate (Turkish)
Currently translated at 100.0% (759 of 759 strings)
Translated using Weblate (Turkish)
Currently translated at 100.0% (508 of 508 strings)
Translated using Weblate (Turkish)
Currently translated at 100.0% (500 of 500 strings)
Translated using Weblate (Turkish)
Currently translated at 100.0% (62 of 62 strings)
Translated using Weblate (Turkish)
Currently translated at 100.0% (24 of 24 strings)
Translated using Weblate (Turkish)
Currently translated at 100.0% (759 of 759 strings)
Translated using Weblate (Turkish)
Currently translated at 100.0% (508 of 508 strings)
Translated using Weblate (Turkish)
Currently translated at 100.0% (269 of 269 strings)
Translated using Weblate (Turkish)
Currently translated at 100.0% (1364 of 1364 strings)
Translated using Weblate (Turkish)
Currently translated at 100.0% (119 of 119 strings)
Translated using Weblate (Turkish)
Currently translated at 100.0% (50 of 50 strings)
Translated using Weblate (Turkish)
Currently translated at 96.8% (1321 of 1364 strings)
Translated using Weblate (Turkish)
Currently translated at 100.0% (50 of 50 strings)
Translated using Weblate (Turkish)
Currently translated at 95.3% (1300 of 1364 strings)
Translated using Weblate (Turkish)
Currently translated at 95.2% (1299 of 1364 strings)
Translated using Weblate (Turkish)
Currently translated at 100.0% (759 of 759 strings)
Translated using Weblate (Turkish)
Currently translated at 86.1% (1175 of 1364 strings)
Translated using Weblate (Turkish)
Currently translated at 85.2% (1163 of 1364 strings)
Translated using Weblate (Turkish)
Currently translated at 58.3% (157 of 269 strings)
Translated using Weblate (Turkish)
Currently translated at 84.6% (1155 of 1364 strings)
Translated using Weblate (Turkish)
Currently translated at 84.6% (1155 of 1364 strings)
Translated using Weblate (Turkish)
Currently translated at 82.7% (1129 of 1364 strings)
Translated using Weblate (Turkish)
Currently translated at 100.0% (759 of 759 strings)
Translated using Weblate (Turkish)
Currently translated at 100.0% (508 of 508 strings)
Translated using Weblate (Turkish)
Currently translated at 58.3% (157 of 269 strings)
Translated using Weblate (Turkish)
Currently translated at 74.7% (1019 of 1364 strings)
Translated using Weblate (Turkish)
Currently translated at 100.0% (49 of 49 strings)
Translated using Weblate (Turkish)
Currently translated at 100.0% (119 of 119 strings)
Translated using Weblate (Turkish)
Currently translated at 100.0% (87 of 87 strings)
Translated using Weblate (Turkish)
Currently translated at 100.0% (145 of 145 strings)
Translated using Weblate (Turkish)
Currently translated at 100.0% (35 of 35 strings)
Translated using Weblate (Turkish)
Currently translated at 100.0% (74 of 74 strings)
Translated using Weblate (Turkish)
Currently translated at 100.0% (118 of 118 strings)
Translated using Weblate (Turkish)
Currently translated at 100.0% (46 of 46 strings)
Translated using Weblate (Turkish)
Currently translated at 100.0% (62 of 62 strings)
Translated using Weblate (Turkish)
Currently translated at 100.0% (66 of 66 strings)
Translated using Weblate (Turkish)
Currently translated at 100.0% (24 of 24 strings)
Translated using Weblate (Turkish)
Currently translated at 100.0% (25 of 25 strings)
Translated using Weblate (Turkish)
Currently translated at 100.0% (759 of 759 strings)
Translated using Weblate (Turkish)
Currently translated at 100.0% (508 of 508 strings)
Translated using Weblate (Turkish)
Currently translated at 100.0% (141 of 141 strings)
Translated using Weblate (Turkish)
Currently translated at 58.3% (157 of 269 strings)
Translated using Weblate (Turkish)
Currently translated at 69.5% (949 of 1364 strings)
Translated using Weblate (Turkish)
Currently translated at 100.0% (49 of 49 strings)
Translated using Weblate (Turkish)
Currently translated at 100.0% (119 of 119 strings)
Translated using Weblate (Turkish)
Currently translated at 100.0% (60 of 60 strings)
Translated using Weblate (Turkish)
Currently translated at 100.0% (87 of 87 strings)
Translated using Weblate (Turkish)
Currently translated at 100.0% (145 of 145 strings)
Translated using Weblate (Turkish)
Currently translated at 100.0% (68 of 68 strings)
Translated using Weblate (Turkish)
Currently translated at 100.0% (129 of 129 strings)
Translated using Weblate (Turkish)
Currently translated at 100.0% (35 of 35 strings)
Translated using Weblate (Turkish)
Currently translated at 100.0% (74 of 74 strings)
Translated using Weblate (Turkish)
Currently translated at 100.0% (118 of 118 strings)
Translated using Weblate (Turkish)
Currently translated at 100.0% (50 of 50 strings)
Translated using Weblate (Turkish)
Currently translated at 100.0% (264 of 264 strings)
Translated using Weblate (Turkish)
Currently translated at 91.5% (695 of 759 strings)
Translated using Weblate (Turkish)
Currently translated at 100.0% (508 of 508 strings)
Translated using Weblate (Turkish)
Currently translated at 86.5% (122 of 141 strings)
Translated using Weblate (Turkish)
Currently translated at 48.6% (663 of 1364 strings)
Translated using Weblate (Turkish)
Currently translated at 100.0% (49 of 49 strings)
Translated using Weblate (Turkish)
Currently translated at 94.4% (137 of 145 strings)
Translated using Weblate (Turkish)
Currently translated at 91.4% (118 of 129 strings)
Translated using Weblate (Turkish)
Currently translated at 100.0% (74 of 74 strings)
Translated using Weblate (Turkish)
Currently translated at 100.0% (500 of 500 strings)
Translated using Weblate (Turkish)
Currently translated at 100.0% (264 of 264 strings)
Translated using Weblate (Turkish)
Currently translated at 31.2% (237 of 759 strings)
Translated using Weblate (Turkish)
Currently translated at 31.2% (237 of 759 strings)
Translated using Weblate (Turkish)
Currently translated at 31.2% (237 of 759 strings)
Translated using Weblate (Turkish)
Currently translated at 56.1% (285 of 508 strings)
Translated using Weblate (Turkish)
Currently translated at 56.1% (285 of 508 strings)
Translated using Weblate (Turkish)
Currently translated at 56.1% (285 of 508 strings)
Translated using Weblate (Turkish)
Currently translated at 48.6% (663 of 1364 strings)
Translated using Weblate (Turkish)
Currently translated at 94.4% (137 of 145 strings)
Translated using Weblate (Turkish)
Currently translated at 100.0% (74 of 74 strings)
Update translation files
Updated by "Cleanup translation files" add-on in Weblate.
Translated using Weblate (Turkish)
Currently translated at 1.5% (1 of 66 strings)
Translated using Weblate (Turkish)
Currently translated at 54.1% (13 of 24 strings)
Translated using Weblate (Turkish)
Currently translated at 16.0% (122 of 759 strings)
Translated using Weblate (Turkish)
Currently translated at 25.3% (129 of 508 strings)
Translated using Weblate (Turkish)
Currently translated at 86.5% (122 of 141 strings)
Translated using Weblate (Turkish)
Currently translated at 57.9% (156 of 269 strings)
Translated using Weblate (Turkish)
Currently translated at 48.6% (665 of 1366 strings)
Translated using Weblate (Turkish)
Currently translated at 80.6% (96 of 119 strings)
Translated using Weblate (Turkish)
Currently translated at 94.4% (137 of 145 strings)
Translated using Weblate (Turkish)
Currently translated at 100.0% (68 of 68 strings)
Translated using Weblate (Turkish)
Currently translated at 100.0% (35 of 35 strings)
Translated using Weblate (Turkish)
Currently translated at 100.0% (74 of 74 strings)
Translated using Weblate (Turkish)
Currently translated at 100.0% (118 of 118 strings)
Translated using Weblate (Turkish)
Currently translated at 100.0% (500 of 500 strings)
Translated using Weblate (Turkish)
Currently translated at 100.0% (264 of 264 strings)
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Murat Odabasi <murat12@gmail.com>
Co-authored-by: pcislocked <git@pcislocked.net>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/audio/tr/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/common/tr/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-auth/tr/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-camera/tr/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-dialog/tr/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-filter/tr/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-icons/tr/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-player/tr/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-cameras/tr/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-global/tr/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-groups/tr/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-validation/tr/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/objects/tr/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-chat/tr/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-classificationmodel/tr/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-configeditor/tr/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-events/tr/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-explore/tr/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-exports/tr/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-facelibrary/tr/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-live/tr/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-motionsearch/tr/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-recording/tr/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-replay/tr/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-search/tr/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-settings/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-settings/tr/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-system/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-system/tr/
Translation: Frigate NVR/Config - Cameras
Translation: Frigate NVR/Config - Global
Translation: Frigate NVR/Config - Groups
Translation: Frigate NVR/Config - Validation
Translation: Frigate NVR/audio
Translation: Frigate NVR/common
Translation: Frigate NVR/components-auth
Translation: Frigate NVR/components-camera
Translation: Frigate NVR/components-dialog
Translation: Frigate NVR/components-filter
Translation: Frigate NVR/components-icons
Translation: Frigate NVR/components-player
Translation: Frigate NVR/objects
Translation: Frigate NVR/views-chat
Translation: Frigate NVR/views-classificationmodel
Translation: Frigate NVR/views-configeditor
Translation: Frigate NVR/views-events
Translation: Frigate NVR/views-explore
Translation: Frigate NVR/views-exports
Translation: Frigate NVR/views-facelibrary
Translation: Frigate NVR/views-live
Translation: Frigate NVR/views-motionSearch
Translation: Frigate NVR/views-recording
Translation: Frigate NVR/views-replay
Translation: Frigate NVR/views-search
Translation: Frigate NVR/views-settings
Translation: Frigate NVR/views-system
* fix auto quality recovery after a downswitch
The downswitch callback armed the upswitch probe, but `triggerDownswitch` reset the stall history right after the callback returned, which disarmed it again. Auto quality stayed on the sub stream until the next chunk boundary no matter how much the connection recovered. The governor now arms the probe itself after the reset.
The chunk boundary effect also ran on mount, so when coverage was already cached it immediately undid the low quality cold start the seed effect had just picked. It now only runs when the chunk actually changes.
* fix recording playback quality switches and silent codec failures
A quality switch changes `bufferLength` a commit before the new source arrives, and since it was a dependency of the hls.js setup effect, the player rebuilt once on the outgoing playlist (jumping back to its original `startPosition`) and again on the new one. The buffer length now updates the running instance's config instead.
A fatal codec error with no lower quality stream to fall back to did nothing at all, so playback just sat there with no message. It now shows the playback failure toast, which is also limited to once per source since hls.js and the video element can both report the same failure.
* retry failed WebRTC probes and skip offline streams
The connectivity probe only ever tried the first go2rtc stream and cached its result for the whole page session, so a single offline camera at the top of the go2rtc config marked WebRTC unreachable for every camera until a reload, as did any brief network hiccup. The probe now starts with the stream being viewed and moves on to the next one when go2rtc reports that it can't open the stream's source. A failed result is only reused for 30 seconds, and it's retried on the next mount or when the page becomes visible again.
* fix two-way talk on cameras with AAC audio
The mic button was enabled whenever WebRTC was globally available, but the live view only switched to the WebRTC player when the stream itself qualified for WebRTC, and AAC playback audio disqualifies it. On most cameras the mic showed as on while nothing was sent. Two-way talk only needs the stream's video to connect since the backchannel is sent, not received, so AAC playback audio no longer blocks it. The mic is also turned off when a stream switch makes talk unavailable.
* keep Frigate+ model references when saving the models section
`/api/config` served a Frigate+ model's path as the resolved `/config/model_cache/<id>` file, and since the models list is saved whole, editing any model in the settings UI wrote that cache path back to the config in place of `plus://<id>`. After a restart the model loaded as a custom model with the default labelmap. The config API now reports the `plus://<id>` reference the model was configured with, and the models section drops the fields the Frigate+ model info supplies (size, tensor, pixel format, dtype, and type) instead of pinning them in the config.
* allow models to share shareable detection hardware
The hardware picker treated every device another model listed as taken, so a second model couldn't pick an Intel GPU or the CPU that the first one already used. The backend only rejects reuse of devices that can't be shared (Coral, MemryX), so the picker now matches that and only marks exclusive units as claimed.
* fix model card state and camera counts in the models editor
Model cards were keyed by index, so deleting one handed its state (such as the selected model source tab) to the card after it. Cards are keyed by scene now, which is unique per model.
The camera count on each card also ignored the backend's fallback to the `all` model, so a camera whose detect scene had no model of its own wasn't counted anywhere. It's counted under `all` now, which also feeds the recommended detector count.
* share a unit's temperature across repeated detector devices
Detector temperatures were matched to units by counting detectors of each type, so a device listed twice to run a second inference process (`hailo:PCIe` and `hailo:PCIe#2`) showed the next unit's temperature, or none at all. Distinct devices are numbered now and repeats share their unit's reading.
* update monitored hardware after a runtime config swap
`swap_runtime_config` rebound the stats emitter to the new config but not its `HardwareStats`, which kept polling hardware for the old config and applied camera updates to the discarded object. It now follows the swap along with its camera update subscriber.
* time out model downloads that never respond
`download_from_url` had no timeout, so a proxy or server that accepted the connection and never answered hung the download forever, including runtime downloads during startup. Connect and read timeouts now fail it like any other download error. The read timeout applies per socket read, so large models still finish.
* resolve segment start times in segment order
A camera stream's cached segments are probed concurrently, and each one chained its start off `last_segment_end` as soon as its own probe finished. When segments backed up in the cache and a later probe finished first, it chained off the wrong segment and the earlier one then moved `last_segment_end` backwards, so rows lost their exact adjacency. Probes still run concurrently, but each segment now waits for the one before it to settle its start before resolving its own.
* plan exports from the same coverage the vod route serves
The vod manifest nulls video-only glitch rows on audio-bearing streams, but exports planned their stream runs from the raw coverage, so a glitch row could produce a mixed-stream file or a 404 that failed the export. `null_audio_glitches` now works out each stream's audio composition itself, and exports go through it like the manifest and its realized timelines do.
An unstaged auto export also paged its playlist and chapters over main whenever main had any rows in range, even when the manifest served the range from sub and main only contributed glitches or slivers at the edges. It now reads the rows of the stream its single run actually uses.
* keep staged export chapters aligned across stream hand-offs
Each staged run of a mixed-stream export is rendered from its own pinned vod playlist, and that playlist's first clip snaps back to the preceding keyframe, so every staged file runs up to a GOP longer than its slice of the merged timeline. Chapters were placed on the merged timeline, so they drifted further from the video at every hand-off. Chapter windows for staged exports are now planned the same way each run's playlist is, carrying that keyframe lead-in into the offsets.
* clarify which hardware units only one model can use
* add e2e tests for shareable hardware and Frigate+ model saves
* only show the path field for a Frigate+ model without an API key
Without `PLUS_API_KEY` the models editor has no Frigate+ tab, so a `plus://` model showed every custom model field. The size, format, type, and labelmap fields are all supplied by the Frigate+ model info and ignored for a Frigate+ model, so editing them did nothing. Only the path is shown now, which still lets the model be switched to a custom one.
* keep a configured input_dtype when saving a Frigate+ model
The backend only overwrites `input_dtype` when the Frigate+ model info supplies `inputDataType`, which older models don't, so a configured dtype still matters for them. Saving the models section was dropping it along with the fields the backend always overwrites.
* probe every go2rtc stream until one isn't refused
The probe stopped after three streams, so with three offline cameras ahead of a working one, WebRTC was marked unreachable everywhere. It only moves past a stream when go2rtc refuses it, which is quick, and a stream that hangs still ends the probe at its timeout, so the cap bought nothing.
* only reuse a failed WebRTC probe for the stream it started from
A failed probe was reused for 30 seconds by every caller, so a camera whose stream timed out kept WebRTC unavailable for the next camera viewed, including one opened while that probe was still running. A pass still counts for every stream since it proves the connection, but a failure is only reused by probes that start from the same stream.
* strip input_dtype from Frigate+ models again
A Frigate+ model's config comes entirely from its model info, and a missing `inputDataType` means the `int` default. Keeping `input_dtype` meant switching from a custom model with `input_dtype: float` to a Frigate+ model carried the stale dtype over, with the field hidden so it couldn't be corrected.