diff --git a/Dockerfile b/Dockerfile index 8becfba..c6399c2 100644 --- a/Dockerfile +++ b/Dockerfile @@ -17,6 +17,7 @@ ENV RCLONE_RETENTION=7d ENV RCLONE_DESTINATION=my_remote:/unifi_protect_backup ENV VERBOSITY="v" ENV TZ=UTC +ENV IGNORE_CAMERAS="" VOLUME [ "/root/.config/rclone/" ] diff --git a/README.md b/README.md index 805aa5c..efbefb4 100644 --- a/README.md +++ b/README.md @@ -61,32 +61,39 @@ Options: `gdrive:/backups/unifi_protect` [required] --retention TEXT How long should event clips be backed up for. Format as per the `--max-age` argument - of rclone` + of `rclone` (https://rclone.org/filtering/#max-age-don- t-transfer-any-file-older-than-this) + --ignore-camera TEXT IDs of cameras for which events should not + be backed up. Use multiple times to ignore + multiple IDs. If being set as an environment + variable the IDs should be separated by + whitespace. -v, --verbose How verbose the logging output should be. - None: Only log info messages created by - `unifi-protect-backup`, and all warnings + None: Only log info messages created by + `unifi-protect-backup`, and all warnings - -v: Only log info & debug messages created - by `unifi-protect-backup`, and all warnings + -v: Only log info & debug messages + created by `unifi-protect-backup`, and + all warnings - -vv: Log info & debug messages created by - `unifi-protect-backup`, command output, and - all warnings + -vv: Log info & debug messages created + by `unifi-protect-backup`, command + output, and all warnings - -vvv Log debug messages created by `unifi- - protect-backup`, command output, all info - messages, and all warnings + -vvv Log debug messages created by + `unifi-protect-backup`, command output, + all info messages, and all warnings - -vvvv: Log debug messages created by `unifi- - protect-backup` command output, all info - messages, all warnings, and websocket data + -vvvv: Log debug messages created by + `unifi-protect-backup` command output, + all info messages, all warnings, and + websocket data - -vvvvv: Log websocket data, command output, - all debug messages, all info messages and - all warnings [x>=0] + -vvvvv: Log websocket data, command + output, all debug messages, all info + messages and all warnings [x>=0] --help Show this message and exit. ``` @@ -99,6 +106,7 @@ always take priority over environment variables): - `UFP_SSL_VERIFY` - `RCLONE_RETENTION` - `RCLONE_DESTINATION` +- `IGNORE_CAMERAS` ## Docker Container You can run this tool as a container if you prefer with the following command. diff --git a/unifi_protect_backup/cli.py b/unifi_protect_backup/cli.py index 74f4403..ba82561 100644 --- a/unifi_protect_backup/cli.py +++ b/unifi_protect_backup/cli.py @@ -32,6 +32,14 @@ from unifi_protect_backup import UnifiProtectBackup help="How long should event clips be backed up for. Format as per the `--max-age` argument of " "`rclone` (https://rclone.org/filtering/#max-age-don-t-transfer-any-file-older-than-this)", ) +@click.option( + '--ignore-camera', + 'ignore_cameras', + multiple=True, + envvar="IGNORE_CAMERAS", + help="IDs of cameras for which events should not be backed up. Use multiple times to ignore " + "multiple IDs. If being set as an environment variable the IDs should be separated by whitespace.", +) @click.option( '-v', '--verbose', diff --git a/unifi_protect_backup/unifi_protect_backup.py b/unifi_protect_backup/unifi_protect_backup.py index 72427b8..57afed6 100644 --- a/unifi_protect_backup/unifi_protect_backup.py +++ b/unifi_protect_backup/unifi_protect_backup.py @@ -3,7 +3,7 @@ import asyncio import logging import pathlib import shutil -from typing import Callable, Optional +from typing import Callable, List, Optional import aiocron from pyunifiprotect import ProtectApiClient @@ -167,6 +167,7 @@ class UnifiProtectBackup: retention (str): How long should event clips be backed up for. Format as per the `--max-age` argument of `rclone` (https://rclone.org/filtering/#max-age-don-t-transfer-any-file-older-than-this) + ignore_cameras (List[str]): List of camera IDs for which to not backup events verbose (int): How verbose to setup logging, see :func:`setup_logging` for details. _download_queue (asyncio.Queue): Queue of events that need to be backed up _unsub (Callable): Unsubscribe from the websocket callback @@ -180,6 +181,7 @@ class UnifiProtectBackup: verify_ssl: bool, rclone_destination: str, retention: str, + ignore_cameras: List[str], verbose: int, port: int = 443, ): @@ -197,6 +199,7 @@ class UnifiProtectBackup: retention (str): How long should event clips be backed up for. Format as per the `--max-age` argument of `rclone` (https://rclone.org/filtering/#max-age-don-t-transfer-any-file-older-than-this) + ignore_cameras (List[str]): List of camera IDs for which to not backup events verbose (int): How verbose to setup logging, see :func:`setup_logging` for details. """ setup_logging(verbose) @@ -212,6 +215,7 @@ class UnifiProtectBackup: verify_ssl=verify_ssl, subscribed_models={ModelType.EVENT}, ) + self.ignore_cameras = ignore_cameras self._download_queue: asyncio.Queue = asyncio.Queue() self._unsub: Callable[[], None] @@ -312,6 +316,8 @@ class UnifiProtectBackup: assert isinstance(msg.new_obj, Event) if msg.action != WSAction.UPDATE: return + if msg.new_obj.camera_id in self.ignore_cameras: + return if msg.new_obj.end is None: return if msg.new_obj.type not in {EventType.MOTION, EventType.SMART_DETECT}: