mirror of
https://github.com/Cleanuparr/Cleanuparr.git
synced 2026-02-19 07:17:04 -05:00
Add download cleaner and dry run (#58)
This commit is contained in:
@@ -27,9 +27,12 @@ public sealed class NotificationConsumer<T> : IConsumer<T> where T : Notificatio
|
||||
case StalledStrikeNotification stalledMessage:
|
||||
await _notificationService.Notify(stalledMessage);
|
||||
break;
|
||||
case QueueItemDeleteNotification queueItemDeleteMessage:
|
||||
case QueueItemDeletedNotification queueItemDeleteMessage:
|
||||
await _notificationService.Notify(queueItemDeleteMessage);
|
||||
break;
|
||||
case DownloadCleanedNotification downloadCleanedNotification:
|
||||
await _notificationService.Notify(downloadCleanedNotification);
|
||||
break;
|
||||
default:
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
@@ -6,5 +6,7 @@ public interface INotificationFactory
|
||||
|
||||
List<INotificationProvider> OnStalledStrikeEnabled();
|
||||
|
||||
List<INotificationProvider> OnQueueItemDeleteEnabled();
|
||||
List<INotificationProvider> OnQueueItemDeletedEnabled();
|
||||
|
||||
List<INotificationProvider> OnDownloadCleanedEnabled();
|
||||
}
|
||||
@@ -13,5 +13,7 @@ public interface INotificationProvider
|
||||
|
||||
Task OnStalledStrike(StalledStrikeNotification notification);
|
||||
|
||||
Task OnQueueItemDelete(QueueItemDeleteNotification notification);
|
||||
Task OnQueueItemDeleted(QueueItemDeletedNotification notification);
|
||||
|
||||
Task OnDownloadCleaned(DownloadCleanedNotification notification);
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
using Domain.Enums;
|
||||
|
||||
namespace Infrastructure.Verticals.Notifications.Models;
|
||||
|
||||
public record ArrNotification : Notification
|
||||
{
|
||||
public required InstanceType InstanceType { get; init; }
|
||||
|
||||
public required Uri InstanceUrl { get; init; }
|
||||
|
||||
public required string Hash { get; init; }
|
||||
|
||||
public Uri? Image { get; init; }
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
namespace Infrastructure.Verticals.Notifications.Models;
|
||||
|
||||
public sealed record DownloadCleanedNotification : Notification
|
||||
{
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
namespace Infrastructure.Verticals.Notifications.Models;
|
||||
|
||||
public sealed record FailedImportStrikeNotification : Notification
|
||||
public sealed record FailedImportStrikeNotification : ArrNotification
|
||||
{
|
||||
}
|
||||
@@ -1,20 +1,12 @@
|
||||
using Domain.Enums;
|
||||
namespace Infrastructure.Verticals.Notifications.Models;
|
||||
|
||||
namespace Infrastructure.Verticals.Notifications.Models;
|
||||
|
||||
public record Notification
|
||||
public abstract record Notification
|
||||
{
|
||||
public required InstanceType InstanceType { get; init; }
|
||||
|
||||
public required Uri InstanceUrl { get; init; }
|
||||
|
||||
public required string Hash { get; init; }
|
||||
|
||||
public required string Title { get; init; }
|
||||
|
||||
public required string Description { get; init; }
|
||||
|
||||
public Uri? Image { get; init; }
|
||||
|
||||
public List<NotificationField>? Fields { get; init; }
|
||||
|
||||
public NotificationLevel Level { get; init; }
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
namespace Infrastructure.Verticals.Notifications.Models;
|
||||
|
||||
public enum NotificationLevel
|
||||
{
|
||||
Test,
|
||||
Information,
|
||||
Warning,
|
||||
Important
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
namespace Infrastructure.Verticals.Notifications.Models;
|
||||
|
||||
public sealed record QueueItemDeleteNotification : Notification
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
namespace Infrastructure.Verticals.Notifications.Models;
|
||||
|
||||
public sealed record QueueItemDeletedNotification : ArrNotification
|
||||
{
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
namespace Infrastructure.Verticals.Notifications.Models;
|
||||
|
||||
public sealed record StalledStrikeNotification : Notification
|
||||
public sealed record StalledStrikeNotification : ArrNotification
|
||||
{
|
||||
}
|
||||
@@ -1,4 +1,3 @@
|
||||
using Domain.Enums;
|
||||
using Infrastructure.Verticals.Notifications.Models;
|
||||
using Mapster;
|
||||
using Microsoft.Extensions.Options;
|
||||
@@ -12,6 +11,7 @@ public class NotifiarrProvider : NotificationProvider
|
||||
|
||||
private const string WarningColor = "f0ad4e";
|
||||
private const string ImportantColor = "bb2124";
|
||||
private const string Logo = "https://github.com/flmorg/cleanuperr/blob/main/Logo/48.png?raw=true";
|
||||
|
||||
public NotifiarrProvider(IOptions<NotifiarrConfig> config, INotifiarrProxy proxy)
|
||||
: base(config)
|
||||
@@ -32,12 +32,17 @@ public class NotifiarrProvider : NotificationProvider
|
||||
await _proxy.SendNotification(BuildPayload(notification, WarningColor), _config);
|
||||
}
|
||||
|
||||
public override async Task OnQueueItemDelete(QueueItemDeleteNotification notification)
|
||||
public override async Task OnQueueItemDeleted(QueueItemDeletedNotification notification)
|
||||
{
|
||||
await _proxy.SendNotification(BuildPayload(notification, ImportantColor), _config);
|
||||
}
|
||||
|
||||
private NotifiarrPayload BuildPayload(Notification notification, string color)
|
||||
public override async Task OnDownloadCleaned(DownloadCleanedNotification notification)
|
||||
{
|
||||
await _proxy.SendNotification(BuildPayload(notification), _config);
|
||||
}
|
||||
|
||||
private NotifiarrPayload BuildPayload(ArrNotification notification, string color)
|
||||
{
|
||||
NotifiarrPayload payload = new()
|
||||
{
|
||||
@@ -47,7 +52,7 @@ public class NotifiarrProvider : NotificationProvider
|
||||
Text = new()
|
||||
{
|
||||
Title = notification.Title,
|
||||
Icon = "https://github.com/flmorg/cleanuperr/blob/main/Logo/48.png?raw=true",
|
||||
Icon = Logo,
|
||||
Description = notification.Description,
|
||||
Fields = new()
|
||||
{
|
||||
@@ -62,7 +67,7 @@ public class NotifiarrProvider : NotificationProvider
|
||||
},
|
||||
Images = new()
|
||||
{
|
||||
Thumbnail = new Uri("https://github.com/flmorg/cleanuperr/blob/main/Logo/48.png?raw=true"),
|
||||
Thumbnail = new Uri(Logo),
|
||||
Image = notification.Image
|
||||
}
|
||||
}
|
||||
@@ -72,4 +77,32 @@ public class NotifiarrProvider : NotificationProvider
|
||||
|
||||
return payload;
|
||||
}
|
||||
|
||||
private NotifiarrPayload BuildPayload(DownloadCleanedNotification notification)
|
||||
{
|
||||
NotifiarrPayload payload = new()
|
||||
{
|
||||
Discord = new()
|
||||
{
|
||||
Color = ImportantColor,
|
||||
Text = new()
|
||||
{
|
||||
Title = notification.Title,
|
||||
Icon = Logo,
|
||||
Description = notification.Description,
|
||||
Fields = notification.Fields?.Adapt<List<Field>>() ?? []
|
||||
},
|
||||
Ids = new Ids
|
||||
{
|
||||
Channel = _config.ChannelId
|
||||
},
|
||||
Images = new()
|
||||
{
|
||||
Thumbnail = new Uri(Logo)
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return payload;
|
||||
}
|
||||
}
|
||||
@@ -25,8 +25,13 @@ public class NotificationFactory : INotificationFactory
|
||||
.Where(n => n.Config.OnStalledStrike)
|
||||
.ToList();
|
||||
|
||||
public List<INotificationProvider> OnQueueItemDeleteEnabled() =>
|
||||
public List<INotificationProvider> OnQueueItemDeletedEnabled() =>
|
||||
ActiveProviders()
|
||||
.Where(n => n.Config.OnQueueItemDelete)
|
||||
.Where(n => n.Config.OnQueueItemDeleted)
|
||||
.ToList();
|
||||
|
||||
public List<INotificationProvider> OnDownloadCleanedEnabled() =>
|
||||
ActiveProviders()
|
||||
.Where(n => n.Config.OnDownloadCleaned)
|
||||
.ToList();
|
||||
}
|
||||
@@ -19,5 +19,7 @@ public abstract class NotificationProvider : INotificationProvider
|
||||
|
||||
public abstract Task OnStalledStrike(StalledStrikeNotification notification);
|
||||
|
||||
public abstract Task OnQueueItemDelete(QueueItemDeleteNotification notification);
|
||||
public abstract Task OnQueueItemDeleted(QueueItemDeletedNotification notification);
|
||||
|
||||
public abstract Task OnDownloadCleaned(DownloadCleanedNotification notification);
|
||||
}
|
||||
@@ -1,6 +1,9 @@
|
||||
using Common.Configuration.Arr;
|
||||
using System.Globalization;
|
||||
using Common.Attributes;
|
||||
using Common.Configuration.Arr;
|
||||
using Domain.Enums;
|
||||
using Domain.Models.Arr.Queue;
|
||||
using Infrastructure.Interceptors;
|
||||
using Infrastructure.Verticals.Context;
|
||||
using Infrastructure.Verticals.Notifications.Models;
|
||||
using Mapster;
|
||||
@@ -9,27 +12,35 @@ using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Infrastructure.Verticals.Notifications;
|
||||
|
||||
public sealed class NotificationPublisher
|
||||
public class NotificationPublisher : InterceptedService, IDryRunService
|
||||
{
|
||||
private readonly ILogger<NotificationPublisher> _logger;
|
||||
private readonly IBus _messageBus;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Constructor to be used by interceptors.
|
||||
/// </summary>
|
||||
public NotificationPublisher()
|
||||
{
|
||||
}
|
||||
|
||||
public NotificationPublisher(ILogger<NotificationPublisher> logger, IBus messageBus)
|
||||
{
|
||||
_logger = logger;
|
||||
_messageBus = messageBus;
|
||||
}
|
||||
|
||||
public async Task NotifyStrike(StrikeType strikeType, int strikeCount)
|
||||
[DryRunSafeguard]
|
||||
public virtual async Task NotifyStrike(StrikeType strikeType, int strikeCount)
|
||||
{
|
||||
try
|
||||
{
|
||||
QueueRecord record = GetRecordFromContext();
|
||||
InstanceType instanceType = GetInstanceTypeFromContext();
|
||||
Uri instanceUrl = GetInstanceUrlFromContext();
|
||||
Uri? imageUrl = GetImageFromContext(record, instanceType);
|
||||
QueueRecord record = ContextProvider.Get<QueueRecord>(nameof(QueueRecord));
|
||||
InstanceType instanceType = (InstanceType)ContextProvider.Get<object>(nameof(InstanceType));
|
||||
Uri instanceUrl = ContextProvider.Get<Uri>(nameof(ArrInstance) + nameof(ArrInstance.Url));
|
||||
Uri imageUrl = GetImageFromContext(record, instanceType);
|
||||
|
||||
Notification notification = new()
|
||||
ArrNotification notification = new()
|
||||
{
|
||||
InstanceType = instanceType,
|
||||
InstanceUrl = instanceUrl,
|
||||
@@ -56,14 +67,15 @@ public sealed class NotificationPublisher
|
||||
}
|
||||
}
|
||||
|
||||
public async Task NotifyQueueItemDelete(bool removeFromClient, DeleteReason reason)
|
||||
[DryRunSafeguard]
|
||||
public virtual async Task NotifyQueueItemDeleted(bool removeFromClient, DeleteReason reason)
|
||||
{
|
||||
QueueRecord record = GetRecordFromContext();
|
||||
InstanceType instanceType = GetInstanceTypeFromContext();
|
||||
Uri instanceUrl = GetInstanceUrlFromContext();
|
||||
Uri? imageUrl = GetImageFromContext(record, instanceType);
|
||||
QueueRecord record = ContextProvider.Get<QueueRecord>(nameof(QueueRecord));
|
||||
InstanceType instanceType = (InstanceType)ContextProvider.Get<object>(nameof(InstanceType));
|
||||
Uri instanceUrl = ContextProvider.Get<Uri>(nameof(ArrInstance) + nameof(ArrInstance.Url));
|
||||
Uri imageUrl = GetImageFromContext(record, instanceType);
|
||||
|
||||
Notification notification = new()
|
||||
QueueItemDeletedNotification notification = new()
|
||||
{
|
||||
InstanceType = instanceType,
|
||||
InstanceUrl = instanceUrl,
|
||||
@@ -74,20 +86,29 @@ public sealed class NotificationPublisher
|
||||
Fields = [new() { Title = "Removed from download client?", Text = removeFromClient ? "Yes" : "No" }]
|
||||
};
|
||||
|
||||
await _messageBus.Publish(notification.Adapt<QueueItemDeleteNotification>());
|
||||
await _messageBus.Publish(notification);
|
||||
}
|
||||
|
||||
private static QueueRecord GetRecordFromContext() =>
|
||||
ContextProvider.Get<QueueRecord>(nameof(QueueRecord)) ?? throw new Exception("failed to get record from context");
|
||||
[DryRunSafeguard]
|
||||
public virtual async Task NotifyDownloadCleaned(double ratio, TimeSpan seedingTime, string categoryName, CleanReason reason)
|
||||
{
|
||||
DownloadCleanedNotification notification = new()
|
||||
{
|
||||
Title = $"Cleaned item from download client with reason: {reason}",
|
||||
Description = ContextProvider.Get<string>("downloadName"),
|
||||
Fields =
|
||||
[
|
||||
new() { Title = "Hash", Text = ContextProvider.Get<string>("hash").ToLowerInvariant() },
|
||||
new() { Title = "Category", Text = categoryName.ToLowerInvariant() },
|
||||
new() { Title = "Ratio", Text = $"{ratio.ToString(CultureInfo.InvariantCulture)}%" },
|
||||
new() { Title = "Seeding hours", Text = $"{Math.Round(seedingTime.TotalHours, 0).ToString(CultureInfo.InvariantCulture)}h" }
|
||||
],
|
||||
Level = NotificationLevel.Important
|
||||
};
|
||||
|
||||
await _messageBus.Publish(notification);
|
||||
}
|
||||
|
||||
private static InstanceType GetInstanceTypeFromContext() =>
|
||||
(InstanceType)(ContextProvider.Get<object>(nameof(InstanceType)) ??
|
||||
throw new Exception("failed to get instance type from context"));
|
||||
|
||||
private static Uri GetInstanceUrlFromContext() =>
|
||||
ContextProvider.Get<Uri>(nameof(ArrInstance) + nameof(ArrInstance.Url)) ??
|
||||
throw new Exception("failed to get instance url from context");
|
||||
|
||||
private static Uri GetImageFromContext(QueueRecord record, InstanceType instanceType) =>
|
||||
instanceType switch
|
||||
{
|
||||
|
||||
@@ -44,13 +44,28 @@ public class NotificationService
|
||||
}
|
||||
}
|
||||
|
||||
public async Task Notify(QueueItemDeleteNotification notification)
|
||||
public async Task Notify(QueueItemDeletedNotification notification)
|
||||
{
|
||||
foreach (INotificationProvider provider in _notificationFactory.OnQueueItemDeleteEnabled())
|
||||
foreach (INotificationProvider provider in _notificationFactory.OnQueueItemDeletedEnabled())
|
||||
{
|
||||
try
|
||||
{
|
||||
await provider.OnQueueItemDelete(notification);
|
||||
await provider.OnQueueItemDeleted(notification);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
_logger.LogWarning(exception, "failed to send notification | provider {provider}", provider.Name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public async Task Notify(DownloadCleanedNotification notification)
|
||||
{
|
||||
foreach (INotificationProvider provider in _notificationFactory.OnDownloadCleanedEnabled())
|
||||
{
|
||||
try
|
||||
{
|
||||
await provider.OnDownloadCleaned(notification);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user