mirror of
https://github.com/blakeblackshear/frigate.git
synced 2025-08-22 13:47:29 +02:00
Fixes (#18552)
* Ensure config editor recalculates layout on error * ensure empty lists are returned when lpr recognition model fails * Add docs section for session_length * clarify Co-authored-by: Josh Hawkins <32435876+hawkeye217@users.noreply.github.com> * clarify Co-authored-by: Josh Hawkins <32435876+hawkeye217@users.noreply.github.com> * Catch missing file * Improve graph axis colors * Ensure playback rate controls are portaled to the video container in history view On larger tablets in landscape view, the playback rate dropdown disappeared underneath the bottom bar. This small change ensures we use the correct container on the DropdownMenuContent so that the div is portaled correctly. The VideoControls are also used in motion review which does not pass in a container ref, so we can just fall back to the existing controlsContainer ref when it's undefined. --------- Co-authored-by: Nicolas Mowen <nickmowen213@gmail.com>
This commit is contained in:
parent
dba9206898
commit
ed43df9c13
@ -52,6 +52,21 @@ auth:
|
||||
- 172.18.0.0/16 # <---- this is the subnet for the internal Docker Compose network
|
||||
```
|
||||
|
||||
## Session Length
|
||||
|
||||
The default session length for user authentication in Frigate is 24 hours. This setting determines how long a user's authenticated session remains active before a token refresh is required — otherwise, the user will need to log in again.
|
||||
|
||||
While the default provides a balance of security and convenience, you can customize this duration to suit your specific security requirements and user experience preferences. The session length is configured in seconds.
|
||||
|
||||
The default value of `86400` will expire the authentication session after 24 hours. Some other examples:
|
||||
- `0`: Setting the session length to 0 will require a user to log in every time they access the application or after a very short, immediate timeout.
|
||||
- `604800`: Setting the session length to 604800 will require a user to log in if the token is not refreshed for 7 days.
|
||||
|
||||
```yaml
|
||||
auth:
|
||||
session_length: 86400
|
||||
```
|
||||
|
||||
## JWT Token Secret
|
||||
|
||||
The JWT token secret needs to be kept secure. Anyone with this secret can generate valid JWT tokens to authenticate with Frigate. This should be a cryptographically random string of at least 64 characters.
|
||||
|
@ -167,6 +167,8 @@ class LicensePlateProcessingMixin:
|
||||
outputs = self.model_runner.recognition_model(norm_images)
|
||||
except Exception as e:
|
||||
logger.warning(f"Error running LPR recognition model: {e}")
|
||||
return [], []
|
||||
|
||||
return self.ctc_decoder(outputs)
|
||||
|
||||
def _process_license_plate(
|
||||
|
@ -6,6 +6,7 @@ import json
|
||||
import logging
|
||||
import os
|
||||
import shutil
|
||||
from pathlib import Path
|
||||
from typing import Any, Optional
|
||||
|
||||
import cv2
|
||||
@ -538,4 +539,4 @@ class FaceRealTimeProcessor(RealTimeProcessorApi):
|
||||
|
||||
# delete oldest face image if maximum is reached
|
||||
if len(files) > self.config.face_recognition.save_attempts:
|
||||
os.unlink(os.path.join(folder, files[-1]))
|
||||
Path(os.path.join(folder, files[-1])).unlink(missing_ok=True)
|
||||
|
@ -106,6 +106,9 @@ export function CameraLineGraph({
|
||||
labels: {
|
||||
rotate: 0,
|
||||
formatter: formatTime,
|
||||
style: {
|
||||
colors: "#6B6B6B",
|
||||
},
|
||||
},
|
||||
axisBorder: {
|
||||
show: false,
|
||||
@ -118,6 +121,9 @@ export function CameraLineGraph({
|
||||
show: true,
|
||||
labels: {
|
||||
formatter: (val: number) => Math.ceil(val).toString(),
|
||||
style: {
|
||||
colors: "#6B6B6B",
|
||||
},
|
||||
},
|
||||
min: 0,
|
||||
},
|
||||
@ -138,7 +144,7 @@ export function CameraLineGraph({
|
||||
className="size-2"
|
||||
style={{ color: GRAPH_COLORS[labelIdx] }}
|
||||
/>
|
||||
<div className="text-xs text-muted-foreground">
|
||||
<div className="text-xs text-secondary-foreground">
|
||||
{t("cameras.label." + label)}
|
||||
</div>
|
||||
<div className="text-xs text-primary">
|
||||
@ -243,6 +249,9 @@ export function EventsPerSecondsLineGraph({
|
||||
labels: {
|
||||
rotate: 0,
|
||||
formatter: formatTime,
|
||||
style: {
|
||||
colors: "#6B6B6B",
|
||||
},
|
||||
},
|
||||
axisBorder: {
|
||||
show: false,
|
||||
@ -255,6 +264,9 @@ export function EventsPerSecondsLineGraph({
|
||||
show: true,
|
||||
labels: {
|
||||
formatter: (val: number) => Math.ceil(val).toString(),
|
||||
style: {
|
||||
colors: "#6B6B6B",
|
||||
},
|
||||
},
|
||||
min: 0,
|
||||
},
|
||||
@ -268,7 +280,7 @@ export function EventsPerSecondsLineGraph({
|
||||
return (
|
||||
<div className="flex w-full flex-col">
|
||||
<div className="flex items-center gap-1">
|
||||
<div className="text-xs text-muted-foreground">{name}</div>
|
||||
<div className="text-xs text-secondary-foreground">{name}</div>
|
||||
<div className="text-xs text-primary">
|
||||
{lastValue}
|
||||
{unit}
|
||||
|
@ -138,6 +138,9 @@ export function ThresholdBarGraph({
|
||||
labels: {
|
||||
rotate: 0,
|
||||
formatter: formatTime,
|
||||
style: {
|
||||
colors: "#6B6B6B",
|
||||
},
|
||||
},
|
||||
axisBorder: {
|
||||
show: false,
|
||||
@ -150,6 +153,9 @@ export function ThresholdBarGraph({
|
||||
show: true,
|
||||
labels: {
|
||||
formatter: (val: number) => Math.ceil(val).toString(),
|
||||
style: {
|
||||
colors: "#6B6B6B",
|
||||
},
|
||||
},
|
||||
min: 0,
|
||||
max: yMax,
|
||||
@ -180,7 +186,7 @@ export function ThresholdBarGraph({
|
||||
return (
|
||||
<div className="flex w-full flex-col">
|
||||
<div className="flex items-center gap-1">
|
||||
<div className="text-xs text-muted-foreground">{name}</div>
|
||||
<div className="text-xs text-secondary-foreground">{name}</div>
|
||||
<div className="text-xs text-primary">
|
||||
{lastValue}
|
||||
{unit}
|
||||
|
@ -250,7 +250,9 @@ export default function VideoControls({
|
||||
>
|
||||
<DropdownMenuTrigger>{`${playbackRate}x`}</DropdownMenuTrigger>
|
||||
<DropdownMenuContent
|
||||
portalProps={{ container: controlsContainerRef.current }}
|
||||
portalProps={{
|
||||
container: containerRef?.current ?? controlsContainerRef.current,
|
||||
}}
|
||||
>
|
||||
<DropdownMenuRadioGroup
|
||||
onValueChange={(rate) => onSetPlaybackRate(parseFloat(rate))}
|
||||
|
@ -209,13 +209,24 @@ function ConfigEditor() {
|
||||
};
|
||||
}, [hasChanges, t]);
|
||||
|
||||
useEffect(() => {
|
||||
if (editorRef.current) {
|
||||
// Small delay to ensure DOM has updated
|
||||
const timeoutId = setTimeout(() => {
|
||||
editorRef.current?.layout();
|
||||
}, 0);
|
||||
|
||||
return () => clearTimeout(timeoutId);
|
||||
}
|
||||
}, [error]);
|
||||
|
||||
if (!config) {
|
||||
return <ActivityIndicator />;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="absolute bottom-2 left-0 right-0 top-2 md:left-2">
|
||||
<div className="relative h-full overflow-hidden">
|
||||
<div className="relative flex h-full flex-col overflow-hidden">
|
||||
<div className="mr-1 flex items-center justify-between">
|
||||
<Heading as="h2" className="mb-0 ml-1 md:ml-0">
|
||||
{t("configEditor")}
|
||||
@ -254,13 +265,14 @@ function ConfigEditor() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{error && (
|
||||
<div className="mt-2 max-h-[30%] overflow-auto whitespace-pre-wrap border-2 border-muted bg-background_alt p-4 text-sm text-danger md:max-h-[40%]">
|
||||
{error}
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div ref={configRef} className="mt-2 h-[calc(100%-2.75rem)]" />
|
||||
<div className="flex flex-1 flex-col overflow-hidden">
|
||||
{error && (
|
||||
<div className="mt-2 max-h-[30%] min-h-[2.5rem] overflow-auto whitespace-pre-wrap border-2 border-muted bg-background_alt p-4 text-sm text-danger md:max-h-[40%]">
|
||||
{error}
|
||||
</div>
|
||||
)}
|
||||
<div ref={configRef} className="flex-1 overflow-hidden" />
|
||||
</div>
|
||||
</div>
|
||||
<Toaster closeButton={true} />
|
||||
<RestartDialog
|
||||
|
Loading…
Reference in New Issue
Block a user