Gotify notification updates

New: Option to include links for Gotify notifications
New: Include images and links for Android

(cherry picked from commit 3c857135c59029635b0972f959f9a8255bcff21f)

Closes #10433
Fixes #10410
pull/10440/head
Bogdan 4 months ago
parent c1f1307345
commit 7528882adf

@ -1099,6 +1099,10 @@
"NotificationsGotifySettingsAppToken": "App Token", "NotificationsGotifySettingsAppToken": "App Token",
"NotificationsGotifySettingsAppTokenHelpText": "The Application Token generated by Gotify", "NotificationsGotifySettingsAppTokenHelpText": "The Application Token generated by Gotify",
"NotificationsGotifySettingsPriorityHelpText": "Priority of the notification", "NotificationsGotifySettingsPriorityHelpText": "Priority of the notification",
"NotificationsGotifySettingsMetadataLinks": "Metadata Links",
"NotificationsGotifySettingsMetadataLinksMovieHelpText": "Add a links to movie metadata when sending notifications",
"NotificationsGotifySettingsPreferredMetadataLink": "Preferred Metadata Link",
"NotificationsGotifySettingsPreferredMetadataLinkHelpText": "Metadata link for clients that only support a single link",
"NotificationsGotifySettingsServer": "Gotify Server", "NotificationsGotifySettingsServer": "Gotify Server",
"NotificationsGotifySettingsServerHelpText": "Gotify server URL, including http(s):// and port if needed", "NotificationsGotifySettingsServerHelpText": "Gotify server URL, including http(s):// and port if needed",
"NotificationsJoinSettingsApiKeyHelpText": "The API Key from your Join account settings (click Join API button).", "NotificationsJoinSettingsApiKeyHelpText": "The API Key from your Join account settings (click Join API button).",

@ -4,6 +4,7 @@ using System.Linq;
using System.Text; using System.Text;
using FluentValidation.Results; using FluentValidation.Results;
using NLog; using NLog;
using NzbDrone.Common.Extensions;
using NzbDrone.Core.Localization; using NzbDrone.Core.Localization;
using NzbDrone.Core.MediaCover; using NzbDrone.Core.MediaCover;
using NzbDrone.Core.Movies; using NzbDrone.Core.Movies;
@ -12,6 +13,8 @@ namespace NzbDrone.Core.Notifications.Gotify
{ {
public class Gotify : NotificationBase<GotifySettings> public class Gotify : NotificationBase<GotifySettings>
{ {
private const string RadarrImageUrl = "https://raw.githubusercontent.com/Radarr/Radarr/develop/Logo/128.png";
private readonly IGotifyProxy _proxy; private readonly IGotifyProxy _proxy;
private readonly ILocalizationService _localizationService; private readonly ILocalizationService _localizationService;
private readonly Logger _logger; private readonly Logger _logger;
@ -83,20 +86,30 @@ namespace NzbDrone.Core.Notifications.Gotify
var sb = new StringBuilder(); var sb = new StringBuilder();
sb.AppendLine("This is a test message from Radarr"); sb.AppendLine("This is a test message from Radarr");
var payload = new GotifyMessage
{
Title = title,
Priority = Settings.Priority
};
if (Settings.IncludeMoviePoster) if (Settings.IncludeMoviePoster)
{ {
isMarkdown = true; isMarkdown = true;
sb.AppendLine("\r![](https://raw.githubusercontent.com/Radarr/Radarr/develop/Logo/128.png)"); sb.AppendLine($"\r![]({RadarrImageUrl})");
payload.SetImage(RadarrImageUrl);
} }
var payload = new GotifyMessage if (Settings.MetadataLinks.Any())
{ {
Title = title, isMarkdown = true;
Message = sb.ToString(),
Priority = Settings.Priority
};
sb.AppendLine("");
sb.AppendLine("[Radarr.video](https://radarr.video)");
payload.SetClickUrl("https://radarr.video");
}
payload.Message = sb.ToString();
payload.SetContentType(isMarkdown); payload.SetContentType(isMarkdown);
_proxy.SendNotification(payload, Settings); _proxy.SendNotification(payload, Settings);
@ -117,24 +130,66 @@ namespace NzbDrone.Core.Notifications.Gotify
sb.AppendLine(message); sb.AppendLine(message);
if (Settings.IncludeMoviePoster && movie != null) var payload = new GotifyMessage
{ {
var poster = movie.MovieMetadata.Value.Images.FirstOrDefault(x => x.CoverType == MediaCoverTypes.Poster)?.RemoteUrl; Title = title,
Priority = Settings.Priority
};
if (movie != null)
{
if (Settings.IncludeMoviePoster)
{
var poster = movie.MovieMetadata.Value.Images.FirstOrDefault(x => x.CoverType == MediaCoverTypes.Poster)?.RemoteUrl;
if (poster != null)
{
isMarkdown = true;
sb.AppendLine($"\r![]({poster})");
payload.SetImage(poster);
}
}
if (poster != null) if (Settings.MetadataLinks.Any())
{ {
isMarkdown = true; isMarkdown = true;
sb.AppendLine($"\r![]({poster})"); sb.AppendLine("");
foreach (var link in Settings.MetadataLinks)
{
var linkType = (MetadataLinkType)link;
var linkText = "";
var linkUrl = "";
if (linkType == MetadataLinkType.Tmdb && movie.TmdbId > 0)
{
linkText = "TMDb";
linkUrl = $"https://www.themoviedb.org/movie/{movie.TmdbId}";
}
if (linkType == MetadataLinkType.Imdb && movie.ImdbId.IsNotNullOrWhiteSpace())
{
linkText = "IMDb";
linkUrl = $"https://www.imdb.com/title/{movie.ImdbId}";
}
if (linkType == MetadataLinkType.Trakt && movie.TmdbId > 0)
{
linkText = "Trakt";
linkUrl = $"https://trakt.tv/search/tmdb/{movie.TmdbId}?id_type=movie";
}
sb.AppendLine($"[{linkText}]({linkUrl})");
if (link == Settings.PreferredMetadataLink)
{
payload.SetClickUrl(linkUrl);
}
}
} }
} }
var payload = new GotifyMessage payload.Message = sb.ToString();
{
Title = title,
Message = sb.ToString(),
Priority = Settings.Priority
};
payload.SetContentType(isMarkdown); payload.SetContentType(isMarkdown);
_proxy.SendNotification(payload, Settings); _proxy.SendNotification(payload, Settings);

@ -20,12 +20,27 @@ namespace NzbDrone.Core.Notifications.Gotify
Extras.ClientDisplay = new GotifyClientDisplay(contentType); Extras.ClientDisplay = new GotifyClientDisplay(contentType);
} }
public void SetImage(string imageUrl)
{
Extras.ClientNotification ??= new GotifyClientNotification();
Extras.ClientNotification.BigImageUrl = imageUrl;
}
public void SetClickUrl(string url)
{
Extras.ClientNotification ??= new GotifyClientNotification();
Extras.ClientNotification.Click = new GotifyClientNotificationClick(url);
}
} }
public class GotifyExtras public class GotifyExtras
{ {
[JsonProperty("client::display")] [JsonProperty("client::display")]
public GotifyClientDisplay ClientDisplay { get; set; } public GotifyClientDisplay ClientDisplay { get; set; }
[JsonProperty("client::notification")]
public GotifyClientNotification ClientNotification { get; set; }
} }
public class GotifyClientDisplay public class GotifyClientDisplay
@ -37,4 +52,20 @@ namespace NzbDrone.Core.Notifications.Gotify
ContentType = contentType; ContentType = contentType;
} }
} }
public class GotifyClientNotification
{
public string BigImageUrl { get; set; }
public GotifyClientNotificationClick Click { get; set; }
}
public class GotifyClientNotificationClick
{
public string Url { get; set; }
public GotifyClientNotificationClick(string url)
{
Url = url;
}
}
} }

@ -1,4 +1,8 @@
using System;
using System.Collections.Generic;
using System.Linq;
using FluentValidation; using FluentValidation;
using NzbDrone.Common.Extensions;
using NzbDrone.Core.Annotations; using NzbDrone.Core.Annotations;
using NzbDrone.Core.Validation; using NzbDrone.Core.Validation;
@ -10,6 +14,30 @@ namespace NzbDrone.Core.Notifications.Gotify
{ {
RuleFor(c => c.Server).IsValidUrl(); RuleFor(c => c.Server).IsValidUrl();
RuleFor(c => c.AppToken).NotEmpty(); RuleFor(c => c.AppToken).NotEmpty();
RuleFor(c => c.MetadataLinks).Custom((links, context) =>
{
foreach (var link in links)
{
if (!Enum.IsDefined(typeof(MetadataLinkType), link))
{
context.AddFailure("MetadataLinks", $"MetadataLink is not valid: {link}");
}
}
});
RuleFor(c => c).Custom((c, context) =>
{
if (c.MetadataLinks.Empty())
{
return;
}
if (!c.MetadataLinks.Contains(c.PreferredMetadataLink))
{
context.AddFailure("PreferredMetadataLink", "Must be a selected link");
}
});
} }
} }
@ -20,6 +48,8 @@ namespace NzbDrone.Core.Notifications.Gotify
public GotifySettings() public GotifySettings()
{ {
Priority = 5; Priority = 5;
MetadataLinks = Enumerable.Empty<int>();
PreferredMetadataLink = (int)MetadataLinkType.Tmdb;
} }
[FieldDefinition(0, Label = "NotificationsGotifySettingsServer", HelpText = "NotificationsGotifySettingsServerHelpText")] [FieldDefinition(0, Label = "NotificationsGotifySettingsServer", HelpText = "NotificationsGotifySettingsServerHelpText")]
@ -34,6 +64,12 @@ namespace NzbDrone.Core.Notifications.Gotify
[FieldDefinition(3, Label = "NotificationsGotifySettingIncludeMoviePoster", Type = FieldType.Checkbox, HelpText = "NotificationsGotifySettingIncludeMoviePosterHelpText")] [FieldDefinition(3, Label = "NotificationsGotifySettingIncludeMoviePoster", Type = FieldType.Checkbox, HelpText = "NotificationsGotifySettingIncludeMoviePosterHelpText")]
public bool IncludeMoviePoster { get; set; } public bool IncludeMoviePoster { get; set; }
[FieldDefinition(4, Label = "NotificationsGotifySettingsMetadataLinks", Type = FieldType.Select, SelectOptions = typeof(MetadataLinkType), HelpText = "NotificationsGotifySettingsMetadataLinksMovieHelpText")]
public IEnumerable<int> MetadataLinks { get; set; }
[FieldDefinition(5, Label = "NotificationsGotifySettingsPreferredMetadataLink", Type = FieldType.Select, SelectOptions = typeof(MetadataLinkType), HelpText = "NotificationsGotifySettingsPreferredMetadataLinkHelpText")]
public int PreferredMetadataLink { get; set; }
public override NzbDroneValidationResult Validate() public override NzbDroneValidationResult Validate()
{ {
return new NzbDroneValidationResult(Validator.Validate(this)); return new NzbDroneValidationResult(Validator.Validate(this));

@ -0,0 +1,16 @@
using NzbDrone.Core.Annotations;
namespace NzbDrone.Core.Notifications
{
public enum MetadataLinkType
{
[FieldOption(Label = "TMDb")]
Tmdb = 0,
[FieldOption(Label = "IMDb")]
Imdb = 1,
[FieldOption(Label = "Trakt")]
Trakt = 2
}
}
Loading…
Cancel
Save