Skip to content

Commit 246ec4d

Browse files
authored
Add option to set a tag instead of changing the category for unlinked downloads (#133)
1 parent 569eeae commit 246ec4d

File tree

11 files changed

+71
-15
lines changed

11 files changed

+71
-15
lines changed

code/Common/Configuration/DownloadCleaner/DownloadCleanerConfig.cs

+3
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ public sealed record DownloadCleanerConfig : IJobConfig, IIgnoredDownloadsConfig
2020
[ConfigurationKeyName("UNLINKED_TARGET_CATEGORY")]
2121
public string UnlinkedTargetCategory { get; init; } = "cleanuperr-unlinked";
2222

23+
[ConfigurationKeyName("UNLINKED_USE_TAG")]
24+
public bool UnlinkedUseTag { get; init; }
25+
2326
[ConfigurationKeyName("UNLINKED_IGNORED_ROOT_DIR")]
2427
public string UnlinkedIgnoredRootDir { get; init; } = string.Empty;
2528

code/Executable/appsettings.Development.json

+1
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@
5757
}
5858
],
5959
"UNLINKED_TARGET_CATEGORY": "cleanuperr-unlinked",
60+
"UNLINKED_USE_TAG": false,
6061
"UNLINKED_IGNORED_ROOT_DIR": "",
6162
"UNLINKED_CATEGORIES": [
6263
"tv-sonarr",

code/Executable/appsettings.json

+1
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
"DELETE_PRIVATE": false,
4848
"CATEGORIES": [],
4949
"UNLINKED_TARGET_CATEGORY": "cleanuperr-unlinked",
50+
"UNLINKED_USE_TAG": false,
5051
"UNLINKED_IGNORED_ROOT_DIR": "",
5152
"UNLINKED_CATEGORIES": [],
5253
"IGNORED_DOWNLOADS_PATH": ""

code/Infrastructure/Verticals/DownloadCleaner/DownloadCleaner.cs

+6-3
Original file line numberDiff line numberDiff line change
@@ -86,9 +86,12 @@ public override async Task ExecuteAsync()
8686
{
8787
if (!_hardLinkCategoryCreated)
8888
{
89-
_logger.LogDebug("creating category {cat}", _config.UnlinkedTargetCategory);
90-
91-
await _downloadService.CreateCategoryAsync(_config.UnlinkedTargetCategory);
89+
if (_downloadClientConfig.DownloadClient is Common.Enums.DownloadClient.QBittorrent && !_config.UnlinkedUseTag)
90+
{
91+
_logger.LogDebug("creating category {cat}", _config.UnlinkedTargetCategory);
92+
await _downloadService.CreateCategoryAsync(_config.UnlinkedTargetCategory);
93+
}
94+
9295
_hardLinkCategoryCreated = true;
9396
}
9497

code/Infrastructure/Verticals/DownloadClient/QBittorrent/QBitService.cs

+26-5
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,15 @@ IReadOnlyList<string> ignoredDownloads
251251
?.Cast<TorrentInfo>()
252252
.Where(x => !string.IsNullOrEmpty(x.Hash))
253253
.Where(x => categories.Any(cat => cat.Equals(x.Category, StringComparison.InvariantCultureIgnoreCase)))
254+
.Where(x =>
255+
{
256+
if (_downloadCleanerConfig.UnlinkedUseTag)
257+
{
258+
return !x.Tags.Any(tag => tag.Equals(_downloadCleanerConfig.UnlinkedTargetCategory, StringComparison.InvariantCultureIgnoreCase));
259+
}
260+
261+
return true;
262+
})
254263
.Cast<object>()
255264
.ToList();
256265

@@ -436,12 +445,18 @@ public override async Task ChangeCategoryForNoHardLinksAsync(List<object>? downl
436445
}
437446

438447
await _dryRunInterceptor.InterceptAsync(ChangeCategory, download.Hash, _downloadCleanerConfig.UnlinkedTargetCategory);
448+
449+
if (_downloadCleanerConfig.UnlinkedUseTag)
450+
{
451+
_logger.LogInformation("category changed for {name}", download.Name);
452+
download.Category = _downloadCleanerConfig.UnlinkedTargetCategory;
453+
}
454+
else
455+
{
456+
_logger.LogInformation("tag added for {name}", download.Name);
457+
}
439458

440-
_logger.LogInformation("category changed for {name}", download.Name);
441-
442-
await _notifier.NotifyCategoryChanged(download.Category, _downloadCleanerConfig.UnlinkedTargetCategory);
443-
444-
download.Category = _downloadCleanerConfig.UnlinkedTargetCategory;
459+
await _notifier.NotifyCategoryChanged(download.Category, _downloadCleanerConfig.UnlinkedTargetCategory, _downloadCleanerConfig.UnlinkedUseTag);
445460
}
446461
}
447462

@@ -467,6 +482,12 @@ protected virtual async Task SkipFile(string hash, int fileIndex)
467482
[DryRunSafeguard]
468483
protected virtual async Task ChangeCategory(string hash, string newCategory)
469484
{
485+
if (_downloadCleanerConfig.UnlinkedUseTag)
486+
{
487+
await _client.AddTorrentTagAsync([hash], newCategory);
488+
return;
489+
}
490+
470491
await _client.SetTorrentCategoryAsync([hash], newCategory);
471492
}
472493

code/Infrastructure/Verticals/Notifications/INotificationPublisher.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,5 @@ public interface INotificationPublisher
1010

1111
Task NotifyDownloadCleaned(double ratio, TimeSpan seedingTime, string categoryName, CleanReason reason);
1212

13-
Task NotifyCategoryChanged(string oldCategory, string newCategory);
13+
Task NotifyCategoryChanged(string oldCategory, string newCategory, bool isTag = false);
1414
}

code/Infrastructure/Verticals/Notifications/NotificationPublisher.cs

+13-5
Original file line numberDiff line numberDiff line change
@@ -123,21 +123,29 @@ public virtual async Task NotifyDownloadCleaned(double ratio, TimeSpan seedingTi
123123
}
124124
}
125125

126-
public virtual async Task NotifyCategoryChanged(string oldCategory, string newCategory)
126+
public virtual async Task NotifyCategoryChanged(string oldCategory, string newCategory, bool isTag = false)
127127
{
128128
CategoryChangedNotification notification = new()
129129
{
130-
Title = "Category changed",
130+
Title = isTag? "Tag added" : "Category changed",
131131
Description = ContextProvider.Get<string>("downloadName"),
132132
Fields =
133133
[
134-
new() { Title = "Hash", Text = ContextProvider.Get<string>("hash").ToLowerInvariant() },
135-
new() { Title = "Old category", Text = oldCategory },
136-
new() { Title = "New category", Text = newCategory }
134+
new() { Title = "Hash", Text = ContextProvider.Get<string>("hash").ToLowerInvariant() }
137135
],
138136
Level = NotificationLevel.Important
139137
};
140138

139+
if (isTag)
140+
{
141+
notification.Fields.Add(new() { Title = "Tag", Text = newCategory });
142+
}
143+
else
144+
{
145+
notification.Fields.Add(new() { Title = "Old category", Text = oldCategory });
146+
notification.Fields.Add(new() { Title = "New category", Text = newCategory });
147+
}
148+
141149
await NotifyInternal(notification);
142150
}
143151

code/test/docker-compose.yml

+4-1
Original file line numberDiff line numberDiff line change
@@ -221,15 +221,18 @@ services:
221221
- DOWNLOADCLEANER__ENABLED=true
222222
- DOWNLOADCLEANER__IGNORED_DOWNLOADS_PATH=/ignored
223223
- DOWNLOADCLEANER__DELETE_PRIVATE=false
224+
224225
- DOWNLOADCLEANER__CATEGORIES__0__NAME=tv-sonarr
225226
- DOWNLOADCLEANER__CATEGORIES__0__MAX_RATIO=-1
226227
- DOWNLOADCLEANER__CATEGORIES__0__MIN_SEED_TIME=0
227228
- DOWNLOADCLEANER__CATEGORIES__0__MAX_SEED_TIME=99999
228-
- DOWNLOADCLEANER__CATEGORIES__1__NAME=nohardlink
229+
- DOWNLOADCLEANER__CATEGORIES__1__NAME=cleanuperr-unlinked
229230
- DOWNLOADCLEANER__CATEGORIES__1__MAX_RATIO=-1
230231
- DOWNLOADCLEANER__CATEGORIES__1__MIN_SEED_TIME=0
231232
- DOWNLOADCLEANER__CATEGORIES__1__MAX_SEED_TIME=99999
233+
232234
- DOWNLOADCLEANER__UNLINKED_TARGET_CATEGORY=cleanuperr-unlinked
235+
- DOWNLOADCLEANER__UNLINKED_USE_TAG=false
233236
- DOWNLOADCLEANER__UNLINKED_IGNORED_ROOT_DIR=/downloads
234237
- DOWNLOADCLEANER__UNLINKED_CATEGORIES__0=tv-sonarr
235238
- DOWNLOADCLEANER__UNLINKED_CATEGORIES__1=radarr

docs/docs/configuration/examples/1_docker.mdx

+1
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ services:
9191
9292
# change category for downloads with no hardlinks
9393
- DOWNLOADCLEANER__UNLINKED_TARGET_CATEGORY=cleanuperr-unlinked
94+
- DOWNLOADCLEANER__UNLINKED_USE_TAG=false
9495
- DOWNLOADCLEANER__UNLINKED_IGNORED_ROOT_DIR=/downloads
9596
- DOWNLOADCLEANER__UNLINKED_CATEGORIES__0=tv-sonarr
9697
- DOWNLOADCLEANER__UNLINKED_CATEGORIES__1=radarr

docs/docs/configuration/examples/2_config-file.mdx

+1
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ import { Note } from '@site/src/components/Admonition';
7878
}
7979
],
8080
"UNLINKED_TARGET_CATEGORY": "cleanuperr-unlinked",
81+
"DOWNLOADCLEANER__UNLINKED_USE_TAG": false,
8182
"UNLINKED_IGNORED_ROOT_DIR": "/downloads",
8283
"UNLINKED_CATEGORIES": [
8384
"tv-sonarr",

docs/src/components/configuration/download-cleaner/DownloadCleanerHardlinksSettings.tsx

+14
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,20 @@ const settings: EnvVarProps[] = [
1111
defaultValue: "cleanuperr-unlinked",
1212
required: false,
1313
},
14+
{
15+
name: "DOWNLOADCLEANER__UNLINKED_USE_TAG",
16+
description: [
17+
"If set to true, a tag will be set instead of changing the category.",
18+
],
19+
type: "boolean",
20+
defaultValue: "false",
21+
required: false,
22+
acceptedValues: ["true", "false"],
23+
notes: [
24+
"Works only for qBittorrent.",
25+
],
26+
27+
},
1428
{
1529
name: "DOWNLOADCLEANER__UNLINKED_IGNORED_ROOT_DIR",
1630
description: [

0 commit comments

Comments
 (0)