Compare commits

...

48 Commits

Author SHA1 Message Date
Hosted Weblate
5bc32ebc11
Update translation files
Updated by "Squash Git commits" add-on in Weblate.

Translation: Frigate NVR/common
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/common/
2026-03-04 16:08:58 +00:00
Hosted Weblate
e1b9af56b9
Translated using Weblate (Cantonese (Traditional Han script))
Currently translated at 0.2% (1 of 464 strings)

Added translation using Weblate (Cantonese (Traditional Han script))

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Languages add-on <noreply-addon-languages@weblate.org>
Co-authored-by: beginner2047 <leoywng44@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-cameras/yue_Hant/
Translation: Frigate NVR/Config - Cameras
2026-03-04 16:08:55 +00:00
Hosted Weblate
3b2f3e5676
Added translation using Weblate (Norwegian Bokmål)
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Languages add-on <noreply-addon-languages@weblate.org>
2026-03-04 16:08:54 +00:00
Hosted Weblate
4457f9d73a
Added translation using Weblate (Chinese (Simplified Han script))
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Languages add-on <noreply-addon-languages@weblate.org>
2026-03-04 16:08:51 +00:00
Hosted Weblate
532a2727e7
Added translation using Weblate (Chinese (Traditional Han script))
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Languages add-on <noreply-addon-languages@weblate.org>
2026-03-04 16:08:50 +00:00
Hosted Weblate
58458f4d07
Added translation using Weblate (Uzbek)
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Languages add-on <noreply-addon-languages@weblate.org>
2026-03-04 16:08:48 +00:00
Hosted Weblate
7116bff118
Added translation using Weblate (Urdu)
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Languages add-on <noreply-addon-languages@weblate.org>
2026-03-04 16:08:47 +00:00
Hosted Weblate
5eb02e5cba
Added translation using Weblate (Slovenian)
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Languages add-on <noreply-addon-languages@weblate.org>
2026-03-04 16:08:46 +00:00
Hosted Weblate
3c43dbf437
Added translation using Weblate (Slovak)
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Languages add-on <noreply-addon-languages@weblate.org>
2026-03-04 16:08:44 +00:00
Hosted Weblate
d87e359256
Added translation using Weblate (Korean)
Translated using Weblate (Korean)

Currently translated at 86.2% (50 of 58 strings)

Translated using Weblate (Korean)

Currently translated at 99.5% (227 of 228 strings)

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: John <john@akfn.net>
Co-authored-by: Languages add-on <noreply-addon-languages@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/common/ko/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-dialog/ko/
Translation: Frigate NVR/common
Translation: Frigate NVR/components-dialog
2026-03-04 16:08:43 +00:00
Hosted Weblate
66448952c6
Added translation using Weblate (Serbian)
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Languages add-on <noreply-addon-languages@weblate.org>
2026-03-04 16:08:41 +00:00
Hosted Weblate
211b91c6a3
Added translation using Weblate (Finnish)
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Languages add-on <noreply-addon-languages@weblate.org>
2026-03-04 16:08:40 +00:00
Hosted Weblate
9180bf53c0
Added translation using Weblate (Persian)
Translated using Weblate (Persian)

Currently translated at 99.0% (215 of 217 strings)

Co-authored-by: Amir reza Irani ali poor <amir1376irani@yahoo.com>
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Languages add-on <noreply-addon-languages@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/common/fa/
Translation: Frigate NVR/common
2026-03-04 16:08:39 +00:00
Hosted Weblate
baa555b7c0
Added translation using Weblate (Swedish)
Translated using Weblate (Swedish)

Currently translated at 96.5% (56 of 58 strings)

Translated using Weblate (Swedish)

Currently translated at 92.5% (136 of 147 strings)

Translated using Weblate (Swedish)

Currently translated at 95.1% (217 of 228 strings)

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Languages add-on <noreply-addon-languages@weblate.org>
Co-authored-by: ThomasW <thomas.wursig@remote24.se>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/common/sv/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-dialog/sv/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-system/sv/
Translation: Frigate NVR/common
Translation: Frigate NVR/components-dialog
Translation: Frigate NVR/views-system
2026-03-04 16:08:38 +00:00
Hosted Weblate
c91363131f
Translated using Weblate (French)
Currently translated at 80.4% (720 of 895 strings)

Translated using Weblate (French)

Currently translated at 99.5% (227 of 228 strings)

Translated using Weblate (French)

Currently translated at 33.1% (154 of 464 strings)

Translated using Weblate (French)

Currently translated at 100.0% (147 of 147 strings)

Added translation using Weblate (French)

Translated using Weblate (French)

Currently translated at 100.0% (58 of 58 strings)

Translated using Weblate (French)

Currently translated at 100.0% (23 of 23 strings)

Translated using Weblate (French)

Currently translated at 93.8% (138 of 147 strings)

Translated using Weblate (French)

Currently translated at 96.4% (220 of 228 strings)

Translated using Weblate (French)

Currently translated at 81.0% (716 of 883 strings)

Co-authored-by: Apocoloquintose <bertrand.moreux@gmail.com>
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Languages add-on <noreply-addon-languages@weblate.org>
Co-authored-by: eepy-furry <eepy-furry@users.noreply.hosted.weblate.org>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/common/fr/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-dialog/fr/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-cameras/fr/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-exports/fr/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-settings/fr/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-system/fr/
Translation: Frigate NVR/Config - Cameras
Translation: Frigate NVR/common
Translation: Frigate NVR/components-dialog
Translation: Frigate NVR/views-exports
Translation: Frigate NVR/views-settings
Translation: Frigate NVR/views-system
2026-03-04 16:08:36 +00:00
Hosted Weblate
ef9fe5d8d8
Added translation using Weblate (Spanish)
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Languages add-on <noreply-addon-languages@weblate.org>
2026-03-04 16:08:34 +00:00
Hosted Weblate
97d64e3576
Added translation using Weblate (Dutch)
Translated using Weblate (Dutch)

Currently translated at 100.0% (58 of 58 strings)

Translated using Weblate (Dutch)

Currently translated at 100.0% (23 of 23 strings)

Translated using Weblate (Dutch)

Currently translated at 74.9% (671 of 895 strings)

Translated using Weblate (Dutch)

Currently translated at 93.1% (137 of 147 strings)

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Languages add-on <noreply-addon-languages@weblate.org>
Co-authored-by: Marijn <168113859+Marijn0@users.noreply.github.com>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-dialog/nl/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-exports/nl/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-settings/nl/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-system/nl/
Translation: Frigate NVR/components-dialog
Translation: Frigate NVR/views-exports
Translation: Frigate NVR/views-settings
Translation: Frigate NVR/views-system
2026-03-04 16:08:33 +00:00
Hosted Weblate
a0adb117ca
Added translation using Weblate (Indonesian)
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Languages add-on <noreply-addon-languages@weblate.org>
2026-03-04 16:08:32 +00:00
Hosted Weblate
2442dc35b5
Added translation using Weblate (Arabic)
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Languages add-on <noreply-addon-languages@weblate.org>
2026-03-04 16:08:31 +00:00
Hosted Weblate
9151314d10
Added translation using Weblate (Italian)
Translated using Weblate (Italian)

Currently translated at 100.0% (228 of 228 strings)

Translated using Weblate (Italian)

Currently translated at 100.0% (58 of 58 strings)

Translated using Weblate (Italian)

Currently translated at 100.0% (23 of 23 strings)

Translated using Weblate (Italian)

Currently translated at 100.0% (147 of 147 strings)

Co-authored-by: Gringo <ita.translations@tiscali.it>
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Languages add-on <noreply-addon-languages@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/common/it/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-dialog/it/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-exports/it/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-system/it/
Translation: Frigate NVR/common
Translation: Frigate NVR/components-dialog
Translation: Frigate NVR/views-exports
Translation: Frigate NVR/views-system
2026-03-04 16:08:30 +00:00
Hosted Weblate
78bceb8ec2
Translated using Weblate (Polish)
Currently translated at 16.5% (77 of 464 strings)

Added translation using Weblate (Polish)

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: J P <jpoloczek24@gmail.com>
Co-authored-by: Languages add-on <noreply-addon-languages@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-cameras/pl/
Translation: Frigate NVR/Config - Cameras
2026-03-04 16:08:28 +00:00
Hosted Weblate
f682ea3509
Added translation using Weblate (Malayalam)
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Languages add-on <noreply-addon-languages@weblate.org>
2026-03-04 16:08:27 +00:00
Hosted Weblate
05a58d8d81
Added translation using Weblate (Hebrew)
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Languages add-on <noreply-addon-languages@weblate.org>
2026-03-04 16:08:25 +00:00
Hosted Weblate
9e45b016c1
Added translation using Weblate (Hindi)
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Languages add-on <noreply-addon-languages@weblate.org>
2026-03-04 16:08:24 +00:00
Hosted Weblate
31509dbc77
Added translation using Weblate (Hungarian)
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Languages add-on <noreply-addon-languages@weblate.org>
2026-03-04 16:08:23 +00:00
Hosted Weblate
e342de3e8c
Added translation using Weblate (Croatian)
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Languages add-on <noreply-addon-languages@weblate.org>
2026-03-04 16:08:21 +00:00
Hosted Weblate
c2b57c6d9b
Added translation using Weblate (Icelandic)
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Languages add-on <noreply-addon-languages@weblate.org>
2026-03-04 16:08:19 +00:00
Hosted Weblate
8df568dabb
Added translation using Weblate (Vietnamese)
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Languages add-on <noreply-addon-languages@weblate.org>
2026-03-04 16:08:18 +00:00
Hosted Weblate
57dd19aeaf
Translated using Weblate (Portuguese)
Currently translated at 89.6% (52 of 58 strings)

Added translation using Weblate (Portuguese)

Translated using Weblate (Portuguese)

Currently translated at 89.6% (52 of 58 strings)

Translated using Weblate (Portuguese)

Currently translated at 90.7% (49 of 54 strings)

Translated using Weblate (Portuguese)

Currently translated at 29.5% (36 of 122 strings)

Translated using Weblate (Portuguese)

Currently translated at 43.4% (10 of 23 strings)

Co-authored-by: Abel Nunes <lidh08@gmail.com>
Co-authored-by: Hellyson Rodrigo Parteka <hellysonrp@gmail.com>
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Languages add-on <noreply-addon-languages@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-dialog/pt/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-classificationmodel/pt/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-exports/pt/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-facelibrary/pt/
Translation: Frigate NVR/components-dialog
Translation: Frigate NVR/views-classificationmodel
Translation: Frigate NVR/views-exports
Translation: Frigate NVR/views-facelibrary
2026-03-04 16:08:17 +00:00
Hosted Weblate
233a78b84e
Added translation using Weblate (Czech)
Translated using Weblate (Czech)

Currently translated at 100.0% (217 of 217 strings)

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Languages add-on <noreply-addon-languages@weblate.org>
Co-authored-by: vaclav <zahorec@orcave.com>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/common/cs/
Translation: Frigate NVR/common
2026-03-04 16:08:15 +00:00
Hosted Weblate
8614768cf4
Update translation files
Updated by "Squash Git commits" add-on in Weblate.

Added translation using Weblate (Catalan)

Added translation using Weblate (Catalan)

Added translation using Weblate (Catalan)

Translated using Weblate (Catalan)

Currently translated at 100.0% (464 of 464 strings)

Translated using Weblate (Catalan)

Currently translated at 100.0% (136 of 136 strings)

Translated using Weblate (Catalan)

Currently translated at 100.0% (895 of 895 strings)

Translated using Weblate (Catalan)

Currently translated at 100.0% (118 of 118 strings)

Added translation using Weblate (Catalan)

Translated using Weblate (Catalan)

Currently translated at 100.0% (895 of 895 strings)

Translated using Weblate (Catalan)

Currently translated at 100.0% (228 of 228 strings)

Translated using Weblate (Catalan)

Currently translated at 100.0% (23 of 23 strings)

Translated using Weblate (Catalan)

Currently translated at 100.0% (58 of 58 strings)

Translated using Weblate (Catalan)

Currently translated at 100.0% (122 of 122 strings)

Translated using Weblate (Catalan)

Currently translated at 100.0% (883 of 883 strings)

Translated using Weblate (Catalan)

Currently translated at 100.0% (147 of 147 strings)

Co-authored-by: Eduardo Pastor Fernández <123eduardoneko123@gmail.com>
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Josh Hawkins <joshhawk2003@yahoo.com>
Co-authored-by: Languages add-on <noreply-addon-languages@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/common/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/common/ca/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-dialog/ca/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-cameras/ca/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/objects/ca/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-classificationmodel/ca/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-explore/ca/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-exports/ca/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-settings/ca/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-system/ca/
Translation: Frigate NVR/Config - Cameras
Translation: Frigate NVR/common
Translation: Frigate NVR/components-dialog
Translation: Frigate NVR/objects
Translation: Frigate NVR/views-classificationmodel
Translation: Frigate NVR/views-explore
Translation: Frigate NVR/views-exports
Translation: Frigate NVR/views-settings
Translation: Frigate NVR/views-system
2026-03-04 16:08:14 +00:00
Hosted Weblate
08773100e0
Added translation using Weblate (Japanese)
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Languages add-on <noreply-addon-languages@weblate.org>
2026-03-04 16:08:12 +00:00
Hosted Weblate
16b28c3c09
Added translation using Weblate (Ukrainian)
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Languages add-on <noreply-addon-languages@weblate.org>
2026-03-04 16:08:11 +00:00
Hosted Weblate
3fa2694ab4
Added translation using Weblate (Bulgarian)
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Languages add-on <noreply-addon-languages@weblate.org>
2026-03-04 16:08:10 +00:00
Hosted Weblate
688d736f65
Update translation files
Updated by "Squash Git commits" add-on in Weblate.

Added translation using Weblate (Romanian)

Added translation using Weblate (Romanian)

Added translation using Weblate (Romanian)

Added translation using Weblate (Romanian)

Translated using Weblate (Romanian)

Currently translated at 100.0% (23 of 23 strings)

Translated using Weblate (Romanian)

Currently translated at 100.0% (98 of 98 strings)

Translated using Weblate (Romanian)

Currently translated at 100.0% (46 of 46 strings)

Translated using Weblate (Romanian)

Currently translated at 100.0% (74 of 74 strings)

Translated using Weblate (Romanian)

Currently translated at 100.0% (49 of 49 strings)

Translated using Weblate (Romanian)

Currently translated at 100.0% (147 of 147 strings)

Translated using Weblate (Romanian)

Currently translated at 100.0% (228 of 228 strings)

Translated using Weblate (Romanian)

Currently translated at 100.0% (58 of 58 strings)

Translated using Weblate (Romanian)

Currently translated at 100.0% (136 of 136 strings)

Translated using Weblate (Romanian)

Currently translated at 100.0% (895 of 895 strings)

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Languages add-on <noreply-addon-languages@weblate.org>
Co-authored-by: lukasig <lukasig@hotmail.com>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/common/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/common/ro/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-camera/ro/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-dialog/ro/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-filter/ro/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-explore/ro/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-exports/ro/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-live/ro/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-search/ro/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-settings/ro/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-system/ro/
Translation: Frigate NVR/common
Translation: Frigate NVR/components-camera
Translation: Frigate NVR/components-dialog
Translation: Frigate NVR/components-filter
Translation: Frigate NVR/views-explore
Translation: Frigate NVR/views-exports
Translation: Frigate NVR/views-live
Translation: Frigate NVR/views-search
Translation: Frigate NVR/views-settings
Translation: Frigate NVR/views-system
2026-03-04 16:08:08 +00:00
Hosted Weblate
d7c1b1b95a
Added translation using Weblate (Russian)
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Languages add-on <noreply-addon-languages@weblate.org>
2026-03-04 16:08:07 +00:00
Hosted Weblate
f597e30f11
Added translation using Weblate (Estonian)
Translated using Weblate (Estonian)

Currently translated at 100.0% (228 of 228 strings)

Translated using Weblate (Estonian)

Currently translated at 99.5% (227 of 228 strings)

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Languages add-on <noreply-addon-languages@weblate.org>
Co-authored-by: Priit Jõerüüt <jrthwlate@users.noreply.hosted.weblate.org>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/common/et/
Translation: Frigate NVR/common
2026-03-04 16:08:05 +00:00
Hosted Weblate
aaa92fa01e
Added translation using Weblate (Greek)
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Languages add-on <noreply-addon-languages@weblate.org>
2026-03-04 16:08:04 +00:00
Hosted Weblate
85327a48bc
Added translation using Weblate (Danish)
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Languages add-on <noreply-addon-languages@weblate.org>
2026-03-04 16:08:03 +00:00
Hosted Weblate
eaff63ca60
Added translation using Weblate (German)
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Languages add-on <noreply-addon-languages@weblate.org>
2026-03-04 16:08:02 +00:00
Hosted Weblate
84d53de33c
Translated using Weblate (Portuguese (Brazil))
Currently translated at 96.5% (56 of 58 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (54 of 54 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (98 of 98 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (228 of 228 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (23 of 23 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 2.3% (11 of 464 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 50.5% (452 of 895 strings)

Added translation using Weblate (Portuguese (Brazil))

Co-authored-by: Hellyson Rodrigo Parteka <hellysonrp@gmail.com>
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Languages add-on <noreply-addon-languages@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/common/pt_BR/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-dialog/pt_BR/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-cameras/pt_BR/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-exports/pt_BR/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-facelibrary/pt_BR/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-live/pt_BR/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-settings/pt_BR/
Translation: Frigate NVR/Config - Cameras
Translation: Frigate NVR/common
Translation: Frigate NVR/components-dialog
Translation: Frigate NVR/views-exports
Translation: Frigate NVR/views-facelibrary
Translation: Frigate NVR/views-live
Translation: Frigate NVR/views-settings
2026-03-04 16:08:01 +00:00
Hosted Weblate
2559360eff
Added translation using Weblate (Thai)
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Languages add-on <noreply-addon-languages@weblate.org>
2026-03-04 16:07:59 +00:00
Hosted Weblate
f75311a947
Added translation using Weblate (Lithuanian)
Translated using Weblate (Lithuanian)

Currently translated at 62.1% (556 of 895 strings)

Translated using Weblate (Lithuanian)

Currently translated at 96.5% (56 of 58 strings)

Translated using Weblate (Lithuanian)

Currently translated at 100.0% (23 of 23 strings)

Translated using Weblate (Lithuanian)

Currently translated at 100.0% (54 of 54 strings)

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Karolis Jeicenas <jeicenas@gmail.com>
Co-authored-by: Languages add-on <noreply-addon-languages@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-dialog/lt/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-exports/lt/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-facelibrary/lt/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-settings/lt/
Translation: Frigate NVR/components-dialog
Translation: Frigate NVR/views-exports
Translation: Frigate NVR/views-facelibrary
Translation: Frigate NVR/views-settings
2026-03-04 16:07:58 +00:00
Hosted Weblate
607d9b84ca
Added translation using Weblate (Latvian)
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Languages add-on <noreply-addon-languages@weblate.org>
2026-03-04 16:07:56 +00:00
Hosted Weblate
559c25a22c
Added translation using Weblate (Turkish)
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Languages add-on <noreply-addon-languages@weblate.org>
2026-03-04 16:07:55 +00:00
Hosted Weblate
62e2a20655
Added translation using Weblate (Galician)
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Languages add-on <noreply-addon-languages@weblate.org>
2026-03-04 16:07:53 +00:00
Josh Hawkins
95956a690b
Debug replay (#22212)
Some checks are pending
CI / AMD64 Build (push) Waiting to run
CI / ARM Build (push) Waiting to run
CI / Jetson Jetpack 6 (push) Waiting to run
CI / AMD64 Extra Build (push) Blocked by required conditions
CI / ARM Extra Build (push) Blocked by required conditions
CI / Synaptics Build (push) Blocked by required conditions
CI / Assemble and push default build (push) Blocked by required conditions
* debug replay implementation

* fix masks after dev rebase

* fix squash merge issues

* fix

* fix

* fix

* no need to write debug replay camera to config

* camera and filter button and dropdown

* add filters

* add ability to edit motion and object config for debug replay

* add debug draw overlay to debug replay

* add guard to prevent crash when camera is no longer in camera_states

* fix overflow due to radix absolutely positioned elements

* increase number of messages

* ensure deep_merge replaces existing list values when override is true

* add back button

* add debug replay to explore and review menus

* clean up

* clean up

* update instructions to prevent exposing exception info

* fix typing

* refactor output logic

* refactor with helper function

* move init to function for consistency
2026-03-04 10:07:34 -06:00
Josh Hawkins
5e7d426768
Add fullscreen controls to tracking details videos (#22252) 2026-03-04 07:59:12 -07:00
211 changed files with 7823 additions and 1232 deletions

View File

@ -324,6 +324,12 @@ try:
value = await sensor.read()
except Exception: # ❌ Too broad
logger.error("Failed")
# Returning exceptions in JSON responses
except ValueError as e:
return JSONResponse(
content={"success": False, "message": str(e)},
)
```
### ✅ Use These Instead
@ -353,6 +359,16 @@ try:
value = await sensor.read()
except SensorException as err: # ✅ Specific
logger.exception("Failed to read sensor")
# Safe error responses
except ValueError:
logger.exception("Invalid parameters for API request")
return JSONResponse(
content={
"success": False,
"message": "Invalid request parameters",
},
)
```
## Project-Specific Conventions

View File

@ -75,4 +75,4 @@ Many providers also have a public facing chat interface for their models. Downlo
- OpenAI - [ChatGPT](https://chatgpt.com)
- Gemini - [Google AI Studio](https://aistudio.google.com)
- Ollama - [Open WebUI](https://docs.openwebui.com/)
- Ollama - [Open WebUI](https://docs.openwebui.com/)

View File

@ -49,12 +49,13 @@ from frigate.stats.prometheus import get_metrics, update_metrics
from frigate.types import JobStatusTypesEnum
from frigate.util.builtin import (
clean_camera_user_pass,
deep_merge,
flatten_config_data,
load_labels,
process_config_query_string,
update_yaml_file_bulk,
)
from frigate.util.config import find_config_file
from frigate.util.config import apply_section_update, find_config_file
from frigate.util.schema import get_config_schema
from frigate.util.services import (
get_nvidia_driver_info,
@ -422,9 +423,100 @@ def config_save(save_option: str, body: Any = Body(media_type="text/plain")):
)
def _config_set_in_memory(request: Request, body: AppConfigSetBody) -> JSONResponse:
"""Apply config changes in-memory only, without writing to YAML.
Used for temporary config changes like debug replay camera tuning.
Updates the in-memory Pydantic config and publishes ZMQ updates,
bypassing YAML parsing entirely.
"""
try:
updates = {}
if body.config_data:
updates = flatten_config_data(body.config_data)
updates = {k: ("" if v is None else v) for k, v in updates.items()}
if not updates:
return JSONResponse(
content={"success": False, "message": "No configuration data provided"},
status_code=400,
)
config: FrigateConfig = request.app.frigate_config
# Group flat key paths into nested per-camera, per-section dicts
grouped: dict[str, dict[str, dict]] = {}
for key_path, value in updates.items():
parts = key_path.split(".")
if len(parts) < 3 or parts[0] != "cameras":
continue
cam, section = parts[1], parts[2]
grouped.setdefault(cam, {}).setdefault(section, {})
# Build nested dict from remaining path (e.g. "filters.person.threshold")
target = grouped[cam][section]
for part in parts[3:-1]:
target = target.setdefault(part, {})
if len(parts) > 3:
target[parts[-1]] = value
elif isinstance(value, dict):
grouped[cam][section] = deep_merge(
grouped[cam][section], value, override=True
)
else:
grouped[cam][section] = value
# Apply each section update
for cam_name, sections in grouped.items():
camera_config = config.cameras.get(cam_name)
if not camera_config:
return JSONResponse(
content={
"success": False,
"message": f"Camera '{cam_name}' not found",
},
status_code=400,
)
for section_name, update in sections.items():
err = apply_section_update(camera_config, section_name, update)
if err is not None:
return JSONResponse(
content={"success": False, "message": err},
status_code=400,
)
# Publish ZMQ updates so processing threads pick up changes
if body.update_topic and body.update_topic.startswith("config/cameras/"):
_, _, camera, field = body.update_topic.split("/")
settings = getattr(config.cameras.get(camera, None), field, None)
if settings is not None:
request.app.config_publisher.publish_update(
CameraConfigUpdateTopic(CameraConfigUpdateEnum[field], camera),
settings,
)
return JSONResponse(
content={"success": True, "message": "Config applied in-memory"},
status_code=200,
)
except Exception as e:
logger.error(f"Error applying config in-memory: {e}")
return JSONResponse(
content={"success": False, "message": "Error applying config"},
status_code=500,
)
@router.put("/config/set", dependencies=[Depends(require_role(["admin"]))])
def config_set(request: Request, body: AppConfigSetBody):
config_file = find_config_file()
if body.skip_save:
return _config_set_in_memory(request, body)
lock = FileLock(f"{config_file}.lock", timeout=5)
try:

176
frigate/api/debug_replay.py Normal file
View File

@ -0,0 +1,176 @@
"""Debug replay API endpoints."""
import asyncio
import logging
from datetime import datetime
from fastapi import APIRouter, Depends, Request
from fastapi.responses import JSONResponse
from pydantic import BaseModel, Field
from frigate.api.auth import require_role
from frigate.api.defs.tags import Tags
logger = logging.getLogger(__name__)
router = APIRouter(tags=[Tags.app])
class DebugReplayStartBody(BaseModel):
"""Request body for starting a debug replay session."""
camera: str = Field(title="Source camera name")
start_time: float = Field(title="Start timestamp")
end_time: float = Field(title="End timestamp")
class DebugReplayStartResponse(BaseModel):
"""Response for starting a debug replay session."""
success: bool
replay_camera: str
class DebugReplayStatusResponse(BaseModel):
"""Response for debug replay status."""
active: bool
replay_camera: str | None = None
source_camera: str | None = None
start_time: float | None = None
end_time: float | None = None
live_ready: bool = False
class DebugReplayStopResponse(BaseModel):
"""Response for stopping a debug replay session."""
success: bool
@router.post(
"/debug_replay/start",
response_model=DebugReplayStartResponse,
dependencies=[Depends(require_role(["admin"]))],
summary="Start debug replay",
description="Start a debug replay session from camera recordings.",
)
async def start_debug_replay(request: Request, body: DebugReplayStartBody):
"""Start a debug replay session."""
replay_manager = request.app.replay_manager
if replay_manager.active:
return JSONResponse(
content={
"success": False,
"message": "A replay session is already active",
},
status_code=409,
)
try:
replay_camera = await asyncio.to_thread(
replay_manager.start,
source_camera=body.camera,
start_ts=body.start_time,
end_ts=body.end_time,
frigate_config=request.app.frigate_config,
config_publisher=request.app.config_publisher,
)
except ValueError:
logger.exception("Invalid parameters for debug replay start request")
return JSONResponse(
content={
"success": False,
"message": "Invalid debug replay request parameters",
},
status_code=400,
)
except RuntimeError:
logger.exception("Error while starting debug replay session")
return JSONResponse(
content={
"success": False,
"message": "An internal error occurred while starting debug replay",
},
status_code=500,
)
return DebugReplayStartResponse(
success=True,
replay_camera=replay_camera,
)
@router.get(
"/debug_replay/status",
response_model=DebugReplayStatusResponse,
dependencies=[Depends(require_role(["admin"]))],
summary="Get debug replay status",
description="Get the status of the current debug replay session.",
)
def get_debug_replay_status(request: Request):
"""Get the current replay session status."""
replay_manager = request.app.replay_manager
live_ready = False
replay_camera = replay_manager.replay_camera_name
if replay_manager.active and replay_camera:
frame_processor = request.app.detected_frames_processor
frame = frame_processor.get_current_frame(replay_camera)
if frame is not None:
frame_time = frame_processor.get_current_frame_time(replay_camera)
camera_config = request.app.frigate_config.cameras.get(replay_camera)
retry_interval = 10
if camera_config is not None:
retry_interval = float(camera_config.ffmpeg.retry_interval or 10)
live_ready = datetime.now().timestamp() <= frame_time + retry_interval
return DebugReplayStatusResponse(
active=replay_manager.active,
replay_camera=replay_camera,
source_camera=replay_manager.source_camera,
start_time=replay_manager.start_ts,
end_time=replay_manager.end_ts,
live_ready=live_ready,
)
@router.post(
"/debug_replay/stop",
response_model=DebugReplayStopResponse,
dependencies=[Depends(require_role(["admin"]))],
summary="Stop debug replay",
description="Stop the active debug replay session and clean up all artifacts.",
)
async def stop_debug_replay(request: Request):
"""Stop the active replay session."""
replay_manager = request.app.replay_manager
if not replay_manager.active:
return JSONResponse(
content={"success": False, "message": "No active replay session"},
status_code=400,
)
try:
await asyncio.to_thread(
replay_manager.stop,
frigate_config=request.app.frigate_config,
config_publisher=request.app.config_publisher,
)
except (ValueError, RuntimeError, OSError) as e:
logger.error("Error stopping replay: %s", e)
return JSONResponse(
content={
"success": False,
"message": "Failed to stop replay session due to an internal error.",
},
status_code=500,
)
return DebugReplayStopResponse(success=True)

View File

@ -7,6 +7,7 @@ class AppConfigSetBody(BaseModel):
requires_restart: int = 1
update_topic: str | None = None
config_data: Optional[Dict[str, Any]] = None
skip_save: bool = False
class AppPutPasswordBody(BaseModel):

View File

@ -18,6 +18,7 @@ from frigate.api import (
camera,
chat,
classification,
debug_replay,
event,
export,
media,
@ -32,6 +33,7 @@ from frigate.comms.event_metadata_updater import (
)
from frigate.config import FrigateConfig
from frigate.config.camera.updater import CameraConfigUpdatePublisher
from frigate.debug_replay import DebugReplayManager
from frigate.embeddings import EmbeddingsContext
from frigate.genai import GenAIClientManager
from frigate.ptz.onvif import OnvifController
@ -65,6 +67,7 @@ def create_fastapi_app(
stats_emitter: StatsEmitter,
event_metadata_updater: EventMetadataPublisher,
config_publisher: CameraConfigUpdatePublisher,
replay_manager: DebugReplayManager,
enforce_default_admin: bool = True,
):
logger.info("Starting FastAPI app")
@ -133,6 +136,7 @@ def create_fastapi_app(
app.include_router(event.router)
app.include_router(media.router)
app.include_router(record.router)
app.include_router(debug_replay.router)
# App Properties
app.frigate_config = frigate_config
app.genai_manager = GenAIClientManager(frigate_config)
@ -144,6 +148,7 @@ def create_fastapi_app(
app.stats_emitter = stats_emitter
app.event_metadata_updater = event_metadata_updater
app.config_publisher = config_publisher
app.replay_manager = replay_manager
if frigate_config.auth.enabled:
secret = get_jwt_secret()

View File

@ -43,6 +43,10 @@ from frigate.const import (
)
from frigate.data_processing.types import DataProcessorMetrics
from frigate.db.sqlitevecq import SqliteVecQueueDatabase
from frigate.debug_replay import (
DebugReplayManager,
cleanup_replay_cameras,
)
from frigate.embeddings import EmbeddingProcess, EmbeddingsContext
from frigate.events.audio import AudioProcessor
from frigate.events.cleanup import EventCleanup
@ -139,6 +143,9 @@ class FrigateApp:
else:
logger.debug(f"Skipping directory: {d}")
def init_debug_replay_manager(self) -> None:
self.replay_manager = DebugReplayManager()
def init_camera_metrics(self) -> None:
# create camera_metrics
for camera_name in self.config.cameras.keys():
@ -531,6 +538,7 @@ class FrigateApp:
set_file_limit()
# Start frigate services.
self.init_debug_replay_manager()
self.init_camera_metrics()
self.init_queues()
self.init_database()
@ -541,6 +549,10 @@ class FrigateApp:
self.init_embeddings_manager()
self.bind_database()
self.check_db_data_migrations()
# Clean up any stale replay camera artifacts (filesystem + DB)
cleanup_replay_cameras()
self.init_inter_process_communicator()
self.start_detectors()
self.init_dispatcher()
@ -572,6 +584,7 @@ class FrigateApp:
self.stats_emitter,
self.event_metadata_updater,
self.inter_config_updater,
self.replay_manager,
),
host="127.0.0.1",
port=5001,
@ -637,6 +650,7 @@ class FrigateApp:
self.record_cleanup.join()
self.stats_emitter.join()
self.frigate_watchdog.join()
self.camera_maintainer.join()
self.db.stop()
# Save embeddings stats to disk

View File

@ -57,6 +57,9 @@ class CameraActivityManager:
all_objects: list[dict[str, Any]] = []
for camera in new_activity.keys():
if camera not in self.config.cameras:
continue
# handle cameras that were added dynamically
if camera not in self.camera_all_object_counts:
self.__init_camera(self.config.cameras[camera])
@ -124,7 +127,11 @@ class CameraActivityManager:
any_changed = False
# run through each object and check what topics need to be updated
for label in self.config.cameras[camera].objects.track:
camera_config = self.config.cameras.get(camera)
if camera_config is None:
return
for label in camera_config.objects.track:
if label in self.config.model.non_logo_attributes:
continue
@ -174,6 +181,9 @@ class AudioActivityManager:
now = datetime.datetime.now().timestamp()
for camera in new_activity.keys():
if camera not in self.config.cameras:
continue
# handle cameras that were added dynamically
if camera not in self.current_audio_detections:
self.__init_camera(self.config.cameras[camera])
@ -193,7 +203,11 @@ class AudioActivityManager:
def compare_audio_activity(
self, camera: str, new_detections: list[tuple[str, float]], now: float
) -> None:
max_not_heard = self.config.cameras[camera].audio.max_not_heard
camera_config = self.config.cameras.get(camera)
if camera_config is None:
return False
max_not_heard = camera_config.audio.max_not_heard
current = self.current_audio_detections[camera]
any_changed = False

View File

@ -55,8 +55,20 @@ class CameraMaintainer(threading.Thread):
self.shm_count = self.__calculate_shm_frame_count()
self.camera_processes: dict[str, mp.Process] = {}
self.capture_processes: dict[str, mp.Process] = {}
self.camera_stop_events: dict[str, MpEvent] = {}
self.metrics_manager = metrics_manager
def __ensure_camera_stop_event(self, camera: str) -> MpEvent:
camera_stop_event = self.camera_stop_events.get(camera)
if camera_stop_event is None:
camera_stop_event = mp.Event()
self.camera_stop_events[camera] = camera_stop_event
else:
camera_stop_event.clear()
return camera_stop_event
def __init_historical_regions(self) -> None:
# delete region grids for removed or renamed cameras
cameras = list(self.config.cameras.keys())
@ -99,6 +111,8 @@ class CameraMaintainer(threading.Thread):
logger.info(f"Camera processor not started for disabled camera {name}")
return
camera_stop_event = self.__ensure_camera_stop_event(name)
if runtime:
self.camera_metrics[name] = CameraMetrics(self.metrics_manager)
self.ptz_metrics[name] = PTZMetrics(autotracker_enabled=False)
@ -135,7 +149,7 @@ class CameraMaintainer(threading.Thread):
self.camera_metrics[name],
self.ptz_metrics[name],
self.region_grids[name],
self.stop_event,
camera_stop_event,
self.config.logger,
)
self.camera_processes[config.name] = camera_process
@ -150,6 +164,8 @@ class CameraMaintainer(threading.Thread):
logger.info(f"Capture process not started for disabled camera {name}")
return
camera_stop_event = self.__ensure_camera_stop_event(name)
# pre-create shms
count = 10 if runtime else self.shm_count
for i in range(count):
@ -160,7 +176,7 @@ class CameraMaintainer(threading.Thread):
config,
count,
self.camera_metrics[name],
self.stop_event,
camera_stop_event,
self.config.logger,
)
capture_process.daemon = True
@ -170,18 +186,36 @@ class CameraMaintainer(threading.Thread):
logger.info(f"Capture process started for {name}: {capture_process.pid}")
def __stop_camera_capture_process(self, camera: str) -> None:
capture_process = self.capture_processes[camera]
capture_process = self.capture_processes.get(camera)
if capture_process is not None:
logger.info(f"Waiting for capture process for {camera} to stop")
capture_process.terminate()
capture_process.join()
camera_stop_event = self.camera_stop_events.get(camera)
if camera_stop_event is not None:
camera_stop_event.set()
capture_process.join(timeout=10)
if capture_process.is_alive():
logger.warning(
f"Capture process for {camera} didn't exit, forcing termination"
)
capture_process.terminate()
capture_process.join()
def __stop_camera_process(self, camera: str) -> None:
camera_process = self.camera_processes[camera]
camera_process = self.camera_processes.get(camera)
if camera_process is not None:
logger.info(f"Waiting for process for {camera} to stop")
camera_process.terminate()
camera_process.join()
camera_stop_event = self.camera_stop_events.get(camera)
if camera_stop_event is not None:
camera_stop_event.set()
camera_process.join(timeout=10)
if camera_process.is_alive():
logger.warning(f"Process for {camera} didn't exit, forcing termination")
camera_process.terminate()
camera_process.join()
logger.info(f"Closing frame queue for {camera}")
empty_and_close_queue(self.camera_metrics[camera].frame_queue)
@ -199,6 +233,12 @@ class CameraMaintainer(threading.Thread):
for update_type, updated_cameras in updates.items():
if update_type == CameraConfigUpdateEnum.add.name:
for camera in updated_cameras:
if (
camera in self.camera_processes
or camera in self.capture_processes
):
continue
self.__start_camera_processor(
camera,
self.update_subscriber.camera_configs[camera],
@ -210,15 +250,22 @@ class CameraMaintainer(threading.Thread):
runtime=True,
)
elif update_type == CameraConfigUpdateEnum.remove.name:
self.__stop_camera_capture_process(camera)
self.__stop_camera_process(camera)
for camera in updated_cameras:
self.__stop_camera_capture_process(camera)
self.__stop_camera_process(camera)
self.capture_processes.pop(camera, None)
self.camera_processes.pop(camera, None)
self.camera_stop_events.pop(camera, None)
self.region_grids.pop(camera, None)
self.camera_metrics.pop(camera, None)
self.ptz_metrics.pop(camera, None)
# ensure the capture processes are done
for camera in self.camera_processes.keys():
for camera in self.capture_processes.keys():
self.__stop_camera_capture_process(camera)
# ensure the camera processors are done
for camera in self.capture_processes.keys():
for camera in self.camera_processes.keys():
self.__stop_camera_process(camera)
self.update_subscriber.stop()

View File

@ -26,8 +26,8 @@ class ConfigPublisher:
def stop(self) -> None:
self.stop_event.set()
self.socket.close()
self.context.destroy()
self.socket.close(linger=0)
self.context.destroy(linger=0)
class ConfigSubscriber:
@ -55,5 +55,5 @@ class ConfigSubscriber:
return (None, None)
def stop(self) -> None:
self.socket.close()
self.context.destroy()
self.socket.close(linger=0)
self.context.destroy(linger=0)

View File

@ -110,6 +110,9 @@ class Dispatcher:
payload: str,
sub_command: str | None = None,
) -> None:
if camera_name not in self.config.cameras:
return
try:
if command_type == "set":
if sub_command:
@ -131,6 +134,9 @@ class Dispatcher:
def handle_request_region_grid() -> Any:
camera = payload
if camera not in self.config.cameras:
return None
grid = get_camera_regions_grid(
camera,
self.config.cameras[camera].detect,
@ -243,7 +249,11 @@ class Dispatcher:
self.publish("birdseye_layout", json.dumps(self.birdseye_layout.copy()))
def handle_on_connect() -> None:
camera_status = self.camera_activity.last_camera_activity.copy()
camera_status = {
camera: status
for camera, status in self.camera_activity.last_camera_activity.copy().items()
if camera in self.config.cameras
}
audio_detections = self.audio_activity.current_audio_detections.copy()
cameras_with_status = camera_status.keys()
@ -346,7 +356,8 @@ class Dispatcher:
# example /cam_name/notifications/suspend payload=duration
camera_name = parts[-3]
command = parts[-2]
self._on_camera_notification_suspend(camera_name, payload)
if camera_name in self.config.cameras:
self._on_camera_notification_suspend(camera_name, payload)
except IndexError:
logger.error(
f"Received invalid {topic.split('/')[-1]} command: {topic}"

View File

@ -61,8 +61,8 @@ class InterProcessCommunicator(Communicator):
def stop(self) -> None:
self.stop_event.set()
self.reader_thread.join()
self.socket.close()
self.context.destroy()
self.socket.close(linger=0)
self.context.destroy(linger=0)
class InterProcessRequestor:
@ -82,5 +82,5 @@ class InterProcessRequestor:
return ""
def stop(self) -> None:
self.socket.close()
self.context.destroy()
self.socket.close(linger=0)
self.context.destroy(linger=0)

View File

@ -43,7 +43,7 @@ class ZmqProxy:
def stop(self) -> None:
# destroying the context will tell the proxy to stop
self.context.destroy()
self.context.destroy(linger=0)
self.runner.join()
@ -66,8 +66,8 @@ class Publisher(Generic[T]):
self.socket.send_string(f"{self.topic}{sub_topic} {json.dumps(payload)}")
def stop(self) -> None:
self.socket.close()
self.context.destroy()
self.socket.close(linger=0)
self.context.destroy(linger=0)
class Subscriber(Generic[T]):
@ -96,8 +96,8 @@ class Subscriber(Generic[T]):
return self._return_object("", None)
def stop(self) -> None:
self.socket.close()
self.context.destroy()
self.socket.close(linger=0)
self.context.destroy(linger=0)
def _return_object(self, topic: str, payload: T | None) -> T | None:
return payload

View File

@ -80,8 +80,8 @@ class CameraConfigUpdateSubscriber:
self.camera_configs[camera] = updated_config
return
elif update_type == CameraConfigUpdateEnum.remove:
self.config.cameras.pop(camera)
self.camera_configs.pop(camera)
self.config.cameras.pop(camera, None)
self.camera_configs.pop(camera, None)
return
config = self.camera_configs.get(camera)

View File

@ -14,6 +14,8 @@ RECORD_DIR = f"{BASE_DIR}/recordings"
TRIGGER_DIR = f"{CLIPS_DIR}/triggers"
BIRDSEYE_PIPE = "/tmp/cache/birdseye"
CACHE_DIR = "/tmp/cache"
REPLAY_CAMERA_PREFIX = "_replay_"
REPLAY_DIR = os.path.join(CACHE_DIR, "replay")
PLUS_ENV_VAR = "PLUS_API_KEY"
PLUS_API_HOST = "https://api.frigate.video"

443
frigate/debug_replay.py Normal file
View File

@ -0,0 +1,443 @@
"""Debug replay camera management for replaying recordings with detection overlays."""
import logging
import os
import shutil
import subprocess as sp
import threading
from ruamel.yaml import YAML
from frigate.config import FrigateConfig
from frigate.config.camera.updater import (
CameraConfigUpdateEnum,
CameraConfigUpdatePublisher,
CameraConfigUpdateTopic,
)
from frigate.const import (
CLIPS_DIR,
RECORD_DIR,
REPLAY_CAMERA_PREFIX,
REPLAY_DIR,
THUMB_DIR,
)
from frigate.models import Event, Recordings, ReviewSegment, Timeline
from frigate.util.config import find_config_file
logger = logging.getLogger(__name__)
class DebugReplayManager:
"""Manages a single debug replay session."""
def __init__(self) -> None:
self._lock = threading.Lock()
self.replay_camera_name: str | None = None
self.source_camera: str | None = None
self.clip_path: str | None = None
self.start_ts: float | None = None
self.end_ts: float | None = None
@property
def active(self) -> bool:
"""Whether a replay session is currently active."""
return self.replay_camera_name is not None
def start(
self,
source_camera: str,
start_ts: float,
end_ts: float,
frigate_config: FrigateConfig,
config_publisher: CameraConfigUpdatePublisher,
) -> str:
"""Start a debug replay session.
Args:
source_camera: Name of the source camera to replay
start_ts: Start timestamp
end_ts: End timestamp
frigate_config: Current Frigate configuration
config_publisher: Publisher for camera config updates
Returns:
The replay camera name
Raises:
ValueError: If a session is already active or parameters are invalid
RuntimeError: If clip generation fails
"""
with self._lock:
return self._start_locked(
source_camera, start_ts, end_ts, frigate_config, config_publisher
)
def _start_locked(
self,
source_camera: str,
start_ts: float,
end_ts: float,
frigate_config: FrigateConfig,
config_publisher: CameraConfigUpdatePublisher,
) -> str:
if self.active:
raise ValueError("A replay session is already active")
if source_camera not in frigate_config.cameras:
raise ValueError(f"Camera '{source_camera}' not found")
if end_ts <= start_ts:
raise ValueError("End time must be after start time")
# Query recordings for the source camera in the time range
recordings = (
Recordings.select(
Recordings.path,
Recordings.start_time,
Recordings.end_time,
)
.where(
Recordings.start_time.between(start_ts, end_ts)
| Recordings.end_time.between(start_ts, end_ts)
| ((start_ts > Recordings.start_time) & (end_ts < Recordings.end_time))
)
.where(Recordings.camera == source_camera)
.order_by(Recordings.start_time.asc())
)
if not recordings.count():
raise ValueError(
f"No recordings found for camera '{source_camera}' in the specified time range"
)
# Create replay directory
os.makedirs(REPLAY_DIR, exist_ok=True)
# Generate replay camera name
replay_name = f"{REPLAY_CAMERA_PREFIX}{source_camera}"
# Build concat file for ffmpeg
concat_file = os.path.join(REPLAY_DIR, f"{replay_name}_concat.txt")
clip_path = os.path.join(REPLAY_DIR, f"{replay_name}.mp4")
with open(concat_file, "w") as f:
for recording in recordings:
f.write(f"file '{recording.path}'\n")
# Concatenate recordings into a single clip with -c copy (fast)
ffmpeg_cmd = [
frigate_config.ffmpeg.ffmpeg_path,
"-hide_banner",
"-y",
"-f",
"concat",
"-safe",
"0",
"-i",
concat_file,
"-c",
"copy",
"-movflags",
"+faststart",
clip_path,
]
logger.info(
"Generating replay clip for %s (%.1f - %.1f)",
source_camera,
start_ts,
end_ts,
)
try:
result = sp.run(
ffmpeg_cmd,
capture_output=True,
text=True,
timeout=120,
)
if result.returncode != 0:
logger.error("FFmpeg error: %s", result.stderr)
raise RuntimeError(
f"Failed to generate replay clip: {result.stderr[-500:]}"
)
except sp.TimeoutExpired:
raise RuntimeError("Clip generation timed out")
finally:
# Clean up concat file
if os.path.exists(concat_file):
os.remove(concat_file)
if not os.path.exists(clip_path):
raise RuntimeError("Clip file was not created")
# Build camera config dict for the replay camera
source_config = frigate_config.cameras[source_camera]
camera_dict = self._build_camera_config_dict(
source_config, replay_name, clip_path
)
# Build an in-memory config with the replay camera added
config_file = find_config_file()
yaml_parser = YAML()
with open(config_file, "r") as f:
config_data = yaml_parser.load(f)
if "cameras" not in config_data or config_data["cameras"] is None:
config_data["cameras"] = {}
config_data["cameras"][replay_name] = camera_dict
try:
new_config = FrigateConfig.parse_object(config_data)
except Exception as e:
raise RuntimeError(f"Failed to validate replay camera config: {e}")
# Update the running config
frigate_config.cameras[replay_name] = new_config.cameras[replay_name]
# Publish the add event
config_publisher.publish_update(
CameraConfigUpdateTopic(CameraConfigUpdateEnum.add, replay_name),
new_config.cameras[replay_name],
)
# Store session state
self.replay_camera_name = replay_name
self.source_camera = source_camera
self.clip_path = clip_path
self.start_ts = start_ts
self.end_ts = end_ts
logger.info("Debug replay started: %s -> %s", source_camera, replay_name)
return replay_name
def stop(
self,
frigate_config: FrigateConfig,
config_publisher: CameraConfigUpdatePublisher,
) -> None:
"""Stop the active replay session and clean up all artifacts.
Args:
frigate_config: Current Frigate configuration
config_publisher: Publisher for camera config updates
"""
with self._lock:
self._stop_locked(frigate_config, config_publisher)
def _stop_locked(
self,
frigate_config: FrigateConfig,
config_publisher: CameraConfigUpdatePublisher,
) -> None:
if not self.active:
logger.warning("No active replay session to stop")
return
replay_name = self.replay_camera_name
# Publish remove event so subscribers stop and remove from their config
if replay_name in frigate_config.cameras:
config_publisher.publish_update(
CameraConfigUpdateTopic(CameraConfigUpdateEnum.remove, replay_name),
frigate_config.cameras[replay_name],
)
# Do NOT pop here — let subscribers handle removal from the shared
# config dict when they process the ZMQ message to avoid race conditions
# Defensive DB cleanup
self._cleanup_db(replay_name)
# Remove filesystem artifacts
self._cleanup_files(replay_name)
# Reset state
self.replay_camera_name = None
self.source_camera = None
self.clip_path = None
self.start_ts = None
self.end_ts = None
logger.info("Debug replay stopped and cleaned up: %s", replay_name)
def _build_camera_config_dict(
self,
source_config,
replay_name: str,
clip_path: str,
) -> dict:
"""Build a camera config dictionary for the replay camera.
Args:
source_config: Source camera's CameraConfig
replay_name: Name for the replay camera
clip_path: Path to the replay clip file
Returns:
Camera config as a dictionary
"""
# Extract detect config (exclude computed fields)
detect_dict = source_config.detect.model_dump(
exclude={"min_initialized", "max_disappeared", "enabled_in_config"}
)
# Extract objects config, using .dict() on filters to convert
# RuntimeFilterConfig ndarray masks back to string coordinates
objects_dict = {
"track": source_config.objects.track,
"mask": {
mask_id: (
mask_cfg.model_dump(
exclude={"raw_coordinates", "enabled_in_config"}
)
if mask_cfg is not None
else None
)
for mask_id, mask_cfg in source_config.objects.mask.items()
}
if source_config.objects.mask
else {},
"filters": {
name: filt.dict() if hasattr(filt, "dict") else filt.model_dump()
for name, filt in source_config.objects.filters.items()
},
}
# Extract zones (exclude_defaults avoids serializing empty defaults
# like distances=[] that fail validation on re-parse)
zones_dict = {}
for zone_name, zone_config in source_config.zones.items():
zone_dump = zone_config.model_dump(
exclude={"contour", "color"}, exclude_defaults=True
)
# Always include required fields
zone_dump.setdefault("coordinates", zone_config.coordinates)
zones_dict[zone_name] = zone_dump
# Extract motion config (exclude runtime fields)
motion_dict = {}
if source_config.motion is not None:
motion_dict = source_config.motion.model_dump(
exclude={
"frame_shape",
"raw_mask",
"mask",
"improved_contrast_enabled",
"rasterized_mask",
}
)
return {
"enabled": True,
"ffmpeg": {
"inputs": [
{
"path": clip_path,
"roles": ["detect"],
"input_args": "-re -stream_loop -1 -fflags +genpts",
}
],
"hwaccel_args": [],
},
"detect": detect_dict,
"objects": objects_dict,
"zones": zones_dict,
"motion": motion_dict,
"record": {"enabled": False},
"snapshots": {"enabled": False},
"review": {
"alerts": {"enabled": False},
"detections": {"enabled": False},
},
"birdseye": {"enabled": False},
"audio": {"enabled": False},
"lpr": {"enabled": False},
"face_recognition": {"enabled": False},
}
def _cleanup_db(self, camera_name: str) -> None:
"""Defensively remove any database rows for the replay camera."""
try:
Event.delete().where(Event.camera == camera_name).execute()
except Exception as e:
logger.error("Failed to delete replay events: %s", e)
try:
Timeline.delete().where(Timeline.camera == camera_name).execute()
except Exception as e:
logger.error("Failed to delete replay timeline: %s", e)
try:
Recordings.delete().where(Recordings.camera == camera_name).execute()
except Exception as e:
logger.error("Failed to delete replay recordings: %s", e)
try:
ReviewSegment.delete().where(ReviewSegment.camera == camera_name).execute()
except Exception as e:
logger.error("Failed to delete replay review segments: %s", e)
def _cleanup_files(self, camera_name: str) -> None:
"""Remove filesystem artifacts for the replay camera."""
dirs_to_clean = [
os.path.join(RECORD_DIR, camera_name),
os.path.join(CLIPS_DIR, camera_name),
os.path.join(THUMB_DIR, camera_name),
]
for dir_path in dirs_to_clean:
if os.path.exists(dir_path):
try:
shutil.rmtree(dir_path)
logger.debug("Removed replay directory: %s", dir_path)
except Exception as e:
logger.error("Failed to remove %s: %s", dir_path, e)
# Remove replay clip and any related files
if os.path.exists(REPLAY_DIR):
try:
shutil.rmtree(REPLAY_DIR)
logger.debug("Removed replay cache directory")
except Exception as e:
logger.error("Failed to remove replay cache: %s", e)
def cleanup_replay_cameras() -> None:
"""Remove any stale replay camera artifacts on startup.
Since replay cameras are memory-only and never written to YAML, they
won't appear in the config after a restart. This function cleans up
filesystem and database artifacts from any replay that was running when
the process stopped.
Must be called AFTER the database is bound.
"""
stale_cameras: set[str] = set()
# Scan filesystem for leftover replay artifacts to derive camera names
for dir_path in [RECORD_DIR, CLIPS_DIR, THUMB_DIR]:
if os.path.isdir(dir_path):
for entry in os.listdir(dir_path):
if entry.startswith(REPLAY_CAMERA_PREFIX):
stale_cameras.add(entry)
if os.path.isdir(REPLAY_DIR):
for entry in os.listdir(REPLAY_DIR):
if entry.startswith(REPLAY_CAMERA_PREFIX) and entry.endswith(".mp4"):
stale_cameras.add(entry.removesuffix(".mp4"))
if not stale_cameras:
return
logger.info("Cleaning up stale replay camera artifacts: %s", list(stale_cameras))
manager = DebugReplayManager()
for camera_name in stale_cameras:
manager._cleanup_db(camera_name)
manager._cleanup_files(camera_name)
if os.path.exists(REPLAY_DIR):
try:
shutil.rmtree(REPLAY_DIR)
except Exception as e:
logger.error("Failed to remove replay cache directory: %s", e)

View File

@ -421,7 +421,9 @@ class EmbeddingMaintainer(threading.Thread):
if self.config.semantic_search.enabled:
self.embeddings.update_stats()
camera_config = self.config.cameras[camera]
camera_config = self.config.cameras.get(camera)
if camera_config is None:
return
# no need to process updated objects if no processors are active
if len(self.realtime_processors) == 0 and len(self.post_processors) == 0:
@ -639,7 +641,10 @@ class EmbeddingMaintainer(threading.Thread):
if not camera or camera not in self.config.cameras:
return
camera_config = self.config.cameras[camera]
camera_config = self.config.cameras.get(camera)
if camera_config is None:
return
dedicated_lpr_enabled = (
camera_config.type == CameraTypeEnum.lpr
and "license_plate" not in camera_config.objects.track

View File

@ -7,6 +7,7 @@ from typing import Dict
from frigate.comms.events_updater import EventEndPublisher, EventUpdateSubscriber
from frigate.config import FrigateConfig
from frigate.config.classification import ObjectClassificationType
from frigate.const import REPLAY_CAMERA_PREFIX
from frigate.events.types import EventStateEnum, EventTypeEnum
from frigate.models import Event
from frigate.util.builtin import to_relative_box
@ -146,7 +147,9 @@ class EventProcessor(threading.Thread):
if should_update_db(self.events_in_process[event_data["id"]], event_data):
updated_db = True
camera_config = self.config.cameras[camera]
camera_config = self.config.cameras.get(camera)
if camera_config is None:
return
width = camera_config.detect.width
height = camera_config.detect.height
first_detector = list(self.config.detectors.values())[0]
@ -283,6 +286,10 @@ class EventProcessor(threading.Thread):
def handle_external_detection(
self, event_type: EventStateEnum, event_data: Event
) -> None:
# Skip replay cameras
if event_data.get("camera", "").startswith(REPLAY_CAMERA_PREFIX):
return
if event_type == EventStateEnum.start:
event = {
Event.id: event_data["id"],

View File

@ -420,7 +420,8 @@ class BirdsEyeFrameManager:
[
cam
for cam, cam_data in self.cameras.items()
if self.config.cameras[cam].birdseye.enabled
if cam in self.config.cameras
and self.config.cameras[cam].birdseye.enabled
and self.config.cameras[cam].enabled_in_config
and self.config.cameras[cam].enabled
and cam_data["last_active_frame"] > 0
@ -723,8 +724,11 @@ class BirdsEyeFrameManager:
Update birdseye for a specific camera with new frame data.
Returns (frame_changed, layout_changed) to indicate if the frame or layout changed.
"""
# don't process if birdseye is disabled for this camera
camera_config = self.config.cameras[camera]
# don't process if camera was removed or birdseye is disabled
camera_config = self.config.cameras.get(camera)
if camera_config is None:
return False, False
force_update = False
# disabling birdseye is a little tricky

View File

@ -22,7 +22,12 @@ from frigate.config.camera.updater import (
CameraConfigUpdateEnum,
CameraConfigUpdateSubscriber,
)
from frigate.const import CACHE_DIR, CLIPS_DIR, PROCESS_PRIORITY_MED
from frigate.const import (
CACHE_DIR,
CLIPS_DIR,
PROCESS_PRIORITY_MED,
REPLAY_CAMERA_PREFIX,
)
from frigate.output.birdseye import Birdseye
from frigate.output.camera import JsmpegCamera
from frigate.output.preview import PreviewRecorder
@ -79,6 +84,32 @@ class OutputProcess(FrigateProcess):
)
self.config = config
def is_debug_replay_camera(self, camera: str) -> bool:
return camera.startswith(REPLAY_CAMERA_PREFIX)
def add_camera(
self,
camera: str,
websocket_server: WSGIServer,
jsmpeg_cameras: dict[str, JsmpegCamera],
preview_recorders: dict[str, PreviewRecorder],
preview_write_times: dict[str, float],
birdseye: Birdseye | None,
) -> None:
camera_config = self.config.cameras[camera]
jsmpeg_cameras[camera] = JsmpegCamera(
camera_config, self.stop_event, websocket_server
)
preview_recorders[camera] = PreviewRecorder(camera_config)
preview_write_times[camera] = 0
if (
birdseye is not None
and self.config.birdseye.enabled
and camera_config.birdseye.enabled
):
birdseye.add_camera(camera)
def run(self) -> None:
self.pre_run_setup(self.config.logger)
@ -118,14 +149,17 @@ class OutputProcess(FrigateProcess):
move_preview_frames("cache")
for camera, cam_config in self.config.cameras.items():
if not cam_config.enabled_in_config:
if not cam_config.enabled_in_config or self.is_debug_replay_camera(camera):
continue
jsmpeg_cameras[camera] = JsmpegCamera(
cam_config, self.stop_event, websocket_server
self.add_camera(
camera,
websocket_server,
jsmpeg_cameras,
preview_recorders,
preview_write_times,
birdseye,
)
preview_recorders[camera] = PreviewRecorder(cam_config)
preview_write_times[camera] = 0
if self.config.birdseye.enabled:
birdseye = Birdseye(self.config, self.stop_event, websocket_server)
@ -138,19 +172,15 @@ class OutputProcess(FrigateProcess):
if CameraConfigUpdateEnum.add in updates:
for camera in updates["add"]:
jsmpeg_cameras[camera] = JsmpegCamera(
self.config.cameras[camera], self.stop_event, websocket_server
)
preview_recorders[camera] = PreviewRecorder(
self.config.cameras[camera]
)
preview_write_times[camera] = 0
if (
self.config.birdseye.enabled
and self.config.cameras[camera].birdseye.enabled
):
birdseye.add_camera(camera)
if not self.is_debug_replay_camera(camera):
self.add_camera(
camera,
websocket_server,
jsmpeg_cameras,
preview_recorders,
preview_write_times,
birdseye,
)
(topic, data) = detection_subscriber.check_for_update(timeout=1)
now = datetime.datetime.now().timestamp()
@ -174,7 +204,11 @@ class OutputProcess(FrigateProcess):
_,
) = data
if not self.config.cameras[camera].enabled:
if (
camera not in self.config.cameras
or not self.config.cameras[camera].enabled
or self.is_debug_replay_camera(camera)
):
continue
frame = frame_manager.get(

View File

@ -287,11 +287,12 @@ class RecordingMaintainer(threading.Thread):
)
# publish most recently available recording time and None if disabled
camera_cfg = self.config.cameras.get(camera)
self.recordings_publisher.publish(
(
camera,
recordings[0]["start_time"].timestamp()
if self.config.cameras[camera].record.enabled
if camera_cfg and camera_cfg.record.enabled
else None,
None,
),
@ -315,9 +316,8 @@ class RecordingMaintainer(threading.Thread):
) -> Optional[Recordings]:
cache_path: str = recording["cache_path"]
start_time: datetime.datetime = recording["start_time"]
record_config = self.config.cameras[camera].record
# Just delete files if recordings are turned off
# Just delete files if camera removed or recordings are turned off
if (
camera not in self.config.cameras
or not self.config.cameras[camera].record.enabled

View File

@ -652,6 +652,9 @@ class ReviewSegmentMaintainer(threading.Thread):
if camera not in self.indefinite_events:
self.indefinite_events[camera] = {}
if camera not in self.config.cameras:
continue
if (
not self.config.cameras[camera].enabled
or not self.config.cameras[camera].record.enabled

View File

@ -340,6 +340,9 @@ def stats_snapshot(
stats["cameras"] = {}
for name, camera_stats in camera_metrics.items():
if name not in config.cameras:
continue
total_camera_fps += camera_stats.camera_fps.value
total_process_fps += camera_stats.process_fps.value
total_skipped_fps += camera_stats.skipped_fps.value

View File

@ -8,7 +8,7 @@ from pathlib import Path
from peewee import SQL, fn
from frigate.config import FrigateConfig
from frigate.const import RECORD_DIR
from frigate.const import RECORD_DIR, REPLAY_CAMERA_PREFIX
from frigate.models import Event, Recordings
from frigate.util.builtin import clear_and_unlink
@ -32,6 +32,10 @@ class StorageMaintainer(threading.Thread):
def calculate_camera_bandwidth(self) -> None:
"""Calculate an average MB/hr for each camera."""
for camera in self.config.cameras.keys():
# Skip replay cameras
if camera.startswith(REPLAY_CAMERA_PREFIX):
continue
# cameras with < 50 segments should be refreshed to keep size accurate
# when few segments are available
if self.camera_storage_stats.get(camera, {}).get("needs_refresh", True):
@ -77,6 +81,10 @@ class StorageMaintainer(threading.Thread):
usages: dict[str, dict] = {}
for camera in self.config.cameras.keys():
# Skip replay cameras
if camera.startswith(REPLAY_CAMERA_PREFIX):
continue
camera_storage = (
Recordings.select(fn.SUM(Recordings.segment_size))
.where(Recordings.camera == camera, Recordings.segment_size != 0)

View File

@ -13,6 +13,7 @@ from pydantic import Json
from frigate.api.fastapi_app import create_fastapi_app
from frigate.config import FrigateConfig
from frigate.const import BASE_DIR, CACHE_DIR
from frigate.debug_replay import DebugReplayManager
from frigate.models import Event, Recordings, ReviewSegment
from frigate.review.types import SeverityEnum
from frigate.test.const import TEST_DB, TEST_DB_CLEANUPS
@ -141,6 +142,7 @@ class BaseTestHttp(unittest.TestCase):
stats,
event_metadata_publisher,
None,
DebugReplayManager(),
enforce_default_admin=False,
)

View File

@ -22,3 +22,32 @@ class TestHttpApp(BaseTestHttp):
response = client.get("/stats")
response_json = response.json()
assert response_json == self.test_stats
def test_config_set_in_memory_replaces_objects_track_list(self):
self.minimal_config["cameras"]["front_door"]["objects"] = {
"track": ["person", "car"],
}
app = super().create_app()
app.config_publisher = Mock()
with AuthTestClient(app) as client:
response = client.put(
"/config/set",
json={
"requires_restart": 0,
"skip_save": True,
"update_topic": "config/cameras/front_door/objects",
"config_data": {
"cameras": {
"front_door": {
"objects": {
"track": ["person"],
}
}
}
},
},
)
assert response.status_code == 200
assert app.frigate_config.cameras["front_door"].objects.track == ["person"]

View File

@ -151,6 +151,22 @@ class TestConfig(unittest.TestCase):
frigate_config = FrigateConfig(**config)
assert "dog" in frigate_config.cameras["back"].objects.track
def test_deep_merge_override_replaces_list_values(self):
base = {"objects": {"track": ["person", "face"]}}
update = {"objects": {"track": ["person"]}}
merged = deep_merge(base, update, override=True)
assert merged["objects"]["track"] == ["person"]
def test_deep_merge_merge_lists_still_appends(self):
base = {"track": ["person"]}
update = {"track": ["face"]}
merged = deep_merge(base, update, override=True, merge_lists=True)
assert merged["track"] == ["person", "face"]
def test_override_birdseye(self):
config = {
"mqtt": {"host": "mqtt"},

View File

@ -86,7 +86,9 @@ class TimelineProcessor(threading.Thread):
event_data: dict[Any, Any],
) -> bool:
"""Handle object detection."""
camera_config = self.config.cameras[camera]
camera_config = self.config.cameras.get(camera)
if camera_config is None:
return False
event_id = event_data["id"]
# Base timeline entry data that all entries will share

View File

@ -690,9 +690,13 @@ class TrackedObjectProcessor(threading.Thread):
self.create_camera_state(camera)
elif "remove" in updated_topics:
for camera in updated_topics["remove"]:
camera_state = self.camera_states[camera]
camera_state.shutdown()
removed_camera_state = self.camera_states[camera]
removed_camera_state.shutdown()
self.camera_states.pop(camera)
self.camera_activity.pop(camera, None)
self.last_motion_detected.pop(camera, None)
self.requestor.send_data(UPDATE_CAMERA_ACTIVITY, self.camera_activity)
# manage camera disabled state
for camera, config in self.config.cameras.items():
@ -700,6 +704,10 @@ class TrackedObjectProcessor(threading.Thread):
continue
current_enabled = config.enabled
camera_state = self.camera_states.get(camera)
if camera_state is None:
continue
camera_state = self.camera_states[camera]
if camera_state.prev_enabled and not current_enabled:
@ -752,7 +760,11 @@ class TrackedObjectProcessor(threading.Thread):
except queue.Empty:
continue
if not self.config.cameras[camera].enabled:
camera_config = self.config.cameras.get(camera)
if camera_config is None:
continue
if not camera_config.enabled:
logger.debug(f"Camera {camera} disabled, skipping update")
continue

View File

@ -16,7 +16,7 @@ from frigate.config import (
SnapshotsConfig,
UIConfig,
)
from frigate.const import CLIPS_DIR, THUMB_DIR
from frigate.const import CLIPS_DIR, REPLAY_CAMERA_PREFIX, THUMB_DIR
from frigate.detectors.detector_config import ModelConfig
from frigate.review.types import SeverityEnum
from frigate.util.builtin import sanitize_float
@ -621,6 +621,9 @@ class TrackedObject:
if not self.camera_config.name:
return
if self.camera_config.name.startswith(REPLAY_CAMERA_PREFIX):
return
directory = os.path.join(THUMB_DIR, self.camera_config.name)
if not os.path.exists(directory):

View File

@ -84,7 +84,8 @@ def deep_merge(dct1: dict, dct2: dict, override=False, merge_lists=False) -> dic
"""
:param dct1: First dict to merge
:param dct2: Second dict to merge
:param override: if same key exists in both dictionaries, should override? otherwise ignore. (default=True)
:param override: if same key exists in both dictionaries, should override? otherwise ignore.
:param merge_lists: if True, lists will be merged.
:return: The merge dictionary
"""
merged = copy.deepcopy(dct1)
@ -96,6 +97,8 @@ def deep_merge(dct1: dict, dct2: dict, override=False, merge_lists=False) -> dic
elif isinstance(v1, list) and isinstance(v2, list):
if merge_lists:
merged[k] = v1 + v2
elif override:
merged[k] = copy.deepcopy(v2)
else:
if override:
merged[k] = copy.deepcopy(v2)

View File

@ -9,6 +9,7 @@ from typing import Any, Optional, Union
from ruamel.yaml import YAML
from frigate.const import CONFIG_DIR, EXPORT_DIR
from frigate.util.builtin import deep_merge
from frigate.util.services import get_video_properties
logger = logging.getLogger(__name__)
@ -688,3 +689,78 @@ class StreamInfoRetriever:
info = asyncio.run(get_video_properties(ffmpeg, path))
self.stream_cache[path] = info
return info
def apply_section_update(camera_config, section: str, update: dict) -> Optional[str]:
"""Merge an update dict into a camera config section and rebuild runtime variants.
For motion and object filter sections, the plain Pydantic models are rebuilt
as RuntimeMotionConfig / RuntimeFilterConfig so that rasterized numpy masks
are recomputed. This mirrors the logic in FrigateConfig.post_validation.
Args:
camera_config: The CameraConfig instance to update.
section: Config section name (e.g. "motion", "objects").
update: Nested dict of field updates to merge.
Returns:
None on success, or an error message string on failure.
"""
from frigate.config.config import RuntimeFilterConfig, RuntimeMotionConfig
current = getattr(camera_config, section, None)
if current is None:
return f"Section '{section}' not found on camera '{camera_config.name}'"
try:
frame_shape = camera_config.frame_shape
if section == "motion":
merged = deep_merge(
current.model_dump(exclude_unset=True, exclude={"rasterized_mask"}),
update,
override=True,
)
camera_config.motion = RuntimeMotionConfig(
frame_shape=frame_shape, **merged
)
elif section == "objects":
merged = deep_merge(
current.model_dump(
exclude={"filters": {"__all__": {"rasterized_mask"}}}
),
update,
override=True,
)
new_objects = current.__class__.model_validate(merged)
# Preserve private _all_objects from original config
try:
new_objects._all_objects = current._all_objects
except AttributeError:
pass
# Rebuild RuntimeFilterConfig with merged global + per-object masks
for obj_name, filt in new_objects.filters.items():
merged_mask = dict(filt.mask)
if new_objects.mask:
for gid, gmask in new_objects.mask.items():
merged_mask[f"global_{gid}"] = gmask
new_objects.filters[obj_name] = RuntimeFilterConfig(
frame_shape=frame_shape,
mask=merged_mask,
**filt.model_dump(exclude_unset=True, exclude={"mask", "raw_mask"}),
)
camera_config.objects = new_objects
else:
merged = deep_merge(current.model_dump(), update, override=True)
setattr(camera_config, section, current.__class__.model_validate(merged))
except Exception:
logger.exception("Config validation error")
return "Validation error. Check logs for details."
return None

View File

@ -106,7 +106,8 @@
"logout": "Tanca la sessió",
"current": "Usuari actual: {{user}}"
},
"classification": "Classificació"
"classification": "Classificació",
"chat": "Xat"
},
"pagination": {
"previous": {
@ -268,7 +269,17 @@
"unselect": "Desseleccionar",
"enable": "Habilitar",
"enabled": "Habilitat",
"continue": "Continua"
"continue": "Continua",
"add": "Afegeix",
"undo": "Desfés",
"copiedToClipboard": "S'ha copiat al porta-retalls",
"modified": "Modificat",
"overridden": "Sobreescrit",
"resetToGlobal": "Restableix a global",
"resetToDefault": "Restableix al valor predeterminat",
"saveAll": "Desa-ho tot",
"savingAll": "S'està desant tot…",
"undoAll": "Desfés-ho tot"
},
"toast": {
"copyUrlToClipboard": "URL copiada al porta-retalls.",

View File

@ -65,6 +65,10 @@
"fromTimeline": {
"saveExport": "Guardar exportació",
"previewExport": "Previsualitzar exportació"
},
"case": {
"label": "Cas",
"placeholder": "Selecciona un cas"
}
},
"streaming": {

View File

@ -0,0 +1,936 @@
{
"label": "ConfiguracióDeLaCcàmera",
"name": {
"label": "Nom de la càmera",
"description": "Es requereix el nom de la càmera"
},
"friendly_name": {
"label": "Nom amistós",
"description": "Nom amigable de la càmera utilitzat a la interfície d'usuari de la Frigate"
},
"enabled": {
"label": "Habilitat",
"description": "Habilitat"
},
"audio": {
"label": "Esdeveniments d'àudio",
"description": "Configuració per a la detecció d'esdeveniments basats en àudio per a aquesta càmera.",
"enabled": {
"label": "Habilita la detecció d'àudio",
"description": "Activa o desactiva la detecció d'esdeveniments d'àudio per a aquesta càmera."
},
"max_not_heard": {
"label": "Temps d'espera final",
"description": "Quantitat de segons sense el tipus d'àudio configurat abans que acabi l'esdeveniment d'àudio."
},
"min_volume": {
"label": "Volum mínim",
"description": "Llindar mínim de volum RMS necessari per executar la detecció d'àudio; els valors més baixos augmenten la sensibilitat (p. ex., 200 alta, 500 mitjana, 1000 baixa)."
},
"listen": {
"label": "Tipus d'escoltes",
"description": "Llista de tipus d'esdeveniment d'àudio a detectar (per exemple: escorça, focarmalarma, crit, parla, crida)."
},
"filters": {
"label": "Filtres d'àudio",
"description": "Paràmetres de filtre per-àudio-tipus, com ara llindars de confiança utilitzats per reduir falsos positius."
},
"enabled_in_config": {
"label": "Estat d'àudio original",
"description": "Indica si la detecció d'àudio s'ha activat originalment al fitxer de configuració estàtic."
},
"num_threads": {
"label": "Fils de detecció",
"description": "Nombre de fils a utilitzar per al processament de detecció d'àudio."
}
},
"audio_transcription": {
"label": "Transcripció d'àudio",
"description": "Configuració per a la transcripció d'àudio en viu i de veu utilitzada per a esdeveniments i llegendes en directe.",
"enabled": {
"label": "Habilita la transcripció",
"description": "Activa o desactiva la transcripció d'esdeveniments d'àudio activada manualment."
},
"enabled_in_config": {
"label": "Estat de transcripció original"
},
"live_enabled": {
"label": "Transcripció en viu",
"description": "Habilita la transcripció en directe per a l'àudio a mesura que es rep."
}
},
"birdseye": {
"label": "Birdseye",
"description": "Arranjament per a la vista composta Birdseye que compon múltiples canals de càmera en una única disposició.",
"enabled": {
"label": "Habilita Birdseye",
"description": "Activa o desactiva la funció de vista Birdseye."
},
"mode": {
"label": "Mode de seguiment",
"description": "Mode per a incloure càmeres en Birdseye: 'objectes', 'motion' o 'continuous'."
},
"order": {
"label": "Posició",
"description": "Posició numèrica que controla l'ordenació de la càmera en la disposició Birdseye."
}
},
"detect": {
"label": "Detecció d'objectes",
"description": "Configuració del rol de detecció utilitzat per executar la detecció d'objectes i inicialitzar els rastrejadors.",
"enabled": {
"label": "Detecció activada",
"description": "Activa o desactiva la detecció d'objectes per a aquesta càmera. La detecció s'ha d'activar perquè s'executi el seguiment d'objectes."
},
"height": {
"label": "Detecta l'alçada",
"description": "Alçada (píxels) dels fotogrames utilitzats per al flux de detecció; deixeu-ho buit per a utilitzar la resolució nativa del flux."
},
"width": {
"label": "Detecta l'amplada",
"description": "Amplada (píxels) dels fotogrames utilitzats per al flux de detecció; deixeu-ho buit per a utilitzar la resolució nativa del flux."
},
"fps": {
"label": "Detecta FPS",
"description": "Fotogrames desitjats per segon per executar la detecció; els valors més baixos redueixen l'ús de la CPU (el valor recomanat és 5, només estableix més alt - com a màxim 10 - si el seguiment d'objectes en moviment extremadament ràpid)."
},
"min_initialized": {
"label": "Fotogrames d'inicialització mínims",
"description": "Nombre d'incidències de detecció consecutives necessàries abans de crear un objecte rastrejat. Incrementa per a reduir les falses inicialitzacions. El valor per defecte és fps dividit per 2."
},
"max_disappeared": {
"label": "Màxim de fotogrames desapareguts",
"description": "Nombre de fotogrames sense detecció abans que es consideri que un objecte rastrejat ha desaparegut."
},
"stationary": {
"label": "Configuració d'objectes estacionaris",
"description": "Configuració per detectar i gestionar objectes que romanen estacionaris durant un període de temps.",
"interval": {
"label": "Interval estacionari",
"description": "Amb quina freqüència (en fotogrames) s'executa una comprovació de detecció per confirmar un objecte estacionari."
},
"threshold": {
"label": "Llindar estacionari",
"description": "Nombre de fotogrames sense cap canvi de posició necessari per a marcar un objecte com a estacionari."
},
"max_frames": {
"label": "Fotogrames màxims",
"description": "Limita quant de temps es segueixen els objectes estacionaris abans de descartar-los.",
"default": {
"label": "Fotogrames màxims predeterminats",
"description": "Fotogrames màxims predeterminats per a fer el seguiment d'un objecte estacionari abans d'aturar-se."
},
"objects": {
"label": "Fotogrames màxims de l'objecte",
"description": "Sobreescriu l'objecte per als fotogrames màxims per fer un seguiment dels objectes estacionaris."
}
},
"classifier": {
"label": "Habilita el classificador visual",
"description": "Utilitza un classificador visual per detectar objectes realment estàtics, fins i tot quan els quadres de delimitació tremolen."
}
},
"annotation_offset": {
"label": "Desplaçament de l'anotació",
"description": "Mil·lisegons per a desplaçar detecta anotacions per a alinear millor els límits de la línia de temps amb els enregistraments; pot ser positiu o negatiu."
}
},
"face_recognition": {
"label": "Reconeixement de cares",
"description": "Configuració per a la detecció de la cara i el reconeixement d'aquesta càmera.",
"enabled": {
"label": "Habilita el reconeixement facial",
"description": "Activa o desactiva el reconeixement facial."
},
"min_area": {
"label": "Àrea mínima de la cara",
"description": "Àrea mínima (píxels) d'un quadre facial detectat requerit per intentar el reconeixement."
}
},
"ffmpeg": {
"label": "FFmpeg",
"description": "Paràmetres del FFmpeg que inclouen camins binaris, args, opcions de hwaccel i args de sortida per rol.",
"path": {
"label": "Ruta FFmpeg",
"description": "Camí al binari FFmpeg a usar o un àlies de versió («5.0» o «7.0»)."
},
"global_args": {
"label": "Arguments globals del FFmpeg",
"description": "Arguments globals passats als processos FFmpeg."
},
"hwaccel_args": {
"label": "Arguments d'acceleració del maquinari",
"description": "Arguments d'acceleració de maquinari per a FFmpeg. Es recomanen predefinits específics del proveïdor."
},
"input_args": {
"label": "Arguments d'entrada",
"description": "Arguments d'entrada aplicats als fluxos d'entrada del FFmpeg."
},
"output_args": {
"label": "Arguments de sortida",
"description": "Arguments de sortida predeterminats utilitzats per a diferents rols FFmpeg com detecta i registra.",
"detect": {
"label": "Detecta els arguments de sortida",
"description": "Arguments de sortida predeterminats per a detectar fluxos de rol."
},
"record": {
"label": "Registra els arguments de sortida",
"description": "Arguments de sortida predeterminats per a enregistrar fluxos de rols."
}
},
"retry_interval": {
"label": "Temps de reintent del FFmpeg",
"description": "Segons a esperar abans d'intentar tornar a connectar un flux de càmera després d'un error. Per defecte és 10."
},
"apple_compatibility": {
"label": "Compatibilitat d'Apple",
"description": "Activa l'etiquetatge HEVC per a una millor compatibilitat amb el reproductor d'Apple en gravar H.265."
},
"gpu": {
"label": "Índex de GPU",
"description": "Índex de GPU predeterminat utilitzat per a l'acceleració de maquinari si està disponible."
},
"inputs": {
"label": "Entrada de la càmera",
"description": "Llista de definicions de flux d'entrada (camins i rols) per a aquesta càmera.",
"path": {
"label": "Ruta d'entrada",
"description": "URL o ruta del flux d'entrada de la càmera."
},
"roles": {
"label": "Rols d'entrada",
"description": "Rols per a aquest flux d'entrada."
},
"global_args": {
"label": "Arguments globals del FFmpeg",
"description": "Arguments globals del FFmpeg per a aquest flux d'entrada."
},
"hwaccel_args": {
"label": "Arguments d'acceleració del maquinari",
"description": "Arguments d'acceleració del maquinari per a aquest flux d'entrada."
},
"input_args": {
"label": "Arguments d'entrada",
"description": "Arguments d'entrada específics d'aquest flux."
}
}
},
"live": {
"label": "Reproducció en directe",
"description": "Configuració utilitzada per la interfície d'usuari web per controlar la selecció, resolució i qualitat del flux en viu.",
"streams": {
"label": "Noms de flux en viu",
"description": "Assignació de noms de flux configurats per a restream/go2rtc noms utilitzats per a la reproducció en viu."
},
"height": {
"label": "Alçada del directe",
"description": "Alçada (píxels) per a renderitzar el flux en viu jsmpeg a la interfície d'usuari web; ha de ser . detecta l'alçada del flux."
},
"quality": {
"label": "Qualitat del directe",
"description": "Qualitat de codificació per al flux jsmpeg (1 més alt, 31 més baix)."
}
},
"lpr": {
"label": "Reconeixement de matrícules",
"description": "Paràmetres de reconeixement de la matrícula de la llicència, inclosos els llindars de detecció, el format i les plaques conegudes.",
"enabled": {
"label": "Habilita el LPR",
"description": "Activa o desactiva LPR en aquesta càmera."
},
"expire_time": {
"label": "Segons de caducitat",
"description": "Temps en segons després del qual una matrícules no vista expira del rastrejador (només per a càmeres LPR dedicades)."
},
"min_area": {
"label": "Àrea mínima de la matrícula",
"description": "Àrea mínima de matrícula (píxels) necessària per intentar el reconeixement."
},
"enhancement": {
"label": "Nivell de millora",
"description": "Nivell de millora (0-10) per aplicar als cultius de plaques abans de l'OCR; els valors més alts no sempre poden millorar els resultats, els nivells superiors a 5 només poden funcionar amb plaques nocturnes i s'han d'utilitzar amb precaució."
}
},
"motion": {
"label": "Detecció de moviment",
"enabled": {
"label": "Habilita la detecció de moviment",
"description": "Activa o desactiva la detecció de moviment d'aquesta càmera."
},
"description": "Configuració predeterminada de detecció de moviment per a aquesta càmera.",
"threshold": {
"label": "Llindar del moviment",
"description": "Llindar de diferència de píxels utilitzat pel detector de moviment; els valors més alts redueixen la sensibilitat (interval 1-255)."
},
"lightning_threshold": {
"label": "Llindar del llamp",
"description": "Llindar per detectar i ignorar les puntes d'il·luminació breu (més baixes són més sensibles, valors entre 0,3 i 1,0)."
},
"improve_contrast": {
"label": "Millora el contrast",
"description": "Aplicar la millora del contrast als fotogrames abans de l'anàlisi del moviment per ajudar a la detecció."
},
"contour_area": {
"label": "Àrea de la vora",
"description": "Àrea mínima de contorn en píxels necessària per a comptar un contorn de moviment."
},
"delta_alpha": {
"label": "Delta alfa",
"description": "Factor de barreja alfa utilitzat en la diferència de fotogrames per al càlcul del moviment."
},
"frame_alpha": {
"label": "Alfa del fotograma",
"description": "Valor alfa utilitzat en la barreja de fotogrames per al preprocessament del moviment."
},
"frame_height": {
"label": "Alçada del fotograma",
"description": "Alçada en píxels per a escalar els fotogrames quan es computa el moviment."
},
"mask": {
"label": "Coordenades de la màscara",
"description": "Coordenades x,y que defineixen el polígon de màscara de moviment utilitzat per incloure/excloure àrees."
},
"mqtt_off_delay": {
"label": "Retard MQTT desactivat",
"description": "Segons a esperar després de l'última moció abans de publicar un estat MQTT 'off'."
},
"enabled_in_config": {
"label": "Estat del moviment original",
"description": "Indica si la detecció de moviment s'ha activat en la configuració estàtica original."
},
"raw_mask": {
"label": "Màscara en brut"
}
},
"objects": {
"label": "Objectes",
"description": "Object tracking defaults incloent quines etiquetes rastrejar i per objecte filtres.",
"track": {
"label": "Objectes a seguir",
"description": "Llista d'etiquetes d'objectes a seguir per a aquesta càmera."
},
"filters": {
"label": "Filtres d'objectes",
"description": "Filtres aplicats als objectes detectats per reduir falsos positius (àrea, relació, confiança).",
"min_area": {
"label": "Àrea mínima de l'objecte",
"description": "Es requereix una àrea de caixa contenidora mínima (píxels o percentatge) per a aquest tipus d'objecte. Pot ser píxels (int) o percentatge (float entre 0,000001 i 0.99)."
},
"max_area": {
"label": "Àrea màxima de l'objecte",
"description": "Es permet l'àrea màxima de la caixa contenidora (píxels o percentatge) per a aquest tipus d'objecte. Pot ser píxels (int) o percentatge (float entre 0,000001 i 0.99)."
},
"min_ratio": {
"label": "Relació mínima d'aspecte",
"description": "Relació mínima d'amplada/alçada requerida per a la casella contenidora a qualificar."
},
"max_ratio": {
"description": "Es permet la relació màxima d'amplada/alçada per a la casella contenidora a qualificar.",
"label": "Relació màxima d'aspecte"
},
"threshold": {
"label": "Llindar de confiança",
"description": "Es requereix un llindar de confiança mitjà per a la detecció perquè l'objecte es consideri un veritable positiu."
},
"min_score": {
"label": "Confiança mínima",
"description": "Es requereix una confiança mínima de detecció d'un sol fotograma per a comptar l'objecte."
},
"mask": {
"label": "Màscara de filtre",
"description": "Coordenades de polígon que defineixen on s'aplica aquest filtre dins del marc."
},
"raw_mask": {
"label": "Màscara en brut"
}
},
"mask": {
"label": "Màscara d'objecte",
"description": "Polígon de màscara utilitzat per evitar la detecció d'objectes en àrees especificades."
},
"raw_mask": {
"label": "Màscara en brut"
},
"genai": {
"label": "Configuració de l'objecte GenAI",
"description": "Opcions de GenAI per descriure objectes rastrejats i enviar fotogrames per a la generació.",
"enabled": {
"label": "Habilita el GenAI",
"description": "Habilita la generació de descripcions de GenAI per als objectes rastrejats de manera predeterminada."
},
"use_snapshot": {
"label": "Utilitza instantànies",
"description": "Usa instantànies d'objecte en lloc de miniatures per a la generació de descripcions de GenAI."
},
"prompt": {
"label": "Indicació de la llegenda",
"description": "Plantilla de pregunta predeterminada utilitzada en generar descripcions amb GenAI."
},
"object_prompts": {
"label": "Peticions d'objecte",
"description": "Per objecte demana personalitzar les sortides de GenAI per a etiquetes específiques."
},
"objects": {
"label": "Objectes GenAI",
"description": "Llista d'etiquetes d'objectes a enviar a GenAI per defecte."
},
"required_zones": {
"label": "Zones requerides",
"description": "Zones que s'han d'introduir perquè els objectes es puguin classificar per a la generació de descripcions de GenAI."
},
"debug_save_thumbnails": {
"label": "Desa les miniatures",
"description": "Desa les miniatures enviades a GenAI per a la depuració i la revisió."
},
"send_triggers": {
"label": "Activadors de GenAI",
"description": "Defineix quan s'han d'enviar fotogrames a GenAI (al final, després de les actualitzacions, etc.).",
"tracked_object_end": {
"label": "Envia al final",
"description": "Envia una sol·licitud a GenAI quan acabi l'objecte rastrejat."
},
"after_significant_updates": {
"label": "Activador de GenAI primerenc",
"description": "Envia una sol·licitud a GenAI després d'un nombre especificat d'actualitzacions significatives per a l'objecte rastrejat."
}
},
"enabled_in_config": {
"label": "Estat original de GenAI",
"description": "Indica si el GenAI s'ha activat a la configuració estàtica original."
}
}
},
"record": {
"label": "Enregistrament",
"description": "Configuració d'enregistrament i retenció d'aquesta càmera.",
"enabled": {
"label": "Habilita l'enregistrament",
"description": "Activa o desactiva l'enregistrament d'aquesta càmera."
},
"expire_interval": {
"label": "Interval de neteja de l'enregistrament",
"description": "Minuts entre passades de neteja que eliminen segments d'enregistrament caducats."
},
"continuous": {
"label": "Retenció contínua",
"description": "Nombre de dies per a retenir els enregistraments independentment dels objectes rastrejats o del moviment. Establiu-ho a 0 si només voleu retenir enregistraments d'alertes i deteccions.",
"days": {
"label": "Dies de retenció",
"description": "Dies per retenir enregistraments."
}
},
"motion": {
"label": "Retenció del moviment",
"description": "Nombre de dies per a retenir els enregistraments activats pel moviment independentment dels objectes rastrejats. Establiu-ho a 0 si només voleu retenir enregistraments d'alertes i deteccions.",
"days": {
"label": "Dies de retenció",
"description": "Dies per retenir enregistraments."
}
},
"detections": {
"label": "Retenció de detecció",
"description": "Configuració de retenció de l'enregistrament per a esdeveniments de detecció, incloent-hi la durada de la captura anterior a la publicació.",
"pre_capture": {
"label": "Segons de precaptura",
"description": "Nombre de segons abans de l'esdeveniment de detecció a incloure en l'enregistrament."
},
"post_capture": {
"label": "Segons de postcaptura",
"description": "Nombre de segons després de l'esdeveniment de detecció que s'inclourà a l'enregistrament."
},
"retain": {
"label": "Retenció d'esdeveniments",
"description": "Configuració de retenció per a enregistraments d'esdeveniments de detecció.",
"days": {
"label": "Dies de retenció",
"description": "Nombre de dies per a retenir enregistraments d'esdeveniments de detecció."
},
"mode": {
"label": "Mode de retenció",
"description": "Mode de retenció: tot (desa tots els segments), moviment (desa els segments amb moviment), o actiuobobjectes (desa els segments amb objectes actius)."
}
}
},
"alerts": {
"label": "Retenció d'alerta",
"description": "Configuració de retenció de l'enregistrament per a esdeveniments d'alerta, incloses les durades de captura anteriors a la publicació.",
"pre_capture": {
"label": "Segons de precaptura",
"description": "Nombre de segons abans de l'esdeveniment de detecció a incloure en l'enregistrament."
},
"post_capture": {
"label": "Segons de postcaptura",
"description": "Nombre de segons després de l'esdeveniment de detecció que s'inclourà a l'enregistrament."
},
"retain": {
"label": "Retenció d'esdeveniments",
"description": "Configuració de retenció per a enregistraments d'esdeveniments de detecció.",
"days": {
"label": "Dies de retenció",
"description": "Nombre de dies per a retenir enregistraments d'esdeveniments de detecció."
},
"mode": {
"label": "Mode de retenció",
"description": "Mode de retenció: tot (desa tots els segments), moviment (desa els segments amb moviment), o actiuobobjectes (desa els segments amb objectes actius)."
}
}
},
"export": {
"label": "Exporta la configuració",
"description": "Paràmetres utilitzats en exportar enregistraments com el timelapse i l'acceleració del maquinari.",
"hwaccel_args": {
"label": "Exporta els arguments de l'hwaccel",
"description": "Args d'acceleració de maquinari a utilitzar per a operacions d'exportació/transcodificació."
}
},
"preview": {
"label": "Configuració de la vista prèvia",
"description": "Paràmetres que controlen la qualitat de les vistes prèvies de l'enregistrament que es mostren a la interfície d'usuari.",
"quality": {
"label": "Qualitat de la vista prèvia",
"description": "Nivell de qualitat de la vista prèvia (moltlowbaix, baix, mitjà, alt, molt).alt)."
}
},
"enabled_in_config": {
"label": "Estat de l'enregistrament original",
"description": "Indica si l'enregistrament s'ha activat en la configuració estàtica original."
}
},
"review": {
"label": "Revisió",
"description": "Configuració que controla les alertes, les deteccions i els resums de revisió de GenAI utilitzats per la interfície d'usuari i l'emmagatzematge d'aquesta càmera.",
"alerts": {
"label": "Configuració d'alertes",
"description": "Paràmetres per als quals els objectes rastrejats generen alertes i com es mantenen les alertes.",
"enabled": {
"label": "Habilita les alertes",
"description": "Activa o desactiva la generació d'alertes per a aquesta càmera."
},
"labels": {
"label": "Etiquetes d'alerta",
"description": "Llista d'etiquetes d'objectes que qualifiquen d'alertes (per exemple: cotxe, persona)."
},
"required_zones": {
"label": "Zones requerides",
"description": "Zones que un objecte ha d'introduir per a ser considerat una alerta; deixeu-ho buit per a permetre qualsevol zona."
},
"enabled_in_config": {
"label": "Estat de les alertes originals",
"description": "Fa un seguiment de si les alertes es van habilitar originalment a la configuració estàtica."
},
"cutoff_time": {
"label": "Temps de tall d'alertes",
"description": "Segons a esperar després de no provocar activitat d'alerta abans de tallar una alerta."
}
},
"detections": {
"label": "Configuració de les deteccions",
"description": "Paràmetres per a crear esdeveniments de detecció (no-alerta) i quant de temps conservar-los.",
"enabled": {
"label": "Habilita les deteccions",
"description": "Activa o desactiva els esdeveniments de detecció d'aquesta càmera."
},
"labels": {
"label": "Etiquetes de detecció",
"description": "Llista d'etiquetes d'objectes que es qualifiquen com a esdeveniments de detecció."
},
"required_zones": {
"label": "Zones requerides",
"description": "Zones que un objecte ha d'introduir per a ser considerat una detecció; deixeu-ho buit per a permetre qualsevol zona."
},
"cutoff_time": {
"label": "Temps de tall de detecció",
"description": "Segons a esperar després de no haver-hi activitat de detecció abans de tallar una detecció."
},
"enabled_in_config": {
"label": "Estat de les deteccions originals",
"description": "Fa un seguiment de si les deteccions es van habilitar originalment a la configuració estàtica."
}
},
"genai": {
"label": "Configuració del GenAI",
"description": "Controla l'ús de la IA generativa per a la producció de descripcions i resums d'articles de revisió.",
"enabled": {
"label": "Habilita les descripcions del GenAI",
"description": "Activa o desactiva les descripcions i resums generats per GenAI per als elements de revisió."
},
"alerts": {
"label": "Habilita el GenAI per a alertes",
"description": "Utilitzeu GenAI per a generar descripcions per als elements d'alerta."
},
"detections": {
"label": "Habilita el GenAI per a les deteccions",
"description": "Utilitzeu GenAI per generar descripcions per als elements de detecció."
},
"image_source": {
"label": "Revisa l'origen de la imatge",
"description": "Font d'imatges enviades a GenAI ('previsualització' o 'enregistraments'); 'enregistraments' utilitza Fotogrames de més qualitat però més tokens."
},
"additional_concerns": {
"label": "Altres preocupacions",
"description": "Una llista de preocupacions o notes addicionals que el GenAI ha de tenir en compte a l'hora d'avaluar l'activitat en aquesta càmera."
},
"debug_save_thumbnails": {
"label": "Desa les miniatures",
"description": "Desa les miniatures que s'envien al proveïdor GenAI per a la depuració i la revisió."
},
"enabled_in_config": {
"label": "Estat original de GenAI",
"description": "Fa un seguiment de si la revisió de GenAI es va habilitar originalment a la configuració estàtica."
},
"preferred_language": {
"label": "Idioma preferit",
"description": "Idioma preferit per sol·licitar al proveïdor GenAI respostes generades."
},
"activity_context_prompt": {
"label": "Indicador de context de l'activitat",
"description": "Pregunta personalitzada que descriu el que és i no és una activitat sospitosa per proporcionar context per als resums de GenAI."
}
}
},
"semantic_search": {
"label": "Cerca semàntica",
"description": "Paràmetres per a la cerca semàntica que construeix i consulta incrustacions d'objectes per a trobar elements similars.",
"triggers": {
"label": "Activadors",
"description": "Accions i criteris coincidents per als desencadenants de cerca semàntica específics de la càmera.",
"friendly_name": {
"label": "Nom amistós",
"description": "Nom opcional amistós que es mostra a la interfície d'usuari per a aquest activador."
},
"enabled": {
"label": "Habilita aquest activador",
"description": "Activa o desactiva aquest activador de cerca semàntica."
},
"type": {
"label": "Tipus d'activador",
"description": "Tipus d'activador: «miniatures» (match contra imatge) o «descripció» (match contra text)."
},
"data": {
"label": "Contingut del disparador",
"description": "Frase de text o ID de miniatures per a coincidir amb els objectes rastrejats."
},
"threshold": {
"label": "Llindar d'activació",
"description": "Puntuació mínima de similitud (0-1) necessària per activar aquest activador."
},
"actions": {
"label": "Accions d'activació",
"description": "Llista d'accions a executar quan coincideixi l'activador (notificació, sublabeletiqueta, atribut)."
}
}
},
"snapshots": {
"label": "Instantànies",
"description": "Configuració per a les instantànies JPEG desades dels objectes seguits per a aquesta càmera.",
"enabled": {
"label": "Instantànies habilitades",
"description": "Activa o desactiva el desament de les instantànies d'aquesta càmera."
},
"clean_copy": {
"label": "Desa la còpia neta",
"description": "Desa una còpia neta no anotada de les instantànies a més de les anotades."
},
"timestamp": {
"label": "Superposició de marca horària",
"description": "Superposa una marca horària a les instantànies desades."
},
"bounding_box": {
"label": "Superposició de la caixa contenidora",
"description": "Dibuixa caixes delimitadores per als objectes seguits en les instantànies desades."
},
"crop": {
"label": "Retalla la instantània",
"description": "Retalla les instantànies desades a la caixa delimitadora de l'objecte detectat."
},
"required_zones": {
"label": "Zones requerides",
"description": "Zones que ha d'introduir un objecte perquè es desi una instantània."
},
"height": {
"label": "Alçada de la instantània",
"description": "Alçada (píxels) per a canviar la mida de les instantànies desades; deixeu-ho buit per a preservar la mida original."
},
"retain": {
"label": "Retenció de la instantània",
"description": "Paràmetres de retenció per a les instantànies desades, inclosos els dies predeterminats i les anul·lacions per objecte.",
"default": {
"label": "Retenció predeterminada",
"description": "Nombre predeterminat de dies per a retenir les instantànies."
},
"mode": {
"label": "Mode de retenció",
"description": "Mode de retenció: tot (desa tots els segments), moviment (desa els segments amb moviment), o actiuobobjectes (desa els segments amb objectes actius)."
},
"objects": {
"label": "Retenció d'objectes",
"description": "Anul·lació per objecte per dies de retenció d'instantànies."
}
},
"quality": {
"label": "Qualitat JPEG",
"description": "Qualitat del codi JPEG per a les instantànies desades (0-100)."
}
},
"timestamp_style": {
"label": "Estil de la marca horària",
"description": "Opcions d'estilització per a marques de temps d'alimentació aplicades a enregistraments i instantànies.",
"position": {
"label": "Posició de la marca horària",
"description": "Posició de la marca horària a la imatge (tl/tr/bl/br)."
},
"format": {
"label": "Format de la marca horària",
"description": "Cadena de format de data i hora utilitzada per a marques horàries (codis de format de data i hora de Python)."
},
"color": {
"label": "Color de la marca horària",
"description": "Valors de color RGB per al text de la marca de temps (tots els valors 0-255).",
"red": {
"label": "Vermell",
"description": "Component vermell (0-255) per al color de la marca horària."
},
"green": {
"label": "Verd",
"description": "Component verd (0-255) per al color de la marca horària."
},
"blue": {
"label": "Blau",
"description": "Component blau (0-255) per al color de la marca horària."
}
},
"thickness": {
"label": "Gruix de la marca de temps",
"description": "Gruix de la línia del text de la marca de temps."
},
"effect": {
"label": "Efecte de marca horària",
"description": "Efecte visual per al text de la marca de temps (cap, sòlid, ombra)."
}
},
"best_image_timeout": {
"label": "Temps d'espera de la millor imatge",
"description": "Quant de temps s'espera per a la imatge amb la puntuació de confiança més alta."
},
"mqtt": {
"label": "MQTT",
"description": "Configuració de la publicació d'imatges MQTT.",
"enabled": {
"label": "Envia la imatge",
"description": "Habilita la publicació d'instantànies d'imatges per a objectes als temes MQTT d'aquesta càmera."
},
"timestamp": {
"label": "Afegeix una marca horària",
"description": "Superposa una marca horària a les imatges publicades a MQTT."
},
"bounding_box": {
"label": "Afegeix el quadre de delimitació",
"description": "Dibuixa caixes delimitadores en imatges publicades sobre MQTT."
},
"crop": {
"label": "Retalla la imatge",
"description": "Retalla les imatges publicades a MQTT a la caixa contenidora de l'objecte detectat."
},
"height": {
"label": "Alçada de la imatge",
"description": "Alçada (píxels) per a canviar la mida de les imatges publicades sobre MQTT."
},
"required_zones": {
"label": "Zones requerides",
"description": "Zones que ha d'introduir un objecte perquè es publiqui una imatge MQTT."
},
"quality": {
"label": "Qualitat JPEG",
"description": "Qualitat JPEG per a les imatges publicades a MQTT (0-100)."
}
},
"notifications": {
"label": "Notificacions",
"description": "Configuració per a habilitar i controlar les notificacions d'aquesta càmera.",
"enabled": {
"label": "Habilita les notificacions",
"description": "Activa o desactiva les notificacions d'aquesta càmera."
},
"email": {
"label": "Correu electrònic de notificació",
"description": "Adreça de correu electrònic utilitzada per a notificacions push o requerides per determinats proveïdors de notificacions."
},
"cooldown": {
"label": "Període de reducció",
"description": "Retirada (segons) entre notificacions per evitar els destinataris de correu brossa."
},
"enabled_in_config": {
"label": "Estat de les notificacions originals",
"description": "Indica si les notificacions s'han activat en la configuració estàtica original."
}
},
"onvif": {
"label": "ONVIF",
"description": "Connexió ONVIF i configuració de seguiment automàtic PTZ per a aquesta càmera.",
"host": {
"label": "Servidor ONVIF",
"description": "Host (i esquema opcional) per al servei ONVIF per a aquesta càmera."
},
"port": {
"label": "Port ONVIF",
"description": "Número de port del servei ONVIF."
},
"user": {
"label": "Nom d'usuari ONVIF",
"description": "Nom d'usuari per a l'autenticació ONVIF; alguns dispositius requereixen l'usuari administrador per a ONVIF."
},
"password": {
"label": "Contrasenya ONVIF",
"description": "Contrasenya per a l'autenticació ONVIF."
},
"tls_insecure": {
"label": "Inhabilita la verificació TLS",
"description": "Omet la verificació TLS i desactiva l'autenticació de resum per a ONVIF (no segur; només s'utilitza en xarxes segures)."
},
"autotracking": {
"label": "Seguiment automàtic",
"description": "Segueix automàticament els objectes en moviment i els manté centrats en el marc utilitzant els moviments de la càmera PTZ.",
"enabled": {
"label": "Habilita el seguiment automàtic",
"description": "Activa o desactiva el seguiment automàtic de la càmera PTZ dels objectes detectats."
},
"calibrate_on_startup": {
"label": "Calibra a l'inici",
"description": "Mesura les velocitats del motor PTZ a l'inici per millorar la precisió del seguiment. Frigate actualitzarà la configuració amb «movtion.weights» després del calibratge."
},
"zooming": {
"label": "Mode de zoom",
"description": "Comportament de zoom de control: desactivat (només pan/tilt), absolut (més compatible) o relatiu (pa/tilt/zoom concurrent)."
},
"zoom_factor": {
"label": "Factor de zoom",
"description": "Controla el nivell d'ampliació dels objectes rastrejats. Els valors més baixos mantenen més escena a la vista; els valors més alts s'apropen, però poden perdre el seguiment. Valors entre 0,1 i 0,75."
},
"track": {
"label": "Objectes rastrejats",
"description": "Llista de tipus d'objectes que haurien d'activar el seguiment automàtic."
},
"required_zones": {
"label": "Zones requerides",
"description": "Els objectes han d'entrar en una d'aquestes zones abans que comenci el seguiment automàtic."
},
"return_preset": {
"label": "Retorna la predefinició",
"description": "Nom predefinit ONVIF configurat al microprogramari de la càmera per tornar després de finalitzar el seguiment."
},
"timeout": {
"label": "Temps d'espera de retorn",
"description": "Espereu tants segons després de perdre el seguiment abans de tornar la càmera a la posició preestablerta."
},
"movement_weights": {
"label": "Pes del moviment",
"description": "Valors de calibratge generats automàticament pel calibratge de la càmera. No modifiquis manualment."
},
"enabled_in_config": {
"label": "Estat d'autoseguiment original",
"description": "Camp intern per a fer el seguiment de si s'ha habilitat el seguiment automàtic a la configuració."
}
},
"ignore_time_mismatch": {
"label": "Ignora el desajust de temps",
"description": "Ignora les diferències de sincronització de temps entre càmera i servidor Frigate per a la comunicació ONVIF."
}
},
"type": {
"label": "Tipus de càmera",
"description": "Tipus de càmera"
},
"ui": {
"label": "Interfície d'usuari de la càmera",
"description": "Mostra l'ordre i la visibilitat d'aquesta càmera a la interfície d'usuari. La comanda afecta el tauler predeterminat. Per a un control més granular, utilitzeu grups de càmera.",
"order": {
"label": "Ordre de la interfície",
"description": "Ordre numèric utilitzat per ordenar la càmera a la interfície d'usuari (taulell de control i llistes per defecte); els nombres més grans apareixen més tard."
},
"dashboard": {
"label": "Mostra a l'interfície d'usuari",
"description": "Estableix si aquesta càmera és visible a tot arreu a la interfície d'usuari de la Frigate. Desactivar això requerirà editar manualment la configuració per tornar a veure aquesta càmera a la interfície d'usuari."
}
},
"webui_url": {
"label": "URL de la càmera",
"description": "URL per visitar la càmera directament des de la pàgina del sistema"
},
"zones": {
"label": "Zones",
"description": "Les zones permeten definir una àrea específica del marc perquè pugueu determinar si un objecte es troba dins d'una àrea determinada.",
"friendly_name": {
"label": "Nom de la zona",
"description": "Un nom fàcil d'utilitzar per a la zona, que es mostra a la interfície d'usuari de la fragata. Si no s'estableix, s'utilitzarà una versió amb format del nom de la zona."
},
"enabled": {
"label": "Si aquesta zona està activa. Les zones inhabilitades s'ignoren en temps d'execució."
},
"enabled_in_config": {
"label": "Feu un seguiment de l'estat original de la zona."
},
"filters": {
"label": "Filtres de zona",
"description": "Filtres que s'aplicaran als objectes d'aquesta zona. S'utilitza per reduir falsos positius o restringir quins objectes es consideren presents a la zona.",
"min_area": {
"label": "Àrea mínima de l'objecte",
"description": "Es requereix una àrea de caixa contenidora mínima (píxels o percentatge) per a aquest tipus d'objecte. Pot ser píxels (int) o percentatge (float entre 0,000001 i 0.99)."
},
"max_area": {
"label": "Àrea màxima de l'objecte",
"description": "Es permet l'àrea màxima de la caixa contenidora (píxels o percentatge) per a aquest tipus d'objecte. Pot ser píxels (int) o percentatge (float entre 0,000001 i 0.99)."
},
"min_ratio": {
"label": "Relació mínima d'aspecte",
"description": "Relació mínima d'amplada/alçada requerida per a la casella contenidora a qualificar."
},
"max_ratio": {
"label": "Relació màxima d'aspecte",
"description": "Es permet la relació màxima d'amplada/alçada per a la casella contenidora a qualificar."
},
"threshold": {
"label": "Llindar de confiança",
"description": "Es requereix un llindar de confiança mitjà per a la detecció perquè l'objecte es consideri un veritable positiu."
},
"min_score": {
"label": "Confiança mínima",
"description": "Es requereix una confiança mínima de detecció d'un sol fotograma per a comptar l'objecte."
},
"mask": {
"label": "Màscara de filtre",
"description": "Coordenades de polígon que defineixen on s'aplica aquest filtre dins del marc."
},
"raw_mask": {
"label": "Màscara en brut"
}
},
"objects": {
"description": "Llista de tipus d'objectes (des del mapa d'etiquetes) que poden activar aquesta zona. Pot ser una cadena o una llista de cadenes. Si està buit, es consideraran tots els objectes.",
"label": "Objectes d'activació"
},
"coordinates": {
"label": "Coordenades",
"description": "Coordenades de polígon que defineixen l'àrea de zona. Pot ser una cadena separada per comes o una llista de cadenes de coordenades. Les coordenades han de ser relatives (0-1) o absolutes (antic)."
},
"distances": {
"label": "Distàncies del món real",
"description": "Distàncies opcionals del món real per a cada costat del quadrilàter de la zona, utilitzades per a càlculs de velocitat o distància. Si s'estableix, ha de tenir exactament 4 valors."
},
"inertia": {
"label": "Fotogrames d'inèrcia",
"description": "Nombre de fotogrames consecutius que s'ha de detectar un objecte a la zona abans de considerar-lo present. Ajuda a filtrar les deteccions transitòries."
},
"loitering_time": {
"label": "Segons flotants",
"description": "Nombre de segons que un objecte ha de romandre a la zona a considerar com a errant. Establiu-ho a 0 per a desactivar la detecció de la itinerància."
},
"speed_threshold": {
"label": "Velocitat mínima",
"description": "Velocitat mínima (en unitats del món real si s'estableixen distàncies) necessària perquè un objecte es consideri present a la zona. S'utilitza per a activadors de zona basats en velocitat."
}
},
"enabled_in_config": {
"label": "Estat original de la càmera",
"description": "Feu un seguiment de l'estat original de la càmera."
}
}

View File

@ -39,7 +39,7 @@
"surfboard": "Taula de surf",
"tennis_racket": "Raqueta de tenis",
"bottle": "Ampolla",
"plate": "Placa",
"plate": "Matrícula",
"wine_glass": "Got de vi",
"cup": "Copa",
"fork": "Forquilla",

View File

@ -27,7 +27,7 @@
"deleteImageFailed": "No s'ha pogut suprimir: {{errorMessage}}",
"deleteCategoryFailed": "No s'ha pogut suprimir la classe: {{errorMessage}}",
"categorizeFailed": "No s'ha pogut categoritzar la imatge: {{errorMessage}}",
"trainingFailed": "Ha fallat l'entrenament del model. Comproveu els registres de fragata per a més detalls.",
"trainingFailed": "Ha fallat l'entrenament del model. Comproveu els registres de Frigate per a més detalls.",
"deleteModelFailed": "No s'ha pogut suprimir el model: {{errorMessage}}",
"updateModelFailed": "No s'ha pogut actualitzar el model: {{errorMessage}}",
"renameCategoryFailed": "No s'ha pogut canviar el nom de la classe: {{errorMessage}}",

View File

@ -285,7 +285,7 @@
"title": "Configuració d'anotacions",
"showAllZones": {
"title": "Mostra totes les Zones",
"desc": "Mostra sempre les zones amb marcs on els objectes hagin entrat a la zona."
"desc": "Mostra sempre les zones amb fotogrames on els objectes hagin entrat a la zona."
},
"offset": {
"label": "Òfset d'Anotació",

View File

@ -11,13 +11,27 @@
},
"toast": {
"error": {
"renameExportFailed": "Error al canviar el nom de lexportació: {{errorMessage}}"
"renameExportFailed": "Error al canviar el nom de lexportació: {{errorMessage}}",
"assignCaseFailed": "No s'ha pogut actualitzar l'assignació de cas:{{errorMessage}}"
}
},
"tooltip": {
"shareExport": "Comparteix l'exportació",
"downloadVideo": "Baixa el vídeo",
"editName": "Edita el nom",
"deleteExport": "Suprimeix l'exportació"
"deleteExport": "Suprimeix l'exportació",
"assignToCase": "Afegeix al cas"
},
"headings": {
"cases": "Casos",
"uncategorizedExports": "Exportacions sense categoria"
},
"caseDialog": {
"title": "Afegeix al cas",
"description": "Trieu un cas existent o creeu-ne un de nou.",
"selectLabel": "Cas",
"newCaseOption": "Crea un cas nou",
"nameLabel": "Nom del cas",
"descriptionLabel": "Descripció"
}
}

View File

@ -7,17 +7,20 @@
"authentication": "Configuració d'autenticació - Frigate",
"camera": "Paràmetres de càmera - Frigate",
"masksAndZones": "Editor de màscares i zones - Frigate",
"general": "Configuració de la interfície d'usuari - Fragata",
"general": "Configuració del perfil - Frigate",
"frigatePlus": "Paràmetres de Frigate+ - Frigate",
"notifications": "Paràmetres de notificació - Frigate",
"cameraManagement": "Gestionar càmeres - Frigate",
"cameraReview": "Configuració Revisió de Càmeres - Frigate"
"cameraReview": "Configuració Revisió de Càmeres - Frigate",
"globalConfig": "Configuració global - Frigate",
"cameraConfig": "Configuració de la càmera - Frigate",
"maintenance": "Manteniment - Frigate"
},
"menu": {
"ui": "Interfície d'usuari",
"cameras": "Paràmetres de la càmera",
"masksAndZones": "Màscares / Zones",
"motionTuner": "Ajust de detecció de moviment",
"motionTuner": "Afinador de moviment",
"users": "Usuaris",
"notifications": "Notificacions",
"debug": "Depuració",
@ -26,7 +29,62 @@
"triggers": "Disparadors",
"cameraManagement": "Gestió",
"cameraReview": "Revisió",
"roles": "Rols"
"roles": "Rols",
"general": "General",
"globalConfig": "Configuració global",
"system": "Sistema",
"integrations": "Integracions",
"profileSettings": "Configuració del perfil",
"globalDetect": "Detecció d'objectes",
"globalRecording": "Enregistrament",
"globalSnapshots": "Instantànies",
"globalFfmpeg": "FFmpeg",
"globalMotion": "Detecció de moviment",
"globalObjects": "Objectes",
"globalReview": "Revisió",
"globalAudioEvents": "Esdeveniments d'àudio",
"globalLivePlayback": "Reproducció en directe",
"globalTimestampStyle": "Estil de la marca horària",
"systemDatabase": "Base de dades",
"systemTls": "TLS",
"systemAuthentication": "Autenticació",
"systemNetworking": "Xarxa",
"systemProxy": "Proxy",
"systemUi": "UI",
"systemLogging": "Registre",
"systemEnvironmentVariables": "Variables d'entorn",
"systemTelemetry": "Telemetria",
"systemBirdseye": "Birdseye",
"systemFfmpeg": "FFmpeg",
"systemDetectorHardware": "Hardware del detector",
"systemDetectionModel": "Model de detecció",
"systemMqtt": "MQTT",
"integrationSemanticSearch": "Cerca semàntica",
"integrationGenerativeAi": "IA generativa",
"integrationFaceRecognition": "Reconeixement de cares",
"integrationLpr": "Reconeixement de la matrícula",
"integrationObjectClassification": "Classificació de l'objecte",
"integrationAudioTranscription": "Transcripció d'àudio",
"cameraDetect": "Detecció d'objectes",
"cameraFfmpeg": "FFmpeg",
"cameraRecording": "Enregistrament",
"cameraSnapshots": "Instantànies",
"cameraMotion": "Detecció de moviment",
"cameraObjects": "Objectes",
"cameraConfigReview": "Revisió",
"cameraAudioEvents": "Esdeveniments d'àudio",
"cameraAudioTranscription": "Transcripció d'àudio",
"cameraNotifications": "Notificacions",
"cameraLivePlayback": "Reproducció en directe",
"cameraBirdseye": "Birdseye",
"cameraFaceRecognition": "Reconeixement de cares",
"cameraLpr": "Reconeixement de la matrícula",
"cameraMqttConfig": "MQTT",
"cameraOnvif": "ONVIF",
"cameraUi": "UI de la càmera",
"cameraTimestampStyle": "Estil de la marca horària",
"cameraMqtt": "Càmera MQTT",
"maintenance": "Manteniment"
},
"dialog": {
"unsavedChanges": {
@ -39,7 +97,7 @@
"noCamera": "Cap càmera"
},
"general": {
"title": "Paràmetres de la interfície d'usuari",
"title": "Configuració del perfil",
"liveDashboard": {
"title": "Panell en directe",
"automaticLiveView": {
@ -205,6 +263,10 @@
"clickDrawPolygon": "Fes click per a dibuixar un polígon a la imatge.",
"toast": {
"success": "S'ha desat la zona ({{zoneName}})."
},
"enabled": {
"title": "Habilitat",
"description": "Si aquesta zona està activa i activada al fitxer de configuració. Si està desactivat, no pot ser habilitat per MQTT. Les zones inhabilitades s'ignoren en temps d'execució."
}
},
"filter": {
@ -237,6 +299,12 @@
"title": "{{polygonName}} s'ha desat.",
"noName": "La màscara de moviment ha estat desada."
}
},
"defaultName": "Màscara de moviment {{number}}",
"name": {
"title": "Nom",
"description": "Un nom opcional per a aquesta màscara de moviment.",
"placeholder": "Introduïu un nom..."
}
},
"objectMasks": {
@ -263,11 +331,16 @@
"noName": "La màscara d'objectes ha estat desada."
}
},
"context": "Les màscares de filtratge dobjectes sutilitzen per descartar falsos positius dun tipus dobjecte concret segons la seva ubicació."
"context": "Les màscares de filtratge dobjectes sutilitzen per descartar falsos positius dun tipus dobjecte concret segons la seva ubicació.",
"name": {
"title": "Nom",
"description": "Un nom opcional per a aquesta màscara d'objecte.",
"placeholder": "Introduïu un nom..."
}
},
"restart_required": "Reinici necessari (canvi de màscares o zones)",
"motionMaskLabel": "Màscara de moviment {{number}}",
"objectMaskLabel": "Màscara d'objecte {{number}} ({{label}})",
"objectMaskLabel": "Màscara d'objecte {{number}}",
"toast": {
"success": {
"copyCoordinates": "S'han copiat les coordenades per a {{polyName}} al porta-retalls."
@ -275,6 +348,13 @@
"error": {
"copyCoordinatesFailed": "No s'han pogut copiar les coordenades al porta-retalls."
}
},
"disabledInConfig": "L'element està desactivat al fitxer de configuració",
"masks": {
"enabled": {
"title": "Habilitat",
"description": "Si aquesta màscara està activada al fitxer de configuració. Si està desactivat, no pot ser habilitat per MQTT. Les màscares desactivades s'ignoren en temps d'execució."
}
}
},
"notification": {
@ -644,7 +724,14 @@
"error": "No s'han pogut guardar els canvis de configuració: {{errorMessage}}",
"success": "Els paràmetres de Frigate+ han estat desats. Reincia Frigate per aplicar els canvis."
},
"restart_required": "Es necessari un reinici (El model de Frigate+ ha cambiat)"
"restart_required": "Es necessari un reinici (El model de Frigate+ ha cambiat)",
"description": "Frigate+ és un servei de subscripció que proporciona accés a funcions i capacitats addicionals per a la vostra instància de Frigate, inclosa la capacitat d'utilitzar models de detecció d'objectes personalitzats entrenats en les vostres pròpies dades. Podeu gestionar la configuració del model Frigate+ aquí.",
"cardTitles": {
"api": "API",
"currentModel": "Model actual",
"otherModels": "Altres models",
"configuration": "Configuració"
}
},
"enrichments": {
"semanticSearch": {
@ -665,7 +752,7 @@
"success": "La reindexació ha començat amb èxit.",
"label": "Reindexar ara",
"confirmTitle": "Confirmar la reindexació",
"desc": "La reindexació regenerarà les incrustacions (embeddings) de tots els objectes seguits. Aquest procés sexecuta en segon pla i pot arribar a saturar la CPU, així com trigar una bona estona depenent del nombre dobjectes seguits que tinguis.",
"desc": "La reindexació regenerarà les incrustacions per a tots els objectes rastrejats. Aquest procés s'executa en segon pla i pot treure el màxim de la CPU i prendre una quantitat de temps raonable depenent del nombre d'objectes rastrejats que tingueu.",
"confirmDesc": "Estàs segur que vols reindexar totes les incrustacions (embeddings) dels objectes seguits? Aquest procés sexecutarà en segon pla, però pot arribar a saturar la CPU i trigar bastant temps. Pots seguir-ne el progrés a la pàgina dExplora.",
"alreadyInProgress": "La reindexació ja està en curs.",
"error": "Error en iniciar la reindexació: {{errorMessage}}"
@ -1181,7 +1268,12 @@
"backToSettings": "Torna a la configuració de la càmera",
"streams": {
"title": "Habilita / Inhabilita les càmeres",
"desc": "Inhabilita temporalment una càmera fins que es reiniciï la fragata. La inhabilitació d'una càmera atura completament el processament de Frigate dels fluxos d'aquesta càmera. La detecció, l'enregistrament i la depuració no estaran disponibles.<br /> <em>Nota: això no desactiva les retransmissions de go2rtc.</em>"
"desc": "Inhabilita temporalment una càmera fins que es reiniciï la fragata. La inhabilitació d'una càmera atura completament el processament de Frigate dels fluxos d'aquesta càmera. La detecció, l'enregistrament i la depuració no estaran disponibles.<br /> <em>Nota: això no desactiva les retransmissions de go2rtc.</em>",
"enableLabel": "Càmeres habilitades",
"enableDesc": "Inhabilita temporalment una càmera habilitada fins que es reiniciï Frigate. La inhabilitació d'una càmera atura completament el processament de Frigate dels fluxos d'aquesta càmera. La detecció, l'enregistrament i la depuració no estaran disponibles.<br /> <em>Nota: això no desactiva les retransmissions de go2rtc.</em>",
"disableLabel": "Càmeres inhabilitades",
"disableDesc": "Habilita una càmera que actualment no és visible a la interfície d'usuari i està desactivada a la configuració. Es requereix un reinici de Frigate després d'activar-la.",
"enableSuccess": "{{cameraName}} activat a la configuració. Reinicia Frigate per aplicar els canvis."
},
"cameraConfig": {
"add": "Afegeix una càmera",
@ -1236,7 +1328,7 @@
"selectDetectionsZones": "Selecció de zones per a les deteccions",
"limitDetections": "Limita les deteccions a zones específiques",
"toast": {
"success": "S'ha desat la configuració de la classificació de la revisió. Reinicia la fragata per aplicar canvis."
"success": "S'ha desat la configuració de la classificació de la revisió. Reinicia Frigate per aplicar canvis."
},
"unsavedChanges": "Paràmetres de classificació de revisions sense desar per {{camera}}",
"objectAlertsTips": "Totes els objectes {{alertsLabels}} de {{cameraName}} es mostraran com avisos.",
@ -1249,5 +1341,254 @@
}
},
"title": "Paràmetres de Revisió de la Càmera"
}
},
"saveAllPreview": {
"title": "Canvis a desar",
"triggerLabel": "Revisa els canvis pendents",
"empty": "No hi ha canvis pendents.",
"scope": {
"label": "Àmbit",
"global": "Global",
"camera": "Càmara:{{cameraName}}"
},
"field": {
"label": "Camp"
},
"value": {
"label": "Valor nou",
"reset": "Restableix"
}
},
"detectionModel": {
"plusActive": {
"title": "Gestió del model Frigate+",
"label": "Font del model actual",
"description": "Aquesta instància està executant un model Frigate+. Seleccioneu o canvieu el vostre model a la configuració de Frigate+.",
"goToFrigatePlus": "Ves a la configuració de Frigate+",
"showModelForm": "Configuració manual d'un model"
}
},
"maintenance": {
"title": "Manteniment",
"sync": {
"title": "Sincronització multimèdia",
"desc": "Frigate netejarà periòdicament els mitjans en un horari regular segons la configuració de la seva retenció. És normal veure alguns arxius orfes mentre corre Frigate. Utilitzeu aquesta característica per eliminar fitxers multimèdia orfes del disc que ja no estan referenciats a la base de dades.",
"started": "S'ha iniciat la sincronització del mitjà.",
"alreadyRunning": "Ja s'està executant una tasca de sincronització",
"error": "No s'ha pogut iniciar la sincronització",
"currentStatus": "Estat",
"jobId": "ID de la tasca",
"startTime": "Hora d'inici",
"endTime": "Hora final",
"statusLabel": "Estat",
"results": "Resultats",
"errorLabel": "Error",
"mediaTypes": "Tipus de suport",
"allMedia": "Tots els suports",
"dryRun": "Executa en sec",
"dryRunEnabled": "No s'eliminarà cap fitxer",
"dryRunDisabled": "S'eliminaran els fitxers",
"force": "Força",
"forceDesc": "Evita el llindar de seguretat i completa la sincronització fins i tot si més del 50% dels fitxers s'eliminarien.",
"running": "Sincronització en execució...",
"start": "Inicia la sincronització",
"inProgress": "La sincronització està en curs. Aquesta pàgina està desactivada.",
"status": {
"queued": "En cua",
"running": "En execució",
"completed": "Completat",
"failed": "Ha fallat",
"notRunning": "No s'està executant"
},
"resultsFields": {
"filesChecked": "Fitxers comprovats",
"orphansFound": "Orfes trobades",
"orphansDeleted": "Orfes eliminats",
"aborted": "Avortat. La supressió superaria el llindar de seguretat.",
"error": "Error",
"totals": "Totals"
},
"event_snapshots": "Instantànies de l'objecte rastrejat",
"event_thumbnails": "Miniatures d'objecte rastrejat",
"review_thumbnails": "Revisa les miniatures",
"previews": "Previsualitzacions",
"exports": "Exporta",
"recordings": "Enregistraments"
}
},
"configForm": {
"global": {
"title": "Configuració global",
"description": "Aquestes opcions de configuració s'apliquen a totes les càmeres, llevat que se substitueixin en la configuració específica de la càmera."
},
"camera": {
"title": "Configuració de la càmera",
"description": "Aquests paràmetres només s'apliquen a aquesta càmera i substitueixen els paràmetres globals."
},
"advancedSettingsCount": "Configuració avançada ({{count}})",
"advancedCount": "Avançat ({{count}})",
"showAdvanced": "Mostra la configuració avançada",
"tabs": {
"sharedDefaults": "Per defecte compartit",
"system": "Sistema",
"integrations": "Integracions"
},
"additionalProperties": {
"keyLabel": "Clau",
"valueLabel": "Valor",
"keyPlaceholder": "Nou valor",
"remove": "Elimina"
},
"timezone": {
"defaultOption": "Utilitza la zona horària del navegador"
},
"roleMap": {
"empty": "No hi ha assignacions de rols",
"roleLabel": "Rol",
"groupsLabel": "Grups",
"addMapping": "Afegeix un mapatge de rol",
"remove": "Elimina"
},
"ffmpegArgs": {
"preset": "Predefinit",
"manual": "Arguments manuals",
"inherit": "Hereta de la configuració de la càmera",
"selectPreset": "Selecció de valors predefinits",
"manualPlaceholder": "ntroduïu els arguments FFmpeg"
},
"cameraInputs": {
"itemTitle": "Flux {{index}}"
},
"restartRequiredField": "Reinicia requerit",
"restartRequiredFooter": "S'ha canviat la configuració - es requereix reiniciar",
"sections": {
"detect": "Detecció",
"record": "Enregistrament",
"snapshots": "Instantànies",
"motion": "Moviment",
"objects": "Objectes",
"review": "Revisió",
"audio": "Àudio",
"notifications": "Notificacions",
"live": "Vista en viu",
"timestamp_style": "Marques temporals",
"mqtt": "MQTT",
"database": "Base de dades",
"telemetry": "Telemetria",
"auth": "Autenticació",
"tls": "TLS",
"proxy": "Proxy",
"go2rtc": "go2rtc",
"ffmpeg": "FFmpeg",
"detectors": "Detectors",
"model": "Model",
"semantic_search": "Cerca semàntica",
"genai": "GenAI",
"face_recognition": "Reconeixement de cares",
"lpr": "Reconeixement de matrícules",
"birdseye": "Birdseye"
},
"detect": {
"title": "Configuració de detecció"
},
"detectors": {
"title": "Configuració del detector",
"singleType": "Només es permet un detector {{type}}.",
"keyRequired": "Es requereix el nom del detector.",
"keyDuplicate": "El nom del detector ja existeix.",
"noSchema": "No hi ha esquemes de detector disponibles.",
"none": "No s'ha configurat cap instància de detector.",
"add": "Afegeix un detector"
},
"record": {
"title": "Configuració de l'enregistrament"
},
"snapshots": {
"title": "Configuració de la instantània"
},
"motion": {
"title": "Configuració del moviment"
},
"objects": {
"title": "Configuració de l'objecte"
},
"audioLabels": {
"summary": "{{count}} etiquetes d'àudio seleccionades",
"empty": "No hi ha etiquetes d'àudio disponibles"
},
"objectLabels": {
"summary": "{{count}} tipus d'objectes seleccionats",
"empty": "No hi ha cap etiqueta d'objecte disponible"
},
"filters": {
"objectFieldLabel": "{{field}} per {{label}}"
},
"zoneNames": {
"summary": "{{count}} seleccionats",
"empty": "No hi ha zones disponibles"
},
"inputRoles": {
"summary": "{{count}} rols seleccionats",
"empty": "No hi ha cap rol disponible",
"options": {
"detect": "Detecta",
"record": "Registre",
"audio": "Àudio"
}
},
"review": {
"title": "Configuració de la revisió"
},
"audio": {
"title": "Configuració de l'àudio"
},
"notifications": {
"title": "Configuració de notificacions"
},
"live": {
"title": "Configuració de la vista en viu"
},
"timestamp_style": {
"title": "Configuració de la marca horària"
},
"searchPlaceholder": "Cerca..."
},
"globalConfig": {
"title": "Configuració global",
"description": "Configura la configuració global que s'aplica a totes les càmeres llevat que se sobreescriti.",
"toast": {
"success": "La configuració global s'ha desat correctament",
"error": "No s'ha pogut desar la configuració global",
"validationError": "Ha fallat la validació"
}
},
"cameraConfig": {
"title": "Configuració de la càmera",
"description": "Configura la configuració per a les càmeres individuals. La configuració substitueix els valors predeterminats globals.",
"overriddenBadge": "Sobreescrit",
"resetToGlobal": "Restableix a global",
"toast": {
"success": "La configuració de la càmera s'ha desat correctament",
"error": "Ha fallat en desar la configuració de la càmera"
}
},
"toast": {
"success": "La configuració s'ha desat correctament",
"successRestartRequired": "La configuració s'ha desat correctament. Reinicia Frigate per aplicar els canvis.",
"error": "No s'ha pogut desar la configuració",
"validationError": "Ha fallat la validació: {{message}}",
"resetSuccess": "Restableix als valors predeterminats globals",
"resetError": "No s'ha pogut restablir la configuració",
"saveAllSuccess_one": "S'ha desat la secció {{count}} correctament.",
"saveAllSuccess_many": "Totes les {{count}} seccions s'han desat correctament.",
"saveAllSuccess_other": "Totes les {{count}} seccions s'han desat correctament.",
"saveAllPartial_one": "{{successCount}} de la secció {{totalCount}} desada. {{failCount}} ha fallat.",
"saveAllPartial_many": "{{successCount}} de {{totalCount}} seccions desades. {{failCount}} ha fallat.",
"saveAllPartial_other": "{{successCount}} de {{totalCount}} seccions desades. {{failCount}} ha fallat.",
"saveAllFailure": "Ha fallat en desar totes les seccions."
},
"unsavedChanges": "Teniu canvis sense desar",
"confirmReset": "Confirma el restabliment",
"resetToDefaultDescription": "Això restablirà tots els paràmetres d'aquesta secció als seus valors predeterminats. Aquesta acció no es pot desfer.",
"resetToGlobalDescription": "Això restablirà la configuració d'aquesta secció als valors predeterminats globals. Aquesta acció no es pot desfer."
}

View File

@ -80,8 +80,10 @@
"intelGpuWarning": {
"title": "Avís d'estadístiques de la GPU d'Intel",
"message": "Estadístiques de GPU no disponibles",
"description": "Aquest és un error conegut en les eines d'informació de les estadístiques de GPU d'Intel (intel.gpu.top) on es trencarà i retornarà repetidament un ús de GPU del 0% fins i tot en els casos en què l'acceleració del maquinari i la detecció d'objectes s'executen correctament a la (i)GPU. Això no és un error de fragata. Podeu reiniciar l'amfitrió per a corregir temporalment el problema i confirmar que la GPU funciona correctament. Això no afecta el rendiment."
}
"description": "Aquest és un error conegut en les eines d'informació de les estadístiques de GPU d'Intel (intel.gpu.top) on es trencarà i retornarà repetidament un ús de GPU del 0% fins i tot en els casos en què l'acceleració del maquinari i la detecció d'objectes s'executen correctament a la (i)GPU. Això no és un error de Frigate. Podeu reiniciar l'amfitrió per a corregir temporalment el problema i confirmar que la GPU funciona correctament. Això no afecta el rendiment."
},
"gpuTemperature": "Temperatura de la GPU",
"npuTemperature": "Temperatura NPU"
},
"otherProcesses": {
"title": "Altres processos",
@ -165,6 +167,17 @@
"error": {
"unableToProbeCamera": "No s'ha pogut sondejar la càmera: {{errorMessage}}"
}
},
"connectionQuality": {
"title": "Qualitat de la connexió",
"excellent": "Excel·lent",
"fair": "Fira",
"poor": "Pobre",
"unusable": "No utilitzable",
"fps": "FPS",
"expectedFps": "FPS esperat",
"reconnectsLastHour": "Reconnecta (última hora)",
"stallsLastHour": "Parades (última hora)"
}
},
"lastRefreshed": "Darrera actualització: ",

View File

@ -133,7 +133,7 @@
},
"unit": {
"speed": {
"kph": "Km/h",
"kph": "km/h",
"mph": "míle/h"
},
"length": {
@ -177,7 +177,7 @@
"fi": "Suomi (Finština)",
"sk": "Slovenčina (Slovenština)",
"withSystem": {
"label": "Použít systémové nastavení pro jazyk"
"label": "Použít systémové nastavení jazyka"
},
"zhCN": "简体中文 (Zjednodušená čínština)",
"es": "Español (Španělština)",
@ -205,14 +205,15 @@
"pl": "Polski (Polština)",
"th": "ไทย (Thaiština)",
"ca": "Català (Katalánština)",
"sl": "Slovinština (Slovinsko)",
"ptBR": "Português brasileiro (Brazilian Portuguese)",
"sr": "Српски (Serbian)",
"lt": "Lietuvių (Lithuanian)",
"bg": "Български (Bulgarian)",
"gl": "Galego (Galician)",
"id": "Bahasa Indonesia (Indonesian)",
"ur": "اردو (Urdu)"
"sl": "Slovinština (Slovinština)",
"ptBR": "Português brasileiro (Brazilská Portugalština)",
"sr": "Српски (Srbština)",
"lt": "Lietuvių (Litevština)",
"bg": "Български (Bulharština)",
"gl": "Galego (Galicijština)",
"id": "Bahasa Indonesia (Indonéština)",
"ur": "اردو (Urdština)",
"hr": "Hrvatski (Chorvatština)"
},
"theme": {
"highcontrast": "Vysoký kontrast",

View File

@ -117,6 +117,7 @@
"button": {
"add": "Add",
"apply": "Apply",
"applying": "Applying…",
"reset": "Reset",
"undo": "Undo",
"done": "Done",
@ -252,6 +253,7 @@
"review": "Review",
"explore": "Explore",
"export": "Export",
"actions": "Actions",
"uiPlayground": "UI Playground",
"faceLibrary": "Face Library",
"classification": "Classification",

View File

@ -216,6 +216,10 @@
},
"hideObjectDetails": {
"label": "Hide object path"
},
"debugReplay": {
"label": "Debug replay",
"aria": "View this tracked object in the debug replay view"
}
},
"dialog": {

View File

@ -0,0 +1,54 @@
{
"title": "Debug Replay",
"description": "Replay camera recordings for debugging. The object list shows a time-delayed summary of detected objects and the Messages tab shows a stream of Frigate's internal messages from the replay footage.",
"websocket_messages": "Messages",
"dialog": {
"title": "Start Debug Replay",
"description": "Create a temporary replay camera that loops historical footage for debugging object detection and tracking issues. The replay camera will have the same detection configuration as the source camera. Choose a time range to begin.",
"camera": "Source Camera",
"timeRange": "Time Range",
"preset": {
"1m": "Last 1 Minute",
"5m": "Last 5 Minutes",
"timeline": "From Timeline",
"custom": "Custom"
},
"startButton": "Start Replay",
"selectFromTimeline": "Select",
"starting": "Starting replay...",
"startLabel": "Start",
"endLabel": "End",
"toast": {
"success": "Debug replay started successfully",
"error": "Failed to start debug replay: {{error}}",
"alreadyActive": "A replay session is already active",
"stopped": "Debug replay stopped",
"stopError": "Failed to stop debug replay: {{error}}",
"goToReplay": "Go to Replay"
}
},
"page": {
"noSession": "No Active Replay Session",
"noSessionDesc": "Start a debug replay from the History view by clicking the Debug Replay button in the toolbar.",
"goToRecordings": "Go to History",
"sourceCamera": "Source Camera",
"replayCamera": "Replay Camera",
"initializingReplay": "Initializing replay...",
"stoppingReplay": "Stopping replay...",
"stopReplay": "Stop Replay",
"confirmStop": {
"title": "Stop Debug Replay?",
"description": "This will stop the replay session and clean up all temporary data. Are you sure?",
"confirm": "Stop Replay",
"cancel": "Cancel"
},
"activity": "Activity",
"objects": "Object List",
"audioDetections": "Audio Detections",
"noActivity": "No activity detected",
"activeTracking": "Active tracking",
"noActiveTracking": "No active tracking",
"configuration": "Configuration",
"configurationDesc": "Fine tune motion detection and object tracking settings for the debug replay camera. No changes are saved to your Frigate configuration file."
}
}

View File

@ -1392,6 +1392,7 @@
},
"toast": {
"success": "Settings saved successfully",
"applied": "Settings applied successfully",
"successRestartRequired": "Settings saved successfully. Restart Frigate to apply your changes.",
"error": "Failed to save settings",
"validationError": "Validation failed: {{message}}",

View File

@ -7,12 +7,39 @@
"logs": {
"frigate": "Frigate Logs - Frigate",
"go2rtc": "Go2RTC Logs - Frigate",
"nginx": "Nginx Logs - Frigate"
"nginx": "Nginx Logs - Frigate",
"websocket": "Messages Logs - Frigate"
}
},
"title": "System",
"metrics": "System metrics",
"logs": {
"websocket": {
"label": "Messages",
"pause": "Pause",
"resume": "Resume",
"clear": "Clear",
"filter": {
"all": "All topics",
"topics": "Topics",
"events": "Events",
"reviews": "Reviews",
"classification": "Classification",
"face_recognition": "Face Recognition",
"lpr": "LPR",
"camera_activity": "Camera activity",
"system": "System",
"camera": "Camera",
"all_cameras": "All cameras",
"cameras_count_one": "{{count}} Camera",
"cameras_count_other": "{{count}} Cameras"
},
"empty": "No messages captured yet",
"count": "{{count}} messages",
"expanded": {
"payload": "Payload"
}
},
"download": {
"label": "Download Logs"
},
@ -189,7 +216,8 @@
"cameraIsOffline": "{{camera}} is offline",
"detectIsSlow": "{{detect}} is slow ({{speed}} ms)",
"detectIsVerySlow": "{{detect}} is very slow ({{speed}} ms)",
"shmTooLow": "/dev/shm allocation ({{total}} MB) should be increased to at least {{min}} MB."
"shmTooLow": "/dev/shm allocation ({{total}} MB) should be increased to at least {{min}} MB.",
"debugReplayActive": "Debug replay session is active"
},
"enrichments": {
"title": "Enrichments",

View File

@ -178,7 +178,8 @@
"export": "Ekspordi",
"uiPlayground": "Leht kasutajaliidese katsetamiseks",
"faceLibrary": "Näoteek",
"classification": "Klassifikatsioon"
"classification": "Klassifikatsioon",
"chat": "Vestlus"
},
"unit": {
"speed": {
@ -234,7 +235,17 @@
"export": "Ekspordi",
"deleteNow": "Kustuta kohe",
"next": "Järgmine",
"continue": "Jätka"
"continue": "Jätka",
"add": "Lisa",
"undo": "Võta tegevus tagasi",
"copiedToClipboard": "Kopeeritud lõikelauale",
"modified": "Muudetud",
"overridden": "Sürjutatud",
"resetToDefault": "Lähtesta vaikimisi väärtusteks",
"saveAll": "Salvesta kõik",
"resetToGlobal": "Lähtesta üldiseks väärtusteks",
"savingAll": "Salvestan kõiki…",
"undoAll": "Pööra kõik tegevused tagasi"
},
"label": {
"back": "Mine tagasi",

View File

@ -75,7 +75,8 @@
},
"inProgress": "در حال انجام",
"invalidStartTime": "زمان شروع نامعتبر است",
"invalidEndTime": "زمان پایان نامعتبر است"
"invalidEndTime": "زمان پایان نامعتبر است",
"never": "هرگز"
},
"unit": {
"length": {

View File

@ -129,7 +129,17 @@
"deleteNow": "Supprimer maintenant",
"download": "Télécharger",
"done": "Terminé",
"continue": "Continuer"
"continue": "Continuer",
"add": "Ajouter",
"undo": "Annuler",
"copiedToClipboard": "Copié dans le presse-papiers",
"modified": "Modifié",
"overridden": "Surpassé",
"resetToGlobal": "Réinitialiser aux réglages globaux",
"resetToDefault": "Réinitialiser aux réglages par défaut",
"saveAll": "Tout enregistrer",
"savingAll": "Enregistrement de tout en cours…",
"undoAll": "Tout annuler"
},
"menu": {
"configuration": "Configuration",

View File

@ -77,6 +77,10 @@
"fromTimeline": {
"saveExport": "Enregistrer l'exportation",
"previewExport": "Aperçu de l'exportation"
},
"case": {
"label": "Dossier",
"placeholder": "Sélectionner un dossier"
}
},
"search": {

View File

@ -0,0 +1,320 @@
{
"name": {
"label": "Nom de la caméra",
"description": "Le nom de la caméra est requis"
},
"friendly_name": {
"label": "Nom convivial",
"description": "Nom convivial de la caméra utilisé dans l'IU Frigate"
},
"enabled": {
"label": "Activé",
"description": "Activé"
},
"audio": {
"label": "Événements audio",
"description": "Réglages pour la détection des événements audio de cette caméra.",
"enabled": {
"label": "Activer la détection audio",
"description": "Activer ou désactiver la détection des événements audio pour cette caméra."
},
"max_not_heard": {
"description": "Nombre de secondes sans le type audio configuré avant que l'événement audio se termine.",
"label": "Délai d'inactivité"
},
"min_volume": {
"label": "Volume minimal",
"description": "Seuil minimal d'activation du volume en moyenne quadratique requis pour exécuter la détection audio. Des valeurs plus faibles augmentent la sensibilité (p. ex. 200 est élevé, 500 est moyen et 1000 est faible)."
},
"listen": {
"label": "Types d'écoute",
"description": "Liste des types d'événements audio à détecter (p. ex. bark, fire_alarm, scream, speech, yell)."
},
"filters": {
"label": "Filtres audio",
"description": "Réglages des filtres par type audio, tels que seuils de confiance utilisé afin de réduire les faux positifs."
},
"enabled_in_config": {
"label": "État audio original",
"description": "Indique si la détection audio était initialement activée dans le fichier de configuration statique."
},
"num_threads": {
"label": "Fils d'exécution pour la détection",
"description": "Nombre de fils d'éxécution à utiliser pour le traitement de la détection audio."
}
},
"audio_transcription": {
"label": "Transcription audio",
"description": "Réglages pour la transcription audio et vocale utilisée pour les événements et les sous-titres en temps réel.",
"enabled": {
"label": "Activer la transcription",
"description": "Activer ou désactiver le déclenchement manuel de la transcription des événements audio."
},
"enabled_in_config": {
"label": "État original de la transcription"
},
"live_enabled": {
"label": "Transcription en temps réel",
"description": "Activer la diffusion de la transcription en temps réel pour le flux sonore dès sa réception."
}
},
"birdseye": {
"label": "À vol d'oiseau",
"description": "Réglages pour la vue composée à vol d'oiseau qui combine plusieurs flux de caméras dans une simple disposition.",
"enabled": {
"label": "Activer la vue à vol d'oiseau",
"description": "Activer ou désactiver la fonctionalité de vue à vol d'oiseau."
},
"mode": {
"label": "Mode de suivi",
"description": "Mode pour l'inclusion des caméras dans la vue à vol d'oiseau: 'objects', 'motion', ou 'continuous'."
},
"order": {
"label": "Emplacement",
"description": "Emplacement numérique contrôlant l'ordre de la caméra dans la disposition en vue à vol d'oiseau."
}
},
"detect": {
"label": "Détection d'objets",
"description": "Réglages pour la détection ou le rôle de détection utilisé pour exécuter la détection des objets et initialiser les traceurs.",
"enabled": {
"label": "Détection activée",
"description": "Activer ou désactiver la détection des objets pour cette caméra. La détection doit être activée pour que le suivi des objets fonctionne."
},
"height": {
"label": "Hauteur de détection",
"description": "Hauteur (en pixels) des images utilisées pour le flux de détection; garder vide pour utiliser la résolution native du flux."
},
"width": {
"label": "Largeur de détection",
"description": "Largeur (en pixels) des images utilisées pour le flux de détection; garder vide pour utiliser la résolution native du flux."
},
"fps": {
"label": "IPS de la détection",
"description": "Nombre cible d'images par seconde à utiliser pour la détection; des valeurs plus faibles réduisent l'utilisation de l'UCT (la valeur recommandée est 5, ne la définir à une valeur supérieure - au maximum 10, uniquement lors du suivi d'objets se déplaçant extrêmement rapidement)."
},
"min_initialized": {
"label": "Minimum d'images d'initialisation",
"description": "Nombre de détections consécutives requises avant de créer un objet suivi. Augmenter pour réduire les initialisations erronées. La valeur par défaut est fps divisé par 2."
},
"max_disappeared": {
"label": "Nombre maximal d'images disparues",
"description": "Nombre d'images sans détection avant qu'un objet suivi est considéré comme étant disparu."
},
"stationary": {
"label": "Configuration des objets stationnaires",
"description": "Réglages pour la détection et la gestion des objets qui restent stationnaires pendant un certain temps.",
"interval": {
"label": "Intervalle stationnaire",
"description": "À quelle fréquence (en images) effectuer une détection pour la confirmation d'un objet stationnaire."
},
"threshold": {
"label": "Seuil d'activation stationnaire",
"description": "Nombre d'images sans changement d'emplacement requis pour marquer un objet en tant que stationnaire."
},
"max_frames": {
"label": "Nombre max. d'images",
"description": "Limite le temps pour lequel les objets stationnaires sont suivis avant d'être supprimés.",
"default": {
"label": "Nombre max. d'images par défaut",
"description": "Nombre maximal d'images pour suivre un objet stationnaire avant d'arrêter."
},
"objects": {
"label": "Nombre max. d'images pour l'objet",
"description": "Remplacement des réglages par défaut par objet pour le nombre maximal d'images requis pour suivre les objets stationnaires."
}
},
"classifier": {
"label": "Activer le classificateur visuel",
"description": "Utiliser un classificateur visuel pour détecter les objets véritablement stationnaires même lorsque les boîtes englobantes tremblent."
}
},
"annotation_offset": {
"label": "Décalage de l'annotation",
"description": "Millisecondes pour le décalage des annotations afin de mieux aligner les boîtes englobantes de la ligne du temps avec les enregistrements; peut être positif ou négatif."
}
},
"face_recognition": {
"label": "Reconnaissance faciale",
"description": "Réglages pour la détection et reconnaissance faciale pour cette caméra.",
"enabled": {
"label": "Activer la reconnaissance faciale",
"description": "Activer ou désactiver la reconnaissance faciale."
},
"min_area": {
"label": "Surface minimale du visage",
"description": "Surface minimale (en pixels) d'une boîte faciale détectée requise pour tenter la reconnaissance."
}
},
"ffmpeg": {
"label": "FFmpeg",
"description": "Réglages de FFmpeg incluant l'emplacement du fichier binaire, les arguments, les options pour hwaccel et les arguments de sortie par rôle.",
"path": {
"label": "Emplacement de FFmpeg",
"description": "Emplacement du fichier binaire de FFmpeg à utiliser ou un alias de version (peut être «5.0» ou «7.0»)."
},
"global_args": {
"label": "Arguments globaux de FFmpeg",
"description": "Arguments globaux transmis aux processus de FFmpeg."
},
"hwaccel_args": {
"label": "Arguments pour l'accélération matérielle",
"description": "Arguments de l'accélération matérielle pour FFmpeg. Les préréglages spécifiques au fournisseur sont recommandés."
},
"input_args": {
"label": "Arguments d'entrée",
"description": "Arguments d'entrée appliqués aux flux d'entrée FFmpeg."
},
"output_args": {
"label": "Arguments de sortie",
"description": "Arguments de sortie par défaut utilisés pour les différents rôles FFmpeg, tels que detect et record.",
"detect": {
"label": "Détecter les arguments de sortie",
"description": "Arguments de sortie par défaut pour les flux du rôle detect."
},
"record": {
"label": "Arguments de sortie pour l'enregistrement",
"description": "Arguments de sortie par défaut pour les flux du rôle record."
}
},
"retry_interval": {
"label": "Temps de réessai FFmpeg",
"description": "Nombre de secondes à attendre avant de tenter de reconnecter un flux de caméra après un échec. La valeur par défaut est 10."
},
"apple_compatibility": {
"label": "Compatibilité avec Apple",
"description": "Activer l'étiquetage HEVC pour une meilleure compatibilité avec les lecteurs Apple lors de l'enregistrement H.265."
},
"gpu": {
"label": "Index de l'UTG",
"description": "Index par défaut de l'UTG utilisé pour l'accélération matérielle si disponible."
},
"inputs": {
"label": "Entrées des caméras",
"description": "Liste des définitions des flux entrants (emplacements et rôles) pour cette caméra.",
"path": {
"label": "Emplacement d'entrée",
"description": "URL ou emplacement du flux d'entrée de la caméra."
},
"roles": {
"label": "Rôles d'entrée",
"description": "Rôles pour ce flux entrant."
},
"global_args": {
"label": "Arguments globaux de FFmpeg",
"description": "Arguments globaux de FFmpeg pour ce flux entrant."
},
"hwaccel_args": {
"label": "Arguments pour l'accélération matérielle",
"description": "Arguments de l'accélération matérielle pour ce flux entrant."
},
"input_args": {
"label": "Arguments d'entrée",
"description": "Arguments d'entrée spéficiques à ce flux."
}
}
},
"live": {
"label": "Lecture en direct",
"description": "Réglages utilisés par l'IU Web afin de contrôler la sélection, la résolution et la qualité des flux en direct.",
"streams": {
"label": "Nom des flux en direct",
"description": "Mappage des noms des flux configurés vers les noms de restream et go2rtc utilisés pour la lecture en direct."
},
"height": {
"label": "Hauteur de la diffusion en direct",
"description": "Hauteur (en pixels) à laquelle afficher le flux en direct jsmpeg dans l'IU Web; doit être inférieure ou égale à la hauteur détectée du flux."
},
"quality": {
"label": "Qualité de la diffusion en direct",
"description": "Qualité de l'encodage pour le flux jsmpeg (1 étant la plus élevée, 31 la plus faible)."
}
},
"lpr": {
"label": "Reconnaissance des plaques d'immatriculation",
"description": "Réglages de la reconnaissance des plaques d'immatriculation incluant les seuils de détection, le formatage et les plaques connues.",
"enabled": {
"label": "Activer la RPI",
"description": "Activer ou désactiver la RPI sur cette caméra."
},
"expire_time": {
"label": "Expiration en secondes",
"description": "Temps en secondes après lequel une plaque non vue expire du système de suivi (seulement pour les caméras dédiées à la RPI)."
},
"min_area": {
"label": "Surface minimale de la plaque",
"description": "Surface minimale de la plaque (en pixels) requise pour tenter la reconnaissance."
},
"enhancement": {
"label": "Niveau de l'enrichissement",
"description": "Niveau de l'enrichissement (de 0 à 10) à appliquer aux recadrages des plaques avant la ROC. Des valeurs plus élevées n'améliorent pas nécessairement les résultats, les niveaux supérieurs à 5 peuvent ne fonctionner qu'avec des plaques la nuit et doivent être utilisés avec prudence."
}
},
"motion": {
"label": "Détection du mouvement",
"description": "Réglages par défaut de la détection de mouvement pour cette caméra.",
"enabled": {
"label": "Activer la détection de mouvement",
"description": "Activer ou désactiver la détection de mouvement pour cette caméra."
},
"threshold": {
"label": "Seuil de détection du mouvement",
"description": "Seuil de différence de pixels utilisé par le détecteur de mouvement; les valeurs plus élevées réduisent la sensibilité (plage de 1 à 255)."
},
"lightning_threshold": {
"label": "Seuil d'éclairage",
"description": "Seuil permettant de détecter et d'ignorer les brusques pointes d'éclairage (plus la valeur est faible, plus la sensibilité est élevée, valeurs comprises entre 0.3 et 1.0)."
},
"improve_contrast": {
"label": "Améliorer le contraste",
"description": "Appliquer les amélioration du contraste aux images avant l'analyse de mouvement afin d'améliorer la détection."
},
"contour_area": {
"label": "Zone de contour",
"description": "Aire de la zone de contour minimale en pixels requise pour qu'un contour de mouvement soit comptabilisé."
},
"delta_alpha": {
"label": "Delta pour alpha",
"description": "Facteur de mélange alpha utilisé dans la différenciation d'images pour le calcul du mouvement."
},
"frame_alpha": {
"label": "Alpha pour l'image",
"description": "Valeur alpha utilisée lors du mélange d'images pour le prétraitement du mouvement."
},
"frame_height": {
"label": "Hauteur de l'image",
"description": "Hauteur en pixels à laquelle mettre à l'échelle les images lors du traitement du mouvement."
},
"mask": {
"label": "Moordonnées du masque",
"description": "Coordonnées ordonnés x et y définissant le polygone du masque de mouvement utilisé pour inclure ou exclure des aires."
},
"mqtt_off_delay": {
"label": "Délai de désactivation de MQTT",
"description": "Nombre de secondes à attendre après le dernier mouvement avant de publier un état « off » MQTT."
},
"enabled_in_config": {
"label": "État original du mouvement",
"description": "Indique si la détection de mouvement a été activée dans la configuration originale statique."
},
"raw_mask": {
"label": "Masque brut"
}
},
"objects": {
"label": "Objets",
"description": "Réglages par défaut pour le suivi des objets incluant les étiquettes à suivre et les filtres par objets.",
"track": {
"label": "Objets à suivre",
"description": "Liste des étiquettes d'objets à suivre pour cette caméra."
},
"filters": {
"label": "Filtres d'objets",
"description": "Filtres appliqués aux objets détectés afin de réduire les faux positifs (aire, rapport, facteur de confiance).",
"min_area": {
"label": "Aire minimal de l'objet"
}
}
},
"label": "ConfigurationCamera"
}

View File

@ -11,13 +11,27 @@
},
"toast": {
"error": {
"renameExportFailed": "Échec du renommage de l'exportation : {{errorMessage}}"
"renameExportFailed": "Échec du renommage de l'exportation : {{errorMessage}}",
"assignCaseFailed": "Échec de la mise à jour de l'affectation au dossier : {{errorMessage}}"
}
},
"tooltip": {
"shareExport": "Partager l'exportation",
"downloadVideo": "Télécharger la vidéo",
"editName": "Modifier le nom",
"deleteExport": "Supprimer l'exportation"
"deleteExport": "Supprimer l'exportation",
"assignToCase": "Ajouter à un dossier"
},
"headings": {
"cases": "Dossiers",
"uncategorizedExports": "Exportations non classées"
},
"caseDialog": {
"title": "Ajouter à un dossier",
"description": "Choisissez un dossier existant ou créez en un nouveau.",
"selectLabel": "Dossier",
"newCaseOption": "Créer un nouveau dossier",
"nameLabel": "Nom du dossier",
"descriptionLabel": "Description"
}
}

View File

@ -5,20 +5,23 @@
"camera": "Paramètres des caméras - Frigate",
"classification": "Paramètres de classification - Frigate",
"motionTuner": "Réglage de la détection de mouvement - Frigate",
"general": "Paramètres de l'interface utilisateur - Frigate",
"general": "Paramètres du profil - Frigate",
"masksAndZones": "Éditeur de masques et de zones - Frigate",
"object": "Débogage - Frigate",
"frigatePlus": "Paramètres Frigate+ - Frigate",
"notifications": "Paramètres de notification - Frigate",
"enrichments": "Paramètres d'enrichissements - Frigate",
"cameraManagement": "Gestion des caméras - Frigate",
"cameraReview": "Paramètres des activités caméra - Frigate"
"cameraReview": "Paramètres des activités caméra - Frigate",
"globalConfig": "Configuration globale - Frigate",
"cameraConfig": "Configuration de la caméra - Frigate",
"maintenance": "Maintenance - Frigate"
},
"menu": {
"ui": "Interface utilisateur",
"classification": "Classification",
"masksAndZones": "Masques / Zones",
"motionTuner": "Réglage de la détection de mouvement",
"motionTuner": "Ajusteur de la détection de mouvement",
"debug": "Débogage",
"cameras": "Paramètres des caméras",
"users": "Utilisateurs",
@ -28,7 +31,62 @@
"triggers": "Déclencheurs",
"roles": "Rôles",
"cameraManagement": "Gestion",
"cameraReview": "Activités"
"cameraReview": "Activités",
"general": "Général",
"globalConfig": "Configuration globale",
"system": "Système",
"integrations": "Intégrations",
"profileSettings": "Paramètres du profil",
"globalDetect": "Détection d'objets",
"globalRecording": "Enregistrement",
"globalSnapshots": "Instantanés",
"globalFfmpeg": "FFmpeg",
"globalMotion": "Détection de mouvement",
"globalObjects": "Objets",
"globalReview": "Activités",
"globalAudioEvents": "Événements audio",
"globalLivePlayback": "Lecture en direct",
"globalTimestampStyle": "Format d'horodatage",
"systemDatabase": "Base de données",
"systemTls": "TLS",
"systemAuthentication": "Authentification",
"systemNetworking": "Réseau",
"systemProxy": "Proxy",
"systemUi": "Interface",
"systemLogging": "Journalisation",
"systemEnvironmentVariables": "Variables d'environnement",
"systemTelemetry": "Télémétrie",
"systemBirdseye": "Birdseye",
"systemFfmpeg": "FFmpeg",
"systemDetectorHardware": "Matériel de détection",
"systemDetectionModel": "Modèle de détection",
"systemMqtt": "MQTT",
"integrationSemanticSearch": "Recherche sémantique",
"integrationGenerativeAi": "IA générative",
"integrationFaceRecognition": "Reconnaissance faciale",
"integrationLpr": "Lecture de plaques d'immatriculation",
"integrationObjectClassification": "Classification d'objets",
"integrationAudioTranscription": "Transcription audio",
"cameraDetect": "Détection d'objets",
"cameraFfmpeg": "FFmpeg",
"cameraRecording": "Enregistrement",
"cameraSnapshots": "Instantanés",
"cameraMotion": "Détection de mouvement",
"cameraObjects": "Objets",
"cameraConfigReview": "Activités",
"cameraAudioEvents": "Évènements audio",
"cameraAudioTranscription": "Transcription audio",
"cameraNotifications": "Notifications",
"cameraLivePlayback": "Lecture en direct",
"cameraBirdseye": "Birdseye",
"cameraFaceRecognition": "Reconnaissance faciale",
"cameraLpr": "Lecture de plaques d'immatriculation",
"cameraMqttConfig": "MQTT",
"cameraOnvif": "ONVIF",
"cameraUi": "Interface de la caméra",
"cameraTimestampStyle": "Style d'horodatage",
"cameraMqtt": "MQTT de la caméra",
"maintenance": "Maintenance"
},
"dialog": {
"unsavedChanges": {
@ -41,7 +99,7 @@
"noCamera": "Aucune caméra"
},
"general": {
"title": "Paramètres de l'interface utilisateur",
"title": "Paramètres du profil",
"liveDashboard": {
"title": "Tableau de bord en direct",
"automaticLiveView": {
@ -723,7 +781,7 @@
"readTheDocumentation": "Lire la documentation",
"reindexNow": {
"label": "Réindexer maintenant",
"desc": "La réindexation va régénérer les embeddings pour tous les objets suivis. Ce processus s'exécute en arrière-plan et peut saturer votre processeur et prendre un temps considérable en fonction du nombre d'objets suivis.",
"desc": "La réindexation va régénérer les ingrations pour tous les objets suivis. Ce processus s'exécute en arrière-plan et peut saturer votre processeur et prendre un temps considérable en fonction du nombre d'objets suivis.",
"confirmTitle": "Confirmer la réindexation",
"confirmButton": "Réindexer",
"success": "La réindexation a démarré avec succès.",
@ -1315,5 +1373,22 @@
"success": "La configuration de la classification des activités a été enregistrée. Redémarrez Frigate pour appliquer les modifications."
}
}
},
"saveAllPreview": {
"title": "Modifications à enregistrer",
"triggerLabel": "Examiner les modifications en attente",
"empty": "Aucune modification en attente",
"scope": {
"label": "Portée",
"global": "Global",
"camera": "Caméra : {{cameraName}}"
},
"field": {
"label": "Champ"
},
"value": {
"label": "Nouvelle valeur",
"reset": "Réinitialiser"
}
}
}

View File

@ -81,7 +81,9 @@
"title": "Avertissement relatif aux statistiques du GPU Intel",
"message": "Statistiques du GPU non disponibles",
"description": "Il s'agit d'un bug connu de l'outil de statistiques GPU d'Intel (intel_gpu_top) : il peut afficher à tort une utilisation de 0 %, même lorsque l'accélération matérielle et la détection d'objets fonctionnent correctement sur l'iGPU. Ce problème ne vient pas de Frigate. Vous pouvez redémarrer l'hôte pour rétablir temporairement l'affichage et confirmer le fonctionnement du GPU. Les performances ne sont pas affectées."
}
},
"gpuTemperature": "Température du GPU",
"npuTemperature": "Température du NPU"
},
"otherProcesses": {
"title": "Autres processus",
@ -165,6 +167,17 @@
"error": {
"unableToProbeCamera": "Impossible d'interroger la caméra : {{errorMessage}}"
}
},
"connectionQuality": {
"title": "Qualité de la connexion",
"excellent": "Excellente",
"fair": "Acceptable",
"poor": "Médiocre",
"unusable": "Inutilisable",
"fps": "IPS",
"expectedFps": "IPS attendues",
"reconnectsLastHour": "Reconnexions (dernière heure)",
"stallsLastHour": "Baisses de qualité (dernière heure)"
}
},
"lastRefreshed": "Dernier rafraichissement : ",

View File

@ -129,7 +129,17 @@
"pictureInPicture": "Immagine nell'immagine",
"twoWayTalk": "Comunicazione bidirezionale",
"cameraAudio": "Audio della telecamera",
"continue": "Continua"
"continue": "Continua",
"add": "Aggiungi",
"undo": "Annulla",
"copiedToClipboard": "Copiato negli appunti",
"modified": "Modificato",
"overridden": "Sovrascritto",
"resetToGlobal": "Ripristina impostazioni globali",
"resetToDefault": "Ripristina impostazioni predefinite",
"saveAll": "Salva tutto",
"savingAll": "Salvataggio di tutto…",
"undoAll": "Annulla tutto"
},
"unit": {
"speed": {
@ -260,7 +270,8 @@
},
"withSystem": "Sistema",
"faceLibrary": "Raccolta volti",
"classification": "Classificazione"
"classification": "Classificazione",
"chat": "Chat"
},
"pagination": {
"next": {

View File

@ -77,6 +77,10 @@
"select": "Seleziona",
"name": {
"placeholder": "Assegna un nome all'esportazione"
},
"case": {
"label": "Caso",
"placeholder": "Seleziona un caso"
}
},
"streaming": {

View File

@ -11,13 +11,27 @@
},
"toast": {
"error": {
"renameExportFailed": "Impossibile rinominare l'esportazione: {{errorMessage}}"
"renameExportFailed": "Impossibile rinominare l'esportazione: {{errorMessage}}",
"assignCaseFailed": "Impossibile aggiornare l'assegnazione del caso: {{errorMessage}}"
}
},
"tooltip": {
"shareExport": "Condividi esportazione",
"downloadVideo": "Scarica video",
"editName": "Modifica nome",
"deleteExport": "Elimina esportazione"
"deleteExport": "Elimina esportazione",
"assignToCase": "Aggiungi al caso"
},
"headings": {
"cases": "Casi",
"uncategorizedExports": "Esportazioni non categorizzate"
},
"caseDialog": {
"title": "Aggiungi al caso",
"description": "Scegli un caso esistente o creane uno nuovo.",
"selectLabel": "Caso",
"newCaseOption": "Crea un nuovo caso",
"nameLabel": "Nome del caso",
"descriptionLabel": "Descrizione"
}
}

View File

@ -70,7 +70,9 @@
"title": "Avviso statistiche GPU Intel",
"message": "Statistiche GPU non disponibili",
"description": "Si tratta di un problema noto negli strumenti di reportistica delle statistiche GPU di Intel (intel_gpu_top), che si interrompe e restituisce ripetutamente un utilizzo della GPU pari a 0% anche nei casi in cui l'accelerazione hardware e il rilevamento degli oggetti funzionano correttamente sulla (i)GPU. Non si tratta di un problema di Frigate. È possibile riavviare il sistema per risolvere temporaneamente il problema e verificare che la GPU funzioni correttamente. Ciò non influisce sulle prestazioni."
}
},
"gpuTemperature": "Temperatura GPU",
"npuTemperature": "Temperatura NPU"
},
"detector": {
"inferenceSpeed": "Velocità inferenza rilevatore",
@ -165,6 +167,17 @@
"error": {
"unableToProbeCamera": "Impossibile analizzare la telecamera: {{errorMessage}}"
}
},
"connectionQuality": {
"title": "Qualità connessione",
"excellent": "Ottima",
"fair": "Discreta",
"poor": "Scarsa",
"unusable": "Inutilizzabile",
"fps": "FPS",
"expectedFps": "FPS previsti",
"reconnectsLastHour": "Riconnessioni (ultima ora)",
"stallsLastHour": "Blocchi (ultima ora)"
}
},
"stats": {

View File

@ -11,7 +11,7 @@
"5minutes": "5분",
"untilRestart": "재시작 될 때까지",
"ago": "{{timeAgo}} 전",
"justNow": "지금 막",
"justNow": "방금",
"today": "오늘",
"yesterday": "어제",
"last7": "최근 7일",
@ -67,7 +67,11 @@
"formattedTimestampFilename": {
"12hour": "MM-dd-yy-h-mm-ss-a",
"24hour": "MM-dd-yy-HH-mm-ss"
}
},
"never": "한 번도 없음",
"inProgress": "진행 중",
"invalidStartTime": "잘못된 시작 시간",
"invalidEndTime": "잘못된 종료 시간"
},
"notFound": {
"title": "404",
@ -96,48 +100,49 @@
"configurationEditor": "설정 편집기",
"languages": "언어",
"language": {
"en": "English (English)",
"es": "Español (Spanish)",
"zhCN": "简体中文 (Simplified Chinese)",
"hi": "हिन्दी (Hindi)",
"fr": "Français (French)",
"ar": "العربية (Arabic)",
"pt": "Português (Portuguese)",
"ptBR": "Português brasileiro (Brazilian Portuguese)",
"ru": "Русский (Russian)",
"de": "Deutsch (German)",
"ja": "日本語 (Japanese)",
"tr": "Türkçe (Turkish)",
"it": "Italiano (Italian)",
"nl": "Nederlands (Dutch)",
"sv": "Svenska (Swedish)",
"cs": "Čeština (Czech)",
"nb": "Norsk Bokmål (Norwegian Bokmål)",
"ko": "한국어 (Korean)",
"vi": "Tiếng Việt (Vietnamese)",
"fa": "فارسی (Persian)",
"pl": "Polski (Polish)",
"uk": "Українська (Ukrainian)",
"he": "עברית (Hebrew)",
"el": "Ελληνικά (Greek)",
"ro": "Română (Romanian)",
"hu": "Magyar (Hungarian)",
"en": "English (영어)",
"es": "Español (스페인어)",
"zhCN": "简体中文 (중국어 간체)",
"hi": "हिन्दी (힌두어)",
"fr": "Français (프랑스어)",
"ar": "العربية (아랍어)",
"pt": "Português (포르투갈어)",
"ptBR": "Português brasileiro (브라질 포르투갈어)",
"ru": "Русский (러시아어)",
"de": "Deutsch (독일어)",
"ja": "日本語 (일본어)",
"tr": "Türkçe (튀르키예어)",
"it": "Italiano (이탈리아어)",
"nl": "Nederlands (네덜란드어)",
"sv": "Svenska (스웨덴어)",
"cs": "Čeština (체코어)",
"nb": "Norsk Bokmål (노르웨이어 보크몰)",
"ko": "한국어",
"vi": "Tiếng Việt (베트남어)",
"fa": "فارسی (페르시아어)",
"pl": "Polski (폴란드어)",
"uk": "Українська (우크라이나어)",
"he": "עברית (히브리어)",
"el": "Ελληνικά (그리스어)",
"ro": "Română (루마니아어)",
"hu": "Magyar (헝가리어)",
"fi": "Suomi (Finnish)",
"da": "Dansk (Danish)",
"sk": "Slovenčina (Slovak)",
"yue": "粵語 (Cantonese)",
"th": "ไทย (Thai)",
"ca": "Català (Catalan)",
"sr": "Српски (Serbian)",
"sl": "Slovenščina (Slovenian)",
"lt": "Lietuvių (Lithuanian)",
"bg": "Български (Bulgarian)",
"gl": "Galego (Galician)",
"id": "Bahasa Indonesia (Indonesian)",
"ur": "اردو (Urdu)",
"da": "Dansk (덴마크어)",
"sk": "Slovenčina (슬로바키아어)",
"yue": "粵語 (광둥어)",
"th": "ไทย (태국어)",
"ca": "Català (카탈로니아어)",
"sr": "Српски (세르비아어)",
"sl": "Slovenščina (슬로베니아어)",
"lt": "Lietuvių (리투아니아어)",
"bg": "Български (불가리아어)",
"gl": "Galego (갈리시아어)",
"id": "Bahasa Indonesia (인도네시아어)",
"ur": "اردو (우르두어)",
"withSystem": {
"label": "시스템 설정 언어 사용"
}
},
"hr": "Hrvatski (크로아티아어)"
},
"appearance": "화면 설정",
"darkMode": {
@ -175,8 +180,10 @@
"review": "다시보기",
"explore": "탐색",
"export": "내보내기",
"uiPlayground": "UI 실험장",
"faceLibrary": "얼굴 라이브러리"
"uiPlayground": "UI 실험실",
"faceLibrary": "얼굴 라이브러리",
"classification": "분류",
"chat": "채팅"
},
"unit": {
"speed": {
@ -191,13 +198,19 @@
"kbps": "kB/s",
"mbps": "MB/s",
"gbps": "GB/s",
"kbph": "kB/hour",
"mbph": "MB/hour",
"gbph": "GB/hour"
"kbph": "kB/시간",
"mbph": "MB/시간",
"gbph": "GB/시간"
}
},
"label": {
"back": "뒤로"
"back": "뒤로",
"hide": "{{item}} 숨기기",
"show": "{{item}} 표시",
"ID": "아이디",
"none": "없음",
"all": "전체",
"other": "그 외"
},
"button": {
"apply": "적용",
@ -216,7 +229,7 @@
"history": "히스토리",
"fullscreen": "전체화면",
"exitFullscreen": "전체화면 나가기",
"pictureInPicture": "Picture in Picture",
"pictureInPicture": "화면 속 화면",
"twoWayTalk": "양방향 말하기",
"cameraAudio": "카메라 오디오",
"on": "켜기",
@ -234,7 +247,18 @@
"unselect": "선택 해제",
"export": "내보내기",
"deleteNow": "바로 삭제하기",
"next": "다음"
"next": "다음",
"add": "추가",
"undo": "실행 취소",
"copiedToClipboard": "클립보드에 복사",
"continue": "계속하기",
"modified": "수정됨",
"overridden": "재정의됨",
"resetToGlobal": "글로벌 설정으로 재설정",
"resetToDefault": "기본값으로 재설정",
"saveAll": "모두 저장",
"savingAll": "모두 저장 중. …",
"undoAll": "모두 실행 취소"
},
"toast": {
"copyUrlToClipboard": "클립보드에 URL이 복사되었습니다.",
@ -267,5 +291,14 @@
"selectItem": "{{item}} 선택",
"information": {
"pixels": "{{area}}px"
},
"list": {
"two": "{{0}}과 {{1}}",
"many": "{{items}} 그리고 {{last}}",
"separatorWithSpace": ", "
},
"field": {
"optional": "선택",
"internalID": "Frigate 내부 ID는 구성 및 데이터베이스에서 사용됩니다"
}
}

View File

@ -6,7 +6,8 @@
"title": "Frigate이 재시작 중입니다",
"content": "이 페이지는 {{countdown}} 뒤에 새로 고침 됩니다.",
"button": "강제 재시작"
}
},
"description": "이 작업은 Frigate가 재시작 되는 동안 잠시 작동이 중지됩니다."
},
"explore": {
"plus": {
@ -15,7 +16,13 @@
},
"review": {
"question": {
"label": "Frigate +에 이 레이블 등록하기"
"label": "Frigate +에 이 레이블 등록하기",
"ask_a": "이 것은 <code>{{label}}</code> 인가요?",
"ask_an": "이 것은 <code>{{label}}</code> 인가요?",
"ask_full": "이 것은 <code>{{untranslatedLabel}}</code> ({{translatedLabel}}) 인가요?"
},
"state": {
"submitted": "제출됨"
}
}
},
@ -26,7 +33,7 @@
"export": {
"time": {
"fromTimeline": "타임라인에서 선택하기",
"lastHour_other": "지난 시간",
"lastHour_other": "지난 {{count}} 시간­",
"custom": "커스텀",
"start": {
"title": "시작 시간",
@ -44,12 +51,13 @@
"export": "내보내기",
"selectOrExport": "선택 또는 내보내기",
"toast": {
"success": "내보내기가 성공적으로 시작되었습니다. /exports 폴더에서 파일을 보실 수 있습니다.",
"success": "내보내기가 성공적으로 시작되었습니다. 내보내기 페이지에서 파일을 보실 수 있습니다.",
"error": {
"failed": "내보내기 시작 실패:{{error}}",
"endTimeMustAfterStartTime": "종료 시간은 시작 시간보다 뒤에 있어야합니다",
"noVaildTimeSelected": "유효한 시간 범위가 선택되지 않았습니다"
}
},
"view": "보기"
},
"fromTimeline": {
"saveExport": "내보내기 저장",
@ -86,7 +94,19 @@
},
"recording": {
"confirmDelete": {
"title": "삭제 확인"
"title": "삭제 확인",
"desc": {
"selected": "이 리뷰 항목과 관련된 모든 녹화된 영상을 삭제하시겠습니까?<br /><br />다음에 이 팝업을 건너뛰려면 <em>Shift</em> 키를 누르고 삭제하세요."
},
"toast": {
"success": "선택한 리뷰 항목과 관련된 동영상 파일이 성공적으로 삭제되었습니다.",
"error": "삭제 실패: {{error}}"
}
},
"button": {
"export": "내보내기",
"markAsReviewed": "검토 완료로 표시",
"markAsUnreviewed": "검토 안 함 표시"
}
}
}

View File

@ -6,7 +6,8 @@
"title": "Frigate Persikrauna",
"content": "Šis puslapis persikraus už {{countdown}} sekundžių.",
"button": "Priverstinai Perkrauti Dabar"
}
},
"description": "Frigate laikinai sustabdoma, iki kol programa persikraus."
},
"explore": {
"plus": {

View File

@ -11,13 +11,27 @@
},
"toast": {
"error": {
"renameExportFailed": "Nepavyko pervadinti eksportuojamo įrašo: {{errorMessage}}"
"renameExportFailed": "Nepavyko pervadinti eksportuojamo įrašo: {{errorMessage}}",
"assignCaseFailed": "Nepavyko atnaujinti atvėjo užduoties: {{errorMessage}}"
}
},
"tooltip": {
"shareExport": "Pasidalinti įrašu",
"downloadVideo": "Atsisiųsti video",
"editName": "Koreguoti pavadinimą",
"deleteExport": "Ištrinti eksportus"
"deleteExport": "Ištrinti eksportus",
"assignToCase": "Pridėti prie atvėjo"
},
"headings": {
"cases": "Atvėjai",
"uncategorizedExports": "Nekategorizuoti eksportai"
},
"caseDialog": {
"title": "Pridėti prie atvėjo",
"selectLabel": "Atvėjis",
"newCaseOption": "Sukurti naują atvėjį",
"descriptionLabel": "Aprašymas",
"nameLabel": "Atvėjo pavadinimas",
"description": "Pasirinkite jau egzisutojantį atvėjį arba sukurkite naują."
}
}

View File

@ -2,7 +2,8 @@
"description": {
"addFace": "Pridėkite naują kolekciją į Veidų Kolekciją įkeldami savo pirmą nuotrauką.",
"placeholder": "Įveskite pavadinimą šiai kolekcijai",
"invalidName": "Netinkamas vardas. Vardas gali būti sudarytas tik iš raidžiū, skaičių, tarpų, apostrofų, pabraukimų ar brūkšnelių."
"invalidName": "Netinkamas vardas. Vardas gali būti sudarytas tik iš raidžiū, skaičių, tarpų, apostrofų, pabraukimų ar brūkšnelių.",
"nameCannotContainHash": "Pavadinime negali būti #."
},
"details": {
"person": "Žmogus",

View File

@ -4,21 +4,23 @@
"authentication": "Autentifikavimo Nustatymai - Frigate",
"camera": "Kameros Nustatymai - Frigate",
"object": "Debug - Frigate",
"general": "Vizualiniai Nustatymai - Frigate",
"general": "Išvaizdos Parametrai - Frigate",
"frigatePlus": "Frigate+ Nustatymai - Frigate",
"notifications": "Pranešimų Nustatymai - Frigate",
"motionTuner": "Judesio Derinimas - Frigate",
"enrichments": "Patobulinimų Nustatymai - Frigate",
"masksAndZones": "Maskavimo ir Zonų redaktorius - Frigate",
"cameraManagement": "Valdyti Kameras - Frigate",
"cameraReview": "Kameros Peržiūros Nustatymai - Frigate"
"cameraReview": "Kameros Peržiūros Nustatymai - Frigate",
"globalConfig": "Visuotiniai Parametrai — Frigate",
"cameraConfig": "Kameros Parametrai — Frigate"
},
"menu": {
"ui": "UI",
"enrichments": "Patobulinimai",
"cameras": "Kameros Nustatymai",
"masksAndZones": "Maskavimai / Zonos",
"motionTuner": "Judesio Derintojas",
"motionTuner": "Judesio Derinimas",
"debug": "Debug",
"users": "Vartotojai",
"notifications": "Pranešimai",
@ -345,7 +347,7 @@
}
},
"motionMaskLabel": "Judesio Maskuotė {{number}}",
"objectMaskLabel": "Obejkto Maskuotė {{number}} {{label}}",
"objectMaskLabel": "Obejkto Maskuotė {{number}}",
"form": {
"zoneName": {
"error": {
@ -440,7 +442,7 @@
"desc": "Rodyti apribojančius stačiakampius aplink sekamus objektus",
"colors": {
"label": "Objektus Apribojančių Stačiakampių Spalvos",
"info": "<li>Pradžioje, skirtingos spalvos bus priskirtos kiekvienai objekto etiketei</li><li>Tamsiai mėlyna plona linija simbolizuoja, kad objektas esamu momentu dar nėra aptiktas</li><li>Pilka linija nurodo kad objektas yra aptiktas kaip nejudantis</li><li> Stora linija nurodo kad objektas yra automatiškai sekamas (kai įjungta)</li>"
"info": "<li>Pradžioje, skirtingos spalvos bus priskirtos kiekvienai objekto etiketei</li><li>Tamsiai mėlyna plona linija simbolizuoja, kad objektas esamu momentu dar nėra aptiktas</li><li>Pilka linija nurodo kad objektas yra aptiktas kaip nejudantis</li><li>Stora linija nurodo kad objektas yra automatiškai sekamas (kai įjungta)</li>"
}
},
"timestamp": {

View File

@ -74,7 +74,11 @@
"previewExport": "Export vooraf bekijken"
},
"export": "Exporteren",
"selectOrExport": "Selecteren of exporteren"
"selectOrExport": "Selecteren of exporteren",
"case": {
"label": "Dossier",
"placeholder": "Selecteer een dossier"
}
},
"streaming": {
"label": "Stream",

View File

@ -3,7 +3,8 @@
"search": "Zoek",
"toast": {
"error": {
"renameExportFailed": "Het is niet gelukt om de export te hernoemen: {{errorMessage}}"
"renameExportFailed": "Het is niet gelukt om de export te hernoemen: {{errorMessage}}",
"assignCaseFailed": "Kan toewijzing aan dossier niet bijwerken: {{errorMessage}}"
}
},
"editExport": {
@ -18,6 +19,19 @@
"shareExport": "Deel export",
"downloadVideo": "Download video",
"editName": "Naam bewerken",
"deleteExport": "Verwijder export"
"deleteExport": "Verwijder export",
"assignToCase": "Toevoegen aan dossier"
},
"headings": {
"cases": "Gevallen",
"uncategorizedExports": "Ongecategoriseerde exporten"
},
"caseDialog": {
"title": "Toevoegen aan dossier",
"description": "Kies een bestaand dossier of maak een nieuw dossier aan.",
"selectLabel": "Dossier",
"newCaseOption": "Nieuw dossier aanmaken",
"nameLabel": "Dossiernaam",
"descriptionLabel": "Beschrijving"
}
}

View File

@ -7,12 +7,15 @@
"classification": "Classificatie-instellingen - Frigate",
"masksAndZones": "Masker- en zone-editor - Frigate",
"object": "Foutopsporing Frigate",
"general": "Gebruikersinterface-instellingen - Frigate",
"general": "Profielinstellingen - Frigate",
"frigatePlus": "Frigate+ Instellingen - Frigate",
"notifications": "Meldingsinstellingen - Frigate",
"enrichments": "Verrijkingsinstellingen - Frigate",
"cameraManagement": "Camera's beheren - Frigate",
"cameraReview": "Camera Review Instellingen - Frigate"
"cameraReview": "Camera Review Instellingen - Frigate",
"globalConfig": "Globale configuratie - Frigate",
"cameraConfig": "Camera-instellingen - Frigate",
"maintenance": "Onderhoud - Frigate"
},
"menu": {
"ui": "Gebruikersinterface",
@ -28,7 +31,25 @@
"triggers": "Triggers",
"roles": "Rollen",
"cameraManagement": "Beheer",
"cameraReview": "Beoordeel"
"cameraReview": "Beoordeel",
"general": "Algemeen",
"globalConfig": "Globale configuratie",
"system": "Systeem",
"integrations": "Integraties",
"profileSettings": "Profielinstellingen",
"globalDetect": "Objectdetectie",
"globalRecording": "Opname",
"globalSnapshots": "Snapshots",
"globalFfmpeg": "FFmpeg",
"globalMotion": "Bewegingsdetectie",
"globalObjects": "Objecten",
"globalReview": "Beoordelen",
"globalAudioEvents": "Geluidsgebeurtenissen",
"globalLivePlayback": "Live afspelen",
"globalTimestampStyle": "Tijdstempelstijl",
"systemDatabase": "Database",
"systemTls": "TLS",
"systemAuthentication": "Authenticatie"
},
"dialog": {
"unsavedChanges": {

View File

@ -80,7 +80,8 @@
"title": "Waarschuwing Intel GPU-statistieken",
"message": "GPU-statistieken niet beschikbaar",
"description": "Dit is een bekend probleem in de GPU-statistiekentools van Intel (intel_gpu_top). Deze raken defect en geven herhaaldelijk een GPU-gebruik van 0% weer, zelfs wanneer hardware-acceleratie en objectdetectie correct draaien op de (i)GPU. Dit is geen bug in Frigate. Je kunt de host opnieuw opstarten om het tijdelijk op te lossen en te controleren dat de GPU goed werkt. Dit heeft geen invloed op de prestaties."
}
},
"gpuTemperature": "GPU Temperatuur"
},
"otherProcesses": {
"processMemoryUsage": "Process Geheugen Gebruik",

View File

@ -1 +0,0 @@
{}

View File

@ -1 +0,0 @@
{}

View File

@ -1 +0,0 @@
{}

Some files were not shown because too many files have changed in this diff Show More