diff --git a/app/config.py b/app/config.py index 7dcdb65..22ec9d5 100644 --- a/app/config.py +++ b/app/config.py @@ -83,10 +83,10 @@ def validate_settings_for_instance(self, library): for setting in library: if ( setting in SETTINGS_PER_INSTANCE - and instance_type in SETTINGS_PER_INSTANCE[setting] + and instance_type not in SETTINGS_PER_INSTANCE[setting] ): self.log_and_exit( - f"'{setting}' can only be set for {instance_type} instances" + f"'{setting}' can only be set for instances of type: {SETTINGS_PER_INSTANCE[setting]}" ) def validate_sonarr_and_radarr(self): @@ -157,6 +157,7 @@ def validate_libraries(self): self.validate_action_mode(library) self.validate_watch_status(library) self.validate_sort_configuration(library) + self.validate_settings_for_instance(library) return True diff --git a/app/constants.py b/app/constants.py index b4c084d..18375ac 100644 --- a/app/constants.py +++ b/app/constants.py @@ -10,6 +10,8 @@ "episodes", ] +VALID_INSTANCE_TYPES = ["radarr", "sonarr"] + # Valid sort orders VALID_SORT_ORDERS = ["asc", "desc"] @@ -17,9 +19,9 @@ VALID_ACTION_MODES = ["delete"] SETTINGS_PER_ACTION = { - "exclude_on_delete": ["delete"], + "add_list_exclusion_on_delete": ["delete"], } SETTINGS_PER_INSTANCE = { - "exclude_on_delete": ["radarr"], + "add_list_exclusion_on_delete": ["radarr"], } diff --git a/app/media_cleaner.py b/app/media_cleaner.py index 147e56e..e44cbf5 100644 --- a/app/media_cleaner.py +++ b/app/media_cleaner.py @@ -350,13 +350,13 @@ def delete_movie_if_allowed( radarr_instance.del_movie( radarr_movie["id"], delete_files=True, - add_exclusion=library.get("exclude_on_delete", False), + add_exclusion=library.get("add_list_exclusion_on_delete", False), ) else: radarr_instance.del_movie( radarr_movie["id"], delete_files=True, - add_exclusion=library.get("exclude_on_delete", False), + add_exclusion=library.get("add_list_exclusion_on_delete", False), ) def get_library_config(self, config, show): diff --git a/config/settings.yaml.example b/config/settings.yaml.example index 9e913d1..df41444 100644 --- a/config/settings.yaml.example +++ b/config/settings.yaml.example @@ -51,6 +51,7 @@ libraries: - name: "Movies" # The name of your Plex library radarr: "Radarr" # The Radarr instance to use for this library action_mode: "delete" # Actions can be "delete" + add_list_exclusion_on_delete: True # Prevents radarr from importing the deleted movie automatically again from a list last_watched_threshold: 30 # Time threshold in days. Media not watched in this period will be subject to actions watch_status: watched # Watched status of the media apply_last_watch_threshold_to_collections: true # If true, the last watched threshold will be applied to all other items in the collection diff --git a/docs/CONFIGURATION.md b/docs/CONFIGURATION.md index 819eea1..2050242 100644 --- a/docs/CONFIGURATION.md +++ b/docs/CONFIGURATION.md @@ -148,8 +148,9 @@ For each of your Plex libraries, specify how you want Deleterr to behave. Define | `series_type` | Only used if `sonarr` is set. It's required to filter for the show type, defaults to `standard`. | `"standard", "anime"` | `standard`, `anime`, `daily` | | `action_mode` | The action to perform on the media items. | `delete` | `delete` | | `last_watched_threshold` | Time threshold in days. Media watched in this period will not be actionable | `90` | - | +| `add_list_exclusion_on_delete` | Prevent Radarr/Sonarr from importing the media automatically again from a list. Currently only works with Radarr. | `true` | `true`,`false` | | `watch_status` | Watch status. Media not in this is state will not be actionable | `-` | `watched`, `unwatched` | -| `apply_last_watch_threshold_to_collections` | If set to `true`, the last watched threshold will be applied to all other items in the same collection. | `true` | `true` / `false` | +| `apply_last_watch_threshold_to_collections` | If set to `true`, the last watched threshold will be applied to all other items in the same collection. | `true` | `true`, `false` | | `added_at_threshold` | Media that added to Plex within this period (in days) will not be actionable | `180` | - | | `disk_size_threshold` | Library deletion will only happen when below this threshold. It requires a `path` (that the `sonarr` or `radarr` instance can access) and a size threshold | `path: /media/local`
`threshold: 1TB` | Valid units: [`B`, `KB`, `MB`, `GB`, `TB`, `PB`, `EB`] | | `max_actions_per_run` | Limit the number of actions performed per run. Defaults to `10` | `3000` | - | diff --git a/tests/test_config.py b/tests/test_config.py index c7ec8f2..5b5161b 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -1,7 +1,14 @@ import pytest from app.config import Config -from app.constants import VALID_ACTION_MODES, VALID_SORT_FIELDS, VALID_SORT_ORDERS +from app.constants import ( + SETTINGS_PER_ACTION, + SETTINGS_PER_INSTANCE, + VALID_ACTION_MODES, + VALID_INSTANCE_TYPES, + VALID_SORT_FIELDS, + VALID_SORT_ORDERS, +) # Test case for validate_libraries @@ -66,6 +73,44 @@ def test_invalid_sorting_options(library_config): validator.validate_libraries() +@pytest.mark.parametrize("action_mode", VALID_ACTION_MODES) +@pytest.mark.parametrize("setting", SETTINGS_PER_ACTION.keys()) +@pytest.mark.parametrize("instance", VALID_INSTANCE_TYPES) +def test_settings_per_instance_and_action_mode(action_mode, setting, instance): + library_config = { + "name": "TV Shows", + "action_mode": action_mode, + instance: "test", + setting: True, + } + + instance_config = [ + {"name": "test", "url": "http://localhost:8989", "api_key": "API_KEY"} + ] + + validator = Config({"libraries": [library_config], instance: instance_config}) + + if ( + # If the setting is valid for the action mode or the action mode is not specified + (setting in SETTINGS_PER_ACTION and action_mode in SETTINGS_PER_ACTION[setting]) + or (setting not in SETTINGS_PER_ACTION) + ) and ( + ( + # And if the setting is valid for the instance + setting in SETTINGS_PER_INSTANCE + and instance in SETTINGS_PER_INSTANCE[setting] + ) + # Or the instance is not specified + or (setting not in SETTINGS_PER_INSTANCE) + ): + # Then the validation should pass + assert validator.validate_libraries() == True + else: + # Otherwise, the validation should fail + with pytest.raises(SystemExit): + validator.validate_libraries() + + # Test case for validate_libraries @pytest.mark.parametrize("sort_field", VALID_SORT_FIELDS) @pytest.mark.parametrize("sort_order", VALID_SORT_ORDERS)