New: Add pushsafer notification service (#8770)
parent
3055ed5336
commit
f38077aac7
@ -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
|
||||
}
|
||||
}
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in new issue