mirror of
https://github.com/Cleanuparr/Cleanuparr.git
synced 2026-01-02 19:08:04 -05:00
Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
279bd6d82d | ||
|
|
5dced28228 | ||
|
|
51bdaf64e4 | ||
|
|
9c8e0ebedc | ||
|
|
e1bea8a8c8 | ||
|
|
a6d3820104 | ||
|
|
36c793a5fb |
47
README.md
47
README.md
@@ -8,12 +8,42 @@ cleanuperr is a tool for automating the cleanup of unwanted or blocked files in
|
||||
|
||||
cleanuperr was created primarily to address malicious files, such as `*.lnk` or `*.zipx`, that were getting stuck in Sonarr/Radarr and required manual intervention. Some of the reddit posts that made cleanuperr come to life can be found [here](https://www.reddit.com/r/sonarr/comments/1gqnx16/psa_sonarr_downloaded_a_virus/), [here](https://www.reddit.com/r/sonarr/comments/1gqwklr/sonar_downloaded_a_mkv_file_which_looked_like_a/), [here](https://www.reddit.com/r/sonarr/comments/1gpw2wa/downloaded_waiting_to_import/) and [here](https://www.reddit.com/r/sonarr/comments/1gpi344/downloads_not_importing_no_files_found/).
|
||||
|
||||
The tool 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.
|
||||
> [!IMPORTANT]
|
||||
> **Features:**
|
||||
> - Strike system to mark stalled or downloads stuck in metadata downloading.
|
||||
> - Remove and block downloads that reached a maximum number of strikes.
|
||||
> - 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.
|
||||
|
||||
#
|
||||
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.
|
||||
|
||||
> [!WARNING]
|
||||
> This tool is actively developed and still a work in progress, so using the `latest` Docker tag may result in breaking changes. Join the Discord server if you want to reach out to me quickly (or just stay updated on new releases) so we can squash those pesky bugs together:
|
||||
>
|
||||
> https://discord.gg/sWggpnmGNY
|
||||
|
||||
## Table of contents:
|
||||
- [Naming choice](README.md#naming-choice)
|
||||
- [Quick Start](README.md#quick-start)
|
||||
- [How it works](README.md#how-it-works)
|
||||
- [Setup](README.md#setup)
|
||||
- [Usage](README.md#usage)
|
||||
- [Docker Compose](README.md#docker-compose-yaml)
|
||||
- [Environment Variables](README.md#environment-variables)
|
||||
- [Binaries](README.md#binaries-if-youre-not-using-docker)
|
||||
- [Credits](README.md#credits)
|
||||
|
||||
## Naming choice
|
||||
|
||||
I've had people asking why it's `cleanuperr` and not `cleanuparr` and that I should change it. This name was intentional.
|
||||
|
||||
I've seen a few discussions on this type of naming and I've decided that I didn't deserve the `arr` moniker since `cleanuperr` is not a fork of `NZB.Drone` and it does not have any affiliation with the arrs. I still wanted to keep the naming style close enough though, to suggest a correlation between them.
|
||||
|
||||
## Quick Start
|
||||
|
||||
> [!NOTE]
|
||||
> ### Quick Start
|
||||
>
|
||||
> 1. **Docker (Recommended)**
|
||||
> Pull the Docker image from `ghcr.io/flmorg/cleanuperr:latest`.
|
||||
@@ -27,10 +57,6 @@ The tool supports both qBittorrent's built-in exclusion features and its own blo
|
||||
> [!TIP]
|
||||
> Refer to the [Environment variables](#Environment-variables) section for detailed configuration instructions and the [Setup](#Setup) section for an in-depth explanation of the cleanup process.
|
||||
|
||||
## Key features
|
||||
- Marks unwanted files as skip/unwanted in the download client.
|
||||
- Automatically strikes stalled or stuck downloads.
|
||||
- Removes and blocks downloads that reached the maximum number of strikes or are marked as unwanted by the download client or by cleanuperr and triggers a search for removed downloads.
|
||||
|
||||
> [!IMPORTANT]
|
||||
> Only the **latest versions** of the following apps are supported, or earlier versions that have the same API as the latest version:
|
||||
@@ -41,10 +67,6 @@ The tool supports both qBittorrent's built-in exclusion features and its own blo
|
||||
> - Radarr
|
||||
> - Lidarr
|
||||
|
||||
This tool is actively developed and still a work in progress, so using the `latest` Docker tag may result in breaking changes. Join the Discord server if you want to reach out to me quickly (or just stay updated on new releases) so we can squash those pesky bugs together:
|
||||
|
||||
> https://discord.gg/sWggpnmGNY
|
||||
|
||||
# How it works
|
||||
|
||||
1. **Content blocker** will:
|
||||
@@ -102,7 +124,8 @@ This tool is actively developed and still a work in progress, so using the `late
|
||||
3. Optionally set failed import message patterns to ignore using `QUEUECLEANER__IMPORT_FAILED_IGNORE_PATTERNS__<NUMBER>`.
|
||||
4. Set `DOWNLOAD_CLIENT` to `none`.
|
||||
|
||||
**No other action involving a download client would work (e.g. content blocking, removing stalled downloads, excluding private trackers).**
|
||||
> [!WARNING]
|
||||
> When `DOWNLOAD_CLIENT=none`, no other action involving a download client would work (e.g. content blocking, removing stalled downloads, excluding private trackers).
|
||||
|
||||
## Usage
|
||||
|
||||
|
||||
@@ -10,6 +10,9 @@ deployment:
|
||||
repository: ghcr.io/flmorg/cleanuperr
|
||||
tag: latest
|
||||
env:
|
||||
- name: DRY_RUN
|
||||
value: "false"
|
||||
|
||||
- name: LOGGING__LOGLEVEL
|
||||
value: Debug
|
||||
- name: LOGGING__FILE__ENABLED
|
||||
@@ -18,6 +21,7 @@ deployment:
|
||||
value: /var/logs
|
||||
- name: LOGGING__ENHANCED
|
||||
value: "true"
|
||||
|
||||
- name: TRIGGERS__QUEUECLEANER
|
||||
value: 0 0/5 * * * ?
|
||||
- name: TRIGGERS__CONTENTBLOCKER
|
||||
@@ -47,6 +51,9 @@ deployment:
|
||||
- name: CONTENTBLOCKER__DELETE_PRIVATE
|
||||
value: "false"
|
||||
|
||||
- name: DOWNLOADCLEANER__ENABLED
|
||||
value: "false"
|
||||
|
||||
- name: DOWNLOAD_CLIENT
|
||||
value: qbittorrent
|
||||
- name: QBITTORRENT__URL
|
||||
@@ -75,6 +82,17 @@ deployment:
|
||||
value: http://service.radarr-low-res.svc.cluster.local
|
||||
- name: RADARR__INSTANCES__1__URL
|
||||
value: http://service.radarr-high-res.svc.cluster.local
|
||||
|
||||
- name: NOTIFIARR__ON_IMPORT_FAILED_STRIKE
|
||||
value: "true"
|
||||
- name: NOTIFIARR__ON_STALLED_STRIKE
|
||||
value: "true"
|
||||
- name: NOTIFIARR__ON_QUEUE_ITEM_DELETED
|
||||
value: "true"
|
||||
- name: NOTIFIARR__ON_DOWNLOAD_CLEANED
|
||||
value: "true"
|
||||
- name: NOTIFIARR__CHANNEL_ID
|
||||
value: "1340708411259748413"
|
||||
envFromSecret:
|
||||
- secretName: qbit-auth
|
||||
envs:
|
||||
@@ -94,6 +112,10 @@ deployment:
|
||||
key: RDRL_API_KEY
|
||||
- name: RADARR__INSTANCES__1__APIKEY
|
||||
key: RDRH_API_KEY
|
||||
- secretName: notifiarr-auth
|
||||
envs:
|
||||
- name: NOTIFIARR__API_KEY
|
||||
key: API_KEY
|
||||
resources:
|
||||
requests:
|
||||
cpu: 0m
|
||||
@@ -133,4 +155,8 @@ vaultSecrets:
|
||||
path: secrets/sonarr
|
||||
templates:
|
||||
SNRL_API_KEY: "{% .Secrets.low_api_key %}"
|
||||
SNRH_API_KEY: "{% .Secrets.high_api_key %}"
|
||||
SNRH_API_KEY: "{% .Secrets.high_api_key %}"
|
||||
- name: notifiarr-auth
|
||||
path: secrets/notifiarr
|
||||
templates:
|
||||
API_KEY: "{% .Secrets.passthrough_api_key %}"
|
||||
@@ -1,8 +1,6 @@
|
||||
using System.Net;
|
||||
using Castle.DynamicProxy;
|
||||
using Common.Configuration.General;
|
||||
using Common.Helpers;
|
||||
using Infrastructure.Interceptors;
|
||||
using Infrastructure.Verticals.DownloadClient.Deluge;
|
||||
using Infrastructure.Verticals.Notifications.Consumers;
|
||||
using Infrastructure.Verticals.Notifications.Models;
|
||||
@@ -42,8 +40,7 @@ public static class MainDI
|
||||
e.PrefetchCount = 1;
|
||||
});
|
||||
});
|
||||
})
|
||||
.AddDryRunInterceptor();
|
||||
});
|
||||
|
||||
private static IServiceCollection AddHttpClients(this IServiceCollection services, IConfiguration configuration)
|
||||
{
|
||||
@@ -65,7 +62,7 @@ public static class MainDI
|
||||
services
|
||||
.AddHttpClient(nameof(DelugeService), x =>
|
||||
{
|
||||
x.Timeout = TimeSpan.FromSeconds(5);
|
||||
x.Timeout = TimeSpan.FromSeconds(config.Timeout);
|
||||
})
|
||||
.ConfigurePrimaryHttpMessageHandler(_ =>
|
||||
{
|
||||
@@ -91,31 +88,4 @@ public static class MainDI
|
||||
.OrResult(response => !response.IsSuccessStatusCode && response.StatusCode != HttpStatusCode.Unauthorized)
|
||||
.WaitAndRetryAsync(config.MaxRetries, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)))
|
||||
);
|
||||
|
||||
private static IServiceCollection AddDryRunInterceptor(this IServiceCollection services)
|
||||
{
|
||||
services
|
||||
.Where(s => s.ServiceType != typeof(IDryRunService) && typeof(IDryRunService).IsAssignableFrom(s.ServiceType))
|
||||
.ToList()
|
||||
.ForEach(service =>
|
||||
{
|
||||
services.Decorate(service.ServiceType, (target, svc) =>
|
||||
{
|
||||
ProxyGenerator proxyGenerator = new();
|
||||
DryRunAsyncInterceptor interceptor = svc.GetRequiredService<DryRunAsyncInterceptor>();
|
||||
|
||||
object implementation = proxyGenerator.CreateClassProxyWithTarget(
|
||||
service.ServiceType,
|
||||
target,
|
||||
interceptor
|
||||
);
|
||||
|
||||
((IInterceptedService)target).Proxy = implementation;
|
||||
|
||||
return implementation;
|
||||
});
|
||||
});
|
||||
|
||||
return services;
|
||||
}
|
||||
}
|
||||
@@ -10,7 +10,7 @@ public static class NotificationsDI
|
||||
.Configure<NotifiarrConfig>(configuration.GetSection(NotifiarrConfig.SectionName))
|
||||
.AddTransient<INotifiarrProxy, NotifiarrProxy>()
|
||||
.AddTransient<INotificationProvider, NotifiarrProvider>()
|
||||
.AddTransient<NotificationPublisher>()
|
||||
.AddTransient<INotificationPublisher, NotificationPublisher>()
|
||||
.AddTransient<INotificationFactory, NotificationFactory>()
|
||||
.AddTransient<NotificationService>();
|
||||
}
|
||||
@@ -15,7 +15,7 @@ public static class ServicesDI
|
||||
{
|
||||
public static IServiceCollection AddServices(this IServiceCollection services) =>
|
||||
services
|
||||
.AddTransient<DryRunAsyncInterceptor>()
|
||||
.AddTransient<IDryRunInterceptor, DryRunInterceptor>()
|
||||
.AddTransient<SonarrClient>()
|
||||
.AddTransient<RadarrClient>()
|
||||
.AddTransient<LidarrClient>()
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using Common.Configuration.ContentBlocker;
|
||||
using Common.Configuration.DownloadCleaner;
|
||||
using Common.Configuration.QueueCleaner;
|
||||
using Infrastructure.Interceptors;
|
||||
using Infrastructure.Verticals.ContentBlocker;
|
||||
using Infrastructure.Verticals.DownloadClient;
|
||||
using Infrastructure.Verticals.ItemStriker;
|
||||
@@ -53,7 +54,8 @@ public class DownloadServiceFixture : IDisposable
|
||||
downloadCleanerOptions.Value.Returns(new DownloadCleanerConfig());
|
||||
|
||||
var filenameEvaluator = Substitute.For<IFilenameEvaluator>();
|
||||
var notifier = Substitute.For<NotificationPublisher>();
|
||||
var notifier = Substitute.For<INotificationPublisher>();
|
||||
var dryRunInterceptor = Substitute.For<IDryRunInterceptor>();
|
||||
|
||||
return new TestDownloadService(
|
||||
Logger,
|
||||
@@ -63,7 +65,8 @@ public class DownloadServiceFixture : IDisposable
|
||||
Cache,
|
||||
filenameEvaluator,
|
||||
Striker,
|
||||
notifier
|
||||
notifier,
|
||||
dryRunInterceptor
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.Text.RegularExpressions;
|
||||
using Common.Configuration.ContentBlocker;
|
||||
using Common.Configuration.DownloadCleaner;
|
||||
using Common.Configuration.QueueCleaner;
|
||||
using Infrastructure.Interceptors;
|
||||
using Infrastructure.Verticals.ContentBlocker;
|
||||
using Infrastructure.Verticals.DownloadClient;
|
||||
using Infrastructure.Verticals.ItemStriker;
|
||||
@@ -23,9 +24,12 @@ public class TestDownloadService : DownloadService
|
||||
IMemoryCache cache,
|
||||
IFilenameEvaluator filenameEvaluator,
|
||||
IStriker striker,
|
||||
NotificationPublisher notifier)
|
||||
: base(logger, queueCleanerConfig, contentBlockerConfig, downloadCleanerConfig,
|
||||
cache, filenameEvaluator, striker, notifier)
|
||||
INotificationPublisher notifier,
|
||||
IDryRunInterceptor dryRunInterceptor
|
||||
) : base(
|
||||
logger, queueCleanerConfig, contentBlockerConfig, downloadCleanerConfig, cache,
|
||||
filenameEvaluator, striker, notifier, dryRunInterceptor
|
||||
)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Castle.Core.AsyncInterceptor" Version="2.1.0" />
|
||||
<PackageReference Include="FLM.QBittorrent" Version="1.0.0" />
|
||||
<PackageReference Include="FLM.Transmission" Version="1.0.2" />
|
||||
<PackageReference Include="Mapster" Version="7.4.0" />
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using System.Reflection;
|
||||
using Castle.DynamicProxy;
|
||||
using Common.Attributes;
|
||||
using Common.Configuration.General;
|
||||
using Microsoft.Extensions.Logging;
|
||||
@@ -7,41 +6,70 @@ using Microsoft.Extensions.Options;
|
||||
|
||||
namespace Infrastructure.Interceptors;
|
||||
|
||||
public class DryRunAsyncInterceptor : AsyncInterceptorBase
|
||||
public class DryRunInterceptor : IDryRunInterceptor
|
||||
{
|
||||
private readonly ILogger<DryRunAsyncInterceptor> _logger;
|
||||
private readonly ILogger<DryRunInterceptor> _logger;
|
||||
private readonly DryRunConfig _config;
|
||||
|
||||
public DryRunAsyncInterceptor(ILogger<DryRunAsyncInterceptor> logger, IOptions<DryRunConfig> config)
|
||||
public DryRunInterceptor(ILogger<DryRunInterceptor> logger, IOptions<DryRunConfig> config)
|
||||
{
|
||||
_logger = logger;
|
||||
_config = config.Value;
|
||||
}
|
||||
|
||||
protected override async Task InterceptAsync(IInvocation invocation, IInvocationProceedInfo proceedInfo, Func<IInvocation, IInvocationProceedInfo, Task> proceed)
|
||||
public void Intercept(Action action)
|
||||
{
|
||||
MethodInfo? method = invocation.MethodInvocationTarget ?? invocation.Method;
|
||||
if (IsDryRun(method))
|
||||
MethodInfo methodInfo = action.Method;
|
||||
|
||||
if (IsDryRun(methodInfo))
|
||||
{
|
||||
_logger.LogInformation("[DRY RUN] skipping method: {name}", method.Name);
|
||||
_logger.LogInformation("[DRY RUN] skipping method: {name}", methodInfo.Name);
|
||||
return;
|
||||
}
|
||||
|
||||
await proceed(invocation, proceedInfo);
|
||||
action();
|
||||
}
|
||||
|
||||
protected override async Task<TResult> InterceptAsync<TResult>(IInvocation invocation, IInvocationProceedInfo proceedInfo, Func<IInvocation, IInvocationProceedInfo, Task<TResult>> proceed)
|
||||
|
||||
public Task InterceptAsync(Delegate action, params object[] parameters)
|
||||
{
|
||||
MethodInfo? method = invocation.MethodInvocationTarget ?? invocation.Method;
|
||||
if (IsDryRun(method))
|
||||
MethodInfo methodInfo = action.Method;
|
||||
|
||||
if (IsDryRun(methodInfo))
|
||||
{
|
||||
_logger.LogInformation("[DRY RUN] skipping method: {name}", method.Name);
|
||||
return default!;
|
||||
_logger.LogInformation("[DRY RUN] skipping method: {name}", methodInfo.Name);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
return await proceed(invocation, proceedInfo);
|
||||
}
|
||||
object? result = action.DynamicInvoke(parameters);
|
||||
|
||||
if (result is Task task)
|
||||
{
|
||||
return task;
|
||||
}
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public Task<T?> InterceptAsync<T>(Delegate action, params object[] parameters)
|
||||
{
|
||||
MethodInfo methodInfo = action.Method;
|
||||
|
||||
if (IsDryRun(methodInfo))
|
||||
{
|
||||
_logger.LogInformation("[DRY RUN] skipping method: {name}", methodInfo.Name);
|
||||
return Task.FromResult(default(T));
|
||||
}
|
||||
|
||||
object? result = action.DynamicInvoke(parameters);
|
||||
|
||||
if (result is Task<T?> task)
|
||||
{
|
||||
return task;
|
||||
}
|
||||
|
||||
return Task.FromResult(default(T));
|
||||
}
|
||||
|
||||
private bool IsDryRun(MethodInfo method)
|
||||
{
|
||||
return method.GetCustomAttributes(typeof(DryRunSafeguardAttribute), true).Any() && _config.IsDryRun;
|
||||
|
||||
10
code/Infrastructure/Interceptors/IDryRunInterceptor.cs
Normal file
10
code/Infrastructure/Interceptors/IDryRunInterceptor.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
namespace Infrastructure.Interceptors;
|
||||
|
||||
public interface IDryRunInterceptor
|
||||
{
|
||||
void Intercept(Action action);
|
||||
|
||||
Task InterceptAsync(Delegate action, params object[] parameters);
|
||||
|
||||
Task<T?> InterceptAsync<T>(Delegate action, params object[] parameters);
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
namespace Infrastructure.Interceptors;
|
||||
|
||||
public interface IDryRunService : IInterceptedService
|
||||
{
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
namespace Infrastructure.Interceptors;
|
||||
|
||||
public interface IInterceptedService
|
||||
{
|
||||
public object Proxy { get; set; }
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
namespace Infrastructure.Interceptors;
|
||||
|
||||
public class InterceptedService : IInterceptedService
|
||||
{
|
||||
private object? _proxy;
|
||||
|
||||
public object Proxy
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_proxy is null)
|
||||
{
|
||||
throw new Exception("Proxy is not set");
|
||||
}
|
||||
|
||||
return _proxy;
|
||||
}
|
||||
|
||||
set => _proxy = value;
|
||||
}
|
||||
}
|
||||
@@ -15,27 +15,22 @@ using Newtonsoft.Json;
|
||||
|
||||
namespace Infrastructure.Verticals.Arr;
|
||||
|
||||
public abstract class ArrClient : InterceptedService, IArrClient, IDryRunService
|
||||
public abstract class ArrClient : IArrClient
|
||||
{
|
||||
protected readonly ILogger<ArrClient> _logger;
|
||||
protected readonly HttpClient _httpClient;
|
||||
protected readonly LoggingConfig _loggingConfig;
|
||||
protected readonly QueueCleanerConfig _queueCleanerConfig;
|
||||
protected readonly IStriker _striker;
|
||||
|
||||
/// <summary>
|
||||
/// Constructor to be used by interceptors.
|
||||
/// </summary>
|
||||
protected ArrClient()
|
||||
{
|
||||
}
|
||||
protected readonly IDryRunInterceptor _dryRunInterceptor;
|
||||
|
||||
protected ArrClient(
|
||||
ILogger<ArrClient> logger,
|
||||
IHttpClientFactory httpClientFactory,
|
||||
IOptions<LoggingConfig> loggingConfig,
|
||||
IOptions<QueueCleanerConfig> queueCleanerConfig,
|
||||
IStriker striker
|
||||
IStriker striker,
|
||||
IDryRunInterceptor dryRunInterceptor
|
||||
)
|
||||
{
|
||||
_logger = logger;
|
||||
@@ -43,6 +38,7 @@ public abstract class ArrClient : InterceptedService, IArrClient, IDryRunService
|
||||
_loggingConfig = loggingConfig.Value;
|
||||
_queueCleanerConfig = queueCleanerConfig.Value;
|
||||
_striker = striker;
|
||||
_dryRunInterceptor = dryRunInterceptor;
|
||||
}
|
||||
|
||||
public virtual async Task<QueueListResponse> GetQueueItemsAsync(ArrInstance arrInstance, int page)
|
||||
@@ -125,7 +121,8 @@ public abstract class ArrClient : InterceptedService, IArrClient, IDryRunService
|
||||
using HttpRequestMessage request = new(HttpMethod.Delete, uri);
|
||||
SetApiKey(request, arrInstance.ApiKey);
|
||||
|
||||
using var _ = await ((ArrClient)Proxy).SendRequestAsync(request);
|
||||
HttpResponseMessage? response = await _dryRunInterceptor.InterceptAsync<HttpResponseMessage>(SendRequestAsync, request);
|
||||
response?.Dispose();
|
||||
|
||||
_logger.LogInformation(
|
||||
removeFromClient
|
||||
|
||||
@@ -5,6 +5,7 @@ using Common.Configuration.QueueCleaner;
|
||||
using Domain.Models.Arr;
|
||||
using Domain.Models.Arr.Queue;
|
||||
using Domain.Models.Lidarr;
|
||||
using Infrastructure.Interceptors;
|
||||
using Infrastructure.Verticals.Arr.Interfaces;
|
||||
using Infrastructure.Verticals.ItemStriker;
|
||||
using Microsoft.Extensions.Logging;
|
||||
@@ -15,18 +16,14 @@ namespace Infrastructure.Verticals.Arr;
|
||||
|
||||
public class LidarrClient : ArrClient, ILidarrClient
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public LidarrClient()
|
||||
{
|
||||
}
|
||||
|
||||
public LidarrClient(
|
||||
ILogger<LidarrClient> logger,
|
||||
IHttpClientFactory httpClientFactory,
|
||||
IOptions<LoggingConfig> loggingConfig,
|
||||
IOptions<QueueCleanerConfig> queueCleanerConfig,
|
||||
IStriker striker
|
||||
) : base(logger, httpClientFactory, loggingConfig, queueCleanerConfig, striker)
|
||||
IStriker striker,
|
||||
IDryRunInterceptor dryRunInterceptor
|
||||
) : base(logger, httpClientFactory, loggingConfig, queueCleanerConfig, striker, dryRunInterceptor)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -64,7 +61,8 @@ public class LidarrClient : ArrClient, ILidarrClient
|
||||
|
||||
try
|
||||
{
|
||||
using var _ = await ((LidarrClient)Proxy).SendRequestAsync(request);
|
||||
HttpResponseMessage? response = await _dryRunInterceptor.InterceptAsync<HttpResponseMessage>(SendRequestAsync, request);
|
||||
response?.Dispose();
|
||||
|
||||
_logger.LogInformation("{log}", GetSearchLog(arrInstance.Url, command, true, logContext));
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ using Common.Configuration.QueueCleaner;
|
||||
using Domain.Models.Arr;
|
||||
using Domain.Models.Arr.Queue;
|
||||
using Domain.Models.Radarr;
|
||||
using Infrastructure.Interceptors;
|
||||
using Infrastructure.Verticals.Arr.Interfaces;
|
||||
using Infrastructure.Verticals.ItemStriker;
|
||||
using Microsoft.Extensions.Logging;
|
||||
@@ -15,18 +16,14 @@ namespace Infrastructure.Verticals.Arr;
|
||||
|
||||
public class RadarrClient : ArrClient, IRadarrClient
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public RadarrClient()
|
||||
{
|
||||
}
|
||||
|
||||
public RadarrClient(
|
||||
ILogger<ArrClient> logger,
|
||||
IHttpClientFactory httpClientFactory,
|
||||
IOptions<LoggingConfig> loggingConfig,
|
||||
IOptions<QueueCleanerConfig> queueCleanerConfig,
|
||||
IStriker striker
|
||||
) : base(logger, httpClientFactory, loggingConfig, queueCleanerConfig, striker)
|
||||
IStriker striker,
|
||||
IDryRunInterceptor dryRunInterceptor
|
||||
) : base(logger, httpClientFactory, loggingConfig, queueCleanerConfig, striker, dryRunInterceptor)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -72,7 +69,8 @@ public class RadarrClient : ArrClient, IRadarrClient
|
||||
|
||||
try
|
||||
{
|
||||
using var _ = await ((RadarrClient)Proxy).SendRequestAsync(request);
|
||||
HttpResponseMessage? response = await _dryRunInterceptor.InterceptAsync<HttpResponseMessage>(SendRequestAsync, request);
|
||||
response?.Dispose();
|
||||
|
||||
_logger.LogInformation("{log}", GetSearchLog(arrInstance.Url, command, true, logContext));
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ using Common.Configuration.QueueCleaner;
|
||||
using Domain.Models.Arr;
|
||||
using Domain.Models.Arr.Queue;
|
||||
using Domain.Models.Sonarr;
|
||||
using Infrastructure.Interceptors;
|
||||
using Infrastructure.Verticals.Arr.Interfaces;
|
||||
using Infrastructure.Verticals.ItemStriker;
|
||||
using Microsoft.Extensions.Logging;
|
||||
@@ -16,18 +17,14 @@ namespace Infrastructure.Verticals.Arr;
|
||||
|
||||
public class SonarrClient : ArrClient, ISonarrClient
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public SonarrClient()
|
||||
{
|
||||
}
|
||||
|
||||
public SonarrClient(
|
||||
ILogger<SonarrClient> logger,
|
||||
IHttpClientFactory httpClientFactory,
|
||||
IOptions<LoggingConfig> loggingConfig,
|
||||
IOptions<QueueCleanerConfig> queueCleanerConfig,
|
||||
IStriker striker
|
||||
) : base(logger, httpClientFactory, loggingConfig, queueCleanerConfig, striker)
|
||||
IStriker striker,
|
||||
IDryRunInterceptor dryRunInterceptor
|
||||
) : base(logger, httpClientFactory, loggingConfig, queueCleanerConfig, striker, dryRunInterceptor)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -68,8 +65,9 @@ public class SonarrClient : ArrClient, ISonarrClient
|
||||
|
||||
try
|
||||
{
|
||||
using var _ = await ((SonarrClient)Proxy).SendRequestAsync(request);
|
||||
|
||||
HttpResponseMessage? response = await _dryRunInterceptor.InterceptAsync<HttpResponseMessage>(SendRequestAsync, request);
|
||||
response?.Dispose();
|
||||
|
||||
_logger.LogInformation("{log}", GetSearchLog(command.SearchType, arrInstance.Url, command, true, logContext));
|
||||
}
|
||||
catch
|
||||
|
||||
@@ -36,7 +36,7 @@ public sealed class ContentBlocker : GenericHandler
|
||||
ArrQueueIterator arrArrQueueIterator,
|
||||
BlocklistProvider blocklistProvider,
|
||||
DownloadServiceFactory downloadServiceFactory,
|
||||
NotificationPublisher notifier
|
||||
INotificationPublisher notifier
|
||||
) : base(
|
||||
logger, downloadClientConfig,
|
||||
sonarrConfig, radarrConfig, lidarrConfig,
|
||||
|
||||
@@ -31,7 +31,7 @@ public sealed class DownloadCleaner : GenericHandler
|
||||
LidarrClient lidarrClient,
|
||||
ArrQueueIterator arrArrQueueIterator,
|
||||
DownloadServiceFactory downloadServiceFactory,
|
||||
NotificationPublisher notifier
|
||||
INotificationPublisher notifier
|
||||
) : base(
|
||||
logger, downloadClientConfig,
|
||||
sonarrConfig, radarrConfig, lidarrConfig,
|
||||
@@ -46,6 +46,12 @@ public sealed class DownloadCleaner : GenericHandler
|
||||
|
||||
public override async Task ExecuteAsync()
|
||||
{
|
||||
if (_downloadClientConfig.DownloadClient is Common.Enums.DownloadClient.None)
|
||||
{
|
||||
_logger.LogWarning("download client is set to none");
|
||||
return;
|
||||
}
|
||||
|
||||
if (_config.Categories?.Count is null or 0)
|
||||
{
|
||||
_logger.LogWarning("no categories configured");
|
||||
|
||||
@@ -7,11 +7,11 @@ using Common.Configuration.DownloadClient;
|
||||
using Common.Configuration.QueueCleaner;
|
||||
using Domain.Enums;
|
||||
using Domain.Models.Deluge.Response;
|
||||
using Infrastructure.Interceptors;
|
||||
using Infrastructure.Verticals.ContentBlocker;
|
||||
using Infrastructure.Verticals.Context;
|
||||
using Infrastructure.Verticals.ItemStriker;
|
||||
using Infrastructure.Verticals.Notifications;
|
||||
using MassTransit.Configuration;
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
@@ -22,11 +22,6 @@ public class DelugeService : DownloadService, IDelugeService
|
||||
{
|
||||
private readonly DelugeClient _client;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public DelugeService()
|
||||
{
|
||||
}
|
||||
|
||||
public DelugeService(
|
||||
ILogger<DelugeService> logger,
|
||||
IOptions<DelugeConfig> config,
|
||||
@@ -37,8 +32,12 @@ public class DelugeService : DownloadService, IDelugeService
|
||||
IMemoryCache cache,
|
||||
IFilenameEvaluator filenameEvaluator,
|
||||
IStriker striker,
|
||||
NotificationPublisher notifier
|
||||
) : base(logger, queueCleanerConfig, contentBlockerConfig, downloadCleanerConfig, cache, filenameEvaluator, striker, notifier)
|
||||
INotificationPublisher notifier,
|
||||
IDryRunInterceptor dryRunInterceptor
|
||||
) : base(
|
||||
logger, queueCleanerConfig, contentBlockerConfig, downloadCleanerConfig, cache,
|
||||
filenameEvaluator, striker, notifier, dryRunInterceptor
|
||||
)
|
||||
{
|
||||
config.Value.Validate();
|
||||
_client = new (config, httpClientFactory);
|
||||
@@ -190,7 +189,7 @@ public class DelugeService : DownloadService, IDelugeService
|
||||
return result;
|
||||
}
|
||||
|
||||
await ((DelugeService)Proxy).ChangeFilesPriority(hash, sortedPriorities);
|
||||
await _dryRunInterceptor.InterceptAsync(ChangeFilesPriority, hash, sortedPriorities);
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -245,8 +244,8 @@ public class DelugeService : DownloadService, IDelugeService
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
await ((DelugeService)Proxy).DeleteDownload(download.Hash);
|
||||
|
||||
await _dryRunInterceptor.InterceptAsync(DeleteDownload, download.Hash);
|
||||
|
||||
_logger.LogInformation(
|
||||
"download cleaned | {reason} reached | {name}",
|
||||
|
||||
@@ -18,7 +18,7 @@ using Microsoft.Extensions.Options;
|
||||
|
||||
namespace Infrastructure.Verticals.DownloadClient;
|
||||
|
||||
public abstract class DownloadService : InterceptedService, IDownloadService
|
||||
public abstract class DownloadService : IDownloadService
|
||||
{
|
||||
protected readonly ILogger<DownloadService> _logger;
|
||||
protected readonly QueueCleanerConfig _queueCleanerConfig;
|
||||
@@ -28,15 +28,9 @@ public abstract class DownloadService : InterceptedService, IDownloadService
|
||||
protected readonly IFilenameEvaluator _filenameEvaluator;
|
||||
protected readonly IStriker _striker;
|
||||
protected readonly MemoryCacheEntryOptions _cacheOptions;
|
||||
protected readonly NotificationPublisher _notifier;
|
||||
protected readonly INotificationPublisher _notifier;
|
||||
protected readonly IDryRunInterceptor _dryRunInterceptor;
|
||||
|
||||
/// <summary>
|
||||
/// Constructor to be used by interceptors.
|
||||
/// </summary>
|
||||
protected DownloadService()
|
||||
{
|
||||
}
|
||||
|
||||
protected DownloadService(
|
||||
ILogger<DownloadService> logger,
|
||||
IOptions<QueueCleanerConfig> queueCleanerConfig,
|
||||
@@ -45,7 +39,9 @@ public abstract class DownloadService : InterceptedService, IDownloadService
|
||||
IMemoryCache cache,
|
||||
IFilenameEvaluator filenameEvaluator,
|
||||
IStriker striker,
|
||||
NotificationPublisher notifier)
|
||||
INotificationPublisher notifier,
|
||||
IDryRunInterceptor dryRunInterceptor
|
||||
)
|
||||
{
|
||||
_logger = logger;
|
||||
_queueCleanerConfig = queueCleanerConfig.Value;
|
||||
@@ -55,6 +51,7 @@ public abstract class DownloadService : InterceptedService, IDownloadService
|
||||
_filenameEvaluator = filenameEvaluator;
|
||||
_striker = striker;
|
||||
_notifier = notifier;
|
||||
_dryRunInterceptor = dryRunInterceptor;
|
||||
_cacheOptions = new MemoryCacheEntryOptions()
|
||||
.SetSlidingExpiration(StaticConfiguration.TriggerValue + Constants.CacheLimitBuffer);
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.Text.RegularExpressions;
|
||||
using Common.Configuration.ContentBlocker;
|
||||
using Common.Configuration.DownloadCleaner;
|
||||
using Common.Configuration.QueueCleaner;
|
||||
using Infrastructure.Interceptors;
|
||||
using Infrastructure.Verticals.ContentBlocker;
|
||||
using Infrastructure.Verticals.ItemStriker;
|
||||
using Infrastructure.Verticals.Notifications;
|
||||
@@ -14,12 +15,7 @@ namespace Infrastructure.Verticals.DownloadClient;
|
||||
|
||||
public class DummyDownloadService : DownloadService
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public DummyDownloadService()
|
||||
{
|
||||
}
|
||||
|
||||
public DummyDownloadService(ILogger<DownloadService> logger, IOptions<QueueCleanerConfig> queueCleanerConfig, IOptions<ContentBlockerConfig> contentBlockerConfig, IOptions<DownloadCleanerConfig> downloadCleanerConfig, IMemoryCache cache, IFilenameEvaluator filenameEvaluator, IStriker striker, NotificationPublisher notifier) : base(logger, queueCleanerConfig, contentBlockerConfig, downloadCleanerConfig, cache, filenameEvaluator, striker, notifier)
|
||||
public DummyDownloadService(ILogger<DownloadService> logger, IOptions<QueueCleanerConfig> queueCleanerConfig, IOptions<ContentBlockerConfig> contentBlockerConfig, IOptions<DownloadCleanerConfig> downloadCleanerConfig, IMemoryCache cache, IFilenameEvaluator filenameEvaluator, IStriker striker, INotificationPublisher notifier, IDryRunInterceptor dryRunInterceptor) : base(logger, queueCleanerConfig, contentBlockerConfig, downloadCleanerConfig, cache, filenameEvaluator, striker, notifier, dryRunInterceptor)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ using Infrastructure.Interceptors;
|
||||
|
||||
namespace Infrastructure.Verticals.DownloadClient;
|
||||
|
||||
public interface IDownloadService : IDisposable, IDryRunService
|
||||
public interface IDownloadService : IDisposable
|
||||
{
|
||||
public Task LoginAsync();
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
namespace Infrastructure.Verticals.DownloadClient.QBittorrent;
|
||||
|
||||
public interface IQBitService : IDownloadService
|
||||
public interface IQBitService : IDownloadService, IDisposable
|
||||
{
|
||||
}
|
||||
@@ -7,6 +7,7 @@ using Common.Configuration.DownloadClient;
|
||||
using Common.Configuration.QueueCleaner;
|
||||
using Common.Helpers;
|
||||
using Domain.Enums;
|
||||
using Infrastructure.Interceptors;
|
||||
using Infrastructure.Verticals.ContentBlocker;
|
||||
using Infrastructure.Verticals.Context;
|
||||
using Infrastructure.Verticals.ItemStriker;
|
||||
@@ -24,11 +25,6 @@ public class QBitService : DownloadService, IQBitService
|
||||
private readonly QBitConfig _config;
|
||||
private readonly QBittorrentClient _client;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public QBitService()
|
||||
{
|
||||
}
|
||||
|
||||
public QBitService(
|
||||
ILogger<QBitService> logger,
|
||||
IHttpClientFactory httpClientFactory,
|
||||
@@ -39,8 +35,12 @@ public class QBitService : DownloadService, IQBitService
|
||||
IMemoryCache cache,
|
||||
IFilenameEvaluator filenameEvaluator,
|
||||
IStriker striker,
|
||||
NotificationPublisher notifier
|
||||
) : base(logger, queueCleanerConfig, contentBlockerConfig, downloadCleanerConfig, cache, filenameEvaluator, striker, notifier)
|
||||
INotificationPublisher notifier,
|
||||
IDryRunInterceptor dryRunInterceptor
|
||||
) : base(
|
||||
logger, queueCleanerConfig, contentBlockerConfig, downloadCleanerConfig, cache,
|
||||
filenameEvaluator, striker, notifier, dryRunInterceptor
|
||||
)
|
||||
{
|
||||
_config = config.Value;
|
||||
_config.Validate();
|
||||
@@ -200,7 +200,7 @@ public class QBitService : DownloadService, IQBitService
|
||||
|
||||
foreach (int fileIndex in unwantedFiles)
|
||||
{
|
||||
await ((QBitService)Proxy).SkipFile(hash, fileIndex);
|
||||
await _dryRunInterceptor.InterceptAsync(SkipFile, hash, fileIndex);
|
||||
}
|
||||
|
||||
return result;
|
||||
@@ -272,7 +272,7 @@ public class QBitService : DownloadService, IQBitService
|
||||
continue;
|
||||
}
|
||||
|
||||
await ((QBitService)Proxy).DeleteDownload(download.Hash);
|
||||
await _dryRunInterceptor.InterceptAsync(DeleteDownload, download.Hash);
|
||||
|
||||
_logger.LogInformation(
|
||||
"download cleaned | {reason} reached | {name}",
|
||||
|
||||
@@ -7,6 +7,7 @@ using Common.Configuration.DownloadClient;
|
||||
using Common.Configuration.QueueCleaner;
|
||||
using Common.Helpers;
|
||||
using Domain.Enums;
|
||||
using Infrastructure.Interceptors;
|
||||
using Infrastructure.Verticals.ContentBlocker;
|
||||
using Infrastructure.Verticals.Context;
|
||||
using Infrastructure.Verticals.ItemStriker;
|
||||
@@ -26,11 +27,6 @@ public class TransmissionService : DownloadService, ITransmissionService
|
||||
private readonly Client _client;
|
||||
private TorrentInfo[]? _torrentsCache;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public TransmissionService()
|
||||
{
|
||||
}
|
||||
|
||||
public TransmissionService(
|
||||
IHttpClientFactory httpClientFactory,
|
||||
ILogger<TransmissionService> logger,
|
||||
@@ -41,8 +37,12 @@ public class TransmissionService : DownloadService, ITransmissionService
|
||||
IMemoryCache cache,
|
||||
IFilenameEvaluator filenameEvaluator,
|
||||
IStriker striker,
|
||||
NotificationPublisher notifier
|
||||
) : base(logger, queueCleanerConfig, contentBlockerConfig, downloadCleanerConfig, cache, filenameEvaluator, striker, notifier)
|
||||
INotificationPublisher notifier,
|
||||
IDryRunInterceptor dryRunInterceptor
|
||||
) : base(
|
||||
logger, queueCleanerConfig, contentBlockerConfig, downloadCleanerConfig, cache,
|
||||
filenameEvaluator, striker, notifier, dryRunInterceptor
|
||||
)
|
||||
{
|
||||
_config = config.Value;
|
||||
_config.Validate();
|
||||
@@ -174,8 +174,8 @@ public class TransmissionService : DownloadService, ITransmissionService
|
||||
}
|
||||
|
||||
_logger.LogDebug("changing priorities | torrent {hash}", hash);
|
||||
|
||||
await ((TransmissionService)Proxy).SetUnwantedFiles(torrent.Id, unwantedFiles.ToArray());
|
||||
|
||||
await _dryRunInterceptor.InterceptAsync(SetUnwantedFiles, torrent.Id, unwantedFiles.ToArray());
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -203,7 +203,16 @@ public class TransmissionService : DownloadService, ITransmissionService
|
||||
?.Where(x => !string.IsNullOrEmpty(x.HashString))
|
||||
.Where(x => x.Status is 5 or 6)
|
||||
.Where(x => categories
|
||||
.Any(cat => x.DownloadDir?.EndsWith(cat.Name, StringComparison.InvariantCultureIgnoreCase) is true)
|
||||
.Any(cat =>
|
||||
{
|
||||
if (x.DownloadDir is null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return Path.GetFileName(Path.TrimEndingDirectorySeparator(x.DownloadDir))
|
||||
.Equals(cat.Name, StringComparison.InvariantCultureIgnoreCase);
|
||||
})
|
||||
)
|
||||
.Cast<object>()
|
||||
.ToList();
|
||||
@@ -220,8 +229,17 @@ public class TransmissionService : DownloadService, ITransmissionService
|
||||
}
|
||||
|
||||
Category? category = categoriesToClean
|
||||
.FirstOrDefault(x => download.DownloadDir?.EndsWith(x.Name, StringComparison.InvariantCultureIgnoreCase) is true);
|
||||
.FirstOrDefault(x =>
|
||||
{
|
||||
if (download.DownloadDir is null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return Path.GetFileName(Path.TrimEndingDirectorySeparator(download.DownloadDir))
|
||||
.Equals(x.Name, StringComparison.InvariantCultureIgnoreCase);
|
||||
});
|
||||
|
||||
if (category is null)
|
||||
{
|
||||
continue;
|
||||
@@ -250,7 +268,7 @@ public class TransmissionService : DownloadService, ITransmissionService
|
||||
continue;
|
||||
}
|
||||
|
||||
await ((TransmissionService)Proxy).RemoveDownloadAsync(download.Id);
|
||||
await _dryRunInterceptor.InterceptAsync(RemoveDownloadAsync, download.Id);
|
||||
|
||||
_logger.LogInformation(
|
||||
"download cleaned | {reason} reached | {name}",
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using Common.Helpers;
|
||||
using Domain.Enums;
|
||||
using Infrastructure.Helpers;
|
||||
using Infrastructure.Interceptors;
|
||||
using Infrastructure.Verticals.Context;
|
||||
using Infrastructure.Verticals.Notifications;
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
@@ -13,13 +14,15 @@ public sealed class Striker : IStriker
|
||||
private readonly ILogger<Striker> _logger;
|
||||
private readonly IMemoryCache _cache;
|
||||
private readonly MemoryCacheEntryOptions _cacheOptions;
|
||||
private readonly NotificationPublisher _notifier;
|
||||
private readonly INotificationPublisher _notifier;
|
||||
private readonly IDryRunInterceptor _dryRunInterceptor;
|
||||
|
||||
public Striker(ILogger<Striker> logger, IMemoryCache cache, NotificationPublisher notifier)
|
||||
public Striker(ILogger<Striker> logger, IMemoryCache cache, INotificationPublisher notifier, IDryRunInterceptor dryRunInterceptor)
|
||||
{
|
||||
_logger = logger;
|
||||
_cache = cache;
|
||||
_notifier = notifier;
|
||||
_dryRunInterceptor = dryRunInterceptor;
|
||||
_cacheOptions = new MemoryCacheEntryOptions()
|
||||
.SetSlidingExpiration(StaticConfiguration.TriggerValue + Constants.CacheLimitBuffer);
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ public abstract class GenericHandler : IHandler, IDisposable
|
||||
protected readonly ILidarrClient _lidarrClient;
|
||||
protected readonly ArrQueueIterator _arrArrQueueIterator;
|
||||
protected readonly IDownloadService _downloadService;
|
||||
protected readonly NotificationPublisher _notifier;
|
||||
protected readonly INotificationPublisher _notifier;
|
||||
|
||||
protected GenericHandler(
|
||||
ILogger<GenericHandler> logger,
|
||||
@@ -37,7 +37,7 @@ public abstract class GenericHandler : IHandler, IDisposable
|
||||
ILidarrClient lidarrClient,
|
||||
ArrQueueIterator arrArrQueueIterator,
|
||||
DownloadServiceFactory downloadServiceFactory,
|
||||
NotificationPublisher notifier
|
||||
INotificationPublisher notifier
|
||||
)
|
||||
{
|
||||
_logger = logger;
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
using Domain.Enums;
|
||||
|
||||
namespace Infrastructure.Verticals.Notifications;
|
||||
|
||||
public interface INotificationPublisher
|
||||
{
|
||||
Task NotifyStrike(StrikeType strikeType, int strikeCount);
|
||||
|
||||
Task NotifyQueueItemDeleted(bool removeFromClient, DeleteReason reason);
|
||||
|
||||
Task NotifyDownloadCleaned(double ratio, TimeSpan seedingTime, string categoryName, CleanReason reason);
|
||||
}
|
||||
@@ -12,25 +12,19 @@ using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Infrastructure.Verticals.Notifications;
|
||||
|
||||
public class NotificationPublisher : InterceptedService, IDryRunService
|
||||
public class NotificationPublisher : INotificationPublisher
|
||||
{
|
||||
private readonly ILogger<NotificationPublisher> _logger;
|
||||
private readonly ILogger<INotificationPublisher> _logger;
|
||||
private readonly IBus _messageBus;
|
||||
|
||||
/// <summary>
|
||||
/// Constructor to be used by interceptors.
|
||||
/// </summary>
|
||||
public NotificationPublisher()
|
||||
{
|
||||
}
|
||||
|
||||
public NotificationPublisher(ILogger<NotificationPublisher> logger, IBus messageBus)
|
||||
private readonly IDryRunInterceptor _dryRunInterceptor;
|
||||
|
||||
public NotificationPublisher(ILogger<INotificationPublisher> logger, IBus messageBus, IDryRunInterceptor dryRunInterceptor)
|
||||
{
|
||||
_logger = logger;
|
||||
_messageBus = messageBus;
|
||||
_dryRunInterceptor = dryRunInterceptor;
|
||||
}
|
||||
|
||||
[DryRunSafeguard]
|
||||
public virtual async Task NotifyStrike(StrikeType strikeType, int strikeCount)
|
||||
{
|
||||
try
|
||||
@@ -54,10 +48,10 @@ public class NotificationPublisher : InterceptedService, IDryRunService
|
||||
switch (strikeType)
|
||||
{
|
||||
case StrikeType.Stalled:
|
||||
await _messageBus.Publish(notification.Adapt<StalledStrikeNotification>());
|
||||
await _dryRunInterceptor.InterceptAsync(Notify<StalledStrikeNotification>, notification.Adapt<StalledStrikeNotification>());
|
||||
break;
|
||||
case StrikeType.ImportFailed:
|
||||
await _messageBus.Publish(notification.Adapt<FailedImportStrikeNotification>());
|
||||
await _dryRunInterceptor.InterceptAsync(Notify<FailedImportStrikeNotification>, notification.Adapt<FailedImportStrikeNotification>());
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -67,7 +61,6 @@ public class NotificationPublisher : InterceptedService, IDryRunService
|
||||
}
|
||||
}
|
||||
|
||||
[DryRunSafeguard]
|
||||
public virtual async Task NotifyQueueItemDeleted(bool removeFromClient, DeleteReason reason)
|
||||
{
|
||||
QueueRecord record = ContextProvider.Get<QueueRecord>(nameof(QueueRecord));
|
||||
@@ -86,10 +79,9 @@ public class NotificationPublisher : InterceptedService, IDryRunService
|
||||
Fields = [new() { Title = "Removed from download client?", Text = removeFromClient ? "Yes" : "No" }]
|
||||
};
|
||||
|
||||
await _messageBus.Publish(notification);
|
||||
await _dryRunInterceptor.InterceptAsync(Notify<QueueItemDeletedNotification>, notification);
|
||||
}
|
||||
|
||||
[DryRunSafeguard]
|
||||
public virtual async Task NotifyDownloadCleaned(double ratio, TimeSpan seedingTime, string categoryName, CleanReason reason)
|
||||
{
|
||||
DownloadCleanedNotification notification = new()
|
||||
@@ -106,7 +98,13 @@ public class NotificationPublisher : InterceptedService, IDryRunService
|
||||
Level = NotificationLevel.Important
|
||||
};
|
||||
|
||||
await _messageBus.Publish(notification);
|
||||
await _dryRunInterceptor.InterceptAsync(Notify<DownloadCleanedNotification>, notification);
|
||||
}
|
||||
|
||||
[DryRunSafeguard]
|
||||
private Task Notify<T>(T message) where T: notnull
|
||||
{
|
||||
return _messageBus.Publish(message);
|
||||
}
|
||||
|
||||
private static Uri GetImageFromContext(QueueRecord record, InstanceType instanceType) =>
|
||||
|
||||
@@ -32,7 +32,7 @@ public sealed class QueueCleaner : GenericHandler
|
||||
LidarrClient lidarrClient,
|
||||
ArrQueueIterator arrArrQueueIterator,
|
||||
DownloadServiceFactory downloadServiceFactory,
|
||||
NotificationPublisher notifier
|
||||
INotificationPublisher notifier
|
||||
) : base(
|
||||
logger, downloadClientConfig,
|
||||
sonarrConfig, radarrConfig, lidarrConfig,
|
||||
|
||||
@@ -250,6 +250,7 @@ services:
|
||||
# - NOTIFIARR__ON_IMPORT_FAILED_STRIKE=true
|
||||
# - NOTIFIARR__ON_STALLED_STRIKE=true
|
||||
# - NOTIFIARR__ON_QUEUE_ITEM_DELETED=true
|
||||
# - NOTIFIARR__ON_DOWNLOAD_CLEANED=true
|
||||
# - NOTIFIARR__API_KEY=notifiarr_secret
|
||||
# - NOTIFIARR__CHANNEL_ID=discord_channel_id
|
||||
volumes:
|
||||
|
||||
Reference in New Issue
Block a user