Compare commits

...

52 Commits

Author SHA1 Message Date
Weblate (bot)
eb762f70ce
Merge 3f12a082dd into 34cc1208a6 2026-03-06 00:28:50 +00:00
Hosted Weblate
3f12a082dd
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-06 01:21:07 +01:00
Hosted Weblate
6193399c60
Added translation using Weblate (Cantonese (Traditional Han script))
Update translation files

Updated by "Squash Git commits" add-on in Weblate.

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

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

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/common/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-cameras/yue_Hant/
Translation: Frigate NVR/Config - Cameras
Translation: Frigate NVR/common
2026-03-06 01:21:05 +01:00
Hosted Weblate
6273f8c689
Added translation using Weblate (Norwegian Bokmål)
Update translation files

Updated by "Squash Git commits" add-on in Weblate.

Added translation using Weblate (Norwegian Bokmål)

Added translation using Weblate (Norwegian Bokmål)

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>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/common/
Translation: Frigate NVR/common
2026-03-06 01:21:03 +01:00
Hosted Weblate
6df3a7cedb
Added translation using Weblate (Chinese (Simplified Han script))
Update translation files

Updated by "Squash Git commits" add-on in Weblate.

Added translation using Weblate (Chinese (Simplified Han script))

Added translation using Weblate (Chinese (Simplified Han script))

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>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/common/
Translation: Frigate NVR/common
2026-03-06 01:21:02 +01:00
Hosted Weblate
e902a32696
Added translation using Weblate (Chinese (Traditional Han script))
Update translation files

Updated by "Squash Git commits" add-on in Weblate.

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

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

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>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/common/
Translation: Frigate NVR/common
2026-03-06 01:21:01 +01:00
Hosted Weblate
623471178f
Added translation using Weblate (Uzbek)
Update translation files

Updated by "Squash Git commits" add-on in Weblate.

Added translation using Weblate (Uzbek)

Added translation using Weblate (Uzbek)

Added translation using Weblate (Uzbek)

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/
Translation: Frigate NVR/common
2026-03-06 01:21:01 +01:00
Hosted Weblate
d15f35f94f
Added translation using Weblate (Urdu)
Update translation files

Updated by "Squash Git commits" add-on in Weblate.

Added translation using Weblate (Urdu)

Added translation using Weblate (Urdu)

Added translation using Weblate (Urdu)

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/
Translation: Frigate NVR/common
2026-03-06 01:21:00 +01:00
Hosted Weblate
fd6d175fea
Added translation using Weblate (Slovenian)
Update translation files

Updated by "Squash Git commits" add-on in Weblate.

Added translation using Weblate (Slovenian)

Added translation using Weblate (Slovenian)

Added translation using Weblate (Slovenian)

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/
Translation: Frigate NVR/common
2026-03-06 01:20:59 +01:00
Hosted Weblate
7d47369b2f
Added translation using Weblate (Slovak)
Update translation files

Updated by "Squash Git commits" add-on in Weblate.

Added translation using Weblate (Slovak)

Added translation using Weblate (Slovak)

Added translation using Weblate (Slovak)

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/
Translation: Frigate NVR/common
2026-03-06 01:20:58 +01:00
Hosted Weblate
88581c5b35
Added translation using Weblate (Korean)
Update translation files

Updated by "Squash Git commits" add-on in Weblate.

Added translation using Weblate (Korean)

Added translation using Weblate (Korean)

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/
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-06 01:20:57 +01:00
Hosted Weblate
8978540d8d
Added translation using Weblate (Serbian)
Update translation files

Updated by "Squash Git commits" add-on in Weblate.

Added translation using Weblate (Serbian)

Added translation using Weblate (Serbian)

Added translation using Weblate (Serbian)

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/
Translation: Frigate NVR/common
2026-03-06 01:20:56 +01:00
Hosted Weblate
b963340322
Added translation using Weblate (Finnish)
Update translation files

Updated by "Squash Git commits" add-on in Weblate.

Added translation using Weblate (Finnish)

Added translation using Weblate (Finnish)

Added translation using Weblate (Finnish)

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/
Translation: Frigate NVR/common
2026-03-06 01:20:55 +01:00
Hosted Weblate
03aa405b88
Added translation using Weblate (Persian)
Update translation files

Updated by "Squash Git commits" add-on in Weblate.

Added translation using Weblate (Persian)

Added translation using Weblate (Persian)

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/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/common/fa/
Translation: Frigate NVR/common
2026-03-06 01:20:54 +01:00
Hosted Weblate
0bd543204c
Added translation using Weblate (Swedish)
Update translation files

Updated by "Squash Git commits" add-on in Weblate.

Added translation using Weblate (Swedish)

Added translation using Weblate (Swedish)

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/
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-06 01:20:53 +01:00
Hosted Weblate
919e14041b
Translated using Weblate (French)
Currently translated at 0.1% (1 of 1082 strings)

Translated using Weblate (French)

Currently translated at 4.0% (1 of 25 strings)

Translated using Weblate (French)

Currently translated at 4.5% (1 of 22 strings)

Added translation using Weblate (French)

Update translation files

Updated by "Squash Git commits" add-on in Weblate.

Added translation using Weblate (French)

Added translation using Weblate (French)

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/
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/config-global/fr/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-groups/fr/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-validation/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/Config - Global
Translation: Frigate NVR/Config - Groups
Translation: Frigate NVR/Config - Validation
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-06 01:20:52 +01:00
Hosted Weblate
b9787e65d6
Translated using Weblate (Spanish)
Currently translated at 83.4% (141 of 169 strings)

Translated using Weblate (Spanish)

Currently translated at 56.0% (14 of 25 strings)

Translated using Weblate (Spanish)

Currently translated at 69.5% (16 of 23 strings)

Translated using Weblate (Spanish)

Currently translated at 73.1% (655 of 896 strings)

Translated using Weblate (Spanish)

Currently translated at 2.8% (13 of 464 strings)

Translated using Weblate (Spanish)

Currently translated at 1.7% (19 of 1082 strings)

Translated using Weblate (Spanish)

Currently translated at 63.6% (14 of 22 strings)

Translated using Weblate (Spanish)

Currently translated at 0.8% (9 of 1082 strings)

Translated using Weblate (Spanish)

Currently translated at 65.2% (15 of 23 strings)

Translated using Weblate (Spanish)

Currently translated at 81.0% (137 of 169 strings)

Translated using Weblate (Spanish)

Currently translated at 28.0% (7 of 25 strings)

Translated using Weblate (Spanish)

Currently translated at 1.0% (5 of 464 strings)

Translated using Weblate (Spanish)

Currently translated at 31.8% (7 of 22 strings)

Added translation using Weblate (Spanish)

Update translation files

Updated by "Squash Git commits" add-on in Weblate.

Added translation using Weblate (Spanish)

Added translation using Weblate (Spanish)

Added translation using Weblate (Spanish)

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Jorge Sandi <jorensanbar+weblate@gmail.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/config-cameras/es/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-global/es/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-groups/es/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-validation/es/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-exports/es/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-settings/es/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-system/es/
Translation: Frigate NVR/Config - Cameras
Translation: Frigate NVR/Config - Global
Translation: Frigate NVR/Config - Groups
Translation: Frigate NVR/Config - Validation
Translation: Frigate NVR/common
Translation: Frigate NVR/views-exports
Translation: Frigate NVR/views-settings
Translation: Frigate NVR/views-system
2026-03-06 01:20:51 +01:00
Hosted Weblate
e4adf3faa9
Translated using Weblate (Dutch)
Currently translated at 13.7% (64 of 464 strings)

Translated using Weblate (Dutch)

Currently translated at 13.5% (63 of 464 strings)

Translated using Weblate (Dutch)

Currently translated at 4.7% (51 of 1082 strings)

Added translation using Weblate (Dutch)

Update translation files

Updated by "Squash Git commits" add-on in Weblate.

Added translation using Weblate (Dutch)

Added translation using Weblate (Dutch)

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>
Co-authored-by: Paul Bröerken <broerken@me.com>
Co-authored-by: marcel vanrooden <marcelvanrooden@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/common/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-dialog/nl/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-cameras/nl/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-global/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/Config - Cameras
Translation: Frigate NVR/Config - Global
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-06 01:20:50 +01:00
Hosted Weblate
52cfac97aa
Added translation using Weblate (Indonesian)
Update translation files

Updated by "Squash Git commits" add-on in Weblate.

Added translation using Weblate (Indonesian)

Added translation using Weblate (Indonesian)

Added translation using Weblate (Indonesian)

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/
Translation: Frigate NVR/common
2026-03-06 01:20:49 +01:00
Hosted Weblate
904fd9a0cc
Added translation using Weblate (Arabic)
Update translation files

Updated by "Squash Git commits" add-on in Weblate.

Added translation using Weblate (Arabic)

Added translation using Weblate (Arabic)

Added translation using Weblate (Arabic)

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/
Translation: Frigate NVR/common
2026-03-06 01:20:48 +01:00
Hosted Weblate
3d238a9c83
Added translation using Weblate (Italian)
Update translation files

Updated by "Squash Git commits" add-on in Weblate.

Added translation using Weblate (Italian)

Added translation using Weblate (Italian)

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/
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-06 01:20:47 +01:00
Hosted Weblate
c10cfc1861
Added translation using Weblate (Polish)
Update translation files

Updated by "Squash Git commits" add-on in Weblate.

Added translation using Weblate (Polish)

Added translation using Weblate (Polish)

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/common/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-cameras/pl/
Translation: Frigate NVR/Config - Cameras
Translation: Frigate NVR/common
2026-03-06 01:20:47 +01:00
Hosted Weblate
a9058f7d1d
Added translation using Weblate (Malayalam)
Update translation files

Updated by "Squash Git commits" add-on in Weblate.

Added translation using Weblate (Malayalam)

Added translation using Weblate (Malayalam)

Added translation using Weblate (Malayalam)

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/
Translation: Frigate NVR/common
2026-03-06 01:20:46 +01:00
Hosted Weblate
2d73e2ef06
Added translation using Weblate (Hebrew)
Update translation files

Updated by "Squash Git commits" add-on in Weblate.

Added translation using Weblate (Hebrew)

Added translation using Weblate (Hebrew)

Added translation using Weblate (Hebrew)

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/
Translation: Frigate NVR/common
2026-03-06 01:20:45 +01:00
Hosted Weblate
0bf45f0208
Added translation using Weblate (Hindi)
Update translation files

Updated by "Squash Git commits" add-on in Weblate.

Added translation using Weblate (Hindi)

Added translation using Weblate (Hindi)

Added translation using Weblate (Hindi)

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/
Translation: Frigate NVR/common
2026-03-06 01:20:44 +01:00
Hosted Weblate
cacacb8be6
Added translation using Weblate (Hungarian)
Update translation files

Updated by "Squash Git commits" add-on in Weblate.

Added translation using Weblate (Hungarian)

Added translation using Weblate (Hungarian)

Added translation using Weblate (Hungarian)

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/
Translation: Frigate NVR/common
2026-03-06 01:20:43 +01:00
Hosted Weblate
bc58277243
Added translation using Weblate (Croatian)
Update translation files

Updated by "Squash Git commits" add-on in Weblate.

Added translation using Weblate (Croatian)

Added translation using Weblate (Croatian)

Added translation using Weblate (Croatian)

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/
Translation: Frigate NVR/common
2026-03-06 01:20:42 +01:00
Hosted Weblate
0202b219c2
Added translation using Weblate (Icelandic)
Update translation files

Updated by "Squash Git commits" add-on in Weblate.

Added translation using Weblate (Icelandic)

Added translation using Weblate (Icelandic)

Added translation using Weblate (Icelandic)

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/
Translation: Frigate NVR/common
2026-03-06 01:20:41 +01:00
Hosted Weblate
79de297622
Added translation using Weblate (Vietnamese)
Update translation files

Updated by "Squash Git commits" add-on in Weblate.

Added translation using Weblate (Vietnamese)

Added translation using Weblate (Vietnamese)

Added translation using Weblate (Vietnamese)

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/
Translation: Frigate NVR/common
2026-03-06 01:20:40 +01:00
Hosted Weblate
39c9472899
Added translation using Weblate (Portuguese)
Update translation files

Updated by "Squash Git commits" add-on in Weblate.

Added translation using Weblate (Portuguese)

Added translation using Weblate (Portuguese)

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/common/
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/common
Translation: Frigate NVR/components-dialog
Translation: Frigate NVR/views-classificationmodel
Translation: Frigate NVR/views-exports
Translation: Frigate NVR/views-facelibrary
2026-03-06 01:20:39 +01:00
Hosted Weblate
6f1338d528
Added translation using Weblate (Czech)
Update translation files

Updated by "Squash Git commits" add-on in Weblate.

Added translation using Weblate (Czech)

Added translation using Weblate (Czech)

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/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/common/cs/
Translation: Frigate NVR/common
2026-03-06 01:20:38 +01:00
Hosted Weblate
474af69a7a
Translated using Weblate (Catalan)
Currently translated at 100.0% (464 of 464 strings)

Translated using Weblate (Catalan)

Currently translated at 100.0% (1082 of 1082 strings)

Translated using Weblate (Catalan)

Currently translated at 100.0% (1082 of 1082 strings)

Translated using Weblate (Catalan)

Currently translated at 100.0% (464 of 464 strings)

Translated using Weblate (Catalan)

Currently translated at 100.0% (1082 of 1082 strings)

Translated using Weblate (Catalan)

Currently translated at 100.0% (464 of 464 strings)

Translated using Weblate (Catalan)

Currently translated at 90.6% (981 of 1082 strings)

Translated using Weblate (Catalan)

Currently translated at 46.3% (502 of 1082 strings)

Translated using Weblate (Catalan)

Currently translated at 100.0% (230 of 230 strings)

Translated using Weblate (Catalan)

Currently translated at 100.0% (169 of 169 strings)

Translated using Weblate (Catalan)

Currently translated at 100.0% (25 of 25 strings)

Translated using Weblate (Catalan)

Currently translated at 100.0% (138 of 138 strings)

Translated using Weblate (Catalan)

Currently translated at 100.0% (22 of 22 strings)

Translated using Weblate (Catalan)

Currently translated at 100.0% (896 of 896 strings)

Translated using Weblate (Catalan)

Currently translated at 20.6% (223 of 1082 strings)

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/config-global/ca/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-groups/ca/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-validation/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/Config - Global
Translation: Frigate NVR/Config - Groups
Translation: Frigate NVR/Config - Validation
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-06 01:20:37 +01:00
Hosted Weblate
3ecdd9a391
Added translation using Weblate (Japanese)
Update translation files

Updated by "Squash Git commits" add-on in Weblate.

Added translation using Weblate (Japanese)

Added translation using Weblate (Japanese)

Added translation using Weblate (Japanese)

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/
Translation: Frigate NVR/common
2026-03-06 01:20:35 +01:00
Hosted Weblate
dc69d3c036
Added translation using Weblate (Ukrainian)
Update translation files

Updated by "Squash Git commits" add-on in Weblate.

Added translation using Weblate (Ukrainian)

Added translation using Weblate (Ukrainian)

Added translation using Weblate (Ukrainian)

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/
Translation: Frigate NVR/common
2026-03-06 01:20:34 +01:00
Hosted Weblate
a9794767c6
Added translation using Weblate (Bulgarian)
Update translation files

Updated by "Squash Git commits" add-on in Weblate.

Added translation using Weblate (Bulgarian)

Added translation using Weblate (Bulgarian)

Added translation using Weblate (Bulgarian)

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/
Translation: Frigate NVR/common
2026-03-06 01:20:33 +01:00
Hosted Weblate
759bc2f487
Translated using Weblate (Romanian)
Currently translated at 100.0% (22 of 22 strings)

Translated using Weblate (Romanian)

Currently translated at 100.0% (896 of 896 strings)

Translated using Weblate (Romanian)

Currently translated at 100.0% (25 of 25 strings)

Translated using Weblate (Romanian)

Currently translated at 100.0% (464 of 464 strings)

Translated using Weblate (Romanian)

Currently translated at 100.0% (138 of 138 strings)

Translated using Weblate (Romanian)

Currently translated at 100.0% (1082 of 1082 strings)

Translated using Weblate (Romanian)

Currently translated at 100.0% (230 of 230 strings)

Translated using Weblate (Romanian)

Currently translated at 100.0% (169 of 169 strings)

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/config-cameras/ro/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-global/ro/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-groups/ro/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-validation/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/Config - Cameras
Translation: Frigate NVR/Config - Global
Translation: Frigate NVR/Config - Groups
Translation: Frigate NVR/Config - Validation
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-06 01:20:33 +01:00
Hosted Weblate
aaf8d62486
Added translation using Weblate (Russian)
Update translation files

Updated by "Squash Git commits" add-on in Weblate.

Added translation using Weblate (Russian)

Added translation using Weblate (Russian)

Added translation using Weblate (Russian)

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/
Translation: Frigate NVR/common
2026-03-06 01:20:31 +01:00
Hosted Weblate
49ace018ab
Added translation using Weblate (Estonian)
Update translation files

Updated by "Squash Git commits" add-on in Weblate.

Translated using Weblate (Estonian)

Currently translated at 100.0% (230 of 230 strings)

Translated using Weblate (Estonian)

Currently translated at 100.0% (58 of 58 strings)

Translated using Weblate (Estonian)

Currently translated at 29.6% (16 of 54 strings)

Translated using Weblate (Estonian)

Currently translated at 21.4% (192 of 896 strings)

Translated using Weblate (Estonian)

Currently translated at 100.0% (23 of 23 strings)

Translated using Weblate (Estonian)

Currently translated at 85.7% (84 of 98 strings)

Added translation using Weblate (Estonian)

Added translation using Weblate (Estonian)

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/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/common/et/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-dialog/et/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-exports/et/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-facelibrary/et/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-live/et/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-settings/et/
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-06 01:20:30 +01:00
Hosted Weblate
46ba340123
Added translation using Weblate (Greek)
Update translation files

Updated by "Squash Git commits" add-on in Weblate.

Added translation using Weblate (Greek)

Added translation using Weblate (Greek)

Added translation using Weblate (Greek)

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/
Translation: Frigate NVR/common
2026-03-06 01:20:29 +01:00
Hosted Weblate
9e6a240fde
Update translation files
Updated by "Squash Git commits" add-on in Weblate.

Added translation using Weblate (Danish)

Added translation using Weblate (Danish)

Added translation using Weblate (Danish)

Added translation using Weblate (Danish)

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/
Translation: Frigate NVR/common
2026-03-06 01:20:29 +01:00
Hosted Weblate
31a1777bd2
Translated using Weblate (German)
Currently translated at 99.1% (228 of 230 strings)

Translated using Weblate (German)

Currently translated at 100.0% (22 of 22 strings)

Translated using Weblate (German)

Currently translated at 73.1% (655 of 896 strings)

Translated using Weblate (German)

Currently translated at 32.0% (8 of 25 strings)

Translated using Weblate (German)

Currently translated at 3.0% (14 of 464 strings)

Translated using Weblate (German)

Currently translated at 65.2% (15 of 23 strings)

Translated using Weblate (German)

Currently translated at 1.1% (12 of 1082 strings)

Translated using Weblate (German)

Currently translated at 0.6% (3 of 464 strings)

Translated using Weblate (German)

Currently translated at 0.2% (3 of 1082 strings)

Translated using Weblate (German)

Currently translated at 12.0% (3 of 25 strings)

Translated using Weblate (German)

Currently translated at 4.5% (1 of 22 strings)

Update translation files

Updated by "Squash Git commits" add-on in Weblate.

Added translation using Weblate (German)

Added translation using Weblate (German)

Added translation using Weblate (German)

Added translation using Weblate (German)

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Languages add-on <noreply-addon-languages@weblate.org>
Co-authored-by: maz <matthi.hrbek@outlook.com>
Co-authored-by: redrekort <redrekort.wold@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/common/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/common/de/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-cameras/de/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-global/de/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-groups/de/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-validation/de/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-exports/de/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-settings/de/
Translation: Frigate NVR/Config - Cameras
Translation: Frigate NVR/Config - Global
Translation: Frigate NVR/Config - Groups
Translation: Frigate NVR/Config - Validation
Translation: Frigate NVR/common
Translation: Frigate NVR/views-exports
Translation: Frigate NVR/views-settings
2026-03-06 01:20:28 +01:00
Hosted Weblate
446f1ce07d
Update translation files
Updated by "Squash Git commits" add-on in Weblate.

Added translation using Weblate (Portuguese (Brazil))

Added translation using Weblate (Portuguese (Brazil))

Added translation using Weblate (Portuguese (Brazil))

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/
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-06 01:20:27 +01:00
Hosted Weblate
a0cbf3b370
Update translation files
Updated by "Squash Git commits" add-on in Weblate.

Added translation using Weblate (Thai)

Added translation using Weblate (Thai)

Added translation using Weblate (Thai)

Added translation using Weblate (Thai)

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/
Translation: Frigate NVR/common
2026-03-06 01:20:24 +01:00
Hosted Weblate
d66822be84
Update translation files
Updated by "Squash Git commits" add-on in Weblate.

Added translation using Weblate (Lithuanian)

Added translation using Weblate (Lithuanian)

Added translation using Weblate (Lithuanian)

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/common/
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/common
Translation: Frigate NVR/components-dialog
Translation: Frigate NVR/views-exports
Translation: Frigate NVR/views-facelibrary
Translation: Frigate NVR/views-settings
2026-03-06 01:20:23 +01:00
Hosted Weblate
cfdc6dc95c
Update translation files
Updated by "Squash Git commits" add-on in Weblate.

Added translation using Weblate (Latvian)

Added translation using Weblate (Latvian)

Added translation using Weblate (Latvian)

Added translation using Weblate (Latvian)

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/
Translation: Frigate NVR/common
2026-03-06 01:20:22 +01:00
Hosted Weblate
75130ef634
Update translation files
Updated by "Squash Git commits" add-on in Weblate.

Added translation using Weblate (Turkish)

Added translation using Weblate (Turkish)

Added translation using Weblate (Turkish)

Added translation using Weblate (Turkish)

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/
Translation: Frigate NVR/common
2026-03-06 01:20:21 +01:00
Hosted Weblate
01d4dc8bd0
Update translation files
Updated by "Squash Git commits" add-on in Weblate.

Added translation using Weblate (Galician)

Added translation using Weblate (Galician)

Added translation using Weblate (Galician)

Added translation using Weblate (Galician)

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/
Translation: Frigate NVR/common
2026-03-06 01:20:21 +01:00
Josh Hawkins
34cc1208a6
Skip motion threshold configuration (#22255)
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
* backend

* frontend

* i18n

* docs

* add test

* clean up

* clean up motion detection docs

* formatting

* make optional
2026-03-05 18:20:03 -06:00
Josh Hawkins
2babfd2ec9
Improve motion review and add motion search (#22253)
* implement motion search and motion previews

* tweaks

* fix merge issue

* fix copilot instructions
2026-03-05 17:53:48 -06:00
Josh Hawkins
229436c94a
Add ability to clear region grids from the frontend (#22277)
* backend

* frontend

* i18n

* tweaks
2026-03-05 16:19:30 -07:00
Josh Hawkins
02678f4a09
show log when anonymous users log in (#22254)
based on a cache key built from remote_addr and user agent, expires after 7 days by default
2026-03-05 16:17:41 -07:00
Josh Hawkins
65db9b0aec
Fixes (#22280)
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
* fix ollama chat tool calling

handle dict arguments, streaming fallback, and message format

* pin setuptools<81 to ensure pkg_resources remains available

When ensure_torch_dependencies() installs torch/torchvision via pip, it can upgrade setuptools to >=81.0.0, which removed the pkg_resources module. rknn-toolkit2 depends on pkg_resources internally, so subsequent RKNN conversion fails with No module named 'pkg_resources'.
2026-03-05 14:11:32 -06:00
290 changed files with 16045 additions and 1130 deletions

View File

@ -38,7 +38,6 @@ Remember that motion detection is just used to determine when object detection s
The threshold value dictates how much of a change in a pixels luminance is required to be considered motion.
```yaml
# default threshold value
motion:
# Optional: The threshold passed to cv2.threshold to determine if a pixel is different enough to be counted as motion. (default: shown below)
# Increasing this value will make motion detection less sensitive and decreasing it will make motion detection more sensitive.
@ -53,7 +52,6 @@ Watching the motion boxes in the debug view, increase the threshold until you on
### Contour Area
```yaml
# default contour_area value
motion:
# Optional: Minimum size in pixels in the resized motion image that counts as motion (default: shown below)
# Increasing this value will prevent smaller areas of motion from being detected. Decreasing will
@ -81,27 +79,49 @@ However, if the preferred day settings do not work well at night it is recommend
## Tuning For Large Changes In Motion
### Lightning Threshold
```yaml
# default lightning_threshold:
motion:
# Optional: The percentage of the image used to detect lightning or other substantial changes where motion detection
# needs to recalibrate. (default: shown below)
# Increasing this value will make motion detection more likely to consider lightning or ir mode changes as valid motion.
# Decreasing this value will make motion detection more likely to ignore large amounts of motion such as a person approaching
# a doorbell camera.
# Optional: The percentage of the image used to detect lightning or
# other substantial changes where motion detection needs to
# recalibrate. (default: shown below)
# Increasing this value will make motion detection more likely
# to consider lightning or IR mode changes as valid motion.
# Decreasing this value will make motion detection more likely
# to ignore large amounts of motion such as a person
# approaching a doorbell camera.
lightning_threshold: 0.8
```
Large changes in motion like PTZ moves and camera switches between Color and IR mode should result in a pause in object detection. `lightning_threshold` defines the percentage of the image used to detect these substantial changes. Increasing this value makes motion detection more likely to treat large changes (like IR mode switches) as valid motion. Decreasing it makes motion detection more likely to ignore large amounts of motion, such as a person approaching a doorbell camera.
Note that `lightning_threshold` does **not** stop motion-based recordings from being saved — it only prevents additional motion analysis after the threshold is exceeded, reducing false positive object detections during high-motion periods (e.g. storms or PTZ sweeps) without interfering with recordings.
:::warning
Some cameras like doorbell cameras may have missed detections when someone walks directly in front of the camera and the lightning_threshold causes motion detection to be re-calibrated. In this case, it may be desirable to increase the `lightning_threshold` to ensure these objects are not missed.
Some cameras, like doorbell cameras, may have missed detections when someone walks directly in front of the camera and the `lightning_threshold` causes motion detection to recalibrate. In this case, it may be desirable to increase the `lightning_threshold` to ensure these objects are not missed.
:::
:::note
### Skip Motion On Large Scene Changes
Lightning threshold does not stop motion based recordings from being saved.
```yaml
motion:
# Optional: Fraction of the frame that must change in a single update
# before Frigate will completely ignore any motion in that frame.
# Values range between 0.0 and 1.0, leave unset (null) to disable.
# Setting this to 0.7 would cause Frigate to **skip** reporting
# motion boxes when more than 70% of the image appears to change
# (e.g. during lightning storms, IR/color mode switches, or other
# sudden lighting events).
skip_motion_threshold: 0.7
```
This option is handy when you want to prevent large transient changes from triggering recordings or object detection. It differs from `lightning_threshold` because it completely suppresses motion instead of just forcing a recalibration.
:::warning
When the skip threshold is exceeded, **no motion is reported** for that frame, meaning **nothing is recorded** for that frame. That means you can miss something important, like a PTZ camera auto-tracking an object or activity while the camera is moving. If you prefer to guarantee that every frame is saved, leave this unset and accept occasional recordings containing scene noise — they typically only take up a few megabytes and are quick to scan in the timeline UI.
:::
Large changes in motion like PTZ moves and camera switches between Color and IR mode should result in a pause in object detection. This is done via the `lightning_threshold` configuration. It is defined as the percentage of the image used to detect lightning or other substantial changes where motion detection needs to recalibrate. Increasing this value will make motion detection more likely to consider lightning or IR mode changes as valid motion. Decreasing this value will make motion detection more likely to ignore large amounts of motion such as a person approaching a doorbell camera.

View File

@ -480,12 +480,16 @@ motion:
# Increasing this value will make motion detection less sensitive and decreasing it will make motion detection more sensitive.
# The value should be between 1 and 255.
threshold: 30
# Optional: The percentage of the image used to detect lightning or other substantial changes where motion detection
# needs to recalibrate. (default: shown below)
# Optional: The percentage of the image used to detect lightning or other substantial changes where motion detection needs
# to recalibrate and motion checks stop for that frame. Recordings are unaffected. (default: shown below)
# Increasing this value will make motion detection more likely to consider lightning or ir mode changes as valid motion.
# Decreasing this value will make motion detection more likely to ignore large amounts of motion such as a person approaching
# a doorbell camera.
# Decreasing this value will make motion detection more likely to ignore large amounts of motion such as a person approaching a doorbell camera.
lightning_threshold: 0.8
# Optional: Fraction of the frame that must change in a single update before motion boxes are completely
# ignored. Values range between 0.0 and 1.0. When exceeded, no motion boxes are reported and **no motion
# recording** is created for that frame. Leave unset (null) to disable this feature. Use with care on PTZ
# cameras or other situations where you require guaranteed frame capture.
skip_motion_threshold: None
# Optional: Minimum size in pixels in the resized motion image that counts as motion (default: shown below)
# Increasing this value will prevent smaller areas of motion from being detected. Decreasing will
# make motion detection more sensitive to smaller moving objects.

View File

@ -32,6 +32,12 @@ from frigate.models import User
logger = logging.getLogger(__name__)
# In-memory cache to track which clients we've logged for an anonymous access event.
# Keyed by a hashed value combining remote address + user-agent. The value is
# an expiration timestamp (float).
FIRST_LOAD_TTL_SECONDS = 60 * 60 * 24 * 7 # 7 days
_first_load_seen: dict[str, float] = {}
def require_admin_by_default():
"""
@ -284,6 +290,15 @@ def get_remote_addr(request: Request):
return remote_addr or "127.0.0.1"
def _cleanup_first_load_seen() -> None:
"""Cleanup expired entries in the in-memory first-load cache."""
now = time.time()
# Build list for removal to avoid mutating dict during iteration
expired = [k for k, exp in _first_load_seen.items() if exp <= now]
for k in expired:
del _first_load_seen[k]
def get_jwt_secret() -> str:
jwt_secret = None
# check env var
@ -744,10 +759,30 @@ def profile(request: Request):
roles_dict = request.app.frigate_config.auth.roles
allowed_cameras = User.get_allowed_cameras(role, roles_dict, all_camera_names)
return JSONResponse(
response = JSONResponse(
content={"username": username, "role": role, "allowed_cameras": allowed_cameras}
)
if username == "anonymous":
try:
remote_addr = get_remote_addr(request)
except Exception:
remote_addr = (
request.client.host if hasattr(request, "client") else "unknown"
)
ua = request.headers.get("user-agent", "")
key_material = f"{remote_addr}|{ua}"
cache_key = hashlib.sha256(key_material.encode()).hexdigest()
_cleanup_first_load_seen()
now = time.time()
if cache_key not in _first_load_seen:
_first_load_seen[cache_key] = now + FIRST_LOAD_TTL_SECONDS
logger.info(f"Anonymous user access from {remote_addr} ua={ua[:200]}")
return response
@router.get(
"/logout",

View File

@ -11,6 +11,7 @@ class Tags(Enum):
classification = "Classification"
logs = "Logs"
media = "Media"
motion_search = "Motion Search"
notifications = "Notifications"
preview = "Preview"
recordings = "Recordings"

View File

@ -22,6 +22,7 @@ from frigate.api import (
event,
export,
media,
motion_search,
notification,
preview,
record,
@ -135,6 +136,7 @@ def create_fastapi_app(
app.include_router(export.router)
app.include_router(event.router)
app.include_router(media.router)
app.include_router(motion_search.router)
app.include_router(record.router)
app.include_router(debug_replay.router)
# App Properties

View File

@ -24,6 +24,7 @@ from tzlocal import get_localzone_name
from frigate.api.auth import (
allow_any_authenticated,
require_camera_access,
require_role,
)
from frigate.api.defs.query.media_query_parameters import (
Extension,
@ -1005,6 +1006,23 @@ def grid_snapshot(
)
@router.delete(
"/{camera_name}/region_grid", dependencies=[Depends(require_role("admin"))]
)
def clear_region_grid(request: Request, camera_name: str):
"""Clear the region grid for a camera."""
if camera_name not in request.app.frigate_config.cameras:
return JSONResponse(
content={"success": False, "message": "Camera not found"},
status_code=404,
)
Regions.delete().where(Regions.camera == camera_name).execute()
return JSONResponse(
content={"success": True, "message": "Region grid cleared"},
)
@router.get(
"/events/{event_id}/snapshot-clean.webp",
dependencies=[Depends(require_camera_access)],

View File

@ -0,0 +1,292 @@
"""Motion search API for detecting changes within a region of interest."""
import logging
from typing import Any, List, Optional
from fastapi import APIRouter, Depends, Request
from fastapi.responses import JSONResponse
from pydantic import BaseModel, Field
from frigate.api.auth import require_camera_access
from frigate.api.defs.tags import Tags
from frigate.jobs.motion_search import (
cancel_motion_search_job,
get_motion_search_job,
start_motion_search_job,
)
from frigate.types import JobStatusTypesEnum
logger = logging.getLogger(__name__)
router = APIRouter(tags=[Tags.motion_search])
class MotionSearchRequest(BaseModel):
"""Request body for motion search."""
start_time: float = Field(description="Start timestamp for the search range")
end_time: float = Field(description="End timestamp for the search range")
polygon_points: List[List[float]] = Field(
description="List of [x, y] normalized coordinates (0-1) defining the ROI polygon"
)
threshold: int = Field(
default=30,
ge=1,
le=255,
description="Pixel difference threshold (1-255)",
)
min_area: float = Field(
default=5.0,
ge=0.1,
le=100.0,
description="Minimum change area as a percentage of the ROI",
)
frame_skip: int = Field(
default=5,
ge=1,
le=30,
description="Process every Nth frame (1=all frames, 5=every 5th frame)",
)
parallel: bool = Field(
default=False,
description="Enable parallel scanning across segments",
)
max_results: int = Field(
default=25,
ge=1,
le=200,
description="Maximum number of search results to return",
)
class MotionSearchResult(BaseModel):
"""A single search result with timestamp and change info."""
timestamp: float = Field(description="Timestamp where change was detected")
change_percentage: float = Field(description="Percentage of ROI area that changed")
class MotionSearchMetricsResponse(BaseModel):
"""Metrics collected during motion search execution."""
segments_scanned: int = 0
segments_processed: int = 0
metadata_inactive_segments: int = 0
heatmap_roi_skip_segments: int = 0
fallback_full_range_segments: int = 0
frames_decoded: int = 0
wall_time_seconds: float = 0.0
segments_with_errors: int = 0
class MotionSearchStartResponse(BaseModel):
"""Response when motion search job starts."""
success: bool
message: str
job_id: str
class MotionSearchStatusResponse(BaseModel):
"""Response containing job status and results."""
success: bool
message: str
status: str # "queued", "running", "success", "failed", or "cancelled"
results: Optional[List[MotionSearchResult]] = None
total_frames_processed: Optional[int] = None
error_message: Optional[str] = None
metrics: Optional[MotionSearchMetricsResponse] = None
@router.post(
"/{camera_name}/search/motion",
response_model=MotionSearchStartResponse,
dependencies=[Depends(require_camera_access)],
summary="Start motion search job",
description="""Starts an asynchronous search for significant motion changes within
a user-defined Region of Interest (ROI) over a specified time range. Returns a job_id
that can be used to poll for results.""",
)
async def start_motion_search(
request: Request,
camera_name: str,
body: MotionSearchRequest,
):
"""Start an async motion search job."""
config = request.app.frigate_config
if camera_name not in config.cameras:
return JSONResponse(
content={"success": False, "message": f"Camera {camera_name} not found"},
status_code=404,
)
# Validate polygon has at least 3 points
if len(body.polygon_points) < 3:
return JSONResponse(
content={
"success": False,
"message": "Polygon must have at least 3 points",
},
status_code=400,
)
# Validate time range
if body.start_time >= body.end_time:
return JSONResponse(
content={
"success": False,
"message": "Start time must be before end time",
},
status_code=400,
)
# Start the job using the jobs module
job_id = start_motion_search_job(
config=config,
camera_name=camera_name,
start_time=body.start_time,
end_time=body.end_time,
polygon_points=body.polygon_points,
threshold=body.threshold,
min_area=body.min_area,
frame_skip=body.frame_skip,
parallel=body.parallel,
max_results=body.max_results,
)
return JSONResponse(
content={
"success": True,
"message": "Search job started",
"job_id": job_id,
}
)
@router.get(
"/{camera_name}/search/motion/{job_id}",
response_model=MotionSearchStatusResponse,
dependencies=[Depends(require_camera_access)],
summary="Get motion search job status",
description="Returns the status and results (if complete) of a motion search job.",
)
async def get_motion_search_status_endpoint(
request: Request,
camera_name: str,
job_id: str,
):
"""Get the status of a motion search job."""
config = request.app.frigate_config
if camera_name not in config.cameras:
return JSONResponse(
content={"success": False, "message": f"Camera {camera_name} not found"},
status_code=404,
)
job = get_motion_search_job(job_id)
if not job:
return JSONResponse(
content={"success": False, "message": "Job not found"},
status_code=404,
)
api_status = job.status
# Build response content
response_content: dict[str, Any] = {
"success": api_status != JobStatusTypesEnum.failed,
"status": api_status,
}
if api_status == JobStatusTypesEnum.failed:
response_content["message"] = job.error_message or "Search failed"
response_content["error_message"] = job.error_message
elif api_status == JobStatusTypesEnum.cancelled:
response_content["message"] = "Search cancelled"
response_content["total_frames_processed"] = job.total_frames_processed
elif api_status == JobStatusTypesEnum.success:
response_content["message"] = "Search complete"
if job.results:
response_content["results"] = job.results.get("results", [])
response_content["total_frames_processed"] = job.results.get(
"total_frames_processed", job.total_frames_processed
)
else:
response_content["results"] = []
response_content["total_frames_processed"] = job.total_frames_processed
else:
response_content["message"] = "Job processing"
response_content["total_frames_processed"] = job.total_frames_processed
# Include partial results if available (streaming)
if job.results:
response_content["results"] = job.results.get("results", [])
response_content["total_frames_processed"] = job.results.get(
"total_frames_processed", job.total_frames_processed
)
# Include metrics if available
if job.metrics:
response_content["metrics"] = job.metrics.to_dict()
return JSONResponse(content=response_content)
@router.post(
"/{camera_name}/search/motion/{job_id}/cancel",
dependencies=[Depends(require_camera_access)],
summary="Cancel motion search job",
description="Cancels an active motion search job if it is still processing.",
)
async def cancel_motion_search_endpoint(
request: Request,
camera_name: str,
job_id: str,
):
"""Cancel an active motion search job."""
config = request.app.frigate_config
if camera_name not in config.cameras:
return JSONResponse(
content={"success": False, "message": f"Camera {camera_name} not found"},
status_code=404,
)
job = get_motion_search_job(job_id)
if not job:
return JSONResponse(
content={"success": False, "message": "Job not found"},
status_code=404,
)
# Check if already finished
api_status = job.status
if api_status not in (JobStatusTypesEnum.queued, JobStatusTypesEnum.running):
return JSONResponse(
content={
"success": True,
"message": "Job already finished",
"status": api_status,
}
)
# Request cancellation
cancelled = cancel_motion_search_job(job_id)
if cancelled:
return JSONResponse(
content={
"success": True,
"message": "Search cancelled",
"status": "cancelled",
}
)
return JSONResponse(
content={
"success": False,
"message": "Failed to cancel job",
},
status_code=500,
)

View File

@ -261,6 +261,7 @@ async def recordings(
Recordings.segment_size,
Recordings.motion,
Recordings.objects,
Recordings.motion_heatmap,
Recordings.duration,
)
.where(

View File

@ -51,6 +51,7 @@ from frigate.embeddings import EmbeddingProcess, EmbeddingsContext
from frigate.events.audio import AudioProcessor
from frigate.events.cleanup import EventCleanup
from frigate.events.maintainer import EventProcessor
from frigate.jobs.motion_search import stop_all_motion_search_jobs
from frigate.log import _stop_logging
from frigate.models import (
Event,
@ -599,6 +600,9 @@ class FrigateApp:
# used by the docker healthcheck
Path("/dev/shm/.frigate-is-stopping").touch()
# Cancel any running motion search jobs before setting stop_event
stop_all_motion_search_jobs()
self.stop_event.set()
# set an end_time on entries without an end_time before exiting

View File

@ -24,10 +24,17 @@ class MotionConfig(FrigateBaseModel):
lightning_threshold: float = Field(
default=0.8,
title="Lightning threshold",
description="Threshold to detect and ignore brief lighting spikes (lower is more sensitive, values between 0.3 and 1.0).",
description="Threshold to detect and ignore brief lighting spikes (lower is more sensitive, values between 0.3 and 1.0). This does not prevent motion detection entirely; it merely causes the detector to stop analyzing additional frames once the threshold is exceeded. Motion-based recordings are still created during these events.",
ge=0.3,
le=1.0,
)
skip_motion_threshold: Optional[float] = Field(
default=None,
title="Skip motion threshold",
description="If set to a value between 0.0 and 1.0, and more than this fraction of the image changes in a single frame, the detector will return no motion boxes and immediately recalibrate. This can save CPU and reduce false positives during lightning, storms, etc., but may miss real events such as a PTZ camera autotracking an object. The tradeoff is between dropping a few megabytes of recordings versus reviewing a couple short clips. Leave unset (None) to disable this feature.",
ge=0.0,
le=1.0,
)
improve_contrast: bool = Field(
default=True,
title="Improve contrast",

View File

@ -1,5 +1,6 @@
"""Ollama Provider for Frigate AI."""
import json
import logging
from typing import Any, Optional
@ -108,7 +109,22 @@ class OllamaClient(GenAIClient):
if msg.get("name"):
msg_dict["name"] = msg["name"]
if msg.get("tool_calls"):
msg_dict["tool_calls"] = msg["tool_calls"]
# Ollama requires tool call arguments as dicts, but the
# conversation format (OpenAI-style) stores them as JSON
# strings. Convert back to dicts for Ollama.
ollama_tool_calls = []
for tc in msg["tool_calls"]:
func = tc.get("function") or {}
args = func.get("arguments") or {}
if isinstance(args, str):
try:
args = json.loads(args)
except (json.JSONDecodeError, TypeError):
args = {}
ollama_tool_calls.append(
{"function": {"name": func.get("name", ""), "arguments": args}}
)
msg_dict["tool_calls"] = ollama_tool_calls
request_messages.append(msg_dict)
request_params: dict[str, Any] = {
@ -120,25 +136,27 @@ class OllamaClient(GenAIClient):
request_params["stream"] = True
if tools:
request_params["tools"] = tools
if tool_choice:
request_params["tool_choice"] = (
"none"
if tool_choice == "none"
else "required"
if tool_choice == "required"
else "auto"
)
return request_params
def _message_from_response(self, response: dict[str, Any]) -> dict[str, Any]:
"""Parse Ollama chat response into {content, tool_calls, finish_reason}."""
if not response or "message" not in response:
logger.debug("Ollama response empty or missing 'message' key")
return {
"content": None,
"tool_calls": None,
"finish_reason": "error",
}
message = response["message"]
logger.debug(
"Ollama response message keys: %s, content_len=%s, thinking_len=%s, "
"tool_calls=%s, done=%s",
list(message.keys()) if hasattr(message, "keys") else "N/A",
len(message.get("content", "") or "") if message.get("content") else 0,
len(message.get("thinking", "") or "") if message.get("thinking") else 0,
bool(message.get("tool_calls")),
response.get("done"),
)
content = message.get("content", "").strip() if message.get("content") else None
tool_calls = parse_tool_calls_from_message(message)
finish_reason = "error"
@ -198,7 +216,13 @@ class OllamaClient(GenAIClient):
tools: Optional[list[dict[str, Any]]] = None,
tool_choice: Optional[str] = "auto",
):
"""Stream chat with tools; yields content deltas then final message."""
"""Stream chat with tools; yields content deltas then final message.
When tools are provided, Ollama streaming does not include tool_calls
in the response chunks. To work around this, we use a non-streaming
call when tools are present to ensure tool calls are captured, then
emit the content as a single delta followed by the final message.
"""
if self.provider is None:
logger.warning(
"Ollama provider has not been initialized. Check your Ollama configuration."
@ -213,6 +237,27 @@ class OllamaClient(GenAIClient):
)
return
try:
# Ollama does not return tool_calls in streaming mode, so fall
# back to a non-streaming call when tools are provided.
if tools:
logger.debug(
"Ollama: tools provided, using non-streaming call for tool support"
)
request_params = self._build_request_params(
messages, tools, tool_choice, stream=False
)
async_client = OllamaAsyncClient(
host=self.genai_config.base_url,
timeout=self.timeout,
)
response = await async_client.chat(**request_params)
result = self._message_from_response(response)
content = result.get("content")
if content:
yield ("content_delta", content)
yield ("message", result)
return
request_params = self._build_request_params(
messages, tools, tool_choice, stream=True
)
@ -233,11 +278,10 @@ class OllamaClient(GenAIClient):
yield ("content_delta", delta)
if chunk.get("done"):
full_content = "".join(content_parts).strip() or None
tool_calls = parse_tool_calls_from_message(msg)
final_message = {
"content": full_content,
"tool_calls": tool_calls,
"finish_reason": "tool_calls" if tool_calls else "stop",
"tool_calls": None,
"finish_reason": "stop",
}
break

View File

@ -23,21 +23,26 @@ def parse_tool_calls_from_message(
if not raw or not isinstance(raw, list):
return None
result = []
for tool_call in raw:
for idx, tool_call in enumerate(raw):
function_data = tool_call.get("function") or {}
try:
arguments_str = function_data.get("arguments") or "{}"
arguments = json.loads(arguments_str)
except (json.JSONDecodeError, KeyError, TypeError) as e:
logger.warning(
"Failed to parse tool call arguments: %s, tool: %s",
e,
function_data.get("name", "unknown"),
)
raw_arguments = function_data.get("arguments") or {}
if isinstance(raw_arguments, dict):
arguments = raw_arguments
elif isinstance(raw_arguments, str):
try:
arguments = json.loads(raw_arguments)
except (json.JSONDecodeError, KeyError, TypeError) as e:
logger.warning(
"Failed to parse tool call arguments: %s, tool: %s",
e,
function_data.get("name", "unknown"),
)
arguments = {}
else:
arguments = {}
result.append(
{
"id": tool_call.get("id", ""),
"id": tool_call.get("id", "") or f"call_{idx}",
"name": function_data.get("name", ""),
"arguments": arguments,
}

View File

@ -0,0 +1,864 @@
"""Motion search job management with background execution and parallel verification."""
import logging
import os
import threading
from concurrent.futures import Future, ThreadPoolExecutor, as_completed
from dataclasses import asdict, dataclass, field
from datetime import datetime
from typing import Any, Optional
import cv2
import numpy as np
from frigate.comms.inter_process import InterProcessRequestor
from frigate.config import FrigateConfig
from frigate.const import UPDATE_JOB_STATE
from frigate.jobs.job import Job
from frigate.jobs.manager import (
get_job_by_id,
set_current_job,
)
from frigate.models import Recordings
from frigate.types import JobStatusTypesEnum
logger = logging.getLogger(__name__)
# Constants
HEATMAP_GRID_SIZE = 16
@dataclass
class MotionSearchMetrics:
"""Metrics collected during motion search execution."""
segments_scanned: int = 0
segments_processed: int = 0
metadata_inactive_segments: int = 0
heatmap_roi_skip_segments: int = 0
fallback_full_range_segments: int = 0
frames_decoded: int = 0
wall_time_seconds: float = 0.0
segments_with_errors: int = 0
def to_dict(self) -> dict[str, Any]:
"""Convert to dictionary."""
return asdict(self)
@dataclass
class MotionSearchResult:
"""A single search result with timestamp and change info."""
timestamp: float
change_percentage: float
def to_dict(self) -> dict[str, Any]:
"""Convert to dictionary."""
return asdict(self)
@dataclass
class MotionSearchJob(Job):
"""Job state for motion search operations."""
job_type: str = "motion_search"
camera: str = ""
start_time_range: float = 0.0
end_time_range: float = 0.0
polygon_points: list[list[float]] = field(default_factory=list)
threshold: int = 30
min_area: float = 5.0
frame_skip: int = 5
parallel: bool = False
max_results: int = 25
# Track progress
total_frames_processed: int = 0
# Metrics for observability
metrics: Optional[MotionSearchMetrics] = None
def to_dict(self) -> dict[str, Any]:
"""Convert to dictionary for WebSocket transmission."""
d = asdict(self)
if self.metrics:
d["metrics"] = self.metrics.to_dict()
return d
def create_polygon_mask(
polygon_points: list[list[float]], frame_width: int, frame_height: int
) -> np.ndarray:
"""Create a binary mask from normalized polygon coordinates."""
motion_points = np.array(
[[int(p[0] * frame_width), int(p[1] * frame_height)] for p in polygon_points],
dtype=np.int32,
)
mask = np.zeros((frame_height, frame_width), dtype=np.uint8)
cv2.fillPoly(mask, [motion_points], 255)
return mask
def compute_roi_bbox_normalized(
polygon_points: list[list[float]],
) -> tuple[float, float, float, float]:
"""Compute the bounding box of the ROI in normalized coordinates (0-1).
Returns (x_min, y_min, x_max, y_max) in normalized coordinates.
"""
if not polygon_points:
return (0.0, 0.0, 1.0, 1.0)
x_coords = [p[0] for p in polygon_points]
y_coords = [p[1] for p in polygon_points]
return (min(x_coords), min(y_coords), max(x_coords), max(y_coords))
def heatmap_overlaps_roi(
heatmap: dict[str, int], roi_bbox: tuple[float, float, float, float]
) -> bool:
"""Check if a sparse motion heatmap has any overlap with the ROI bounding box.
Args:
heatmap: Sparse dict mapping cell index (str) to intensity (1-255).
roi_bbox: (x_min, y_min, x_max, y_max) in normalized coordinates (0-1).
Returns:
True if there is overlap (any active cell in the ROI region).
"""
if not isinstance(heatmap, dict):
# Invalid heatmap, assume overlap to be safe
return True
x_min, y_min, x_max, y_max = roi_bbox
# Convert normalized coordinates to grid cells (0-15)
grid_x_min = max(0, int(x_min * HEATMAP_GRID_SIZE))
grid_y_min = max(0, int(y_min * HEATMAP_GRID_SIZE))
grid_x_max = min(HEATMAP_GRID_SIZE - 1, int(x_max * HEATMAP_GRID_SIZE))
grid_y_max = min(HEATMAP_GRID_SIZE - 1, int(y_max * HEATMAP_GRID_SIZE))
# Check each cell in the ROI bbox
for y in range(grid_y_min, grid_y_max + 1):
for x in range(grid_x_min, grid_x_max + 1):
idx = str(y * HEATMAP_GRID_SIZE + x)
if idx in heatmap:
return True
return False
def segment_passes_activity_gate(recording: Recordings) -> bool:
"""Check if a segment passes the activity gate.
Returns True if any of motion, objects, or regions is non-zero/non-null.
Returns True if all are null (old segments without data).
"""
motion = recording.motion
objects = recording.objects
regions = recording.regions
# Old segments without metadata - pass through (conservative)
if motion is None and objects is None and regions is None:
return True
# Pass if any activity indicator is positive
return bool(motion) or bool(objects) or bool(regions)
def segment_passes_heatmap_gate(
recording: Recordings, roi_bbox: tuple[float, float, float, float]
) -> bool:
"""Check if a segment passes the heatmap overlap gate.
Returns True if:
- No heatmap is stored (old segments).
- The heatmap overlaps with the ROI bbox.
"""
heatmap = getattr(recording, "motion_heatmap", None)
if heatmap is None:
# No heatmap stored, fall back to activity gate
return True
return heatmap_overlaps_roi(heatmap, roi_bbox)
class MotionSearchRunner(threading.Thread):
"""Thread-based runner for motion search jobs with parallel verification."""
def __init__(
self,
job: MotionSearchJob,
config: FrigateConfig,
cancel_event: threading.Event,
) -> None:
super().__init__(daemon=True, name=f"motion_search_{job.id}")
self.job = job
self.config = config
self.cancel_event = cancel_event
self.internal_stop_event = threading.Event()
self.requestor = InterProcessRequestor()
self.metrics = MotionSearchMetrics()
self.job.metrics = self.metrics
# Worker cap: min(4, cpu_count)
cpu_count = os.cpu_count() or 1
self.max_workers = min(4, cpu_count)
def run(self) -> None:
"""Execute the motion search job."""
try:
self.job.status = JobStatusTypesEnum.running
self.job.start_time = datetime.now().timestamp()
self._broadcast_status()
results = self._execute_search()
if self.cancel_event.is_set():
self.job.status = JobStatusTypesEnum.cancelled
else:
self.job.status = JobStatusTypesEnum.success
self.job.results = {
"results": [r.to_dict() for r in results],
"total_frames_processed": self.job.total_frames_processed,
}
self.job.end_time = datetime.now().timestamp()
self.metrics.wall_time_seconds = self.job.end_time - self.job.start_time
self.job.metrics = self.metrics
logger.debug(
"Motion search job %s completed: status=%s, results=%d, frames=%d",
self.job.id,
self.job.status,
len(results),
self.job.total_frames_processed,
)
self._broadcast_status()
except Exception as e:
logger.exception("Motion search job %s failed: %s", self.job.id, e)
self.job.status = JobStatusTypesEnum.failed
self.job.error_message = str(e)
self.job.end_time = datetime.now().timestamp()
self.metrics.wall_time_seconds = self.job.end_time - (
self.job.start_time or 0
)
self.job.metrics = self.metrics
self._broadcast_status()
finally:
if self.requestor:
self.requestor.stop()
def _broadcast_status(self) -> None:
"""Broadcast job status update via IPC to WebSocket subscribers."""
if self.job.status == JobStatusTypesEnum.running and self.job.start_time:
self.metrics.wall_time_seconds = (
datetime.now().timestamp() - self.job.start_time
)
try:
self.requestor.send_data(UPDATE_JOB_STATE, self.job.to_dict())
except Exception as e:
logger.warning("Failed to broadcast motion search status: %s", e)
def _should_stop(self) -> bool:
"""Check if processing should stop due to cancellation or internal limits."""
return self.cancel_event.is_set() or self.internal_stop_event.is_set()
def _execute_search(self) -> list[MotionSearchResult]:
"""Main search execution logic."""
camera_name = self.job.camera
camera_config = self.config.cameras.get(camera_name)
if not camera_config:
raise ValueError(f"Camera {camera_name} not found")
frame_width = camera_config.detect.width
frame_height = camera_config.detect.height
# Create polygon mask
polygon_mask = create_polygon_mask(
self.job.polygon_points, frame_width, frame_height
)
if np.count_nonzero(polygon_mask) == 0:
logger.warning("Polygon mask is empty for job %s", self.job.id)
return []
# Compute ROI bbox in normalized coordinates for heatmap gate
roi_bbox = compute_roi_bbox_normalized(self.job.polygon_points)
# Query recordings
recordings = list(
Recordings.select()
.where(
(
Recordings.start_time.between(
self.job.start_time_range, self.job.end_time_range
)
)
| (
Recordings.end_time.between(
self.job.start_time_range, self.job.end_time_range
)
)
| (
(self.job.start_time_range > Recordings.start_time)
& (self.job.end_time_range < Recordings.end_time)
)
)
.where(Recordings.camera == camera_name)
.order_by(Recordings.start_time.asc())
)
if not recordings:
logger.debug("No recordings found for motion search job %s", self.job.id)
return []
logger.debug(
"Motion search job %s: queried %d recording segments for camera %s "
"(range %.1f - %.1f)",
self.job.id,
len(recordings),
camera_name,
self.job.start_time_range,
self.job.end_time_range,
)
self.metrics.segments_scanned = len(recordings)
# Apply activity and heatmap gates
filtered_recordings = []
for recording in recordings:
if not segment_passes_activity_gate(recording):
self.metrics.metadata_inactive_segments += 1
self.metrics.segments_processed += 1
logger.debug(
"Motion search job %s: segment %s skipped by activity gate "
"(motion=%s, objects=%s, regions=%s)",
self.job.id,
recording.id,
recording.motion,
recording.objects,
recording.regions,
)
continue
if not segment_passes_heatmap_gate(recording, roi_bbox):
self.metrics.heatmap_roi_skip_segments += 1
self.metrics.segments_processed += 1
logger.debug(
"Motion search job %s: segment %s skipped by heatmap gate "
"(heatmap present=%s, roi_bbox=%s)",
self.job.id,
recording.id,
recording.motion_heatmap is not None,
roi_bbox,
)
continue
filtered_recordings.append(recording)
self._broadcast_status()
# Fallback: if all segments were filtered out, scan all segments
# This allows motion search to find things the detector missed
if not filtered_recordings and recordings:
logger.info(
"All %d segments filtered by gates, falling back to full scan",
len(recordings),
)
self.metrics.fallback_full_range_segments = len(recordings)
filtered_recordings = recordings
logger.debug(
"Motion search job %s: %d/%d segments passed gates "
"(activity_skipped=%d, heatmap_skipped=%d)",
self.job.id,
len(filtered_recordings),
len(recordings),
self.metrics.metadata_inactive_segments,
self.metrics.heatmap_roi_skip_segments,
)
if self.job.parallel:
return self._search_motion_parallel(filtered_recordings, polygon_mask)
return self._search_motion_sequential(filtered_recordings, polygon_mask)
def _search_motion_parallel(
self,
recordings: list[Recordings],
polygon_mask: np.ndarray,
) -> list[MotionSearchResult]:
"""Search for motion in parallel across segments, streaming results."""
all_results: list[MotionSearchResult] = []
total_frames = 0
next_recording_idx_to_merge = 0
logger.debug(
"Motion search job %s: starting motion search with %d workers "
"across %d segments",
self.job.id,
self.max_workers,
len(recordings),
)
# Initialize partial results on the job so they stream to the frontend
self.job.results = {"results": [], "total_frames_processed": 0}
with ThreadPoolExecutor(max_workers=self.max_workers) as executor:
futures: dict[Future, int] = {}
completed_segments: dict[int, tuple[list[MotionSearchResult], int]] = {}
for idx, recording in enumerate(recordings):
if self._should_stop():
break
future = executor.submit(
self._process_recording_for_motion,
recording.path,
recording.start_time,
recording.end_time,
self.job.start_time_range,
self.job.end_time_range,
polygon_mask,
self.job.threshold,
self.job.min_area,
self.job.frame_skip,
)
futures[future] = idx
for future in as_completed(futures):
if self._should_stop():
# Cancel remaining futures
for f in futures:
f.cancel()
break
recording_idx = futures[future]
recording = recordings[recording_idx]
try:
results, frames = future.result()
self.metrics.segments_processed += 1
completed_segments[recording_idx] = (results, frames)
while next_recording_idx_to_merge in completed_segments:
segment_results, segment_frames = completed_segments.pop(
next_recording_idx_to_merge
)
all_results.extend(segment_results)
total_frames += segment_frames
self.job.total_frames_processed = total_frames
self.metrics.frames_decoded = total_frames
if segment_results:
deduped = self._deduplicate_results(all_results)
self.job.results = {
"results": [
r.to_dict() for r in deduped[: self.job.max_results]
],
"total_frames_processed": total_frames,
}
self._broadcast_status()
if segment_results and len(deduped) >= self.job.max_results:
self.internal_stop_event.set()
for pending_future in futures:
pending_future.cancel()
break
next_recording_idx_to_merge += 1
if self.internal_stop_event.is_set():
break
except Exception as e:
self.metrics.segments_processed += 1
self.metrics.segments_with_errors += 1
self._broadcast_status()
logger.warning(
"Error processing segment %s: %s",
recording.path,
e,
)
self.job.total_frames_processed = total_frames
self.metrics.frames_decoded = total_frames
logger.debug(
"Motion search job %s: motion search complete, "
"found %d raw results, decoded %d frames, %d segment errors",
self.job.id,
len(all_results),
total_frames,
self.metrics.segments_with_errors,
)
# Sort and deduplicate results
all_results.sort(key=lambda x: x.timestamp)
return self._deduplicate_results(all_results)[: self.job.max_results]
def _search_motion_sequential(
self,
recordings: list[Recordings],
polygon_mask: np.ndarray,
) -> list[MotionSearchResult]:
"""Search for motion sequentially across segments, streaming results."""
all_results: list[MotionSearchResult] = []
total_frames = 0
logger.debug(
"Motion search job %s: starting sequential motion search across %d segments",
self.job.id,
len(recordings),
)
self.job.results = {"results": [], "total_frames_processed": 0}
for recording in recordings:
if self.cancel_event.is_set():
break
try:
results, frames = self._process_recording_for_motion(
recording.path,
recording.start_time,
recording.end_time,
self.job.start_time_range,
self.job.end_time_range,
polygon_mask,
self.job.threshold,
self.job.min_area,
self.job.frame_skip,
)
all_results.extend(results)
total_frames += frames
self.job.total_frames_processed = total_frames
self.metrics.frames_decoded = total_frames
self.metrics.segments_processed += 1
if results:
all_results.sort(key=lambda x: x.timestamp)
deduped = self._deduplicate_results(all_results)[
: self.job.max_results
]
self.job.results = {
"results": [r.to_dict() for r in deduped],
"total_frames_processed": total_frames,
}
self._broadcast_status()
if results and len(deduped) >= self.job.max_results:
break
except Exception as e:
self.metrics.segments_processed += 1
self.metrics.segments_with_errors += 1
self._broadcast_status()
logger.warning("Error processing segment %s: %s", recording.path, e)
self.job.total_frames_processed = total_frames
self.metrics.frames_decoded = total_frames
logger.debug(
"Motion search job %s: sequential motion search complete, "
"found %d raw results, decoded %d frames, %d segment errors",
self.job.id,
len(all_results),
total_frames,
self.metrics.segments_with_errors,
)
all_results.sort(key=lambda x: x.timestamp)
return self._deduplicate_results(all_results)[: self.job.max_results]
def _deduplicate_results(
self, results: list[MotionSearchResult], min_gap: float = 1.0
) -> list[MotionSearchResult]:
"""Deduplicate results that are too close together."""
if not results:
return results
deduplicated: list[MotionSearchResult] = []
last_timestamp = 0.0
for result in results:
if result.timestamp - last_timestamp >= min_gap:
deduplicated.append(result)
last_timestamp = result.timestamp
return deduplicated
def _process_recording_for_motion(
self,
recording_path: str,
recording_start: float,
recording_end: float,
search_start: float,
search_end: float,
polygon_mask: np.ndarray,
threshold: int,
min_area: float,
frame_skip: int,
) -> tuple[list[MotionSearchResult], int]:
"""Process a single recording file for motion detection.
This method is designed to be called from a thread pool.
Args:
min_area: Minimum change area as a percentage of the ROI (0-100).
"""
results: list[MotionSearchResult] = []
frames_processed = 0
if not os.path.exists(recording_path):
logger.warning("Recording file not found: %s", recording_path)
return results, frames_processed
cap = cv2.VideoCapture(recording_path)
if not cap.isOpened():
logger.error("Could not open recording: %s", recording_path)
return results, frames_processed
try:
fps = cap.get(cv2.CAP_PROP_FPS) or 30.0
total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
recording_duration = recording_end - recording_start
# Calculate frame range
start_offset = max(0, search_start - recording_start)
end_offset = min(recording_duration, search_end - recording_start)
start_frame = int(start_offset * fps)
end_frame = int(end_offset * fps)
start_frame = max(0, min(start_frame, total_frames - 1))
end_frame = max(0, min(end_frame, total_frames))
if start_frame >= end_frame:
return results, frames_processed
cap.set(cv2.CAP_PROP_POS_FRAMES, start_frame)
# Get ROI bounding box
roi_bbox = cv2.boundingRect(polygon_mask)
roi_x, roi_y, roi_w, roi_h = roi_bbox
prev_frame_gray = None
frame_step = max(frame_skip, 1)
frame_idx = start_frame
while frame_idx < end_frame:
if self._should_stop():
break
ret, frame = cap.read()
if not ret:
frame_idx += 1
continue
if (frame_idx - start_frame) % frame_step != 0:
frame_idx += 1
continue
frames_processed += 1
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
# Handle frame dimension changes
if gray.shape != polygon_mask.shape:
resized_mask = cv2.resize(
polygon_mask, (gray.shape[1], gray.shape[0]), cv2.INTER_NEAREST
)
current_bbox = cv2.boundingRect(resized_mask)
else:
resized_mask = polygon_mask
current_bbox = roi_bbox
roi_x, roi_y, roi_w, roi_h = current_bbox
cropped_gray = gray[roi_y : roi_y + roi_h, roi_x : roi_x + roi_w]
cropped_mask = resized_mask[
roi_y : roi_y + roi_h, roi_x : roi_x + roi_w
]
cropped_mask_area = np.count_nonzero(cropped_mask)
if cropped_mask_area == 0:
frame_idx += 1
continue
# Convert percentage to pixel count for this ROI
min_area_pixels = int((min_area / 100.0) * cropped_mask_area)
masked_gray = cv2.bitwise_and(
cropped_gray, cropped_gray, mask=cropped_mask
)
if prev_frame_gray is not None:
diff = cv2.absdiff(prev_frame_gray, masked_gray)
diff_blurred = cv2.GaussianBlur(diff, (3, 3), 0)
_, thresh = cv2.threshold(
diff_blurred, threshold, 255, cv2.THRESH_BINARY
)
thresh_dilated = cv2.dilate(thresh, None, iterations=1)
thresh_masked = cv2.bitwise_and(
thresh_dilated, thresh_dilated, mask=cropped_mask
)
change_pixels = cv2.countNonZero(thresh_masked)
if change_pixels > min_area_pixels:
contours, _ = cv2.findContours(
thresh_masked, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE
)
total_change_area = sum(
cv2.contourArea(c)
for c in contours
if cv2.contourArea(c) >= min_area_pixels
)
if total_change_area > 0:
frame_time_offset = (frame_idx - start_frame) / fps
timestamp = (
recording_start + start_offset + frame_time_offset
)
change_percentage = (
total_change_area / cropped_mask_area
) * 100
results.append(
MotionSearchResult(
timestamp=timestamp,
change_percentage=round(change_percentage, 2),
)
)
prev_frame_gray = masked_gray
frame_idx += 1
finally:
cap.release()
logger.debug(
"Motion search segment complete: %s, %d frames processed, %d results found",
recording_path,
frames_processed,
len(results),
)
return results, frames_processed
# Module-level state for managing per-camera jobs
_motion_search_jobs: dict[str, tuple[MotionSearchJob, threading.Event]] = {}
_jobs_lock = threading.Lock()
def stop_all_motion_search_jobs() -> None:
"""Cancel all running motion search jobs for clean shutdown."""
with _jobs_lock:
for job_id, (job, cancel_event) in _motion_search_jobs.items():
if job.status in (JobStatusTypesEnum.queued, JobStatusTypesEnum.running):
cancel_event.set()
logger.debug("Signalling motion search job %s to stop", job_id)
def start_motion_search_job(
config: FrigateConfig,
camera_name: str,
start_time: float,
end_time: float,
polygon_points: list[list[float]],
threshold: int = 30,
min_area: float = 5.0,
frame_skip: int = 5,
parallel: bool = False,
max_results: int = 25,
) -> str:
"""Start a new motion search job.
Returns the job ID.
"""
job = MotionSearchJob(
camera=camera_name,
start_time_range=start_time,
end_time_range=end_time,
polygon_points=polygon_points,
threshold=threshold,
min_area=min_area,
frame_skip=frame_skip,
parallel=parallel,
max_results=max_results,
)
cancel_event = threading.Event()
with _jobs_lock:
_motion_search_jobs[job.id] = (job, cancel_event)
set_current_job(job)
runner = MotionSearchRunner(job, config, cancel_event)
runner.start()
logger.debug(
"Started motion search job %s for camera %s: "
"time_range=%.1f-%.1f, threshold=%d, min_area=%.1f%%, "
"frame_skip=%d, parallel=%s, max_results=%d, polygon_points=%d vertices",
job.id,
camera_name,
start_time,
end_time,
threshold,
min_area,
frame_skip,
parallel,
max_results,
len(polygon_points),
)
return job.id
def get_motion_search_job(job_id: str) -> Optional[MotionSearchJob]:
"""Get a motion search job by ID."""
with _jobs_lock:
job_entry = _motion_search_jobs.get(job_id)
if job_entry:
return job_entry[0]
# Check completed jobs via manager
return get_job_by_id("motion_search", job_id)
def cancel_motion_search_job(job_id: str) -> bool:
"""Cancel a motion search job.
Returns True if cancellation was initiated, False if job not found.
"""
with _jobs_lock:
job_entry = _motion_search_jobs.get(job_id)
if not job_entry:
return False
job, cancel_event = job_entry
if job.status not in (JobStatusTypesEnum.queued, JobStatusTypesEnum.running):
# Already finished
return True
cancel_event.set()
job.status = JobStatusTypesEnum.cancelled
job_payload = job.to_dict()
logger.info("Cancelled motion search job %s", job_id)
requestor: Optional[InterProcessRequestor] = None
try:
requestor = InterProcessRequestor()
requestor.send_data(UPDATE_JOB_STATE, job_payload)
except Exception as e:
logger.warning(
"Failed to broadcast cancelled motion search job %s: %s", job_id, e
)
finally:
if requestor:
requestor.stop()
return True

View File

@ -78,6 +78,7 @@ class Recordings(Model):
dBFS = IntegerField(null=True)
segment_size = FloatField(default=0) # this should be stored as MB
regions = IntegerField(null=True)
motion_heatmap = JSONField(null=True) # 16x16 grid, 256 values (0-255)
class ExportCase(Model):

View File

@ -176,11 +176,32 @@ class ImprovedMotionDetector(MotionDetector):
motion_boxes = []
pct_motion = 0
# skip motion entirely if the scene change percentage exceeds configured
# threshold. this is useful to ignore lighting storms, IR mode switches,
# etc. rather than registering them as brief motion and then recalibrating.
# note: skipping means the frame is dropped and **no recording will be
# created**, which could hide a legitimate object if the camera is actively
# autotracking. the alternative is to allow motion and accept a small
# recording that can be reviewed in the timeline. disabled by default (None).
if (
self.config.skip_motion_threshold is not None
and pct_motion > self.config.skip_motion_threshold
):
# force a recalibration so we transition to the new background
self.calibrating = True
return []
# once the motion is less than 5% and the number of contours is < 4, assume its calibrated
if pct_motion < 0.05 and len(motion_boxes) <= 4:
self.calibrating = False
# if calibrating or the motion contours are > 80% of the image area (lightning, ir, ptz) recalibrate
# if calibrating or the motion contours are > 80% of the image area
# (lightning, ir, ptz) recalibrate. the lightning threshold does **not**
# stop motion detection entirely; it simply halts additional processing for
# the current frame once the percentage crosses the threshold. this helps
# reduce false positive object detections and CPU usage during highmotion
# events. recordings continue to be generated because users expect data
# while a PTZ camera is moving.
if self.calibrating or pct_motion > self.config.lightning_threshold:
self.calibrating = True

View File

@ -50,11 +50,13 @@ class SegmentInfo:
active_object_count: int,
region_count: int,
average_dBFS: int,
motion_heatmap: dict[str, int] | None = None,
) -> None:
self.motion_count = motion_count
self.active_object_count = active_object_count
self.region_count = region_count
self.average_dBFS = average_dBFS
self.motion_heatmap = motion_heatmap
def should_discard_segment(self, retain_mode: RetainModeEnum) -> bool:
keep = False
@ -454,6 +456,59 @@ class RecordingMaintainer(threading.Thread):
if end_time < retain_cutoff:
self.drop_segment(cache_path)
def _compute_motion_heatmap(
self, camera: str, motion_boxes: list[tuple[int, int, int, int]]
) -> dict[str, int] | None:
"""Compute a 16x16 motion intensity heatmap from motion boxes.
Returns a sparse dict mapping cell index (as string) to intensity (1-255).
Only cells with motion are included.
Args:
camera: Camera name to get detect dimensions from.
motion_boxes: List of (x1, y1, x2, y2) pixel coordinates.
Returns:
Sparse dict like {"45": 3, "46": 5}, or None if no boxes.
"""
if not motion_boxes:
return None
camera_config = self.config.cameras.get(camera)
if not camera_config:
return None
frame_width = camera_config.detect.width
frame_height = camera_config.detect.height
if frame_width <= 0 or frame_height <= 0:
return None
GRID_SIZE = 16
counts: dict[int, int] = {}
for box in motion_boxes:
if len(box) < 4:
continue
x1, y1, x2, y2 = box
# Convert pixel coordinates to grid cells
grid_x1 = max(0, int((x1 / frame_width) * GRID_SIZE))
grid_y1 = max(0, int((y1 / frame_height) * GRID_SIZE))
grid_x2 = min(GRID_SIZE - 1, int((x2 / frame_width) * GRID_SIZE))
grid_y2 = min(GRID_SIZE - 1, int((y2 / frame_height) * GRID_SIZE))
for y in range(grid_y1, grid_y2 + 1):
for x in range(grid_x1, grid_x2 + 1):
idx = y * GRID_SIZE + x
counts[idx] = min(255, counts.get(idx, 0) + 1)
if not counts:
return None
# Convert to string keys for JSON storage
return {str(k): v for k, v in counts.items()}
def segment_stats(
self, camera: str, start_time: datetime.datetime, end_time: datetime.datetime
) -> SegmentInfo:
@ -461,6 +516,8 @@ class RecordingMaintainer(threading.Thread):
active_count = 0
region_count = 0
motion_count = 0
all_motion_boxes: list[tuple[int, int, int, int]] = []
for frame in self.object_recordings_info[camera]:
# frame is after end time of segment
if frame[0] > end_time.timestamp():
@ -479,6 +536,8 @@ class RecordingMaintainer(threading.Thread):
)
motion_count += len(frame[2])
region_count += len(frame[3])
# Collect motion boxes for heatmap computation
all_motion_boxes.extend(frame[2])
audio_values = []
for frame in self.audio_recordings_info[camera]:
@ -498,8 +557,14 @@ class RecordingMaintainer(threading.Thread):
average_dBFS = 0 if not audio_values else np.average(audio_values)
motion_heatmap = self._compute_motion_heatmap(camera, all_motion_boxes)
return SegmentInfo(
motion_count, active_count, region_count, round(average_dBFS)
motion_count,
active_count,
region_count,
round(average_dBFS),
motion_heatmap,
)
async def move_segment(
@ -590,6 +655,7 @@ class RecordingMaintainer(threading.Thread):
Recordings.regions.name: segment_info.region_count,
Recordings.dBFS.name: segment_info.average_dBFS,
Recordings.segment_size.name: segment_size,
Recordings.motion_heatmap.name: segment_info.motion_heatmap,
}
except Exception as e:
logger.error(f"Unable to store recording segment {cache_path}")

View File

@ -0,0 +1,91 @@
import unittest
import numpy as np
from frigate.config.camera.motion import MotionConfig
from frigate.motion.improved_motion import ImprovedMotionDetector
class TestImprovedMotionDetector(unittest.TestCase):
def setUp(self):
# small frame for testing; actual frames are grayscale
self.frame_shape = (100, 100) # height, width
self.config = MotionConfig()
# motion detector assumes a rasterized_mask attribute exists on config
# when update_mask() is called; add one manually by bypassing pydantic.
object.__setattr__(
self.config,
"rasterized_mask",
np.ones((self.frame_shape[0], self.frame_shape[1]), dtype=np.uint8),
)
# create minimal PTZ metrics stub to satisfy detector checks
class _Stub:
def __init__(self, value=False):
self.value = value
def is_set(self):
return bool(self.value)
class DummyPTZ:
def __init__(self):
self.autotracker_enabled = _Stub(False)
self.motor_stopped = _Stub(False)
self.stop_time = _Stub(0)
self.detector = ImprovedMotionDetector(
self.frame_shape, self.config, fps=30, ptz_metrics=DummyPTZ()
)
# establish a baseline frame (all zeros)
base_frame = np.zeros(
(self.frame_shape[0], self.frame_shape[1]), dtype=np.uint8
)
self.detector.detect(base_frame)
def _half_change_frame(self) -> np.ndarray:
"""Produce a frame where roughly half of the pixels are different."""
frame = np.zeros((self.frame_shape[0], self.frame_shape[1]), dtype=np.uint8)
# flip the top half to white
frame[: self.frame_shape[0] // 2, :] = 255
return frame
def test_skip_motion_threshold_default(self):
"""With the default (None) setting, motion should always be reported."""
frame = self._half_change_frame()
boxes = self.detector.detect(frame)
self.assertTrue(
boxes, "Expected motion boxes when skip threshold is unset (disabled)"
)
def test_skip_motion_threshold_applied(self):
"""Setting a low skip threshold should prevent any boxes from being returned."""
# change the config and update the detector reference
self.config.skip_motion_threshold = 0.4
self.detector.config = self.config
self.detector.update_mask()
frame = self._half_change_frame()
boxes = self.detector.detect(frame)
self.assertEqual(
boxes,
[],
"Motion boxes should be empty when scene change exceeds skip threshold",
)
def test_skip_motion_threshold_does_not_affect_calibration(self):
"""Even when skipping, the detector should go into calibrating state."""
self.config.skip_motion_threshold = 0.4
self.detector.config = self.config
self.detector.update_mask()
frame = self._half_change_frame()
_ = self.detector.detect(frame)
self.assertTrue(
self.detector.calibrating,
"Detector should be in calibrating state after skip event",
)
if __name__ == "__main__":
unittest.main()

View File

@ -110,6 +110,7 @@ def ensure_torch_dependencies() -> bool:
"pip",
"install",
"--break-system-packages",
"setuptools<81",
"torch",
"torchvision",
],

View File

@ -0,0 +1,34 @@
"""Peewee migrations -- 035_add_motion_heatmap.py.
Some examples (model - class or model name)::
> Model = migrator.orm['model_name'] # Return model in current state by name
> migrator.sql(sql) # Run custom SQL
> migrator.python(func, *args, **kwargs) # Run python code
> migrator.create_model(Model) # Create a model (could be used as decorator)
> migrator.remove_model(model, cascade=True) # Remove a model
> migrator.add_fields(model, **fields) # Add fields to a model
> migrator.change_fields(model, **fields) # Change fields
> migrator.remove_fields(model, *field_names, cascade=True)
> migrator.rename_field(model, old_field_name, new_field_name)
> migrator.rename_table(model, new_table_name)
> migrator.add_index(model, *col_names, unique=False)
> migrator.drop_index(model, *col_names)
> migrator.add_not_null(model, *field_names)
> migrator.drop_not_null(model, *field_names)
> migrator.add_default(model, field_name, default)
"""
import peewee as pw
SQL = pw.SQL
def migrate(migrator, database, fake=False, **kwargs):
migrator.sql('ALTER TABLE "recordings" ADD COLUMN "motion_heatmap" TEXT NULL')
def rollback(migrator, database, fake=False, **kwargs):
pass

63
web/package-lock.json generated
View File

@ -22,6 +22,7 @@
"@radix-ui/react-hover-card": "^1.1.6",
"@radix-ui/react-label": "^2.1.2",
"@radix-ui/react-popover": "^1.1.6",
"@radix-ui/react-progress": "^1.1.8",
"@radix-ui/react-radio-group": "^1.2.3",
"@radix-ui/react-scroll-area": "^1.2.3",
"@radix-ui/react-select": "^2.1.6",
@ -2922,6 +2923,68 @@
}
}
},
"node_modules/@radix-ui/react-progress": {
"version": "1.1.8",
"resolved": "https://registry.npmjs.org/@radix-ui/react-progress/-/react-progress-1.1.8.tgz",
"integrity": "sha512-+gISHcSPUJ7ktBy9RnTqbdKW78bcGke3t6taawyZ71pio1JewwGSJizycs7rLhGTvMJYCQB1DBK4KQsxs7U8dA==",
"license": "MIT",
"dependencies": {
"@radix-ui/react-context": "1.1.3",
"@radix-ui/react-primitive": "2.1.4"
},
"peerDependencies": {
"@types/react": "*",
"@types/react-dom": "*",
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
},
"@types/react-dom": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-progress/node_modules/@radix-ui/react-context": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.3.tgz",
"integrity": "sha512-ieIFACdMpYfMEjF0rEf5KLvfVyIkOz6PDGyNnP+u+4xQ6jny3VCgA4OgXOwNx2aUkxn8zx9fiVcM8CfFYv9Lxw==",
"license": "MIT",
"peerDependencies": {
"@types/react": "*",
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-progress/node_modules/@radix-ui/react-primitive": {
"version": "2.1.4",
"resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.4.tgz",
"integrity": "sha512-9hQc4+GNVtJAIEPEqlYqW5RiYdrr8ea5XQ0ZOnD6fgru+83kqT15mq2OCcbe8KnjRZl5vF3ks69AKz3kh1jrhg==",
"license": "MIT",
"dependencies": {
"@radix-ui/react-slot": "1.2.4"
},
"peerDependencies": {
"@types/react": "*",
"@types/react-dom": "*",
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
},
"@types/react-dom": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-radio-group": {
"version": "1.3.8",
"resolved": "https://registry.npmjs.org/@radix-ui/react-radio-group/-/react-radio-group-1.3.8.tgz",

View File

@ -28,6 +28,7 @@
"@radix-ui/react-hover-card": "^1.1.6",
"@radix-ui/react-label": "^2.1.2",
"@radix-ui/react-popover": "^1.1.6",
"@radix-ui/react-progress": "^1.1.8",
"@radix-ui/react-radio-group": "^1.2.3",
"@radix-ui/react-scroll-area": "^1.2.3",
"@radix-ui/react-select": "^2.1.6",

View File

@ -106,7 +106,9 @@
"logout": "Tanca la sessió",
"current": "Usuari actual: {{user}}"
},
"classification": "Classificació"
"classification": "Classificació",
"chat": "Xat",
"actions": "Accions"
},
"pagination": {
"previous": {
@ -268,7 +270,18 @@
"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",
"applying": "S'està aplicant…"
},
"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": "Utilitzeu un classificador visual per detectar objectes realment estacionaris, fins i tot quan les caixes contenidores 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": "Ruta 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 camí 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 la placa de llicència",
"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": "Caduca els segons",
"description": "Temps en segons després del qual una placa no vista expira del rastrejador (només per a càmeres LPR dedicades)."
},
"min_area": {
"label": "Àrea mínima de la placa",
"description": "Àrea mínima de placa (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 marc",
"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 contenidores per als objectes seguits en les instantànies desades."
},
"crop": {
"label": "Retalla la instantània",
"description": "Retalla les instantànies desades a la caixa contenidora 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": "Aeguiment 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 de la pista automàtica 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."
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,73 @@
{
"audio": {
"global": {
"detection": "Detecció global",
"sensitivity": "Sensibilitat global"
},
"cameras": {
"detection": "Detecció",
"sensitivity": "Sensibilitat"
}
},
"timestamp_style": {
"global": {
"appearance": "Aparença global"
},
"cameras": {
"appearance": "Aparença"
}
},
"motion": {
"global": {
"sensitivity": "Sensibilitat global",
"algorithm": "Algorisme global"
},
"cameras": {
"sensitivity": "Sensibilitat",
"algorithm": "Algorisme"
}
},
"snapshots": {
"global": {
"display": "Visualització global"
},
"cameras": {
"display": "Mostra"
}
},
"detect": {
"global": {
"resolution": "Resolució global",
"tracking": "Seguiment global"
},
"cameras": {
"resolution": "Resolució",
"tracking": "Seguiment"
}
},
"objects": {
"global": {
"tracking": "Seguiment global",
"filtering": "Filtratge global"
},
"cameras": {
"tracking": "Seguiment",
"filtering": "Filtra"
}
},
"record": {
"global": {
"retention": "Retenció global",
"events": "Esdeveniments globals"
},
"cameras": {
"retention": "Retenció",
"events": "Esdeveniment"
}
},
"ffmpeg": {
"cameras": {
"cameraFfmpeg": "Arguments específics del FFmpeg"
}
}
}

View File

@ -0,0 +1,32 @@
{
"minimum": "Ha de ser com a mínim {{limit}}",
"maximum": "Ha de ser com a màxim {{limit}}",
"exclusiveMinimum": "Ha de ser més gran que {{limit}}",
"exclusiveMaximum": "Ha de ser inferior a {{limit}}",
"minLength": "Ha de tenir com a mínim {{limit}} caràcters",
"maxLength": "Ha de tenir com a màxim {{limit}} caràcters",
"minItems": "Ha de tenir com a mínim {{limit}} elements",
"maxItems": "Ha de tenir com a màxim {{limit}} elements",
"pattern": "Format no vàlid",
"required": "Aquest camp és obligatori",
"type": "Tipus de valor no vàlid",
"enum": "Ha de ser un dels valors permesos",
"const": "El valor no coincideix amb la constant esperada",
"uniqueItems": "Tots els elements han de ser únics",
"format": "Format no vàlid",
"additionalProperties": "No es permet la propietat desconeguda",
"oneOf": "Ha de coincidir exactament amb un dels esquemes permesos",
"anyOf": "Ha de coincidir almenys amb un dels esquemes permesos",
"proxy": {
"header_map": {
"roleHeaderRequired": "Es requereix la capçalera del rol quan es configuren els mapes de rols."
}
},
"ffmpeg": {
"inputs": {
"rolesUnique": "Cada rol només es pot assignar a un flux d'entrada.",
"detectRequired": "Almenys un flux d'entrada ha de tenir assignat el rol «detecta».",
"hwaccelDetectOnly": "Només el flux d'entrada amb el rol detect pot definir arguments d'acceleració del maquinari."
}
}
}

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

@ -234,6 +234,10 @@
"downloadCleanSnapshot": {
"label": "Descarrega la instantània neta",
"aria": "Descarrega la instantània neta"
},
"debugReplay": {
"label": "Depura la repetició",
"aria": "Mostra aquest objecte rastrejat a la vista de reproducció de depuració"
}
},
"noTrackedObjects": "No s'han trobat objectes rastrejats",
@ -285,7 +289,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,255 @@
}
},
"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": "Enregistrament",
"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.",
"applied": "La configuració s'ha aplicat correctament"
},
"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

@ -6,7 +6,8 @@
"logs": {
"frigate": "Registres de Frigate - Frigate",
"go2rtc": "Registres de Go2RTC - Frigate",
"nginx": "Registres de Nginix - Frigate"
"nginx": "Registres de Nginix - Frigate",
"websocket": "Registres de missatges - Frigate"
},
"enrichments": "Estadístiques complementàries - Frigate"
},
@ -33,6 +34,32 @@
"fetchingLogsFailed": "Error al obtenir els registres: {{errorMessage}}",
"whileStreamingLogs": "Error en la transmissió dels registres: {{errorMessage}}"
}
},
"websocket": {
"label": "Missatges",
"pause": "Pausa",
"resume": "Reprèn",
"clear": "Neteja",
"filter": {
"all": "Tots els temes",
"topics": "Temes",
"events": "Esdeveniment",
"reviews": "Revisions",
"classification": "Classificació",
"face_recognition": "Reconeixement facial",
"lpr": "LPR",
"camera_activity": "Activitat de la càmera",
"system": "Sistema",
"camera": "Càmara",
"all_cameras": "Totes les càmeres",
"cameras_count_one": "{{count}} càmera",
"cameras_count_other": "{{count}} Càmeres"
},
"empty": "Encara no s'ha capturat cap missatge",
"count": "{{count}} missatges",
"expanded": {
"payload": "Payload"
}
}
},
"general": {
@ -80,8 +107,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 +194,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ó: ",
@ -176,7 +216,8 @@
"detectHighCpuUsage": "{{camera}} te un ús elevat de CPU per la detecció ({{detectAvg}}%)",
"detectIsVerySlow": "{{detect}} és molt lent ({{speed}} ms)",
"detectIsSlow": "{{detect}} és lent ({{speed}} ms)",
"shmTooLow": "/dev/shm directori ({{total}} MB) hauria de ser incrementat com a mínim {{min}} MB."
"shmTooLow": "/dev/shm directori ({{total}} MB) hauria de ser incrementat com a mínim {{min}} MB.",
"debugReplayActive": "La sessió de repetició de depuració està activa"
},
"enrichments": {
"title": "Enriquiments",

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

@ -123,7 +123,18 @@
"on": "AN",
"suspended": "Pausierte",
"unsuspended": "fortsetzen",
"continue": "Weiter"
"continue": "Weiter",
"add": "Hinzufügen",
"applying": "Wird angewendet…",
"undo": "Rückgängig",
"copiedToClipboard": "In die Zwischenablage kopiert",
"modified": "Verändert",
"overridden": "Überschrieben",
"resetToGlobal": "Auf Global zurückgesetzen",
"resetToDefault": "Auf Werkseinstellungen zurücksetzten",
"saveAll": "Alle speichern",
"savingAll": "Alle werden gespeichert…",
"undoAll": "Alle rückgängig"
},
"label": {
"back": "Zurück",

View File

@ -0,0 +1,32 @@
{
"label": "KameraEinstellungen",
"name": {
"label": "Name der Kamera",
"description": "Kameraname ist erforderlich"
},
"enabled": {
"label": "Aktiviert",
"description": "Aktiviert"
},
"audio": {
"label": "Audioereignisse",
"description": "Einstellungen für audiobasierte Ereigniserkennung für diese Kamera.",
"enabled": {
"label": "Aktivieren der Audioerkennung",
"description": "Aktivieren / Deaktivieren der audiobasierten Ereigniserkennung für diese Kamera."
},
"min_volume": {
"label": "Mindestlautstärke"
},
"listen": {
"description": "Liste der zu erkennenden Audioereignisse (z.B: bellen, Feueralarm, schreien, sprechen, rufen)."
},
"filters": {
"label": "Audiofilter"
}
},
"friendly_name": {
"label": "Anzeigename",
"description": "Kamera-Anzeigename in der Frigate-Benutzeroberfläche"
}
}

View File

@ -0,0 +1,32 @@
{
"version": {
"label": "Aktuelle Version der Konfiguration",
"description": "Die Version Numerisch oder als Zeichenketten der aktiven Konfiguration, um Migrationen oder Formatänderungen zu erkennen."
},
"safe_mode": {
"label": "abgesicherter Modus",
"description": "Wenn aktiviert, starte Frigate im abgesicherten Modus mit reduzierten Features für die Fehlersuche."
},
"audio": {
"label": "Audioereignisse",
"enabled": {
"label": "Aktivieren der Audioerkennung"
},
"min_volume": {
"label": "Mindestlautstärke"
},
"listen": {
"description": "Liste der zu erkennenden Audioereignisse (z.B: bellen, Feueralarm, schreien, sprechen, rufen)."
},
"filters": {
"label": "Audiofilter"
}
},
"environment_vars": {
"label": "Umgebungsvariablen",
"description": "Schlüssel-/Wertpaare für Umgebungsvariablen des Frigate-Prozesses in Home Assistant OS. Nicht-HAOS Benutzer müssen anstatt dessen Docker Umgebungsvariablen nutzen."
},
"logger": {
"label": "Protokollierung"
}
}

View File

@ -0,0 +1,26 @@
{
"audio": {
"global": {
"detection": "Globale Erkennung",
"sensitivity": "Globale Empfindlichkeit"
},
"cameras": {
"detection": "Erkennung",
"sensitivity": "Empfindlichkeit"
}
},
"timestamp_style": {
"global": {
"appearance": "Globale Darstellung"
},
"cameras": {
"appearance": "Erscheinungsbild"
}
},
"motion": {
"global": {
"sensitivity": "Globale Empfindlichkeit",
"algorithm": "Globaler Algorithmus"
}
}
}

View File

@ -0,0 +1,32 @@
{
"maximum": "Darf nicht größer sein als {{limit}}",
"minimum": "Darf nicht kleiner sein als {{limit}}",
"exclusiveMinimum": "Muss größer sein als {{limit}}",
"minLength": "Muss mindestens {{limit}} Zeichen lang sein",
"maxLength": "Muss maximal {{limit}} Zeichen lang sein",
"minItems": "Muss mindestens {{limit}} mal vorkommen",
"exclusiveMaximum": "Muss kleiner sein als {{limit}}",
"maxItems": "Muss maximal {{limit}} mal vorkommen",
"pattern": "Ungültiges Format",
"required": "Pflichtfeld",
"type": "Ungültiger Wertetyp",
"enum": "Muss einer der erlaubten Werte sein",
"const": "Wert stimmt nicht mit erwarteter Konstante überein",
"uniqueItems": "Alle Einträge müssen eindeutig sein",
"format": "Ungültiges Format",
"additionalProperties": "Unbekannte Eigenschaft ist nicht erlaubt",
"oneOf": "Muss exakt mit einem der erlaubten Schemas übereinstimmen",
"anyOf": "Muss mindestens mit einem der erlaubten Schemas übereinstimmen",
"proxy": {
"header_map": {
"roleHeaderRequired": "Rollen-Header muss angegeben werden, wenn Rollen-Zuordnungen konfiguriert sind."
}
},
"ffmpeg": {
"inputs": {
"rolesUnique": "Jede Rolle kann nur einem input stream zugeteilt werden.",
"detectRequired": "Es muss mindestens ein input stream die Rolle 'erkennen' tragen.",
"hwaccelDetectOnly": "Nur der input-stream mit der Rolle 'erkennen' kann Hardwarebeschleunigungs Argumente definieren."
}
}
}

View File

@ -19,5 +19,9 @@
"downloadVideo": "Video herunterladen",
"editName": "Name ändern",
"deleteExport": "Export löschen"
},
"headings": {
"cases": "Fälle",
"uncategorizedExports": "Unkategorisierte Exporte"
}
}

View File

@ -5,7 +5,7 @@
"camera": "Kameraeinstellungen - Frigate",
"masksAndZones": "Masken- und Zoneneditor Frigate",
"object": "Debug - Frigate",
"general": "UI-Einstellungen - Frigate",
"general": "Profileinstellungen - Frigate",
"frigatePlus": "Frigate+ Einstellungen Frigate",
"classification": "Klassifizierungseinstellungen Frigate",
"motionTuner": "Bewegungserkennungs-Optimierer Frigate",
@ -28,7 +28,8 @@
"triggers": "Auslöser",
"roles": "Rollen",
"cameraManagement": "Verwaltung",
"cameraReview": "Überprüfung"
"cameraReview": "Überprüfung",
"system": "System"
},
"dialog": {
"unsavedChanges": {
@ -41,7 +42,7 @@
"noCamera": "Keine Kamera"
},
"general": {
"title": "Einstellungen der Benutzeroberfläche",
"title": "Profileinstellungen",
"liveDashboard": {
"title": "Live Übersicht",
"playAlertVideos": {
@ -408,7 +409,7 @@
}
},
"motionMaskLabel": "Bewegungsmaske {{number}}",
"objectMaskLabel": "Objektmaske {{number}} ({{label}})"
"objectMaskLabel": "Objektmaske {{number}}"
},
"debug": {
"objectShapeFilterDrawing": {

View File

@ -264,7 +264,11 @@
},
"lightning_threshold": {
"label": "Lightning threshold",
"description": "Threshold to detect and ignore brief lighting spikes (lower is more sensitive, values between 0.3 and 1.0)."
"description": "Threshold to detect and ignore brief lighting spikes (lower is more sensitive, values between 0.3 and 1.0). This does not prevent motion detection entirely; it merely causes the detector to stop analyzing additional frames once the threshold is exceeded. Motion-based recordings are still created during these events."
},
"skip_motion_threshold": {
"label": "Skip motion threshold",
"description": "If more than this fraction of the image changes in a single frame, the detector will return no motion boxes and immediately recalibrate. This can save CPU and reduce false positives during lightning, storms, etc., but may miss real events such as a PTZ camera autotracking an object. The tradeoff is between dropping a few megabytes of recordings versus reviewing a couple short clips. Range 0.0 to 1.0."
},
"improve_contrast": {
"label": "Improve contrast",
@ -864,7 +868,8 @@
"description": "A user-friendly name for the zone, displayed in the Frigate UI. If not set, a formatted version of the zone name will be used."
},
"enabled": {
"label": "Whether this zone is active. Disabled zones are ignored at runtime."
"label": "Enabled",
"description": "Enable or disable this zone. Disabled zones are ignored at runtime."
},
"enabled_in_config": {
"label": "Keep track of original state of zone."

View File

@ -1391,7 +1391,11 @@
},
"lightning_threshold": {
"label": "Lightning threshold",
"description": "Threshold to detect and ignore brief lighting spikes (lower is more sensitive, values between 0.3 and 1.0)."
"description": "Threshold to detect and ignore brief lighting spikes (lower is more sensitive, values between 0.3 and 1.0). This does not prevent motion detection entirely; it merely causes the detector to stop analyzing additional frames once the threshold is exceeded. Motion-based recordings are still created during these events."
},
"skip_motion_threshold": {
"label": "Skip motion threshold",
"description": "If more than this fraction of the image changes in a single frame, the detector will return no motion boxes and immediately recalibrate. This can save CPU and reduce false positives during lightning, storms, etc., but may miss real events such as a PTZ camera autotracking an object. The tradeoff is between dropping a few megabytes of recordings versus reviewing a couple short clips. Range 0.0 to 1.0."
},
"improve_contrast": {
"label": "Improve contrast",

View File

@ -61,5 +61,25 @@
"detected": "detected",
"normalActivity": "Normal",
"needsReview": "Needs review",
"securityConcern": "Security concern"
"securityConcern": "Security concern",
"motionSearch": {
"menuItem": "Motion search",
"openMenu": "Camera options"
},
"motionPreviews": {
"menuItem": "View motion previews",
"title": "Motion previews: {{camera}}",
"mobileSettingsTitle": "Motion Preview Settings",
"mobileSettingsDesc": "Adjust playback speed and dimming, and choose a date to review motion-only clips.",
"dim": "Dim",
"dimAria": "Adjust dimming intensity",
"dimDesc": "Increase dimming to increase motion area visibility.",
"speed": "Speed",
"speedAria": "Select preview playback speed",
"speedDesc": "Choose how quickly preview clips play.",
"back": "Back",
"empty": "No previews available",
"noPreview": "Preview unavailable",
"seekAria": "Seek {{camera}} player to {{time}}"
}
}

View File

@ -0,0 +1,75 @@
{
"documentTitle": "Motion Search - Frigate",
"title": "Motion Search",
"description": "Draw a polygon to define the region of interest, and specify a time range to search for motion changes within that region.",
"selectCamera": "Motion Search is loading",
"startSearch": "Start Search",
"searchStarted": "Search started",
"searchCancelled": "Search cancelled",
"cancelSearch": "Cancel",
"searching": "Search in progress.",
"searchComplete": "Search complete",
"noResultsYet": "Run a search to find motion changes in the selected region",
"noChangesFound": "No pixel changes detected in the selected region",
"changesFound_one": "Found {{count}} motion change",
"changesFound_other": "Found {{count}} motion changes",
"framesProcessed": "{{count}} frames processed",
"jumpToTime": "Jump to this time",
"results": "Results",
"showSegmentHeatmap": "Heatmap",
"newSearch": "New Search",
"clearResults": "Clear Results",
"clearROI": "Clear polygon",
"polygonControls": {
"points_one": "{{count}} point",
"points_other": "{{count}} points",
"undo": "Undo last point",
"reset": "Reset polygon"
},
"motionHeatmapLabel": "Motion Heatmap",
"dialog": {
"title": "Motion Search",
"cameraLabel": "Camera",
"previewAlt": "Camera preview for {{camera}}"
},
"timeRange": {
"title": "Search Range",
"start": "Start time",
"end": "End time"
},
"settings": {
"title": "Search Settings",
"parallelMode": "Parallel mode",
"parallelModeDesc": "Scan multiple recording segments at the same time (faster, but significantly more CPU intensive)",
"threshold": "Sensitivity Threshold",
"thresholdDesc": "Lower values detect smaller changes (1-255)",
"minArea": "Minimum Change Area",
"minAreaDesc": "Minimum percentage of the region of interest that must change to be considered significant",
"frameSkip": "Frame Skip",
"frameSkipDesc": "Process every Nth frame. Set this to your camera's frame rate to process one frame per second (e.g. 5 for a 5 FPS camera, 30 for a 30 FPS camera). Higher values will be faster, but may miss short motion events.",
"maxResults": "Maximum Results",
"maxResultsDesc": "Stop after this many matching timestamps"
},
"errors": {
"noCamera": "Please select a camera",
"noROI": "Please draw a region of interest",
"noTimeRange": "Please select a time range",
"invalidTimeRange": "End time must be after start time",
"searchFailed": "Search failed: {{message}}",
"polygonTooSmall": "Polygon must have at least 3 points",
"unknown": "Unknown error"
},
"changePercentage": "{{percentage}}% changed",
"metrics": {
"title": "Search Metrics",
"segmentsScanned": "Segments scanned",
"segmentsProcessed": "Processed",
"segmentsSkippedInactive": "Skipped (no activity)",
"segmentsSkippedHeatmap": "Skipped (no ROI overlap)",
"fallbackFullRange": "Fallback full-range scan",
"framesDecoded": "Frames decoded",
"wallTime": "Search time",
"segmentErrors": "Segment errors",
"seconds": "{{seconds}}s"
}
}

View File

@ -83,7 +83,8 @@
"triggers": "Triggers",
"debug": "Debug",
"frigateplus": "Frigate+",
"maintenance": "Maintenance"
"mediaSync": "Media sync",
"regionGrid": "Region grid"
},
"dialog": {
"unsavedChanges": {
@ -1232,6 +1233,16 @@
"previews": "Previews",
"exports": "Exports",
"recordings": "Recordings"
},
"regionGrid": {
"title": "Region Grid",
"desc": "The region grid is an optimization that learns where objects of different sizes typically appear in each camera's field of view. Frigate uses this data to efficiently size detection regions. The grid is automatically built over time from tracked object data.",
"clear": "Clear region grid",
"clearConfirmTitle": "Clear Region Grid",
"clearConfirmDesc": "Clearing the region grid is not recommended unless you have recently changed your detector model size or have changed your camera's physical position and are having object tracking issues. The grid will be automatically rebuilt over time as objects are tracked. A Frigate restart is required for changes to take effect.",
"clearSuccess": "Region grid cleared successfully",
"clearError": "Failed to clear region grid",
"restartRequired": "Restart required for region grid changes to take effect"
}
},
"configForm": {

View File

@ -0,0 +1,29 @@
{
"name": {
"label": "Nombre de cámara",
"description": "El nombre de la cámara es necesario"
},
"enabled": {
"label": "Habilitado",
"description": "Habilitado"
},
"audio": {
"label": "Eventos de audio",
"description": "Configuración para la detección de eventos basada en audio para esta cámara.",
"enabled": {
"label": "Habilitar la detección de audio",
"description": "Activar o deshabilitar la detección de eventos de audio para esta cámara."
},
"max_not_heard": {
"label": "Finalizar el tiempo de espera",
"description": "Cantidad de segundos sin el tipo de audio configurado antes de que finalice el evento de audio."
},
"min_volume": {
"label": "Volumen mínimo"
}
},
"friendly_name": {
"label": "Nombre descriptivo",
"description": "Nombre descriptivo de la cámara utilizado en la interfaz de usuario de Frigate"
}
}

View File

@ -0,0 +1,43 @@
{
"version": {
"label": "Versión de configuración actual",
"description": "Versión numérica o de cadena de la configuración activa para ayudar a detectar migraciones o cambios de formato."
},
"safe_mode": {
"label": "Modo seguro",
"description": "Cuando está habilitado, inicia Frigate en modo seguro con funciones reducidas para la solución de problemas."
},
"environment_vars": {
"label": "Variables de entorno",
"description": "Pares clave/valor de variables de entorno para establecer para el proceso de Frigate en el sistema operativo Home Assistant. Los usuarios que no son de HAOS deben usar la configuración de variables de entorno de Docker."
},
"logger": {
"label": "Registro",
"description": "Controla la verbosidad de registro predeterminada y la sobre-escritura de nivel de registro por componente.",
"default": {
"label": "Nivel de registro",
"description": "Nivel de detalle global predeterminada del registro (depuración, información, advertencia, error)."
},
"logs": {
"label": "Nivel de registro por proceso",
"description": "Sobre-escribir el nivel de registro por componente para aumentar o disminuir el nivel de detalle de módulos específicos."
}
},
"audio": {
"label": "Eventos de audio",
"enabled": {
"label": "Habilitar la detección de audio"
},
"max_not_heard": {
"label": "Finalizar el tiempo de espera",
"description": "Cantidad de segundos sin el tipo de audio configurado antes de que finalice el evento de audio."
},
"min_volume": {
"label": "Volumen mínimo"
}
},
"auth": {
"label": "Autenticación",
"description": "Configuración relacionada con la autenticación y la sesión, incluidas las opciones de cookies y límite de peticiones."
}
}

View File

@ -0,0 +1,44 @@
{
"audio": {
"global": {
"detection": "Detección Global",
"sensitivity": "Sensibilidad Global"
},
"cameras": {
"detection": "Detección",
"sensitivity": "Sensibilidad"
}
},
"timestamp_style": {
"global": {
"appearance": "Apariencia Global"
},
"cameras": {
"appearance": "Apariencia"
}
},
"motion": {
"global": {
"sensitivity": "Sensibilidad Global",
"algorithm": "Algoritmo Global"
},
"cameras": {
"sensitivity": "Sensibilidad",
"algorithm": "Algoritmo"
}
},
"snapshots": {
"global": {
"display": "Pantalla Global"
},
"cameras": {
"display": "Pantalla"
}
},
"detect": {
"global": {
"resolution": "Resolución Global",
"tracking": "Seguimiento Global"
}
}
}

View File

@ -0,0 +1,16 @@
{
"minimum": "Debe ser al menos {{limit}}",
"maximum": "Debe ser como mucho {{limit}}",
"exclusiveMinimum": "Debe ser mayor que {{limit}}",
"exclusiveMaximum": "Debe ser menor que {{limit}}",
"minLength": "Debe ser al menos {{limit}} carácter(es)",
"maxLength": "Debe ser como máximo {{limit}} carácter(es)",
"minItems": "Debe tener al menos {{limit}} objetos",
"maxItems": "Debe tener como máximo {{limit}} objetos",
"pattern": "Formato no válido",
"required": "Este campo es requerido",
"type": "Tipo de valor no válido",
"enum": "Debe ser uno de los valores permitidos",
"const": "El valor no coincide con la constante esperada",
"uniqueItems": "Todos los objetos deben ser únicos"
}

View File

@ -18,6 +18,11 @@
"shareExport": "Compartir exportación",
"downloadVideo": "Descargar video",
"editName": "Editar nombre",
"deleteExport": "Eliminar exportación"
"deleteExport": "Eliminar exportación",
"assignToCase": "Añadir al caso"
},
"headings": {
"cases": "Casos",
"uncategorizedExports": "Exportaciones sin categorizar"
}
}

View File

@ -12,7 +12,10 @@
"notifications": "Configuración de Notificaciones - Frigate",
"enrichments": "Configuración de Análisis Avanzado - Frigate",
"cameraManagement": "Administrar Cámaras - Frigate",
"cameraReview": "Revisar Configuración de Cámaras - Frigate"
"cameraReview": "Revisar Configuración de Cámaras - Frigate",
"globalConfig": "Configuración Global - Frigate",
"cameraConfig": "Configuración de la cámara - Frigate",
"maintenance": "Mantenimiento - Frigate"
},
"menu": {
"cameras": "Configuración de Cámara",

View File

@ -5,7 +5,8 @@
"logs": {
"frigate": "Registros de Frigate - Frigate",
"go2rtc": "Registros de Go2RTC - Frigate",
"nginx": "Registros de Nginx - Frigate"
"nginx": "Registros de Nginx - Frigate",
"websocket": "Mensajes Logs - Frigata"
},
"cameras": "Estadísticas de cámaras - Frigate",
"enrichments": "Estadísticas de Enriquecimientos - Frigate"
@ -31,6 +32,12 @@
},
"download": {
"label": "Descargar registros"
},
"websocket": {
"label": "Mensajes",
"pause": "Pausar",
"resume": "Continuar",
"clear": "Limpiar"
}
},
"title": "Sistema",

View File

@ -178,7 +178,9 @@
"export": "Ekspordi",
"uiPlayground": "Leht kasutajaliidese katsetamiseks",
"faceLibrary": "Näoteek",
"classification": "Klassifikatsioon"
"classification": "Klassifikatsioon",
"chat": "Vestlus",
"actions": "Tegevused"
},
"unit": {
"speed": {
@ -234,7 +236,18 @@
"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",
"applying": "Võtan kasutusele…"
},
"label": {
"back": "Mine tagasi",

View File

@ -78,6 +78,10 @@
"fromTimeline": {
"saveExport": "Salvesta eksporditud sisu",
"previewExport": "Eksporditud sisu eelvaade"
},
"case": {
"label": "Juhtum",
"placeholder": "Vali juhtum"
}
},
"streaming": {

View File

@ -13,11 +13,25 @@
"shareExport": "Jaga eksporditud sisu",
"downloadVideo": "Laadi video alla",
"editName": "Muuda nime",
"deleteExport": "Kustuta eksporditud sisu"
"deleteExport": "Kustuta eksporditud sisu",
"assignToCase": "Lisa juhtumile"
},
"toast": {
"error": {
"renameExportFailed": "Eksporditud sisu nime muutmine ei õnnestunud: {{errorMessage}}"
"renameExportFailed": "Eksporditud sisu nime muutmine ei õnnestunud: {{errorMessage}}",
"assignCaseFailed": "Juhtumiga seose uuendamine ei õnnestunud: {{errorMessage}}"
}
},
"headings": {
"cases": "Juhtumid",
"uncategorizedExports": "Kategooriata eksportimised"
},
"caseDialog": {
"title": "Lisa juhtumile",
"selectLabel": "Juhtum",
"newCaseOption": "Lisa uus juhtum",
"nameLabel": "Juhtumi nimi",
"descriptionLabel": "Kirjeldus",
"description": "Vali olemasolev juhtum või lisa uus."
}
}

View File

@ -6,7 +6,8 @@
"description": {
"placeholder": "Sisesta nimi selle kogumiku jaoks",
"invalidName": "Vigane nimi. Nimed võivad sisaldada ainult tähti, numbreid, tühikuid, ülakomasid, alakriipse ja sidekriipse.",
"addFace": "Laadides üles oma esimese pildi saad lisada uue kogumiku Näoteeki."
"addFace": "Laadides üles oma esimese pildi saad lisada uue kogumiku Näoteeki.",
"nameCannotContainHash": "Nimi ei saa sisaldada # märki."
},
"documentTitle": "Näoteek - Frigate",
"createFaceLibrary": {

View File

@ -11,7 +11,8 @@
"audioDetection": "Heli tuvastus",
"transcription": "Heli üleskirjutus",
"snapshots": "Hetkvõtted",
"autotracking": "Automaatne jälgimine"
"autotracking": "Automaatne jälgimine",
"recording": "Salvestus"
},
"documentTitle": "Otseülekanne - Frigate",
"documentTitle.withCamera": "{{camera}} - Otseülekanne - Frigate",
@ -100,6 +101,10 @@
"audio": {
"available": "Selles voogedastuses on heliriba saadaval",
"unavailable": "Selles voogedastuses pole heliriba saadaval"
},
"title": "Voogedastus",
"lowBandwidth": {
"resetStream": "Lähtesta voogedastus"
}
},
"notifications": "Teavitused",
@ -127,7 +132,8 @@
"playInBackground": {
"label": "Esita taustal",
"desc": "Kasuta seda valikut, kui tahad voogedastuse jätkumist ka siis, kui pildivaade on peidetud."
}
},
"debugView": "Veaotsinguvaade"
},
"noCameras": {
"buttonText": "Lisa kaamera",
@ -136,7 +142,17 @@
"description": "Sul pole õigust ühegi selle grupi kaamera vaatamiseks."
},
"title": "Ühtegi kaamerat pole seadistatud",
"description": "Alustamiseks ühenda mõni kaamera Frigate'iga."
"description": "Alustamiseks ühenda mõni kaamera Frigate'iga.",
"default": {
"title": "Ühtegi kaamerat pole seadistatud",
"description": "Alustamiseks ühenda mõni kaamera Frigate'iga.",
"buttonText": "Lisa kaamera"
},
"group": {
"title": "Grupid pole ühtegi kaamerat",
"description": "Selles kaameragrupis pole ühtegi määratud ega kasutusel kaamerat.",
"buttonText": "Halda gruppe"
}
},
"effectiveRetainMode": {
"modes": {

View File

@ -172,7 +172,7 @@
"default": "Seadistused - Frigate",
"authentication": "Autentimise seadistused - Frigate",
"cameraReview": "Kaamerate kordusvaatuste seadistused - Frigate",
"general": "Kasutajaliidese seadistused - Frigate",
"general": "Profiili seadistused - Frigate",
"frigatePlus": "Frigate+ seadistused - Frigate",
"notifications": "Teavituste seadistused - Frigate",
"cameraManagement": "Kaamerate haldus - Frigate",
@ -180,7 +180,7 @@
"object": "Silumine ja veaotsing - Frigate"
},
"general": {
"title": "Kasutajaliidese seadistused",
"title": "Profiili seadistused",
"cameraGroupStreaming": {
"clearAll": "Kustuta kõik voogedastuse seadistused"
},

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

@ -0,0 +1,5 @@
{
"version": {
"label": "Version actuelle de la configuration"
}
}

View File

@ -0,0 +1,7 @@
{
"audio": {
"global": {
"detection": "Détection globale"
}
}
}

View File

@ -0,0 +1,3 @@
{
"minimum": "Doit être au minimum {{limit}}"
}

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"
}
}
}

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