mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-02-07 11:45:24 +03:00
Merge remote-tracking branch 'upstream/dev' into go2rtc-unix-socket
This commit is contained in:
commit
7b12b920bf
@ -33,7 +33,7 @@ RUN --mount=type=tmpfs,target=/tmp --mount=type=tmpfs,target=/var/cache/apt \
|
|||||||
FROM scratch AS go2rtc
|
FROM scratch AS go2rtc
|
||||||
ARG TARGETARCH
|
ARG TARGETARCH
|
||||||
WORKDIR /rootfs/usr/local/go2rtc/bin
|
WORKDIR /rootfs/usr/local/go2rtc/bin
|
||||||
ADD --link --chmod=755 "https://github.com/AlexxIT/go2rtc/releases/download/v1.8.3/go2rtc_linux_${TARGETARCH}" go2rtc
|
ADD --link --chmod=755 "https://github.com/AlexxIT/go2rtc/releases/download/v1.8.4/go2rtc_linux_${TARGETARCH}" go2rtc
|
||||||
|
|
||||||
|
|
||||||
####
|
####
|
||||||
|
|||||||
@ -23,6 +23,7 @@ scipy == 1.11.*
|
|||||||
norfair == 2.2.*
|
norfair == 2.2.*
|
||||||
setproctitle == 1.3.*
|
setproctitle == 1.3.*
|
||||||
ws4py == 0.5.*
|
ws4py == 0.5.*
|
||||||
|
unidecode == 1.3.*
|
||||||
# Openvino Library - Custom built with MYRIAD support
|
# Openvino Library - Custom built with MYRIAD support
|
||||||
openvino @ https://github.com/NateMeyer/openvino-wheels/releases/download/multi-arch_2022.3.1/openvino-2022.3.1-1-cp39-cp39-manylinux_2_31_x86_64.whl; platform_machine == 'x86_64'
|
openvino @ https://github.com/NateMeyer/openvino-wheels/releases/download/multi-arch_2022.3.1/openvino-2022.3.1-1-cp39-cp39-manylinux_2_31_x86_64.whl; platform_machine == 'x86_64'
|
||||||
openvino @ https://github.com/NateMeyer/openvino-wheels/releases/download/multi-arch_2022.3.1/openvino-2022.3.1-1-cp39-cp39-linux_aarch64.whl; platform_machine == 'aarch64'
|
openvino @ https://github.com/NateMeyer/openvino-wheels/releases/download/multi-arch_2022.3.1/openvino-2022.3.1-1-cp39-cp39-linux_aarch64.whl; platform_machine == 'aarch64'
|
||||||
|
|||||||
@ -48,6 +48,7 @@ export LIBAVFORMAT_VERSION_MAJOR=$(ffmpeg -version | grep -Po 'libavformat\W+\K\
|
|||||||
if [[ -f "/dev/shm/go2rtc.yaml" ]]; then
|
if [[ -f "/dev/shm/go2rtc.yaml" ]]; then
|
||||||
echo "[INFO] Removing stale config from last run..."
|
echo "[INFO] Removing stale config from last run..."
|
||||||
rm /dev/shm/go2rtc.yaml
|
rm /dev/shm/go2rtc.yaml
|
||||||
|
fi
|
||||||
|
|
||||||
if [[ ! -f "/dev/shm/go2rtc.yaml" ]]; then
|
if [[ ! -f "/dev/shm/go2rtc.yaml" ]]; then
|
||||||
echo "[INFO] Preparing new go2rtc config..."
|
echo "[INFO] Preparing new go2rtc config..."
|
||||||
|
|||||||
@ -115,6 +115,20 @@ if int(os.environ["LIBAVFORMAT_VERSION_MAJOR"]) < 59:
|
|||||||
"rtsp"
|
"rtsp"
|
||||||
] = "-fflags nobuffer -flags low_delay -stimeout 5000000 -user_agent go2rtc/ffmpeg -rtsp_transport tcp -i {input}"
|
] = "-fflags nobuffer -flags low_delay -stimeout 5000000 -user_agent go2rtc/ffmpeg -rtsp_transport tcp -i {input}"
|
||||||
|
|
||||||
|
# add hardware acceleration presets for rockchip devices
|
||||||
|
# may be removed if frigate uses a go2rtc version that includes these presets
|
||||||
|
if go2rtc_config.get("ffmpeg") is None:
|
||||||
|
go2rtc_config["ffmpeg"] = {
|
||||||
|
"h264/rk": "-c:v h264_rkmpp_encoder -g 50 -bf 0",
|
||||||
|
"h265/rk": "-c:v hevc_rkmpp_encoder -g 50 -bf 0",
|
||||||
|
}
|
||||||
|
else:
|
||||||
|
if go2rtc_config["ffmpeg"].get("h264/rk") is None:
|
||||||
|
go2rtc_config["ffmpeg"]["h264/rk"] = "-c:v h264_rkmpp_encoder -g 50 -bf 0"
|
||||||
|
|
||||||
|
if go2rtc_config["ffmpeg"].get("h265/rk") is None:
|
||||||
|
go2rtc_config["ffmpeg"]["h265/rk"] = "-c:v hevc_rkmpp_encoder -g 50 -bf 0"
|
||||||
|
|
||||||
for name in go2rtc_config.get("streams", {}):
|
for name in go2rtc_config.get("streams", {}):
|
||||||
stream = go2rtc_config["streams"][name]
|
stream = go2rtc_config["streams"][name]
|
||||||
|
|
||||||
|
|||||||
@ -28,5 +28,5 @@ ADD https://github.com/MarcA711/rknn-models/releases/download/v1.5.2-rk3588/yolo
|
|||||||
|
|
||||||
RUN rm -rf /usr/lib/btbn-ffmpeg/bin/ffmpeg
|
RUN rm -rf /usr/lib/btbn-ffmpeg/bin/ffmpeg
|
||||||
RUN rm -rf /usr/lib/btbn-ffmpeg/bin/ffprobe
|
RUN rm -rf /usr/lib/btbn-ffmpeg/bin/ffprobe
|
||||||
ADD --chmod=111 https://github.com/MarcA711/Rockchip-FFmpeg-Builds/releases/download/latest/ffmpeg /usr/lib/btbn-ffmpeg/bin/
|
ADD --chmod=111 https://github.com/MarcA711/Rockchip-FFmpeg-Builds/releases/download/6.0-1/ffmpeg /usr/lib/btbn-ffmpeg/bin/
|
||||||
ADD --chmod=111 https://github.com/MarcA711/Rockchip-FFmpeg-Builds/releases/download/latest/ffprobe /usr/lib/btbn-ffmpeg/bin/
|
ADD --chmod=111 https://github.com/MarcA711/Rockchip-FFmpeg-Builds/releases/download/6.0-1/ffprobe /usr/lib/btbn-ffmpeg/bin/
|
||||||
|
|||||||
@ -120,7 +120,7 @@ NOTE: The folder that is mapped from the host needs to be the folder that contai
|
|||||||
|
|
||||||
## Custom go2rtc version
|
## Custom go2rtc version
|
||||||
|
|
||||||
Frigate currently includes go2rtc v1.8.3, there may be certain cases where you want to run a different version of go2rtc.
|
Frigate currently includes go2rtc v1.8.4, there may be certain cases where you want to run a different version of go2rtc.
|
||||||
|
|
||||||
To do this:
|
To do this:
|
||||||
|
|
||||||
|
|||||||
@ -140,7 +140,7 @@ go2rtc:
|
|||||||
- rtspx://192.168.1.1:7441/abcdefghijk
|
- rtspx://192.168.1.1:7441/abcdefghijk
|
||||||
```
|
```
|
||||||
|
|
||||||
[See the go2rtc docs for more information](https://github.com/AlexxIT/go2rtc/tree/v1.8.3#source-rtsp)
|
[See the go2rtc docs for more information](https://github.com/AlexxIT/go2rtc/tree/v1.8.4#source-rtsp)
|
||||||
|
|
||||||
In the Unifi 2.0 update Unifi Protect Cameras had a change in audio sample rate which causes issues for ffmpeg. The input rate needs to be set for record and rtmp if used directly with unifi protect.
|
In the Unifi 2.0 update Unifi Protect Cameras had a change in audio sample rate which causes issues for ffmpeg. The input rate needs to be set for record and rtmp if used directly with unifi protect.
|
||||||
|
|
||||||
|
|||||||
@ -354,3 +354,29 @@ ffmpeg:
|
|||||||
Make sure that your SoC supports hardware acceleration for your input stream. For example, if your camera streams with h265 encoding and a 4k resolution, your SoC must be able to de- and encode h265 with a 4k resolution or higher. If you are unsure whether your SoC meets the requirements, take a look at the datasheet.
|
Make sure that your SoC supports hardware acceleration for your input stream. For example, if your camera streams with h265 encoding and a 4k resolution, your SoC must be able to de- and encode h265 with a 4k resolution or higher. If you are unsure whether your SoC meets the requirements, take a look at the datasheet.
|
||||||
|
|
||||||
:::
|
:::
|
||||||
|
|
||||||
|
### go2rtc presets for hardware accelerated transcoding
|
||||||
|
|
||||||
|
If your input stream is to be transcoded using hardware acceleration, there are these presets for go2rtc: `h264/rk` and `h265/rk`. You can use them this way:
|
||||||
|
|
||||||
|
```
|
||||||
|
go2rtc:
|
||||||
|
streams:
|
||||||
|
Cam_h264: ffmpeg:rtsp://username:password@192.168.1.123/av_stream/ch0#video=h264/rk
|
||||||
|
Cam_h265: ffmpeg:rtsp://username:password@192.168.1.123/av_stream/ch0#video=h265/rk
|
||||||
|
```
|
||||||
|
|
||||||
|
:::warning
|
||||||
|
|
||||||
|
The go2rtc docs may suggest the following configuration:
|
||||||
|
|
||||||
|
```
|
||||||
|
go2rtc:
|
||||||
|
streams:
|
||||||
|
Cam_h264: ffmpeg:rtsp://username:password@192.168.1.123/av_stream/ch0#video=h264#hardware=rk
|
||||||
|
Cam_h265: ffmpeg:rtsp://username:password@192.168.1.123/av_stream/ch0#video=h265#hardware=rk
|
||||||
|
```
|
||||||
|
|
||||||
|
However, this does not currently work.
|
||||||
|
|
||||||
|
:::
|
||||||
|
|||||||
@ -370,7 +370,7 @@ $ cat /sys/kernel/debug/rknpu/load
|
|||||||
- By default the rknn detector uses the yolov8n model (`model: path: default-yolov8n`). This model comes with the image, so no further steps than those mentioned above are necessary.
|
- By default the rknn detector uses the yolov8n model (`model: path: default-yolov8n`). This model comes with the image, so no further steps than those mentioned above are necessary.
|
||||||
- If you want to use a more precise model, you can pass `default-yolov8s`, `default-yolov8m`, `default-yolov8l` or `default-yolov8x` as `model: path:` option.
|
- If you want to use a more precise model, you can pass `default-yolov8s`, `default-yolov8m`, `default-yolov8l` or `default-yolov8x` as `model: path:` option.
|
||||||
- If the model does not exist, it will be automatically downloaded to `/config/model_cache/rknn`.
|
- If the model does not exist, it will be automatically downloaded to `/config/model_cache/rknn`.
|
||||||
- If your server has no internet connection, you can download the model from [this Github repository](https://github.com/MarcA711/rknn-models/releases/tag/latest) using another device and place it in the `config/model_cache/rknn` on your system.
|
- If your server has no internet connection, you can download the model from [this Github repository](https://github.com/MarcA711/rknn-models/releases) using another device and place it in the `config/model_cache/rknn` on your system.
|
||||||
- Finally, you can also provide your own model. Note that only yolov8 models are currently supported. Moreover, you will need to convert your model to the rknn format using `rknn-toolkit2` on a x86 machine. Afterwards, you can place your `.rknn` model file in the `config/model_cache/rknn` directory on your system. Then you need to pass the path to your model using the `path` option of your `model` block like this:
|
- Finally, you can also provide your own model. Note that only yolov8 models are currently supported. Moreover, you will need to convert your model to the rknn format using `rknn-toolkit2` on a x86 machine. Afterwards, you can place your `.rknn` model file in the `config/model_cache/rknn` directory on your system. Then you need to pass the path to your model using the `path` option of your `model` block like this:
|
||||||
```yaml
|
```yaml
|
||||||
model:
|
model:
|
||||||
|
|||||||
@ -7,7 +7,7 @@ title: Restream
|
|||||||
|
|
||||||
Frigate can restream your video feed as an RTSP feed for other applications such as Home Assistant to utilize it at `rtsp://<frigate_host>:8554/<camera_name>`. Port 8554 must be open. [This allows you to use a video feed for detection in Frigate and Home Assistant live view at the same time without having to make two separate connections to the camera](#reduce-connections-to-camera). The video feed is copied from the original video feed directly to avoid re-encoding. This feed does not include any annotation by Frigate.
|
Frigate can restream your video feed as an RTSP feed for other applications such as Home Assistant to utilize it at `rtsp://<frigate_host>:8554/<camera_name>`. Port 8554 must be open. [This allows you to use a video feed for detection in Frigate and Home Assistant live view at the same time without having to make two separate connections to the camera](#reduce-connections-to-camera). The video feed is copied from the original video feed directly to avoid re-encoding. This feed does not include any annotation by Frigate.
|
||||||
|
|
||||||
Frigate uses [go2rtc](https://github.com/AlexxIT/go2rtc/tree/v1.8.3) to provide its restream and MSE/WebRTC capabilities. The go2rtc config is hosted at the `go2rtc` in the config, see [go2rtc docs](https://github.com/AlexxIT/go2rtc/tree/v1.8.3#configuration) for more advanced configurations and features.
|
Frigate uses [go2rtc](https://github.com/AlexxIT/go2rtc/tree/v1.8.4) to provide its restream and MSE/WebRTC capabilities. The go2rtc config is hosted at the `go2rtc` in the config, see [go2rtc docs](https://github.com/AlexxIT/go2rtc/tree/v1.8.4#configuration) for more advanced configurations and features.
|
||||||
|
|
||||||
:::note
|
:::note
|
||||||
|
|
||||||
@ -138,7 +138,7 @@ cameras:
|
|||||||
|
|
||||||
## Advanced Restream Configurations
|
## Advanced Restream Configurations
|
||||||
|
|
||||||
The [exec](https://github.com/AlexxIT/go2rtc/tree/v1.8.3#source-exec) source in go2rtc can be used for custom ffmpeg commands. An example is below:
|
The [exec](https://github.com/AlexxIT/go2rtc/tree/v1.8.4#source-exec) source in go2rtc can be used for custom ffmpeg commands. An example is below:
|
||||||
|
|
||||||
NOTE: The output will need to be passed with two curly braces `{{output}}`
|
NOTE: The output will need to be passed with two curly braces `{{output}}`
|
||||||
|
|
||||||
|
|||||||
@ -13,7 +13,7 @@ Use of the bundled go2rtc is optional. You can still configure FFmpeg to connect
|
|||||||
|
|
||||||
# Setup a go2rtc stream
|
# Setup a go2rtc stream
|
||||||
|
|
||||||
First, you will want to configure go2rtc to connect to your camera stream by adding the stream you want to use for live view in your Frigate config file. If you set the stream name under go2rtc to match the name of your camera, it will automatically be mapped and you will get additional live view options for the camera. Avoid changing any other parts of your config at this step. Note that go2rtc supports [many different stream types](https://github.com/AlexxIT/go2rtc/tree/v1.8.3#module-streams), not just rtsp.
|
First, you will want to configure go2rtc to connect to your camera stream by adding the stream you want to use for live view in your Frigate config file. If you set the stream name under go2rtc to match the name of your camera, it will automatically be mapped and you will get additional live view options for the camera. Avoid changing any other parts of your config at this step. Note that go2rtc supports [many different stream types](https://github.com/AlexxIT/go2rtc/tree/v1.8.4#module-streams), not just rtsp.
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
go2rtc:
|
go2rtc:
|
||||||
@ -26,7 +26,7 @@ The easiest live view to get working is MSE. After adding this to the config, re
|
|||||||
|
|
||||||
### What if my video doesn't play?
|
### What if my video doesn't play?
|
||||||
|
|
||||||
If you are unable to see your video feed, first check the go2rtc logs in the Frigate UI under Logs in the sidebar. If go2rtc is having difficulty connecting to your camera, you should see some error messages in the log. If you do not see any errors, then the video codec of the stream may not be supported in your browser. If your camera stream is set to H265, try switching to H264. You can see more information about [video codec compatibility](https://github.com/AlexxIT/go2rtc/tree/v1.8.3#codecs-madness) in the go2rtc documentation. If you are not able to switch your camera settings from H265 to H264 or your stream is a different format such as MJPEG, you can use go2rtc to re-encode the video using the [FFmpeg parameters](https://github.com/AlexxIT/go2rtc/tree/v1.8.3#source-ffmpeg). It supports rotating and resizing video feeds and hardware acceleration. Keep in mind that transcoding video from one format to another is a resource intensive task and you may be better off using the built-in jsmpeg view. Here is an example of a config that will re-encode the stream to H264 without hardware acceleration:
|
If you are unable to see your video feed, first check the go2rtc logs in the Frigate UI under Logs in the sidebar. If go2rtc is having difficulty connecting to your camera, you should see some error messages in the log. If you do not see any errors, then the video codec of the stream may not be supported in your browser. If your camera stream is set to H265, try switching to H264. You can see more information about [video codec compatibility](https://github.com/AlexxIT/go2rtc/tree/v1.8.4#codecs-madness) in the go2rtc documentation. If you are not able to switch your camera settings from H265 to H264 or your stream is a different format such as MJPEG, you can use go2rtc to re-encode the video using the [FFmpeg parameters](https://github.com/AlexxIT/go2rtc/tree/v1.8.4#source-ffmpeg). It supports rotating and resizing video feeds and hardware acceleration. Keep in mind that transcoding video from one format to another is a resource intensive task and you may be better off using the built-in jsmpeg view. Here is an example of a config that will re-encode the stream to H264 without hardware acceleration:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
go2rtc:
|
go2rtc:
|
||||||
|
|||||||
@ -16,11 +16,13 @@ There are many guides on how to install Debian Server, so this will be an abbrev
|
|||||||
#### Prepare installation media
|
#### Prepare installation media
|
||||||
|
|
||||||
1. Download the small installation image from the [Debian website](https://www.debian.org/distrib/netinst)
|
1. Download the small installation image from the [Debian website](https://www.debian.org/distrib/netinst)
|
||||||
1. Flash the ISO to a USB device
|
1. Flash the ISO to a USB device (popular tool is [balena Etcher](https://etcher.balena.io/))
|
||||||
1. Boot your device from USB
|
1. Boot your device from USB
|
||||||
|
|
||||||
#### Install and setup Debian for remote access
|
#### Install and setup Debian for remote access
|
||||||
|
|
||||||
|
1. Ensure your device is connected to the network so updates and software options can be installed
|
||||||
|
1. Choose the non-graphical install option if you don't have a mouse connected, but either install method works fine
|
||||||
1. You will be prompted to set the root user password and create a user with a password
|
1. You will be prompted to set the root user password and create a user with a password
|
||||||
1. Install the minimum software. Fewer dependencies result in less maintenance.
|
1. Install the minimum software. Fewer dependencies result in less maintenance.
|
||||||
1. Uncheck "Debian desktop environment" and "GNOME"
|
1. Uncheck "Debian desktop environment" and "GNOME"
|
||||||
@ -37,12 +39,12 @@ There are many guides on how to install Debian Server, so this will be an abbrev
|
|||||||
```
|
```
|
||||||
1. Shutdown by running `poweroff`
|
1. Shutdown by running `poweroff`
|
||||||
|
|
||||||
At this point, you can install the device in a permanent location. The remaining steps can be performed via SSH.
|
At this point, you can install the device in a permanent location. The remaining steps can be performed via SSH from another device. If you don't have an SSH client, you can install one of the options listed in the [Visual Studio Code documentation](https://code.visualstudio.com/docs/remote/troubleshooting#_installing-a-supported-ssh-client).
|
||||||
|
|
||||||
#### Finish setup via SSH
|
#### Finish setup via SSH
|
||||||
|
|
||||||
1. Connect via SSH and login with your non-root user
|
1. Connect via SSH and login with your non-root user created during install
|
||||||
1. Setup passwordless sudo so you don't have to type your password for each sudo command
|
1. Setup passwordless sudo so you don't have to type your password for each sudo command (change `blake` in the command below to your user)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
echo 'blake ALL=(ALL) NOPASSWD:ALL' | sudo tee /etc/sudoers.d/user
|
echo 'blake ALL=(ALL) NOPASSWD:ALL' | sudo tee /etc/sudoers.d/user
|
||||||
@ -91,6 +93,8 @@ This will create the above structure:
|
|||||||
mkdir storage config && touch docker-compose.yml config/config.yml
|
mkdir storage config && touch docker-compose.yml config/config.yml
|
||||||
```
|
```
|
||||||
|
|
||||||
|
If you are setting up Frigate on a Linux device via SSH, you can use [nano](https://itsfoss.com/nano-editor-guide/) to edit the following files. If you prefer to edit remote files with a full editor instead of a terminal, I recommend using [Visual Studio Code](https://code.visualstudio.com/) with the [Remote SSH extension](https://code.visualstudio.com/docs/remote/ssh-tutorial).
|
||||||
|
|
||||||
:::note
|
:::note
|
||||||
|
|
||||||
This `docker-compose.yml` file is just a starter for amd64 devices. You will need to customize it for your setup as detailed in the [Installation docs](/frigate/installation#docker).
|
This `docker-compose.yml` file is just a starter for amd64 devices. You will need to customize it for your setup as detailed in the [Installation docs](/frigate/installation#docker).
|
||||||
|
|||||||
@ -302,6 +302,14 @@ It is also possible to export this recording as a timelapse.
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### `DELETE /api/export/<export_name>`
|
||||||
|
|
||||||
|
Delete an export from disk.
|
||||||
|
|
||||||
|
### `PATCH /api/export/<export_name_current>/<export_name_new>`
|
||||||
|
|
||||||
|
Renames an export.
|
||||||
|
|
||||||
### `GET /api/<camera_name>/recordings/summary`
|
### `GET /api/<camera_name>/recordings/summary`
|
||||||
|
|
||||||
Hourly summary of recordings data for a camera.
|
Hourly summary of recordings data for a camera.
|
||||||
|
|||||||
@ -22,7 +22,7 @@ module.exports = {
|
|||||||
{
|
{
|
||||||
type: "link",
|
type: "link",
|
||||||
label: "Go2RTC Configuration Reference",
|
label: "Go2RTC Configuration Reference",
|
||||||
href: "https://github.com/AlexxIT/go2rtc/tree/v1.8.2#configuration",
|
href: "https://github.com/AlexxIT/go2rtc/tree/v1.8.4#configuration",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
Detectors: [
|
Detectors: [
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import glob
|
|||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
|
import re
|
||||||
import subprocess as sp
|
import subprocess as sp
|
||||||
import time
|
import time
|
||||||
import traceback
|
import traceback
|
||||||
@ -875,7 +876,7 @@ def event_clip(id):
|
|||||||
response.headers["Content-Length"] = os.path.getsize(clip_path)
|
response.headers["Content-Length"] = os.path.getsize(clip_path)
|
||||||
response.headers[
|
response.headers[
|
||||||
"X-Accel-Redirect"
|
"X-Accel-Redirect"
|
||||||
] = f"/clips/{file_name}" # nginx: http://wiki.nginx.org/NginxXSendfile
|
] = f"/clips/{file_name}" # nginx: https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_ignore_headers
|
||||||
|
|
||||||
return response
|
return response
|
||||||
|
|
||||||
@ -1153,6 +1154,9 @@ def end_event(event_id):
|
|||||||
def config():
|
def config():
|
||||||
config = current_app.frigate_config.dict()
|
config = current_app.frigate_config.dict()
|
||||||
|
|
||||||
|
# remove the mqtt password
|
||||||
|
config["mqtt"].pop("password", None)
|
||||||
|
|
||||||
for camera_name, camera in current_app.frigate_config.cameras.items():
|
for camera_name, camera in current_app.frigate_config.cameras.items():
|
||||||
camera_dict = config["cameras"][camera_name]
|
camera_dict = config["cameras"][camera_name]
|
||||||
|
|
||||||
@ -1752,7 +1756,7 @@ def recording_clip(camera_name, start_ts, end_ts):
|
|||||||
response.headers["Content-Length"] = os.path.getsize(path)
|
response.headers["Content-Length"] = os.path.getsize(path)
|
||||||
response.headers[
|
response.headers[
|
||||||
"X-Accel-Redirect"
|
"X-Accel-Redirect"
|
||||||
] = f"/cache/{file_name}" # nginx: http://wiki.nginx.org/NginxXSendfile
|
] = f"/cache/{file_name}" # nginx: https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_ignore_headers
|
||||||
|
|
||||||
return response
|
return response
|
||||||
|
|
||||||
@ -1954,9 +1958,68 @@ def export_recording(camera_name: str, start_time, end_time):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def export_filename_check_extension(filename: str):
|
||||||
|
if filename.endswith(".mp4"):
|
||||||
|
return filename
|
||||||
|
else:
|
||||||
|
return filename + ".mp4"
|
||||||
|
|
||||||
|
|
||||||
|
def export_filename_is_valid(filename: str):
|
||||||
|
if re.search(r"[^:_A-Za-z0-9]", filename) or filename.startswith("in_progress."):
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
@bp.route("/export/<file_name_current>/<file_name_new>", methods=["PATCH"])
|
||||||
|
def export_rename(file_name_current, file_name_new: str):
|
||||||
|
safe_file_name_current = secure_filename(
|
||||||
|
export_filename_check_extension(file_name_current)
|
||||||
|
)
|
||||||
|
file_current = os.path.join(EXPORT_DIR, safe_file_name_current)
|
||||||
|
|
||||||
|
if not os.path.exists(file_current):
|
||||||
|
return make_response(
|
||||||
|
jsonify({"success": False, "message": f"{file_name_current} not found."}),
|
||||||
|
404,
|
||||||
|
)
|
||||||
|
|
||||||
|
if not export_filename_is_valid(file_name_new):
|
||||||
|
return make_response(
|
||||||
|
jsonify(
|
||||||
|
{
|
||||||
|
"success": False,
|
||||||
|
"message": f"{file_name_new} contains illegal characters.",
|
||||||
|
}
|
||||||
|
),
|
||||||
|
400,
|
||||||
|
)
|
||||||
|
|
||||||
|
safe_file_name_new = secure_filename(export_filename_check_extension(file_name_new))
|
||||||
|
file_new = os.path.join(EXPORT_DIR, safe_file_name_new)
|
||||||
|
|
||||||
|
if os.path.exists(file_new):
|
||||||
|
return make_response(
|
||||||
|
jsonify({"success": False, "message": f"{file_name_new} already exists."}),
|
||||||
|
400,
|
||||||
|
)
|
||||||
|
|
||||||
|
os.rename(file_current, file_new)
|
||||||
|
return make_response(
|
||||||
|
jsonify(
|
||||||
|
{
|
||||||
|
"success": True,
|
||||||
|
"message": "Successfully renamed file.",
|
||||||
|
}
|
||||||
|
),
|
||||||
|
200,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@bp.route("/export/<file_name>", methods=["DELETE"])
|
@bp.route("/export/<file_name>", methods=["DELETE"])
|
||||||
def export_delete(file_name: str):
|
def export_delete(file_name: str):
|
||||||
safe_file_name = secure_filename(file_name)
|
safe_file_name = secure_filename(export_filename_check_extension(file_name))
|
||||||
file = os.path.join(EXPORT_DIR, safe_file_name)
|
file = os.path.join(EXPORT_DIR, safe_file_name)
|
||||||
|
|
||||||
if not os.path.exists(file):
|
if not os.path.exists(file):
|
||||||
|
|||||||
@ -5,7 +5,7 @@ import numpy as np
|
|||||||
from norfair.drawing.color import Palette
|
from norfair.drawing.color import Palette
|
||||||
from norfair.drawing.drawer import Drawer
|
from norfair.drawing.drawer import Drawer
|
||||||
|
|
||||||
from frigate.util.image import intersection
|
from frigate.util.image import intersection, transliterate_to_latin
|
||||||
from frigate.util.object import (
|
from frigate.util.object import (
|
||||||
get_cluster_boundary,
|
get_cluster_boundary,
|
||||||
get_cluster_candidates,
|
get_cluster_candidates,
|
||||||
@ -82,6 +82,11 @@ class TestRegion(unittest.TestCase):
|
|||||||
|
|
||||||
assert len(cluster_candidates) == 2
|
assert len(cluster_candidates) == 2
|
||||||
|
|
||||||
|
def test_transliterate_to_latin(self):
|
||||||
|
self.assertEqual(transliterate_to_latin("frégate"), "fregate")
|
||||||
|
self.assertEqual(transliterate_to_latin("utilité"), "utilite")
|
||||||
|
self.assertEqual(transliterate_to_latin("imágé"), "image")
|
||||||
|
|
||||||
def test_cluster_boundary(self):
|
def test_cluster_boundary(self):
|
||||||
boxes = [(100, 100, 200, 200), (215, 215, 325, 325)]
|
boxes = [(100, 100, 200, 200), (215, 215, 325, 325)]
|
||||||
boundary_boxes = [
|
boundary_boxes = [
|
||||||
|
|||||||
@ -16,6 +16,7 @@ import pytz
|
|||||||
import yaml
|
import yaml
|
||||||
from ruamel.yaml import YAML
|
from ruamel.yaml import YAML
|
||||||
from tzlocal import get_localzone
|
from tzlocal import get_localzone
|
||||||
|
from zoneinfo import ZoneInfoNotFoundError
|
||||||
|
|
||||||
from frigate.const import REGEX_HTTP_CAMERA_USER_PASS, REGEX_RTSP_CAMERA_USER_PASS
|
from frigate.const import REGEX_HTTP_CAMERA_USER_PASS, REGEX_RTSP_CAMERA_USER_PASS
|
||||||
|
|
||||||
@ -266,7 +267,16 @@ def find_by_key(dictionary, target_key):
|
|||||||
|
|
||||||
def get_tomorrow_at_time(hour: int) -> datetime.datetime:
|
def get_tomorrow_at_time(hour: int) -> datetime.datetime:
|
||||||
"""Returns the datetime of the following day at 2am."""
|
"""Returns the datetime of the following day at 2am."""
|
||||||
tomorrow = datetime.datetime.now(get_localzone()) + datetime.timedelta(days=1)
|
try:
|
||||||
|
tomorrow = datetime.datetime.now(get_localzone()) + datetime.timedelta(days=1)
|
||||||
|
except ZoneInfoNotFoundError:
|
||||||
|
tomorrow = datetime.datetime.now(datetime.timezone.utc) + datetime.timedelta(
|
||||||
|
days=1
|
||||||
|
)
|
||||||
|
logger.warning(
|
||||||
|
"Using utc for maintenance due to missing or incorrect timezone set"
|
||||||
|
)
|
||||||
|
|
||||||
return tomorrow.replace(hour=hour, minute=0, second=0).astimezone(
|
return tomorrow.replace(hour=hour, minute=0, second=0).astimezone(
|
||||||
datetime.timezone.utc
|
datetime.timezone.utc
|
||||||
)
|
)
|
||||||
|
|||||||
@ -9,10 +9,32 @@ from typing import AnyStr, Optional
|
|||||||
|
|
||||||
import cv2
|
import cv2
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
from unidecode import unidecode
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
def transliterate_to_latin(text: str) -> str:
|
||||||
|
"""
|
||||||
|
Transliterate a given text to Latin.
|
||||||
|
|
||||||
|
This function uses the unidecode library to transliterate the input text to Latin.
|
||||||
|
It is useful for converting texts with diacritics or non-Latin characters to a
|
||||||
|
Latin equivalent.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
text (str): The text to be transliterated.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str: The transliterated text.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
>>> transliterate_to_latin('frégate')
|
||||||
|
'fregate'
|
||||||
|
"""
|
||||||
|
return unidecode(text)
|
||||||
|
|
||||||
|
|
||||||
def draw_timestamp(
|
def draw_timestamp(
|
||||||
frame,
|
frame,
|
||||||
timestamp,
|
timestamp,
|
||||||
@ -116,7 +138,10 @@ def draw_box_with_label(
|
|||||||
):
|
):
|
||||||
if color is None:
|
if color is None:
|
||||||
color = (0, 0, 255)
|
color = (0, 0, 255)
|
||||||
display_text = "{}: {}".format(label, info)
|
try:
|
||||||
|
display_text = transliterate_to_latin("{}: {}".format(label, info))
|
||||||
|
except Exception:
|
||||||
|
display_text = "{}: {}".format(label, info)
|
||||||
cv2.rectangle(frame, (x_min, y_min), (x_max, y_max), color, thickness)
|
cv2.rectangle(frame, (x_min, y_min), (x_max, y_max), color, thickness)
|
||||||
font_scale = 0.5
|
font_scale = 0.5
|
||||||
font = cv2.FONT_HERSHEY_SIMPLEX
|
font = cv2.FONT_HERSHEY_SIMPLEX
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user