mirror of
https://github.com/Radarr/Radarr.git
synced 2024-09-11 20:12:41 +02:00
New: Add pushsafer notification service (#8770)
This commit is contained in:
parent
3055ed5336
commit
f38077aac7
74
src/NzbDrone.Core/Notifications/Pushsafer/Pushsafer.cs
Normal file
74
src/NzbDrone.Core/Notifications/Pushsafer/Pushsafer.cs
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using FluentValidation.Results;
|
||||||
|
using NzbDrone.Common.Extensions;
|
||||||
|
using NzbDrone.Core.Movies;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Notifications.Pushsafer
|
||||||
|
{
|
||||||
|
public class Pushsafer : NotificationBase<PushsaferSettings>
|
||||||
|
{
|
||||||
|
private readonly IPushsaferProxy _proxy;
|
||||||
|
|
||||||
|
public Pushsafer(IPushsaferProxy proxy)
|
||||||
|
{
|
||||||
|
_proxy = proxy;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string Name => "Pushsafer";
|
||||||
|
public override string Link => "https://pushsafer.com/";
|
||||||
|
|
||||||
|
public override void OnGrab(GrabMessage grabMessage)
|
||||||
|
{
|
||||||
|
_proxy.SendNotification(MOVIE_GRABBED_TITLE, grabMessage.Message, Settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnDownload(DownloadMessage message)
|
||||||
|
{
|
||||||
|
_proxy.SendNotification(MOVIE_DOWNLOADED_TITLE, message.Message, Settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnMovieAdded(Movie movie)
|
||||||
|
{
|
||||||
|
_proxy.SendNotification(MOVIE_ADDED_TITLE, $"{movie.Title} added to library", Settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnMovieFileDelete(MovieFileDeleteMessage deleteMessage)
|
||||||
|
{
|
||||||
|
_proxy.SendNotification(MOVIE_FILE_DELETED_TITLE, deleteMessage.Message, Settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnMovieDelete(MovieDeleteMessage deleteMessage)
|
||||||
|
{
|
||||||
|
_proxy.SendNotification(MOVIE_DELETED_TITLE, deleteMessage.Message, Settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnHealthIssue(HealthCheck.HealthCheck healthCheck)
|
||||||
|
{
|
||||||
|
_proxy.SendNotification(HEALTH_ISSUE_TITLE, healthCheck.Message, Settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnHealthRestored(HealthCheck.HealthCheck previousCheck)
|
||||||
|
{
|
||||||
|
_proxy.SendNotification(HEALTH_RESTORED_TITLE, $"The following issue is now resolved: {previousCheck.Message}", Settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnApplicationUpdate(ApplicationUpdateMessage updateMessage)
|
||||||
|
{
|
||||||
|
_proxy.SendNotification(APPLICATION_UPDATE_TITLE, updateMessage.Message, Settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnManualInteractionRequired(ManualInteractionRequiredMessage message)
|
||||||
|
{
|
||||||
|
_proxy.SendNotification(MANUAL_INTERACTION_REQUIRED_TITLE, message.Message, Settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override ValidationResult Test()
|
||||||
|
{
|
||||||
|
var failures = new List<ValidationFailure>();
|
||||||
|
|
||||||
|
failures.AddIfNotNull(_proxy.Test(Settings));
|
||||||
|
|
||||||
|
return new ValidationResult(failures);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,11 @@
|
|||||||
|
namespace NzbDrone.Core.Notifications.Pushsafer
|
||||||
|
{
|
||||||
|
public enum PushsaferPriority
|
||||||
|
{
|
||||||
|
Silent = -2,
|
||||||
|
Quiet = -1,
|
||||||
|
Normal = 0,
|
||||||
|
High = 1,
|
||||||
|
Emergency = 2
|
||||||
|
}
|
||||||
|
}
|
105
src/NzbDrone.Core/Notifications/Pushsafer/PushsaferProxy.cs
Normal file
105
src/NzbDrone.Core/Notifications/Pushsafer/PushsaferProxy.cs
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
using System;
|
||||||
|
using System.Net;
|
||||||
|
using FluentValidation.Results;
|
||||||
|
using NLog;
|
||||||
|
using NzbDrone.Common.Extensions;
|
||||||
|
using NzbDrone.Common.Http;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Notifications.Pushsafer
|
||||||
|
{
|
||||||
|
public interface IPushsaferProxy
|
||||||
|
{
|
||||||
|
void SendNotification(string title, string message, PushsaferSettings settings);
|
||||||
|
ValidationFailure Test(PushsaferSettings settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
public class PushsaferProxy : IPushsaferProxy
|
||||||
|
{
|
||||||
|
private const string URL = "https://pushsafer.com/api";
|
||||||
|
private readonly IHttpClient _httpClient;
|
||||||
|
private readonly Logger _logger;
|
||||||
|
|
||||||
|
public PushsaferProxy(IHttpClient httpClient, Logger logger)
|
||||||
|
{
|
||||||
|
_httpClient = httpClient;
|
||||||
|
_logger = logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SendNotification(string title, string message, PushsaferSettings settings)
|
||||||
|
{
|
||||||
|
var requestBuilder = new HttpRequestBuilder(URL).Post();
|
||||||
|
|
||||||
|
requestBuilder.AddFormParameter("k", settings.ApiKey)
|
||||||
|
.AddFormParameter("d", string.Join("|", settings.DeviceIds))
|
||||||
|
.AddFormParameter("t", title)
|
||||||
|
.AddFormParameter("m", message)
|
||||||
|
.AddFormParameter("pr", settings.Priority);
|
||||||
|
|
||||||
|
if ((PushsaferPriority)settings.Priority == PushsaferPriority.Emergency)
|
||||||
|
{
|
||||||
|
requestBuilder.AddFormParameter("re", settings.Retry);
|
||||||
|
requestBuilder.AddFormParameter("ex", settings.Expire);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!settings.Sound.IsNullOrWhiteSpace())
|
||||||
|
{
|
||||||
|
requestBuilder.AddFormParameter("s", settings.Sound);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!settings.Vibration.IsNullOrWhiteSpace())
|
||||||
|
{
|
||||||
|
requestBuilder.AddFormParameter("v", settings.Vibration);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!settings.Icon.IsNullOrWhiteSpace())
|
||||||
|
{
|
||||||
|
requestBuilder.AddFormParameter("i", settings.Icon);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!settings.IconColor.IsNullOrWhiteSpace())
|
||||||
|
{
|
||||||
|
requestBuilder.AddFormParameter("c", settings.IconColor);
|
||||||
|
}
|
||||||
|
|
||||||
|
var request = requestBuilder.Build();
|
||||||
|
|
||||||
|
var response = _httpClient.Post(request);
|
||||||
|
|
||||||
|
// https://www.pushsafer.com/en/pushapi#api-message
|
||||||
|
if (response.StatusCode != HttpStatusCode.OK)
|
||||||
|
{
|
||||||
|
throw new HttpException(request, response);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ValidationFailure Test(PushsaferSettings settings)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
const string title = "Test Notification";
|
||||||
|
const string body = "This is a test message from Radarr";
|
||||||
|
|
||||||
|
SendNotification(title, body, settings);
|
||||||
|
}
|
||||||
|
catch (HttpException ex)
|
||||||
|
{
|
||||||
|
_logger.Error(ex, "Unable to send test message");
|
||||||
|
|
||||||
|
return (int)ex.Response.StatusCode switch
|
||||||
|
{
|
||||||
|
250 => new ValidationFailure("ApiKey", "API key is invalid"),
|
||||||
|
270 => new ValidationFailure("DeviceIds", "Device ID is invalid"),
|
||||||
|
275 => new ValidationFailure("DeviceIds", "Device Group ID is invalid"),
|
||||||
|
_ => null,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.Error(ex, "Unable to send test message");
|
||||||
|
return new ValidationFailure("ApiKey", "Unable to send test message");
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,68 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
using FluentValidation;
|
||||||
|
using NzbDrone.Common.Extensions;
|
||||||
|
using NzbDrone.Core.Annotations;
|
||||||
|
using NzbDrone.Core.ThingiProvider;
|
||||||
|
using NzbDrone.Core.Validation;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Notifications.Pushsafer
|
||||||
|
{
|
||||||
|
public class PushsaferSettingsValidator : AbstractValidator<PushsaferSettings>
|
||||||
|
{
|
||||||
|
public PushsaferSettingsValidator()
|
||||||
|
{
|
||||||
|
RuleFor(c => c.ApiKey).NotEmpty();
|
||||||
|
RuleFor(c => c.Retry).GreaterThanOrEqualTo(60).LessThanOrEqualTo(10800).When(c => (PushsaferPriority)c.Priority == PushsaferPriority.Emergency);
|
||||||
|
RuleFor(c => c.Expire).GreaterThanOrEqualTo(60).LessThanOrEqualTo(10800).When(c => (PushsaferPriority)c.Priority == PushsaferPriority.Emergency);
|
||||||
|
RuleFor(c => c.Sound).ValidParsedStringRange(0, 62).When(c => c.Sound.IsNotNullOrWhiteSpace());
|
||||||
|
RuleFor(c => c.Vibration).ValidParsedStringRange(1, 3).When(c => c.Vibration.IsNotNullOrWhiteSpace());
|
||||||
|
RuleFor(c => c.Icon).ValidParsedStringRange(1, 181).When(c => c.Icon.IsNotNullOrWhiteSpace());
|
||||||
|
RuleFor(c => c.IconColor).Matches(new Regex("^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$")).When(c => c.IconColor.IsNotNullOrWhiteSpace());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class PushsaferSettings : IProviderConfig
|
||||||
|
{
|
||||||
|
private static readonly PushsaferSettingsValidator Validator = new ();
|
||||||
|
|
||||||
|
public PushsaferSettings()
|
||||||
|
{
|
||||||
|
Priority = (int)PushsaferPriority.Normal;
|
||||||
|
DeviceIds = Array.Empty<string>();
|
||||||
|
}
|
||||||
|
|
||||||
|
[FieldDefinition(0, Label = "API Key", Privacy = PrivacyLevel.ApiKey, HelpLink = "https://www.pushsafer.com/en/pushapi_ext#API-K")]
|
||||||
|
public string ApiKey { get; set; }
|
||||||
|
|
||||||
|
[FieldDefinition(1, Label = "Device IDs", HelpText = "Device Group ID or list of Device IDs (leave blank to send to all devices)", Type = FieldType.Tag, Placeholder = "123456789|987654321")]
|
||||||
|
public IEnumerable<string> DeviceIds { get; set; }
|
||||||
|
|
||||||
|
[FieldDefinition(2, Label = "Priority", Type = FieldType.Select, SelectOptions = typeof(PushsaferPriority))]
|
||||||
|
public int Priority { get; set; }
|
||||||
|
|
||||||
|
[FieldDefinition(3, Label = "Retry", Type = FieldType.Textbox, HelpText = "Interval to retry Emergency alerts, minimum 60 seconds")]
|
||||||
|
public int Retry { get; set; }
|
||||||
|
|
||||||
|
[FieldDefinition(4, Label = "Expire", Type = FieldType.Textbox, HelpText = "Maximum time to retry Emergency alerts, maximum 10800 seconds")]
|
||||||
|
public int Expire { get; set; }
|
||||||
|
|
||||||
|
[FieldDefinition(5, Label = "Sound", Type = FieldType.Textbox, Advanced = true, HelpText = "Notification sound 0-62 (leave blank to use the default)", HelpLink = "https://www.pushsafer.com/en/pushapi_ext#API-S")]
|
||||||
|
public string Sound { get; set; }
|
||||||
|
|
||||||
|
[FieldDefinition(6, Label = "Vibration", Type = FieldType.Textbox, Advanced = true, HelpText = "Vibration pattern 1-3 (leave blank to use the device default)", HelpLink = "https://www.pushsafer.com/en/pushapi_ext#API-V")]
|
||||||
|
public string Vibration { get; set; }
|
||||||
|
|
||||||
|
[FieldDefinition(7, Label = "Icon", Type = FieldType.Textbox, Advanced = true, HelpText = "Icon number 1-181 (leave blank to use the default Pushsafer icon)", HelpLink = "https://www.pushsafer.com/en/pushapi_ext#API-I")]
|
||||||
|
public string Icon { get; set; }
|
||||||
|
|
||||||
|
[FieldDefinition(8, Label = "Icon Color", Type = FieldType.Textbox, Advanced = true, HelpText = "Icon color in hex format (leave blank to use the default Pushsafer icon color)", HelpLink = "https://www.pushsafer.com/en/pushapi_ext#API-C")]
|
||||||
|
public string IconColor { get; set; }
|
||||||
|
|
||||||
|
public NzbDroneValidationResult Validate()
|
||||||
|
{
|
||||||
|
return new NzbDroneValidationResult(Validator.Validate(this));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -73,5 +73,18 @@ public static IRuleBuilderOptions<T, string> ContainsRadarr<T>(this IRuleBuilder
|
|||||||
ruleBuilder.SetValidator(new NotEmptyValidator(null));
|
ruleBuilder.SetValidator(new NotEmptyValidator(null));
|
||||||
return ruleBuilder.SetValidator(new RegularExpressionValidator("radarr", RegexOptions.IgnoreCase)).WithMessage("Must contain Radarr");
|
return ruleBuilder.SetValidator(new RegularExpressionValidator("radarr", RegexOptions.IgnoreCase)).WithMessage("Must contain Radarr");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static IRuleBuilderOptions<T, string> ValidParsedStringRange<T>(this IRuleBuilder<T, string> ruleBuilder, int minValue, int maxValue)
|
||||||
|
{
|
||||||
|
return ruleBuilder.Must(x =>
|
||||||
|
{
|
||||||
|
if (int.TryParse(x, out var value))
|
||||||
|
{
|
||||||
|
return value >= minValue && value <= maxValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}).WithMessage($"Must be greater than or equal to '{minValue}' and less than or equal to '{maxValue}'");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user