mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-02-02 09:15:22 +03:00
feat: add experimental feature + fix old camera padding
This commit is contained in:
parent
e7ab6d2d0d
commit
875c74686d
@ -43,6 +43,8 @@ class DetectorConfig(FrigateBaseModel):
|
|||||||
device: str = Field(default="usb", title="Device Type")
|
device: str = Field(default="usb", title="Device Type")
|
||||||
num_threads: int = Field(default=3, title="Number of detection threads")
|
num_threads: int = Field(default=3, title="Number of detection threads")
|
||||||
|
|
||||||
|
class UIConfig(FrigateBaseModel):
|
||||||
|
useExperimentalUI: bool = Field(default=False, title="Experimental UI")
|
||||||
|
|
||||||
class MqttConfig(FrigateBaseModel):
|
class MqttConfig(FrigateBaseModel):
|
||||||
host: str = Field(title="MQTT Host")
|
host: str = Field(title="MQTT Host")
|
||||||
@ -682,6 +684,7 @@ class FrigateConfig(FrigateBaseModel):
|
|||||||
environment_vars: Dict[str, str] = Field(
|
environment_vars: Dict[str, str] = Field(
|
||||||
default_factory=dict, title="Frigate environment variables."
|
default_factory=dict, title="Frigate environment variables."
|
||||||
)
|
)
|
||||||
|
ui: UIConfig = Field(default_factory=UIConfig, title="UI configuration.")
|
||||||
model: ModelConfig = Field(
|
model: ModelConfig = Field(
|
||||||
default_factory=ModelConfig, title="Detection model configuration."
|
default_factory=ModelConfig, title="Detection model configuration."
|
||||||
)
|
)
|
||||||
|
|||||||
@ -10,29 +10,30 @@ import { DarkModeProvider, DrawerProvider } from './context';
|
|||||||
import { FetchStatus, useConfig } from './api';
|
import { FetchStatus, useConfig } from './api';
|
||||||
|
|
||||||
export default function App() {
|
export default function App() {
|
||||||
const { status } = useConfig();
|
const { status, data: config } = useConfig();
|
||||||
|
const cameraComponent = config && config.ui.useExperimentalUI ? Routes.getCameraV2 : Routes.getCamera;
|
||||||
return (
|
return (
|
||||||
<DarkModeProvider>
|
<DarkModeProvider>
|
||||||
<DrawerProvider>
|
<DrawerProvider>
|
||||||
<div data-testid="app" className="w-full">
|
<div data-testid='app' className='w-full'>
|
||||||
<AppBar />
|
<AppBar />
|
||||||
{status !== FetchStatus.LOADED ? (
|
{status !== FetchStatus.LOADED ? (
|
||||||
<div className="flex flex-grow-1 min-h-screen justify-center items-center">
|
<div className='flex flex-grow-1 min-h-screen justify-center items-center'>
|
||||||
<ActivityIndicator />
|
<ActivityIndicator />
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="flex flex-row min-h-screen w-full bg-white dark:bg-gray-900 text-gray-900 dark:text-white">
|
<div className='flex flex-row min-h-screen w-full bg-white dark:bg-gray-900 text-gray-900 dark:text-white'>
|
||||||
<Sidebar />
|
<Sidebar />
|
||||||
<div className="w-full flex-auto mt-16 min-w-0">
|
<div className='w-full flex-auto mt-16 min-w-0'>
|
||||||
<Router>
|
<Router>
|
||||||
<AsyncRoute path="/cameras/:camera/editor" getComponent={Routes.getCameraMap} />
|
<AsyncRoute path='/cameras/:camera/editor' getComponent={Routes.getCameraMap} />
|
||||||
<AsyncRoute path="/cameras/:camera" getComponent={Routes.getCameraV2} />
|
<AsyncRoute path='/cameras/:camera' getComponent={cameraComponent} />
|
||||||
<AsyncRoute path="/birdseye" getComponent={Routes.getBirdseye} />
|
<AsyncRoute path='/birdseye' getComponent={Routes.getBirdseye} />
|
||||||
<AsyncRoute path="/events" getComponent={Routes.getEvents} />
|
<AsyncRoute path='/events' getComponent={Routes.getEvents} />
|
||||||
<AsyncRoute path="/recording/:camera/:date?/:hour?/:seconds?" getComponent={Routes.getRecording} />
|
<AsyncRoute path='/recording/:camera/:date?/:hour?/:seconds?' getComponent={Routes.getRecording} />
|
||||||
<AsyncRoute path="/debug" getComponent={Routes.getDebug} />
|
<AsyncRoute path='/debug' getComponent={Routes.getDebug} />
|
||||||
<AsyncRoute path="/styleguide" getComponent={Routes.getStyleGuide} />
|
<AsyncRoute path='/styleguide' getComponent={Routes.getStyleGuide} />
|
||||||
<Cameras default path="/" />
|
<Cameras default path='/' />
|
||||||
</Router>
|
</Router>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -162,7 +162,9 @@ export default function Timeline({ events, offset, currentIndex, onChange }) {
|
|||||||
<div className='relative flex-grow-1'>
|
<div className='relative flex-grow-1'>
|
||||||
<div className='absolute left-0 top-0 h-full w-full' style={{ textAlign: 'center' }}>
|
<div className='absolute left-0 top-0 h-full w-full' style={{ textAlign: 'center' }}>
|
||||||
<div className='h-full' style={{ margin: '0 auto', textAlign: 'center' }}>
|
<div className='h-full' style={{ margin: '0 auto', textAlign: 'center' }}>
|
||||||
<span className='z-20 text-white'>{markerTime && <span>{markerTime.toLocaleTimeString()}</span>}</span>
|
<span className='z-20 text-black dark:text-white'>
|
||||||
|
{markerTime && <span>{markerTime.toLocaleTimeString()}</span>}
|
||||||
|
</span>
|
||||||
<div
|
<div
|
||||||
className='z-20 h-full absolute'
|
className='z-20 h-full absolute'
|
||||||
style={{
|
style={{
|
||||||
|
|||||||
@ -21,7 +21,7 @@ export default function Camera({ camera }) {
|
|||||||
const [viewMode, setViewMode] = useState('live');
|
const [viewMode, setViewMode] = useState('live');
|
||||||
|
|
||||||
const cameraConfig = config?.cameras[camera];
|
const cameraConfig = config?.cameras[camera];
|
||||||
const liveWidth = Math.round(cameraConfig.live.height * (cameraConfig.detect.width / cameraConfig.detect.height))
|
const liveWidth = Math.round(cameraConfig.live.height * (cameraConfig.detect.width / cameraConfig.detect.height));
|
||||||
const [options, setOptions] = usePersistence(`${camera}-feed`, emptyObject);
|
const [options, setOptions] = usePersistence(`${camera}-feed`, emptyObject);
|
||||||
|
|
||||||
const handleSetOption = useCallback(
|
const handleSetOption = useCallback(
|
||||||
@ -48,36 +48,36 @@ export default function Camera({ camera }) {
|
|||||||
}, [showSettings, setShowSettings]);
|
}, [showSettings, setShowSettings]);
|
||||||
|
|
||||||
const optionContent = showSettings ? (
|
const optionContent = showSettings ? (
|
||||||
<div className="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-4">
|
<div className='grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-4'>
|
||||||
<Switch
|
<Switch
|
||||||
checked={options['bbox']}
|
checked={options['bbox']}
|
||||||
id="bbox"
|
id='bbox'
|
||||||
onChange={handleSetOption}
|
onChange={handleSetOption}
|
||||||
label="Bounding box"
|
label='Bounding box'
|
||||||
labelPosition="after"
|
labelPosition='after'
|
||||||
/>
|
/>
|
||||||
<Switch
|
<Switch
|
||||||
checked={options['timestamp']}
|
checked={options['timestamp']}
|
||||||
id="timestamp"
|
id='timestamp'
|
||||||
onChange={handleSetOption}
|
onChange={handleSetOption}
|
||||||
label="Timestamp"
|
label='Timestamp'
|
||||||
labelPosition="after"
|
labelPosition='after'
|
||||||
/>
|
/>
|
||||||
<Switch checked={options['zones']} id="zones" onChange={handleSetOption} label="Zones" labelPosition="after" />
|
<Switch checked={options['zones']} id='zones' onChange={handleSetOption} label='Zones' labelPosition='after' />
|
||||||
<Switch checked={options['mask']} id="mask" onChange={handleSetOption} label="Masks" labelPosition="after" />
|
<Switch checked={options['mask']} id='mask' onChange={handleSetOption} label='Masks' labelPosition='after' />
|
||||||
<Switch
|
<Switch
|
||||||
checked={options['motion']}
|
checked={options['motion']}
|
||||||
id="motion"
|
id='motion'
|
||||||
onChange={handleSetOption}
|
onChange={handleSetOption}
|
||||||
label="Motion boxes"
|
label='Motion boxes'
|
||||||
labelPosition="after"
|
labelPosition='after'
|
||||||
/>
|
/>
|
||||||
<Switch
|
<Switch
|
||||||
checked={options['regions']}
|
checked={options['regions']}
|
||||||
id="regions"
|
id='regions'
|
||||||
onChange={handleSetOption}
|
onChange={handleSetOption}
|
||||||
label="Regions"
|
label='Regions'
|
||||||
labelPosition="after"
|
labelPosition='after'
|
||||||
/>
|
/>
|
||||||
<Link href={`/cameras/${camera}/editor`}>Mask & Zone creator</Link>
|
<Link href={`/cameras/${camera}/editor`}>Mask & Zone creator</Link>
|
||||||
</div>
|
</div>
|
||||||
@ -92,38 +92,37 @@ export default function Camera({ camera }) {
|
|||||||
</div>
|
</div>
|
||||||
</Fragment>
|
</Fragment>
|
||||||
);
|
);
|
||||||
}
|
} else if (viewMode === 'debug') {
|
||||||
else if (viewMode === 'debug') {
|
|
||||||
player = (
|
player = (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
<div>
|
<div>
|
||||||
<AutoUpdatingCameraImage camera={camera} searchParams={searchParams} />
|
<AutoUpdatingCameraImage camera={camera} searchParams={searchParams} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Button onClick={handleToggleSettings} type="text">
|
<Button onClick={handleToggleSettings} type='text'>
|
||||||
<span className="w-5 h-5">
|
<span className='w-5 h-5'>
|
||||||
<SettingsIcon />
|
<SettingsIcon />
|
||||||
</span>{' '}
|
</span>{' '}
|
||||||
<span>{showSettings ? 'Hide' : 'Show'} Options</span>
|
<span>{showSettings ? 'Hide' : 'Show'} Options</span>
|
||||||
</Button>
|
</Button>
|
||||||
{showSettings ? <Card header="Options" elevated={false} content={optionContent} /> : null}
|
{showSettings ? <Card header='Options' elevated={false} content={optionContent} /> : null}
|
||||||
</Fragment>
|
</Fragment>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="space-y-4">
|
<div className='space-y-4 p-2 px-4'>
|
||||||
<Heading size="2xl">{camera}</Heading>
|
<Heading size='2xl'>{camera}</Heading>
|
||||||
<ButtonsTabbed viewModes={['live', 'debug']} setViewMode={setViewMode} />
|
<ButtonsTabbed viewModes={['live', 'debug']} setViewMode={setViewMode} />
|
||||||
|
|
||||||
{player}
|
{player}
|
||||||
|
|
||||||
<div className="space-y-4">
|
<div className='space-y-4'>
|
||||||
<Heading size="sm">Tracked objects</Heading>
|
<Heading size='sm'>Tracked objects</Heading>
|
||||||
<div className="flex flex-wrap justify-start">
|
<div className='flex flex-wrap justify-start'>
|
||||||
{cameraConfig.objects.track.map((objectType) => (
|
{cameraConfig.objects.track.map((objectType) => (
|
||||||
<Card
|
<Card
|
||||||
className="mb-4 mr-4"
|
className='mb-4 mr-4'
|
||||||
key={objectType}
|
key={objectType}
|
||||||
header={objectType}
|
header={objectType}
|
||||||
href={`/events?camera=${camera}&label=${objectType}`}
|
href={`/events?camera=${camera}&label=${objectType}`}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user