Few refinements, and added obsolete as default target tag

This commit is contained in:
Benjamin Harder
2025-10-19 18:32:40 +02:00
parent 8f1c0bb3df
commit 1858c3d8bf
5 changed files with 49 additions and 38 deletions

View File

@@ -227,6 +227,11 @@ services:
# As written above, these can also be set as Job Defaults so you don't have to specify them as granular as below.
# REMOVE_BAD_FILES: |
# keep_archives: True
# REMOVE_COMPLETED: |
# target_tags:
# - "Obsolete"
# target_categories:
# - "autobrr"
# REMOVE_FAILED_DOWNLOADS: True
# REMOVE_FAILED_IMPORTS: |
# message_patterns:
@@ -326,9 +331,9 @@ Decluttarr v2 is a major update with a cleaner config format and powerful new fe
- 🧼 **Bad files handling**: Added ability to not download potentially malicious files and files such as trailers / samples
- 🐌 **Adaptive slowness**: Slow downloads-removal can be dynamically turned on/off depending on overall bandwidth usage
- 📄 **Log files**: Logs can now be retrieved from a log file
- 📌 **Removal behavior**: Rather than removing downloads, they can now also be tagged for later removal (ie. to allow for seed targets to be reached first). This can be done separately for private and public trackers
- 🗑️ **Removal behavior**: Rather than removing downloads, they can now also be tagged for later removal (ie. to allow for seed targets to be reached first). This can be done separately for private and public trackers
- 📌 **Deletion detection**: If movies or tv shows get deleted (for instance via Plex), decluttarr can notice that and refresh the respective item
- ⛓️ **Being a good seeder**: A new job allows you to wait with the removal until your seed goals have been achieved
---
### ⚠️ Breaking Changes
@@ -407,7 +412,7 @@ Configures the general behavior of the application (across all features)
- Allows you to configure download client names that will be skipped by decluttarr
Note: The names provided here have to 100% match with how you have named your download clients in your *arr application(s)
- Type: List of strings
- Is Mandatory: No (Defaults to [], i.e. nothing ignored])
- Is Mandatory: No (Defaults to [], i.e. nothing ignored)
#### PRIVATE_TRACKER_HANDLING / PUBLIC_TRACKER_HANDLING
@@ -496,6 +501,30 @@ This is the interesting section. It defines which job you want decluttarr to run
- This may be helpful if you use a tool such as [unpackerr](https://github.com/Unpackerr/unpackerr) that can handle it
- However, you may also find that these packages may contain bad/malicious files (which will not removed by decluttarr)
#### REMOVE_COMPLETED
- Removes completed downloads from the download client's queue when they meet your selection criteria (tags and/or categories).
- What "completed" means:
- Downloads are considered completed when the seeding goals configured in your download client are met: either the ratio limit or the seeding time limit (per-torrent overrides or the global limits).
- Type: Boolean or Dict
- Permissible Values:
- If Bool: True, False
- If Dict:
- `target_tags`: List of tag names to match
- `target_categories`: List of category names to match
- Matching logic:
- Requires at least one of `target_tags` or `target_categories`. If neither is provided, the configured obsolete tag will be used as target_tag
- A torrent must be completed AND match (category IN `target_categories`) OR (has any tag IN `target_tags`).
- If both tags and categories are provided, the condition is OR between them.
- Is Mandatory: No (Defaults to False)
- Notes:
- This job currently only supports qBittorrent.
- Works great together with `obsolete_tag`: have other jobs tag torrents (e.g., "Obsolete") and let this job remove them once completed.
- Why not set "Remove torrent and its files" upon reaching seeding goals in download client?
- This setting is discouraged by *arrs and you will get warnings about it.
- You get more granular control.
- You can use this job to clean up after other apps like autobrr that do not have any torrent management features.
#### REMOVE_FAILED_DOWNLOADS
- Steers whether downloads that are marked as "failed" are removed from the queue
@@ -584,29 +613,6 @@ This is the interesting section. It defines which job you want decluttarr to run
- Permissible Values: True, False
- Is Mandatory: No (Defaults to False)
#### REMOVE_COMPLETED
- Removes completed downloads from the download client's queue when they meet your selection criteria (tags and/or categories).
- What "completed" means:
- Downloads are considered completed when the seeding goals configured in your download client are met: either the ratio limit or the seeding time limit (per-torrent overrides or the global limits).
- Type: Boolean or Dict
- Permissible Values:
- If Bool: True, False
- If Dict:
- `target_tags`: List of tag names to match
- `target_categories`: List of category names to match
- Matching logic:
- Requires at least one of `target_tags` or `target_categories`. If neither is provided, nothing will be removed.
- A torrent must be completed AND match (category IN `target_categories`) OR (has any tag IN `target_tags`).
- If both tags and categories are provided, the condition is OR between them.
- Is Mandatory: No (Defaults to False)
- Notes:
- This job currently only supports qBittorrent.
- Works great together with `obsolete_tag`: have other jobs tag torrents (e.g., "Obsolete") and let this job remove them once completed.
- Why not set "Remove torrent and its files" upon reaching seeding goals in download client?
- This setting is discouraged by *arrs and you will get warnings about it.
- You get more granular control.
- You can use this job to clean up after other apps like autobrr that do not have any torrent management features.
#### SEARCH_UNMET_CUTOFF

View File

@@ -17,6 +17,11 @@ job_defaults:
jobs:
remove_bad_files:
# keep_archives: true
remove_completed:
# target_tags:
# - "Obsolete"
# target_categories:
# - "autobrr"
remove_failed_downloads:
remove_failed_imports:
message_patterns:
@@ -42,11 +47,6 @@ jobs:
search_missing:
# min_days_between_searches: 7
# max_concurrent_searches: 3
remove_completed:
target_tags:
- "Obsolete"
# target_categories:
# - "autobrr"
instances:
sonarr:

View File

@@ -34,7 +34,7 @@ class RemoveCompleted(DownloadClientRemovalJob):
if not target_tags and not target_categories:
logger.debug(
"No target tags or categories specified for remove_completed job.",
"remove_completed.py/_get_items_to_remove: No target tags or categories specified for remove_completed job.",
)
return []
@@ -47,7 +47,7 @@ class RemoveCompleted(DownloadClientRemovalJob):
for item in items_to_remove:
logger.debug(
f"Found completed item to remove: {item.get('name', 'unknown')}",
f"remove_completed.py/_get_items_to_remove: Found completed item to remove: {item.get('name', 'unknown')}",
)
return items_to_remove

View File

@@ -13,6 +13,7 @@ class JobParams:
min_speed: int
max_concurrent_searches: int
min_days_between_searches: int
target_tags: list
def __init__(
self,
@@ -23,6 +24,7 @@ class JobParams:
min_speed=None,
max_concurrent_searches=None,
min_days_between_searches=None,
target_tags=None,
):
self.enabled = enabled
self.keep_archives = keep_archives
@@ -31,6 +33,7 @@ class JobParams:
self.min_speed = min_speed
self.max_concurrent_searches = max_concurrent_searches
self.min_days_between_searches = min_days_between_searches
self.target_tags = target_tags
# if not self.max_concurrent_searches <= 0:
# logger.warning(f"Job setting 'max_concurrent_searches' must be an integer greater 0. Found: {str(self.max_concurrent_searches)}. Using default: 3")
@@ -55,9 +58,11 @@ class JobDefaults:
min_days_between_searches: int = 7
min_speed: int = 100
message_patterns = ["*"]
target_tags = []
def __init__(self, config):
def __init__(self, config, settings):
job_defaults_config = config.get("job_defaults", {})
self.target_tags.append(settings.general.obsolete_tag)
self.max_strikes = job_defaults_config.get("max_strikes", self.max_strikes)
max_concurrent_searches = job_defaults_config.get("max_concurrent_searches")
if isinstance(max_concurrent_searches, int) and max_concurrent_searches > 0:
@@ -76,15 +81,15 @@ class JobDefaults:
class Jobs:
"""Represent all jobs explicitly."""
def __init__(self, config):
self.job_defaults = JobDefaults(config)
def __init__(self, config, settings):
self.job_defaults = JobDefaults(config, settings)
self._set_job_defaults()
self._set_job_configs(config)
del self.job_defaults
def _set_job_defaults(self):
self.remove_bad_files = JobParams(keep_archives=self.job_defaults.keep_archives)
self.remove_completed = JobParams()
self.remove_completed = JobParams(target_tags=self.job_defaults.target_tags)
self.remove_failed_downloads = JobParams()
self.remove_failed_imports = JobParams(
message_patterns=self.job_defaults.message_patterns,

View File

@@ -16,7 +16,7 @@ class Settings:
self.envs = Envs()
config = get_user_config(self)
self.general = General(config)
self.jobs = Jobs(config)
self.jobs = Jobs(config, self)
self.download_clients = DownloadClients(config, self)
self.instances = ArrInstances(config, self)
configure_logging(self)