From 150c76f61ca8b3a1c21742ed58d7733247db37a3 Mon Sep 17 00:00:00 2001 From: Mark McDowall Date: Thu, 22 Dec 2022 23:47:05 -0800 Subject: [PATCH] New: Option to include series image for Gotify notifications (cherry picked from commit e57e68c97a9d24f8344623ac8f731c2da220686b) Closes #3240 --- .../Notifications/Gotify/Gotify.cs | 75 ++++++++++++++++--- .../Notifications/Gotify/GotifyMessage.cs | 40 ++++++++++ .../Notifications/Gotify/GotifyProxy.cs | 21 ++++-- .../Notifications/Gotify/GotifySettings.cs | 3 + 4 files changed, 120 insertions(+), 19 deletions(-) create mode 100644 src/NzbDrone.Core/Notifications/Gotify/GotifyMessage.cs diff --git a/src/NzbDrone.Core/Notifications/Gotify/Gotify.cs b/src/NzbDrone.Core/Notifications/Gotify/Gotify.cs index ad3a0cf20..058bd6c4a 100644 --- a/src/NzbDrone.Core/Notifications/Gotify/Gotify.cs +++ b/src/NzbDrone.Core/Notifications/Gotify/Gotify.cs @@ -1,7 +1,11 @@ using System; using System.Collections.Generic; +using System.Linq; +using System.Text; using FluentValidation.Results; using NLog; +using NzbDrone.Core.MediaCover; +using NzbDrone.Core.Music; namespace NzbDrone.Core.Notifications.Gotify { @@ -21,47 +25,47 @@ namespace NzbDrone.Core.Notifications.Gotify public override void OnGrab(GrabMessage grabMessage) { - _proxy.SendNotification(ALBUM_GRABBED_TITLE, grabMessage.Message, Settings); + SendNotification(ALBUM_GRABBED_TITLE, grabMessage.Message, grabMessage.Artist); } public override void OnReleaseImport(AlbumDownloadMessage message) { - _proxy.SendNotification(ALBUM_DOWNLOADED_TITLE, message.Message, Settings); + SendNotification(ALBUM_DOWNLOADED_TITLE, message.Message, message.Artist); } public override void OnAlbumDelete(AlbumDeleteMessage deleteMessage) { - _proxy.SendNotification(ALBUM_DELETED_TITLE, deleteMessage.Message, Settings); + SendNotification(ALBUM_DELETED_TITLE, deleteMessage.Message, deleteMessage.Album?.Artist); } public override void OnArtistDelete(ArtistDeleteMessage deleteMessage) { - _proxy.SendNotification(ARTIST_DELETED_TITLE, deleteMessage.Message, Settings); + SendNotification(ARTIST_DELETED_TITLE, deleteMessage.Message, deleteMessage.Artist); } public override void OnHealthIssue(HealthCheck.HealthCheck healthCheck) { - _proxy.SendNotification(HEALTH_ISSUE_TITLE, healthCheck.Message, Settings); + SendNotification(HEALTH_ISSUE_TITLE, healthCheck.Message, null); } public override void OnHealthRestored(HealthCheck.HealthCheck previousCheck) { - _proxy.SendNotification(HEALTH_RESTORED_TITLE, $"The following issue is now resolved: {previousCheck.Message}", null); + SendNotification(HEALTH_RESTORED_TITLE, $"The following issue is now resolved: {previousCheck.Message}", null); } public override void OnDownloadFailure(DownloadFailedMessage message) { - _proxy.SendNotification(DOWNLOAD_FAILURE_TITLE, message.Message, Settings); + SendNotification(DOWNLOAD_FAILURE_TITLE, message.Message, null); } public override void OnImportFailure(AlbumDownloadMessage message) { - _proxy.SendNotification(IMPORT_FAILURE_TITLE, message.Message, Settings); + SendNotification(IMPORT_FAILURE_TITLE, message.Message, message.Artist); } public override void OnApplicationUpdate(ApplicationUpdateMessage updateMessage) { - _proxy.SendNotification(APPLICATION_UPDATE_TITLE, updateMessage.Message, Settings); + SendNotification(APPLICATION_UPDATE_TITLE, updateMessage.Message, null); } public override ValidationResult Test() @@ -70,10 +74,29 @@ namespace NzbDrone.Core.Notifications.Gotify try { + var isMarkdown = false; const string title = "Test Notification"; - const string body = "This is a test message from Lidarr"; - _proxy.SendNotification(title, body, Settings); + var sb = new StringBuilder(); + sb.AppendLine("This is a test message from Lidarr"); + + if (Settings.IncludeArtistPoster) + { + isMarkdown = true; + + sb.AppendLine("\r![](https://raw.githubusercontent.com/Lidarr/Lidarr/develop/Logo/128.png)"); + } + + var payload = new GotifyMessage + { + Title = title, + Message = sb.ToString(), + Priority = Settings.Priority + }; + + payload.SetContentType(isMarkdown); + + _proxy.SendNotification(payload, Settings); } catch (Exception ex) { @@ -83,5 +106,35 @@ namespace NzbDrone.Core.Notifications.Gotify return new ValidationResult(failures); } + + private void SendNotification(string title, string message, Artist artist) + { + var isMarkdown = false; + var sb = new StringBuilder(); + + sb.AppendLine(message); + + if (Settings.IncludeArtistPoster && artist != null) + { + var poster = artist.Metadata.Value.Images.FirstOrDefault(x => x.CoverType == MediaCoverTypes.Poster)?.Url; + + if (poster != null) + { + isMarkdown = true; + sb.AppendLine($"\r![]({poster})"); + } + } + + var payload = new GotifyMessage + { + Title = title, + Message = sb.ToString(), + Priority = Settings.Priority + }; + + payload.SetContentType(isMarkdown); + + _proxy.SendNotification(payload, Settings); + } } } diff --git a/src/NzbDrone.Core/Notifications/Gotify/GotifyMessage.cs b/src/NzbDrone.Core/Notifications/Gotify/GotifyMessage.cs new file mode 100644 index 000000000..170ce1367 --- /dev/null +++ b/src/NzbDrone.Core/Notifications/Gotify/GotifyMessage.cs @@ -0,0 +1,40 @@ +using Newtonsoft.Json; + +namespace NzbDrone.Core.Notifications.Gotify +{ + public class GotifyMessage + { + public string Title { get; set; } + public string Message { get; set; } + public int Priority { get; set; } + public GotifyExtras Extras { get; set; } + + public GotifyMessage() + { + Extras = new GotifyExtras(); + } + + public void SetContentType(bool isMarkdown) + { + var contentType = isMarkdown ? "text/markdown" : "text/plain"; + + Extras.ClientDisplay = new GotifyClientDisplay(contentType); + } + } + + public class GotifyExtras + { + [JsonProperty("client::display")] + public GotifyClientDisplay ClientDisplay { get; set; } + } + + public class GotifyClientDisplay + { + public string ContentType { get; set; } + + public GotifyClientDisplay(string contentType) + { + ContentType = contentType; + } + } +} diff --git a/src/NzbDrone.Core/Notifications/Gotify/GotifyProxy.cs b/src/NzbDrone.Core/Notifications/Gotify/GotifyProxy.cs index ab1130ab6..30eef6bd9 100644 --- a/src/NzbDrone.Core/Notifications/Gotify/GotifyProxy.cs +++ b/src/NzbDrone.Core/Notifications/Gotify/GotifyProxy.cs @@ -1,11 +1,12 @@ using System.Net; using NzbDrone.Common.Http; +using NzbDrone.Common.Serializer; namespace NzbDrone.Core.Notifications.Gotify { public interface IGotifyProxy { - void SendNotification(string title, string message, GotifySettings settings); + void SendNotification(GotifyMessage payload, GotifySettings settings); } public class GotifyProxy : IGotifyProxy @@ -17,16 +18,20 @@ namespace NzbDrone.Core.Notifications.Gotify _httpClient = httpClient; } - public void SendNotification(string title, string message, GotifySettings settings) + public void SendNotification(GotifyMessage payload, GotifySettings settings) { try { - var request = new HttpRequestBuilder(settings.Server).Resource("message").Post() - .AddQueryParam("token", settings.AppToken) - .AddFormParameter("title", title) - .AddFormParameter("message", message) - .AddFormParameter("priority", settings.Priority) - .Build(); + var request = new HttpRequestBuilder(settings.Server) + .Resource("message") + .Post() + .AddQueryParam("token", settings.AppToken) + .Build(); + + request.Headers.ContentType = "application/json"; + + var json = payload.ToJson(); + request.SetContent(payload.ToJson()); _httpClient.Execute(request); } diff --git a/src/NzbDrone.Core/Notifications/Gotify/GotifySettings.cs b/src/NzbDrone.Core/Notifications/Gotify/GotifySettings.cs index 7c5021e58..fda41517c 100644 --- a/src/NzbDrone.Core/Notifications/Gotify/GotifySettings.cs +++ b/src/NzbDrone.Core/Notifications/Gotify/GotifySettings.cs @@ -32,6 +32,9 @@ namespace NzbDrone.Core.Notifications.Gotify [FieldDefinition(2, Label = "Priority", Type = FieldType.Select, SelectOptions = typeof(GotifyPriority), HelpText = "Priority of the notification")] public int Priority { get; set; } + [FieldDefinition(3, Label = "Include Artist Poster", Type = FieldType.Checkbox, HelpText = "Include artist poster in message")] + public bool IncludeArtistPoster { get; set; } + public NzbDroneValidationResult Validate() { return new NzbDroneValidationResult(Validator.Validate(this));