diff --git a/.github/ISSUE_TEMPLATE/edgetpu_support_request.yml b/.github/ISSUE_TEMPLATE/detector_support_request.yml similarity index 92% rename from .github/ISSUE_TEMPLATE/edgetpu_support_request.yml rename to .github/ISSUE_TEMPLATE/detector_support_request.yml index aad464edf..3f5b34935 100644 --- a/.github/ISSUE_TEMPLATE/edgetpu_support_request.yml +++ b/.github/ISSUE_TEMPLATE/detector_support_request.yml @@ -1,6 +1,6 @@ -name: EdgeTpu Support Request -description: Support for setting up EdgeTPU in Frigate -title: "[EdgeTPU Support]: " +name: Detector Support Request +description: Support for setting up object detector in Frigate (Coral, OpenVINO, TensorRT, etc.) +title: "[Detector Support]: " labels: ["support", "triage"] assignees: [] body: diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index df33eb051..b7705dcf6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -19,6 +19,15 @@ jobs: runs-on: ubuntu-latest name: Image Build steps: + - name: Remove unnecessary files + run: | + sudo rm -rf /usr/share/dotnet + sudo rm -rf /usr/local/lib/android + sudo rm -rf /opt/ghc + - id: lowercaseRepo + uses: ASzc/change-string-case-action@v5 + with: + string: ${{ github.repository }} - name: Check out code uses: actions/checkout@v3 - name: Set up QEMU @@ -36,23 +45,23 @@ jobs: - name: Create short sha run: echo "SHORT_SHA=${GITHUB_SHA::7}" >> $GITHUB_ENV - name: Build and push - uses: docker/build-push-action@v3 + uses: docker/build-push-action@v4 with: context: . push: true - platforms: linux/amd64,linux/arm64,linux/arm/v7 + platforms: linux/amd64,linux/arm64 target: frigate tags: | - ghcr.io/blakeblackshear/frigate:${{ github.ref_name }}-${{ env.SHORT_SHA }} + ghcr.io/${{ steps.lowercaseRepo.outputs.lowercase }}:${{ github.ref_name }}-${{ env.SHORT_SHA }} cache-from: type=gha cache-to: type=gha,mode=max - name: Build and push TensorRT - uses: docker/build-push-action@v3 + uses: docker/build-push-action@v4 with: context: . push: true platforms: linux/amd64 target: frigate-tensorrt tags: | - ghcr.io/blakeblackshear/frigate:${{ github.ref_name }}-${{ env.SHORT_SHA }}-tensorrt + ghcr.io/${{ steps.lowercaseRepo.outputs.lowercase }}:${{ github.ref_name }}-${{ env.SHORT_SHA }}-tensorrt cache-from: type=gha diff --git a/.github/workflows/dependabot-auto-merge.yaml b/.github/workflows/dependabot-auto-merge.yaml index 873350876..a3eecb1d5 100644 --- a/.github/workflows/dependabot-auto-merge.yaml +++ b/.github/workflows/dependabot-auto-merge.yaml @@ -16,7 +16,9 @@ jobs: github-token: ${{ secrets.GITHUB_TOKEN }} - name: Enable auto-merge for Dependabot PRs if: steps.metadata.outputs.dependency-type == 'direct:development' && (steps.metadata.outputs.update-type == 'version-update:semver-minor' || steps.metadata.outputs.update-type == 'version-update:semver-patch') - run: gh pr merge --auto --squash "$PR_URL" + run: | + gh pr review --approve "$PR_URL" + gh pr merge --auto --squash "$PR_URL" env: PR_URL: ${{ github.event.pull_request.html_url }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/maintain_cache.yml b/.github/workflows/maintain_cache.yml new file mode 100644 index 000000000..a15c8c684 --- /dev/null +++ b/.github/workflows/maintain_cache.yml @@ -0,0 +1,45 @@ +name: Maintain Cache + +on: + schedule: + - cron: "13 0 * * 0,4" + +env: + PYTHON_VERSION: 3.9 + +jobs: + multi_arch_build: + runs-on: ubuntu-latest + name: Image Build + steps: + - name: Remove unnecessary files + run: | + sudo rm -rf /usr/share/dotnet + sudo rm -rf /usr/local/lib/android + sudo rm -rf /opt/ghc + - id: lowercaseRepo + uses: ASzc/change-string-case-action@v5 + with: + string: ${{ github.repository }} + - name: Check out code + uses: actions/checkout@v3 + - name: Set up QEMU + uses: docker/setup-qemu-action@v2 + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v2 + - name: Log in to the Container registry + uses: docker/login-action@f4ef78c080cd8ba55a85445d5b36e214a81df20a + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + - name: Create version file + run: make version + - name: Build and push + uses: docker/build-push-action@v4 + with: + context: . + push: false + platforms: linux/amd64,linux/arm64 + target: frigate + cache-from: type=gha diff --git a/Dockerfile b/Dockerfile index 1ddf7d2b1..4059a8059 100644 --- a/Dockerfile +++ b/Dockerfile @@ -27,7 +27,7 @@ RUN --mount=type=tmpfs,target=/tmp --mount=type=tmpfs,target=/var/cache/apt \ FROM wget AS go2rtc ARG TARGETARCH WORKDIR /rootfs/usr/local/go2rtc/bin -RUN wget -qO go2rtc "https://github.com/AlexxIT/go2rtc/releases/download/v1.0.1/go2rtc_linux_${TARGETARCH}" \ +RUN wget -qO go2rtc "https://github.com/AlexxIT/go2rtc/releases/download/v1.2.0/go2rtc_linux_${TARGETARCH}" \ && chmod +x go2rtc @@ -133,11 +133,6 @@ RUN apt-get -qq update \ RUN wget -q https://bootstrap.pypa.io/get-pip.py -O get-pip.py \ && python3 get-pip.py "pip" -RUN if [ "${TARGETARCH}" = "arm" ]; \ - then echo "[global]" > /etc/pip.conf \ - && echo "extra-index-url=https://www.piwheels.org/simple" >> /etc/pip.conf; \ - fi - COPY requirements.txt /requirements.txt RUN pip3 install -r requirements.txt @@ -207,6 +202,10 @@ FROM deps AS devcontainer # But start a fake service for simulating the logs COPY docker/fake_frigate_run /etc/s6-overlay/s6-rc.d/frigate/run +# Create symbolic link to the frigate source code, as go2rtc's create_config.sh uses it +RUN mkdir -p /opt/frigate \ + && ln -svf /workspace/frigate/frigate /opt/frigate/frigate + # Install Node 16 RUN apt-get update \ && apt-get install wget -y \ diff --git a/Makefile b/Makefile index 49281b550..9035a58f4 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ default_target: local COMMIT_HASH := $(shell git log -1 --pretty=format:"%h"|tail -1) -VERSION = 0.12.0 +VERSION = 0.13.0 IMAGE_REPO ?= ghcr.io/blakeblackshear/frigate CURRENT_UID := $(shell id -u) CURRENT_GID := $(shell id -g) @@ -22,14 +22,11 @@ amd64: arm64: docker buildx build --platform linux/arm64 --target=frigate --tag $(IMAGE_REPO):$(VERSION)-$(COMMIT_HASH) . -armv7: - docker buildx build --platform linux/arm/v7 --target=frigate --tag $(IMAGE_REPO):$(VERSION)-$(COMMIT_HASH) . - -build: version amd64 arm64 armv7 - docker buildx build --platform linux/arm/v7,linux/arm64/v8,linux/amd64 --target=frigate --tag $(IMAGE_REPO):$(VERSION)-$(COMMIT_HASH) . +build: version amd64 arm64 + docker buildx build --platform linux/arm64/v8,linux/amd64 --target=frigate --tag $(IMAGE_REPO):$(VERSION)-$(COMMIT_HASH) . push: build - docker buildx build --push --platform linux/arm/v7,linux/arm64/v8,linux/amd64 --target=frigate --tag $(IMAGE_REPO):${GITHUB_REF_NAME}-$(COMMIT_HASH) . + docker buildx build --push --platform linux/arm64/v8,linux/amd64 --target=frigate --tag $(IMAGE_REPO):${GITHUB_REF_NAME}-$(COMMIT_HASH) . docker buildx build --push --platform linux/amd64 --target=frigate-tensorrt --tag $(IMAGE_REPO):${GITHUB_REF_NAME}-$(COMMIT_HASH)-tensorrt . run: local diff --git a/docker/install_deps.sh b/docker/install_deps.sh index 5e19b5217..18ed95319 100755 --- a/docker/install_deps.sh +++ b/docker/install_deps.sh @@ -37,15 +37,6 @@ if [[ "${TARGETARCH}" == "amd64" ]]; then rm -rf btbn-ffmpeg.tar.xz /usr/lib/btbn-ffmpeg/doc /usr/lib/btbn-ffmpeg/bin/ffplay fi -# ffmpeg -> arm32 -if [[ "${TARGETARCH}" == "arm" ]]; then - # add raspberry pi repo - gpg --no-default-keyring --keyring /usr/share/keyrings/raspbian.gpg --keyserver keyserver.ubuntu.com --recv-keys 9165938D90FDDD2E - echo "deb [signed-by=/usr/share/keyrings/raspbian.gpg] http://raspbian.raspberrypi.org/raspbian/ bullseye main contrib non-free rpi" | tee /etc/apt/sources.list.d/raspi.list - apt-get -qq update - apt-get -qq install --no-install-recommends --no-install-suggests -y ffmpeg -fi - # ffmpeg -> arm64 if [[ "${TARGETARCH}" == "arm64" ]]; then # add raspberry pi repo @@ -64,6 +55,9 @@ if [[ "${TARGETARCH}" == "amd64" ]]; then apt-get -qq install --no-install-recommends --no-install-suggests -y \ intel-opencl-icd \ mesa-va-drivers libva-drm2 intel-media-va-driver-non-free i965-va-driver libmfx1 radeontop intel-gpu-tools + # something about this dependency requires it to be installed in a separate call rather than in the line above + apt-get -qq install --no-install-recommends --no-install-suggests -y \ + i965-va-driver-shaders rm -f /etc/apt/sources.list.d/debian-testing.list fi @@ -72,16 +66,6 @@ if [[ "${TARGETARCH}" == "arm64" ]]; then libva-drm2 mesa-va-drivers fi -# not sure why 32bit arm requires all these -if [[ "${TARGETARCH}" == "arm" ]]; then - apt-get -qq install --no-install-recommends --no-install-suggests -y \ - libgtk-3-dev \ - libavcodec-dev libavformat-dev libswscale-dev libv4l-dev \ - libxvidcore-dev libx264-dev libjpeg-dev libpng-dev libtiff-dev \ - gfortran openexr libatlas-base-dev libtbb-dev libdc1394-22-dev libopenexr-dev \ - libgstreamer-plugins-base1.0-dev libgstreamer1.0-dev -fi - apt-get purge gnupg apt-transport-https wget xz-utils -y apt-get clean autoclean -y apt-get autoremove --purge -y diff --git a/docker/install_s6_overlay.sh b/docker/install_s6_overlay.sh index dc032179c..4e858ef07 100755 --- a/docker/install_s6_overlay.sh +++ b/docker/install_s6_overlay.sh @@ -2,12 +2,10 @@ set -euxo pipefail -s6_version="3.1.2.1" +s6_version="3.1.4.1" if [[ "${TARGETARCH}" == "amd64" ]]; then s6_arch="x86_64" -elif [[ "${TARGETARCH}" == "arm" ]]; then - s6_arch="armhf" elif [[ "${TARGETARCH}" == "arm64" ]]; then s6_arch="aarch64" fi diff --git a/docker/rootfs/etc/s6-overlay/s6-rc.d/frigate/finish b/docker/rootfs/etc/s6-overlay/s6-rc.d/frigate/finish index 86f5ea33f..75869b5e7 100755 --- a/docker/rootfs/etc/s6-overlay/s6-rc.d/frigate/finish +++ b/docker/rootfs/etc/s6-overlay/s6-rc.d/frigate/finish @@ -4,6 +4,8 @@ set -o errexit -o nounset -o pipefail +# Logs should be sent to stdout so that s6 can collect them + declare exit_code_container exit_code_container=$(cat /run/s6-linux-init-container-results/exitcode) readonly exit_code_container @@ -11,20 +13,16 @@ readonly exit_code_service="${1}" readonly exit_code_signal="${2}" readonly service="Frigate" -echo "[INFO] Service ${service} exited with code ${exit_code_service} (by signal ${exit_code_signal})" >&2 +echo "[INFO] Service ${service} exited with code ${exit_code_service} (by signal ${exit_code_signal})" if [[ "${exit_code_service}" -eq 256 ]]; then if [[ "${exit_code_container}" -eq 0 ]]; then - echo $((128 + exit_code_signal)) > /run/s6-linux-init-container-results/exitcode + echo $((128 + exit_code_signal)) >/run/s6-linux-init-container-results/exitcode fi elif [[ "${exit_code_service}" -ne 0 ]]; then if [[ "${exit_code_container}" -eq 0 ]]; then - echo "${exit_code_service}" > /run/s6-linux-init-container-results/exitcode + echo "${exit_code_service}" >/run/s6-linux-init-container-results/exitcode fi -else - # Exit code 0 is expected when Frigate is restarted by the user. In this case, - # we create a signal for the go2rtc finish script to tolerate the restart. - touch /dev/shm/restarting-frigate fi exec /run/s6/basedir/bin/halt diff --git a/docker/rootfs/etc/s6-overlay/s6-rc.d/frigate/run b/docker/rootfs/etc/s6-overlay/s6-rc.d/frigate/run index efaef61dc..6c1c1a442 100755 --- a/docker/rootfs/etc/s6-overlay/s6-rc.d/frigate/run +++ b/docker/rootfs/etc/s6-overlay/s6-rc.d/frigate/run @@ -4,6 +4,8 @@ set -o errexit -o nounset -o pipefail +# Logs should be sent to stdout so that s6 can collect them + # Tell S6-Overlay not to restart this service s6-svc -O . @@ -14,7 +16,7 @@ function migrate_db_path() { if [[ -f "${config_file_yaml}" ]]; then config_file="${config_file_yaml}" elif [[ ! -f "${config_file}" ]]; then - echo "[ERROR] Frigate config file not found" >&2 + echo "[ERROR] Frigate config file not found" return 1 fi unset config_file_yaml @@ -29,23 +31,23 @@ function migrate_db_path() { if [[ -f "${previous_db_path}" ]]; then if mountpoint --quiet "${new_db_dir}"; then # /config is a mount point, move the db - echo "[INFO] Moving db from '${previous_db_path}' to the '${new_db_dir}' dir..." >&2 + echo "[INFO] Moving db from '${previous_db_path}' to the '${new_db_dir}' dir..." # Move all files that starts with frigate.db to the new directory mv -vf "${previous_db_path}"* "${new_db_dir}" else - echo "[ERROR] Trying to migrate the db path from '${previous_db_path}' to the '${new_db_dir}' dir, but '${new_db_dir}' is not a mountpoint, please mount the '${new_db_dir}' dir" >&2 + echo "[ERROR] Trying to migrate the db path from '${previous_db_path}' to the '${new_db_dir}' dir, but '${new_db_dir}' is not a mountpoint, please mount the '${new_db_dir}' dir" return 1 fi fi fi } -echo "[INFO] Preparing Frigate..." >&2 +echo "[INFO] Preparing Frigate..." migrate_db_path -echo "[INFO] Starting Frigate..." >&2 +echo "[INFO] Starting Frigate..." -cd /opt/frigate || echo "[ERROR] Failed to change working directory to /opt/frigate" >&2 +cd /opt/frigate || echo "[ERROR] Failed to change working directory to /opt/frigate" # Replace the bash process with the Frigate process, redirecting stderr to stdout exec 2>&1 diff --git a/docker/rootfs/etc/s6-overlay/s6-rc.d/go2rtc-healthcheck/dependencies.d/go2rtc b/docker/rootfs/etc/s6-overlay/s6-rc.d/go2rtc-healthcheck/dependencies.d/go2rtc new file mode 100644 index 000000000..e69de29bb diff --git a/docker/rootfs/etc/s6-overlay/s6-rc.d/go2rtc-healthcheck/finish b/docker/rootfs/etc/s6-overlay/s6-rc.d/go2rtc-healthcheck/finish new file mode 100755 index 000000000..f83421640 --- /dev/null +++ b/docker/rootfs/etc/s6-overlay/s6-rc.d/go2rtc-healthcheck/finish @@ -0,0 +1,12 @@ +#!/command/with-contenv bash +# shellcheck shell=bash + +set -o errexit -o nounset -o pipefail + +# Logs should be sent to stdout so that s6 can collect them + +readonly exit_code_service="${1}" +readonly exit_code_signal="${2}" +readonly service="go2rtc-healthcheck" + +echo "[INFO] The ${service} service exited with code ${exit_code_service} (by signal ${exit_code_signal})" diff --git a/docker/rootfs/etc/s6-overlay/s6-rc.d/go2rtc-healthcheck/producer-for b/docker/rootfs/etc/s6-overlay/s6-rc.d/go2rtc-healthcheck/producer-for new file mode 100644 index 000000000..20fbc45f8 --- /dev/null +++ b/docker/rootfs/etc/s6-overlay/s6-rc.d/go2rtc-healthcheck/producer-for @@ -0,0 +1 @@ +go2rtc-log diff --git a/docker/rootfs/etc/s6-overlay/s6-rc.d/go2rtc-healthcheck/run b/docker/rootfs/etc/s6-overlay/s6-rc.d/go2rtc-healthcheck/run new file mode 100755 index 000000000..3a6e423e5 --- /dev/null +++ b/docker/rootfs/etc/s6-overlay/s6-rc.d/go2rtc-healthcheck/run @@ -0,0 +1,22 @@ +#!/command/with-contenv bash +# shellcheck shell=bash +# Start the go2rtc-healthcheck service + +set -o errexit -o nounset -o pipefail + +# Logs should be sent to stdout so that s6 can collect them + +# Give some additional time for go2rtc to start before start pinging +sleep 10s +echo "[INFO] Starting go2rtc healthcheck service..." + +while sleep 30s; do + # Check if the service is running + if ! curl --connect-timeout 10 --fail --silent --show-error --output /dev/null http://127.0.0.1:1984/api/streams 2>&1; then + echo "[ERROR] The go2rtc service is not responding to ping, restarting..." + # We can also use -r instead of -t to send kill signal rather than term + s6-svc -t /var/run/service/go2rtc 2>&1 + # Give some additional time to go2rtc to restart before start pinging again + sleep 10s + fi +done diff --git a/docker/rootfs/etc/s6-overlay/s6-rc.d/go2rtc-healthcheck/timeout-kill b/docker/rootfs/etc/s6-overlay/s6-rc.d/go2rtc-healthcheck/timeout-kill new file mode 100644 index 000000000..e9c02dad1 --- /dev/null +++ b/docker/rootfs/etc/s6-overlay/s6-rc.d/go2rtc-healthcheck/timeout-kill @@ -0,0 +1 @@ +5000 diff --git a/docker/rootfs/etc/s6-overlay/s6-rc.d/go2rtc-healthcheck/type b/docker/rootfs/etc/s6-overlay/s6-rc.d/go2rtc-healthcheck/type new file mode 100644 index 000000000..5883cff0c --- /dev/null +++ b/docker/rootfs/etc/s6-overlay/s6-rc.d/go2rtc-healthcheck/type @@ -0,0 +1 @@ +longrun diff --git a/docker/rootfs/etc/s6-overlay/s6-rc.d/go2rtc-log/consumer-for b/docker/rootfs/etc/s6-overlay/s6-rc.d/go2rtc-log/consumer-for index 02b16a879..bdd482e42 100644 --- a/docker/rootfs/etc/s6-overlay/s6-rc.d/go2rtc-log/consumer-for +++ b/docker/rootfs/etc/s6-overlay/s6-rc.d/go2rtc-log/consumer-for @@ -1 +1,2 @@ go2rtc +go2rtc-healthcheck diff --git a/docker/rootfs/etc/s6-overlay/s6-rc.d/go2rtc/finish b/docker/rootfs/etc/s6-overlay/s6-rc.d/go2rtc/finish index c5fa99114..e95ba75c8 100755 --- a/docker/rootfs/etc/s6-overlay/s6-rc.d/go2rtc/finish +++ b/docker/rootfs/etc/s6-overlay/s6-rc.d/go2rtc/finish @@ -1,32 +1,12 @@ #!/command/with-contenv bash # shellcheck shell=bash -# Take down the S6 supervision tree when the service exits set -o errexit -o nounset -o pipefail -declare exit_code_container -exit_code_container=$(cat /run/s6-linux-init-container-results/exitcode) -readonly exit_code_container +# Logs should be sent to stdout so that s6 can collect them + readonly exit_code_service="${1}" readonly exit_code_signal="${2}" readonly service="go2rtc" -echo "[INFO] Service ${service} exited with code ${exit_code_service} (by signal ${exit_code_signal})" >&2 - -if [[ "${exit_code_service}" -eq 256 ]]; then - if [[ "${exit_code_container}" -eq 0 ]]; then - echo $((128 + exit_code_signal)) > /run/s6-linux-init-container-results/exitcode - fi -elif [[ "${exit_code_service}" -ne 0 ]]; then - if [[ "${exit_code_container}" -eq 0 ]]; then - echo "${exit_code_service}" > /run/s6-linux-init-container-results/exitcode - fi -else - # go2rtc is not supposed to exit, so even when it exits with 0 we make the - # container with 1. We only tolerate it when Frigate is restarting. - if [[ "${exit_code_container}" -eq 0 && ! -f /dev/shm/restarting-frigate ]]; then - echo "1" > /run/s6-linux-init-container-results/exitcode - fi -fi - -exec /run/s6/basedir/bin/halt +echo "[INFO] The ${service} service exited with code ${exit_code_service} (by signal ${exit_code_signal})" diff --git a/docker/rootfs/etc/s6-overlay/s6-rc.d/go2rtc/run b/docker/rootfs/etc/s6-overlay/s6-rc.d/go2rtc/run index 62fbe33ad..85c8f9526 100755 --- a/docker/rootfs/etc/s6-overlay/s6-rc.d/go2rtc/run +++ b/docker/rootfs/etc/s6-overlay/s6-rc.d/go2rtc/run @@ -4,8 +4,7 @@ set -o errexit -o nounset -o pipefail -# Tell S6-Overlay not to restart this service -s6-svc -O . +# Logs should be sent to stdout so that s6 can collect them function get_ip_and_port_from_supervisor() { local ip_address @@ -19,9 +18,9 @@ function get_ip_and_port_from_supervisor() { jq --exit-status --raw-output '.data.ipv4.address[0]' ) && [[ "${ip_address}" =~ ${ip_regex} ]]; then ip_address="${BASH_REMATCH[1]}" - echo "[INFO] Got IP address from supervisor: ${ip_address}" >&2 + echo "[INFO] Got IP address from supervisor: ${ip_address}" else - echo "[WARN] Failed to get IP address from supervisor" >&2 + echo "[WARN] Failed to get IP address from supervisor" return 0 fi @@ -35,26 +34,37 @@ function get_ip_and_port_from_supervisor() { jq --exit-status --raw-output '.data.network["8555/tcp"]' ) && [[ "${webrtc_port}" =~ ${port_regex} ]]; then webrtc_port="${BASH_REMATCH[1]}" - echo "[INFO] Got WebRTC port from supervisor: ${ip_address}" >&2 + echo "[INFO] Got WebRTC port from supervisor: ${webrtc_port}" else - echo "[WARN] Failed to get WebRTC port from supervisor" >&2 + echo "[WARN] Failed to get WebRTC port from supervisor" return 0 fi export FRIGATE_GO2RTC_WEBRTC_CANDIDATE_INTERNAL="${ip_address}:${webrtc_port}" } -echo "[INFO] Preparing go2rtc config..." >&2 +if [[ ! -f "/dev/shm/go2rtc.yaml" ]]; then + echo "[INFO] Preparing go2rtc config..." -if [[ -n "${SUPERVISOR_TOKEN:-}" ]]; then - # Running as a Home Assistant add-on, infer the IP address and port - get_ip_and_port_from_supervisor + if [[ -n "${SUPERVISOR_TOKEN:-}" ]]; then + # Running as a Home Assistant add-on, infer the IP address and port + get_ip_and_port_from_supervisor + fi + + python3 /usr/local/go2rtc/create_config.py fi -raw_config=$(python3 /usr/local/go2rtc/create_config.py) +readonly config_path="/config" -echo "[INFO] Starting go2rtc..." >&2 +if [[ -x "${config_path}/go2rtc" ]]; then + readonly binary_path="${config_path}/go2rtc" + echo "[WARN] Using go2rtc binary from '${binary_path}' instead of the embedded one" +else + readonly binary_path="/usr/local/go2rtc/bin/go2rtc" +fi + +echo "[INFO] Starting go2rtc..." # Replace the bash process with the go2rtc process, redirecting stderr to stdout exec 2>&1 -exec go2rtc -config="${raw_config}" +exec "${binary_path}" -config=/dev/shm/go2rtc.yaml diff --git a/docker/rootfs/etc/s6-overlay/s6-rc.d/nginx/finish b/docker/rootfs/etc/s6-overlay/s6-rc.d/nginx/finish index c28725f62..d147d74bd 100755 --- a/docker/rootfs/etc/s6-overlay/s6-rc.d/nginx/finish +++ b/docker/rootfs/etc/s6-overlay/s6-rc.d/nginx/finish @@ -4,6 +4,8 @@ set -o errexit -o nounset -o pipefail +# Logs should be sent to stdout so that s6 can collect them + declare exit_code_container exit_code_container=$(cat /run/s6-linux-init-container-results/exitcode) readonly exit_code_container @@ -11,18 +13,18 @@ readonly exit_code_service="${1}" readonly exit_code_signal="${2}" readonly service="NGINX" -echo "[INFO] Service ${service} exited with code ${exit_code_service} (by signal ${exit_code_signal})" >&2 +echo "[INFO] Service ${service} exited with code ${exit_code_service} (by signal ${exit_code_signal})" if [[ "${exit_code_service}" -eq 256 ]]; then if [[ "${exit_code_container}" -eq 0 ]]; then - echo $((128 + exit_code_signal)) > /run/s6-linux-init-container-results/exitcode + echo $((128 + exit_code_signal)) >/run/s6-linux-init-container-results/exitcode fi if [[ "${exit_code_signal}" -eq 15 ]]; then exec /run/s6/basedir/bin/halt fi elif [[ "${exit_code_service}" -ne 0 ]]; then if [[ "${exit_code_container}" -eq 0 ]]; then - echo "${exit_code_service}" > /run/s6-linux-init-container-results/exitcode + echo "${exit_code_service}" >/run/s6-linux-init-container-results/exitcode fi exec /run/s6/basedir/bin/halt fi diff --git a/docker/rootfs/etc/s6-overlay/s6-rc.d/nginx/run b/docker/rootfs/etc/s6-overlay/s6-rc.d/nginx/run index f7a5a6d0a..2754c0d09 100755 --- a/docker/rootfs/etc/s6-overlay/s6-rc.d/nginx/run +++ b/docker/rootfs/etc/s6-overlay/s6-rc.d/nginx/run @@ -4,7 +4,9 @@ set -o errexit -o nounset -o pipefail -echo "[INFO] Starting NGINX..." >&2 +# Logs should be sent to stdout so that s6 can collect them + +echo "[INFO] Starting NGINX..." # Replace the bash process with the NGINX process, redirecting stderr to stdout exec 2>&1 diff --git a/docker/rootfs/usr/local/go2rtc/create_config.py b/docker/rootfs/usr/local/go2rtc/create_config.py index 624415633..d201eb381 100644 --- a/docker/rootfs/usr/local/go2rtc/create_config.py +++ b/docker/rootfs/usr/local/go2rtc/create_config.py @@ -5,8 +5,13 @@ import os import sys import yaml +sys.path.insert(0, "/opt/frigate") +from frigate.const import BIRDSEYE_PIPE, BTBN_PATH +from frigate.ffmpeg_presets import parse_preset_hardware_acceleration_encode + +sys.path.remove("/opt/frigate") + -BTBN_PATH = "/usr/lib/btbn-ffmpeg" FRIGATE_ENV_VARS = {k: v for k, v in os.environ.items() if k.startswith("FRIGATE_")} config_file = os.environ.get("CONFIG_FILE", "/config/config.yml") @@ -19,12 +24,18 @@ with open(config_file) as f: raw_config = f.read() if config_file.endswith((".yaml", ".yml")): - config = yaml.safe_load(raw_config) + config: dict[str, any] = yaml.safe_load(raw_config) elif config_file.endswith(".json"): - config = json.loads(raw_config) + config: dict[str, any] = json.loads(raw_config) go2rtc_config: dict[str, any] = config.get("go2rtc", {}) +# Need to enable CORS for go2rtc so the frigate integration / card work automatically +if go2rtc_config.get("api") is None: + go2rtc_config["api"] = {"origin": "*"} +elif go2rtc_config["api"].get("origin") is None: + go2rtc_config["api"]["origin"] = "*" + # we want to ensure that logs are easy to read if go2rtc_config.get("log") is None: go2rtc_config["log"] = {"format": "text"} @@ -34,7 +45,9 @@ elif go2rtc_config["log"].get("format") is None: if not go2rtc_config.get("webrtc", {}).get("candidates", []): default_candidates = [] # use internal candidate if it was discovered when running through the add-on - internal_candidate = os.environ.get("FRIGATE_GO2RTC_WEBRTC_CANDIDATE_INTERNAL", None) + internal_candidate = os.environ.get( + "FRIGATE_GO2RTC_WEBRTC_CANDIDATE_INTERNAL", None + ) if internal_candidate is not None: default_candidates.append(internal_candidate) # should set default stun server so webrtc can work @@ -42,7 +55,17 @@ if not go2rtc_config.get("webrtc", {}).get("candidates", []): go2rtc_config["webrtc"] = {"candidates": default_candidates} else: - print("[INFO] Not injecting WebRTC candidates into go2rtc config as it has been set manually", file=sys.stderr) + print( + "[INFO] Not injecting WebRTC candidates into go2rtc config as it has been set manually", + ) + +# sets default RTSP response to be equivalent to ?video=h264,h265&audio=aac +# this means user does not need to specify audio codec when using restream +# as source for frigate and the integration supports HLS playback +if go2rtc_config.get("rtsp") is None: + go2rtc_config["rtsp"] = {"default_query": "mp4"} +elif go2rtc_config["rtsp"].get("default_query") is None: + go2rtc_config["rtsp"]["default_query"] = "mp4" # need to replace ffmpeg command when using ffmpeg4 if not os.path.exists(BTBN_PATH): @@ -54,14 +77,30 @@ if not os.path.exists(BTBN_PATH): go2rtc_config["ffmpeg"][ "rtsp" ] = "-fflags nobuffer -flags low_delay -stimeout 5000000 -user_agent go2rtc/ffmpeg -rtsp_transport tcp -i {input}" - + for name in go2rtc_config.get("streams", {}): stream = go2rtc_config["streams"][name] if isinstance(stream, str): - go2rtc_config["streams"][name] = go2rtc_config["streams"][name].format(**FRIGATE_ENV_VARS) + go2rtc_config["streams"][name] = go2rtc_config["streams"][name].format( + **FRIGATE_ENV_VARS + ) elif isinstance(stream, list): for i, stream in enumerate(stream): go2rtc_config["streams"][name][i] = stream.format(**FRIGATE_ENV_VARS) -print(json.dumps(go2rtc_config)) +# add birdseye restream stream if enabled +if config.get("birdseye", {}).get("restream", False): + birdseye: dict[str, any] = config.get("birdseye") + + input = f"-f rawvideo -pix_fmt yuv420p -video_size {birdseye.get('width', 1280)}x{birdseye.get('height', 720)} -r 10 -i {BIRDSEYE_PIPE}" + ffmpeg_cmd = f"exec:{parse_preset_hardware_acceleration_encode(config.get('ffmpeg', {}).get('hwaccel_args'), input, '-rtsp_transport tcp -f rtsp {output}')}" + + if go2rtc_config.get("streams"): + go2rtc_config["streams"]["birdseye"] = ffmpeg_cmd + else: + go2rtc_config["streams"] = {"birdseye": ffmpeg_cmd} + +# Write go2rtc_config to /dev/shm/go2rtc.yaml +with open("/dev/shm/go2rtc.yaml", "w") as f: + yaml.dump(go2rtc_config, f) diff --git a/docs/docs/configuration/camera_specific.md b/docs/docs/configuration/camera_specific.md index d61d5cbd9..8de3837f5 100644 --- a/docs/docs/configuration/camera_specific.md +++ b/docs/docs/configuration/camera_specific.md @@ -16,7 +16,7 @@ Note that mjpeg cameras require encoding the video into h264 for recording, and ```yaml go2rtc: streams: - mjpeg_cam: ffmpeg:{your_mjpeg_stream_url}#video=h264#hardware # <- use hardware acceleration to create an h264 stream usable for other components. + mjpeg_cam: "ffmpeg:{your_mjpeg_stream_url}#video=h264#hardware" # <- use hardware acceleration to create an h264 stream usable for other components. cameras: ... @@ -110,7 +110,7 @@ go2rtc: streams: reolink: - http://reolink_ip/flv?port=1935&app=bcs&stream=channel0_main.bcs&user=username&password=password - - ffmpeg:reolink#audio=opus + - "ffmpeg:reolink#audio=opus" reolink_sub: - http://reolink_ip/flv?port=1935&app=bcs&stream=channel0_ext.bcs&user=username&password=password @@ -126,19 +126,28 @@ cameras: input_args: preset-rtsp-restream roles: - detect - detect: - width: 896 - height: 672 - fps: 7 ``` ### Unifi Protect Cameras -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. +Unifi protect cameras require the rtspx stream to be used with go2rtc. +To utilize a Unifi protect camera, modify the rtsps link to begin with rtspx. +Additionally, remove the "?enableSrtp" from the end of the Unifi link. + +```yaml +go2rtc: + streams: + front: + - rtspx://192.168.1.1:7441/abcdefghijk +``` + +[See the go2rtc docs for more information](https://github.com/AlexxIT/go2rtc/tree/v1.2.0#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. ```yaml ffmpeg: output_args: record: preset-record-ubiquiti - rtmp: preset-rtmp-ubiquiti + rtmp: preset-rtmp-ubiquiti # recommend using go2rtc instead ``` diff --git a/docs/docs/configuration/detectors.md b/docs/docs/configuration/detectors.md index 69e4869ea..b7f442c31 100644 --- a/docs/docs/configuration/detectors.md +++ b/docs/docs/configuration/detectors.md @@ -101,7 +101,7 @@ The OpenVINO device to be used is specified using the `"device"` attribute accor OpenVINO is supported on 6th Gen Intel platforms (Skylake) and newer. A supported Intel platform is required to use the `GPU` device with OpenVINO. The `MYRIAD` device may be run on any platform, including Arm devices. For detailed system requirements, see [OpenVINO System Requirements](https://www.intel.com/content/www/us/en/developer/tools/openvino-toolkit/system-requirements.html) -An OpenVINO model is provided in the container at `/openvino-model/ssdlite_mobilenet_v2.xml` and is used by this detector type by default. The model comes from Intel's Open Model Zoo [SSDLite MobileNet V2](https://github.com/openvinotoolkit/open_model_zoo/tree/master/models/public/ssdlite_mobilenet_v2) and is converted to an FP16 precision IR model. Use the model configuration shown below when using the OpenVINO detector. +An OpenVINO model is provided in the container at `/openvino-model/ssdlite_mobilenet_v2.xml` and is used by this detector type by default. The model comes from Intel's Open Model Zoo [SSDLite MobileNet V2](https://github.com/openvinotoolkit/open_model_zoo/tree/master/models/public/ssdlite_mobilenet_v2) and is converted to an FP16 precision IR model. Use the model configuration shown below when using the OpenVINO detector with the default model. ```yaml detectors: @@ -119,6 +119,25 @@ model: labelmap_path: /openvino-model/coco_91cl_bkgr.txt ``` +This detector also supports some YOLO variants: YOLOX, YOLOv5, and YOLOv8 specifically. Other YOLO variants are not officially supported/tested. Frigate does not come with any yolo models preloaded, so you will need to supply your own models. This detector has been verified to work with the [yolox_tiny](https://github.com/openvinotoolkit/open_model_zoo/tree/master/models/public/yolox-tiny) model from Intel's Open Model Zoo. You can follow [these instructions](https://github.com/openvinotoolkit/open_model_zoo/tree/master/models/public/yolox-tiny#download-a-model-and-convert-it-into-openvino-ir-format) to retrieve the OpenVINO-compatible `yolox_tiny` model. Make sure that the model input dimensions match the `width` and `height` parameters, and `model_type` is set accordingly. See [Full Configuration Reference](/configuration/index.md#full-configuration-reference) for a list of possible `model_type` options. Below is an example of how `yolox_tiny` can be used in Frigate: + +```yaml +detectors: + ov: + type: openvino + device: AUTO + model: + path: /path/to/yolox_tiny.xml + +model: + width: 416 + height: 416 + input_tensor: nchw + input_pixel_format: bgr + model_type: yolox + labelmap_path: /path/to/coco_80cl.txt +``` + ### Intel NCS2 VPU and Myriad X Setup Intel produces a neural net inference accelleration chip called Myriad X. This chip was sold in their Neural Compute Stick 2 (NCS2) which has been discontinued. If intending to use the MYRIAD device for accelleration, additional setup is required to pass through the USB device. The host needs a udev rule installed to handle the NCS2 device. @@ -212,6 +231,10 @@ yolov4x-mish-320 yolov4x-mish-640 yolov7-tiny-288 yolov7-tiny-416 +yolov7-640 +yolov7-320 +yolov7x-640 +yolov7x-320 ``` ### Configuration Parameters diff --git a/docs/docs/configuration/ffmpeg_presets.md b/docs/docs/configuration/ffmpeg_presets.md index 36df0f50d..66747350e 100644 --- a/docs/docs/configuration/ffmpeg_presets.md +++ b/docs/docs/configuration/ffmpeg_presets.md @@ -28,16 +28,17 @@ Input args presets help make the config more readable and handle use cases for d See [the camera specific docs](/configuration/camera_specific.md) for more info on non-standard cameras and recommendations for using them in Frigate. -| Preset | Usage | Other Notes | -| ------------------------- | ------------------------- | --------------------------------------------------- | -| preset-http-jpeg-generic | HTTP Live Jpeg | Recommend restreaming live jpeg instead | -| preset-http-mjpeg-generic | HTTP Mjpeg Stream | Recommend restreaming mjpeg stream instead | -| preset-http-reolink | Reolink HTTP-FLV Stream | Only for reolink http, not when restreaming as rtsp | -| preset-rtmp-generic | RTMP Stream | | -| preset-rtsp-generic | RTSP Stream | This is the default when nothing is specified | -| preset-rtsp-restream | RTSP Stream from restream | Use when using rtsp restream as source | -| preset-rtsp-udp | RTSP Stream via UDP | Use when camera is UDP only | -| preset-rtsp-blue-iris | Blue Iris RTSP Stream | Use when consuming a stream from Blue Iris | +| Preset | Usage | Other Notes | +| -------------------------------- | ------------------------- | ------------------------------------------------------------------------------------------------ | +| preset-http-jpeg-generic | HTTP Live Jpeg | Recommend restreaming live jpeg instead | +| preset-http-mjpeg-generic | HTTP Mjpeg Stream | Recommend restreaming mjpeg stream instead | +| preset-http-reolink | Reolink HTTP-FLV Stream | Only for reolink http, not when restreaming as rtsp | +| preset-rtmp-generic | RTMP Stream | | +| preset-rtsp-generic | RTSP Stream | This is the default when nothing is specified | +| preset-rtsp-restream | RTSP Stream from restream | Use for rtsp restream as source for frigate | +| preset-rtsp-restream-low-latency | RTSP Stream from restream | Use for rtsp restream as source for frigate to lower latency, may cause issues with some cameras | +| preset-rtsp-udp | RTSP Stream via UDP | Use when camera is UDP only | +| preset-rtsp-blue-iris | Blue Iris RTSP Stream | Use when consuming a stream from Blue Iris | :::caution @@ -46,21 +47,22 @@ It is important to be mindful of input args when using restream because you can ::: ```yaml +go2rtc: + streams: + reolink_cam: http://192.168.0.139/flv?port=1935&app=bcs&stream=channel0_main.bcs&user=admin&password=password + cameras: reolink_cam: ffmpeg: inputs: - - path: http://192.168.0.139/flv?port=1935&app=bcs&stream=channel0_ext.bcs&user=admin&password={FRIGATE_CAM_PASSWORD} + - path: http://192.168.0.139/flv?port=1935&app=bcs&stream=channel0_ext.bcs&user=admin&password=password input_args: preset-http-reolink roles: - detect - - path: rtsp://192.168.0.10:8554/garage + - path: rtsp://127.0.0.1:8554/reolink_cam input_args: preset-rtsp-generic roles: - record - - path: http://192.168.0.139/flv?port=1935&app=bcs&stream=channel0_main.bcs&user=admin&password={FRIGATE_CAM_PASSWORD} - roles: - - restream ``` ### Output Args Presets diff --git a/docs/docs/configuration/hardware_acceleration.md b/docs/docs/configuration/hardware_acceleration.md index 7bf2123a9..3c16069cf 100644 --- a/docs/docs/configuration/hardware_acceleration.md +++ b/docs/docs/configuration/hardware_acceleration.md @@ -15,23 +15,39 @@ ffmpeg: hwaccel_args: preset-rpi-64-h264 ``` -### Intel-based CPUs (<10th Generation) via Quicksync +### Intel-based CPUs (<10th Generation) via VAAPI + +VAAPI supports automatic profile selection so it will work automatically with both H.264 and H.265 streams. VAAPI is recommended for all generations of Intel-based CPUs if QSV does not work. ```yaml ffmpeg: hwaccel_args: preset-vaapi ``` + **NOTICE**: With some of the processors, like the J4125, the default driver `iHD` doesn't seem to work correctly for hardware acceleration. You may need to change the driver to `i965` by adding the following environment variable `LIBVA_DRIVER_NAME=i965` to your docker-compose file or [in the `frigate.yaml` for HA OS users](advanced.md#environment_vars). ### Intel-based CPUs (>=10th Generation) via Quicksync +QSV must be set specifically based on the video encoding of the stream. + +#### H.264 streams + ```yaml ffmpeg: hwaccel_args: preset-intel-qsv-h264 ``` +#### H.265 streams + +```yaml +ffmpeg: + hwaccel_args: preset-intel-qsv-h265 +``` + ### AMD/ATI GPUs (Radeon HD 2000 and newer GPUs) via libva-mesa-driver +VAAPI supports automatic profile selection so it will work automatically with both H.264 and H.265 streams. + **Note:** You also need to set `LIBVA_DRIVER_NAME=radeonsi` as an environment variable on the container. ```yaml diff --git a/docs/docs/configuration/index.md b/docs/docs/configuration/index.md index b33ebd40c..113884d6d 100644 --- a/docs/docs/configuration/index.md +++ b/docs/docs/configuration/index.md @@ -3,7 +3,7 @@ id: index title: Configuration File --- -For Home Assistant Addon installations, the config file needs to be in the root of your Home Assistant config directory (same location as `configuration.yaml`) and named `frigate.yaml`. +For Home Assistant Addon installations, the config file needs to be in the root of your Home Assistant config directory (same location as `configuration.yaml`). It can be named `frigate.yaml` or `frigate.yml`, but if both files exist `frigate.yaml` will be preferred and `frigate.yml` will be ignored. For all other installation types, the config file should be mapped to `/config/config.yml` inside the container. @@ -19,7 +19,6 @@ cameras: - path: rtsp://viewer:{FRIGATE_RTSP_PASSWORD}@10.0.10.10:554/cam/realmonitor?channel=1&subtype=2 roles: - detect - - restream detect: width: 1280 height: 720 @@ -37,6 +36,25 @@ It is not recommended to copy this full configuration file. Only specify values ::: +**Note:** The following values will be replaced at runtime by using environment variables + +- `{FRIGATE_MQTT_USER}` +- `{FRIGATE_MQTT_PASSWORD}` +- `{FRIGATE_RTSP_USER}` +- `{FRIGATE_RTSP_PASSWORD}` + +for example: + +```yaml +mqtt: + user: "{FRIGATE_MQTT_USER}" + password: "{FRIGATE_MQTT_PASSWORD}" +``` + +```yaml +- path: rtsp://{FRIGATE_RTSP_USER}:{FRIGATE_RTSP_PASSWORD}@10.0.10.10:8554/unicast +``` + ```yaml mqtt: # Optional: Enable mqtt server (default: shown below) @@ -105,6 +123,9 @@ model: # Optional: Object detection model input tensor format # Valid values are nhwc or nchw (default: shown below) input_tensor: nhwc + # Optional: Object detection model type, currently only used with the OpenVINO detector + # Valid values are ssd, yolox, yolov5, or yolov8 (default: shown below) + model_type: ssd # Optional: Label name modifications. These are merged into the standard labelmap. labelmap: 2: vehicle @@ -146,7 +167,7 @@ birdseye: # More information about presets at https://docs.frigate.video/configuration/ffmpeg_presets ffmpeg: # Optional: global ffmpeg args (default: shown below) - global_args: -hide_banner -loglevel warning + global_args: -hide_banner -loglevel warning -threads 2 # Optional: global hwaccel args (default: shown below) # NOTE: See hardware acceleration docs for your specific device hwaccel_args: [] @@ -155,7 +176,7 @@ ffmpeg: # Optional: global output args output_args: # Optional: output args for detect streams (default: shown below) - detect: -f rawvideo -pix_fmt yuv420p + detect: -threads 2 -f rawvideo -pix_fmt yuv420p # Optional: output args for record streams (default: shown below) record: preset-record-generic # Optional: output args for rtmp streams (default: shown below) @@ -172,7 +193,6 @@ detect: # NOTE: Recommended value of 5. Ideally, try and reduce your FPS on the camera. fps: 5 # Optional: enables detection for the camera (default: True) - # This value can be set via MQTT and will be updated in startup based on retained value enabled: True # Optional: Number of frames without a detection before Frigate considers an object to be gone. (default: 5x the frame rate) max_disappeared: 25 @@ -271,11 +291,6 @@ record: # Optional: Enable recording (default: shown below) # WARNING: If recording is disabled in the config, turning it on via # the UI or MQTT later will have no effect. - # WARNING: Frigate does not currently support limiting recordings based - # on available disk space automatically. If using recordings, - # you must specify retention settings for a number of days that - # will fit within the available disk space of your drive or Frigate - # will crash. enabled: False # Optional: Number of minutes to wait between cleanup runs (default: shown below) # This can be used to reduce the frequency of deleting recording segments from disk if you want to minimize i/o @@ -325,7 +340,6 @@ record: # NOTE: Can be overridden at the camera level snapshots: # Optional: Enable writing jpg snapshot to /media/frigate/clips (default: shown below) - # This value can be set via MQTT and will be updated in startup based on retained value enabled: False # Optional: save a clean PNG copy of the snapshot image (default: shown below) clean_copy: True @@ -355,7 +369,7 @@ rtmp: enabled: False # Optional: Restream configuration -# Uses https://github.com/AlexxIT/go2rtc (v1.0.1) +# Uses https://github.com/AlexxIT/go2rtc (v1.2.0) go2rtc: # Optional: jsmpeg stream configuration for WebUI @@ -410,12 +424,12 @@ cameras: # Required: the path to the stream # NOTE: path may include environment variables, which must begin with 'FRIGATE_' and be referenced in {} - path: rtsp://viewer:{FRIGATE_RTSP_PASSWORD}@10.0.10.10:554/cam/realmonitor?channel=1&subtype=2 - # Required: list of roles for this stream. valid values are: detect,record,restream,rtmp - # NOTICE: In addition to assigning the record, restream, and rtmp roles, + # Required: list of roles for this stream. valid values are: detect,record,rtmp + # NOTICE: In addition to assigning the record and rtmp roles, # they must also be enabled in the camera config. roles: - detect - - restream + - record - rtmp # Optional: stream specific global args (default: inherit) # global_args: @@ -488,9 +502,32 @@ ui: # Optional: Set the default live mode for cameras in the UI (default: shown below) live_mode: mse # Optional: Set a timezone to use in the UI (default: use browser local time) - timezone: None + # timezone: America/Denver # Optional: Use an experimental recordings / camera view UI (default: shown below) - experimental_ui: False + use_experimental: False + # Optional: Set the time format used. + # Options are browser, 12hour, or 24hour (default: shown below) + time_format: browser + # Optional: Set the date style for a specified length. + # Options are: full, long, medium, short + # Examples: + # short: 2/11/23 + # medium: Feb 11, 2023 + # full: Saturday, February 11, 2023 + # (default: shown below). + date_style: short + # Optional: Set the time style for a specified length. + # Options are: full, long, medium, short + # Examples: + # short: 8:14 PM + # medium: 8:15:22 PM + # full: 8:15:22 PM Mountain Standard Time + # (default: shown below). + time_style: medium + # Optional: Ability to manually override the date / time styling to use strftime format + # https://www.gnu.org/software/libc/manual/html_node/Formatting-Calendar-Time.html + # possible values are shown above (default: not set) + strftime_fmt: "%Y/%m/%d %H:%M" # Optional: Telemetry configuration telemetry: diff --git a/docs/docs/configuration/live.md b/docs/docs/configuration/live.md index 9a963748c..9cf30cd1a 100644 --- a/docs/docs/configuration/live.md +++ b/docs/docs/configuration/live.md @@ -3,17 +3,17 @@ id: live title: Live View --- -Frigate has different live view options, some of which require [restream](restream.md) to be enabled. +Frigate has different live view options, some of which require the bundled `go2rtc` to be configured as shown in the [step by step guide](/guides/configuring_go2rtc). ## Live View Options Live view options can be selected while viewing the live stream. The options are: -| Source | Latency | Frame Rate | Resolution | Audio | Requires Restream | Other Limitations | -| ------ | ------- | ------------------------------------- | -------------- | ---------------------------- | ----------------- | -------------------------------------------- | -| jsmpeg | low | same as `detect -> fps`, capped at 10 | same as detect | no | no | none | -| mse | low | native | native | yes (depends on audio codec) | yes | not supported on iOS, Firefox is h.264 only | -| webrtc | lowest | native | native | yes (depends on audio codec) | yes | requires extra config, doesn't support h.265 | +| Source | Latency | Frame Rate | Resolution | Audio | Requires go2rtc | Other Limitations | +| ------ | ------- | ------------------------------------- | -------------- | ---------------------------- | --------------- | -------------------------------------------- | +| jsmpeg | low | same as `detect -> fps`, capped at 10 | same as detect | no | no | none | +| mse | low | native | native | yes (depends on audio codec) | yes | not supported on iOS, Firefox is h.264 only | +| webrtc | lowest | native | native | yes (depends on audio codec) | yes | requires extra config, doesn't support h.265 | ### Audio Support @@ -24,9 +24,10 @@ go2rtc: streams: rtsp_cam: # <- for RTSP streams - rtsp://192.168.1.5:554/live0 # <- stream which supports video & aac audio - - ffmpeg:rtsp_cam#audio=opus # <- copy of the stream which transcodes audio to the missing codec (usually will be opus) + - "ffmpeg:rtsp_cam#audio=opus" # <- copy of the stream which transcodes audio to the missing codec (usually will be opus) http_cam: # <- for http streams - - "ffmpeg:http://192.168.50.155/flv?port=1935&app=bcs&stream=channel0_main.bcs&user=user&password=password#video=copy#audio=copy#audio=opus" # <- http streams must use ffmpeg to set all types + - http://192.168.50.155/flv?port=1935&app=bcs&stream=channel0_main.bcs&user=user&password=password # <- stream which supports video & aac audio + - "ffmpeg:http_cam#audio=opus" # <- copy of the stream which transcodes audio to the missing codec (usually will be opus) ``` ### Setting Stream For Live UI @@ -36,12 +37,12 @@ There may be some cameras that you would prefer to use the sub stream for live v ```yaml go2rtc: streams: - rtsp_cam: - - rtsp://192.168.1.5:554/live0 # <- stream which supports video & aac audio. This is only supported for rtsp streams, http must use ffmpeg - - ffmpeg:rtsp_cam#audio=opus # <- copy of the stream which transcodes audio to opus + rtsp_cam: + - rtsp://192.168.1.5:554/live0 # <- stream which supports video & aac audio. + - "ffmpeg:rtsp_cam#audio=opus" # <- copy of the stream which transcodes audio to opus rtsp_cam_sub: - - rtsp://192.168.1.5:554/substream # <- stream which supports video & aac audio. This is only supported for rtsp streams, http must use ffmpeg - - ffmpeg:rtsp_cam_sub#audio=opus # <- copy of the stream which transcodes audio to opus + - rtsp://192.168.1.5:554/substream # <- stream which supports video & aac audio. + - "ffmpeg:rtsp_cam_sub#audio=opus" # <- copy of the stream which transcodes audio to opus cameras: test_cam: @@ -49,16 +50,16 @@ cameras: output_args: record: preset-record-generic-audio-copy inputs: - - path: rtsp://127.0.0.1:8554/test_cam?video=copy&audio=aac # <--- the name here must match the name of the camera in restream + - path: rtsp://127.0.0.1:8554/test_cam # <--- the name here must match the name of the camera in restream input_args: preset-rtsp-restream roles: - record - - path: rtsp://127.0.0.1:8554/test_cam_sub?video=copy # <--- the name here must match the name of the camera_sub in restream + - path: rtsp://127.0.0.1:8554/test_cam_sub # <--- the name here must match the name of the camera_sub in restream input_args: preset-rtsp-restream roles: - detect live: - stream_name: test_cam_sub + stream_name: rtsp_cam_sub ``` ### WebRTC extra configuration: @@ -68,15 +69,15 @@ WebRTC works by creating a TCP or UDP connection on port `8555`. However, it req - For external access, over the internet, setup your router to forward port `8555` to port `8555` on the Frigate device, for both TCP and UDP. - For internal/local access, unless you are running through the add-on, you will also need to set the WebRTC candidates list in the go2rtc config. For example, if `192.168.1.10` is the local IP of the device running Frigate: - ```yaml title="/config/frigate.yaml" - go2rtc: - streams: - test_cam: ... - webrtc: - candidates: - - 192.168.1.10:8555 - - stun:8555 - ``` + ```yaml title="/config/frigate.yaml" + go2rtc: + streams: + test_cam: ... + webrtc: + candidates: + - 192.168.1.10:8555 + - stun:8555 + ``` :::tip @@ -100,4 +101,4 @@ If you are having difficulties getting WebRTC to work and you are running Frigat ::: -See https://github.com/AlexxIT/go2rtc#module-webrtc for more information about this. +See [go2rtc WebRTC docs](https://github.com/AlexxIT/go2rtc/tree/v1.2.0#module-webrtc) for more information about this. diff --git a/docs/docs/configuration/restream.md b/docs/docs/configuration/restream.md index 9f7e54eb4..e7db71634 100644 --- a/docs/docs/configuration/restream.md +++ b/docs/docs/configuration/restream.md @@ -3,17 +3,38 @@ id: restream title: Restream --- -### RTSP +## RTSP Frigate can restream your video feed as an RTSP feed for other applications such as Home Assistant to utilize it at `rtsp://:8554/`. 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) 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#configuration) for more advanced configurations and features. +Frigate uses [go2rtc](https://github.com/AlexxIT/go2rtc/tree/v1.2.0) 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.2.0#configuration) for more advanced configurations and features. -#### Birdseye Restream +:::note + +You can access the go2rtc webUI at `http://frigate_ip:5000/live/webrtc` which can be helpful to debug as well as provide useful information about your camera streams. + +::: + +### Birdseye Restream Birdseye RTSP restream can be enabled at `birdseye -> restream` and accessed at `rtsp://:8554/birdseye`. Enabling the restream will cause birdseye to run 24/7 which may increase CPU usage somewhat. -### RTMP (Deprecated) +### Securing Restream With Authentication + +The go2rtc restream can be secured with RTSP based username / password authentication. Ex: + +```yaml +go2rtc: + rtsp: + username: "admin" + password: "pass" + streams: + ... +``` + +**NOTE:** This does not apply to localhost requests, there is no need to provide credentials when using the restream as a source for frigate cameras. + +## RTMP (Deprecated) In previous Frigate versions RTMP was used for re-streaming. RTMP has disadvantages however including being incompatible with H.265, high bitrates, and certain audio codecs. RTMP is deprecated and it is recommended to move to the new restream role. @@ -30,10 +51,10 @@ go2rtc: streams: rtsp_cam: # <- for RTSP streams - rtsp://192.168.1.5:554/live0 # <- stream which supports video & aac audio - - ffmpeg:rtsp_cam#audio=opus # <- copy of the stream which transcodes audio to the missing codec (usually will be opus) + - "ffmpeg:rtsp_cam#audio=opus" # <- copy of the stream which transcodes audio to the missing codec (usually will be opus) http_cam: # <- for other streams - http://192.168.50.155/flv?port=1935&app=bcs&stream=channel0_main.bcs&user=user&password=password # <- stream which supports video & aac audio - - ffmpeg:http_cam#audio=opus # <- copy of the stream which transcodes audio to the missing codec (usually will be opus) + - "ffmpeg:http_cam#audio=opus" # <- copy of the stream which transcodes audio to the missing codec (usually will be opus) cameras: rtsp_cam: @@ -41,7 +62,7 @@ cameras: output_args: record: preset-record-generic-audio-copy inputs: - - path: rtsp://127.0.0.1:8554/rtsp_cam?video=copy&audio=aac # <--- the name here must match the name of the camera in restream + - path: rtsp://127.0.0.1:8554/rtsp_cam # <--- the name here must match the name of the camera in restream input_args: preset-rtsp-restream roles: - record @@ -51,7 +72,7 @@ cameras: output_args: record: preset-record-generic-audio-copy inputs: - - path: rtsp://127.0.0.1:8554/http_cam?video=copy&audio=aac # <--- the name here must match the name of the camera in restream + - path: rtsp://127.0.0.1:8554/http_cam # <--- the name here must match the name of the camera in restream input_args: preset-rtsp-restream roles: - record @@ -67,16 +88,16 @@ go2rtc: streams: rtsp_cam: - rtsp://192.168.1.5:554/live0 # <- stream which supports video & aac audio. This is only supported for rtsp streams, http must use ffmpeg - - ffmpeg:rtsp_cam#audio=opus # <- copy of the stream which transcodes audio to opus + - "ffmpeg:rtsp_cam#audio=opus" # <- copy of the stream which transcodes audio to opus rtsp_cam_sub: - rtsp://192.168.1.5:554/substream # <- stream which supports video & aac audio. This is only supported for rtsp streams, http must use ffmpeg - - ffmpeg:rtsp_cam_sub#audio=opus # <- copy of the stream which transcodes audio to opus + - "ffmpeg:rtsp_cam_sub#audio=opus" # <- copy of the stream which transcodes audio to opus http_cam: - http://192.168.50.155/flv?port=1935&app=bcs&stream=channel0_main.bcs&user=user&password=password # <- stream which supports video & aac audio. This is only supported for rtsp streams, http must use ffmpeg - - ffmpeg:http_cam#audio=opus # <- copy of the stream which transcodes audio to opus + - "ffmpeg:http_cam#audio=opus" # <- copy of the stream which transcodes audio to opus http_cam_sub: - http://192.168.50.155/flv?port=1935&app=bcs&stream=channel0_ext.bcs&user=user&password=password # <- stream which supports video & aac audio. This is only supported for rtsp streams, http must use ffmpeg - - ffmpeg:http_cam_sub#audio=opus # <- copy of the stream which transcodes audio to opus + - "ffmpeg:http_cam_sub#audio=opus" # <- copy of the stream which transcodes audio to opus cameras: rtsp_cam: @@ -84,11 +105,11 @@ cameras: output_args: record: preset-record-generic-audio-copy inputs: - - path: rtsp://127.0.0.1:8554/rtsp_cam?video=copy&audio=aac # <--- the name here must match the name of the camera in restream + - path: rtsp://127.0.0.1:8554/rtsp_cam # <--- the name here must match the name of the camera in restream input_args: preset-rtsp-restream roles: - record - - path: rtsp://127.0.0.1:8554/rtsp_cam_sub?video=copy&audio=aac # <--- the name here must match the name of the camera_sub in restream + - path: rtsp://127.0.0.1:8554/rtsp_cam_sub # <--- the name here must match the name of the camera_sub in restream input_args: preset-rtsp-restream roles: - detect @@ -97,11 +118,11 @@ cameras: output_args: record: preset-record-generic-audio-copy inputs: - - path: rtsp://127.0.0.1:8554/http_cam?video=copy&audio=aac # <--- the name here must match the name of the camera in restream + - path: rtsp://127.0.0.1:8554/http_cam # <--- the name here must match the name of the camera in restream input_args: preset-rtsp-restream roles: - record - - path: rtsp://127.0.0.1:8554/http_cam_sub?video=copy&audio=aac # <--- the name here must match the name of the camera_sub in restream + - path: rtsp://127.0.0.1:8554/http_cam_sub # <--- the name here must match the name of the camera_sub in restream input_args: preset-rtsp-restream roles: - detect @@ -109,7 +130,7 @@ cameras: ## Advanced Restream Configurations -The [exec](https://github.com/AlexxIT/go2rtc#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.2.0#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}}` @@ -118,15 +139,3 @@ go2rtc: streams: stream1: exec:ffmpeg -hide_banner -re -stream_loop -1 -i /media/BigBuckBunny.mp4 -c copy -rtsp_transport tcp -f rtsp {{output}} ``` - -## Go2rtc Exec - -Go2rtc offers the ability to [run a full command with exec](https://github.com/AlexxIT/go2rtc#source-exec) and calls for `{output}` at the end of the stream. Due to frigate's handling of templates, the output will need to be passed as `{{output}}`. - -ex: - -```yaml -go2rtc: - streams: - test: exec:ffmpeg -hide_banner -re -stream_loop -1 -i /media/BigBuckBunny.mp4 -c copy -rtsp_transport tcp -f rtsp {{output}} -``` diff --git a/docs/docs/configuration/zones.md b/docs/docs/configuration/zones.md index 47855d929..f8e463605 100644 --- a/docs/docs/configuration/zones.md +++ b/docs/docs/configuration/zones.md @@ -11,6 +11,24 @@ During testing, enable the Zones option for the debug feed so you can adjust as To create a zone, follow [the steps for a "Motion mask"](masks.md), but use the section of the web UI for creating a zone instead. +### Restricting events to specific zones + +Often you will only want events to be created when an object enters areas of interest. This is done using zones along with setting required_zones. Let's say you only want to be notified when an object enters your entire_yard zone, the config would be: + +```yaml +camera: + record: + events: + required_zones: + - entire_yard + snapshots: + required_zones: + - entire_yard + zones: + entire_yard: + coordinates: ... +``` + ### Restricting zones to specific objects Sometimes you want to limit a zone to specific object types to have more granular control of when events/snapshots are saved. The following example will limit one zone to person objects and the other to cars. diff --git a/docs/docs/guides/camera_setup.md b/docs/docs/frigate/camera_setup.md similarity index 82% rename from docs/docs/guides/camera_setup.md rename to docs/docs/frigate/camera_setup.md index d1aeba087..0e53b4809 100644 --- a/docs/docs/guides/camera_setup.md +++ b/docs/docs/frigate/camera_setup.md @@ -3,7 +3,7 @@ id: camera_setup title: Camera setup --- -Cameras configured to output H.264 video and AAC audio will offer the most compatibility with all features of Frigate and Home Assistant. H.265 has better compression, but far less compatibility. Safari and Edge are the only browsers able to play H.265. Ideally, cameras should be configured directly for the desired resolutions and frame rates you want to use in Frigate. Reducing frame rates within Frigate will waste CPU resources decoding extra frames that are discarded. There are three different goals that you want to tune your stream configurations around. +Cameras configured to output H.264 video and AAC audio will offer the most compatibility with all features of Frigate and Home Assistant. H.265 has better compression, but less compatibility. Chrome 108+, Safari and Edge are the only browsers able to play H.265 and only support a limited number of H.265 profiles. Ideally, cameras should be configured directly for the desired resolutions and frame rates you want to use in Frigate. Reducing frame rates within Frigate will waste CPU resources decoding extra frames that are discarded. There are three different goals that you want to tune your stream configurations around. - **Detection**: This is the only stream that Frigate will decode for processing. Also, this is the stream where snapshots will be generated from. The resolution for detection should be tuned for the size of the objects you want to detect. See [Choosing a detect resolution](#choosing-a-detect-resolution) for more details. The recommended frame rate is 5fps, but may need to be higher for very fast moving objects. Higher resolutions and frame rates will drive higher CPU usage on your server. diff --git a/docs/docs/frigate/hardware.md b/docs/docs/frigate/hardware.md index bb6652899..e5233e218 100644 --- a/docs/docs/frigate/hardware.md +++ b/docs/docs/frigate/hardware.md @@ -23,15 +23,11 @@ I may earn a small commission for my endorsement, recommendation, testimonial, o My current favorite is the Minisforum GK41 because of the dual NICs that allow you to setup a dedicated private network for your cameras where they can be blocked from accessing the internet. There are many used workstation options on eBay that work very well. Anything with an Intel CPU and capable of running Debian should work fine. As a bonus, you may want to look for devices with a M.2 or PCIe express slot that is compatible with the Google Coral. I may earn a small commission for my endorsement, recommendation, testimonial, or link to any products or services from this website. -| Name | Coral Inference Speed | Coral Compatibility | Notes | -| ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------- | ------------------- | --------------------------------------------------------------------------------------------------------------------------------------- | -| Odyssey X86 Blue J4125 (Amazon) (SeeedStudio) | 9-10ms | M.2 B+M, USB | Dual gigabit NICs for easy isolated camera network. Easily handles several 1080p cameras. | -| Minisforum GK41 (Amazon) | 9-10ms | USB | Dual gigabit NICs for easy isolated camera network. Easily handles several 1080p cameras. | -| Beelink GK55 (Amazon) | 9-10ms | USB | Dual gigabit NICs for easy isolated camera network. Easily handles several 1080p cameras. | -| Intel NUC (Amazon) | 8-10ms | USB | Overkill for most, but great performance. Can handle many cameras at 5fps depending on typical amounts of motion. Requires extra parts. | -| BMAX B2 Plus (Amazon) | 10-12ms | USB | Good balance of performance and cost. Also capable of running many other services at the same time as Frigate. | -| Atomic Pi (Amazon) | 16ms | USB | Good option for a dedicated low power board with a small number of cameras. Can leverage Intel QuickSync for stream decoding. | -| Raspberry Pi 4 (64bit) (Amazon) | 10-15ms | USB | Can handle a small number of cameras. | +| Name | Coral Inference Speed | Coral Compatibility | Notes | +| ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------- | ------------------- | --------------------------------------------------------------------------------------------------------------------------------------- | +| Odyssey X86 Blue J4125 (Amazon) (SeeedStudio) | 9-10ms | M.2 B+M, USB | Dual gigabit NICs for easy isolated camera network. Easily handles several 1080p cameras. | +| Minisforum GK41 (Amazon) | 9-10ms | USB | Dual gigabit NICs for easy isolated camera network. Easily handles several 1080p cameras. | +| Intel NUC (Amazon) | 8-10ms | USB | Overkill for most, but great performance. Can handle many cameras at 5fps depending on typical amounts of motion. Requires extra parts. | ## Detectors @@ -50,19 +46,29 @@ A single Coral can handle many cameras and will be sufficient for the majority o ### OpenVino The OpenVINO detector type is able to run on: + - 6th Gen Intel Platforms and newer that have an iGPU -- x86 & Arm32/64 hosts with VPU Hardware (ex: Intel NCS2) +- x86 & Arm64 hosts with VPU Hardware (ex: Intel NCS2) More information is available [in the detector docs](/configuration/detectors#openvino-detector) Inference speeds vary greatly depending on the CPU, GPU, or VPU used, some known examples are below: -| Name | Inference Speed | Notes | -| ------------------- | --------------- | --------------------------------------------------------------------- | -| Intel Celeron J4105 | ~ 25 ms | Inference speeds on CPU were ~ 150 ms | -| Intel Celeron N4020 | 50 - 200 ms | Inference speeds on CPU were ~ 800 ms, greatly depends on other loads | -| Intel NCS2 VPU | 60 - 65 ms | May vary based on host device | -| Intel i5 1135G7 | 10 - 15 ms | | +| Name | Inference Speed | Notes | +| -------------------- | --------------- | --------------------------------------------------------------------- | +| Intel NCS2 VPU | 60 - 65 ms | May vary based on host device | +| Intel Celeron J4105 | ~ 25 ms | Inference speeds on CPU were 150 - 200 ms | +| Intel Celeron N3060 | 130 - 150 ms | Inference speeds on CPU were ~ 550 ms | +| Intel Celeron N3205U | ~ 120 ms | Inference speeds on CPU were ~ 380 ms | +| Intel Celeron N4020 | 50 - 200 ms | Inference speeds on CPU were ~ 800 ms, greatly depends on other loads | +| Intel i3 6100T | 15 - 35 ms | Inference speeds on CPU were 60 - 120 ms | +| Intel i3 8100 | ~ 15 ms | Inference speeds on CPU were ~ 65 ms | +| Intel i5 4590 | ~ 20 ms | Inference speeds on CPU were ~ 230 ms | +| Intel i5 6500 | ~ 15 ms | Inference speeds on CPU were ~ 150 ms | +| Intel i5 7200u | 15 - 25 ms | Inference speeds on CPU were ~ 150 ms | +| Intel i5 7500 | ~ 15 ms | Inference speeds on CPU were ~ 260 ms | +| Intel i5 1135G7 | 10 - 15 ms | | +| Intel i5 12600K | ~ 15 ms | Inference speeds on CPU were ~ 35 ms | ### TensorRT @@ -71,10 +77,15 @@ The TensortRT detector is able to run on x86 hosts that have an Nvidia GPU which Inference speeds will vary greatly depending on the GPU and the model used. `tiny` variants are faster than the equivalent non-tiny model, some known examples are below: -| Name | Model | Inference Speed | -| -------- | --------------- | --------------- | -| RTX 3050 | yolov4-tiny-416 | ~ 5 ms | -| RTX 3050 | yolov7-tiny-416 | ~ 6 ms | +| Name | Inference Speed | +| --------------- | --------------- | +| GTX 1060 6GB | ~ 7 ms | +| GTX 1070 | ~ 6 ms | +| GTX 1660 SUPER | ~ 4 ms | +| RTX 3050 | 5 - 7 ms | +| RTX 3070 Mobile | ~ 5 ms | +| Quadro P400 2GB | 20 - 25 ms | +| Quadro P2000 | ~ 12 ms | ## What does Frigate use the CPU for and what does it use a detector for? (ELI5 Version) diff --git a/docs/docs/frigate/installation.md b/docs/docs/frigate/installation.md index bcaeb4f49..78482d153 100644 --- a/docs/docs/frigate/installation.md +++ b/docs/docs/frigate/installation.md @@ -137,7 +137,10 @@ docker run -d \ :::caution -Due to limitations in Home Assistant Operating System, utilizing external storage for recordings or snapshots requires [modifying udev rules manually](https://community.home-assistant.io/t/solved-mount-usb-drive-in-hassio-to-be-used-on-the-media-folder-with-udev-customization/258406/46). +There are important limitations in Home Assistant Operating System to be aware of: +- Utilizing external storage for recordings or snapshots requires [modifying udev rules manually](https://community.home-assistant.io/t/solved-mount-usb-drive-in-hassio-to-be-used-on-the-media-folder-with-udev-customization/258406/46). +- AMD GPUs are not supported because HA OS does not include the mesa driver. +- Nvidia GPUs are not supported because addons do not support the nvidia runtime. ::: @@ -168,6 +171,13 @@ There are several versions of the addon available: ## Home Assistant Supervised +:::caution + +There are important limitations in Home Assistant Supervised to be aware of: +- Nvidia GPUs are not supported because addons do not support the nvidia runtime. + +::: + :::tip If possible, it is recommended to run Frigate standalone in Docker and use [Frigate's Proxy Addon](https://github.com/blakeblackshear/frigate-hass-addons/blob/main/frigate_proxy/README.md). diff --git a/docs/docs/guides/configuring_go2rtc.md b/docs/docs/guides/configuring_go2rtc.md new file mode 100644 index 000000000..fa4c30782 --- /dev/null +++ b/docs/docs/guides/configuring_go2rtc.md @@ -0,0 +1,77 @@ +--- +id: configuring_go2rtc +title: Configuring go2rtc +--- + +Use of the bundled go2rtc is optional. You can still configure FFmpeg to connect directly to your cameras. However, adding go2rtc to your configuration is required for the following features: + +- WebRTC or MSE for live viewing with higher resolutions and frame rates than the jsmpeg stream which is limited to the detect stream +- RTSP (instead of RTMP) relay for use with Home Assistant or other consumers to reduce the number of connections to your camera streams + +# 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.2.0#module-streams), not just rtsp. + +```yaml +go2rtc: + streams: + back: + - rtsp://user:password@10.0.10.10:554/cam/realmonitor?channel=1&subtype=2 +``` + +The easiest live view to get working is MSE. After adding this to the config, restart Frigate and try to watch the live stream by selecting MSE in the dropdown after clicking on the camera. + +### 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.2.0#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.2.0#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 +go2rtc: + streams: + back: + - rtsp://user:password@10.0.10.10:554/cam/realmonitor?channel=1&subtype=2 + - "ffmpeg:back#video=h264" +``` + +Some camera streams may need to use the ffmpeg module in go2rtc. This has the downside of slower startup times, but has compatibility with more stream types. + +```yaml +go2rtc: + streams: + back: + - ffmpeg:rtsp://user:password@10.0.10.10:554/cam/realmonitor?channel=1&subtype=2 +``` + +If you can see the video but do not have audio, this is most likely because your camera's audio stream is not AAC. If possible, update your camera's audio settings to AAC. If your cameras do not support AAC audio, you will need to tell go2rtc to re-encode the audio to AAC on demand if you want audio. This will use additional CPU and add some latency. To add AAC audio on demand, you can update your go2rtc config as follows: + +```yaml +go2rtc: + streams: + back: + - rtsp://user:password@10.0.10.10:554/cam/realmonitor?channel=1&subtype=2 + - "ffmpeg:back#audio=aac" +``` + +If you need to convert **both** the audio and video streams, you can use the following: + +```yaml +go2rtc: + streams: + back: + - rtsp://user:password@10.0.10.10:554/cam/realmonitor?channel=1&subtype=2 + - "ffmpeg:back#video=h264#audio=aac" +``` + +When using the ffmpeg module, you would add AAC audio like this: + +```yaml +go2rtc: + streams: + back: + - "ffmpeg:rtsp://user:password@10.0.10.10:554/cam/realmonitor?channel=1&subtype=2#video=copy#audio=copy#audio=aac" +``` + +## Next steps + +1. If the stream you added to go2rtc is also used by Frigate for the `record` or `detect` role, you can migrate your config to pull from the RTSP restream to reduce the number of connections to your camera as shown [here](/configuration/restream#reduce-connections-to-camera). +1. You may also prefer to [setup WebRTC](/configuration/live#webrtc-extra-configuration) for slightly lower latency than MSE. Note that WebRTC only supports h264 and specific audio formats. diff --git a/docs/docs/guides/events_setup.md b/docs/docs/guides/events_setup.md deleted file mode 100644 index bc5c46e94..000000000 --- a/docs/docs/guides/events_setup.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -id: events_setup -title: Setting Up Events ---- - -[Snapshots](../configuration/snapshots.md) and/or [Recordings](../configuration/record.md) must be enabled for events to be created for detected objects. - -## Limiting Events to Areas of Interest - -The best way to limit events to areas of interest is to use [zones](../configuration/zones.md) along with `required_zones` for events and snapshots to only have events created in areas of interest. diff --git a/docs/docs/guides/getting_started.md b/docs/docs/guides/getting_started.md index 39bbe2354..b40baef33 100644 --- a/docs/docs/guides/getting_started.md +++ b/docs/docs/guides/getting_started.md @@ -1,79 +1,32 @@ --- id: getting_started -title: Creating a config file +title: Getting started --- -This guide walks through the steps to build a configuration file for Frigate. It assumes that you already have an environment setup as described in [Installation](../frigate/installation.md). You should also configure your cameras according to the [camera setup guide](/guides/camera_setup) +This guide walks through the steps to build a configuration file for Frigate. It assumes that you already have an environment setup as described in [Installation](../frigate/installation.md). You should also configure your cameras according to the [camera setup guide](/frigate/camera_setup). Pay particular attention to the section on choosing a detect resolution. -### Step 1: Configure the MQTT server (Optional) +### Step 1: Add a detect stream -Use of a functioning MQTT server is optional for Frigate, but required for the home assistant integration. Start by adding the mqtt section at the top level in your config: +First we will add the detect stream for the camera: -If using mqtt: -```yaml -mqtt: - host: -``` - -If not using mqtt: ```yaml mqtt: enabled: False -``` - -If using the Mosquitto Addon in Home Assistant, a username and password is required. For example: - -```yaml -mqtt: - host: - user: - password: -``` - -Frigate supports many configuration options for mqtt. See the [configuration reference](../configuration/index.md#full-configuration-reference) for more info. - -### Step 2: Configure detectors - -By default, Frigate will use a single CPU detector. If you have a USB Coral, you will need to add a detectors section to your config. - -```yaml -mqtt: - host: - -detectors: - coral: - type: edgetpu - device: usb -``` - -More details on available detectors can be found [here](../configuration/detectors.md). - -### Step 3: Add a minimal camera configuration - -Now let's add the first camera: - -```yaml -mqtt: - host: - -detectors: - coral: - type: edgetpu - device: usb cameras: camera_1: # <------ Name the camera ffmpeg: inputs: - - path: rtsp://10.0.10.10:554/rtsp # <----- Update for your camera + - path: rtsp://10.0.10.10:554/rtsp # <----- The stream you want to use for detection roles: - detect detect: + enabled: False # <---- disable detection until you have a working camera feed width: 1280 # <---- update for your camera's resolution height: 720 # <---- update for your camera's resolution ``` -### Step 4: Start Frigate +### Step 2: Start Frigate At this point you should be able to start Frigate and see the the video feed in the UI. @@ -81,41 +34,48 @@ If you get an error image from the camera, this means ffmpeg was not able to get FFmpeg arguments for other types of cameras can be found [here](../configuration/camera_specific.md). -### Step 5: Configure hardware acceleration (optional) +### Step 3: Configure hardware acceleration (recommended) Now that you have a working camera configuration, you want to setup hardware acceleration to minimize the CPU required to decode your video streams. See the [hardware acceleration](../configuration/hardware_acceleration.md) config reference for examples applicable to your hardware. -In order to best evaluate the performance impact of hardware acceleration, it is recommended to temporarily disable detection. +Here is an example configuration with hardware acceleration configured for Intel processors with an integrated GPU using the [preset](../configuration/ffmpeg_presets.md): ```yaml mqtt: ... -detectors: ... - -cameras: - camera_1: - ffmpeg: ... - detect: - enabled: False - ... -``` - -Here is an example configuration with hardware acceleration configured: - -```yaml -mqtt: ... - -detectors: ... - cameras: camera_1: ffmpeg: inputs: ... - hwaccel_args: -c:v h264_v4l2m2m + hwaccel_args: preset-vaapi detect: ... ``` -### Step 6: Setup motion masks +### Step 4: Configure detectors + +By default, Frigate will use a single CPU detector. If you have a USB Coral, you will need to add a detectors section to your config. + +```yaml +mqtt: ... + +detectors: # <---- add detectors + coral: + type: edgetpu + device: usb + +cameras: + camera_1: + ffmpeg: ... + detect: + enabled: True # <---- turn on detection + ... +``` + +More details on available detectors can be found [here](../configuration/detectors.md). + +Restart Frigate and you should start seeing detections for `person`. If you want to track other objects, they will need to be added according to the [configuration file reference](../configuration/index.md#full-configuration-reference). + +### Step 5: Setup motion masks Now that you have optimized your configuration for decoding the video stream, you will want to check to see where to implement motion masks. To do this, navigate to the camera in the UI, select "Debug" at the top, and enable "Motion boxes" in the options below the video feed. Watch for areas that continuously trigger unwanted motion to be detected. Common areas to mask include camera timestamps and trees that frequently blow in the wind. The goal is to avoid wasting object detection cycles looking at these areas. @@ -131,7 +91,7 @@ Your configuration should look similar to this now. ```yaml mqtt: - host: mqtt.local + enabled: False detectors: coral: @@ -153,9 +113,13 @@ cameras: - 0,461,3,0,1919,0,1919,843,1699,492,1344,458,1346,336,973,317,869,375,866,432 ``` -### Step 7: Enable recording (optional) +### Step 6: Enable recording and/or snapshots -To enable recording video, add the `record` role to a stream and enable it in the config. +In order to see Events in the Frigate UI, either snapshots or record will need to be enabled. + +#### Record + +To enable recording video, add the `record` role to a stream and enable it in the config. If record is disabled in the config, turning it on via the UI will not have any effect. ```yaml mqtt: ... @@ -169,7 +133,7 @@ cameras: - path: rtsp://10.0.10.10:554/rtsp roles: - detect - - path: rtsp://10.0.10.10:554/high_res_stream # <----- Add high res stream + - path: rtsp://10.0.10.10:554/high_res_stream # <----- Add stream you want to record from roles: - record detect: ... @@ -182,9 +146,9 @@ If you don't have separate streams for detect and record, you would just add the By default, Frigate will retain video of all events for 10 days. The full set of options for recording can be found [here](../configuration/index.md#full-configuration-reference). -### Step 8: Enable snapshots (optional) +#### Snapshots -To enable snapshots of your events, just enable it in the config. +To enable snapshots of your events, just enable it in the config. Snapshots are taken from the detect stream because it is the only stream decoded. ```yaml mqtt: ... @@ -201,3 +165,10 @@ cameras: ``` By default, Frigate will retain snapshots of all events for 10 days. The full set of options for snapshots can be found [here](../configuration/index.md#full-configuration-reference). + +### Step 7: Follow up guides + +Now that you have a working install, you can use the following guides for additional features: + +1. [Configuring go2rtc](configuring_go2rtc) - Additional live view options and RTSP relay +2. [Home Assistant Integration](../integrations/home-assistant.md) - Integrate with Home Assistant diff --git a/docs/docs/guides/reverse_proxy.md b/docs/docs/guides/reverse_proxy.md index 22884a4d8..2e284eede 100644 --- a/docs/docs/guides/reverse_proxy.md +++ b/docs/docs/guides/reverse_proxy.md @@ -1,6 +1,6 @@ --- id: reverse_proxy -title: Setting up a Reverse Proxy +title: Setting up a reverse proxy --- This guide outlines the basic configuration steps needed to expose your Frigate UI to the internet. @@ -8,6 +8,7 @@ A common way of accomplishing this is to use a reverse proxy webserver between y A reverse proxy accepts HTTP requests from the public internet and redirects them transparently to internal webserver(s) on your network. The suggested steps are: + - **Configure** a 'proxy' HTTP webserver (such as [Apache2](https://httpd.apache.org/docs/current/) or [NPM](https://github.com/NginxProxyManager/nginx-proxy-manager)) and only expose ports 80/443 from this webserver to the internet - **Encrypt** content from the proxy webserver by installing SSL (such as with [Let's Encrypt](https://letsencrypt.org/)). Note that SSL is then not required on your Frigate webserver as the proxy encrypts all requests for you - **Restrict** access to your Frigate instance at the proxy using, for example, password authentication @@ -31,6 +32,7 @@ On Debian Apache2 the configuration file will be named along the lines of `/etc/ Make life easier for yourself by presenting your Frigate interface as a DNS sub-domain rather than as a sub-folder of your main domain. Here we access Frigate via https://cctv.mydomain.co.uk + ```xml ServerName cctv.mydomain.co.uk @@ -38,7 +40,7 @@ Here we access Frigate via https://cctv.mydomain.co.uk ProxyPreserveHost On ProxyPass "/" "http://frigatepi.local:5000/" ProxyPassReverse "/" "http://frigatepi.local:5000/" - + ProxyPass /ws ws://frigatepi.local:5000/ws ProxyPassReverse /ws ws://frigatepi.local:5000/ws diff --git a/docs/docs/integrations/api.md b/docs/docs/integrations/api.md index 51887b14b..2b89288db 100644 --- a/docs/docs/integrations/api.md +++ b/docs/docs/integrations/api.md @@ -168,6 +168,16 @@ Events from the database. Accepts the following query string parameters: | `include_thumbnails` | int | Include thumbnails in the response (0 or 1) | | `in_progress` | int | Limit to events in progress (0 or 1) | +### `GET /api/timeline` + +Timeline of key moments of an event(s) from the database. Accepts the following query string parameters: + +| param | Type | Description | +| -------------------- | ---- | --------------------------------------------- | +| `camera` | int | Name of camera | +| `source_id` | str | ID of tracked object | +| `limit` | int | Limit the number of events returned | + ### `GET /api/events/summary` Returns summary data for events in the database. Used by the Home Assistant integration. @@ -233,6 +243,10 @@ Accepts the following query string parameters, but they are only applied when an Returns the snapshot image from the latest event for the given camera and label combo. Using `any` as the label will return the latest thumbnail regardless of type. +### `GET /api//recording//snapshot.png` + +Returns the snapshot image from the specific point in that cameras recordings. + ### `GET /clips/-.jpg` JPG snapshot for the given camera and event id. diff --git a/docs/docs/integrations/home-assistant.md b/docs/docs/integrations/home-assistant.md index 040eb3536..8fd1acb15 100644 --- a/docs/docs/integrations/home-assistant.md +++ b/docs/docs/integrations/home-assistant.md @@ -16,6 +16,8 @@ See the [MQTT integration documentation](https://www.home-assistant.io/integrations/mqtt/) for more details. +In addition, MQTT must be enabled in your Frigate configuration file and Frigate must be connected to the same MQTT server as Home Assistant for many of the entities created by the integration to function. + ### Integration installation Available via HACS as a default repository. To install: @@ -30,7 +32,7 @@ Home Assistant > HACS > Integrations > "Explore & Add Integrations" > Frigate - Then add/configure the integration: ``` -Home Assistant > Configuration > Integrations > Add Integration > Frigate +Home Assistant > Settings > Devices & Services > Add Integration > Frigate ``` Note: You will also need @@ -64,13 +66,13 @@ Home Assistant > Configuration > Integrations > Frigate > Options | Option | Description | | ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| RTSP URL Template | A [jinja2](https://jinja.palletsprojects.com/) template that is used to override the standard RTMP stream URL (e.g. for use with reverse proxies). This option is only shown to users who have [advanced mode](https://www.home-assistant.io/blog/2019/07/17/release-96/#advanced-mode) enabled. See [RTSP streams](#streams) below. | +| RTSP URL Template | A [jinja2](https://jinja.palletsprojects.com/) template that is used to override the standard RTSP stream URL (e.g. for use with reverse proxies). This option is only shown to users who have [advanced mode](https://www.home-assistant.io/blog/2019/07/17/release-96/#advanced-mode) enabled. See [RTSP streams](#streams) below. | ## Entities Provided | Platform | Description | | --------------- | --------------------------------------------------------------------------------- | -| `camera` | Live camera stream (requires RTMP), camera for image of the last detected object. | +| `camera` | Live camera stream (requires RTSP), camera for image of the last detected object. | | `sensor` | States to monitor Frigate performance, object counts for all zones and cameras. | | `switch` | Switch entities to toggle detection, recordings and snapshots. | | `binary_sensor` | A "motion" binary sensor entity per camera/zone/object. | diff --git a/docs/docs/integrations/plus.md b/docs/docs/integrations/plus.md index 22462a74e..4bab29ef3 100644 --- a/docs/docs/integrations/plus.md +++ b/docs/docs/integrations/plus.md @@ -39,6 +39,12 @@ You cannot use the `environment_vars` section of your configuration file to set Once your API key is configured, you can submit examples directly from the events page in Frigate using the `SEND TO FRIGATE+` button. +:::note + +Snapshots must be enabled to be able to submit examples to Frigate+ + +::: + ![Send To Plus](/img/send-to-plus.png) ### Annotate and verify diff --git a/docs/docs/troubleshooting/faqs.md b/docs/docs/troubleshooting/faqs.md index a3a703ec3..75ab6df97 100644 --- a/docs/docs/troubleshooting/faqs.md +++ b/docs/docs/troubleshooting/faqs.md @@ -17,16 +17,18 @@ ffmpeg: record: preset-record-generic-audio-aac ``` +### I can't view events or recordings in the Web UI. + +Ensure your cameras send h264 encoded video, or [transcode them](/configuration/restream.md). + +You can open `chrome://media-internals/` in another tab and then try to playback, the media internals page will give information about why playback is failing. + ### My mjpeg stream or snapshots look green and crazy This almost always means that the width/height defined for your camera are not correct. Double check the resolution with VLC or another player. Also make sure you don't have the width and height values backwards. ![mismatched-resolution](/img/mismatched-resolution-min.jpg) -### I can't view events or recordings in the Web UI. - -Ensure your cameras send h264 encoded video, or [transcode them](/configuration/restream.md). - ### "[mov,mp4,m4a,3gp,3g2,mj2 @ 0x5639eeb6e140] moov atom not found" These messages in the logs are expected in certain situations. Frigate checks the integrity of the recordings before storing. Occasionally these cached files will be invalid and cleaned up automatically. diff --git a/docs/package-lock.json b/docs/package-lock.json index e74604119..7f946b030 100644 --- a/docs/package-lock.json +++ b/docs/package-lock.json @@ -8,8 +8,8 @@ "name": "docs", "version": "0.0.0", "dependencies": { - "@docusaurus/core": "^2.2.0", - "@docusaurus/preset-classic": "^2.2.0", + "@docusaurus/core": "^2.4.0", + "@docusaurus/preset-classic": "^2.4.0", "@mdx-js/react": "^1.6.22", "clsx": "^1.2.1", "prism-react-renderer": "^1.3.5", @@ -18,7 +18,7 @@ "react-dom": "^17.0.2" }, "devDependencies": { - "@docusaurus/module-type-aliases": "2.2.0", + "@docusaurus/module-type-aliases": "^2.4.0", "@types/react": "^17.0.0" }, "engines": { @@ -26,19 +26,19 @@ } }, "node_modules/@algolia/autocomplete-core": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/@algolia/autocomplete-core/-/autocomplete-core-1.7.2.tgz", - "integrity": "sha512-eclwUDC6qfApNnEfu1uWcL/rudQsn59tjEoUYZYE2JSXZrHLRjBUGMxiCoknobU2Pva8ejb0eRxpIYDtVVqdsw==", + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-core/-/autocomplete-core-1.7.4.tgz", + "integrity": "sha512-daoLpQ3ps/VTMRZDEBfU8ixXd+amZcNJ4QSP3IERGyzqnL5Ch8uSRFt/4G8pUvW9c3o6GA4vtVv4I4lmnkdXyg==", "dependencies": { - "@algolia/autocomplete-shared": "1.7.2" + "@algolia/autocomplete-shared": "1.7.4" } }, "node_modules/@algolia/autocomplete-preset-algolia": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/@algolia/autocomplete-preset-algolia/-/autocomplete-preset-algolia-1.7.2.tgz", - "integrity": "sha512-+RYEG6B0QiGGfRb2G3MtPfyrl0dALF3cQNTWBzBX6p5o01vCCGTTinAm2UKG3tfc2CnOMAtnPLkzNZyJUpnVJw==", + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-preset-algolia/-/autocomplete-preset-algolia-1.7.4.tgz", + "integrity": "sha512-s37hrvLEIfcmKY8VU9LsAXgm2yfmkdHT3DnA3SgHaY93yjZ2qL57wzb5QweVkYuEBZkT2PIREvRoLXC2sxTbpQ==", "dependencies": { - "@algolia/autocomplete-shared": "1.7.2" + "@algolia/autocomplete-shared": "1.7.4" }, "peerDependencies": { "@algolia/client-search": ">= 4.9.1 < 6", @@ -46,79 +46,79 @@ } }, "node_modules/@algolia/autocomplete-shared": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/@algolia/autocomplete-shared/-/autocomplete-shared-1.7.2.tgz", - "integrity": "sha512-QCckjiC7xXHIUaIL3ektBtjJ0w7tTA3iqKcAE/Hjn1lZ5omp7i3Y4e09rAr9ZybqirL7AbxCLLq0Ra5DDPKeug==" + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-shared/-/autocomplete-shared-1.7.4.tgz", + "integrity": "sha512-2VGCk7I9tA9Ge73Km99+Qg87w0wzW4tgUruvWAn/gfey1ZXgmxZtyIRBebk35R1O8TbK77wujVtCnpsGpRy1kg==" }, "node_modules/@algolia/cache-browser-local-storage": { - "version": "4.14.2", - "resolved": "https://registry.npmjs.org/@algolia/cache-browser-local-storage/-/cache-browser-local-storage-4.14.2.tgz", - "integrity": "sha512-FRweBkK/ywO+GKYfAWbrepewQsPTIEirhi1BdykX9mxvBPtGNKccYAxvGdDCumU1jL4r3cayio4psfzKMejBlA==", + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/@algolia/cache-browser-local-storage/-/cache-browser-local-storage-4.17.0.tgz", + "integrity": "sha512-myRSRZDIMYB8uCkO+lb40YKiYHi0fjpWRtJpR/dgkaiBlSD0plRyB6lLOh1XIfmMcSeBOqDE7y9m8xZMrXYfyQ==", "dependencies": { - "@algolia/cache-common": "4.14.2" + "@algolia/cache-common": "4.17.0" } }, "node_modules/@algolia/cache-common": { - "version": "4.14.2", - "resolved": "https://registry.npmjs.org/@algolia/cache-common/-/cache-common-4.14.2.tgz", - "integrity": "sha512-SbvAlG9VqNanCErr44q6lEKD2qoK4XtFNx9Qn8FK26ePCI8I9yU7pYB+eM/cZdS9SzQCRJBbHUumVr4bsQ4uxg==" + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/@algolia/cache-common/-/cache-common-4.17.0.tgz", + "integrity": "sha512-g8mXzkrcUBIPZaulAuqE7xyHhLAYAcF2xSch7d9dABheybaU3U91LjBX6eJTEB7XVhEsgK4Smi27vWtAJRhIKQ==" }, "node_modules/@algolia/cache-in-memory": { - "version": "4.14.2", - "resolved": "https://registry.npmjs.org/@algolia/cache-in-memory/-/cache-in-memory-4.14.2.tgz", - "integrity": "sha512-HrOukWoop9XB/VFojPv1R5SVXowgI56T9pmezd/djh2JnVN/vXswhXV51RKy4nCpqxyHt/aGFSq2qkDvj6KiuQ==", + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/@algolia/cache-in-memory/-/cache-in-memory-4.17.0.tgz", + "integrity": "sha512-PT32ciC/xI8z919d0oknWVu3kMfTlhQn3MKxDln3pkn+yA7F7xrxSALysxquv+MhFfNAcrtQ/oVvQVBAQSHtdw==", "dependencies": { - "@algolia/cache-common": "4.14.2" + "@algolia/cache-common": "4.17.0" } }, "node_modules/@algolia/client-account": { - "version": "4.14.2", - "resolved": "https://registry.npmjs.org/@algolia/client-account/-/client-account-4.14.2.tgz", - "integrity": "sha512-WHtriQqGyibbb/Rx71YY43T0cXqyelEU0lB2QMBRXvD2X0iyeGl4qMxocgEIcbHyK7uqE7hKgjT8aBrHqhgc1w==", + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/@algolia/client-account/-/client-account-4.17.0.tgz", + "integrity": "sha512-sSEHx9GA6m7wrlsSMNBGfyzlIfDT2fkz2u7jqfCCd6JEEwmxt8emGmxAU/0qBfbhRSuGvzojoLJlr83BSZAKjA==", "dependencies": { - "@algolia/client-common": "4.14.2", - "@algolia/client-search": "4.14.2", - "@algolia/transporter": "4.14.2" + "@algolia/client-common": "4.17.0", + "@algolia/client-search": "4.17.0", + "@algolia/transporter": "4.17.0" } }, "node_modules/@algolia/client-analytics": { - "version": "4.14.2", - "resolved": "https://registry.npmjs.org/@algolia/client-analytics/-/client-analytics-4.14.2.tgz", - "integrity": "sha512-yBvBv2mw+HX5a+aeR0dkvUbFZsiC4FKSnfqk9rrfX+QrlNOKEhCG0tJzjiOggRW4EcNqRmaTULIYvIzQVL2KYQ==", + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/@algolia/client-analytics/-/client-analytics-4.17.0.tgz", + "integrity": "sha512-84ooP8QA3mQ958hQ9wozk7hFUbAO+81CX1CjAuerxBqjKIInh1fOhXKTaku05O/GHBvcfExpPLIQuSuLYziBXQ==", "dependencies": { - "@algolia/client-common": "4.14.2", - "@algolia/client-search": "4.14.2", - "@algolia/requester-common": "4.14.2", - "@algolia/transporter": "4.14.2" + "@algolia/client-common": "4.17.0", + "@algolia/client-search": "4.17.0", + "@algolia/requester-common": "4.17.0", + "@algolia/transporter": "4.17.0" } }, "node_modules/@algolia/client-common": { - "version": "4.14.2", - "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-4.14.2.tgz", - "integrity": "sha512-43o4fslNLcktgtDMVaT5XwlzsDPzlqvqesRi4MjQz2x4/Sxm7zYg5LRYFol1BIhG6EwxKvSUq8HcC/KxJu3J0Q==", + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-4.17.0.tgz", + "integrity": "sha512-jHMks0ZFicf8nRDn6ma8DNNsdwGgP/NKiAAL9z6rS7CymJ7L0+QqTJl3rYxRW7TmBhsUH40wqzmrG6aMIN/DrQ==", "dependencies": { - "@algolia/requester-common": "4.14.2", - "@algolia/transporter": "4.14.2" + "@algolia/requester-common": "4.17.0", + "@algolia/transporter": "4.17.0" } }, "node_modules/@algolia/client-personalization": { - "version": "4.14.2", - "resolved": "https://registry.npmjs.org/@algolia/client-personalization/-/client-personalization-4.14.2.tgz", - "integrity": "sha512-ACCoLi0cL8CBZ1W/2juehSltrw2iqsQBnfiu/Rbl9W2yE6o2ZUb97+sqN/jBqYNQBS+o0ekTMKNkQjHHAcEXNw==", + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/@algolia/client-personalization/-/client-personalization-4.17.0.tgz", + "integrity": "sha512-RMzN4dZLIta1YuwT7QC9o+OeGz2cU6eTOlGNE/6RcUBLOU3l9tkCOdln5dPE2jp8GZXPl2yk54b2nSs1+pAjqw==", "dependencies": { - "@algolia/client-common": "4.14.2", - "@algolia/requester-common": "4.14.2", - "@algolia/transporter": "4.14.2" + "@algolia/client-common": "4.17.0", + "@algolia/requester-common": "4.17.0", + "@algolia/transporter": "4.17.0" } }, "node_modules/@algolia/client-search": { - "version": "4.14.2", - "resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-4.14.2.tgz", - "integrity": "sha512-L5zScdOmcZ6NGiVbLKTvP02UbxZ0njd5Vq9nJAmPFtjffUSOGEp11BmD2oMJ5QvARgx2XbX4KzTTNS5ECYIMWw==", + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-4.17.0.tgz", + "integrity": "sha512-x4P2wKrrRIXszT8gb7eWsMHNNHAJs0wE7/uqbufm4tZenAp+hwU/hq5KVsY50v+PfwM0LcDwwn/1DroujsTFoA==", "dependencies": { - "@algolia/client-common": "4.14.2", - "@algolia/requester-common": "4.14.2", - "@algolia/transporter": "4.14.2" + "@algolia/client-common": "4.17.0", + "@algolia/requester-common": "4.17.0", + "@algolia/transporter": "4.17.0" } }, "node_modules/@algolia/events": { @@ -127,47 +127,47 @@ "integrity": "sha512-FQzvOCgoFXAbf5Y6mYozw2aj5KCJoA3m4heImceldzPSMbdyS4atVjJzXKMsfX3wnZTFYwkkt8/z8UesLHlSBQ==" }, "node_modules/@algolia/logger-common": { - "version": "4.14.2", - "resolved": "https://registry.npmjs.org/@algolia/logger-common/-/logger-common-4.14.2.tgz", - "integrity": "sha512-/JGlYvdV++IcMHBnVFsqEisTiOeEr6cUJtpjz8zc0A9c31JrtLm318Njc72p14Pnkw3A/5lHHh+QxpJ6WFTmsA==" + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/@algolia/logger-common/-/logger-common-4.17.0.tgz", + "integrity": "sha512-DGuoZqpTmIKJFDeyAJ7M8E/LOenIjWiOsg1XJ1OqAU/eofp49JfqXxbfgctlVZVmDABIyOz8LqEoJ6ZP4DTyvw==" }, "node_modules/@algolia/logger-console": { - "version": "4.14.2", - "resolved": "https://registry.npmjs.org/@algolia/logger-console/-/logger-console-4.14.2.tgz", - "integrity": "sha512-8S2PlpdshbkwlLCSAB5f8c91xyc84VM9Ar9EdfE9UmX+NrKNYnWR1maXXVDQQoto07G1Ol/tYFnFVhUZq0xV/g==", + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/@algolia/logger-console/-/logger-console-4.17.0.tgz", + "integrity": "sha512-zMPvugQV/gbXUvWBCzihw6m7oxIKp48w37QBIUu/XqQQfxhjoOE9xyfJr1KldUt5FrYOKZJVsJaEjTsu+bIgQg==", "dependencies": { - "@algolia/logger-common": "4.14.2" + "@algolia/logger-common": "4.17.0" } }, "node_modules/@algolia/requester-browser-xhr": { - "version": "4.14.2", - "resolved": "https://registry.npmjs.org/@algolia/requester-browser-xhr/-/requester-browser-xhr-4.14.2.tgz", - "integrity": "sha512-CEh//xYz/WfxHFh7pcMjQNWgpl4wFB85lUMRyVwaDPibNzQRVcV33YS+63fShFWc2+42YEipFGH2iPzlpszmDw==", + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/@algolia/requester-browser-xhr/-/requester-browser-xhr-4.17.0.tgz", + "integrity": "sha512-aSOX/smauyTkP21Pf52pJ1O2LmNFJ5iHRIzEeTh0mwBeADO4GdG94cAWDILFA9rNblq/nK3EDh3+UyHHjplZ1A==", "dependencies": { - "@algolia/requester-common": "4.14.2" + "@algolia/requester-common": "4.17.0" } }, "node_modules/@algolia/requester-common": { - "version": "4.14.2", - "resolved": "https://registry.npmjs.org/@algolia/requester-common/-/requester-common-4.14.2.tgz", - "integrity": "sha512-73YQsBOKa5fvVV3My7iZHu1sUqmjjfs9TteFWwPwDmnad7T0VTCopttcsM3OjLxZFtBnX61Xxl2T2gmG2O4ehg==" + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/@algolia/requester-common/-/requester-common-4.17.0.tgz", + "integrity": "sha512-XJjmWFEUlHu0ijvcHBoixuXfEoiRUdyzQM6YwTuB8usJNIgShua8ouFlRWF8iCeag0vZZiUm4S2WCVBPkdxFgg==" }, "node_modules/@algolia/requester-node-http": { - "version": "4.14.2", - "resolved": "https://registry.npmjs.org/@algolia/requester-node-http/-/requester-node-http-4.14.2.tgz", - "integrity": "sha512-oDbb02kd1o5GTEld4pETlPZLY0e+gOSWjWMJHWTgDXbv9rm/o2cF7japO6Vj1ENnrqWvLBmW1OzV9g6FUFhFXg==", + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/@algolia/requester-node-http/-/requester-node-http-4.17.0.tgz", + "integrity": "sha512-bpb/wDA1aC6WxxM8v7TsFspB7yBN3nqCGs2H1OADolQR/hiAIjAxusbuMxVbRFOdaUvAIqioIIkWvZdpYNIn8w==", "dependencies": { - "@algolia/requester-common": "4.14.2" + "@algolia/requester-common": "4.17.0" } }, "node_modules/@algolia/transporter": { - "version": "4.14.2", - "resolved": "https://registry.npmjs.org/@algolia/transporter/-/transporter-4.14.2.tgz", - "integrity": "sha512-t89dfQb2T9MFQHidjHcfhh6iGMNwvuKUvojAj+JsrHAGbuSy7yE4BylhLX6R0Q1xYRoC4Vvv+O5qIw/LdnQfsQ==", + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/@algolia/transporter/-/transporter-4.17.0.tgz", + "integrity": "sha512-6xL6H6fe+Fi0AEP3ziSgC+G04RK37iRb4uUUqVAH9WPYFI8g+LYFq6iv5HS8Cbuc5TTut+Bwj6G+dh/asdb9uA==", "dependencies": { - "@algolia/cache-common": "4.14.2", - "@algolia/logger-common": "4.14.2", - "@algolia/requester-common": "4.14.2" + "@algolia/cache-common": "4.17.0", + "@algolia/logger-common": "4.17.0", + "@algolia/requester-common": "4.17.0" } }, "node_modules/@ampproject/remapping": { @@ -1860,11 +1860,11 @@ } }, "node_modules/@babel/runtime": { - "version": "7.20.1", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.20.1.tgz", - "integrity": "sha512-mrzLkl6U9YLF8qpqI7TB82PESyEGjm/0Ly91jG575eVxMMlb8fYfOXFZIJ8XfLrJZQbm7dlKry2bJmXBUEkdFg==", + "version": "7.21.0", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.21.0.tgz", + "integrity": "sha512-xwII0//EObnq89Ji5AKYQaRYiW/nZ3llSv29d49IuxPhKbtJoLP+9QUUZ4nVragQVtaVGeZrpB+ZtG/Pdy/POw==", "dependencies": { - "regenerator-runtime": "^0.13.10" + "regenerator-runtime": "^0.13.11" }, "engines": { "node": ">=6.9.0" @@ -1938,18 +1938,18 @@ } }, "node_modules/@docsearch/css": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/@docsearch/css/-/css-3.3.0.tgz", - "integrity": "sha512-rODCdDtGyudLj+Va8b6w6Y85KE85bXRsps/R4Yjwt5vueXKXZQKYw0aA9knxLBT6a/bI/GMrAcmCR75KYOM6hg==" + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/@docsearch/css/-/css-3.3.3.tgz", + "integrity": "sha512-6SCwI7P8ao+se1TUsdZ7B4XzL+gqeQZnBc+2EONZlcVa0dVrk0NjETxozFKgMv0eEGH8QzP1fkN+A1rH61l4eg==" }, "node_modules/@docsearch/react": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/@docsearch/react/-/react-3.3.0.tgz", - "integrity": "sha512-fhS5adZkae2SSdMYEMVg6pxI5a/cE+tW16ki1V0/ur4Fdok3hBRkmN/H8VvlXnxzggkQIIRIVvYPn00JPjen3A==", + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/@docsearch/react/-/react-3.3.3.tgz", + "integrity": "sha512-pLa0cxnl+G0FuIDuYlW+EBK6Rw2jwLw9B1RHIeS4N4s2VhsfJ/wzeCi3CWcs5yVfxLd5ZK50t//TMA5e79YT7Q==", "dependencies": { - "@algolia/autocomplete-core": "1.7.2", - "@algolia/autocomplete-preset-algolia": "1.7.2", - "@docsearch/css": "3.3.0", + "@algolia/autocomplete-core": "1.7.4", + "@algolia/autocomplete-preset-algolia": "1.7.4", + "@docsearch/css": "3.3.3", "algoliasearch": "^4.0.0" }, "peerDependencies": { @@ -1970,9 +1970,9 @@ } }, "node_modules/@docusaurus/core": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@docusaurus/core/-/core-2.2.0.tgz", - "integrity": "sha512-Vd6XOluKQqzG12fEs9prJgDtyn6DPok9vmUWDR2E6/nV5Fl9SVkhEQOBxwObjk3kQh7OY7vguFaLh0jqdApWsA==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@docusaurus/core/-/core-2.4.0.tgz", + "integrity": "sha512-J55/WEoIpRcLf3afO5POHPguVZosKmJEQWKBL+K7TAnfuE7i+Y0NPLlkKtnWCehagGsgTqClfQEexH/UT4kELA==", "dependencies": { "@babel/core": "^7.18.6", "@babel/generator": "^7.18.7", @@ -1984,13 +1984,13 @@ "@babel/runtime": "^7.18.6", "@babel/runtime-corejs3": "^7.18.6", "@babel/traverse": "^7.18.8", - "@docusaurus/cssnano-preset": "2.2.0", - "@docusaurus/logger": "2.2.0", - "@docusaurus/mdx-loader": "2.2.0", + "@docusaurus/cssnano-preset": "2.4.0", + "@docusaurus/logger": "2.4.0", + "@docusaurus/mdx-loader": "2.4.0", "@docusaurus/react-loadable": "5.5.2", - "@docusaurus/utils": "2.2.0", - "@docusaurus/utils-common": "2.2.0", - "@docusaurus/utils-validation": "2.2.0", + "@docusaurus/utils": "2.4.0", + "@docusaurus/utils-common": "2.4.0", + "@docusaurus/utils-validation": "2.4.0", "@slorber/static-site-generator-webpack-plugin": "^4.0.7", "@svgr/webpack": "^6.2.1", "autoprefixer": "^10.4.7", @@ -2011,7 +2011,7 @@ "del": "^6.1.1", "detect-port": "^1.3.0", "escape-html": "^1.0.3", - "eta": "^1.12.3", + "eta": "^2.0.0", "file-loader": "^6.2.0", "fs-extra": "^10.1.0", "html-minifier-terser": "^6.1.0", @@ -2058,9 +2058,9 @@ } }, "node_modules/@docusaurus/cssnano-preset": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@docusaurus/cssnano-preset/-/cssnano-preset-2.2.0.tgz", - "integrity": "sha512-mAAwCo4n66TMWBH1kXnHVZsakW9VAXJzTO4yZukuL3ro4F+JtkMwKfh42EG75K/J/YIFQG5I/Bzy0UH/hFxaTg==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@docusaurus/cssnano-preset/-/cssnano-preset-2.4.0.tgz", + "integrity": "sha512-RmdiA3IpsLgZGXRzqnmTbGv43W4OD44PCo+6Q/aYjEM2V57vKCVqNzuafE94jv0z/PjHoXUrjr69SaRymBKYYw==", "dependencies": { "cssnano-preset-advanced": "^5.3.8", "postcss": "^8.4.14", @@ -2072,9 +2072,9 @@ } }, "node_modules/@docusaurus/logger": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@docusaurus/logger/-/logger-2.2.0.tgz", - "integrity": "sha512-DF3j1cA5y2nNsu/vk8AG7xwpZu6f5MKkPPMaaIbgXLnWGfm6+wkOeW7kNrxnM95YOhKUkJUophX69nGUnLsm0A==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@docusaurus/logger/-/logger-2.4.0.tgz", + "integrity": "sha512-T8+qR4APN+MjcC9yL2Es+xPJ2923S9hpzDmMtdsOcUGLqpCGBbU1vp3AAqDwXtVgFkq+NsEk7sHdVsfLWR/AXw==", "dependencies": { "chalk": "^4.1.2", "tslib": "^2.4.0" @@ -2084,14 +2084,14 @@ } }, "node_modules/@docusaurus/mdx-loader": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@docusaurus/mdx-loader/-/mdx-loader-2.2.0.tgz", - "integrity": "sha512-X2bzo3T0jW0VhUU+XdQofcEeozXOTmKQMvc8tUnWRdTnCvj4XEcBVdC3g+/jftceluiwSTNRAX4VBOJdNt18jA==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@docusaurus/mdx-loader/-/mdx-loader-2.4.0.tgz", + "integrity": "sha512-GWoH4izZKOmFoC+gbI2/y8deH/xKLvzz/T5BsEexBye8EHQlwsA7FMrVa48N063bJBH4FUOiRRXxk5rq9cC36g==", "dependencies": { "@babel/parser": "^7.18.8", "@babel/traverse": "^7.18.8", - "@docusaurus/logger": "2.2.0", - "@docusaurus/utils": "2.2.0", + "@docusaurus/logger": "2.4.0", + "@docusaurus/utils": "2.4.0", "@mdx-js/mdx": "^1.6.22", "escape-html": "^1.0.3", "file-loader": "^6.2.0", @@ -2115,12 +2115,12 @@ } }, "node_modules/@docusaurus/module-type-aliases": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@docusaurus/module-type-aliases/-/module-type-aliases-2.2.0.tgz", - "integrity": "sha512-wDGW4IHKoOr9YuJgy7uYuKWrDrSpsUSDHLZnWQYM9fN7D5EpSmYHjFruUpKWVyxLpD/Wh0rW8hYZwdjJIQUQCQ==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@docusaurus/module-type-aliases/-/module-type-aliases-2.4.0.tgz", + "integrity": "sha512-YEQO2D3UXs72qCn8Cr+RlycSQXVGN9iEUyuHwTuK4/uL/HFomB2FHSU0vSDM23oLd+X/KibQ3Ez6nGjQLqXcHg==", "dependencies": { "@docusaurus/react-loadable": "5.5.2", - "@docusaurus/types": "2.2.0", + "@docusaurus/types": "2.4.0", "@types/history": "^4.7.11", "@types/react": "*", "@types/react-router-config": "*", @@ -2134,17 +2134,17 @@ } }, "node_modules/@docusaurus/plugin-content-blog": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-blog/-/plugin-content-blog-2.2.0.tgz", - "integrity": "sha512-0mWBinEh0a5J2+8ZJXJXbrCk1tSTNf7Nm4tYAl5h2/xx+PvH/Bnu0V+7mMljYm/1QlDYALNIIaT/JcoZQFUN3w==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-blog/-/plugin-content-blog-2.4.0.tgz", + "integrity": "sha512-YwkAkVUxtxoBAIj/MCb4ohN0SCtHBs4AS75jMhPpf67qf3j+U/4n33cELq7567hwyZ6fMz2GPJcVmctzlGGThQ==", "dependencies": { - "@docusaurus/core": "2.2.0", - "@docusaurus/logger": "2.2.0", - "@docusaurus/mdx-loader": "2.2.0", - "@docusaurus/types": "2.2.0", - "@docusaurus/utils": "2.2.0", - "@docusaurus/utils-common": "2.2.0", - "@docusaurus/utils-validation": "2.2.0", + "@docusaurus/core": "2.4.0", + "@docusaurus/logger": "2.4.0", + "@docusaurus/mdx-loader": "2.4.0", + "@docusaurus/types": "2.4.0", + "@docusaurus/utils": "2.4.0", + "@docusaurus/utils-common": "2.4.0", + "@docusaurus/utils-validation": "2.4.0", "cheerio": "^1.0.0-rc.12", "feed": "^4.2.2", "fs-extra": "^10.1.0", @@ -2164,17 +2164,17 @@ } }, "node_modules/@docusaurus/plugin-content-docs": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-docs/-/plugin-content-docs-2.2.0.tgz", - "integrity": "sha512-BOazBR0XjzsHE+2K1wpNxz5QZmrJgmm3+0Re0EVPYFGW8qndCWGNtXW/0lGKhecVPML8yyFeAmnUCIs7xM2wPw==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-docs/-/plugin-content-docs-2.4.0.tgz", + "integrity": "sha512-ic/Z/ZN5Rk/RQo+Io6rUGpToOtNbtPloMR2JcGwC1xT2riMu6zzfSwmBi9tHJgdXH6CB5jG+0dOZZO8QS5tmDg==", "dependencies": { - "@docusaurus/core": "2.2.0", - "@docusaurus/logger": "2.2.0", - "@docusaurus/mdx-loader": "2.2.0", - "@docusaurus/module-type-aliases": "2.2.0", - "@docusaurus/types": "2.2.0", - "@docusaurus/utils": "2.2.0", - "@docusaurus/utils-validation": "2.2.0", + "@docusaurus/core": "2.4.0", + "@docusaurus/logger": "2.4.0", + "@docusaurus/mdx-loader": "2.4.0", + "@docusaurus/module-type-aliases": "2.4.0", + "@docusaurus/types": "2.4.0", + "@docusaurus/utils": "2.4.0", + "@docusaurus/utils-validation": "2.4.0", "@types/react-router-config": "^5.0.6", "combine-promises": "^1.1.0", "fs-extra": "^10.1.0", @@ -2194,15 +2194,15 @@ } }, "node_modules/@docusaurus/plugin-content-pages": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-pages/-/plugin-content-pages-2.2.0.tgz", - "integrity": "sha512-+OTK3FQHk5WMvdelz8v19PbEbx+CNT6VSpx7nVOvMNs5yJCKvmqBJBQ2ZSxROxhVDYn+CZOlmyrC56NSXzHf6g==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-pages/-/plugin-content-pages-2.4.0.tgz", + "integrity": "sha512-Pk2pOeOxk8MeU3mrTU0XLIgP9NZixbdcJmJ7RUFrZp1Aj42nd0RhIT14BGvXXyqb8yTQlk4DmYGAzqOfBsFyGw==", "dependencies": { - "@docusaurus/core": "2.2.0", - "@docusaurus/mdx-loader": "2.2.0", - "@docusaurus/types": "2.2.0", - "@docusaurus/utils": "2.2.0", - "@docusaurus/utils-validation": "2.2.0", + "@docusaurus/core": "2.4.0", + "@docusaurus/mdx-loader": "2.4.0", + "@docusaurus/types": "2.4.0", + "@docusaurus/utils": "2.4.0", + "@docusaurus/utils-validation": "2.4.0", "fs-extra": "^10.1.0", "tslib": "^2.4.0", "webpack": "^5.73.0" @@ -2216,13 +2216,13 @@ } }, "node_modules/@docusaurus/plugin-debug": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-debug/-/plugin-debug-2.2.0.tgz", - "integrity": "sha512-p9vOep8+7OVl6r/NREEYxf4HMAjV8JMYJ7Bos5fCFO0Wyi9AZEo0sCTliRd7R8+dlJXZEgcngSdxAUo/Q+CJow==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-debug/-/plugin-debug-2.4.0.tgz", + "integrity": "sha512-KC56DdYjYT7Txyux71vXHXGYZuP6yYtqwClvYpjKreWIHWus5Zt6VNi23rMZv3/QKhOCrN64zplUbdfQMvddBQ==", "dependencies": { - "@docusaurus/core": "2.2.0", - "@docusaurus/types": "2.2.0", - "@docusaurus/utils": "2.2.0", + "@docusaurus/core": "2.4.0", + "@docusaurus/types": "2.4.0", + "@docusaurus/utils": "2.4.0", "fs-extra": "^10.1.0", "react-json-view": "^1.21.3", "tslib": "^2.4.0" @@ -2236,13 +2236,13 @@ } }, "node_modules/@docusaurus/plugin-google-analytics": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-analytics/-/plugin-google-analytics-2.2.0.tgz", - "integrity": "sha512-+eZVVxVeEnV5nVQJdey9ZsfyEVMls6VyWTIj8SmX0k5EbqGvnIfET+J2pYEuKQnDIHxy+syRMoRM6AHXdHYGIg==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-analytics/-/plugin-google-analytics-2.4.0.tgz", + "integrity": "sha512-uGUzX67DOAIglygdNrmMOvEp8qG03X20jMWadeqVQktS6nADvozpSLGx4J0xbkblhJkUzN21WiilsP9iVP+zkw==", "dependencies": { - "@docusaurus/core": "2.2.0", - "@docusaurus/types": "2.2.0", - "@docusaurus/utils-validation": "2.2.0", + "@docusaurus/core": "2.4.0", + "@docusaurus/types": "2.4.0", + "@docusaurus/utils-validation": "2.4.0", "tslib": "^2.4.0" }, "engines": { @@ -2254,13 +2254,31 @@ } }, "node_modules/@docusaurus/plugin-google-gtag": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-gtag/-/plugin-google-gtag-2.2.0.tgz", - "integrity": "sha512-6SOgczP/dYdkqUMGTRqgxAS1eTp6MnJDAQMy8VCF1QKbWZmlkx4agHDexihqmYyCujTYHqDAhm1hV26EET54NQ==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-gtag/-/plugin-google-gtag-2.4.0.tgz", + "integrity": "sha512-adj/70DANaQs2+TF/nRdMezDXFAV/O/pjAbUgmKBlyOTq5qoMe0Tk4muvQIwWUmiUQxFJe+sKlZGM771ownyOg==", "dependencies": { - "@docusaurus/core": "2.2.0", - "@docusaurus/types": "2.2.0", - "@docusaurus/utils-validation": "2.2.0", + "@docusaurus/core": "2.4.0", + "@docusaurus/types": "2.4.0", + "@docusaurus/utils-validation": "2.4.0", + "tslib": "^2.4.0" + }, + "engines": { + "node": ">=16.14" + }, + "peerDependencies": { + "react": "^16.8.4 || ^17.0.0", + "react-dom": "^16.8.4 || ^17.0.0" + } + }, + "node_modules/@docusaurus/plugin-google-tag-manager": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-tag-manager/-/plugin-google-tag-manager-2.4.0.tgz", + "integrity": "sha512-E66uGcYs4l7yitmp/8kMEVQftFPwV9iC62ORh47Veqzs6ExwnhzBkJmwDnwIysHBF1vlxnzET0Fl2LfL5fRR3A==", + "dependencies": { + "@docusaurus/core": "2.4.0", + "@docusaurus/types": "2.4.0", + "@docusaurus/utils-validation": "2.4.0", "tslib": "^2.4.0" }, "engines": { @@ -2272,16 +2290,16 @@ } }, "node_modules/@docusaurus/plugin-sitemap": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-sitemap/-/plugin-sitemap-2.2.0.tgz", - "integrity": "sha512-0jAmyRDN/aI265CbWZNZuQpFqiZuo+5otk2MylU9iVrz/4J7gSc+ZJ9cy4EHrEsW7PV8s1w18hIEsmcA1YgkKg==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-sitemap/-/plugin-sitemap-2.4.0.tgz", + "integrity": "sha512-pZxh+ygfnI657sN8a/FkYVIAmVv0CGk71QMKqJBOfMmDHNN1FeDeFkBjWP49ejBqpqAhjufkv5UWq3UOu2soCw==", "dependencies": { - "@docusaurus/core": "2.2.0", - "@docusaurus/logger": "2.2.0", - "@docusaurus/types": "2.2.0", - "@docusaurus/utils": "2.2.0", - "@docusaurus/utils-common": "2.2.0", - "@docusaurus/utils-validation": "2.2.0", + "@docusaurus/core": "2.4.0", + "@docusaurus/logger": "2.4.0", + "@docusaurus/types": "2.4.0", + "@docusaurus/utils": "2.4.0", + "@docusaurus/utils-common": "2.4.0", + "@docusaurus/utils-validation": "2.4.0", "fs-extra": "^10.1.0", "sitemap": "^7.1.1", "tslib": "^2.4.0" @@ -2295,22 +2313,23 @@ } }, "node_modules/@docusaurus/preset-classic": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@docusaurus/preset-classic/-/preset-classic-2.2.0.tgz", - "integrity": "sha512-yKIWPGNx7BT8v2wjFIWvYrS+nvN04W+UameSFf8lEiJk6pss0kL6SG2MRvyULiI3BDxH+tj6qe02ncpSPGwumg==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@docusaurus/preset-classic/-/preset-classic-2.4.0.tgz", + "integrity": "sha512-/5z5o/9bc6+P5ool2y01PbJhoGddEGsC0ej1MF6mCoazk8A+kW4feoUd68l7Bnv01rCnG3xy7kHUQP97Y0grUA==", "dependencies": { - "@docusaurus/core": "2.2.0", - "@docusaurus/plugin-content-blog": "2.2.0", - "@docusaurus/plugin-content-docs": "2.2.0", - "@docusaurus/plugin-content-pages": "2.2.0", - "@docusaurus/plugin-debug": "2.2.0", - "@docusaurus/plugin-google-analytics": "2.2.0", - "@docusaurus/plugin-google-gtag": "2.2.0", - "@docusaurus/plugin-sitemap": "2.2.0", - "@docusaurus/theme-classic": "2.2.0", - "@docusaurus/theme-common": "2.2.0", - "@docusaurus/theme-search-algolia": "2.2.0", - "@docusaurus/types": "2.2.0" + "@docusaurus/core": "2.4.0", + "@docusaurus/plugin-content-blog": "2.4.0", + "@docusaurus/plugin-content-docs": "2.4.0", + "@docusaurus/plugin-content-pages": "2.4.0", + "@docusaurus/plugin-debug": "2.4.0", + "@docusaurus/plugin-google-analytics": "2.4.0", + "@docusaurus/plugin-google-gtag": "2.4.0", + "@docusaurus/plugin-google-tag-manager": "2.4.0", + "@docusaurus/plugin-sitemap": "2.4.0", + "@docusaurus/theme-classic": "2.4.0", + "@docusaurus/theme-common": "2.4.0", + "@docusaurus/theme-search-algolia": "2.4.0", + "@docusaurus/types": "2.4.0" }, "engines": { "node": ">=16.14" @@ -2333,26 +2352,26 @@ } }, "node_modules/@docusaurus/theme-classic": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@docusaurus/theme-classic/-/theme-classic-2.2.0.tgz", - "integrity": "sha512-kjbg/qJPwZ6H1CU/i9d4l/LcFgnuzeiGgMQlt6yPqKo0SOJIBMPuz7Rnu3r/WWbZFPi//o8acclacOzmXdUUEg==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@docusaurus/theme-classic/-/theme-classic-2.4.0.tgz", + "integrity": "sha512-GMDX5WU6Z0OC65eQFgl3iNNEbI9IMJz9f6KnOyuMxNUR6q0qVLsKCNopFUDfFNJ55UU50o7P7o21yVhkwpfJ9w==", "dependencies": { - "@docusaurus/core": "2.2.0", - "@docusaurus/mdx-loader": "2.2.0", - "@docusaurus/module-type-aliases": "2.2.0", - "@docusaurus/plugin-content-blog": "2.2.0", - "@docusaurus/plugin-content-docs": "2.2.0", - "@docusaurus/plugin-content-pages": "2.2.0", - "@docusaurus/theme-common": "2.2.0", - "@docusaurus/theme-translations": "2.2.0", - "@docusaurus/types": "2.2.0", - "@docusaurus/utils": "2.2.0", - "@docusaurus/utils-common": "2.2.0", - "@docusaurus/utils-validation": "2.2.0", + "@docusaurus/core": "2.4.0", + "@docusaurus/mdx-loader": "2.4.0", + "@docusaurus/module-type-aliases": "2.4.0", + "@docusaurus/plugin-content-blog": "2.4.0", + "@docusaurus/plugin-content-docs": "2.4.0", + "@docusaurus/plugin-content-pages": "2.4.0", + "@docusaurus/theme-common": "2.4.0", + "@docusaurus/theme-translations": "2.4.0", + "@docusaurus/types": "2.4.0", + "@docusaurus/utils": "2.4.0", + "@docusaurus/utils-common": "2.4.0", + "@docusaurus/utils-validation": "2.4.0", "@mdx-js/react": "^1.6.22", "clsx": "^1.2.1", "copy-text-to-clipboard": "^3.0.1", - "infima": "0.2.0-alpha.42", + "infima": "0.2.0-alpha.43", "lodash": "^4.17.21", "nprogress": "^0.2.0", "postcss": "^8.4.14", @@ -2372,16 +2391,17 @@ } }, "node_modules/@docusaurus/theme-common": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@docusaurus/theme-common/-/theme-common-2.2.0.tgz", - "integrity": "sha512-R8BnDjYoN90DCL75gP7qYQfSjyitXuP9TdzgsKDmSFPNyrdE3twtPNa2dIN+h+p/pr+PagfxwWbd6dn722A1Dw==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@docusaurus/theme-common/-/theme-common-2.4.0.tgz", + "integrity": "sha512-IkG/l5f/FLY6cBIxtPmFnxpuPzc5TupuqlOx+XDN+035MdQcAh8wHXXZJAkTeYDeZ3anIUSUIvWa7/nRKoQEfg==", "dependencies": { - "@docusaurus/mdx-loader": "2.2.0", - "@docusaurus/module-type-aliases": "2.2.0", - "@docusaurus/plugin-content-blog": "2.2.0", - "@docusaurus/plugin-content-docs": "2.2.0", - "@docusaurus/plugin-content-pages": "2.2.0", - "@docusaurus/utils": "2.2.0", + "@docusaurus/mdx-loader": "2.4.0", + "@docusaurus/module-type-aliases": "2.4.0", + "@docusaurus/plugin-content-blog": "2.4.0", + "@docusaurus/plugin-content-docs": "2.4.0", + "@docusaurus/plugin-content-pages": "2.4.0", + "@docusaurus/utils": "2.4.0", + "@docusaurus/utils-common": "2.4.0", "@types/history": "^4.7.11", "@types/react": "*", "@types/react-router-config": "*", @@ -2389,6 +2409,7 @@ "parse-numeric-range": "^1.3.0", "prism-react-renderer": "^1.3.5", "tslib": "^2.4.0", + "use-sync-external-store": "^1.2.0", "utility-types": "^3.10.0" }, "engines": { @@ -2400,22 +2421,22 @@ } }, "node_modules/@docusaurus/theme-search-algolia": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@docusaurus/theme-search-algolia/-/theme-search-algolia-2.2.0.tgz", - "integrity": "sha512-2h38B0tqlxgR2FZ9LpAkGrpDWVdXZ7vltfmTdX+4RsDs3A7khiNsmZB+x/x6sA4+G2V2CvrsPMlsYBy5X+cY1w==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@docusaurus/theme-search-algolia/-/theme-search-algolia-2.4.0.tgz", + "integrity": "sha512-pPCJSCL1Qt4pu/Z0uxBAuke0yEBbxh0s4fOvimna7TEcBLPq0x06/K78AaABXrTVQM6S0vdocFl9EoNgU17hqA==", "dependencies": { "@docsearch/react": "^3.1.1", - "@docusaurus/core": "2.2.0", - "@docusaurus/logger": "2.2.0", - "@docusaurus/plugin-content-docs": "2.2.0", - "@docusaurus/theme-common": "2.2.0", - "@docusaurus/theme-translations": "2.2.0", - "@docusaurus/utils": "2.2.0", - "@docusaurus/utils-validation": "2.2.0", + "@docusaurus/core": "2.4.0", + "@docusaurus/logger": "2.4.0", + "@docusaurus/plugin-content-docs": "2.4.0", + "@docusaurus/theme-common": "2.4.0", + "@docusaurus/theme-translations": "2.4.0", + "@docusaurus/utils": "2.4.0", + "@docusaurus/utils-validation": "2.4.0", "algoliasearch": "^4.13.1", "algoliasearch-helper": "^3.10.0", "clsx": "^1.2.1", - "eta": "^1.12.3", + "eta": "^2.0.0", "fs-extra": "^10.1.0", "lodash": "^4.17.21", "tslib": "^2.4.0", @@ -2430,9 +2451,9 @@ } }, "node_modules/@docusaurus/theme-translations": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@docusaurus/theme-translations/-/theme-translations-2.2.0.tgz", - "integrity": "sha512-3T140AG11OjJrtKlY4pMZ5BzbGRDjNs2co5hJ6uYJG1bVWlhcaFGqkaZ5lCgKflaNHD7UHBHU9Ec5f69jTdd6w==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@docusaurus/theme-translations/-/theme-translations-2.4.0.tgz", + "integrity": "sha512-kEoITnPXzDPUMBHk3+fzEzbopxLD3fR5sDoayNH0vXkpUukA88/aDL1bqkhxWZHA3LOfJ3f0vJbOwmnXW5v85Q==", "dependencies": { "fs-extra": "^10.1.0", "tslib": "^2.4.0" @@ -2442,9 +2463,9 @@ } }, "node_modules/@docusaurus/types": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@docusaurus/types/-/types-2.2.0.tgz", - "integrity": "sha512-b6xxyoexfbRNRI8gjblzVOnLr4peCJhGbYGPpJ3LFqpi5nsFfoK4mmDLvWdeah0B7gmJeXabN7nQkFoqeSdmOw==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@docusaurus/types/-/types-2.4.0.tgz", + "integrity": "sha512-xaBXr+KIPDkIaef06c+i2HeTqVNixB7yFut5fBXPGI2f1rrmEV2vLMznNGsFwvZ5XmA3Quuefd4OGRkdo97Dhw==", "dependencies": { "@types/history": "^4.7.11", "@types/react": "*", @@ -2461,12 +2482,13 @@ } }, "node_modules/@docusaurus/utils": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@docusaurus/utils/-/utils-2.2.0.tgz", - "integrity": "sha512-oNk3cjvx7Tt1Lgh/aeZAmFpGV2pDr5nHKrBVx6hTkzGhrnMuQqLt6UPlQjdYQ3QHXwyF/ZtZMO1D5Pfi0lu7SA==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@docusaurus/utils/-/utils-2.4.0.tgz", + "integrity": "sha512-89hLYkvtRX92j+C+ERYTuSUK6nF9bGM32QThcHPg2EDDHVw6FzYQXmX6/p+pU5SDyyx5nBlE4qXR92RxCAOqfg==", "dependencies": { - "@docusaurus/logger": "2.2.0", + "@docusaurus/logger": "2.4.0", "@svgr/webpack": "^6.2.1", + "escape-string-regexp": "^4.0.0", "file-loader": "^6.2.0", "fs-extra": "^10.1.0", "github-slugger": "^1.4.0", @@ -2494,9 +2516,9 @@ } }, "node_modules/@docusaurus/utils-common": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@docusaurus/utils-common/-/utils-common-2.2.0.tgz", - "integrity": "sha512-qebnerHp+cyovdUseDQyYFvMW1n1nv61zGe5JJfoNQUnjKuApch3IVsz+/lZ9a38pId8kqehC1Ao2bW/s0ntDA==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@docusaurus/utils-common/-/utils-common-2.4.0.tgz", + "integrity": "sha512-zIMf10xuKxddYfLg5cS19x44zud/E9I7lj3+0bv8UIs0aahpErfNrGhijEfJpAfikhQ8tL3m35nH3hJ3sOG82A==", "dependencies": { "tslib": "^2.4.0" }, @@ -2513,12 +2535,12 @@ } }, "node_modules/@docusaurus/utils-validation": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@docusaurus/utils-validation/-/utils-validation-2.2.0.tgz", - "integrity": "sha512-I1hcsG3yoCkasOL5qQAYAfnmVoLei7apugT6m4crQjmDGxq+UkiRrq55UqmDDyZlac/6ax/JC0p+usZ6W4nVyg==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@docusaurus/utils-validation/-/utils-validation-2.4.0.tgz", + "integrity": "sha512-IrBsBbbAp6y7mZdJx4S4pIA7dUyWSA0GNosPk6ZJ0fX3uYIEQgcQSGIgTeSC+8xPEx3c16o03en1jSDpgQgz/w==", "dependencies": { - "@docusaurus/logger": "2.2.0", - "@docusaurus/utils": "2.2.0", + "@docusaurus/logger": "2.4.0", + "@docusaurus/utils": "2.4.0", "joi": "^17.6.0", "js-yaml": "^4.1.0", "tslib": "^2.4.0" @@ -3645,30 +3667,30 @@ } }, "node_modules/algoliasearch": { - "version": "4.14.2", - "resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-4.14.2.tgz", - "integrity": "sha512-ngbEQonGEmf8dyEh5f+uOIihv4176dgbuOZspiuhmTTBRBuzWu3KCGHre6uHj5YyuC7pNvQGzB6ZNJyZi0z+Sg==", + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-4.17.0.tgz", + "integrity": "sha512-JMRh2Mw6sEnVMiz6+APsi7lx9a2jiDFF+WUtANaUVCv6uSU9UOLdo5h9K3pdP6frRRybaM2fX8b1u0nqICS9aA==", "dependencies": { - "@algolia/cache-browser-local-storage": "4.14.2", - "@algolia/cache-common": "4.14.2", - "@algolia/cache-in-memory": "4.14.2", - "@algolia/client-account": "4.14.2", - "@algolia/client-analytics": "4.14.2", - "@algolia/client-common": "4.14.2", - "@algolia/client-personalization": "4.14.2", - "@algolia/client-search": "4.14.2", - "@algolia/logger-common": "4.14.2", - "@algolia/logger-console": "4.14.2", - "@algolia/requester-browser-xhr": "4.14.2", - "@algolia/requester-common": "4.14.2", - "@algolia/requester-node-http": "4.14.2", - "@algolia/transporter": "4.14.2" + "@algolia/cache-browser-local-storage": "4.17.0", + "@algolia/cache-common": "4.17.0", + "@algolia/cache-in-memory": "4.17.0", + "@algolia/client-account": "4.17.0", + "@algolia/client-analytics": "4.17.0", + "@algolia/client-common": "4.17.0", + "@algolia/client-personalization": "4.17.0", + "@algolia/client-search": "4.17.0", + "@algolia/logger-common": "4.17.0", + "@algolia/logger-console": "4.17.0", + "@algolia/requester-browser-xhr": "4.17.0", + "@algolia/requester-common": "4.17.0", + "@algolia/requester-node-http": "4.17.0", + "@algolia/transporter": "4.17.0" } }, "node_modules/algoliasearch-helper": { - "version": "3.11.1", - "resolved": "https://registry.npmjs.org/algoliasearch-helper/-/algoliasearch-helper-3.11.1.tgz", - "integrity": "sha512-mvsPN3eK4E0bZG0/WlWJjeqe/bUD2KOEVOl0GyL/TGXn6wcpZU8NOuztGHCUKXkyg5gq6YzUakVTmnmSSO5Yiw==", + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/algoliasearch-helper/-/algoliasearch-helper-3.12.0.tgz", + "integrity": "sha512-/j1U3PEwdan0n6P/QqSnSpNSLC5+cEMvyljd5CnmNmUjDlGrys+vFEOwjVEnqELIiAGMHEA/Nl3CiKVFBUYqyQ==", "dependencies": { "@algolia/events": "^4.0.1" }, @@ -3781,9 +3803,9 @@ } }, "node_modules/autoprefixer": { - "version": "10.4.13", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.13.tgz", - "integrity": "sha512-49vKpMqcZYsJjwotvt4+h/BCjJVnhGwcLpDt5xkcaOG3eLrG/HUYLagrihYsQ+qrIBgIzX1Rw7a6L8I/ZA1Atg==", + "version": "10.4.14", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.14.tgz", + "integrity": "sha512-FQzyfOsTlwVzjHxKEqRIAdJx9niO6VCBCoEwax/VLSoQF29ggECcPuBqUMZ+u8jCZOPSy8b8/8KnuFbp0SaFZQ==", "funding": [ { "type": "opencollective", @@ -3795,8 +3817,8 @@ } ], "dependencies": { - "browserslist": "^4.21.4", - "caniuse-lite": "^1.0.30001426", + "browserslist": "^4.21.5", + "caniuse-lite": "^1.0.30001464", "fraction.js": "^4.2.0", "normalize-range": "^0.1.2", "picocolors": "^1.0.0", @@ -4087,9 +4109,9 @@ } }, "node_modules/browserslist": { - "version": "4.21.4", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.4.tgz", - "integrity": "sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw==", + "version": "4.21.5", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.5.tgz", + "integrity": "sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w==", "funding": [ { "type": "opencollective", @@ -4101,10 +4123,10 @@ } ], "dependencies": { - "caniuse-lite": "^1.0.30001400", - "electron-to-chromium": "^1.4.251", - "node-releases": "^2.0.6", - "update-browserslist-db": "^1.0.9" + "caniuse-lite": "^1.0.30001449", + "electron-to-chromium": "^1.4.284", + "node-releases": "^2.0.8", + "update-browserslist-db": "^1.0.10" }, "bin": { "browserslist": "cli.js" @@ -4233,9 +4255,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001431", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001431.tgz", - "integrity": "sha512-zBUoFU0ZcxpvSt9IU66dXVT/3ctO1cy4y9cscs1szkPlcWb6pasYM144GqrUygUbT+k7cmUCW61cvskjcv0enQ==", + "version": "1.0.30001478", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001478.tgz", + "integrity": "sha512-gMhDyXGItTHipJj2ApIvR+iVB5hd0KP3svMWWXDvZOmjzJJassGLMfxRkQCSYgGd2gtdL/ReeiyvMSFD1Ss6Mw==", "funding": [ { "type": "opencollective", @@ -4244,6 +4266,10 @@ { "type": "tidelift", "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" } ] }, @@ -4680,9 +4706,9 @@ "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" }, "node_modules/copy-text-to-clipboard": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/copy-text-to-clipboard/-/copy-text-to-clipboard-3.0.1.tgz", - "integrity": "sha512-rvVsHrpFcL4F2P8ihsoLdFHmd404+CMg71S756oRSeQgqk51U3kicGdnvfkrxva0xXH92SjGS62B0XIJsbh+9Q==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/copy-text-to-clipboard/-/copy-text-to-clipboard-3.1.0.tgz", + "integrity": "sha512-PFM6BnjLnOON/lB3ta/Jg7Ywsv+l9kQGD4TWDCSlRBGmqnnTM5MrDkhAFgw+8HZt0wW6Q2BBE4cmy9sq+s9Qng==", "engines": { "node": ">=12" }, @@ -5081,12 +5107,12 @@ } }, "node_modules/cssnano-preset-advanced": { - "version": "5.3.9", - "resolved": "https://registry.npmjs.org/cssnano-preset-advanced/-/cssnano-preset-advanced-5.3.9.tgz", - "integrity": "sha512-njnh4pp1xCsibJcEHnWZb4EEzni0ePMqPuPNyuWT4Z+YeXmsgqNuTPIljXFEXhxGsWs9183JkXgHxc1TcsahIg==", + "version": "5.3.10", + "resolved": "https://registry.npmjs.org/cssnano-preset-advanced/-/cssnano-preset-advanced-5.3.10.tgz", + "integrity": "sha512-fnYJyCS9jgMU+cmHO1rPSPf9axbQyD7iUhLO5Df6O4G+fKIOMps+ZbU0PdGFejFBBZ3Pftf18fn1eG7MAPUSWQ==", "dependencies": { "autoprefixer": "^10.4.12", - "cssnano-preset-default": "^5.2.13", + "cssnano-preset-default": "^5.2.14", "postcss-discard-unused": "^5.1.0", "postcss-merge-idents": "^5.1.1", "postcss-reduce-idents": "^5.2.0", @@ -5100,21 +5126,21 @@ } }, "node_modules/cssnano-preset-default": { - "version": "5.2.13", - "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-5.2.13.tgz", - "integrity": "sha512-PX7sQ4Pb+UtOWuz8A1d+Rbi+WimBIxJTRyBdgGp1J75VU0r/HFQeLnMYgHiCAp6AR4rqrc7Y4R+1Rjk3KJz6DQ==", + "version": "5.2.14", + "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-5.2.14.tgz", + "integrity": "sha512-t0SFesj/ZV2OTylqQVOrFgEh5uanxbO6ZAdeCrNsUQ6fVuXwYTxJPNAGvGTxHbD68ldIJNec7PyYZDBrfDQ+6A==", "dependencies": { "css-declaration-sorter": "^6.3.1", "cssnano-utils": "^3.1.0", "postcss-calc": "^8.2.3", - "postcss-colormin": "^5.3.0", + "postcss-colormin": "^5.3.1", "postcss-convert-values": "^5.1.3", "postcss-discard-comments": "^5.1.2", "postcss-discard-duplicates": "^5.1.0", "postcss-discard-empty": "^5.1.1", "postcss-discard-overridden": "^5.1.0", "postcss-merge-longhand": "^5.1.7", - "postcss-merge-rules": "^5.1.3", + "postcss-merge-rules": "^5.1.4", "postcss-minify-font-values": "^5.1.0", "postcss-minify-gradients": "^5.1.1", "postcss-minify-params": "^5.1.4", @@ -5129,7 +5155,7 @@ "postcss-normalize-url": "^5.1.0", "postcss-normalize-whitespace": "^5.1.1", "postcss-ordered-values": "^5.1.3", - "postcss-reduce-initial": "^5.1.1", + "postcss-reduce-initial": "^5.1.2", "postcss-reduce-transforms": "^5.1.0", "postcss-svgo": "^5.1.0", "postcss-unique-selectors": "^5.1.1" @@ -5652,9 +5678,9 @@ } }, "node_modules/eta": { - "version": "1.12.3", - "resolved": "https://registry.npmjs.org/eta/-/eta-1.12.3.tgz", - "integrity": "sha512-qHixwbDLtekO/d51Yr4glcaUJCIjGVJyTzuqV4GPlgZo1YpgOKG+avQynErZIYrfM6JIJdtiG2Kox8tbb+DoGg==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/eta/-/eta-2.0.1.tgz", + "integrity": "sha512-46E2qDPDm7QA+usjffUWz9KfXsxVZclPOuKsXs4ZWZdI/X1wpDF7AO424pt7fdYohCzWsIkXAhNGXSlwo5naAg==", "engines": { "node": ">=6.0.0" }, @@ -6033,9 +6059,9 @@ } }, "node_modules/flux": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/flux/-/flux-4.0.3.tgz", - "integrity": "sha512-yKAbrp7JhZhj6uiT1FTuVMlIAT1J4jqEyBpFApi1kxpGZCvacMVc/t1pMQyotqHhAgvoE3bNvAykhCo2CLjnYw==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/flux/-/flux-4.0.4.tgz", + "integrity": "sha512-NCj3XlayA2UsapRpM7va6wU1+9rE5FIL7qoMcmxWHRzbp0yujihMBm9BBHZ1MDIk5h5o2Bl6eGiCe8rYELAmYw==", "dependencies": { "fbemitter": "^3.0.0", "fbjs": "^3.0.1" @@ -6753,9 +6779,9 @@ } }, "node_modules/htmlparser2": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.1.tgz", - "integrity": "sha512-4lVbmc1diZC7GUJQtRQ5yBAeUCL1exyMwmForWkRLnwyzWBFxN633SALPMGYaWZvKe9j1pRZJpauvmxENSp/EA==", + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz", + "integrity": "sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==", "funding": [ "https://github.com/fb55/htmlparser2?sponsor=1", { @@ -6765,9 +6791,9 @@ ], "dependencies": { "domelementtype": "^2.3.0", - "domhandler": "^5.0.2", + "domhandler": "^5.0.3", "domutils": "^3.0.1", - "entities": "^4.3.0" + "entities": "^4.4.0" } }, "node_modules/http-cache-semantics": { @@ -6948,9 +6974,9 @@ } }, "node_modules/infima": { - "version": "0.2.0-alpha.42", - "resolved": "https://registry.npmjs.org/infima/-/infima-0.2.0-alpha.42.tgz", - "integrity": "sha512-ift8OXNbQQwtbIt6z16KnSWP7uJ/SysSMFI4F87MNRTicypfl4Pv3E2OGVv6N3nSZFJvA8imYulCBS64iyHYww==", + "version": "0.2.0-alpha.43", + "resolved": "https://registry.npmjs.org/infima/-/infima-0.2.0-alpha.43.tgz", + "integrity": "sha512-2uw57LvUqW0rK/SWYnd/2rRfxNA5DDNOh33jxF7fy46VWoNhGxiUQyVZHbBMjQ33mQem0cjdDVwgWVAmlRfgyQ==", "engines": { "node": ">=12" } @@ -7969,9 +7995,9 @@ } }, "node_modules/node-releases": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.6.tgz", - "integrity": "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==" + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.10.tgz", + "integrity": "sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w==" }, "node_modules/normalize-path": { "version": "3.0.0", @@ -8287,9 +8313,9 @@ "integrity": "sha512-twN+njEipszzlMJd4ONUYgSfZPDxgHhT9Ahed5uTigpQn90FggW4SA/AIPq/6a149fTbE9qBEcSwE3FAEp6wQQ==" }, "node_modules/parse5": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.1.tgz", - "integrity": "sha512-kwpuwzB+px5WUg9pyK0IcK/shltJN5/OVhQagxhCQNtT9Y9QRZqNY2e1cmbu/paRh5LMnz/oVTVLBpjFmMZhSg==", + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", + "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", "dependencies": { "entities": "^4.4.0" }, @@ -8489,11 +8515,11 @@ } }, "node_modules/postcss-colormin": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-5.3.0.tgz", - "integrity": "sha512-WdDO4gOFG2Z8n4P8TWBpshnL3JpmNmJwdnfP2gbk2qBA8PWwOYcmjmI/t3CmMeL72a7Hkd+x/Mg9O2/0rD54Pg==", + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-5.3.1.tgz", + "integrity": "sha512-UsWQG0AqTFQmpBegeLLc1+c3jIqBNB0zlDGRWR+dQ3pRKJL1oeMzyqmH3o2PIfn9MBdNrVPWhDbT769LxCTLJQ==", "dependencies": { - "browserslist": "^4.16.6", + "browserslist": "^4.21.4", "caniuse-api": "^3.0.0", "colord": "^2.9.1", "postcss-value-parser": "^4.2.0" @@ -8630,9 +8656,9 @@ } }, "node_modules/postcss-merge-rules": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-5.1.3.tgz", - "integrity": "sha512-LbLd7uFC00vpOuMvyZop8+vvhnfRGpp2S+IMQKeuOZZapPRY4SMq5ErjQeHbHsjCUgJkRNrlU+LmxsKIqPKQlA==", + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-5.1.4.tgz", + "integrity": "sha512-0R2IuYpgU93y9lhVbO/OylTtKMVcHb67zjWIfCiKR9rWL3GUk1677LAqD/BcHizukdZEjT8Ru3oHRoAYoJy44g==", "dependencies": { "browserslist": "^4.21.4", "caniuse-api": "^3.0.0", @@ -8916,9 +8942,9 @@ } }, "node_modules/postcss-reduce-initial": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-5.1.1.tgz", - "integrity": "sha512-//jeDqWcHPuXGZLoolFrUXBDyuEGbr9S2rMo19bkTIjBQ4PqkaO+oI8wua5BOUxpfi97i3PCoInsiFIEBfkm9w==", + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-5.1.2.tgz", + "integrity": "sha512-dE/y2XRaqAi6OvjzD22pjTUQ8eOfc6m/natGHgKFBK9DxFmIm69YmaRVQrGgFlEfc1HePIurY0TmDeROK05rIg==", "dependencies": { "browserslist": "^4.21.4", "caniuse-api": "^3.0.0" @@ -9549,11 +9575,11 @@ } }, "node_modules/react-textarea-autosize": { - "version": "8.3.4", - "resolved": "https://registry.npmjs.org/react-textarea-autosize/-/react-textarea-autosize-8.3.4.tgz", - "integrity": "sha512-CdtmP8Dc19xL8/R6sWvtknD/eCXkQr30dtvC4VmGInhRsfF8X/ihXCq6+9l9qbxmKRiq407/7z5fxE7cVWQNgQ==", + "version": "8.4.1", + "resolved": "https://registry.npmjs.org/react-textarea-autosize/-/react-textarea-autosize-8.4.1.tgz", + "integrity": "sha512-aD2C+qK6QypknC+lCMzteOdIjoMbNlgSFmJjCV+DrfTPwp59i/it9mMNf2HDzvRjQgKAyBDPyLJhcrzElf2U4Q==", "dependencies": { - "@babel/runtime": "^7.10.2", + "@babel/runtime": "^7.20.13", "use-composed-ref": "^1.3.0", "use-latest": "^1.2.1" }, @@ -9632,9 +9658,9 @@ } }, "node_modules/regenerator-runtime": { - "version": "0.13.10", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.10.tgz", - "integrity": "sha512-KepLsg4dU12hryUO7bp/axHAKvwGOCV0sGloQtpagJ12ai+ojVDqkeGSiRX1zlq+kjIMZ1t7gpze+26QqtdGqw==" + "version": "0.13.11", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", + "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==" }, "node_modules/regenerator-transform": { "version": "0.15.0", @@ -11170,9 +11196,9 @@ } }, "node_modules/ua-parser-js": { - "version": "0.7.32", - "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.32.tgz", - "integrity": "sha512-f9BESNVhzlhEFf2CHMSj40NWOjYPl1YKYbrvIr/hFTDEmLq7SRbWvm7FcdcpCYT95zrOhC7gZSxjdnnTpBcwVw==", + "version": "0.7.35", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.35.tgz", + "integrity": "sha512-veRf7dawaj9xaWEu9HoTVn5Pggtc/qj+kqTOFvNiN1l0YdxwC1kvel57UCjThjGa3BHBihE8/UJAHI+uQHmd/g==", "funding": [ { "type": "opencollective", @@ -11639,6 +11665,14 @@ } } }, + "node_modules/use-sync-external-store": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz", + "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -12304,95 +12338,95 @@ }, "dependencies": { "@algolia/autocomplete-core": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/@algolia/autocomplete-core/-/autocomplete-core-1.7.2.tgz", - "integrity": "sha512-eclwUDC6qfApNnEfu1uWcL/rudQsn59tjEoUYZYE2JSXZrHLRjBUGMxiCoknobU2Pva8ejb0eRxpIYDtVVqdsw==", + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-core/-/autocomplete-core-1.7.4.tgz", + "integrity": "sha512-daoLpQ3ps/VTMRZDEBfU8ixXd+amZcNJ4QSP3IERGyzqnL5Ch8uSRFt/4G8pUvW9c3o6GA4vtVv4I4lmnkdXyg==", "requires": { - "@algolia/autocomplete-shared": "1.7.2" + "@algolia/autocomplete-shared": "1.7.4" } }, "@algolia/autocomplete-preset-algolia": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/@algolia/autocomplete-preset-algolia/-/autocomplete-preset-algolia-1.7.2.tgz", - "integrity": "sha512-+RYEG6B0QiGGfRb2G3MtPfyrl0dALF3cQNTWBzBX6p5o01vCCGTTinAm2UKG3tfc2CnOMAtnPLkzNZyJUpnVJw==", + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-preset-algolia/-/autocomplete-preset-algolia-1.7.4.tgz", + "integrity": "sha512-s37hrvLEIfcmKY8VU9LsAXgm2yfmkdHT3DnA3SgHaY93yjZ2qL57wzb5QweVkYuEBZkT2PIREvRoLXC2sxTbpQ==", "requires": { - "@algolia/autocomplete-shared": "1.7.2" + "@algolia/autocomplete-shared": "1.7.4" } }, "@algolia/autocomplete-shared": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/@algolia/autocomplete-shared/-/autocomplete-shared-1.7.2.tgz", - "integrity": "sha512-QCckjiC7xXHIUaIL3ektBtjJ0w7tTA3iqKcAE/Hjn1lZ5omp7i3Y4e09rAr9ZybqirL7AbxCLLq0Ra5DDPKeug==" + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-shared/-/autocomplete-shared-1.7.4.tgz", + "integrity": "sha512-2VGCk7I9tA9Ge73Km99+Qg87w0wzW4tgUruvWAn/gfey1ZXgmxZtyIRBebk35R1O8TbK77wujVtCnpsGpRy1kg==" }, "@algolia/cache-browser-local-storage": { - "version": "4.14.2", - "resolved": "https://registry.npmjs.org/@algolia/cache-browser-local-storage/-/cache-browser-local-storage-4.14.2.tgz", - "integrity": "sha512-FRweBkK/ywO+GKYfAWbrepewQsPTIEirhi1BdykX9mxvBPtGNKccYAxvGdDCumU1jL4r3cayio4psfzKMejBlA==", + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/@algolia/cache-browser-local-storage/-/cache-browser-local-storage-4.17.0.tgz", + "integrity": "sha512-myRSRZDIMYB8uCkO+lb40YKiYHi0fjpWRtJpR/dgkaiBlSD0plRyB6lLOh1XIfmMcSeBOqDE7y9m8xZMrXYfyQ==", "requires": { - "@algolia/cache-common": "4.14.2" + "@algolia/cache-common": "4.17.0" } }, "@algolia/cache-common": { - "version": "4.14.2", - "resolved": "https://registry.npmjs.org/@algolia/cache-common/-/cache-common-4.14.2.tgz", - "integrity": "sha512-SbvAlG9VqNanCErr44q6lEKD2qoK4XtFNx9Qn8FK26ePCI8I9yU7pYB+eM/cZdS9SzQCRJBbHUumVr4bsQ4uxg==" + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/@algolia/cache-common/-/cache-common-4.17.0.tgz", + "integrity": "sha512-g8mXzkrcUBIPZaulAuqE7xyHhLAYAcF2xSch7d9dABheybaU3U91LjBX6eJTEB7XVhEsgK4Smi27vWtAJRhIKQ==" }, "@algolia/cache-in-memory": { - "version": "4.14.2", - "resolved": "https://registry.npmjs.org/@algolia/cache-in-memory/-/cache-in-memory-4.14.2.tgz", - "integrity": "sha512-HrOukWoop9XB/VFojPv1R5SVXowgI56T9pmezd/djh2JnVN/vXswhXV51RKy4nCpqxyHt/aGFSq2qkDvj6KiuQ==", + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/@algolia/cache-in-memory/-/cache-in-memory-4.17.0.tgz", + "integrity": "sha512-PT32ciC/xI8z919d0oknWVu3kMfTlhQn3MKxDln3pkn+yA7F7xrxSALysxquv+MhFfNAcrtQ/oVvQVBAQSHtdw==", "requires": { - "@algolia/cache-common": "4.14.2" + "@algolia/cache-common": "4.17.0" } }, "@algolia/client-account": { - "version": "4.14.2", - "resolved": "https://registry.npmjs.org/@algolia/client-account/-/client-account-4.14.2.tgz", - "integrity": "sha512-WHtriQqGyibbb/Rx71YY43T0cXqyelEU0lB2QMBRXvD2X0iyeGl4qMxocgEIcbHyK7uqE7hKgjT8aBrHqhgc1w==", + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/@algolia/client-account/-/client-account-4.17.0.tgz", + "integrity": "sha512-sSEHx9GA6m7wrlsSMNBGfyzlIfDT2fkz2u7jqfCCd6JEEwmxt8emGmxAU/0qBfbhRSuGvzojoLJlr83BSZAKjA==", "requires": { - "@algolia/client-common": "4.14.2", - "@algolia/client-search": "4.14.2", - "@algolia/transporter": "4.14.2" + "@algolia/client-common": "4.17.0", + "@algolia/client-search": "4.17.0", + "@algolia/transporter": "4.17.0" } }, "@algolia/client-analytics": { - "version": "4.14.2", - "resolved": "https://registry.npmjs.org/@algolia/client-analytics/-/client-analytics-4.14.2.tgz", - "integrity": "sha512-yBvBv2mw+HX5a+aeR0dkvUbFZsiC4FKSnfqk9rrfX+QrlNOKEhCG0tJzjiOggRW4EcNqRmaTULIYvIzQVL2KYQ==", + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/@algolia/client-analytics/-/client-analytics-4.17.0.tgz", + "integrity": "sha512-84ooP8QA3mQ958hQ9wozk7hFUbAO+81CX1CjAuerxBqjKIInh1fOhXKTaku05O/GHBvcfExpPLIQuSuLYziBXQ==", "requires": { - "@algolia/client-common": "4.14.2", - "@algolia/client-search": "4.14.2", - "@algolia/requester-common": "4.14.2", - "@algolia/transporter": "4.14.2" + "@algolia/client-common": "4.17.0", + "@algolia/client-search": "4.17.0", + "@algolia/requester-common": "4.17.0", + "@algolia/transporter": "4.17.0" } }, "@algolia/client-common": { - "version": "4.14.2", - "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-4.14.2.tgz", - "integrity": "sha512-43o4fslNLcktgtDMVaT5XwlzsDPzlqvqesRi4MjQz2x4/Sxm7zYg5LRYFol1BIhG6EwxKvSUq8HcC/KxJu3J0Q==", + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-4.17.0.tgz", + "integrity": "sha512-jHMks0ZFicf8nRDn6ma8DNNsdwGgP/NKiAAL9z6rS7CymJ7L0+QqTJl3rYxRW7TmBhsUH40wqzmrG6aMIN/DrQ==", "requires": { - "@algolia/requester-common": "4.14.2", - "@algolia/transporter": "4.14.2" + "@algolia/requester-common": "4.17.0", + "@algolia/transporter": "4.17.0" } }, "@algolia/client-personalization": { - "version": "4.14.2", - "resolved": "https://registry.npmjs.org/@algolia/client-personalization/-/client-personalization-4.14.2.tgz", - "integrity": "sha512-ACCoLi0cL8CBZ1W/2juehSltrw2iqsQBnfiu/Rbl9W2yE6o2ZUb97+sqN/jBqYNQBS+o0ekTMKNkQjHHAcEXNw==", + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/@algolia/client-personalization/-/client-personalization-4.17.0.tgz", + "integrity": "sha512-RMzN4dZLIta1YuwT7QC9o+OeGz2cU6eTOlGNE/6RcUBLOU3l9tkCOdln5dPE2jp8GZXPl2yk54b2nSs1+pAjqw==", "requires": { - "@algolia/client-common": "4.14.2", - "@algolia/requester-common": "4.14.2", - "@algolia/transporter": "4.14.2" + "@algolia/client-common": "4.17.0", + "@algolia/requester-common": "4.17.0", + "@algolia/transporter": "4.17.0" } }, "@algolia/client-search": { - "version": "4.14.2", - "resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-4.14.2.tgz", - "integrity": "sha512-L5zScdOmcZ6NGiVbLKTvP02UbxZ0njd5Vq9nJAmPFtjffUSOGEp11BmD2oMJ5QvARgx2XbX4KzTTNS5ECYIMWw==", + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-4.17.0.tgz", + "integrity": "sha512-x4P2wKrrRIXszT8gb7eWsMHNNHAJs0wE7/uqbufm4tZenAp+hwU/hq5KVsY50v+PfwM0LcDwwn/1DroujsTFoA==", "requires": { - "@algolia/client-common": "4.14.2", - "@algolia/requester-common": "4.14.2", - "@algolia/transporter": "4.14.2" + "@algolia/client-common": "4.17.0", + "@algolia/requester-common": "4.17.0", + "@algolia/transporter": "4.17.0" } }, "@algolia/events": { @@ -12401,47 +12435,47 @@ "integrity": "sha512-FQzvOCgoFXAbf5Y6mYozw2aj5KCJoA3m4heImceldzPSMbdyS4atVjJzXKMsfX3wnZTFYwkkt8/z8UesLHlSBQ==" }, "@algolia/logger-common": { - "version": "4.14.2", - "resolved": "https://registry.npmjs.org/@algolia/logger-common/-/logger-common-4.14.2.tgz", - "integrity": "sha512-/JGlYvdV++IcMHBnVFsqEisTiOeEr6cUJtpjz8zc0A9c31JrtLm318Njc72p14Pnkw3A/5lHHh+QxpJ6WFTmsA==" + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/@algolia/logger-common/-/logger-common-4.17.0.tgz", + "integrity": "sha512-DGuoZqpTmIKJFDeyAJ7M8E/LOenIjWiOsg1XJ1OqAU/eofp49JfqXxbfgctlVZVmDABIyOz8LqEoJ6ZP4DTyvw==" }, "@algolia/logger-console": { - "version": "4.14.2", - "resolved": "https://registry.npmjs.org/@algolia/logger-console/-/logger-console-4.14.2.tgz", - "integrity": "sha512-8S2PlpdshbkwlLCSAB5f8c91xyc84VM9Ar9EdfE9UmX+NrKNYnWR1maXXVDQQoto07G1Ol/tYFnFVhUZq0xV/g==", + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/@algolia/logger-console/-/logger-console-4.17.0.tgz", + "integrity": "sha512-zMPvugQV/gbXUvWBCzihw6m7oxIKp48w37QBIUu/XqQQfxhjoOE9xyfJr1KldUt5FrYOKZJVsJaEjTsu+bIgQg==", "requires": { - "@algolia/logger-common": "4.14.2" + "@algolia/logger-common": "4.17.0" } }, "@algolia/requester-browser-xhr": { - "version": "4.14.2", - "resolved": "https://registry.npmjs.org/@algolia/requester-browser-xhr/-/requester-browser-xhr-4.14.2.tgz", - "integrity": "sha512-CEh//xYz/WfxHFh7pcMjQNWgpl4wFB85lUMRyVwaDPibNzQRVcV33YS+63fShFWc2+42YEipFGH2iPzlpszmDw==", + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/@algolia/requester-browser-xhr/-/requester-browser-xhr-4.17.0.tgz", + "integrity": "sha512-aSOX/smauyTkP21Pf52pJ1O2LmNFJ5iHRIzEeTh0mwBeADO4GdG94cAWDILFA9rNblq/nK3EDh3+UyHHjplZ1A==", "requires": { - "@algolia/requester-common": "4.14.2" + "@algolia/requester-common": "4.17.0" } }, "@algolia/requester-common": { - "version": "4.14.2", - "resolved": "https://registry.npmjs.org/@algolia/requester-common/-/requester-common-4.14.2.tgz", - "integrity": "sha512-73YQsBOKa5fvVV3My7iZHu1sUqmjjfs9TteFWwPwDmnad7T0VTCopttcsM3OjLxZFtBnX61Xxl2T2gmG2O4ehg==" + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/@algolia/requester-common/-/requester-common-4.17.0.tgz", + "integrity": "sha512-XJjmWFEUlHu0ijvcHBoixuXfEoiRUdyzQM6YwTuB8usJNIgShua8ouFlRWF8iCeag0vZZiUm4S2WCVBPkdxFgg==" }, "@algolia/requester-node-http": { - "version": "4.14.2", - "resolved": "https://registry.npmjs.org/@algolia/requester-node-http/-/requester-node-http-4.14.2.tgz", - "integrity": "sha512-oDbb02kd1o5GTEld4pETlPZLY0e+gOSWjWMJHWTgDXbv9rm/o2cF7japO6Vj1ENnrqWvLBmW1OzV9g6FUFhFXg==", + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/@algolia/requester-node-http/-/requester-node-http-4.17.0.tgz", + "integrity": "sha512-bpb/wDA1aC6WxxM8v7TsFspB7yBN3nqCGs2H1OADolQR/hiAIjAxusbuMxVbRFOdaUvAIqioIIkWvZdpYNIn8w==", "requires": { - "@algolia/requester-common": "4.14.2" + "@algolia/requester-common": "4.17.0" } }, "@algolia/transporter": { - "version": "4.14.2", - "resolved": "https://registry.npmjs.org/@algolia/transporter/-/transporter-4.14.2.tgz", - "integrity": "sha512-t89dfQb2T9MFQHidjHcfhh6iGMNwvuKUvojAj+JsrHAGbuSy7yE4BylhLX6R0Q1xYRoC4Vvv+O5qIw/LdnQfsQ==", + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/@algolia/transporter/-/transporter-4.17.0.tgz", + "integrity": "sha512-6xL6H6fe+Fi0AEP3ziSgC+G04RK37iRb4uUUqVAH9WPYFI8g+LYFq6iv5HS8Cbuc5TTut+Bwj6G+dh/asdb9uA==", "requires": { - "@algolia/cache-common": "4.14.2", - "@algolia/logger-common": "4.14.2", - "@algolia/requester-common": "4.14.2" + "@algolia/cache-common": "4.17.0", + "@algolia/logger-common": "4.17.0", + "@algolia/requester-common": "4.17.0" } }, "@ampproject/remapping": { @@ -13577,11 +13611,11 @@ } }, "@babel/runtime": { - "version": "7.20.1", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.20.1.tgz", - "integrity": "sha512-mrzLkl6U9YLF8qpqI7TB82PESyEGjm/0Ly91jG575eVxMMlb8fYfOXFZIJ8XfLrJZQbm7dlKry2bJmXBUEkdFg==", + "version": "7.21.0", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.21.0.tgz", + "integrity": "sha512-xwII0//EObnq89Ji5AKYQaRYiW/nZ3llSv29d49IuxPhKbtJoLP+9QUUZ4nVragQVtaVGeZrpB+ZtG/Pdy/POw==", "requires": { - "regenerator-runtime": "^0.13.10" + "regenerator-runtime": "^0.13.11" } }, "@babel/runtime-corejs3": { @@ -13637,25 +13671,25 @@ "optional": true }, "@docsearch/css": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/@docsearch/css/-/css-3.3.0.tgz", - "integrity": "sha512-rODCdDtGyudLj+Va8b6w6Y85KE85bXRsps/R4Yjwt5vueXKXZQKYw0aA9knxLBT6a/bI/GMrAcmCR75KYOM6hg==" + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/@docsearch/css/-/css-3.3.3.tgz", + "integrity": "sha512-6SCwI7P8ao+se1TUsdZ7B4XzL+gqeQZnBc+2EONZlcVa0dVrk0NjETxozFKgMv0eEGH8QzP1fkN+A1rH61l4eg==" }, "@docsearch/react": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/@docsearch/react/-/react-3.3.0.tgz", - "integrity": "sha512-fhS5adZkae2SSdMYEMVg6pxI5a/cE+tW16ki1V0/ur4Fdok3hBRkmN/H8VvlXnxzggkQIIRIVvYPn00JPjen3A==", + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/@docsearch/react/-/react-3.3.3.tgz", + "integrity": "sha512-pLa0cxnl+G0FuIDuYlW+EBK6Rw2jwLw9B1RHIeS4N4s2VhsfJ/wzeCi3CWcs5yVfxLd5ZK50t//TMA5e79YT7Q==", "requires": { - "@algolia/autocomplete-core": "1.7.2", - "@algolia/autocomplete-preset-algolia": "1.7.2", - "@docsearch/css": "3.3.0", + "@algolia/autocomplete-core": "1.7.4", + "@algolia/autocomplete-preset-algolia": "1.7.4", + "@docsearch/css": "3.3.3", "algoliasearch": "^4.0.0" } }, "@docusaurus/core": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@docusaurus/core/-/core-2.2.0.tgz", - "integrity": "sha512-Vd6XOluKQqzG12fEs9prJgDtyn6DPok9vmUWDR2E6/nV5Fl9SVkhEQOBxwObjk3kQh7OY7vguFaLh0jqdApWsA==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@docusaurus/core/-/core-2.4.0.tgz", + "integrity": "sha512-J55/WEoIpRcLf3afO5POHPguVZosKmJEQWKBL+K7TAnfuE7i+Y0NPLlkKtnWCehagGsgTqClfQEexH/UT4kELA==", "requires": { "@babel/core": "^7.18.6", "@babel/generator": "^7.18.7", @@ -13667,13 +13701,13 @@ "@babel/runtime": "^7.18.6", "@babel/runtime-corejs3": "^7.18.6", "@babel/traverse": "^7.18.8", - "@docusaurus/cssnano-preset": "2.2.0", - "@docusaurus/logger": "2.2.0", - "@docusaurus/mdx-loader": "2.2.0", + "@docusaurus/cssnano-preset": "2.4.0", + "@docusaurus/logger": "2.4.0", + "@docusaurus/mdx-loader": "2.4.0", "@docusaurus/react-loadable": "5.5.2", - "@docusaurus/utils": "2.2.0", - "@docusaurus/utils-common": "2.2.0", - "@docusaurus/utils-validation": "2.2.0", + "@docusaurus/utils": "2.4.0", + "@docusaurus/utils-common": "2.4.0", + "@docusaurus/utils-validation": "2.4.0", "@slorber/static-site-generator-webpack-plugin": "^4.0.7", "@svgr/webpack": "^6.2.1", "autoprefixer": "^10.4.7", @@ -13694,7 +13728,7 @@ "del": "^6.1.1", "detect-port": "^1.3.0", "escape-html": "^1.0.3", - "eta": "^1.12.3", + "eta": "^2.0.0", "file-loader": "^6.2.0", "fs-extra": "^10.1.0", "html-minifier-terser": "^6.1.0", @@ -13731,9 +13765,9 @@ } }, "@docusaurus/cssnano-preset": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@docusaurus/cssnano-preset/-/cssnano-preset-2.2.0.tgz", - "integrity": "sha512-mAAwCo4n66TMWBH1kXnHVZsakW9VAXJzTO4yZukuL3ro4F+JtkMwKfh42EG75K/J/YIFQG5I/Bzy0UH/hFxaTg==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@docusaurus/cssnano-preset/-/cssnano-preset-2.4.0.tgz", + "integrity": "sha512-RmdiA3IpsLgZGXRzqnmTbGv43W4OD44PCo+6Q/aYjEM2V57vKCVqNzuafE94jv0z/PjHoXUrjr69SaRymBKYYw==", "requires": { "cssnano-preset-advanced": "^5.3.8", "postcss": "^8.4.14", @@ -13742,23 +13776,23 @@ } }, "@docusaurus/logger": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@docusaurus/logger/-/logger-2.2.0.tgz", - "integrity": "sha512-DF3j1cA5y2nNsu/vk8AG7xwpZu6f5MKkPPMaaIbgXLnWGfm6+wkOeW7kNrxnM95YOhKUkJUophX69nGUnLsm0A==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@docusaurus/logger/-/logger-2.4.0.tgz", + "integrity": "sha512-T8+qR4APN+MjcC9yL2Es+xPJ2923S9hpzDmMtdsOcUGLqpCGBbU1vp3AAqDwXtVgFkq+NsEk7sHdVsfLWR/AXw==", "requires": { "chalk": "^4.1.2", "tslib": "^2.4.0" } }, "@docusaurus/mdx-loader": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@docusaurus/mdx-loader/-/mdx-loader-2.2.0.tgz", - "integrity": "sha512-X2bzo3T0jW0VhUU+XdQofcEeozXOTmKQMvc8tUnWRdTnCvj4XEcBVdC3g+/jftceluiwSTNRAX4VBOJdNt18jA==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@docusaurus/mdx-loader/-/mdx-loader-2.4.0.tgz", + "integrity": "sha512-GWoH4izZKOmFoC+gbI2/y8deH/xKLvzz/T5BsEexBye8EHQlwsA7FMrVa48N063bJBH4FUOiRRXxk5rq9cC36g==", "requires": { "@babel/parser": "^7.18.8", "@babel/traverse": "^7.18.8", - "@docusaurus/logger": "2.2.0", - "@docusaurus/utils": "2.2.0", + "@docusaurus/logger": "2.4.0", + "@docusaurus/utils": "2.4.0", "@mdx-js/mdx": "^1.6.22", "escape-html": "^1.0.3", "file-loader": "^6.2.0", @@ -13775,12 +13809,12 @@ } }, "@docusaurus/module-type-aliases": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@docusaurus/module-type-aliases/-/module-type-aliases-2.2.0.tgz", - "integrity": "sha512-wDGW4IHKoOr9YuJgy7uYuKWrDrSpsUSDHLZnWQYM9fN7D5EpSmYHjFruUpKWVyxLpD/Wh0rW8hYZwdjJIQUQCQ==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@docusaurus/module-type-aliases/-/module-type-aliases-2.4.0.tgz", + "integrity": "sha512-YEQO2D3UXs72qCn8Cr+RlycSQXVGN9iEUyuHwTuK4/uL/HFomB2FHSU0vSDM23oLd+X/KibQ3Ez6nGjQLqXcHg==", "requires": { "@docusaurus/react-loadable": "5.5.2", - "@docusaurus/types": "2.2.0", + "@docusaurus/types": "2.4.0", "@types/history": "^4.7.11", "@types/react": "*", "@types/react-router-config": "*", @@ -13790,17 +13824,17 @@ } }, "@docusaurus/plugin-content-blog": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-blog/-/plugin-content-blog-2.2.0.tgz", - "integrity": "sha512-0mWBinEh0a5J2+8ZJXJXbrCk1tSTNf7Nm4tYAl5h2/xx+PvH/Bnu0V+7mMljYm/1QlDYALNIIaT/JcoZQFUN3w==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-blog/-/plugin-content-blog-2.4.0.tgz", + "integrity": "sha512-YwkAkVUxtxoBAIj/MCb4ohN0SCtHBs4AS75jMhPpf67qf3j+U/4n33cELq7567hwyZ6fMz2GPJcVmctzlGGThQ==", "requires": { - "@docusaurus/core": "2.2.0", - "@docusaurus/logger": "2.2.0", - "@docusaurus/mdx-loader": "2.2.0", - "@docusaurus/types": "2.2.0", - "@docusaurus/utils": "2.2.0", - "@docusaurus/utils-common": "2.2.0", - "@docusaurus/utils-validation": "2.2.0", + "@docusaurus/core": "2.4.0", + "@docusaurus/logger": "2.4.0", + "@docusaurus/mdx-loader": "2.4.0", + "@docusaurus/types": "2.4.0", + "@docusaurus/utils": "2.4.0", + "@docusaurus/utils-common": "2.4.0", + "@docusaurus/utils-validation": "2.4.0", "cheerio": "^1.0.0-rc.12", "feed": "^4.2.2", "fs-extra": "^10.1.0", @@ -13813,17 +13847,17 @@ } }, "@docusaurus/plugin-content-docs": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-docs/-/plugin-content-docs-2.2.0.tgz", - "integrity": "sha512-BOazBR0XjzsHE+2K1wpNxz5QZmrJgmm3+0Re0EVPYFGW8qndCWGNtXW/0lGKhecVPML8yyFeAmnUCIs7xM2wPw==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-docs/-/plugin-content-docs-2.4.0.tgz", + "integrity": "sha512-ic/Z/ZN5Rk/RQo+Io6rUGpToOtNbtPloMR2JcGwC1xT2riMu6zzfSwmBi9tHJgdXH6CB5jG+0dOZZO8QS5tmDg==", "requires": { - "@docusaurus/core": "2.2.0", - "@docusaurus/logger": "2.2.0", - "@docusaurus/mdx-loader": "2.2.0", - "@docusaurus/module-type-aliases": "2.2.0", - "@docusaurus/types": "2.2.0", - "@docusaurus/utils": "2.2.0", - "@docusaurus/utils-validation": "2.2.0", + "@docusaurus/core": "2.4.0", + "@docusaurus/logger": "2.4.0", + "@docusaurus/mdx-loader": "2.4.0", + "@docusaurus/module-type-aliases": "2.4.0", + "@docusaurus/types": "2.4.0", + "@docusaurus/utils": "2.4.0", + "@docusaurus/utils-validation": "2.4.0", "@types/react-router-config": "^5.0.6", "combine-promises": "^1.1.0", "fs-extra": "^10.1.0", @@ -13836,88 +13870,100 @@ } }, "@docusaurus/plugin-content-pages": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-pages/-/plugin-content-pages-2.2.0.tgz", - "integrity": "sha512-+OTK3FQHk5WMvdelz8v19PbEbx+CNT6VSpx7nVOvMNs5yJCKvmqBJBQ2ZSxROxhVDYn+CZOlmyrC56NSXzHf6g==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-pages/-/plugin-content-pages-2.4.0.tgz", + "integrity": "sha512-Pk2pOeOxk8MeU3mrTU0XLIgP9NZixbdcJmJ7RUFrZp1Aj42nd0RhIT14BGvXXyqb8yTQlk4DmYGAzqOfBsFyGw==", "requires": { - "@docusaurus/core": "2.2.0", - "@docusaurus/mdx-loader": "2.2.0", - "@docusaurus/types": "2.2.0", - "@docusaurus/utils": "2.2.0", - "@docusaurus/utils-validation": "2.2.0", + "@docusaurus/core": "2.4.0", + "@docusaurus/mdx-loader": "2.4.0", + "@docusaurus/types": "2.4.0", + "@docusaurus/utils": "2.4.0", + "@docusaurus/utils-validation": "2.4.0", "fs-extra": "^10.1.0", "tslib": "^2.4.0", "webpack": "^5.73.0" } }, "@docusaurus/plugin-debug": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-debug/-/plugin-debug-2.2.0.tgz", - "integrity": "sha512-p9vOep8+7OVl6r/NREEYxf4HMAjV8JMYJ7Bos5fCFO0Wyi9AZEo0sCTliRd7R8+dlJXZEgcngSdxAUo/Q+CJow==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-debug/-/plugin-debug-2.4.0.tgz", + "integrity": "sha512-KC56DdYjYT7Txyux71vXHXGYZuP6yYtqwClvYpjKreWIHWus5Zt6VNi23rMZv3/QKhOCrN64zplUbdfQMvddBQ==", "requires": { - "@docusaurus/core": "2.2.0", - "@docusaurus/types": "2.2.0", - "@docusaurus/utils": "2.2.0", + "@docusaurus/core": "2.4.0", + "@docusaurus/types": "2.4.0", + "@docusaurus/utils": "2.4.0", "fs-extra": "^10.1.0", "react-json-view": "^1.21.3", "tslib": "^2.4.0" } }, "@docusaurus/plugin-google-analytics": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-analytics/-/plugin-google-analytics-2.2.0.tgz", - "integrity": "sha512-+eZVVxVeEnV5nVQJdey9ZsfyEVMls6VyWTIj8SmX0k5EbqGvnIfET+J2pYEuKQnDIHxy+syRMoRM6AHXdHYGIg==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-analytics/-/plugin-google-analytics-2.4.0.tgz", + "integrity": "sha512-uGUzX67DOAIglygdNrmMOvEp8qG03X20jMWadeqVQktS6nADvozpSLGx4J0xbkblhJkUzN21WiilsP9iVP+zkw==", "requires": { - "@docusaurus/core": "2.2.0", - "@docusaurus/types": "2.2.0", - "@docusaurus/utils-validation": "2.2.0", + "@docusaurus/core": "2.4.0", + "@docusaurus/types": "2.4.0", + "@docusaurus/utils-validation": "2.4.0", "tslib": "^2.4.0" } }, "@docusaurus/plugin-google-gtag": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-gtag/-/plugin-google-gtag-2.2.0.tgz", - "integrity": "sha512-6SOgczP/dYdkqUMGTRqgxAS1eTp6MnJDAQMy8VCF1QKbWZmlkx4agHDexihqmYyCujTYHqDAhm1hV26EET54NQ==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-gtag/-/plugin-google-gtag-2.4.0.tgz", + "integrity": "sha512-adj/70DANaQs2+TF/nRdMezDXFAV/O/pjAbUgmKBlyOTq5qoMe0Tk4muvQIwWUmiUQxFJe+sKlZGM771ownyOg==", "requires": { - "@docusaurus/core": "2.2.0", - "@docusaurus/types": "2.2.0", - "@docusaurus/utils-validation": "2.2.0", + "@docusaurus/core": "2.4.0", + "@docusaurus/types": "2.4.0", + "@docusaurus/utils-validation": "2.4.0", + "tslib": "^2.4.0" + } + }, + "@docusaurus/plugin-google-tag-manager": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-tag-manager/-/plugin-google-tag-manager-2.4.0.tgz", + "integrity": "sha512-E66uGcYs4l7yitmp/8kMEVQftFPwV9iC62ORh47Veqzs6ExwnhzBkJmwDnwIysHBF1vlxnzET0Fl2LfL5fRR3A==", + "requires": { + "@docusaurus/core": "2.4.0", + "@docusaurus/types": "2.4.0", + "@docusaurus/utils-validation": "2.4.0", "tslib": "^2.4.0" } }, "@docusaurus/plugin-sitemap": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-sitemap/-/plugin-sitemap-2.2.0.tgz", - "integrity": "sha512-0jAmyRDN/aI265CbWZNZuQpFqiZuo+5otk2MylU9iVrz/4J7gSc+ZJ9cy4EHrEsW7PV8s1w18hIEsmcA1YgkKg==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-sitemap/-/plugin-sitemap-2.4.0.tgz", + "integrity": "sha512-pZxh+ygfnI657sN8a/FkYVIAmVv0CGk71QMKqJBOfMmDHNN1FeDeFkBjWP49ejBqpqAhjufkv5UWq3UOu2soCw==", "requires": { - "@docusaurus/core": "2.2.0", - "@docusaurus/logger": "2.2.0", - "@docusaurus/types": "2.2.0", - "@docusaurus/utils": "2.2.0", - "@docusaurus/utils-common": "2.2.0", - "@docusaurus/utils-validation": "2.2.0", + "@docusaurus/core": "2.4.0", + "@docusaurus/logger": "2.4.0", + "@docusaurus/types": "2.4.0", + "@docusaurus/utils": "2.4.0", + "@docusaurus/utils-common": "2.4.0", + "@docusaurus/utils-validation": "2.4.0", "fs-extra": "^10.1.0", "sitemap": "^7.1.1", "tslib": "^2.4.0" } }, "@docusaurus/preset-classic": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@docusaurus/preset-classic/-/preset-classic-2.2.0.tgz", - "integrity": "sha512-yKIWPGNx7BT8v2wjFIWvYrS+nvN04W+UameSFf8lEiJk6pss0kL6SG2MRvyULiI3BDxH+tj6qe02ncpSPGwumg==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@docusaurus/preset-classic/-/preset-classic-2.4.0.tgz", + "integrity": "sha512-/5z5o/9bc6+P5ool2y01PbJhoGddEGsC0ej1MF6mCoazk8A+kW4feoUd68l7Bnv01rCnG3xy7kHUQP97Y0grUA==", "requires": { - "@docusaurus/core": "2.2.0", - "@docusaurus/plugin-content-blog": "2.2.0", - "@docusaurus/plugin-content-docs": "2.2.0", - "@docusaurus/plugin-content-pages": "2.2.0", - "@docusaurus/plugin-debug": "2.2.0", - "@docusaurus/plugin-google-analytics": "2.2.0", - "@docusaurus/plugin-google-gtag": "2.2.0", - "@docusaurus/plugin-sitemap": "2.2.0", - "@docusaurus/theme-classic": "2.2.0", - "@docusaurus/theme-common": "2.2.0", - "@docusaurus/theme-search-algolia": "2.2.0", - "@docusaurus/types": "2.2.0" + "@docusaurus/core": "2.4.0", + "@docusaurus/plugin-content-blog": "2.4.0", + "@docusaurus/plugin-content-docs": "2.4.0", + "@docusaurus/plugin-content-pages": "2.4.0", + "@docusaurus/plugin-debug": "2.4.0", + "@docusaurus/plugin-google-analytics": "2.4.0", + "@docusaurus/plugin-google-gtag": "2.4.0", + "@docusaurus/plugin-google-tag-manager": "2.4.0", + "@docusaurus/plugin-sitemap": "2.4.0", + "@docusaurus/theme-classic": "2.4.0", + "@docusaurus/theme-common": "2.4.0", + "@docusaurus/theme-search-algolia": "2.4.0", + "@docusaurus/types": "2.4.0" } }, "@docusaurus/react-loadable": { @@ -13930,26 +13976,26 @@ } }, "@docusaurus/theme-classic": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@docusaurus/theme-classic/-/theme-classic-2.2.0.tgz", - "integrity": "sha512-kjbg/qJPwZ6H1CU/i9d4l/LcFgnuzeiGgMQlt6yPqKo0SOJIBMPuz7Rnu3r/WWbZFPi//o8acclacOzmXdUUEg==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@docusaurus/theme-classic/-/theme-classic-2.4.0.tgz", + "integrity": "sha512-GMDX5WU6Z0OC65eQFgl3iNNEbI9IMJz9f6KnOyuMxNUR6q0qVLsKCNopFUDfFNJ55UU50o7P7o21yVhkwpfJ9w==", "requires": { - "@docusaurus/core": "2.2.0", - "@docusaurus/mdx-loader": "2.2.0", - "@docusaurus/module-type-aliases": "2.2.0", - "@docusaurus/plugin-content-blog": "2.2.0", - "@docusaurus/plugin-content-docs": "2.2.0", - "@docusaurus/plugin-content-pages": "2.2.0", - "@docusaurus/theme-common": "2.2.0", - "@docusaurus/theme-translations": "2.2.0", - "@docusaurus/types": "2.2.0", - "@docusaurus/utils": "2.2.0", - "@docusaurus/utils-common": "2.2.0", - "@docusaurus/utils-validation": "2.2.0", + "@docusaurus/core": "2.4.0", + "@docusaurus/mdx-loader": "2.4.0", + "@docusaurus/module-type-aliases": "2.4.0", + "@docusaurus/plugin-content-blog": "2.4.0", + "@docusaurus/plugin-content-docs": "2.4.0", + "@docusaurus/plugin-content-pages": "2.4.0", + "@docusaurus/theme-common": "2.4.0", + "@docusaurus/theme-translations": "2.4.0", + "@docusaurus/types": "2.4.0", + "@docusaurus/utils": "2.4.0", + "@docusaurus/utils-common": "2.4.0", + "@docusaurus/utils-validation": "2.4.0", "@mdx-js/react": "^1.6.22", "clsx": "^1.2.1", "copy-text-to-clipboard": "^3.0.1", - "infima": "0.2.0-alpha.42", + "infima": "0.2.0-alpha.43", "lodash": "^4.17.21", "nprogress": "^0.2.0", "postcss": "^8.4.14", @@ -13962,16 +14008,17 @@ } }, "@docusaurus/theme-common": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@docusaurus/theme-common/-/theme-common-2.2.0.tgz", - "integrity": "sha512-R8BnDjYoN90DCL75gP7qYQfSjyitXuP9TdzgsKDmSFPNyrdE3twtPNa2dIN+h+p/pr+PagfxwWbd6dn722A1Dw==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@docusaurus/theme-common/-/theme-common-2.4.0.tgz", + "integrity": "sha512-IkG/l5f/FLY6cBIxtPmFnxpuPzc5TupuqlOx+XDN+035MdQcAh8wHXXZJAkTeYDeZ3anIUSUIvWa7/nRKoQEfg==", "requires": { - "@docusaurus/mdx-loader": "2.2.0", - "@docusaurus/module-type-aliases": "2.2.0", - "@docusaurus/plugin-content-blog": "2.2.0", - "@docusaurus/plugin-content-docs": "2.2.0", - "@docusaurus/plugin-content-pages": "2.2.0", - "@docusaurus/utils": "2.2.0", + "@docusaurus/mdx-loader": "2.4.0", + "@docusaurus/module-type-aliases": "2.4.0", + "@docusaurus/plugin-content-blog": "2.4.0", + "@docusaurus/plugin-content-docs": "2.4.0", + "@docusaurus/plugin-content-pages": "2.4.0", + "@docusaurus/utils": "2.4.0", + "@docusaurus/utils-common": "2.4.0", "@types/history": "^4.7.11", "@types/react": "*", "@types/react-router-config": "*", @@ -13979,26 +14026,27 @@ "parse-numeric-range": "^1.3.0", "prism-react-renderer": "^1.3.5", "tslib": "^2.4.0", + "use-sync-external-store": "^1.2.0", "utility-types": "^3.10.0" } }, "@docusaurus/theme-search-algolia": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@docusaurus/theme-search-algolia/-/theme-search-algolia-2.2.0.tgz", - "integrity": "sha512-2h38B0tqlxgR2FZ9LpAkGrpDWVdXZ7vltfmTdX+4RsDs3A7khiNsmZB+x/x6sA4+G2V2CvrsPMlsYBy5X+cY1w==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@docusaurus/theme-search-algolia/-/theme-search-algolia-2.4.0.tgz", + "integrity": "sha512-pPCJSCL1Qt4pu/Z0uxBAuke0yEBbxh0s4fOvimna7TEcBLPq0x06/K78AaABXrTVQM6S0vdocFl9EoNgU17hqA==", "requires": { "@docsearch/react": "^3.1.1", - "@docusaurus/core": "2.2.0", - "@docusaurus/logger": "2.2.0", - "@docusaurus/plugin-content-docs": "2.2.0", - "@docusaurus/theme-common": "2.2.0", - "@docusaurus/theme-translations": "2.2.0", - "@docusaurus/utils": "2.2.0", - "@docusaurus/utils-validation": "2.2.0", + "@docusaurus/core": "2.4.0", + "@docusaurus/logger": "2.4.0", + "@docusaurus/plugin-content-docs": "2.4.0", + "@docusaurus/theme-common": "2.4.0", + "@docusaurus/theme-translations": "2.4.0", + "@docusaurus/utils": "2.4.0", + "@docusaurus/utils-validation": "2.4.0", "algoliasearch": "^4.13.1", "algoliasearch-helper": "^3.10.0", "clsx": "^1.2.1", - "eta": "^1.12.3", + "eta": "^2.0.0", "fs-extra": "^10.1.0", "lodash": "^4.17.21", "tslib": "^2.4.0", @@ -14006,18 +14054,18 @@ } }, "@docusaurus/theme-translations": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@docusaurus/theme-translations/-/theme-translations-2.2.0.tgz", - "integrity": "sha512-3T140AG11OjJrtKlY4pMZ5BzbGRDjNs2co5hJ6uYJG1bVWlhcaFGqkaZ5lCgKflaNHD7UHBHU9Ec5f69jTdd6w==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@docusaurus/theme-translations/-/theme-translations-2.4.0.tgz", + "integrity": "sha512-kEoITnPXzDPUMBHk3+fzEzbopxLD3fR5sDoayNH0vXkpUukA88/aDL1bqkhxWZHA3LOfJ3f0vJbOwmnXW5v85Q==", "requires": { "fs-extra": "^10.1.0", "tslib": "^2.4.0" } }, "@docusaurus/types": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@docusaurus/types/-/types-2.2.0.tgz", - "integrity": "sha512-b6xxyoexfbRNRI8gjblzVOnLr4peCJhGbYGPpJ3LFqpi5nsFfoK4mmDLvWdeah0B7gmJeXabN7nQkFoqeSdmOw==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@docusaurus/types/-/types-2.4.0.tgz", + "integrity": "sha512-xaBXr+KIPDkIaef06c+i2HeTqVNixB7yFut5fBXPGI2f1rrmEV2vLMznNGsFwvZ5XmA3Quuefd4OGRkdo97Dhw==", "requires": { "@types/history": "^4.7.11", "@types/react": "*", @@ -14030,12 +14078,13 @@ } }, "@docusaurus/utils": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@docusaurus/utils/-/utils-2.2.0.tgz", - "integrity": "sha512-oNk3cjvx7Tt1Lgh/aeZAmFpGV2pDr5nHKrBVx6hTkzGhrnMuQqLt6UPlQjdYQ3QHXwyF/ZtZMO1D5Pfi0lu7SA==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@docusaurus/utils/-/utils-2.4.0.tgz", + "integrity": "sha512-89hLYkvtRX92j+C+ERYTuSUK6nF9bGM32QThcHPg2EDDHVw6FzYQXmX6/p+pU5SDyyx5nBlE4qXR92RxCAOqfg==", "requires": { - "@docusaurus/logger": "2.2.0", + "@docusaurus/logger": "2.4.0", "@svgr/webpack": "^6.2.1", + "escape-string-regexp": "^4.0.0", "file-loader": "^6.2.0", "fs-extra": "^10.1.0", "github-slugger": "^1.4.0", @@ -14052,20 +14101,20 @@ } }, "@docusaurus/utils-common": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@docusaurus/utils-common/-/utils-common-2.2.0.tgz", - "integrity": "sha512-qebnerHp+cyovdUseDQyYFvMW1n1nv61zGe5JJfoNQUnjKuApch3IVsz+/lZ9a38pId8kqehC1Ao2bW/s0ntDA==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@docusaurus/utils-common/-/utils-common-2.4.0.tgz", + "integrity": "sha512-zIMf10xuKxddYfLg5cS19x44zud/E9I7lj3+0bv8UIs0aahpErfNrGhijEfJpAfikhQ8tL3m35nH3hJ3sOG82A==", "requires": { "tslib": "^2.4.0" } }, "@docusaurus/utils-validation": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@docusaurus/utils-validation/-/utils-validation-2.2.0.tgz", - "integrity": "sha512-I1hcsG3yoCkasOL5qQAYAfnmVoLei7apugT6m4crQjmDGxq+UkiRrq55UqmDDyZlac/6ax/JC0p+usZ6W4nVyg==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@docusaurus/utils-validation/-/utils-validation-2.4.0.tgz", + "integrity": "sha512-IrBsBbbAp6y7mZdJx4S4pIA7dUyWSA0GNosPk6ZJ0fX3uYIEQgcQSGIgTeSC+8xPEx3c16o03en1jSDpgQgz/w==", "requires": { - "@docusaurus/logger": "2.2.0", - "@docusaurus/utils": "2.2.0", + "@docusaurus/logger": "2.4.0", + "@docusaurus/utils": "2.4.0", "joi": "^17.6.0", "js-yaml": "^4.1.0", "tslib": "^2.4.0" @@ -14961,30 +15010,30 @@ "requires": {} }, "algoliasearch": { - "version": "4.14.2", - "resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-4.14.2.tgz", - "integrity": "sha512-ngbEQonGEmf8dyEh5f+uOIihv4176dgbuOZspiuhmTTBRBuzWu3KCGHre6uHj5YyuC7pNvQGzB6ZNJyZi0z+Sg==", + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-4.17.0.tgz", + "integrity": "sha512-JMRh2Mw6sEnVMiz6+APsi7lx9a2jiDFF+WUtANaUVCv6uSU9UOLdo5h9K3pdP6frRRybaM2fX8b1u0nqICS9aA==", "requires": { - "@algolia/cache-browser-local-storage": "4.14.2", - "@algolia/cache-common": "4.14.2", - "@algolia/cache-in-memory": "4.14.2", - "@algolia/client-account": "4.14.2", - "@algolia/client-analytics": "4.14.2", - "@algolia/client-common": "4.14.2", - "@algolia/client-personalization": "4.14.2", - "@algolia/client-search": "4.14.2", - "@algolia/logger-common": "4.14.2", - "@algolia/logger-console": "4.14.2", - "@algolia/requester-browser-xhr": "4.14.2", - "@algolia/requester-common": "4.14.2", - "@algolia/requester-node-http": "4.14.2", - "@algolia/transporter": "4.14.2" + "@algolia/cache-browser-local-storage": "4.17.0", + "@algolia/cache-common": "4.17.0", + "@algolia/cache-in-memory": "4.17.0", + "@algolia/client-account": "4.17.0", + "@algolia/client-analytics": "4.17.0", + "@algolia/client-common": "4.17.0", + "@algolia/client-personalization": "4.17.0", + "@algolia/client-search": "4.17.0", + "@algolia/logger-common": "4.17.0", + "@algolia/logger-console": "4.17.0", + "@algolia/requester-browser-xhr": "4.17.0", + "@algolia/requester-common": "4.17.0", + "@algolia/requester-node-http": "4.17.0", + "@algolia/transporter": "4.17.0" } }, "algoliasearch-helper": { - "version": "3.11.1", - "resolved": "https://registry.npmjs.org/algoliasearch-helper/-/algoliasearch-helper-3.11.1.tgz", - "integrity": "sha512-mvsPN3eK4E0bZG0/WlWJjeqe/bUD2KOEVOl0GyL/TGXn6wcpZU8NOuztGHCUKXkyg5gq6YzUakVTmnmSSO5Yiw==", + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/algoliasearch-helper/-/algoliasearch-helper-3.12.0.tgz", + "integrity": "sha512-/j1U3PEwdan0n6P/QqSnSpNSLC5+cEMvyljd5CnmNmUjDlGrys+vFEOwjVEnqELIiAGMHEA/Nl3CiKVFBUYqyQ==", "requires": { "@algolia/events": "^4.0.1" } @@ -15072,12 +15121,12 @@ "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==" }, "autoprefixer": { - "version": "10.4.13", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.13.tgz", - "integrity": "sha512-49vKpMqcZYsJjwotvt4+h/BCjJVnhGwcLpDt5xkcaOG3eLrG/HUYLagrihYsQ+qrIBgIzX1Rw7a6L8I/ZA1Atg==", + "version": "10.4.14", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.14.tgz", + "integrity": "sha512-FQzyfOsTlwVzjHxKEqRIAdJx9niO6VCBCoEwax/VLSoQF29ggECcPuBqUMZ+u8jCZOPSy8b8/8KnuFbp0SaFZQ==", "requires": { - "browserslist": "^4.21.4", - "caniuse-lite": "^1.0.30001426", + "browserslist": "^4.21.5", + "caniuse-lite": "^1.0.30001464", "fraction.js": "^4.2.0", "normalize-range": "^0.1.2", "picocolors": "^1.0.0", @@ -15306,14 +15355,14 @@ } }, "browserslist": { - "version": "4.21.4", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.4.tgz", - "integrity": "sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw==", + "version": "4.21.5", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.5.tgz", + "integrity": "sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w==", "requires": { - "caniuse-lite": "^1.0.30001400", - "electron-to-chromium": "^1.4.251", - "node-releases": "^2.0.6", - "update-browserslist-db": "^1.0.9" + "caniuse-lite": "^1.0.30001449", + "electron-to-chromium": "^1.4.284", + "node-releases": "^2.0.8", + "update-browserslist-db": "^1.0.10" } }, "buffer-from": { @@ -15405,9 +15454,9 @@ } }, "caniuse-lite": { - "version": "1.0.30001431", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001431.tgz", - "integrity": "sha512-zBUoFU0ZcxpvSt9IU66dXVT/3ctO1cy4y9cscs1szkPlcWb6pasYM144GqrUygUbT+k7cmUCW61cvskjcv0enQ==" + "version": "1.0.30001478", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001478.tgz", + "integrity": "sha512-gMhDyXGItTHipJj2ApIvR+iVB5hd0KP3svMWWXDvZOmjzJJassGLMfxRkQCSYgGd2gtdL/ReeiyvMSFD1Ss6Mw==" }, "ccount": { "version": "1.1.0", @@ -15727,9 +15776,9 @@ "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" }, "copy-text-to-clipboard": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/copy-text-to-clipboard/-/copy-text-to-clipboard-3.0.1.tgz", - "integrity": "sha512-rvVsHrpFcL4F2P8ihsoLdFHmd404+CMg71S756oRSeQgqk51U3kicGdnvfkrxva0xXH92SjGS62B0XIJsbh+9Q==" + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/copy-text-to-clipboard/-/copy-text-to-clipboard-3.1.0.tgz", + "integrity": "sha512-PFM6BnjLnOON/lB3ta/Jg7Ywsv+l9kQGD4TWDCSlRBGmqnnTM5MrDkhAFgw+8HZt0wW6Q2BBE4cmy9sq+s9Qng==" }, "copy-webpack-plugin": { "version": "11.0.0", @@ -15977,12 +16026,12 @@ } }, "cssnano-preset-advanced": { - "version": "5.3.9", - "resolved": "https://registry.npmjs.org/cssnano-preset-advanced/-/cssnano-preset-advanced-5.3.9.tgz", - "integrity": "sha512-njnh4pp1xCsibJcEHnWZb4EEzni0ePMqPuPNyuWT4Z+YeXmsgqNuTPIljXFEXhxGsWs9183JkXgHxc1TcsahIg==", + "version": "5.3.10", + "resolved": "https://registry.npmjs.org/cssnano-preset-advanced/-/cssnano-preset-advanced-5.3.10.tgz", + "integrity": "sha512-fnYJyCS9jgMU+cmHO1rPSPf9axbQyD7iUhLO5Df6O4G+fKIOMps+ZbU0PdGFejFBBZ3Pftf18fn1eG7MAPUSWQ==", "requires": { "autoprefixer": "^10.4.12", - "cssnano-preset-default": "^5.2.13", + "cssnano-preset-default": "^5.2.14", "postcss-discard-unused": "^5.1.0", "postcss-merge-idents": "^5.1.1", "postcss-reduce-idents": "^5.2.0", @@ -15990,21 +16039,21 @@ } }, "cssnano-preset-default": { - "version": "5.2.13", - "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-5.2.13.tgz", - "integrity": "sha512-PX7sQ4Pb+UtOWuz8A1d+Rbi+WimBIxJTRyBdgGp1J75VU0r/HFQeLnMYgHiCAp6AR4rqrc7Y4R+1Rjk3KJz6DQ==", + "version": "5.2.14", + "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-5.2.14.tgz", + "integrity": "sha512-t0SFesj/ZV2OTylqQVOrFgEh5uanxbO6ZAdeCrNsUQ6fVuXwYTxJPNAGvGTxHbD68ldIJNec7PyYZDBrfDQ+6A==", "requires": { "css-declaration-sorter": "^6.3.1", "cssnano-utils": "^3.1.0", "postcss-calc": "^8.2.3", - "postcss-colormin": "^5.3.0", + "postcss-colormin": "^5.3.1", "postcss-convert-values": "^5.1.3", "postcss-discard-comments": "^5.1.2", "postcss-discard-duplicates": "^5.1.0", "postcss-discard-empty": "^5.1.1", "postcss-discard-overridden": "^5.1.0", "postcss-merge-longhand": "^5.1.7", - "postcss-merge-rules": "^5.1.3", + "postcss-merge-rules": "^5.1.4", "postcss-minify-font-values": "^5.1.0", "postcss-minify-gradients": "^5.1.1", "postcss-minify-params": "^5.1.4", @@ -16019,7 +16068,7 @@ "postcss-normalize-url": "^5.1.0", "postcss-normalize-whitespace": "^5.1.1", "postcss-ordered-values": "^5.1.3", - "postcss-reduce-initial": "^5.1.1", + "postcss-reduce-initial": "^5.1.2", "postcss-reduce-transforms": "^5.1.0", "postcss-svgo": "^5.1.0", "postcss-unique-selectors": "^5.1.1" @@ -16394,9 +16443,9 @@ "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==" }, "eta": { - "version": "1.12.3", - "resolved": "https://registry.npmjs.org/eta/-/eta-1.12.3.tgz", - "integrity": "sha512-qHixwbDLtekO/d51Yr4glcaUJCIjGVJyTzuqV4GPlgZo1YpgOKG+avQynErZIYrfM6JIJdtiG2Kox8tbb+DoGg==" + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/eta/-/eta-2.0.1.tgz", + "integrity": "sha512-46E2qDPDm7QA+usjffUWz9KfXsxVZclPOuKsXs4ZWZdI/X1wpDF7AO424pt7fdYohCzWsIkXAhNGXSlwo5naAg==" }, "etag": { "version": "1.8.1", @@ -16691,9 +16740,9 @@ } }, "flux": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/flux/-/flux-4.0.3.tgz", - "integrity": "sha512-yKAbrp7JhZhj6uiT1FTuVMlIAT1J4jqEyBpFApi1kxpGZCvacMVc/t1pMQyotqHhAgvoE3bNvAykhCo2CLjnYw==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/flux/-/flux-4.0.4.tgz", + "integrity": "sha512-NCj3XlayA2UsapRpM7va6wU1+9rE5FIL7qoMcmxWHRzbp0yujihMBm9BBHZ1MDIk5h5o2Bl6eGiCe8rYELAmYw==", "requires": { "fbemitter": "^3.0.0", "fbjs": "^3.0.1" @@ -17217,14 +17266,14 @@ } }, "htmlparser2": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.1.tgz", - "integrity": "sha512-4lVbmc1diZC7GUJQtRQ5yBAeUCL1exyMwmForWkRLnwyzWBFxN633SALPMGYaWZvKe9j1pRZJpauvmxENSp/EA==", + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz", + "integrity": "sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==", "requires": { "domelementtype": "^2.3.0", - "domhandler": "^5.0.2", + "domhandler": "^5.0.3", "domutils": "^3.0.1", - "entities": "^4.3.0" + "entities": "^4.4.0" } }, "http-cache-semantics": { @@ -17345,9 +17394,9 @@ "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==" }, "infima": { - "version": "0.2.0-alpha.42", - "resolved": "https://registry.npmjs.org/infima/-/infima-0.2.0-alpha.42.tgz", - "integrity": "sha512-ift8OXNbQQwtbIt6z16KnSWP7uJ/SysSMFI4F87MNRTicypfl4Pv3E2OGVv6N3nSZFJvA8imYulCBS64iyHYww==" + "version": "0.2.0-alpha.43", + "resolved": "https://registry.npmjs.org/infima/-/infima-0.2.0-alpha.43.tgz", + "integrity": "sha512-2uw57LvUqW0rK/SWYnd/2rRfxNA5DDNOh33jxF7fy46VWoNhGxiUQyVZHbBMjQ33mQem0cjdDVwgWVAmlRfgyQ==" }, "inflight": { "version": "1.0.6", @@ -18064,9 +18113,9 @@ "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==" }, "node-releases": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.6.tgz", - "integrity": "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==" + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.10.tgz", + "integrity": "sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w==" }, "normalize-path": { "version": "3.0.0", @@ -18287,9 +18336,9 @@ "integrity": "sha512-twN+njEipszzlMJd4ONUYgSfZPDxgHhT9Ahed5uTigpQn90FggW4SA/AIPq/6a149fTbE9qBEcSwE3FAEp6wQQ==" }, "parse5": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.1.tgz", - "integrity": "sha512-kwpuwzB+px5WUg9pyK0IcK/shltJN5/OVhQagxhCQNtT9Y9QRZqNY2e1cmbu/paRh5LMnz/oVTVLBpjFmMZhSg==", + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", + "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", "requires": { "entities": "^4.4.0" } @@ -18430,11 +18479,11 @@ } }, "postcss-colormin": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-5.3.0.tgz", - "integrity": "sha512-WdDO4gOFG2Z8n4P8TWBpshnL3JpmNmJwdnfP2gbk2qBA8PWwOYcmjmI/t3CmMeL72a7Hkd+x/Mg9O2/0rD54Pg==", + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-5.3.1.tgz", + "integrity": "sha512-UsWQG0AqTFQmpBegeLLc1+c3jIqBNB0zlDGRWR+dQ3pRKJL1oeMzyqmH3o2PIfn9MBdNrVPWhDbT769LxCTLJQ==", "requires": { - "browserslist": "^4.16.6", + "browserslist": "^4.21.4", "caniuse-api": "^3.0.0", "colord": "^2.9.1", "postcss-value-parser": "^4.2.0" @@ -18510,9 +18559,9 @@ } }, "postcss-merge-rules": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-5.1.3.tgz", - "integrity": "sha512-LbLd7uFC00vpOuMvyZop8+vvhnfRGpp2S+IMQKeuOZZapPRY4SMq5ErjQeHbHsjCUgJkRNrlU+LmxsKIqPKQlA==", + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-5.1.4.tgz", + "integrity": "sha512-0R2IuYpgU93y9lhVbO/OylTtKMVcHb67zjWIfCiKR9rWL3GUk1677LAqD/BcHizukdZEjT8Ru3oHRoAYoJy44g==", "requires": { "browserslist": "^4.21.4", "caniuse-api": "^3.0.0", @@ -18678,9 +18727,9 @@ } }, "postcss-reduce-initial": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-5.1.1.tgz", - "integrity": "sha512-//jeDqWcHPuXGZLoolFrUXBDyuEGbr9S2rMo19bkTIjBQ4PqkaO+oI8wua5BOUxpfi97i3PCoInsiFIEBfkm9w==", + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-5.1.2.tgz", + "integrity": "sha512-dE/y2XRaqAi6OvjzD22pjTUQ8eOfc6m/natGHgKFBK9DxFmIm69YmaRVQrGgFlEfc1HePIurY0TmDeROK05rIg==", "requires": { "browserslist": "^4.21.4", "caniuse-api": "^3.0.0" @@ -19146,11 +19195,11 @@ } }, "react-textarea-autosize": { - "version": "8.3.4", - "resolved": "https://registry.npmjs.org/react-textarea-autosize/-/react-textarea-autosize-8.3.4.tgz", - "integrity": "sha512-CdtmP8Dc19xL8/R6sWvtknD/eCXkQr30dtvC4VmGInhRsfF8X/ihXCq6+9l9qbxmKRiq407/7z5fxE7cVWQNgQ==", + "version": "8.4.1", + "resolved": "https://registry.npmjs.org/react-textarea-autosize/-/react-textarea-autosize-8.4.1.tgz", + "integrity": "sha512-aD2C+qK6QypknC+lCMzteOdIjoMbNlgSFmJjCV+DrfTPwp59i/it9mMNf2HDzvRjQgKAyBDPyLJhcrzElf2U4Q==", "requires": { - "@babel/runtime": "^7.10.2", + "@babel/runtime": "^7.20.13", "use-composed-ref": "^1.3.0", "use-latest": "^1.2.1" } @@ -19208,9 +19257,9 @@ } }, "regenerator-runtime": { - "version": "0.13.10", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.10.tgz", - "integrity": "sha512-KepLsg4dU12hryUO7bp/axHAKvwGOCV0sGloQtpagJ12ai+ojVDqkeGSiRX1zlq+kjIMZ1t7gpze+26QqtdGqw==" + "version": "0.13.11", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", + "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==" }, "regenerator-transform": { "version": "0.15.0", @@ -20354,9 +20403,9 @@ "peer": true }, "ua-parser-js": { - "version": "0.7.32", - "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.32.tgz", - "integrity": "sha512-f9BESNVhzlhEFf2CHMSj40NWOjYPl1YKYbrvIr/hFTDEmLq7SRbWvm7FcdcpCYT95zrOhC7gZSxjdnnTpBcwVw==" + "version": "0.7.35", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.35.tgz", + "integrity": "sha512-veRf7dawaj9xaWEu9HoTVn5Pggtc/qj+kqTOFvNiN1l0YdxwC1kvel57UCjThjGa3BHBihE8/UJAHI+uQHmd/g==" }, "unherit": { "version": "1.1.3", @@ -20649,6 +20698,12 @@ "use-isomorphic-layout-effect": "^1.1.1" } }, + "use-sync-external-store": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz", + "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==", + "requires": {} + }, "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", diff --git a/docs/package.json b/docs/package.json index 02defcc26..4ed541a73 100644 --- a/docs/package.json +++ b/docs/package.json @@ -14,12 +14,12 @@ "write-heading-ids": "docusaurus write-heading-ids" }, "dependencies": { - "@docusaurus/core": "^2.2.0", - "@docusaurus/preset-classic": "^2.2.0", + "@docusaurus/core": "^2.4.0", + "@docusaurus/preset-classic": "^2.4.0", "@mdx-js/react": "^1.6.22", "clsx": "^1.2.1", - "raw-loader": "^4.0.2", "prism-react-renderer": "^1.3.5", + "raw-loader": "^4.0.2", "react": "^17.0.2", "react-dom": "^17.0.2" }, @@ -36,8 +36,8 @@ ] }, "devDependencies": { - "@types/react": "^17.0.0", - "@docusaurus/module-type-aliases": "2.2.0" + "@docusaurus/module-type-aliases": "^2.4.0", + "@types/react": "^17.0.0" }, "engines": { "node": ">=16.14" diff --git a/docs/sidebars.js b/docs/sidebars.js index 18bb2f88c..bcf1f2885 100644 --- a/docs/sidebars.js +++ b/docs/sidebars.js @@ -4,11 +4,11 @@ module.exports = { "frigate/index", "frigate/hardware", "frigate/installation", + "frigate/camera_setup", ], Guides: [ - "guides/camera_setup", "guides/getting_started", - "guides/events_setup", + "guides/configuring_go2rtc", "guides/false_positives", "guides/ha_notifications", "guides/stationary_objects", diff --git a/frigate/app.py b/frigate/app.py index 4080ffbf4..8c1cd4433 100644 --- a/frigate/app.py +++ b/frigate/app.py @@ -3,6 +3,7 @@ import multiprocessing as mp from multiprocessing.queues import Queue from multiprocessing.synchronize import Event as MpEvent import os +import shutil import signal import sys from typing import Optional @@ -22,14 +23,14 @@ from frigate.object_detection import ObjectDetectProcess from frigate.events import EventCleanup, EventProcessor from frigate.http import create_app from frigate.log import log_process, root_configurer -from frigate.models import Event, Recordings +from frigate.models import Event, Recordings, Timeline from frigate.object_processing import TrackedObjectProcessor from frigate.output import output_frames from frigate.plus import PlusApi from frigate.record import RecordingCleanup, RecordingMaintainer -from frigate.restream import RestreamApi from frigate.stats import StatsEmitter, stats_init from frigate.storage import StorageMaintainer +from frigate.timeline import TimelineProcessor from frigate.version import VERSION from frigate.video import capture_camera, track_camera from frigate.watchdog import FrigateWatchdog @@ -116,6 +117,9 @@ class FrigateApp: if not "werkzeug" in self.config.logger.logs: logging.getLogger("werkzeug").setLevel("ERROR") + if not "ws4py" in self.config.logger.logs: + logging.getLogger("ws4py").setLevel("ERROR") + def init_queues(self) -> None: # Queues for clip processing self.event_queue: Queue = mp.Queue() @@ -132,6 +136,9 @@ class FrigateApp: # Queue for recordings info self.recordings_info_queue: Queue = mp.Queue() + # Queue for timeline events + self.timeline_queue: Queue = mp.Queue() + def init_database(self) -> None: # Migrate DB location old_db_path = DEFAULT_DB_PATH @@ -151,7 +158,7 @@ class FrigateApp: migrate_db.close() self.db = SqliteQueueDatabase(self.config.database.path) - models = [Event, Recordings] + models = [Event, Recordings, Timeline] self.db.bind(models) def init_stats(self) -> None: @@ -169,18 +176,13 @@ class FrigateApp: self.plus_api, ) - def init_restream(self) -> None: - self.restream = RestreamApi(self.config) - self.restream.add_cameras() - def init_dispatcher(self) -> None: comms: list[Communicator] = [] if self.config.mqtt.enabled: comms.append(MqttClient(self.config)) - self.ws_client = WebSocketClient(self.config) - comms.append(self.ws_client) + comms.append(WebSocketClient(self.config)) self.dispatcher = Dispatcher(self.config, self.camera_metrics, comms) def start_detectors(self) -> None: @@ -288,12 +290,19 @@ class FrigateApp: capture_process.start() logger.info(f"Capture process started for {name}: {capture_process.pid}") + def start_timeline_processor(self) -> None: + self.timeline_processor = TimelineProcessor( + self.config, self.timeline_queue, self.stop_event + ) + self.timeline_processor.start() + def start_event_processor(self) -> None: self.event_processor = EventProcessor( self.config, self.camera_metrics, self.event_queue, self.event_processed_queue, + self.timeline_queue, self.stop_event, ) self.event_processor.start() @@ -329,6 +338,22 @@ class FrigateApp: self.frigate_watchdog = FrigateWatchdog(self.detectors, self.stop_event) self.frigate_watchdog.start() + def check_shm(self) -> None: + available_shm = round(shutil.disk_usage("/dev/shm").total / 1000000, 1) + min_req_shm = 30 + + for _, camera in self.config.cameras.items(): + min_req_shm += round( + (camera.detect.width * camera.detect.height * 1.5 * 9 + 270480) + / 1048576, + 1, + ) + + if available_shm < min_req_shm: + logger.warning( + f"The current SHM size of {available_shm}MB is too small, recommend increasing it to at least {min_req_shm}MB." + ) + def start(self) -> None: self.init_logger() logger.info(f"Starting Frigate ({VERSION})") @@ -362,7 +387,6 @@ class FrigateApp: print(e) self.log_process.terminate() sys.exit(1) - self.init_restream() self.start_detectors() self.start_video_output_processor() self.start_detected_frames_processor() @@ -371,13 +395,14 @@ class FrigateApp: self.start_storage_maintainer() self.init_stats() self.init_web_server() + self.start_timeline_processor() self.start_event_processor() self.start_event_cleanup() self.start_recording_maintainer() self.start_recording_cleanup() self.start_stats_emitter() self.start_watchdog() - # self.zeroconf = broadcast_zeroconf(self.config.mqtt.client_id) + self.check_shm() def receiveSignal(signalNumber: int, frame: Optional[FrameType]) -> None: self.stop() @@ -396,7 +421,17 @@ class FrigateApp: logger.info(f"Stopping...") self.stop_event.set() - self.ws_client.stop() + for detector in self.detectors.values(): + detector.stop() + + # Empty the detection queue and set the events for all requests + while not self.detection_queue.empty(): + connection_id = self.detection_queue.get(timeout=1) + self.detection_out_events[connection_id].set() + self.detection_queue.close() + self.detection_queue.join_thread() + + self.dispatcher.stop() self.detected_frames_processor.join() self.event_processor.join() self.event_cleanup.join() @@ -406,10 +441,20 @@ class FrigateApp: self.frigate_watchdog.join() self.db.stop() - for detector in self.detectors.values(): - detector.stop() - while len(self.detection_shms) > 0: shm = self.detection_shms.pop() shm.close() shm.unlink() + + for queue in [ + self.event_queue, + self.event_processed_queue, + self.video_output_queue, + self.detected_frames_queue, + self.recordings_info_queue, + self.log_queue, + ]: + while not queue.empty(): + queue.get_nowait() + queue.close() + queue.join_thread() diff --git a/frigate/comms/dispatcher.py b/frigate/comms/dispatcher.py index aab011fe9..d304509e4 100644 --- a/frigate/comms/dispatcher.py +++ b/frigate/comms/dispatcher.py @@ -27,6 +27,11 @@ class Communicator(ABC): """Pass receiver so communicators can pass commands.""" pass + @abstractmethod + def stop(self) -> None: + """Stop the communicator.""" + pass + class Dispatcher: """Handle communication between Frigate and communicators.""" @@ -72,6 +77,10 @@ class Dispatcher: for comm in self.comms: comm.publish(topic, payload, retain) + def stop(self) -> None: + for comm in self.comms: + comm.stop() + def _on_detect_command(self, camera_name: str, payload: str) -> None: """Callback for detect topic.""" detect_settings = self.config.cameras[camera_name].detect diff --git a/frigate/comms/mqtt.py b/frigate/comms/mqtt.py index b8c1a0ea6..d106aae71 100644 --- a/frigate/comms/mqtt.py +++ b/frigate/comms/mqtt.py @@ -35,6 +35,9 @@ class MqttClient(Communicator): # type: ignore[misc] f"{self.mqtt_config.topic_prefix}/{topic}", payload, retain=retain ) + def stop(self) -> None: + self.client.disconnect() + def _set_initial_topics(self) -> None: """Set initial state topics.""" for camera_name, camera in self.config.cameras.items(): diff --git a/frigate/comms/ws.py b/frigate/comms/ws.py index 0a3aea169..c9cc3988a 100644 --- a/frigate/comms/ws.py +++ b/frigate/comms/ws.py @@ -95,3 +95,4 @@ class WebSocketClient(Communicator): # type: ignore[misc] self.websocket_server.manager.join() self.websocket_server.shutdown() self.websocket_thread.join() + logger.info("Exiting websocket client...") diff --git a/frigate/config.py b/frigate/config.py index 62578e1af..b83f3cbde 100644 --- a/frigate/config.py +++ b/frigate/config.py @@ -66,12 +66,37 @@ class LiveModeEnum(str, Enum): webrtc = "webrtc" +class TimeFormatEnum(str, Enum): + browser = "browser" + hours12 = "12hour" + hours24 = "24hour" + + +class DateTimeStyleEnum(str, Enum): + full = "full" + long = "long" + medium = "medium" + short = "short" + + class UIConfig(FrigateBaseModel): live_mode: LiveModeEnum = Field( default=LiveModeEnum.mse, title="Default Live Mode." ) timezone: Optional[str] = Field(title="Override UI timezone.") use_experimental: bool = Field(default=False, title="Experimental UI") + time_format: TimeFormatEnum = Field( + default=TimeFormatEnum.browser, title="Override UI time format." + ) + date_style: DateTimeStyleEnum = Field( + default=DateTimeStyleEnum.short, title="Override UI dateStyle." + ) + time_style: DateTimeStyleEnum = Field( + default=DateTimeStyleEnum.medium, title="Override UI timeStyle." + ) + strftime_fmt: Optional[str] = Field( + default=None, title="Override date and time format using strftime syntax." + ) class TelemetryConfig(FrigateBaseModel): @@ -139,8 +164,6 @@ class RecordConfig(FrigateBaseModel): default=60, title="Number of minutes to wait between cleanup runs.", ) - # deprecated - to be removed in a future version - retain_days: Optional[float] = Field(title="Recording retention period in days.") retain: RecordRetainConfig = Field( default_factory=RecordRetainConfig, title="Record retention settings." ) @@ -370,9 +393,18 @@ class BirdseyeCameraConfig(BaseModel): ) -FFMPEG_GLOBAL_ARGS_DEFAULT = ["-hide_banner", "-loglevel", "warning"] +# Note: Setting threads to less than 2 caused several issues with recording segments +# https://github.com/blakeblackshear/frigate/issues/5659 +FFMPEG_GLOBAL_ARGS_DEFAULT = ["-hide_banner", "-loglevel", "warning", "-threads", "2"] FFMPEG_INPUT_ARGS_DEFAULT = "preset-rtsp-generic" -DETECT_FFMPEG_OUTPUT_ARGS_DEFAULT = ["-f", "rawvideo", "-pix_fmt", "yuv420p"] +DETECT_FFMPEG_OUTPUT_ARGS_DEFAULT = [ + "-threads", + "2", + "-f", + "rawvideo", + "-pix_fmt", + "yuv420p", +] RTMP_FFMPEG_OUTPUT_ARGS_DEFAULT = "preset-rtmp-generic" RECORD_FFMPEG_OUTPUT_ARGS_DEFAULT = "preset-record-generic" @@ -749,16 +781,6 @@ def verify_valid_live_stream_name( ) -def verify_old_retain_config(camera_config: CameraConfig) -> None: - """Leave log if old retain_days is used.""" - if not camera_config.record.retain_days is None: - logger.warning( - "The 'retain_days' config option has been DEPRECATED and will be removed in a future version. Please use the 'days' setting under 'retain'" - ) - if camera_config.record.retain.days == 0: - camera_config.record.retain.days = camera_config.record.retain_days - - def verify_recording_retention(camera_config: CameraConfig) -> None: """Verify that recording retention modes are ranked correctly.""" rank_map = { @@ -965,7 +987,6 @@ class FrigateConfig(FrigateBaseModel): verify_config_roles(camera_config) verify_valid_live_stream_name(config, camera_config) - verify_old_retain_config(camera_config) verify_recording_retention(camera_config) verify_recording_segments_setup_with_reasonable_time(camera_config) verify_zone_objects_are_tracked(camera_config) diff --git a/frigate/detectors/detector_config.py b/frigate/detectors/detector_config.py index 747a12de4..25dede107 100644 --- a/frigate/detectors/detector_config.py +++ b/frigate/detectors/detector_config.py @@ -23,6 +23,13 @@ class InputTensorEnum(str, Enum): nhwc = "nhwc" +class ModelTypeEnum(str, Enum): + ssd = "ssd" + yolox = "yolox" + yolov5 = "yolov5" + yolov8 = "yolov8" + + class ModelConfig(BaseModel): path: Optional[str] = Field(title="Custom Object detection model path.") labelmap_path: Optional[str] = Field(title="Label map for custom object detector.") @@ -37,6 +44,9 @@ class ModelConfig(BaseModel): input_pixel_format: PixelFormatEnum = Field( default=PixelFormatEnum.rgb, title="Model Input Pixel Color Format" ) + model_type: ModelTypeEnum = Field( + default=ModelTypeEnum.ssd, title="Object Detection Model Type" + ) _merged_labelmap: Optional[Dict[int, str]] = PrivateAttr() _colormap: Dict[int, Tuple[int, int, int]] = PrivateAttr() diff --git a/frigate/detectors/detector_types.py b/frigate/detectors/detector_types.py index 1e2269c94..5c96b2e16 100644 --- a/frigate/detectors/detector_types.py +++ b/frigate/detectors/detector_types.py @@ -13,12 +13,19 @@ from .detector_config import BaseDetectorConfig logger = logging.getLogger(__name__) -plugin_modules = [ - importlib.import_module(name) - for finder, name, ispkg in pkgutil.iter_modules( - plugins.__path__, plugins.__name__ + "." - ) -] + +_included_modules = pkgutil.iter_modules(plugins.__path__, plugins.__name__ + ".") + +plugin_modules = [] + +for _, name, _ in _included_modules: + try: + # currently openvino may fail when importing + # on an arm device with 64 KiB page size. + plugin_modules.append(importlib.import_module(name)) + except ImportError as e: + logger.error(f"Error importing detector runtime: {e}") + api_types = {det.type_key: det for det in DetectionApi.__subclasses__()} diff --git a/frigate/detectors/plugins/cpu_tfl.py b/frigate/detectors/plugins/cpu_tfl.py index 9e24cb1f4..fb9cbbfae 100644 --- a/frigate/detectors/plugins/cpu_tfl.py +++ b/frigate/detectors/plugins/cpu_tfl.py @@ -5,7 +5,11 @@ from frigate.detectors.detection_api import DetectionApi from frigate.detectors.detector_config import BaseDetectorConfig from typing import Literal from pydantic import Extra, Field -import tflite_runtime.interpreter as tflite + +try: + from tflite_runtime.interpreter import Interpreter +except ModuleNotFoundError: + from tensorflow.lite.python.interpreter import Interpreter logger = logging.getLogger(__name__) @@ -22,7 +26,7 @@ class CpuTfl(DetectionApi): type_key = DETECTOR_KEY def __init__(self, detector_config: CpuDetectorConfig): - self.interpreter = tflite.Interpreter( + self.interpreter = Interpreter( model_path=detector_config.model.path or "/cpu_model.tflite", num_threads=detector_config.num_threads or 3, ) diff --git a/frigate/detectors/plugins/edgetpu_tfl.py b/frigate/detectors/plugins/edgetpu_tfl.py index 024e6574b..840d41f66 100644 --- a/frigate/detectors/plugins/edgetpu_tfl.py +++ b/frigate/detectors/plugins/edgetpu_tfl.py @@ -5,8 +5,11 @@ from frigate.detectors.detection_api import DetectionApi from frigate.detectors.detector_config import BaseDetectorConfig from typing import Literal from pydantic import Extra, Field -import tflite_runtime.interpreter as tflite -from tflite_runtime.interpreter import load_delegate + +try: + from tflite_runtime.interpreter import Interpreter, load_delegate +except ModuleNotFoundError: + from tensorflow.lite.python.interpreter import Interpreter, load_delegate logger = logging.getLogger(__name__) @@ -33,7 +36,7 @@ class EdgeTpuTfl(DetectionApi): logger.info(f"Attempting to load TPU as {device_config['device']}") edge_tpu_delegate = load_delegate("libedgetpu.so.1.0", device_config) logger.info("TPU found") - self.interpreter = tflite.Interpreter( + self.interpreter = Interpreter( model_path=detector_config.model.path or "/edgetpu_model.tflite", experimental_delegates=[edge_tpu_delegate], ) diff --git a/frigate/detectors/plugins/openvino.py b/frigate/detectors/plugins/openvino.py index 93f3cf6a6..993b2b8ff 100644 --- a/frigate/detectors/plugins/openvino.py +++ b/frigate/detectors/plugins/openvino.py @@ -3,7 +3,7 @@ import numpy as np import openvino.runtime as ov from frigate.detectors.detection_api import DetectionApi -from frigate.detectors.detector_config import BaseDetectorConfig +from frigate.detectors.detector_config import BaseDetectorConfig, ModelTypeEnum from typing import Literal from pydantic import Extra, Field @@ -24,12 +24,18 @@ class OvDetector(DetectionApi): def __init__(self, detector_config: OvDetectorConfig): self.ov_core = ov.Core() self.ov_model = self.ov_core.read_model(detector_config.model.path) + self.ov_model_type = detector_config.model.model_type + + self.h = detector_config.model.height + self.w = detector_config.model.width self.interpreter = self.ov_core.compile_model( model=self.ov_model, device_name=detector_config.device ) + logger.info(f"Model Input Shape: {self.interpreter.input(0).shape}") self.output_indexes = 0 + while True: try: tensor_shape = self.interpreter.output(self.output_indexes).shape @@ -38,29 +44,131 @@ class OvDetector(DetectionApi): except: logger.info(f"Model has {self.output_indexes} Output Tensors") break + if self.ov_model_type == ModelTypeEnum.yolox: + self.num_classes = tensor_shape[2] - 5 + logger.info(f"YOLOX model has {self.num_classes} classes") + self.set_strides_grids() + + def set_strides_grids(self): + grids = [] + expanded_strides = [] + + strides = [8, 16, 32] + + hsizes = [self.h // stride for stride in strides] + wsizes = [self.w // stride for stride in strides] + + for hsize, wsize, stride in zip(hsizes, wsizes, strides): + xv, yv = np.meshgrid(np.arange(wsize), np.arange(hsize)) + grid = np.stack((xv, yv), 2).reshape(1, -1, 2) + grids.append(grid) + shape = grid.shape[:2] + expanded_strides.append(np.full((*shape, 1), stride)) + self.grids = np.concatenate(grids, 1) + self.expanded_strides = np.concatenate(expanded_strides, 1) + + ## Takes in class ID, confidence score, and array of [x, y, w, h] that describes detection position, + ## returns an array that's easily passable back to Frigate. + def process_yolo(self, class_id, conf, pos): + return [ + class_id, # class ID + conf, # confidence score + (pos[1] - (pos[3] / 2)) / self.h, # y_min + (pos[0] - (pos[2] / 2)) / self.w, # x_min + (pos[1] + (pos[3] / 2)) / self.h, # y_max + (pos[0] + (pos[2] / 2)) / self.w, # x_max + ] def detect_raw(self, tensor_input): - infer_request = self.interpreter.create_infer_request() infer_request.infer([tensor_input]) - results = infer_request.get_output_tensor() + if self.ov_model_type == ModelTypeEnum.ssd: + results = infer_request.get_output_tensor() - detections = np.zeros((20, 6), np.float32) - i = 0 - for object_detected in results.data[0, 0, :]: - if object_detected[0] != -1: - logger.debug(object_detected) - if object_detected[2] < 0.1 or i == 20: - break - detections[i] = [ - object_detected[1], # Label ID - float(object_detected[2]), # Confidence - object_detected[4], # y_min - object_detected[3], # x_min - object_detected[6], # y_max - object_detected[5], # x_max - ] - i += 1 + detections = np.zeros((20, 6), np.float32) + i = 0 + for object_detected in results.data[0, 0, :]: + if object_detected[0] != -1: + logger.debug(object_detected) + if object_detected[2] < 0.1 or i == 20: + break + detections[i] = [ + object_detected[1], # Label ID + float(object_detected[2]), # Confidence + object_detected[4], # y_min + object_detected[3], # x_min + object_detected[6], # y_max + object_detected[5], # x_max + ] + i += 1 + return detections + elif self.ov_model_type == ModelTypeEnum.yolox: + out_tensor = infer_request.get_output_tensor() + # [x, y, h, w, box_score, class_no_1, ..., class_no_80], + results = out_tensor.data + results[..., :2] = (results[..., :2] + self.grids) * self.expanded_strides + results[..., 2:4] = np.exp(results[..., 2:4]) * self.expanded_strides + image_pred = results[0, ...] - return detections + class_conf = np.max( + image_pred[:, 5 : 5 + self.num_classes], axis=1, keepdims=True + ) + class_pred = np.argmax(image_pred[:, 5 : 5 + self.num_classes], axis=1) + class_pred = np.expand_dims(class_pred, axis=1) + + conf_mask = (image_pred[:, 4] * class_conf.squeeze() >= 0.3).squeeze() + # Detections ordered as (x1, y1, x2, y2, obj_conf, class_conf, class_pred) + dets = np.concatenate((image_pred[:, :5], class_conf, class_pred), axis=1) + dets = dets[conf_mask] + + ordered = dets[dets[:, 5].argsort()[::-1]][:20] + + detections = np.zeros((20, 6), np.float32) + + for i, object_detected in enumerate(ordered): + detections[i] = self.process_yolo( + object_detected[6], object_detected[5], object_detected[:4] + ) + return detections + elif self.ov_model_type == ModelTypeEnum.yolov8: + out_tensor = infer_request.get_output_tensor() + results = out_tensor.data[0] + output_data = np.transpose(results) + scores = np.max(output_data[:, 4:], axis=1) + if len(scores) == 0: + return np.zeros((20, 6), np.float32) + scores = np.expand_dims(scores, axis=1) + # add scores to the last column + dets = np.concatenate((output_data, scores), axis=1) + # filter out lines with scores below threshold + dets = dets[dets[:, -1] > 0.5, :] + # limit to top 20 scores, descending order + ordered = dets[dets[:, -1].argsort()[::-1]][:20] + detections = np.zeros((20, 6), np.float32) + + for i, object_detected in enumerate(ordered): + detections[i] = self.process_yolo( + np.argmax(object_detected[4:-1]), + object_detected[-1], + object_detected[:4], + ) + return detections + elif self.ov_model_type == ModelTypeEnum.yolov5: + out_tensor = infer_request.get_output_tensor() + output_data = out_tensor.data[0] + # filter out lines with scores below threshold + conf_mask = (output_data[:, 4] >= 0.5).squeeze() + output_data = output_data[conf_mask] + # limit to top 20 scores, descending order + ordered = output_data[output_data[:, 4].argsort()[::-1]][:20] + + detections = np.zeros((20, 6), np.float32) + + for i, object_detected in enumerate(ordered): + detections[i] = self.process_yolo( + np.argmax(object_detected[5:]), + object_detected[4], + object_detected[:4], + ) + return detections diff --git a/frigate/events.py b/frigate/events.py index 5f30f8633..416b28fd7 100644 --- a/frigate/events.py +++ b/frigate/events.py @@ -3,14 +3,14 @@ import logging import os import queue import threading -import time from pathlib import Path from peewee import fn -from frigate.config import EventsConfig, FrigateConfig, RecordConfig +from frigate.config import EventsConfig, FrigateConfig from frigate.const import CLIPS_DIR from frigate.models import Event +from frigate.timeline import TimelineSourceEnum from frigate.types import CameraMetricsTypes from multiprocessing.queues import Queue @@ -48,6 +48,7 @@ class EventProcessor(threading.Thread): camera_processes: dict[str, CameraMetricsTypes], event_queue: Queue, event_processed_queue: Queue, + timeline_queue: Queue, stop_event: MpEvent, ): threading.Thread.__init__(self) @@ -56,6 +57,7 @@ class EventProcessor(threading.Thread): self.camera_processes = camera_processes self.event_queue = event_queue self.event_processed_queue = event_processed_queue + self.timeline_queue = timeline_queue self.events_in_process: Dict[str, Event] = {} self.stop_event = stop_event @@ -67,12 +69,22 @@ class EventProcessor(threading.Thread): while not self.stop_event.is_set(): try: - event_type, camera, event_data = self.event_queue.get(timeout=10) + event_type, camera, event_data = self.event_queue.get(timeout=1) except queue.Empty: continue logger.debug(f"Event received: {event_type} {camera} {event_data['id']}") + self.timeline_queue.put( + ( + camera, + TimelineSourceEnum.tracked_object, + event_type, + self.events_in_process.get(event_data["id"]), + event_data, + ) + ) + event_config: EventsConfig = self.config.cameras[camera].record.events if event_type == "start": diff --git a/frigate/ffmpeg_presets.py b/frigate/ffmpeg_presets.py index b708b55a1..67348569c 100644 --- a/frigate/ffmpeg_presets.py +++ b/frigate/ffmpeg_presets.py @@ -1,14 +1,52 @@ """Handles inserting and maintaining ffmpeg presets.""" +import logging import os from typing import Any from frigate.version import VERSION from frigate.const import BTBN_PATH +from frigate.util import vainfo_hwaccel + + +logger = logging.getLogger(__name__) + + +class LibvaGpuSelector: + "Automatically selects the correct libva GPU." + + _selected_gpu = None + + def get_selected_gpu(self) -> str: + """Get selected libva GPU.""" + if not os.path.exists("/dev/dri"): + return "" + + if self._selected_gpu: + return self._selected_gpu + + devices = list(filter(lambda d: d.startswith("render"), os.listdir("/dev/dri"))) + + if len(devices) < 2: + self._selected_gpu = "/dev/dri/renderD128" + return self._selected_gpu + + for device in devices: + check = vainfo_hwaccel(device_name=device) + + logger.debug(f"{device} return vainfo status code: {check.returncode}") + + if check.returncode == 0: + self._selected_gpu = f"/dev/dri/{device}" + return self._selected_gpu + + return "" + TIMEOUT_PARAM = "-timeout" if os.path.exists(BTBN_PATH) else "-stimeout" +_gpu_selector = LibvaGpuSelector() _user_agent_args = [ "-user_agent", f"FFmpeg Frigate/{VERSION}", @@ -23,7 +61,7 @@ PRESETS_HW_ACCEL_DECODE = { "-hwaccel", "vaapi", "-hwaccel_device", - "/dev/dri/renderD128", + _gpu_selector.get_selected_gpu(), "-hwaccel_output_format", "vaapi", ], @@ -31,7 +69,7 @@ PRESETS_HW_ACCEL_DECODE = { "-hwaccel", "qsv", "-qsv_device", - "/dev/dri/renderD128", + _gpu_selector.get_selected_gpu(), "-hwaccel_output_format", "qsv", "-c:v", @@ -43,7 +81,7 @@ PRESETS_HW_ACCEL_DECODE = { "-hwaccel", "qsv", "-qsv_device", - "/dev/dri/renderD128", + _gpu_selector.get_selected_gpu(), "-hwaccel_output_format", "qsv", "-c:v", @@ -54,47 +92,36 @@ PRESETS_HW_ACCEL_DECODE = { "cuda", "-hwaccel_output_format", "cuda", - "-extra_hw_frames", - "2", - "-c:v", - "h264_cuvid", ], "preset-nvidia-h265": [ "-hwaccel", "cuda", "-hwaccel_output_format", "cuda", - "-extra_hw_frames", - "2", - "-c:v", - "hevc_cuvid", ], "preset-nvidia-mjpeg": [ "-hwaccel", "cuda", "-hwaccel_output_format", "cuda", - "-extra_hw_frames", - "2", - "-c:v", - "mjpeg_cuvid", ], } PRESETS_HW_ACCEL_SCALE = { - "preset-rpi-32-h264": "-r {0} -s {1}x{2} -f rawvideo -pix_fmt yuv420p", - "preset-rpi-64-h264": "-r {0} -s {1}x{2} -f rawvideo -pix_fmt yuv420p", - "preset-vaapi": "-r {0} -vf fps={0},scale_vaapi=w={1}:h={2},hwdownload,format=yuv420p -f rawvideo", - "preset-intel-qsv-h264": "-r {0} -vf vpp_qsv=framerate={0}:w={1}:h={2}:format=nv12,hwdownload,format=nv12,format=yuv420p -f rawvideo", - "preset-intel-qsv-h265": "-r {0} -vf vpp_qsv=framerate={0}:w={1}:h={2}:format=nv12,hwdownload,format=nv12,format=yuv420p -f rawvideo", - "preset-nvidia-h264": "-r {0} -vf fps={0},scale_cuda=w={1}:h={2}:format=nv12,hwdownload,format=nv12,format=yuv420p -f rawvideo", - "preset-nvidia-h265": "-r {0} -vf fps={0},scale_cuda=w={1}:h={2}:format=nv12,hwdownload,format=nv12,format=yuv420p -f rawvideo", + "preset-rpi-32-h264": "-r {0} -s {1}x{2}", + "preset-rpi-64-h264": "-r {0} -s {1}x{2}", + "preset-vaapi": "-r {0} -vf fps={0},scale_vaapi=w={1}:h={2},hwdownload,format=yuv420p", + "preset-intel-qsv-h264": "-r {0} -vf vpp_qsv=framerate={0}:w={1}:h={2}:format=nv12,hwdownload,format=nv12,format=yuv420p", + "preset-intel-qsv-h265": "-r {0} -vf vpp_qsv=framerate={0}:w={1}:h={2}:format=nv12,hwdownload,format=nv12,format=yuv420p", + "preset-nvidia-h264": "-r {0} -vf fps={0},scale_cuda=w={1}:h={2}:format=nv12,hwdownload,format=nv12,format=yuv420p", + "preset-nvidia-h265": "-r {0} -vf fps={0},scale_cuda=w={1}:h={2}:format=nv12,hwdownload,format=nv12,format=yuv420p", "default": "-r {0} -s {1}x{2}", } PRESETS_HW_ACCEL_ENCODE = { - "preset-rpi-32-h264": "ffmpeg -hide_banner {0} -c:v h264_v4l2m2m -g 50 -bf 0 {1}", - "preset-rpi-64-h264": "ffmpeg -hide_banner {0} -c:v h264_v4l2m2m -g 50 -bf 0 {1}", + "preset-rpi-32-h264": "ffmpeg -hide_banner {0} -c:v h264_v4l2m2m {1}", + "preset-rpi-64-h264": "ffmpeg -hide_banner {0} -c:v h264_v4l2m2m {1}", + "preset-vaapi": "ffmpeg -hide_banner -hwaccel vaapi -hwaccel_output_format vaapi -hwaccel_device {2} {0} -c:v h264_vaapi -g 50 -bf 0 -profile:v high -level:v 4.1 -sei:v 0 -an -vf format=vaapi|nv12,hwupload {1}", "preset-intel-qsv-h264": "ffmpeg -hide_banner {0} -c:v h264_qsv -g 50 -bf 0 -profile:v high -level:v 4.1 -async_depth:v 1 {1}", "preset-intel-qsv-h265": "ffmpeg -hide_banner {0} -c:v h264_qsv -g 50 -bf 0 -profile:v high -level:v 4.1 -async_depth:v 1 {1}", "preset-nvidia-h264": "ffmpeg -hide_banner {0} -c:v h264_nvenc -g 50 -profile:v high -level:v auto -preset:v p2 -tune:v ll {1}", @@ -127,7 +154,9 @@ def parse_preset_hardware_acceleration_scale( scale = PRESETS_HW_ACCEL_SCALE.get(arg, "") if scale: - return scale.format(fps, width, height).split(" ") + scale = scale.format(fps, width, height).split(" ") + scale.extend(detect_args) + return scale else: scale = scale.format(fps, width, height).split(" ") scale.extend(detect_args) @@ -142,6 +171,7 @@ def parse_preset_hardware_acceleration_encode(arg: Any, input: str, output: str) return PRESETS_HW_ACCEL_ENCODE.get(arg, PRESETS_HW_ACCEL_ENCODE["default"]).format( input, output, + _gpu_selector.get_selected_gpu(), ) @@ -231,6 +261,13 @@ PRESETS_INPUT = { "1", ], "preset-rtsp-restream": _user_agent_args + + [ + "-rtsp_transport", + "tcp", + TIMEOUT_PARAM, + "5000000", + ], + "preset-rtsp-restream-low-latency": _user_agent_args + [ "-rtsp_transport", "tcp", diff --git a/frigate/http.py b/frigate/http.py index 4ae4d4d95..cb8c1cbe8 100644 --- a/frigate/http.py +++ b/frigate/http.py @@ -33,7 +33,7 @@ from playhouse.shortcuts import model_to_dict from frigate.config import FrigateConfig from frigate.const import CLIPS_DIR, MAX_SEGMENT_DURATION, RECORD_DIR -from frigate.models import Event, Recordings +from frigate.models import Event, Recordings, Timeline from frigate.object_processing import TrackedObject from frigate.stats import stats_snapshot from frigate.util import ( @@ -111,6 +111,7 @@ def events_summary(): Event.select( Event.camera, Event.label, + Event.sub_label, fn.strftime( "%Y-%m-%d", fn.datetime( @@ -124,6 +125,7 @@ def events_summary(): .group_by( Event.camera, Event.label, + Event.sub_label, fn.strftime( "%Y-%m-%d", fn.datetime( @@ -184,6 +186,18 @@ def send_to_plus(id): logger.error(message) return make_response(jsonify({"success": False, "message": message}), 404) + if event.end_time is None: + logger.error(f"Unable to load clean png for in-progress event: {event.id}") + return make_response( + jsonify( + { + "success": False, + "message": "Unable to load clean png for in-progress event", + } + ), + 400, + ) + if event.plus_id: message = "Already submitted to plus" logger.error(message) @@ -202,6 +216,15 @@ def send_to_plus(id): 400, ) + if image is None or image.size == 0: + logger.error(f"Unable to load clean png for event: {event.id}") + return make_response( + jsonify( + {"success": False, "message": "Unable to load clean png for event"} + ), + 400, + ) + try: plus_id = current_app.plus_api.upload_image(image, event.camera) except Exception as ex: @@ -301,7 +324,9 @@ def get_sub_labels(): sub_labels.remove(None) if split_joined: - for label in sub_labels: + original_labels = sub_labels.copy() + + for label in original_labels: if "," in label: sub_labels.remove(label) parts = label.split(",") @@ -310,6 +335,7 @@ def get_sub_labels(): if not (part.strip()) in sub_labels: sub_labels.append(part.strip()) + sub_labels.sort() return jsonify(sub_labels) @@ -388,6 +414,42 @@ def event_thumbnail(id, max_cache_age=2592000): return response +@bp.route("/timeline") +def timeline(): + camera = request.args.get("camera", "all") + source_id = request.args.get("source_id", type=str) + limit = request.args.get("limit", 100) + + clauses = [] + + selected_columns = [ + Timeline.timestamp, + Timeline.camera, + Timeline.source, + Timeline.source_id, + Timeline.class_type, + Timeline.data, + ] + + if camera != "all": + clauses.append((Timeline.camera == camera)) + + if source_id: + clauses.append((Timeline.source_id == source_id)) + + if len(clauses) == 0: + clauses.append((True)) + + timeline = ( + Timeline.select(*selected_columns) + .where(reduce(operator.and_, clauses)) + .order_by(Timeline.timestamp.asc()) + .limit(limit) + ) + + return jsonify([model_to_dict(t) for t in timeline]) + + @bp.route("//