mirror of
https://github.com/Cleanuparr/Cleanuparr.git
synced 2026-01-03 03:18:20 -05:00
Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c82b5e11b1 | ||
|
|
c36d9eb9cf | ||
|
|
2f21603e8e | ||
|
|
586f9964b5 | ||
|
|
124670bb98 | ||
|
|
baf6a8c2f4 | ||
|
|
cd345afc54 |
15
README.md
15
README.md
@@ -10,13 +10,16 @@ Cleanuperr was created primarily to address malicious files, such as `*.lnk` or
|
||||
|
||||
> [!IMPORTANT]
|
||||
> **Features:**
|
||||
> - Strike system to mark stalled or downloads stuck in metadata downloading.
|
||||
> - Strike system to mark bad downloads.
|
||||
> - Remove and block downloads that reached a maximum number of strikes.
|
||||
> - Remove and block downloads that have a low download speed or high estimated completion time.
|
||||
> - Remove downloads blocked by qBittorrent or by Cleanuperr's **content blocker**.
|
||||
> - Trigger a search for downloads removed from the *arrs.
|
||||
> - Clean up downloads that have been seeding for a certain amount of time.
|
||||
> - Notify on strike or download removal.
|
||||
> - Remove and block downloads that are **failing to be imported** by the arrs. [configuration](https://flmorg.github.io/cleanuperr/docs/configuration/queue-cleaner/import-failed)
|
||||
> - Remove and block downloads that are **stalled** or in **metadata downloading** state. [configuration](https://flmorg.github.io/cleanuperr/docs/configuration/queue-cleaner/stalled)
|
||||
> - Remove and block downloads that have a **low download speed** or **high estimated completion time**. [configuration](https://flmorg.github.io/cleanuperr/docs/configuration/queue-cleaner/slow)
|
||||
> - Remove and block downloads blocked by qBittorrent or by Cleanuperr's **Content Blocker**. [configuration](https://flmorg.github.io/cleanuperr/docs/configuration/content-blocker/general)
|
||||
> - Automatically trigger a search for downloads removed from the arrs.
|
||||
> - Clean up downloads that have been **seeding** for a certain amount of time. [configuration](https://flmorg.github.io/cleanuperr/docs/configuration/download-cleaner/seeding)
|
||||
> - Remove downloads that are **orphaned**/have no **hardlinks**/are not referenced by the arrs anymore (with [cross-seed](https://www.cross-seed.org/) support). [configuration](https://flmorg.github.io/cleanuperr/docs/configuration/download-cleaner/hardlinks)
|
||||
> - Notify on strike or download removal. [configuration](https://flmorg.github.io/cleanuperr/docs/category/notifications)
|
||||
> - Ignore certain torrent hashes, categories, tags or trackers from being processed by Cleanuperr.
|
||||
|
||||
Cleanuperr supports both qBittorrent's built-in exclusion features and its own blocklist-based system. Binaries for all platforms are provided, along with Docker images for easy deployment.
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Common.Configuration.ContentBlocker;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
|
||||
namespace Common.Configuration.Arr;
|
||||
|
||||
@@ -7,6 +8,9 @@ public abstract record ArrConfig
|
||||
public required bool Enabled { get; init; }
|
||||
|
||||
public Block Block { get; init; } = new();
|
||||
|
||||
[ConfigurationKeyName("IMPORT_FAILED_MAX_STRIKES")]
|
||||
public short ImportFailedMaxStrikes { get; init; } = -1;
|
||||
|
||||
public required List<ArrInstance> Instances { get; init; }
|
||||
}
|
||||
|
||||
12
code/Common/Configuration/General/SearchConfig.cs
Normal file
12
code/Common/Configuration/General/SearchConfig.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
using Microsoft.Extensions.Configuration;
|
||||
|
||||
namespace Common.Configuration.General;
|
||||
|
||||
public sealed record SearchConfig
|
||||
{
|
||||
[ConfigurationKeyName("SEARCH_ENABLED")]
|
||||
public bool SearchEnabled { get; init; } = true;
|
||||
|
||||
[ConfigurationKeyName("SEARCH_DELAY")]
|
||||
public ushort SearchDelay { get; init; } = 30;
|
||||
}
|
||||
@@ -13,6 +13,7 @@ public static class ConfigurationDI
|
||||
public static IServiceCollection AddConfiguration(this IServiceCollection services, IConfiguration configuration) =>
|
||||
services
|
||||
.Configure<DryRunConfig>(configuration)
|
||||
.Configure<SearchConfig>(configuration)
|
||||
.Configure<QueueCleanerConfig>(configuration.GetSection(QueueCleanerConfig.SectionName))
|
||||
.Configure<ContentBlockerConfig>(configuration.GetSection(ContentBlockerConfig.SectionName))
|
||||
.Configure<DownloadCleanerConfig>(configuration.GetSection(DownloadCleanerConfig.SectionName))
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
using System.Net;
|
||||
using Common.Configuration.General;
|
||||
using Common.Helpers;
|
||||
using Domain.Models.Arr;
|
||||
using Infrastructure.Services;
|
||||
using Infrastructure.Verticals.DownloadClient.Deluge;
|
||||
using Infrastructure.Verticals.DownloadRemover.Consumers;
|
||||
using Infrastructure.Verticals.Notifications.Consumers;
|
||||
using Infrastructure.Verticals.Notifications.Models;
|
||||
using MassTransit;
|
||||
using MassTransit.Configuration;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Polly;
|
||||
using Polly.Extensions.Http;
|
||||
@@ -27,6 +30,9 @@ public static class MainDI
|
||||
.AddNotifications(configuration)
|
||||
.AddMassTransit(config =>
|
||||
{
|
||||
config.AddConsumer<DownloadRemoverConsumer<SearchItem>>();
|
||||
config.AddConsumer<DownloadRemoverConsumer<SonarrSearchItem>>();
|
||||
|
||||
config.AddConsumer<NotificationConsumer<FailedImportStrikeNotification>>();
|
||||
config.AddConsumer<NotificationConsumer<StalledStrikeNotification>>();
|
||||
config.AddConsumer<NotificationConsumer<SlowStrikeNotification>>();
|
||||
@@ -36,6 +42,14 @@ public static class MainDI
|
||||
|
||||
config.UsingInMemory((context, cfg) =>
|
||||
{
|
||||
cfg.ReceiveEndpoint("download-remover-queue", e =>
|
||||
{
|
||||
e.ConfigureConsumer<DownloadRemoverConsumer<SearchItem>>(context);
|
||||
e.ConfigureConsumer<DownloadRemoverConsumer<SonarrSearchItem>>(context);
|
||||
e.ConcurrentMessageLimit = 1;
|
||||
e.PrefetchCount = 1;
|
||||
});
|
||||
|
||||
cfg.ReceiveEndpoint("notification-queue", e =>
|
||||
{
|
||||
e.ConfigureConsumer<NotificationConsumer<FailedImportStrikeNotification>>(context);
|
||||
|
||||
@@ -11,6 +11,8 @@ using Infrastructure.Verticals.DownloadClient;
|
||||
using Infrastructure.Verticals.DownloadClient.Deluge;
|
||||
using Infrastructure.Verticals.DownloadClient.QBittorrent;
|
||||
using Infrastructure.Verticals.DownloadClient.Transmission;
|
||||
using Infrastructure.Verticals.DownloadRemover;
|
||||
using Infrastructure.Verticals.DownloadRemover.Interfaces;
|
||||
using Infrastructure.Verticals.Files;
|
||||
using Infrastructure.Verticals.ItemStriker;
|
||||
using Infrastructure.Verticals.QueueCleaner;
|
||||
@@ -26,9 +28,11 @@ public static class ServicesDI
|
||||
.AddTransient<SonarrClient>()
|
||||
.AddTransient<RadarrClient>()
|
||||
.AddTransient<LidarrClient>()
|
||||
.AddTransient<ArrClientFactory>()
|
||||
.AddTransient<QueueCleaner>()
|
||||
.AddTransient<ContentBlocker>()
|
||||
.AddTransient<DownloadCleaner>()
|
||||
.AddTransient<IQueueItemRemover, QueueItemRemover>()
|
||||
.AddTransient<IFilenameEvaluator, FilenameEvaluator>()
|
||||
.AddTransient<IHardLinkFileService, HardLinkFileService>()
|
||||
.AddTransient<UnixHardLinkFileService>()
|
||||
|
||||
@@ -11,6 +11,8 @@
|
||||
"Path": ""
|
||||
}
|
||||
},
|
||||
"SEARCH_ENABLED": true,
|
||||
"SEARCH_DELAY": 5,
|
||||
"Triggers": {
|
||||
"QueueCleaner": "0/10 * * * * ?",
|
||||
"ContentBlocker": "0/10 * * * * ?",
|
||||
@@ -85,6 +87,7 @@
|
||||
},
|
||||
"Sonarr": {
|
||||
"Enabled": true,
|
||||
"IMPORT_FAILED_MAX_STRIKES": -1,
|
||||
"SearchType": "Episode",
|
||||
"Block": {
|
||||
"Type": "blacklist",
|
||||
@@ -99,6 +102,7 @@
|
||||
},
|
||||
"Radarr": {
|
||||
"Enabled": true,
|
||||
"IMPORT_FAILED_MAX_STRIKES": -1,
|
||||
"Block": {
|
||||
"Type": "blacklist",
|
||||
"Path": "https://raw.githubusercontent.com/flmorg/cleanuperr/refs/heads/main/blacklist"
|
||||
@@ -112,6 +116,7 @@
|
||||
},
|
||||
"Lidarr": {
|
||||
"Enabled": true,
|
||||
"IMPORT_FAILED_MAX_STRIKES": -1,
|
||||
"Block": {
|
||||
"Type": "blacklist",
|
||||
"Path": "https://raw.githubusercontent.com/flmorg/cleanuperr/refs/heads/main/blacklist"
|
||||
|
||||
@@ -11,6 +11,8 @@
|
||||
"Path": ""
|
||||
}
|
||||
},
|
||||
"SEARCH_ENABLED": true,
|
||||
"SEARCH_DELAY": 30,
|
||||
"Triggers": {
|
||||
"QueueCleaner": "0 0/5 * * * ?",
|
||||
"ContentBlocker": "0 0/5 * * * ?",
|
||||
@@ -72,6 +74,7 @@
|
||||
},
|
||||
"Sonarr": {
|
||||
"Enabled": false,
|
||||
"IMPORT_FAILED_MAX_STRIKES": -1,
|
||||
"SearchType": "Episode",
|
||||
"Block": {
|
||||
"Type": "blacklist",
|
||||
@@ -86,6 +89,7 @@
|
||||
},
|
||||
"Radarr": {
|
||||
"Enabled": false,
|
||||
"IMPORT_FAILED_MAX_STRIKES": -1,
|
||||
"Block": {
|
||||
"Type": "blacklist",
|
||||
"Path": ""
|
||||
@@ -99,6 +103,7 @@
|
||||
},
|
||||
"Lidarr": {
|
||||
"Enabled": false,
|
||||
"IMPORT_FAILED_MAX_STRIKES": -1,
|
||||
"Block": {
|
||||
"Type": "blacklist",
|
||||
"Path": ""
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using Domain.Models.Deluge.Response;
|
||||
using Infrastructure.Helpers;
|
||||
using Infrastructure.Services;
|
||||
|
||||
namespace Infrastructure.Extensions;
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Infrastructure.Helpers;
|
||||
using Infrastructure.Services;
|
||||
using QBittorrent.Client;
|
||||
|
||||
namespace Infrastructure.Extensions;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Infrastructure.Helpers;
|
||||
using Infrastructure.Services;
|
||||
using Transmission.API.RPC.Entity;
|
||||
|
||||
namespace Infrastructure.Extensions;
|
||||
|
||||
@@ -13,4 +13,6 @@ public static class CacheKeys
|
||||
public static string StrikeItem(string hash, StrikeType strikeType) => $"item_{hash}_{strikeType.ToString()}";
|
||||
|
||||
public static string IgnoredDownloads(string name) => $"{name}_ignored";
|
||||
|
||||
public static string DownloadMarkedForRemoval(string hash, Uri url) => $"remove_{hash.ToLowerInvariant()}_{url}";
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace Infrastructure.Helpers;
|
||||
namespace Infrastructure.Services;
|
||||
|
||||
public static class UriService
|
||||
{
|
||||
@@ -73,7 +73,7 @@ public abstract class ArrClient : IArrClient
|
||||
return queueResponse;
|
||||
}
|
||||
|
||||
public virtual async Task<bool> ShouldRemoveFromQueue(InstanceType instanceType, QueueRecord record, bool isPrivateDownload)
|
||||
public virtual async Task<bool> ShouldRemoveFromQueue(InstanceType instanceType, QueueRecord record, bool isPrivateDownload, short arrMaxStrikes)
|
||||
{
|
||||
if (_queueCleanerConfig.ImportFailedIgnorePrivate && isPrivateDownload)
|
||||
{
|
||||
@@ -102,11 +102,19 @@ public abstract class ArrClient : IArrClient
|
||||
_logger.LogDebug("skip failed import check | contains ignored pattern | {name}", record.Title);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (arrMaxStrikes is 0)
|
||||
{
|
||||
_logger.LogDebug("skip failed import check | arr max strikes is 0 | {name}", record.Title);
|
||||
return false;
|
||||
}
|
||||
|
||||
ushort maxStrikes = arrMaxStrikes > 0 ? (ushort)arrMaxStrikes : _queueCleanerConfig.ImportFailedMaxStrikes;
|
||||
|
||||
return await _striker.StrikeAndCheckLimit(
|
||||
record.DownloadId,
|
||||
record.Title,
|
||||
_queueCleanerConfig.ImportFailedMaxStrikes,
|
||||
maxStrikes,
|
||||
StrikeType.ImportFailed
|
||||
);
|
||||
}
|
||||
@@ -149,7 +157,7 @@ public abstract class ArrClient : IArrClient
|
||||
}
|
||||
}
|
||||
|
||||
public abstract Task RefreshItemsAsync(ArrInstance arrInstance, HashSet<SearchItem>? items);
|
||||
public abstract Task SearchItemsAsync(ArrInstance arrInstance, HashSet<SearchItem>? items);
|
||||
|
||||
public virtual bool IsRecordValid(QueueRecord record)
|
||||
{
|
||||
|
||||
31
code/Infrastructure/Verticals/Arr/ArrClientFactory.cs
Normal file
31
code/Infrastructure/Verticals/Arr/ArrClientFactory.cs
Normal file
@@ -0,0 +1,31 @@
|
||||
using Domain.Enums;
|
||||
using Infrastructure.Verticals.Arr.Interfaces;
|
||||
|
||||
namespace Infrastructure.Verticals.Arr;
|
||||
|
||||
public sealed class ArrClientFactory
|
||||
{
|
||||
private readonly ISonarrClient _sonarrClient;
|
||||
private readonly IRadarrClient _radarrClient;
|
||||
private readonly ILidarrClient _lidarrClient;
|
||||
|
||||
public ArrClientFactory(
|
||||
SonarrClient sonarrClient,
|
||||
RadarrClient radarrClient,
|
||||
LidarrClient lidarrClient
|
||||
)
|
||||
{
|
||||
_sonarrClient = sonarrClient;
|
||||
_radarrClient = radarrClient;
|
||||
_lidarrClient = lidarrClient;
|
||||
}
|
||||
|
||||
public IArrClient GetClient(InstanceType type) =>
|
||||
type switch
|
||||
{
|
||||
InstanceType.Sonarr => _sonarrClient,
|
||||
InstanceType.Radarr => _radarrClient,
|
||||
InstanceType.Lidarr => _lidarrClient,
|
||||
_ => throw new NotImplementedException($"instance type {type} is not yet supported")
|
||||
};
|
||||
}
|
||||
@@ -9,11 +9,11 @@ public interface IArrClient
|
||||
{
|
||||
Task<QueueListResponse> GetQueueItemsAsync(ArrInstance arrInstance, int page);
|
||||
|
||||
Task<bool> ShouldRemoveFromQueue(InstanceType instanceType, QueueRecord record, bool isPrivateDownload);
|
||||
Task<bool> ShouldRemoveFromQueue(InstanceType instanceType, QueueRecord record, bool isPrivateDownload, short arrMaxStrikes);
|
||||
|
||||
Task DeleteQueueItemAsync(ArrInstance arrInstance, QueueRecord record, bool removeFromClient, DeleteReason deleteReason);
|
||||
|
||||
Task RefreshItemsAsync(ArrInstance arrInstance, HashSet<SearchItem>? items);
|
||||
Task SearchItemsAsync(ArrInstance arrInstance, HashSet<SearchItem>? items);
|
||||
|
||||
bool IsRecordValid(QueueRecord record);
|
||||
}
|
||||
@@ -50,7 +50,7 @@ public class LidarrClient : ArrClient, ILidarrClient
|
||||
return query;
|
||||
}
|
||||
|
||||
public override async Task RefreshItemsAsync(ArrInstance arrInstance, HashSet<SearchItem>? items)
|
||||
public override async Task SearchItemsAsync(ArrInstance arrInstance, HashSet<SearchItem>? items)
|
||||
{
|
||||
if (items?.Count is null or 0)
|
||||
{
|
||||
|
||||
@@ -50,7 +50,7 @@ public class RadarrClient : ArrClient, IRadarrClient
|
||||
return query;
|
||||
}
|
||||
|
||||
public override async Task RefreshItemsAsync(ArrInstance arrInstance, HashSet<SearchItem>? items)
|
||||
public override async Task SearchItemsAsync(ArrInstance arrInstance, HashSet<SearchItem>? items)
|
||||
{
|
||||
if (items?.Count is null or 0)
|
||||
{
|
||||
|
||||
@@ -51,7 +51,7 @@ public class SonarrClient : ArrClient, ISonarrClient
|
||||
return query;
|
||||
}
|
||||
|
||||
public override async Task RefreshItemsAsync(ArrInstance arrInstance, HashSet<SearchItem>? items)
|
||||
public override async Task SearchItemsAsync(ArrInstance arrInstance, HashSet<SearchItem>? items)
|
||||
{
|
||||
if (items?.Count is null or 0)
|
||||
{
|
||||
|
||||
@@ -6,16 +6,20 @@ using Common.Configuration.DownloadClient;
|
||||
using Domain.Enums;
|
||||
using Domain.Models.Arr;
|
||||
using Domain.Models.Arr.Queue;
|
||||
using Infrastructure.Helpers;
|
||||
using Infrastructure.Providers;
|
||||
using Infrastructure.Verticals.Arr;
|
||||
using Infrastructure.Verticals.Arr.Interfaces;
|
||||
using Infrastructure.Verticals.Context;
|
||||
using Infrastructure.Verticals.DownloadClient;
|
||||
using Infrastructure.Verticals.DownloadRemover.Models;
|
||||
using Infrastructure.Verticals.Jobs;
|
||||
using Infrastructure.Verticals.Notifications;
|
||||
using MassTransit;
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Serilog.Context;
|
||||
using LogContext = Serilog.Context.LogContext;
|
||||
|
||||
namespace Infrastructure.Verticals.ContentBlocker;
|
||||
|
||||
@@ -32,9 +36,9 @@ public sealed class ContentBlocker : GenericHandler
|
||||
IOptions<SonarrConfig> sonarrConfig,
|
||||
IOptions<RadarrConfig> radarrConfig,
|
||||
IOptions<LidarrConfig> lidarrConfig,
|
||||
SonarrClient sonarrClient,
|
||||
RadarrClient radarrClient,
|
||||
LidarrClient lidarrClient,
|
||||
IMemoryCache cache,
|
||||
IBus messageBus,
|
||||
ArrClientFactory arrClientFactory,
|
||||
ArrQueueIterator arrArrQueueIterator,
|
||||
BlocklistProvider blocklistProvider,
|
||||
DownloadServiceFactory downloadServiceFactory,
|
||||
@@ -43,8 +47,7 @@ public sealed class ContentBlocker : GenericHandler
|
||||
) : base(
|
||||
logger, downloadClientConfig,
|
||||
sonarrConfig, radarrConfig, lidarrConfig,
|
||||
sonarrClient, radarrClient, lidarrClient,
|
||||
arrArrQueueIterator, downloadServiceFactory,
|
||||
cache, messageBus, arrClientFactory, arrArrQueueIterator, downloadServiceFactory,
|
||||
notifier
|
||||
)
|
||||
{
|
||||
@@ -75,21 +78,16 @@ public sealed class ContentBlocker : GenericHandler
|
||||
await base.ExecuteAsync();
|
||||
}
|
||||
|
||||
protected override async Task ProcessInstanceAsync(ArrInstance instance, InstanceType instanceType)
|
||||
protected override async Task ProcessInstanceAsync(ArrInstance instance, InstanceType instanceType, ArrConfig config)
|
||||
{
|
||||
IReadOnlyList<string> ignoredDownloads = await _ignoredDownloadsProvider.GetIgnoredDownloads();
|
||||
|
||||
using var _ = LogContext.PushProperty("InstanceName", instanceType.ToString());
|
||||
|
||||
HashSet<SearchItem> itemsToBeRefreshed = [];
|
||||
IArrClient arrClient = GetClient(instanceType);
|
||||
IArrClient arrClient = _arrClientFactory.GetClient(instanceType);
|
||||
BlocklistType blocklistType = _blocklistProvider.GetBlocklistType(instanceType);
|
||||
ConcurrentBag<string> patterns = _blocklistProvider.GetPatterns(instanceType);
|
||||
ConcurrentBag<Regex> regexes = _blocklistProvider.GetRegexes(instanceType);
|
||||
|
||||
// push to context
|
||||
ContextProvider.Set(nameof(ArrInstance) + nameof(ArrInstance.Url), instance.Url);
|
||||
ContextProvider.Set(nameof(InstanceType), instanceType);
|
||||
|
||||
await _arrArrQueueIterator.Iterate(arrClient, instance, async items =>
|
||||
{
|
||||
@@ -117,9 +115,14 @@ public sealed class ContentBlocker : GenericHandler
|
||||
_logger.LogInformation("skip | {title} | ignored", record.Title);
|
||||
continue;
|
||||
}
|
||||
|
||||
string downloadRemovalKey = CacheKeys.DownloadMarkedForRemoval(record.DownloadId, instance.Url);
|
||||
|
||||
// push record to context
|
||||
ContextProvider.Set(nameof(QueueRecord), record);
|
||||
if (_cache.TryGetValue(downloadRemovalKey, out bool _))
|
||||
{
|
||||
_logger.LogDebug("skip | already marked for removal | {title}", record.Title);
|
||||
continue;
|
||||
}
|
||||
|
||||
_logger.LogDebug("searching unwanted files for {title}", record.Title);
|
||||
|
||||
@@ -133,8 +136,6 @@ public sealed class ContentBlocker : GenericHandler
|
||||
|
||||
_logger.LogDebug("all files are marked as unwanted | {hash}", record.Title);
|
||||
|
||||
itemsToBeRefreshed.Add(GetRecordSearchItem(instanceType, record, group.Count() > 1));
|
||||
|
||||
bool removeFromClient = true;
|
||||
|
||||
if (result.IsPrivate && !_config.DeletePrivate)
|
||||
@@ -142,11 +143,16 @@ public sealed class ContentBlocker : GenericHandler
|
||||
removeFromClient = false;
|
||||
}
|
||||
|
||||
await arrClient.DeleteQueueItemAsync(instance, record, removeFromClient, DeleteReason.AllFilesBlocked);
|
||||
await _notifier.NotifyQueueItemDeleted(removeFromClient, DeleteReason.AllFilesBlocked);
|
||||
await PublishQueueItemRemoveRequest(
|
||||
downloadRemovalKey,
|
||||
instanceType,
|
||||
instance,
|
||||
record,
|
||||
group.Count() > 1,
|
||||
removeFromClient,
|
||||
DeleteReason.AllFilesBlocked
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
await arrClient.RefreshItemsAsync(instance, itemsToBeRefreshed);
|
||||
}
|
||||
}
|
||||
@@ -9,9 +9,11 @@ using Infrastructure.Verticals.Arr.Interfaces;
|
||||
using Infrastructure.Verticals.DownloadClient;
|
||||
using Infrastructure.Verticals.Jobs;
|
||||
using Infrastructure.Verticals.Notifications;
|
||||
using MassTransit;
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Serilog.Context;
|
||||
using LogContext = Serilog.Context.LogContext;
|
||||
|
||||
namespace Infrastructure.Verticals.DownloadCleaner;
|
||||
|
||||
@@ -30,9 +32,9 @@ public sealed class DownloadCleaner : GenericHandler
|
||||
IOptions<SonarrConfig> sonarrConfig,
|
||||
IOptions<RadarrConfig> radarrConfig,
|
||||
IOptions<LidarrConfig> lidarrConfig,
|
||||
SonarrClient sonarrClient,
|
||||
RadarrClient radarrClient,
|
||||
LidarrClient lidarrClient,
|
||||
IMemoryCache cache,
|
||||
IBus messageBus,
|
||||
ArrClientFactory arrClientFactory,
|
||||
ArrQueueIterator arrArrQueueIterator,
|
||||
DownloadServiceFactory downloadServiceFactory,
|
||||
INotificationPublisher notifier,
|
||||
@@ -40,8 +42,7 @@ public sealed class DownloadCleaner : GenericHandler
|
||||
) : base(
|
||||
logger, downloadClientConfig,
|
||||
sonarrConfig, radarrConfig, lidarrConfig,
|
||||
sonarrClient, radarrClient, lidarrClient,
|
||||
arrArrQueueIterator, downloadServiceFactory,
|
||||
cache, messageBus, arrClientFactory, arrArrQueueIterator, downloadServiceFactory,
|
||||
notifier
|
||||
)
|
||||
{
|
||||
@@ -127,11 +128,11 @@ public sealed class DownloadCleaner : GenericHandler
|
||||
_logger.LogTrace("finished cleaning downloads");
|
||||
}
|
||||
|
||||
protected override async Task ProcessInstanceAsync(ArrInstance instance, InstanceType instanceType)
|
||||
protected override async Task ProcessInstanceAsync(ArrInstance instance, InstanceType instanceType, ArrConfig config)
|
||||
{
|
||||
using var _ = LogContext.PushProperty("InstanceName", instanceType.ToString());
|
||||
|
||||
IArrClient arrClient = GetClient(instanceType);
|
||||
IArrClient arrClient = _arrClientFactory.GetClient(instanceType);
|
||||
|
||||
await _arrArrQueueIterator.Iterate(arrClient, instance, async items =>
|
||||
{
|
||||
|
||||
@@ -448,12 +448,12 @@ public class QBitService : DownloadService, IQBitService
|
||||
|
||||
if (_downloadCleanerConfig.UnlinkedUseTag)
|
||||
{
|
||||
_logger.LogInformation("category changed for {name}", download.Name);
|
||||
download.Category = _downloadCleanerConfig.UnlinkedTargetCategory;
|
||||
_logger.LogInformation("tag added for {name}", download.Name);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.LogInformation("tag added for {name}", download.Name);
|
||||
_logger.LogInformation("category changed for {name}", download.Name);
|
||||
download.Category = _downloadCleanerConfig.UnlinkedTargetCategory;
|
||||
}
|
||||
|
||||
await _notifier.NotifyCategoryChanged(download.Category, _downloadCleanerConfig.UnlinkedTargetCategory, _downloadCleanerConfig.UnlinkedUseTag);
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
using Domain.Models.Arr;
|
||||
using Infrastructure.Verticals.DownloadRemover.Interfaces;
|
||||
using Infrastructure.Verticals.DownloadRemover.Models;
|
||||
using MassTransit;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Infrastructure.Verticals.DownloadRemover.Consumers;
|
||||
|
||||
public class DownloadRemoverConsumer<T> : IConsumer<QueueItemRemoveRequest<T>>
|
||||
where T : SearchItem
|
||||
{
|
||||
private readonly ILogger<DownloadRemoverConsumer<T>> _logger;
|
||||
private readonly IQueueItemRemover _queueItemRemover;
|
||||
|
||||
public DownloadRemoverConsumer(
|
||||
ILogger<DownloadRemoverConsumer<T>> logger,
|
||||
IQueueItemRemover queueItemRemover
|
||||
)
|
||||
{
|
||||
_logger = logger;
|
||||
_queueItemRemover = queueItemRemover;
|
||||
}
|
||||
|
||||
public async Task Consume(ConsumeContext<QueueItemRemoveRequest<T>> context)
|
||||
{
|
||||
try
|
||||
{
|
||||
await _queueItemRemover.RemoveQueueItemAsync(context.Message);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
_logger.LogError(exception,
|
||||
"failed to remove queue item| {title} | {url}",
|
||||
context.Message.Record.Title,
|
||||
context.Message.Instance.Url
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
using Domain.Models.Arr;
|
||||
using Infrastructure.Verticals.DownloadRemover.Models;
|
||||
|
||||
namespace Infrastructure.Verticals.DownloadRemover.Interfaces;
|
||||
|
||||
public interface IQueueItemRemover
|
||||
{
|
||||
Task RemoveQueueItemAsync<T>(QueueItemRemoveRequest<T> request) where T : SearchItem;
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
using Common.Configuration.Arr;
|
||||
using Domain.Enums;
|
||||
using Domain.Models.Arr;
|
||||
using Domain.Models.Arr.Queue;
|
||||
|
||||
namespace Infrastructure.Verticals.DownloadRemover.Models;
|
||||
|
||||
public sealed record QueueItemRemoveRequest<T>
|
||||
where T : SearchItem
|
||||
{
|
||||
public required InstanceType InstanceType { get; init; }
|
||||
|
||||
public required ArrInstance Instance { get; init; }
|
||||
|
||||
public required T SearchItem { get; init; }
|
||||
|
||||
public required QueueRecord Record { get; init; }
|
||||
|
||||
public required bool RemoveFromClient { get; init; }
|
||||
|
||||
public required DeleteReason DeleteReason { get; init; }
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
using Common.Configuration.Arr;
|
||||
using Common.Configuration.General;
|
||||
using Domain.Enums;
|
||||
using Domain.Models.Arr;
|
||||
using Domain.Models.Arr.Queue;
|
||||
using Infrastructure.Helpers;
|
||||
using Infrastructure.Verticals.Arr;
|
||||
using Infrastructure.Verticals.Context;
|
||||
using Infrastructure.Verticals.DownloadRemover.Interfaces;
|
||||
using Infrastructure.Verticals.DownloadRemover.Models;
|
||||
using Infrastructure.Verticals.Notifications;
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace Infrastructure.Verticals.DownloadRemover;
|
||||
|
||||
public sealed class QueueItemRemover : IQueueItemRemover
|
||||
{
|
||||
private readonly SearchConfig _searchConfig;
|
||||
private readonly IMemoryCache _cache;
|
||||
private readonly ArrClientFactory _arrClientFactory;
|
||||
private readonly INotificationPublisher _notifier;
|
||||
|
||||
public QueueItemRemover(
|
||||
IOptions<SearchConfig> searchConfig,
|
||||
IMemoryCache cache,
|
||||
ArrClientFactory arrClientFactory,
|
||||
INotificationPublisher notifier
|
||||
)
|
||||
{
|
||||
_searchConfig = searchConfig.Value;
|
||||
_cache = cache;
|
||||
_arrClientFactory = arrClientFactory;
|
||||
_notifier = notifier;
|
||||
}
|
||||
|
||||
public async Task RemoveQueueItemAsync<T>(QueueItemRemoveRequest<T> request)
|
||||
where T : SearchItem
|
||||
{
|
||||
try
|
||||
{
|
||||
var arrClient = _arrClientFactory.GetClient(request.InstanceType);
|
||||
await arrClient.DeleteQueueItemAsync(request.Instance, request.Record, request.RemoveFromClient, request.DeleteReason);
|
||||
|
||||
// push to context
|
||||
ContextProvider.Set(nameof(QueueRecord), request.Record);
|
||||
ContextProvider.Set(nameof(ArrInstance) + nameof(ArrInstance.Url), request.Instance.Url);
|
||||
ContextProvider.Set(nameof(InstanceType), request.InstanceType);
|
||||
await _notifier.NotifyQueueItemDeleted(request.RemoveFromClient, request.DeleteReason);
|
||||
|
||||
if (!_searchConfig.SearchEnabled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
await arrClient.SearchItemsAsync(request.Instance, [request.SearchItem]);
|
||||
|
||||
// prevent tracker spamming
|
||||
await Task.Delay(TimeSpan.FromSeconds(_searchConfig.SearchDelay));
|
||||
}
|
||||
finally
|
||||
{
|
||||
_cache.Remove(CacheKeys.DownloadMarkedForRemoval(request.Record.DownloadId, request.Instance.Url));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,9 +4,11 @@ using Domain.Enums;
|
||||
using Domain.Models.Arr;
|
||||
using Domain.Models.Arr.Queue;
|
||||
using Infrastructure.Verticals.Arr;
|
||||
using Infrastructure.Verticals.Arr.Interfaces;
|
||||
using Infrastructure.Verticals.DownloadClient;
|
||||
using Infrastructure.Verticals.DownloadRemover.Models;
|
||||
using Infrastructure.Verticals.Notifications;
|
||||
using MassTransit;
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
@@ -19,9 +21,9 @@ public abstract class GenericHandler : IHandler, IDisposable
|
||||
protected readonly SonarrConfig _sonarrConfig;
|
||||
protected readonly RadarrConfig _radarrConfig;
|
||||
protected readonly LidarrConfig _lidarrConfig;
|
||||
protected readonly ISonarrClient _sonarrClient;
|
||||
protected readonly IRadarrClient _radarrClient;
|
||||
protected readonly ILidarrClient _lidarrClient;
|
||||
protected readonly IMemoryCache _cache;
|
||||
protected readonly IBus _messageBus;
|
||||
protected readonly ArrClientFactory _arrClientFactory;
|
||||
protected readonly ArrQueueIterator _arrArrQueueIterator;
|
||||
protected readonly IDownloadService _downloadService;
|
||||
protected readonly INotificationPublisher _notifier;
|
||||
@@ -32,9 +34,9 @@ public abstract class GenericHandler : IHandler, IDisposable
|
||||
IOptions<SonarrConfig> sonarrConfig,
|
||||
IOptions<RadarrConfig> radarrConfig,
|
||||
IOptions<LidarrConfig> lidarrConfig,
|
||||
ISonarrClient sonarrClient,
|
||||
IRadarrClient radarrClient,
|
||||
ILidarrClient lidarrClient,
|
||||
IMemoryCache cache,
|
||||
IBus messageBus,
|
||||
ArrClientFactory arrClientFactory,
|
||||
ArrQueueIterator arrArrQueueIterator,
|
||||
DownloadServiceFactory downloadServiceFactory,
|
||||
INotificationPublisher notifier
|
||||
@@ -45,9 +47,9 @@ public abstract class GenericHandler : IHandler, IDisposable
|
||||
_sonarrConfig = sonarrConfig.Value;
|
||||
_radarrConfig = radarrConfig.Value;
|
||||
_lidarrConfig = lidarrConfig.Value;
|
||||
_sonarrClient = sonarrClient;
|
||||
_radarrClient = radarrClient;
|
||||
_lidarrClient = lidarrClient;
|
||||
_cache = cache;
|
||||
_messageBus = messageBus;
|
||||
_arrClientFactory = arrClientFactory;
|
||||
_arrArrQueueIterator = arrArrQueueIterator;
|
||||
_downloadService = downloadServiceFactory.CreateDownloadClient();
|
||||
_notifier = notifier;
|
||||
@@ -67,7 +69,7 @@ public abstract class GenericHandler : IHandler, IDisposable
|
||||
_downloadService.Dispose();
|
||||
}
|
||||
|
||||
protected abstract Task ProcessInstanceAsync(ArrInstance instance, InstanceType instanceType);
|
||||
protected abstract Task ProcessInstanceAsync(ArrInstance instance, InstanceType instanceType, ArrConfig config);
|
||||
|
||||
protected async Task ProcessArrConfigAsync(ArrConfig config, InstanceType instanceType, bool throwOnFailure = false)
|
||||
{
|
||||
@@ -80,7 +82,7 @@ public abstract class GenericHandler : IHandler, IDisposable
|
||||
{
|
||||
try
|
||||
{
|
||||
await ProcessInstanceAsync(arrInstance, instanceType);
|
||||
await ProcessInstanceAsync(arrInstance, instanceType, config);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
@@ -93,16 +95,50 @@ public abstract class GenericHandler : IHandler, IDisposable
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected IArrClient GetClient(InstanceType type) =>
|
||||
type switch
|
||||
{
|
||||
InstanceType.Sonarr => _sonarrClient,
|
||||
InstanceType.Radarr => _radarrClient,
|
||||
InstanceType.Lidarr => _lidarrClient,
|
||||
_ => throw new NotImplementedException($"instance type {type} is not yet supported")
|
||||
};
|
||||
|
||||
protected async Task PublishQueueItemRemoveRequest(
|
||||
string downloadRemovalKey,
|
||||
InstanceType instanceType,
|
||||
ArrInstance instance,
|
||||
QueueRecord record,
|
||||
bool isPack,
|
||||
bool removeFromClient,
|
||||
DeleteReason deleteReason
|
||||
)
|
||||
{
|
||||
if (instanceType is InstanceType.Sonarr)
|
||||
{
|
||||
QueueItemRemoveRequest<SonarrSearchItem> removeRequest = new()
|
||||
{
|
||||
InstanceType = instanceType,
|
||||
Instance = instance,
|
||||
Record = record,
|
||||
SearchItem = (SonarrSearchItem)GetRecordSearchItem(instanceType, record, isPack),
|
||||
RemoveFromClient = removeFromClient,
|
||||
DeleteReason = deleteReason
|
||||
};
|
||||
|
||||
await _messageBus.Publish(removeRequest);
|
||||
}
|
||||
else
|
||||
{
|
||||
QueueItemRemoveRequest<SearchItem> removeRequest = new()
|
||||
{
|
||||
InstanceType = instanceType,
|
||||
Instance = instance,
|
||||
Record = record,
|
||||
SearchItem = GetRecordSearchItem(instanceType, record, isPack),
|
||||
RemoveFromClient = removeFromClient,
|
||||
DeleteReason = deleteReason
|
||||
};
|
||||
|
||||
await _messageBus.Publish(removeRequest);
|
||||
}
|
||||
|
||||
_cache.Set(downloadRemovalKey, true);
|
||||
_logger.LogInformation("item marked for removal | {title} | {url}", record.Title, instance.Url);
|
||||
}
|
||||
|
||||
protected SearchItem GetRecordSearchItem(InstanceType type, QueueRecord record, bool isPack = false)
|
||||
{
|
||||
return type switch
|
||||
|
||||
@@ -4,22 +4,27 @@ using Common.Configuration.QueueCleaner;
|
||||
using Domain.Enums;
|
||||
using Domain.Models.Arr;
|
||||
using Domain.Models.Arr.Queue;
|
||||
using Infrastructure.Helpers;
|
||||
using Infrastructure.Providers;
|
||||
using Infrastructure.Verticals.Arr;
|
||||
using Infrastructure.Verticals.Arr.Interfaces;
|
||||
using Infrastructure.Verticals.Context;
|
||||
using Infrastructure.Verticals.DownloadClient;
|
||||
using Infrastructure.Verticals.DownloadRemover.Models;
|
||||
using Infrastructure.Verticals.Jobs;
|
||||
using Infrastructure.Verticals.Notifications;
|
||||
using MassTransit;
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Serilog.Context;
|
||||
using LogContext = Serilog.Context.LogContext;
|
||||
|
||||
namespace Infrastructure.Verticals.QueueCleaner;
|
||||
|
||||
public sealed class QueueCleaner : GenericHandler
|
||||
{
|
||||
private readonly QueueCleanerConfig _config;
|
||||
private readonly IMemoryCache _cache;
|
||||
private readonly IgnoredDownloadsProvider<QueueCleanerConfig> _ignoredDownloadsProvider;
|
||||
|
||||
public QueueCleaner(
|
||||
@@ -29,9 +34,9 @@ public sealed class QueueCleaner : GenericHandler
|
||||
IOptions<SonarrConfig> sonarrConfig,
|
||||
IOptions<RadarrConfig> radarrConfig,
|
||||
IOptions<LidarrConfig> lidarrConfig,
|
||||
SonarrClient sonarrClient,
|
||||
RadarrClient radarrClient,
|
||||
LidarrClient lidarrClient,
|
||||
IMemoryCache cache,
|
||||
IBus messageBus,
|
||||
ArrClientFactory arrClientFactory,
|
||||
ArrQueueIterator arrArrQueueIterator,
|
||||
DownloadServiceFactory downloadServiceFactory,
|
||||
INotificationPublisher notifier,
|
||||
@@ -39,24 +44,23 @@ public sealed class QueueCleaner : GenericHandler
|
||||
) : base(
|
||||
logger, downloadClientConfig,
|
||||
sonarrConfig, radarrConfig, lidarrConfig,
|
||||
sonarrClient, radarrClient, lidarrClient,
|
||||
arrArrQueueIterator, downloadServiceFactory,
|
||||
cache, messageBus, arrClientFactory, arrArrQueueIterator, downloadServiceFactory,
|
||||
notifier
|
||||
)
|
||||
{
|
||||
_config = config.Value;
|
||||
_config.Validate();
|
||||
_cache = cache;
|
||||
_ignoredDownloadsProvider = ignoredDownloadsProvider;
|
||||
}
|
||||
|
||||
protected override async Task ProcessInstanceAsync(ArrInstance instance, InstanceType instanceType)
|
||||
protected override async Task ProcessInstanceAsync(ArrInstance instance, InstanceType instanceType, ArrConfig config)
|
||||
{
|
||||
IReadOnlyList<string> ignoredDownloads = await _ignoredDownloadsProvider.GetIgnoredDownloads();
|
||||
|
||||
using var _ = LogContext.PushProperty("InstanceName", instanceType.ToString());
|
||||
|
||||
HashSet<SearchItem> itemsToBeRefreshed = [];
|
||||
IArrClient arrClient = GetClient(instanceType);
|
||||
IArrClient arrClient = _arrClientFactory.GetClient(instanceType);
|
||||
|
||||
// push to context
|
||||
ContextProvider.Set(nameof(ArrInstance) + nameof(ArrInstance.Url), instance.Url);
|
||||
@@ -90,6 +94,14 @@ public sealed class QueueCleaner : GenericHandler
|
||||
continue;
|
||||
}
|
||||
|
||||
string downloadRemovalKey = CacheKeys.DownloadMarkedForRemoval(record.DownloadId, instance.Url);
|
||||
|
||||
if (_cache.TryGetValue(downloadRemovalKey, out bool _))
|
||||
{
|
||||
_logger.LogDebug("skip | already marked for removal | {title}", record.Title);
|
||||
continue;
|
||||
}
|
||||
|
||||
// push record to context
|
||||
ContextProvider.Set(nameof(QueueRecord), record);
|
||||
|
||||
@@ -108,7 +120,7 @@ public sealed class QueueCleaner : GenericHandler
|
||||
}
|
||||
|
||||
// failed import check
|
||||
bool shouldRemoveFromArr = await arrClient.ShouldRemoveFromQueue(instanceType, record, downloadCheckResult.IsPrivate);
|
||||
bool shouldRemoveFromArr = await arrClient.ShouldRemoveFromQueue(instanceType, record, downloadCheckResult.IsPrivate, config.ImportFailedMaxStrikes);
|
||||
DeleteReason deleteReason = downloadCheckResult.ShouldRemove ? downloadCheckResult.DeleteReason : DeleteReason.ImportFailed;
|
||||
|
||||
if (!shouldRemoveFromArr && !downloadCheckResult.ShouldRemove)
|
||||
@@ -116,8 +128,6 @@ public sealed class QueueCleaner : GenericHandler
|
||||
_logger.LogInformation("skip | {title}", record.Title);
|
||||
continue;
|
||||
}
|
||||
|
||||
itemsToBeRefreshed.Add(GetRecordSearchItem(instanceType, record, group.Count() > 1));
|
||||
|
||||
bool removeFromClient = true;
|
||||
|
||||
@@ -140,11 +150,16 @@ public sealed class QueueCleaner : GenericHandler
|
||||
}
|
||||
}
|
||||
|
||||
await arrClient.DeleteQueueItemAsync(instance, record, removeFromClient, deleteReason);
|
||||
await _notifier.NotifyQueueItemDeleted(removeFromClient, deleteReason);
|
||||
await PublishQueueItemRemoveRequest(
|
||||
downloadRemovalKey,
|
||||
instanceType,
|
||||
instance,
|
||||
record,
|
||||
group.Count() > 1,
|
||||
removeFromClient,
|
||||
deleteReason
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
await arrClient.RefreshItemsAsync(instance, itemsToBeRefreshed);
|
||||
}
|
||||
}
|
||||
@@ -186,6 +186,9 @@ services:
|
||||
- HTTP_MAX_RETRIES=0
|
||||
- HTTP_TIMEOUT=20
|
||||
|
||||
- SEARCH_ENABLED=true
|
||||
- SEARCH_DELAY=5
|
||||
|
||||
- TRIGGERS__QUEUECLEANER=0/30 * * * * ?
|
||||
- TRIGGERS__CONTENTBLOCKER=0/30 * * * * ?
|
||||
- TRIGGERS__DOWNLOADCLEANER=0/30 * * * * ?
|
||||
@@ -252,6 +255,7 @@ services:
|
||||
# - TRANSMISSION__PASSWORD=testing
|
||||
|
||||
- SONARR__ENABLED=true
|
||||
- SONARR__IMPORT_FAILED_MAX_STRIKES=-1
|
||||
- SONARR__SEARCHTYPE=Episode
|
||||
- SONARR__BLOCK__TYPE=blacklist
|
||||
- SONARR__BLOCK__PATH=https://raw.githubusercontent.com/flmorg/cleanuperr/refs/heads/main/blacklist
|
||||
@@ -259,12 +263,14 @@ services:
|
||||
- SONARR__INSTANCES__0__APIKEY=425d1e713f0c405cbbf359ac0502c1f4
|
||||
|
||||
- RADARR__ENABLED=true
|
||||
- RADARR__IMPORT_FAILED_MAX_STRIKES=-1
|
||||
- RADARR__BLOCK__TYPE=blacklist
|
||||
- RADARR__BLOCK__PATH=https://raw.githubusercontent.com/flmorg/cleanuperr/refs/heads/main/blacklist
|
||||
- RADARR__INSTANCES__0__URL=http://radarr:7878
|
||||
- RADARR__INSTANCES__0__APIKEY=8b7454f668e54c5b8f44f56f93969761
|
||||
|
||||
- LIDARR__ENABLED=true
|
||||
- LIDARR__IMPORT_FAILED_MAX_STRIKES=-1
|
||||
- LIDARR__BLOCK__TYPE=blacklist
|
||||
- LIDARR__BLOCK__PATH=https://raw.githubusercontent.com/flmorg/cleanuperr/refs/heads/main/blacklist # TODO
|
||||
- LIDARR__INSTANCES__0__URL=http://lidarr:8686
|
||||
|
||||
21
docs/docs/2_features.mdx
Normal file
21
docs/docs/2_features.mdx
Normal file
@@ -0,0 +1,21 @@
|
||||
---
|
||||
sidebar_position: 2
|
||||
---
|
||||
|
||||
import Link from '@docusaurus/Link';
|
||||
|
||||
# Features
|
||||
|
||||
<div style={{ fontSize: '1.2rem' }}>
|
||||
- Strike system to mark bad downloads.
|
||||
- Remove and block downloads that reached a maximum number of strikes.
|
||||
- Remove and block downloads that are **failing to be imported** by the arrs. <Link to="/docs/configuration/queue-cleaner/import-failed">[configuration]</Link>
|
||||
- Remove and block downloads that are **stalled** or in **metadata downloading** state. <Link to="/docs/configuration/queue-cleaner/stalled">[configuration]</Link>
|
||||
- Remove and block downloads that have a **low download speed** or **high estimated completion time**. <Link to="/docs/configuration/queue-cleaner/slow">[configuration]</Link>
|
||||
- Remove and block downloads blocked by qBittorrent or by Cleanuperr's **Content Blocker**. <Link to="/docs/configuration/content-blocker/general">[configuration]</Link>
|
||||
- Automatically trigger a search for downloads removed from the arrs.
|
||||
- Clean up downloads that have been **seeding** for a certain amount of time. <Link to="/docs/configuration/download-cleaner/seeding">[configuration]</Link>
|
||||
- Remove downloads that are **orphaned**/have no **hardlinks**/are not referenced by the arrs anymore (with [cross-seed](https://www.cross-seed.org/) support). <Link to="/docs/configuration/download-cleaner/hardlinks">[configuration]</Link>
|
||||
- Notify on strike or download removal. <Link to="/docs/category/notifications">[configuration]</Link>
|
||||
- Ignore certain torrent hashes, categories, tags or trackers from being processed by Cleanuperr.
|
||||
</div>
|
||||
@@ -1,10 +1,10 @@
|
||||
---
|
||||
sidebar_position: 1
|
||||
sidebar_position: 2
|
||||
---
|
||||
|
||||
import GeneralSettings from '@site/src/components/configuration/GeneralSettings';
|
||||
|
||||
# General Settings
|
||||
# General settings
|
||||
|
||||
These are the general configuration settings that apply to the entire application.
|
||||
|
||||
|
||||
11
docs/docs/configuration/2_search.mdx
Normal file
11
docs/docs/configuration/2_search.mdx
Normal file
@@ -0,0 +1,11 @@
|
||||
---
|
||||
sidebar_position: 3
|
||||
---
|
||||
|
||||
import SearchSettings from '@site/src/components/configuration/SearchSettings';
|
||||
|
||||
# Search settings
|
||||
|
||||
These are the search configuration settings when searching for replacements.
|
||||
|
||||
<SearchSettings/>
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"label": "Arrs settings",
|
||||
"position": 6,
|
||||
"position": 7,
|
||||
"link": {
|
||||
"type": "generated-index",
|
||||
"description": "Servarr settings."
|
||||
|
||||
@@ -3,6 +3,8 @@ sidebar_position: 1
|
||||
---
|
||||
|
||||
import ContentBlockerGeneralSettings from '@site/src/components/configuration/content-blocker/ContentBlockerGeneralSettings';
|
||||
import { Important } from '@site/src/components/Admonition';
|
||||
import Link from '@docusaurus/Link';
|
||||
|
||||
# General Settings
|
||||
|
||||
@@ -16,4 +18,8 @@ These environment variables are needed to enable the Content Blocker functionali
|
||||
- [LIDARR__BLOCK__TYPE](/docs/configuration/arrs/lidarr?LIDARR__BLOCK__TYPE) (if Lidarr is enabled)
|
||||
- [LIDARR__BLOCK__PATH](/docs/configuration/arrs/lidarr?LIDARR__BLOCK__PATH) (if Lidarr is enabled)
|
||||
|
||||
<Important>
|
||||
These settings need a <Link to="/docs/configuration/download-client/general?DOWNLOAD_CLIENT">download client</Link> to be configured.
|
||||
</Important>
|
||||
|
||||
<ContentBlockerGeneralSettings/>
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"label": "Content Blocker",
|
||||
"position": 2,
|
||||
"position": 4,
|
||||
"link": {
|
||||
"type": "generated-index",
|
||||
"description": "Settings for the Content Blocker functionality."
|
||||
|
||||
@@ -3,9 +3,10 @@ sidebar_position: 2
|
||||
---
|
||||
|
||||
import DownloadCleanerCleanupSettings from '@site/src/components/configuration/download-cleaner/DownloadCleanerCleanupSettings';
|
||||
import { Note } from '@site/src/components/Admonition';
|
||||
import { Note, Important } from '@site/src/components/Admonition';
|
||||
import Link from '@docusaurus/Link';
|
||||
|
||||
# Cleanup Settings
|
||||
# Seeding settings
|
||||
|
||||
These settings control how the Download Cleaner handles different categories of downloads that need to be removed.
|
||||
|
||||
@@ -23,4 +24,8 @@ These settings control how the Download Cleaner handles different categories of
|
||||
```
|
||||
</Note>
|
||||
|
||||
<Important>
|
||||
These settings need a <Link to="/docs/configuration/download-client/general?DOWNLOAD_CLIENT">download client</Link> to be configured.
|
||||
</Important>
|
||||
|
||||
<DownloadCleanerCleanupSettings/>
|
||||
@@ -4,12 +4,17 @@ sidebar_position: 3
|
||||
|
||||
import DownloadCleanerHardlinksSettings from '@site/src/components/configuration/download-cleaner/DownloadCleanerHardlinksSettings';
|
||||
import { Important, Warning } from '@site/src/components/Admonition';
|
||||
import Link from '@docusaurus/Link';
|
||||
|
||||
# Hardlinks Settings
|
||||
|
||||
These settings control how the Download Cleaner handles downloads with no hardlinks remaining (they are not available in the arrs anymore).
|
||||
|
||||
The Download Cleaner will change the category of a download that has no hardlinks and the new category can be cleaned based on the rules configured [here](/docs/configuration/download-cleaner/categories).
|
||||
The Download Cleaner will change the category of a download that has no hardlinks and the new category can be cleaned based on the rules configured [here](/docs/configuration/download-cleaner/seeding).
|
||||
|
||||
<Important>
|
||||
These settings need a <Link to="/docs/configuration/download-client/general?DOWNLOAD_CLIENT">download client</Link> to be configured.
|
||||
</Important>
|
||||
|
||||
<Important>
|
||||
If you are using Docker, make sure to mount the downloads directory the same way it is mounted for the download client.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"label": "Download Cleaner",
|
||||
"position": 3,
|
||||
"position": 5,
|
||||
"link": {
|
||||
"type": "generated-index",
|
||||
"description": "Configure the Download Cleaner to automatically clean up downloads that have been seeding for a certain amount of time."
|
||||
|
||||
@@ -4,7 +4,7 @@ sidebar_position: 1
|
||||
|
||||
import DownloadClientSettings from '@site/src/components/configuration/download-client/DownloadClientSettings';
|
||||
|
||||
# Download Client Settings
|
||||
# General settings
|
||||
|
||||
These settings control how Cleanuperr interacts with your download client.
|
||||
|
||||
|
||||
7
docs/docs/configuration/download-client/2_qbit.mdx
Normal file
7
docs/docs/configuration/download-client/2_qbit.mdx
Normal file
@@ -0,0 +1,7 @@
|
||||
import QBittorrentSettings from '@site/src/components/configuration/download-client/QBittorrentSettings';
|
||||
|
||||
# qBittorrent settings
|
||||
|
||||
Settings used to access your qBittorrent instance.
|
||||
|
||||
<QBittorrentSettings/>
|
||||
7
docs/docs/configuration/download-client/3_deluge.mdx
Normal file
7
docs/docs/configuration/download-client/3_deluge.mdx
Normal file
@@ -0,0 +1,7 @@
|
||||
import DelugeSettings from '@site/src/components/configuration/download-client/DelugeSettings';
|
||||
|
||||
# Deluge settings
|
||||
|
||||
Settings used to access your Deluge instance.
|
||||
|
||||
<DelugeSettings/>
|
||||
@@ -0,0 +1,7 @@
|
||||
import TransmissionSettings from '@site/src/components/configuration/download-client/TransmissionSettings';
|
||||
|
||||
# Transmission settings
|
||||
|
||||
Settings used to access your Transmission instance.
|
||||
|
||||
<TransmissionSettings/>
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"label": "Download Client",
|
||||
"position": 4,
|
||||
"position": 6,
|
||||
"link": {
|
||||
"type": "generated-index",
|
||||
"description": "Configure the download client settings for Cleanuperr."
|
||||
|
||||
@@ -1,162 +1,394 @@
|
||||
import { Note } from '@site/src/components/Admonition';
|
||||
import CodeBlock from '@theme/CodeBlock';
|
||||
import CodeBlockContainer from '@theme/CodeBlock/Container';
|
||||
import Link from '@docusaurus/Link';
|
||||
import styles from './examples.module.css';
|
||||
|
||||
# Docker compose
|
||||
|
||||
<Note>
|
||||
**This example contains all settings and should be modified to fit your needs.**
|
||||
This example contains all settings and should be modified to fit your needs.
|
||||
Remove the variables that you do not need.
|
||||
</Note>
|
||||
|
||||
```
|
||||
services:
|
||||
cleanuperr:
|
||||
image: ghcr.io/flmorg/cleanuperr:latest
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
# if you want persistent logs
|
||||
- ./cleanuperr/logs:/var/logs
|
||||
# if you want to ignore certain downloads from being processed
|
||||
- ./cleanuperr/ignored.txt:/ignored.txt
|
||||
# if you're using cross-seed and the hardlinks functionality
|
||||
- ./downloads:/downloads
|
||||
environment:
|
||||
# general settings
|
||||
- TZ=America/New_York
|
||||
- DRY_RUN=false
|
||||
- HTTP_MAX_RETRIES=0
|
||||
- HTTP_TIMEOUT=100
|
||||
<Note>
|
||||
Click on an environment variable's name to go to its documentation.
|
||||
</Note>
|
||||
|
||||
# logging
|
||||
- LOGGING__LOGLEVEL=Information
|
||||
- LOGGING__FILE__ENABLED=false
|
||||
- LOGGING__FILE__PATH=/var/logs/
|
||||
- LOGGING__ENHANCED=true
|
||||
|
||||
# job triggers
|
||||
- TRIGGERS__QUEUECLEANER=0 0/5 * * * ?
|
||||
- TRIGGERS__CONTENTBLOCKER=0 0/5 * * * ?
|
||||
- TRIGGERS__DOWNLOADCLEANER=0 0 * * * ?
|
||||
|
||||
# queue cleaner
|
||||
- QUEUECLEANER__ENABLED=true
|
||||
- QUEUECLEANER__IGNORED_DOWNLOADS_PATH=/ignored.txt
|
||||
- QUEUECLEANER__RUNSEQUENTIALLY=true
|
||||
|
||||
# failed imports
|
||||
- QUEUECLEANER__IMPORT_FAILED_MAX_STRIKES=5
|
||||
- QUEUECLEANER__IMPORT_FAILED_IGNORE_PRIVATE=false
|
||||
- QUEUECLEANER__IMPORT_FAILED_DELETE_PRIVATE=false
|
||||
- QUEUECLEANER__IMPORT_FAILED_IGNORE_PATTERNS__0=title mismatch
|
||||
- QUEUECLEANER__IMPORT_FAILED_IGNORE_PATTERNS__1=manual import required
|
||||
|
||||
# stalled downloads
|
||||
- QUEUECLEANER__STALLED_MAX_STRIKES=5
|
||||
- QUEUECLEANER__STALLED_RESET_STRIKES_ON_PROGRESS=false
|
||||
- QUEUECLEANER__STALLED_IGNORE_PRIVATE=false
|
||||
- QUEUECLEANER__STALLED_DELETE_PRIVATE=false
|
||||
|
||||
# slow downloads
|
||||
- QUEUECLEANER__SLOW_MAX_STRIKES=5
|
||||
- QUEUECLEANER__SLOW_RESET_STRIKES_ON_PROGRESS=true
|
||||
- QUEUECLEANER__SLOW_IGNORE_PRIVATE=false
|
||||
- QUEUECLEANER__SLOW_DELETE_PRIVATE=false
|
||||
- QUEUECLEANER__SLOW_MIN_SPEED=1MB
|
||||
- QUEUECLEANER__SLOW_MAX_TIME=20
|
||||
- QUEUECLEANER__SLOW_IGNORE_ABOVE_SIZE=60GB
|
||||
|
||||
# content blocker
|
||||
- CONTENTBLOCKER__ENABLED=true
|
||||
- CONTENTBLOCKER__IGNORED_DOWNLOADS_PATH=/ignored.txt
|
||||
- CONTENTBLOCKER__IGNORE_PRIVATE=false
|
||||
- CONTENTBLOCKER__DELETE_PRIVATE=false
|
||||
|
||||
# download cleaner
|
||||
- DOWNLOADCLEANER__ENABLED=true
|
||||
- DOWNLOADCLEANER__IGNORED_DOWNLOADS_PATH=/ignored.txt
|
||||
- DOWNLOADCLEANER__DELETE_PRIVATE=false
|
||||
|
||||
# categories to seed until max ratio or min seed time has been reached
|
||||
- DOWNLOADCLEANER__CATEGORIES__0__NAME=tv-sonarr
|
||||
- DOWNLOADCLEANER__CATEGORIES__0__MAX_RATIO=-1
|
||||
- DOWNLOADCLEANER__CATEGORIES__0__MIN_SEED_TIME=0
|
||||
- DOWNLOADCLEANER__CATEGORIES__0__MAX_SEED_TIME=240
|
||||
- DOWNLOADCLEANER__CATEGORIES__1__NAME=radarr
|
||||
- DOWNLOADCLEANER__CATEGORIES__1__MAX_RATIO=-1
|
||||
- DOWNLOADCLEANER__CATEGORIES__1__MIN_SEED_TIME=0
|
||||
- DOWNLOADCLEANER__CATEGORIES__1__MAX_SEED_TIME=240
|
||||
# remove downloads with no hardlinks
|
||||
- DOWNLOADCLEANER__CATEGORIES__2__NAME=cleanuperr-unlinked
|
||||
- DOWNLOADCLEANER__CATEGORIES__2__MAX_RATIO=-1
|
||||
- DOWNLOADCLEANER__CATEGORIES__2__MIN_SEED_TIME=0
|
||||
- DOWNLOADCLEANER__CATEGORIES__2__MAX_SEED_TIME=0
|
||||
|
||||
# change category for downloads with no hardlinks
|
||||
- DOWNLOADCLEANER__UNLINKED_TARGET_CATEGORY=cleanuperr-unlinked
|
||||
- DOWNLOADCLEANER__UNLINKED_USE_TAG=false
|
||||
- DOWNLOADCLEANER__UNLINKED_IGNORED_ROOT_DIR=/downloads
|
||||
- DOWNLOADCLEANER__UNLINKED_CATEGORIES__0=tv-sonarr
|
||||
- DOWNLOADCLEANER__UNLINKED_CATEGORIES__1=radarr
|
||||
|
||||
- DOWNLOAD_CLIENT=none
|
||||
# OR
|
||||
# - DOWNLOAD_CLIENT=disabled
|
||||
# OR
|
||||
# - DOWNLOAD_CLIENT=qBittorrent
|
||||
# - QBITTORRENT__URL=http://localhost:8080
|
||||
# - QBITTORRENT__URL_BASE=myCustomPath
|
||||
# - QBITTORRENT__USERNAME=user
|
||||
# - QBITTORRENT__PASSWORD=pass
|
||||
# OR
|
||||
# - DOWNLOAD_CLIENT=deluge
|
||||
# - DELUGE__URL_BASE=myCustomPath
|
||||
# - DELUGE__URL=http://localhost:8112
|
||||
# - DELUGE__PASSWORD=testing
|
||||
# OR
|
||||
# - DOWNLOAD_CLIENT=transmission
|
||||
# - TRANSMISSION__URL=http://localhost:9091
|
||||
# - TRANSMISSION__URL_BASE=myCustomPath
|
||||
# - TRANSMISSION__USERNAME=test
|
||||
# - TRANSMISSION__PASSWORD=testing
|
||||
|
||||
- SONARR__ENABLED=true
|
||||
- SONARR__SEARCHTYPE=Episode
|
||||
- SONARR__BLOCK__TYPE=blacklist
|
||||
- SONARR__BLOCK__PATH=https://example.com/path/to/file.txt
|
||||
- SONARR__INSTANCES__0__URL=http://localhost:8989
|
||||
- SONARR__INSTANCES__0__APIKEY=secret1
|
||||
- SONARR__INSTANCES__1__URL=http://localhost:8990
|
||||
- SONARR__INSTANCES__1__APIKEY=secret2
|
||||
|
||||
- RADARR__ENABLED=true
|
||||
- RADARR__BLOCK__TYPE=blacklist
|
||||
- RADARR__BLOCK__PATH=https://example.com/path/to/file.txt
|
||||
- RADARR__INSTANCES__0__URL=http://localhost:7878
|
||||
- RADARR__INSTANCES__0__APIKEY=secret3
|
||||
- RADARR__INSTANCES__1__URL=http://localhost:7879
|
||||
- RADARR__INSTANCES__1__APIKEY=secret4
|
||||
|
||||
- LIDARR__ENABLED=true
|
||||
- LIDARR__BLOCK__TYPE=blacklist
|
||||
- LIDARR__BLOCK__PATH=https://example.com/path/to/file.txt
|
||||
- LIDARR__INSTANCES__0__URL=http://radarr:8686
|
||||
- LIDARR__INSTANCES__0__APIKEY=secret5
|
||||
- LIDARR__INSTANCES__1__URL=http://radarr:8687
|
||||
- LIDARR__INSTANCES__1__APIKEY=secret6
|
||||
|
||||
- NOTIFIARR__ON_IMPORT_FAILED_STRIKE=true
|
||||
- NOTIFIARR__ON_STALLED_STRIKE=true
|
||||
- NOTIFIARR__ON_SLOW_STRIKE=true
|
||||
- NOTIFIARR__ON_QUEUE_ITEM_DELETED=true
|
||||
- NOTIFIARR__ON_DOWNLOAD_CLEANED=true
|
||||
- NOTIFIARR__ON_CATEGORY_CHANGED=true
|
||||
- NOTIFIARR__API_KEY=notifiarr_secret
|
||||
- NOTIFIARR__CHANNEL_ID=discord_channel_id
|
||||
|
||||
- APPRISE__ON_IMPORT_FAILED_STRIKE=true
|
||||
- APPRISE__ON_STALLED_STRIKE=true
|
||||
- APPRISE__ON_SLOW_STRIKE=true
|
||||
- APPRISE__ON_QUEUE_ITEM_DELETED=true
|
||||
- APPRISE__ON_DOWNLOAD_CLEANED=true
|
||||
- NOTIFIARR__ON_CATEGORY_CHANGED=true
|
||||
- APPRISE__URL=http://apprise:8000
|
||||
- APPRISE__KEY=myConfigKey
|
||||
```
|
||||
<CodeBlock language="text" title="Environment Variables" wrap={true}>
|
||||
<div style={{ whiteSpace: 'pre' }}>
|
||||
{`services:
|
||||
cleanuperr:
|
||||
image: ghcr.io/flmorg/cleanuperr:latest
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
# if you want persistent logs
|
||||
- ./cleanuperr/logs:/var/logs
|
||||
# if you want to ignore certain downloads from being processed
|
||||
- ./cleanuperr/ignored.txt:/ignored.txt
|
||||
# if you're using cross-seed and the hardlinks functionality
|
||||
- ./downloads:/downloads
|
||||
environment:
|
||||
- `}
|
||||
<Link to="/docs/configuration/general?TZ">TZ</Link>
|
||||
{`=America/New_York
|
||||
- `}
|
||||
<Link to="/docs/configuration/general?DRY_RUN">DRY_RUN</Link>
|
||||
{`=false
|
||||
- `}
|
||||
<Link to="/docs/configuration/general?HTTP_MAX_RETRIES">HTTP_MAX_RETRIES</Link>
|
||||
{`=0
|
||||
- `}
|
||||
<Link to="/docs/configuration/general?HTTP_TIMEOUT">HTTP_TIMEOUT</Link>
|
||||
{`=100
|
||||
- `}
|
||||
<Link to="/docs/configuration/general?HTTP_VALIDATE_CERT">HTTP_VALIDATE_CERT</Link>
|
||||
{`=Enabled
|
||||
|
||||
- `}
|
||||
<Link to="/docs/configuration/general?LOGGING__LOGLEVEL">LOGGING__LOGLEVEL</Link>
|
||||
{`=Information
|
||||
- `}
|
||||
<Link to="/docs/configuration/general?LOGGING__FILE__ENABLED">LOGGING__FILE__ENABLED</Link>
|
||||
{`=false
|
||||
- `}
|
||||
<Link to="/docs/configuration/general?LOGGING__FILE__PATH">LOGGING__FILE__PATH</Link>
|
||||
{`=/var/logs/
|
||||
- `}
|
||||
<Link to="/docs/configuration/general?LOGGING__ENHANCED">LOGGING__ENHANCED</Link>
|
||||
{`=true
|
||||
|
||||
- `}
|
||||
<Link to="/docs/configuration/search?SEARCH_ENABLED">SEARCH_ENABLED</Link>
|
||||
{`=true
|
||||
- `}
|
||||
<Link to="/docs/configuration/search?SEARCH_DELAY">SEARCH_DELAY</Link>
|
||||
{`=30
|
||||
|
||||
- `}
|
||||
<Link to="/docs/configuration/queue-cleaner/general?TRIGGERS__QUEUECLEANER">TRIGGERS__QUEUECLEANER</Link>
|
||||
{`=0 0/5 * * * ?
|
||||
- `}
|
||||
<Link to="/docs/configuration/queue-cleaner/general?QUEUECLEANER__ENABLED">QUEUECLEANER__ENABLED</Link>
|
||||
{`=true
|
||||
- `}
|
||||
<Link to="/docs/configuration/queue-cleaner/general?QUEUECLEANER__IGNORED_DOWNLOADS_PATH">QUEUECLEANER__IGNORED_DOWNLOADS_PATH</Link>
|
||||
{`=/ignored.txt
|
||||
- `}
|
||||
<Link to="/docs/configuration/queue-cleaner/general?QUEUECLEANER__RUNSEQUENTIALLY">QUEUECLEANER__RUNSEQUENTIALLY</Link>
|
||||
{`=true
|
||||
|
||||
- `}
|
||||
<Link to="/docs/configuration/queue-cleaner/import-failed?QUEUECLEANER__IMPORT_FAILED_MAX_STRIKES">QUEUECLEANER__IMPORT_FAILED_MAX_STRIKES</Link>
|
||||
{`=5
|
||||
- `}
|
||||
<Link to="/docs/configuration/queue-cleaner/import-failed?QUEUECLEANER__IMPORT_FAILED_IGNORE_PRIVATE">QUEUECLEANER__IMPORT_FAILED_IGNORE_PRIVATE</Link>
|
||||
{`=false
|
||||
- `}
|
||||
<Link to="/docs/configuration/queue-cleaner/import-failed?QUEUECLEANER__IMPORT_FAILED_DELETE_PRIVATE">QUEUECLEANER__IMPORT_FAILED_DELETE_PRIVATE</Link>
|
||||
{`=false
|
||||
- `}
|
||||
<Link to="/docs/configuration/queue-cleaner/import-failed?QUEUECLEANER__IMPORT_FAILED_IGNORE_PATTERNS__0">QUEUECLEANER__IMPORT_FAILED_IGNORE_PATTERNS__0</Link>
|
||||
{`=title mismatch
|
||||
- `}
|
||||
<Link to="/docs/configuration/queue-cleaner/import-failed?QUEUECLEANER__IMPORT_FAILED_IGNORE_PATTERNS__1">QUEUECLEANER__IMPORT_FAILED_IGNORE_PATTERNS__1</Link>
|
||||
{`=manual import required
|
||||
|
||||
- `}
|
||||
<Link to="/docs/configuration/queue-cleaner/stalled?QUEUECLEANER__STALLED_MAX_STRIKES">QUEUECLEANER__STALLED_MAX_STRIKES</Link>
|
||||
{`=5
|
||||
- `}
|
||||
<Link to="/docs/configuration/queue-cleaner/stalled?QUEUECLEANER__STALLED_RESET_STRIKES_ON_PROGRESS">QUEUECLEANER__STALLED_RESET_STRIKES_ON_PROGRESS</Link>
|
||||
{`=true
|
||||
- `}
|
||||
<Link to="/docs/configuration/queue-cleaner/stalled?QUEUECLEANER__STALLED_IGNORE_PRIVATE">QUEUECLEANER__STALLED_IGNORE_PRIVATE</Link>
|
||||
{`=false
|
||||
- `}
|
||||
<Link to="/docs/configuration/queue-cleaner/stalled?QUEUECLEANER__STALLED_DELETE_PRIVATE">QUEUECLEANER__STALLED_DELETE_PRIVATE</Link>
|
||||
{`=false
|
||||
|
||||
- `}
|
||||
<Link to="/docs/configuration/queue-cleaner/slow?QUEUECLEANER__SLOW_MAX_STRIKES">QUEUECLEANER__SLOW_MAX_STRIKES</Link>
|
||||
{`=5
|
||||
- `}
|
||||
<Link to="/docs/configuration/queue-cleaner/slow?QUEUECLEANER__SLOW_RESET_STRIKES_ON_PROGRESS">QUEUECLEANER__SLOW_RESET_STRIKES_ON_PROGRESS</Link>
|
||||
{`=true
|
||||
- `}
|
||||
<Link to="/docs/configuration/queue-cleaner/slow?QUEUECLEANER__SLOW_IGNORE_PRIVATE">QUEUECLEANER__SLOW_IGNORE_PRIVATE</Link>
|
||||
{`=false
|
||||
- `}
|
||||
<Link to="/docs/configuration/queue-cleaner/slow?QUEUECLEANER__SLOW_DELETE_PRIVATE">QUEUECLEANER__SLOW_DELETE_PRIVATE</Link>
|
||||
{`=false
|
||||
- `}
|
||||
<Link to="/docs/configuration/queue-cleaner/slow?QUEUECLEANER__SLOW_MIN_SPEED">QUEUECLEANER__SLOW_MIN_SPEED</Link>
|
||||
{`=1MB
|
||||
- `}
|
||||
<Link to="/docs/configuration/queue-cleaner/slow?QUEUECLEANER__SLOW_MAX_TIME">QUEUECLEANER__SLOW_MAX_TIME</Link>
|
||||
{`=20
|
||||
- `}
|
||||
<Link to="/docs/configuration/queue-cleaner/slow?QUEUECLEANER__SLOW_IGNORE_ABOVE_SIZE">QUEUECLEANER__SLOW_IGNORE_ABOVE_SIZE</Link>
|
||||
{`=60GB
|
||||
|
||||
- `}
|
||||
<Link to="/docs/configuration/content-blocker/general?TRIGGERS__CONTENTBLOCKER">TRIGGERS__CONTENTBLOCKER</Link>
|
||||
{`=0 0/5 * * * ?
|
||||
- `}
|
||||
<Link to="/docs/configuration/content-blocker/general?CONTENTBLOCKER__ENABLED">CONTENTBLOCKER__ENABLED</Link>
|
||||
{`=true
|
||||
- `}
|
||||
<Link to="/docs/configuration/content-blocker/general?CONTENTBLOCKER__IGNORED_DOWNLOADS_PATH">CONTENTBLOCKER__IGNORED_DOWNLOADS_PATH</Link>
|
||||
{`=/ignored.txt
|
||||
- `}
|
||||
<Link to="/docs/configuration/content-blocker/general?CONTENTBLOCKER__IGNORE_PRIVATE">CONTENTBLOCKER__IGNORE_PRIVATE</Link>
|
||||
{`=false
|
||||
- `}
|
||||
<Link to="/docs/configuration/content-blocker/general?CONTENTBLOCKER__DELETE_PRIVATE">CONTENTBLOCKER__DELETE_PRIVATE</Link>
|
||||
{`=false
|
||||
|
||||
- `}
|
||||
<Link to="/docs/configuration/download-cleaner/general?TRIGGERS__DOWNLOADCLEANER">TRIGGERS__DOWNLOADCLEANER</Link>
|
||||
{`=0 0 * * * ?
|
||||
- `}
|
||||
<Link to="/docs/configuration/download-cleaner/general?DOWNLOADCLEANER__ENABLED">DOWNLOADCLEANER__ENABLED</Link>
|
||||
{`=true
|
||||
- `}
|
||||
<Link to="/docs/configuration/download-cleaner/general?DOWNLOADCLEANER__IGNORED_DOWNLOADS_PATH">DOWNLOADCLEANER__IGNORED_DOWNLOADS_PATH</Link>
|
||||
{`=/ignored.txt
|
||||
- `}
|
||||
<Link to="/docs/configuration/download-cleaner/general?DOWNLOADCLEANER__DELETE_PRIVATE">DOWNLOADCLEANER__DELETE_PRIVATE</Link>
|
||||
{`=false
|
||||
|
||||
- `}
|
||||
<Link to="/docs/configuration/download-cleaner/seeding?DOWNLOADCLEANER__CATEGORIES__0__NAME">DOWNLOADCLEANER__CATEGORIES__0__NAME</Link>
|
||||
{`=tv-sonarr
|
||||
- `}
|
||||
<Link to="/docs/configuration/download-cleaner/seeding?DOWNLOADCLEANER__CATEGORIES__0__MAX_RATIO">DOWNLOADCLEANER__CATEGORIES__0__MAX_RATIO</Link>
|
||||
{`=1
|
||||
- `}
|
||||
<Link to="/docs/configuration/download-cleaner/seeding?DOWNLOADCLEANER__CATEGORIES__0__MIN_SEED_TIME">DOWNLOADCLEANER__CATEGORIES__0__MIN_SEED_TIME</Link>
|
||||
{`=0
|
||||
- `}
|
||||
<Link to="/docs/configuration/download-cleaner/seeding?DOWNLOADCLEANER__CATEGORIES__0__MAX_SEED_TIME">DOWNLOADCLEANER__CATEGORIES__0__MAX_SEED_TIME</Link>
|
||||
{`=240
|
||||
- `}
|
||||
<Link to="/docs/configuration/download-cleaner/seeding?DOWNLOADCLEANER__CATEGORIES__0__NAME">DOWNLOADCLEANER__CATEGORIES__1__NAME</Link>
|
||||
{`=radarr
|
||||
- `}
|
||||
<Link to="/docs/configuration/download-cleaner/seeding?DOWNLOADCLEANER__CATEGORIES__0__MAX_RATIO">DOWNLOADCLEANER__CATEGORIES__1__MAX_RATIO</Link>
|
||||
{`=1
|
||||
- `}
|
||||
<Link to="/docs/configuration/download-cleaner/seeding?DOWNLOADCLEANER__CATEGORIES__0__MIN_SEED_TIME">DOWNLOADCLEANER__CATEGORIES__1__MIN_SEED_TIME</Link>
|
||||
{`=0
|
||||
- `}
|
||||
<Link to="/docs/configuration/download-cleaner/seeding?DOWNLOADCLEANER__CATEGORIES__0__MAX_SEED_TIME">DOWNLOADCLEANER__CATEGORIES__1__MAX_SEED_TIME</Link>
|
||||
{`=240
|
||||
- `}
|
||||
<Link to="/docs/configuration/download-cleaner/seeding?DOWNLOADCLEANER__CATEGORIES__0__NAME">DOWNLOADCLEANER__CATEGORIES__2__NAME</Link>
|
||||
{`=cleanuperr-unlinked
|
||||
- `}
|
||||
<Link to="/docs/configuration/download-cleaner/seeding?DOWNLOADCLEANER__CATEGORIES__0__MAX_RATIO">DOWNLOADCLEANER__CATEGORIES__2__MAX_RATIO</Link>
|
||||
{`=1
|
||||
- `}
|
||||
<Link to="/docs/configuration/download-cleaner/seeding?DOWNLOADCLEANER__CATEGORIES__0__MIN_SEED_TIME">DOWNLOADCLEANER__CATEGORIES__2__MIN_SEED_TIME</Link>
|
||||
{`=0
|
||||
- `}
|
||||
<Link to="/docs/configuration/download-cleaner/seeding?DOWNLOADCLEANER__CATEGORIES__0__MAX_SEED_TIME">DOWNLOADCLEANER__CATEGORIES__2__MAX_SEED_TIME</Link>
|
||||
{`=240
|
||||
|
||||
- `}
|
||||
<Link to="/docs/configuration/download-cleaner/hardlinks?DOWNLOADCLEANER__UNLINKED_TARGET_CATEGORY">DOWNLOADCLEANER__UNLINKED_TARGET_CATEGORY</Link>
|
||||
{`=cleanuperr-unlinked
|
||||
- `}
|
||||
<Link to="/docs/configuration/download-cleaner/hardlinks?DOWNLOADCLEANER__UNLINKED_USE_TAG">DOWNLOADCLEANER__UNLINKED_USE_TAG</Link>
|
||||
{`=false
|
||||
- `}
|
||||
<Link to="/docs/configuration/download-cleaner/hardlinks?DOWNLOADCLEANER__UNLINKED_IGNORED_ROOT_DIR">DOWNLOADCLEANER__UNLINKED_IGNORED_ROOT_DIR</Link>
|
||||
{`=/downloads
|
||||
- `}
|
||||
<Link to="/docs/configuration/download-cleaner/hardlinks?DOWNLOADCLEANER__UNLINKED_CATEGORIES__0">DOWNLOADCLEANER__UNLINKED_CATEGORIES__0</Link>
|
||||
{`=tv-sonarr
|
||||
- `}
|
||||
<Link to="/docs/configuration/download-cleaner/hardlinks?DOWNLOADCLEANER__UNLINKED_CATEGORIES__0">DOWNLOADCLEANER__UNLINKED_CATEGORIES__1</Link>
|
||||
{`=radarr
|
||||
|
||||
- `}
|
||||
<Link to="/docs/configuration/download-client/general?DOWNLOAD_CLIENT">DOWNLOAD_CLIENT</Link>
|
||||
{`=none
|
||||
# OR
|
||||
# - `}
|
||||
<Link to="/docs/configuration/download-client/general?DOWNLOAD_CLIENT">DOWNLOAD_CLIENT</Link>
|
||||
{`=disabled
|
||||
# OR
|
||||
# - `}
|
||||
<Link to="/docs/configuration/download-client/general?DOWNLOAD_CLIENT">DOWNLOAD_CLIENT</Link>
|
||||
{`=qBittorrent
|
||||
# - `}
|
||||
<Link to="/docs/configuration/download-client/qbit?QBITTORRENT__URL">QBITTORRENT__URL</Link>
|
||||
{`=http://localhost:8080
|
||||
# - `}
|
||||
<Link to="/docs/configuration/download-client/qbit?QBITTORRENT__URL_BASE">QBITTORRENT__URL_BASE</Link>
|
||||
{`=myCustomPath
|
||||
# - `}
|
||||
<Link to="/docs/configuration/download-client/qbit?QBITTORRENT__USERNAME">QBITTORRENT__USERNAME</Link>
|
||||
{`=user
|
||||
# - `}
|
||||
<Link to="/docs/configuration/download-client/qbit?QBITTORRENT__PASSWORD">QBITTORRENT__PASSWORD</Link>
|
||||
{`=pass
|
||||
# OR
|
||||
# - `}
|
||||
<Link to="/docs/configuration/download-client/general?DOWNLOAD_CLIENT">DOWNLOAD_CLIENT</Link>
|
||||
{`=deluge
|
||||
# - `}
|
||||
<Link to="/docs/configuration/download-client/deluge?DELUGE__URL">DELUGE__URL</Link>
|
||||
{`=http://localhost:8112
|
||||
# - `}
|
||||
<Link to="/docs/configuration/download-client/deluge?DELUGE__URL_BASE">DELUGE__URL_BASE</Link>
|
||||
{`=myCustomPath
|
||||
# - `}
|
||||
<Link to="/docs/configuration/download-client/deluge?DELUGE__PASSWORD">DELUGE__PASSWORD</Link>
|
||||
{`=pass
|
||||
# OR
|
||||
# - `}
|
||||
<Link to="/docs/configuration/download-client/general?DOWNLOAD_CLIENT">DOWNLOAD_CLIENT</Link>
|
||||
{`=transmission
|
||||
# - `}
|
||||
<Link to="/docs/configuration/download-client/transmission?TRANSMISSION__URL">TRANSMISSION__URL</Link>
|
||||
{`=http://localhost:9091
|
||||
# - `}
|
||||
<Link to="/docs/configuration/download-client/transmission?TRANSMISSION__URL_BASE">TRANSMISSION__URL_BASE</Link>
|
||||
{`=myCustomPath
|
||||
# - `}
|
||||
<Link to="/docs/configuration/download-client/transmission?TRANSMISSION__USERNAME">TRANSMISSION__USERNAME</Link>
|
||||
{`=user
|
||||
# - `}
|
||||
<Link to="/docs/configuration/download-client/transmission?TRANSMISSION__PASSWORD">TRANSMISSION__PASSWORD</Link>
|
||||
{`=pass
|
||||
|
||||
- `}
|
||||
<Link to="/docs/configuration/arrs/sonarr?SONARR__ENABLED">SONARR__ENABLED</Link>
|
||||
{`=true
|
||||
- `}
|
||||
<Link to="/docs/configuration/arrs/sonarr?SONARR__IMPORT_FAILED_MAX_STRIKES">SONARR__IMPORT_FAILED_MAX_STRIKES</Link>
|
||||
{`=-1
|
||||
- `}
|
||||
<Link to="/docs/configuration/arrs/sonarr?SONARR__SEARCHTYPE">SONARR__SEARCHTYPE</Link>
|
||||
{`=Episode
|
||||
- `}
|
||||
<Link to="/docs/configuration/arrs/sonarr?SONARR__BLOCK__TYPE">SONARR__BLOCK__TYPE</Link>
|
||||
{`=blacklist
|
||||
- `}
|
||||
<Link to="/docs/configuration/arrs/sonarr?SONARR__BLOCK__PATH">SONARR__BLOCK__PATH</Link>
|
||||
{`=https://example.com/path/to/file.txt
|
||||
- `}
|
||||
<Link to="/docs/configuration/arrs/sonarr?SONARR__INSTANCES__0__URL">SONARR__INSTANCES__0__URL</Link>
|
||||
{`=http://localhost:8989
|
||||
- `}
|
||||
<Link to="/docs/configuration/arrs/sonarr?SONARR__INSTANCES__0__APIKEY">SONARR__INSTANCES__0__APIKEY</Link>
|
||||
{`=sonarrSecret1
|
||||
- `}
|
||||
<Link to="/docs/configuration/arrs/sonarr?SONARR__INSTANCES__0__URL">SONARR__INSTANCES__1__URL</Link>
|
||||
{`=http://localhost:8990
|
||||
- `}
|
||||
<Link to="/docs/configuration/arrs/sonarr?SONARR__INSTANCES__0__APIKEY">SONARR__INSTANCES__1__APIKEY</Link>
|
||||
{`=sonarrSecret2
|
||||
|
||||
- `}
|
||||
<Link to="/docs/configuration/arrs/radarr?RADARR__ENABLED">RADARR__ENABLED</Link>
|
||||
{`=true
|
||||
- `}
|
||||
<Link to="/docs/configuration/arrs/radarr?RADARR__IMPORT_FAILED_MAX_STRIKES">RADARR__IMPORT_FAILED_MAX_STRIKES</Link>
|
||||
{`=-1
|
||||
- `}
|
||||
<Link to="/docs/configuration/arrs/radarr?RADARR__BLOCK__TYPE">RADARR__BLOCK__TYPE</Link>
|
||||
{`=blacklist
|
||||
- `}
|
||||
<Link to="/docs/configuration/arrs/radarr?RADARR__BLOCK__PATH">RADARR__BLOCK__PATH</Link>
|
||||
{`=https://example.com/path/to/file.txt
|
||||
- `}
|
||||
<Link to="/docs/configuration/arrs/radarr?RADARR__INSTANCES__0__URL">RADARR__INSTANCES__0__URL</Link>
|
||||
{`=http://localhost:7878
|
||||
- `}
|
||||
<Link to="/docs/configuration/arrs/radarr?RADARR__INSTANCES__0__APIKEY">RADARR__INSTANCES__0__APIKEY</Link>
|
||||
{`=radarrSecret1
|
||||
- `}
|
||||
<Link to="/docs/configuration/arrs/radarr?RADARR__INSTANCES__0__URL">RADARR__INSTANCES__1__URL</Link>
|
||||
{`=http://localhost:7879
|
||||
- `}
|
||||
<Link to="/docs/configuration/arrs/radarr?RADARR__INSTANCES__0__APIKEY">RADARR__INSTANCES__1__APIKEY</Link>
|
||||
{`=radarrSecret2
|
||||
|
||||
- `}
|
||||
<Link to="/docs/configuration/arrs/lidarr?LIDARR__ENABLED">LIDARR__ENABLED</Link>
|
||||
{`=true
|
||||
- `}
|
||||
<Link to="/docs/configuration/arrs/lidarr?LIDARR__IMPORT_FAILED_MAX_STRIKES">LIDARR__IMPORT_FAILED_MAX_STRIKES</Link>
|
||||
{`=-1
|
||||
- `}
|
||||
<Link to="/docs/configuration/arrs/lidarr?LIDARR__BLOCK__TYPE">LIDARR__BLOCK__TYPE</Link>
|
||||
{`=blacklist
|
||||
- `}
|
||||
<Link to="/docs/configuration/arrs/lidarr?LIDARR__BLOCK__PATH">LIDARR__BLOCK__PATH</Link>
|
||||
{`=https://example.com/path/to/file.txt
|
||||
- `}
|
||||
<Link to="/docs/configuration/arrs/lidarr?LIDARR__INSTANCES__0__URL">LIDARR__INSTANCES__0__URL</Link>
|
||||
{`=http://localhost:8686
|
||||
- `}
|
||||
<Link to="/docs/configuration/arrs/lidarr?LIDARR__INSTANCES__0__APIKEY">LIDARR__INSTANCES__0__APIKEY</Link>
|
||||
{`=lidarrSecret1
|
||||
- `}
|
||||
<Link to="/docs/configuration/arrs/lidarr?LIDARR__INSTANCES__0__URL">LIDARR__INSTANCES__1__URL</Link>
|
||||
{`=http://localhost:8687
|
||||
- `}
|
||||
<Link to="/docs/configuration/arrs/lidarr?LIDARR__INSTANCES__0__APIKEY">LIDARR__INSTANCES__1__APIKEY</Link>
|
||||
{`=lidarrSecret2
|
||||
|
||||
- `}
|
||||
<Link to="/docs/configuration/notifications/notifiarr?NOTIFIARR__ON_IMPORT_FAILED_STRIKE">NOTIFIARR__ON_IMPORT_FAILED_STRIKE</Link>
|
||||
{`=true
|
||||
- `}
|
||||
<Link to="/docs/configuration/notifications/notifiarr?NOTIFIARR__ON_STALLED_STRIKE">NOTIFIARR__ON_STALLED_STRIKE</Link>
|
||||
{`=true
|
||||
- `}
|
||||
<Link to="/docs/configuration/notifications/notifiarr?NOTIFIARR__ON_SLOW_STRIKE">NOTIFIARR__ON_SLOW_STRIKE</Link>
|
||||
{`=true
|
||||
- `}
|
||||
<Link to="/docs/configuration/notifications/notifiarr?NOTIFIARR__ON_QUEUE_ITEM_DELETED">NOTIFIARR__ON_QUEUE_ITEM_DELETED</Link>
|
||||
{`=true
|
||||
- `}
|
||||
<Link to="/docs/configuration/notifications/notifiarr?NOTIFIARR__ON_DOWNLOAD_CLEANED">NOTIFIARR__ON_DOWNLOAD_CLEANED</Link>
|
||||
{`=true
|
||||
- `}
|
||||
<Link to="/docs/configuration/notifications/notifiarr?NOTIFIARR__ON_CATEGORY_CHANGED">NOTIFIARR__ON_CATEGORY_CHANGED</Link>
|
||||
{`=true
|
||||
- `}
|
||||
<Link to="/docs/configuration/notifications/notifiarr?NOTIFIARR__API_KEY">NOTIFIARR__API_KEY</Link>
|
||||
{`=notifiarrSecret
|
||||
- `}
|
||||
<Link to="/docs/configuration/notifications/notifiarr?NOTIFIARR__CHANNEL_ID">NOTIFIARR__CHANNEL_ID</Link>
|
||||
{`=discordChannelId
|
||||
|
||||
- `}
|
||||
<Link to="/docs/configuration/notifications/apprise?APPRISE__ON_IMPORT_FAILED_STRIKE">APPRISE__ON_IMPORT_FAILED_STRIKE</Link>
|
||||
{`=true
|
||||
- `}
|
||||
<Link to="/docs/configuration/notifications/apprise?APPRISE__ON_STALLED_STRIKE">APPRISE__ON_STALLED_STRIKE</Link>
|
||||
{`=true
|
||||
- `}
|
||||
<Link to="/docs/configuration/notifications/apprise?APPRISE__ON_SLOW_STRIKE">APPRISE__ON_SLOW_STRIKE</Link>
|
||||
{`=true
|
||||
- `}
|
||||
<Link to="/docs/configuration/notifications/apprise?APPRISE__ON_QUEUE_ITEM_DELETED">APPRISE__ON_QUEUE_ITEM_DELETED</Link>
|
||||
{`=true
|
||||
- `}
|
||||
<Link to="/docs/configuration/notifications/apprise?APPRISE__ON_DOWNLOAD_CLEANED">APPRISE__ON_DOWNLOAD_CLEANED</Link>
|
||||
{`=true
|
||||
- `}
|
||||
<Link to="/docs/configuration/notifications/apprise?APPRISE__ON_CATEGORY_CHANGED">APPRISE__ON_CATEGORY_CHANGED</Link>
|
||||
{`=true
|
||||
- `}
|
||||
<Link to="/docs/configuration/notifications/apprise?APPRISE__URL">APPRISE__URL</Link>
|
||||
{`=http://apprise:8000
|
||||
- `}<Link to="/docs/configuration/notifications/apprise?NOTIFIARR__CHANNEL_ID">APPRISE__KEY</Link>
|
||||
{`=myConfigKey`}
|
||||
</div>
|
||||
</CodeBlock>
|
||||
@@ -1,9 +1,13 @@
|
||||
import { Note } from '@site/src/components/Admonition';
|
||||
|
||||
# Configuration file example (when not using Docker)
|
||||
# Configuration file (when not using Docker)
|
||||
|
||||
<Note>
|
||||
**This example contains all settings and should be modified to fit your needs.**
|
||||
This example contains all settings and should be modified to fit your needs.
|
||||
</Note>
|
||||
|
||||
<Note>
|
||||
Click on an environment variable's name to go to its documentation.
|
||||
</Note>
|
||||
|
||||
```
|
||||
@@ -20,6 +24,8 @@ import { Note } from '@site/src/components/Admonition';
|
||||
"Path": "/var/logs"
|
||||
}
|
||||
},
|
||||
"SEARCH_ENABLED": true,
|
||||
"SEARCH_DELAY": 30,
|
||||
"Triggers": {
|
||||
"QueueCleaner": "0 0/5 * * * ?",
|
||||
"ContentBlocker": "0 0/5 * * * ?",
|
||||
@@ -106,6 +112,7 @@ import { Note } from '@site/src/components/Admonition';
|
||||
},
|
||||
"Sonarr": {
|
||||
"Enabled": true,
|
||||
"IMPORT_FAILED_MAX_STRIKES=-1
|
||||
"SearchType": "Episode",
|
||||
"Block": {
|
||||
"Type": "blacklist",
|
||||
@@ -124,6 +131,7 @@ import { Note } from '@site/src/components/Admonition';
|
||||
},
|
||||
"Radarr": {
|
||||
"Enabled": true,
|
||||
"IMPORT_FAILED_MAX_STRIKES": -1,
|
||||
"Block": {
|
||||
"Type": "blacklist",
|
||||
"Path": "https://example.com/path/to/file.txt"
|
||||
@@ -141,6 +149,7 @@ import { Note } from '@site/src/components/Admonition';
|
||||
},
|
||||
"Lidarr": {
|
||||
"Enabled": true,
|
||||
"IMPORT_FAILED_MAX_STRIKES": -1,
|
||||
"Block": {
|
||||
"Type": "blacklist",
|
||||
"Path": "https://example.com/path/to/file.txt"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"label": "Configuration examples",
|
||||
"position": 8,
|
||||
"label": "Examples",
|
||||
"position": 1,
|
||||
"link": {
|
||||
"type": "generated-index"
|
||||
}
|
||||
|
||||
11
docs/docs/configuration/examples/examples.module.css
Normal file
11
docs/docs/configuration/examples/examples.module.css
Normal file
@@ -0,0 +1,11 @@
|
||||
[data-theme='light'] code a {
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
[data-theme='dark'] code a {
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
code a:hover {
|
||||
text-decoration: none;
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
{
|
||||
"label": "Notifications",
|
||||
"position": 7,
|
||||
"position": 8,
|
||||
"link": {
|
||||
"type": "generated-index",
|
||||
"description": "Settings for receiving notifications."
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,9 +3,15 @@ sidebar_position: 3
|
||||
---
|
||||
|
||||
import QueueCleanerStalledSettings from '@site/src/components/configuration/queue-cleaner/QueueCleanerStalledSettings';
|
||||
import { Important } from '@site/src/components/Admonition';
|
||||
import Link from '@docusaurus/Link';
|
||||
|
||||
# Stalled Downloads Settings
|
||||
|
||||
These settings control how the Queue Cleaner handles stalled downloads.
|
||||
|
||||
<Important>
|
||||
These settings need a <Link to="/docs/configuration/download-client/general?DOWNLOAD_CLIENT">download client</Link> to be configured.
|
||||
</Important>
|
||||
|
||||
<QueueCleanerStalledSettings/>
|
||||
@@ -3,9 +3,15 @@ sidebar_position: 4
|
||||
---
|
||||
|
||||
import QueueCleanerSlowSettings from '@site/src/components/configuration/queue-cleaner/QueueCleanerSlowSettings';
|
||||
import { Important } from '@site/src/components/Admonition';
|
||||
import Link from '@docusaurus/Link';
|
||||
|
||||
# Slow Downloads Settings
|
||||
|
||||
These settings control how the Queue Cleaner handles slow downloads.
|
||||
|
||||
<Important>
|
||||
These settings need a <Link to="/docs/configuration/download-client/general?DOWNLOAD_CLIENT">download client</Link> to be configured.
|
||||
</Important>
|
||||
|
||||
<QueueCleanerSlowSettings/>
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"label": "Queue Cleaner",
|
||||
"position": 1,
|
||||
"position": 3,
|
||||
"link": {
|
||||
"type": "generated-index",
|
||||
"description": "Settings for the Queue Cleaner functionality."
|
||||
|
||||
@@ -76,6 +76,28 @@ const config: Config = {
|
||||
theme: prismThemes.github,
|
||||
darkTheme: prismThemes.dracula,
|
||||
},
|
||||
algolia: {
|
||||
// The application ID provided by Algolia
|
||||
appId: 'Y4APRVTFUQ',
|
||||
|
||||
apiKey: 'bdaa942f24c8f4ed9893a5b5970405fa',
|
||||
|
||||
indexName: 'flmorgio',
|
||||
|
||||
// Optional: see doc section below
|
||||
contextualSearch: true,
|
||||
|
||||
// Optional: Algolia search parameters
|
||||
searchParameters: {},
|
||||
|
||||
// Optional: path for search page that enabled by default (`false` to disable it)
|
||||
searchPagePath: 'search',
|
||||
|
||||
// Optional: whether the insights feature is enabled or not on Docsearch (`false` by default)
|
||||
insights: true,
|
||||
|
||||
//... other Algolia params
|
||||
},
|
||||
} satisfies Preset.ThemeConfig,
|
||||
};
|
||||
|
||||
|
||||
35
docs/src/components/configuration/SearchSettings.tsx
Normal file
35
docs/src/components/configuration/SearchSettings.tsx
Normal file
@@ -0,0 +1,35 @@
|
||||
import React from "react";
|
||||
import EnvVars, { EnvVarProps } from "./EnvVars";
|
||||
|
||||
const settings: EnvVarProps[] = [
|
||||
{
|
||||
name: "SEARCH_ENABLED",
|
||||
description: [
|
||||
"Enabled searching for replacements after a download has been removed from an arr."
|
||||
],
|
||||
type: "boolean",
|
||||
defaultValue: "true",
|
||||
required: false,
|
||||
acceptedValues: ["true", "false"],
|
||||
notes: [
|
||||
"If you are using [Huntarr](https://github.com/plexguide/Huntarr.io), this setting should be set to false to let Huntarr do the searching.",
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "SEARCH_DELAY",
|
||||
description: [
|
||||
"If searching for replacements is enabled, this setting will delay the searches by the specified number of seconds.",
|
||||
"This is useful to avoid overwhelming the indexer with too many requests at once.",
|
||||
],
|
||||
type: "positive integer number",
|
||||
defaultValue: "30",
|
||||
required: false,
|
||||
important: [
|
||||
"A lower value or `0` will result in faster searches, but may cause issues such as being rate limited or banned by the indexer.",
|
||||
]
|
||||
},
|
||||
];
|
||||
|
||||
export default function SearchSettings() {
|
||||
return <EnvVars vars={settings} />;
|
||||
}
|
||||
@@ -12,6 +12,24 @@ const settings: EnvVarProps[] = [
|
||||
required: false,
|
||||
acceptedValues: ["true", "false"],
|
||||
},
|
||||
{
|
||||
name: "LIDARR__IMPORT_FAILED_MAX_STRIKES",
|
||||
description: [
|
||||
"Number of strikes before removing a failed import. Set to `0` to never remove failed imports.",
|
||||
"A strike is given when an item fails to be imported."
|
||||
],
|
||||
type: "integer number",
|
||||
defaultValue: "-1",
|
||||
required: false,
|
||||
notes: [
|
||||
"If the value is a positive number, it overwrites the values of [QUEUECLEANER__IMPORT_FAILED_MAX_STRIKES](/cleanuperr/docs/configuration/queue-cleaner/import-failed?QUEUECLEANER__IMPORT_FAILED_MAX_STRIKES).",
|
||||
"`0` means to never remove failed imports.",
|
||||
"If not set to `0` or a negative number, the minimum value is `3`.",
|
||||
],
|
||||
warnings: [
|
||||
"The value is not restricted to be a certain positive number. Use a low value (e.g. `1`) at your own risk."
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "LIDARR__BLOCK__TYPE",
|
||||
description: [
|
||||
|
||||
@@ -12,6 +12,24 @@ const settings: EnvVarProps[] = [
|
||||
required: false,
|
||||
acceptedValues: ["true", "false"],
|
||||
},
|
||||
{
|
||||
name: "RADARR__IMPORT_FAILED_MAX_STRIKES",
|
||||
description: [
|
||||
"Number of strikes before removing a failed import. Set to `0` to never remove failed imports.",
|
||||
"A strike is given when an item fails to be imported."
|
||||
],
|
||||
type: "integer number",
|
||||
defaultValue: "-1",
|
||||
required: false,
|
||||
notes: [
|
||||
"If the value is a positive number, it overwrites the values of [QUEUECLEANER__IMPORT_FAILED_MAX_STRIKES](/cleanuperr/docs/configuration/queue-cleaner/import-failed?QUEUECLEANER__IMPORT_FAILED_MAX_STRIKES).",
|
||||
"`0` means to never remove failed imports.",
|
||||
"If not set to `0` or a negative number, the minimum value is `3`.",
|
||||
],
|
||||
warnings: [
|
||||
"The value is not restricted to be a certain positive number. Use a low value (e.g. `1`) at your own risk."
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "RADARR__BLOCK__TYPE",
|
||||
description: [
|
||||
|
||||
@@ -12,6 +12,24 @@ const settings: EnvVarProps[] = [
|
||||
required: false,
|
||||
acceptedValues: ["true", "false"],
|
||||
},
|
||||
{
|
||||
name: "SONARR__IMPORT_FAILED_MAX_STRIKES",
|
||||
description: [
|
||||
"Number of strikes before removing a failed import. Set to `0` to never remove failed imports.",
|
||||
"A strike is given when an item fails to be imported."
|
||||
],
|
||||
type: "integer number",
|
||||
defaultValue: "-1",
|
||||
required: false,
|
||||
notes: [
|
||||
"If the value is a positive number, it overwrites the values of [QUEUECLEANER__IMPORT_FAILED_MAX_STRIKES](/cleanuperr/docs/configuration/queue-cleaner/import-failed?QUEUECLEANER__IMPORT_FAILED_MAX_STRIKES).",
|
||||
"`0` means to never remove failed imports.",
|
||||
"If not set to `0` or a negative number, the minimum value is `3`.",
|
||||
],
|
||||
warnings: [
|
||||
"The value is not restricted to be a certain positive number. Use a low value (e.g. `1`) at your own risk."
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "SONARR__BLOCK__TYPE",
|
||||
description: [
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
import React from "react";
|
||||
import EnvVars, { EnvVarProps } from "../EnvVars";
|
||||
|
||||
const settings: EnvVarProps[] = [
|
||||
{
|
||||
name: "DELUGE__URL",
|
||||
description: [
|
||||
"URL of the Deluge instance."
|
||||
],
|
||||
type: "text",
|
||||
defaultValue: "http://localhost:8112",
|
||||
required: false,
|
||||
examples: ["http://localhost:8112", "http://192.168.1.100:8112", "https://mydomain.com:8112"],
|
||||
},
|
||||
{
|
||||
name: "DELUGE__URL_BASE",
|
||||
description: [
|
||||
"Adds a prefix to the deluge json url, such as `[DELUGE__URL]/[DELUGE__URL_BASE]/json`."
|
||||
],
|
||||
type: "text",
|
||||
defaultValue: "Empty",
|
||||
required: false,
|
||||
},
|
||||
{
|
||||
name: "DELUGE__PASSWORD",
|
||||
description: [
|
||||
"Password for Deluge authentication."
|
||||
],
|
||||
type: "text",
|
||||
defaultValue: "Empty",
|
||||
required: false,
|
||||
},
|
||||
];
|
||||
|
||||
export default function DelugeSettings() {
|
||||
return <EnvVars vars={settings} />;
|
||||
}
|
||||
@@ -19,99 +19,6 @@ const settings: EnvVarProps[] = [
|
||||
"Setting `DOWNLOAD_CLIENT=disabled` means you don't care about seeding, ratio, H&R and potentially losing your private tracker account."
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "QBITTORRENT__URL",
|
||||
description: [
|
||||
"URL of the qBittorrent instance."
|
||||
],
|
||||
type: "text",
|
||||
defaultValue: "http://localhost:8080",
|
||||
required: false,
|
||||
examples: ["http://localhost:8080", "http://192.168.1.100:8080", "https://mydomain.com:8080"],
|
||||
},
|
||||
{
|
||||
name: "QBITTORRENT__URL_BASE",
|
||||
description: [
|
||||
"Adds a prefix to the qBittorrent url, such as `[QBITTORRENT__URL]/[QBITTORRENT__URL_BASE]/api`."
|
||||
],
|
||||
type: "text",
|
||||
defaultValue: "Empty",
|
||||
required: false,
|
||||
},
|
||||
{
|
||||
name: "QBITTORRENT__PASSWORD",
|
||||
description: [
|
||||
"Password for qBittorrent authentication."
|
||||
],
|
||||
type: "text",
|
||||
defaultValue: "Empty",
|
||||
required: false,
|
||||
},
|
||||
{
|
||||
name: "DELUGE__URL",
|
||||
description: [
|
||||
"URL of the Deluge instance."
|
||||
],
|
||||
type: "text",
|
||||
defaultValue: "http://localhost:8112",
|
||||
required: false,
|
||||
examples: ["http://localhost:8112", "http://192.168.1.100:8112", "https://mydomain.com:8112"],
|
||||
},
|
||||
{
|
||||
name: "DELUGE__URL_BASE",
|
||||
description: [
|
||||
"Adds a prefix to the deluge json url, such as `[DELUGE__URL]/[DELUGE__URL_BASE]/json`."
|
||||
],
|
||||
type: "text",
|
||||
defaultValue: "Empty",
|
||||
required: false,
|
||||
},
|
||||
{
|
||||
name: "DELUGE__PASSWORD",
|
||||
description: [
|
||||
"Password for Deluge authentication."
|
||||
],
|
||||
type: "text",
|
||||
defaultValue: "Empty",
|
||||
required: false,
|
||||
},
|
||||
{
|
||||
name: "TRANSMISSION__URL",
|
||||
description: [
|
||||
"URL of the Transmission instance."
|
||||
],
|
||||
type: "text",
|
||||
defaultValue: "http://localhost:9091",
|
||||
required: false,
|
||||
examples: ["http://localhost:9091", "http://192.168.1.100:9091", "https://mydomain.com:9091"],
|
||||
},
|
||||
{
|
||||
name: "TRANSMISSION__URL_BASE",
|
||||
description: [
|
||||
"Adds a prefix to the Transmission rpc url, such as `[TRANSMISSION__URL]/[TRANSMISSION__URL_BASE]/rpc`."
|
||||
],
|
||||
type: "text",
|
||||
defaultValue: "transmission",
|
||||
required: false,
|
||||
},
|
||||
{
|
||||
name: "TRANSMISSION__USERNAME",
|
||||
description: [
|
||||
"Username for Transmission authentication."
|
||||
],
|
||||
type: "text",
|
||||
defaultValue: "Empty",
|
||||
required: false,
|
||||
},
|
||||
{
|
||||
name: "TRANSMISSION__PASSWORD",
|
||||
description: [
|
||||
"Password for Transmission authentication."
|
||||
],
|
||||
type: "text",
|
||||
defaultValue: "Empty",
|
||||
required: false,
|
||||
}
|
||||
];
|
||||
|
||||
export default function DownloadClientSettings() {
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
import React from "react";
|
||||
import EnvVars, { EnvVarProps } from "../EnvVars";
|
||||
|
||||
const settings: EnvVarProps[] = [
|
||||
{
|
||||
name: "QBITTORRENT__URL",
|
||||
description: [
|
||||
"URL of the qBittorrent instance."
|
||||
],
|
||||
type: "text",
|
||||
defaultValue: "http://localhost:8080",
|
||||
required: false,
|
||||
examples: ["http://localhost:8080", "http://192.168.1.100:8080", "https://mydomain.com:8080"],
|
||||
},
|
||||
{
|
||||
name: "QBITTORRENT__URL_BASE",
|
||||
description: [
|
||||
"Adds a prefix to the qBittorrent url, such as `[QBITTORRENT__URL]/[QBITTORRENT__URL_BASE]/api`."
|
||||
],
|
||||
type: "text",
|
||||
defaultValue: "Empty",
|
||||
required: false,
|
||||
},
|
||||
{
|
||||
name: "QBITTORRENT__USERNAME",
|
||||
description: [
|
||||
"Username for qBittorrent authentication."
|
||||
],
|
||||
type: "text",
|
||||
defaultValue: "Empty",
|
||||
required: false,
|
||||
},
|
||||
{
|
||||
name: "QBITTORRENT__PASSWORD",
|
||||
description: [
|
||||
"Password for qBittorrent authentication."
|
||||
],
|
||||
type: "text",
|
||||
defaultValue: "Empty",
|
||||
required: false,
|
||||
},
|
||||
];
|
||||
|
||||
export default function QBittorrentSettings() {
|
||||
return <EnvVars vars={settings} />;
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
import React from "react";
|
||||
import EnvVars, { EnvVarProps } from "../EnvVars";
|
||||
|
||||
const settings: EnvVarProps[] = [
|
||||
{
|
||||
name: "TRANSMISSION__URL",
|
||||
description: [
|
||||
"URL of the Transmission instance."
|
||||
],
|
||||
type: "text",
|
||||
defaultValue: "http://localhost:9091",
|
||||
required: false,
|
||||
examples: ["http://localhost:9091", "http://192.168.1.100:9091", "https://mydomain.com:9091"],
|
||||
},
|
||||
{
|
||||
name: "TRANSMISSION__URL_BASE",
|
||||
description: [
|
||||
"Adds a prefix to the Transmission rpc url, such as `[TRANSMISSION__URL]/[TRANSMISSION__URL_BASE]/rpc`."
|
||||
],
|
||||
type: "text",
|
||||
defaultValue: "transmission",
|
||||
required: false,
|
||||
},
|
||||
{
|
||||
name: "TRANSMISSION__USERNAME",
|
||||
description: [
|
||||
"Username for Transmission authentication."
|
||||
],
|
||||
type: "text",
|
||||
defaultValue: "Empty",
|
||||
required: false,
|
||||
},
|
||||
{
|
||||
name: "TRANSMISSION__PASSWORD",
|
||||
description: [
|
||||
"Password for Transmission authentication."
|
||||
],
|
||||
type: "text",
|
||||
defaultValue: "Empty",
|
||||
required: false,
|
||||
}
|
||||
];
|
||||
|
||||
export default function TransmissionSettings() {
|
||||
return <EnvVars vars={settings} />;
|
||||
}
|
||||
Reference in New Issue
Block a user