From fa7647135b9c63414fee1f43ea6afff83d27eb2b Mon Sep 17 00:00:00 2001 From: Qstick Date: Sat, 6 Mar 2021 16:24:38 -0500 Subject: [PATCH] New: VIP Expiration notifications on Newznab --- .../Extensions/DateTimeExtensions.cs | 16 +++- .../HealthCheck/Checks/NewznabVIPCheck.cs | 73 +++++++++++++++++++ .../Definitions/Newznab/NewznabSettings.cs | 13 ++++ src/NzbDrone.Core/Localization/Core/en.json | 2 + 4 files changed, 103 insertions(+), 1 deletion(-) create mode 100644 src/NzbDrone.Core/HealthCheck/Checks/NewznabVIPCheck.cs diff --git a/src/NzbDrone.Common/Extensions/DateTimeExtensions.cs b/src/NzbDrone.Common/Extensions/DateTimeExtensions.cs index 797e62bd7..3014172d4 100644 --- a/src/NzbDrone.Common/Extensions/DateTimeExtensions.cs +++ b/src/NzbDrone.Common/Extensions/DateTimeExtensions.cs @@ -1,4 +1,4 @@ -using System; +using System; namespace NzbDrone.Common.Extensions { @@ -34,6 +34,20 @@ namespace NzbDrone.Common.Extensions return dateTime >= afterDateTime; } + public static bool IsValidDate(this string dateTime) + { + DateTime.TryParse(dateTime, out DateTime result); + + return !result.Equals(default(DateTime)); + } + + public static bool IsFutureDate(this string dateTime) + { + DateTime.TryParse(dateTime, out DateTime result); + + return !result.Equals(default(DateTime)) && result.After(DateTime.Now); + } + public static bool Between(this DateTime dateTime, DateTime afterDateTime, DateTime beforeDateTime) { return dateTime >= afterDateTime && dateTime <= beforeDateTime; diff --git a/src/NzbDrone.Core/HealthCheck/Checks/NewznabVIPCheck.cs b/src/NzbDrone.Core/HealthCheck/Checks/NewznabVIPCheck.cs new file mode 100644 index 000000000..b832ce295 --- /dev/null +++ b/src/NzbDrone.Core/HealthCheck/Checks/NewznabVIPCheck.cs @@ -0,0 +1,73 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using NzbDrone.Common.Extensions; +using NzbDrone.Core.Indexers; +using NzbDrone.Core.Indexers.Newznab; +using NzbDrone.Core.Localization; +using NzbDrone.Core.ThingiProvider.Events; + +namespace NzbDrone.Core.HealthCheck.Checks +{ + [CheckOn(typeof(ProviderAddedEvent))] + [CheckOn(typeof(ProviderUpdatedEvent))] + [CheckOn(typeof(ProviderDeletedEvent))] + public class NewznabVIPCheck : HealthCheckBase + { + private readonly IIndexerFactory _indexerFactory; + + public NewznabVIPCheck(IIndexerFactory indexerFactory, ILocalizationService localizationService) + : base(localizationService) + { + _indexerFactory = indexerFactory; + } + + public override HealthCheck Check() + { + var enabled = _indexerFactory.Enabled(false); + var newznabProviders = enabled.Where(i => i.Definition.Implementation == typeof(Newznab).Name); + var expiringProviders = new List(); + var expiredProviders = new List(); + + foreach (var provider in newznabProviders) + { + var expiration = ((NewznabSettings)provider.Definition.Settings).VipExpiration; + + if (expiration.IsNullOrWhiteSpace()) + { + continue; + } + + if (DateTime.Parse(expiration).Before(DateTime.Now)) + { + expiredProviders.Add(provider); + } + + if (DateTime.Parse(expiration).Between(DateTime.Now, DateTime.Now.AddDays(7))) + { + expiringProviders.Add(provider); + } + } + + if (!expiringProviders.Empty()) + { + return new HealthCheck(GetType(), + HealthCheckResult.Warning, + string.Format(_localizationService.GetLocalizedString("NewznabVipCheckExpiringClientMessage"), + string.Join(", ", expiringProviders.Select(v => v.Definition.Name))), + "#newznab-vip-expiring"); + } + + if (!expiredProviders.Empty()) + { + return new HealthCheck(GetType(), + HealthCheckResult.Warning, + string.Format(_localizationService.GetLocalizedString("NewznabVipCheckExpiredClientMessage"), + string.Join(", ", expiredProviders.Select(v => v.Definition.Name))), + "#newznab-vip-expired"); + } + + return new HealthCheck(GetType()); + } + } +} diff --git a/src/NzbDrone.Core/Indexers/Definitions/Newznab/NewznabSettings.cs b/src/NzbDrone.Core/Indexers/Definitions/Newznab/NewznabSettings.cs index 0df7840dd..006d552f1 100644 --- a/src/NzbDrone.Core/Indexers/Definitions/Newznab/NewznabSettings.cs +++ b/src/NzbDrone.Core/Indexers/Definitions/Newznab/NewznabSettings.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using System.Linq; using System.Text.RegularExpressions; @@ -41,6 +42,14 @@ namespace NzbDrone.Core.Indexers.Newznab RuleFor(c => c.ApiKey).NotEmpty().When(ShouldHaveApiKey); RuleFor(c => c.AdditionalParameters).Matches(AdditionalParametersRegex) .When(c => !c.AdditionalParameters.IsNullOrWhiteSpace()); + + RuleFor(c => c.VipExpiration).Must(c => c.IsValidDate()) + .When(c => c.VipExpiration.IsNotNullOrWhiteSpace()) + .WithMessage("Correctly formatted date is required"); + + RuleFor(c => c.VipExpiration).Must(c => c.IsFutureDate()) + .When(c => c.VipExpiration.IsNotNullOrWhiteSpace()) + .WithMessage("Must be a future date"); } } @@ -51,6 +60,7 @@ namespace NzbDrone.Core.Indexers.Newznab public NewznabSettings() { ApiPath = "/api"; + VipExpiration = ""; } [FieldDefinition(0, Label = "URL")] @@ -65,6 +75,9 @@ namespace NzbDrone.Core.Indexers.Newznab [FieldDefinition(5, Label = "Additional Parameters", HelpText = "Additional Newznab parameters", Advanced = true)] public string AdditionalParameters { get; set; } + [FieldDefinition(6, Label = "VIP Expiration", HelpText = "Enter date (yyyy-mm-dd) for VIP Expiration or blank, Prowlarr will notify 1 week from expiration of VIP")] + public string VipExpiration { get; set; } + public List Categories { get; set; } // Field 8 is used by TorznabSettings MinimumSeeders diff --git a/src/NzbDrone.Core/Localization/Core/en.json b/src/NzbDrone.Core/Localization/Core/en.json index 27850c080..3c36b5ae8 100644 --- a/src/NzbDrone.Core/Localization/Core/en.json +++ b/src/NzbDrone.Core/Localization/Core/en.json @@ -97,6 +97,8 @@ "EnableSSL": "Enable SSL", "EnableSslHelpText": " Requires restart running as administrator to take effect", "Error": "Error", + "NewznabVipCheckExpiringClientMessage": "Indexer VIP benefits expiring soon: {0}", + "NewznabVipCheckExpiredClientMessage": "Indexer VIP benefits have expired: {0}", "ErrorLoadingContents": "Error loading contents", "Events": "Events", "EventType": "Event Type",