From bc97e884a34de38c327cfb7c444f45918f11251a Mon Sep 17 00:00:00 2001 From: Mark McDowall Date: Sat, 13 Apr 2024 09:26:59 -0700 Subject: [PATCH] Cleanup and multiple links --- src/NzbDrone.Core/Localization/Core/en.json | 4 +- .../Notifications/Telegram/Telegram.cs | 78 ++++++++++--------- .../Notifications/Telegram/TelegramLink.cs | 14 ++++ .../Notifications/Telegram/TelegramProxy.cs | 24 ++++-- .../Telegram/TelegramSettings.cs | 25 ++++-- 5 files changed, 93 insertions(+), 52 deletions(-) create mode 100644 src/NzbDrone.Core/Notifications/Telegram/TelegramLink.cs diff --git a/src/NzbDrone.Core/Localization/Core/en.json b/src/NzbDrone.Core/Localization/Core/en.json index 01fb12483..a36ccadec 100644 --- a/src/NzbDrone.Core/Localization/Core/en.json +++ b/src/NzbDrone.Core/Localization/Core/en.json @@ -1429,12 +1429,12 @@ "NotificationsTelegramSettingsChatIdHelpText": "You must start a conversation with the bot or add it to your group to receive messages", "NotificationsTelegramSettingsIncludeAppName": "Include {appName} in Title", "NotificationsTelegramSettingsIncludeAppNameHelpText": "Optionally prefix message title with {appName} to differentiate notifications from different applications", + "NotificationsTelegramSettingsMetadataLinks": "Metadata Links", + "NotificationsTelegramSettingsMetadataLinksHelpText": "Add a links to series metadata when sending notifications", "NotificationsTelegramSettingsSendSilently": "Send Silently", "NotificationsTelegramSettingsSendSilentlyHelpText": "Sends the message silently. Users will receive a notification with no sound", "NotificationsTelegramSettingsTopicId": "Topic ID", "NotificationsTelegramSettingsTopicIdHelpText": "Specify a Topic ID to send notifications to that topic. Leave blank to use the general topic (Supergroups only)", - "NotificationsTelegramSettingsSendMetadataLink": "Add a link to the series metadata", - "NotificationsTelegramSettingsSendMetadataLinkHelpText": "Add a link to the series metadata when sending the notifications", "NotificationsTraktSettingsAccessToken": "Access Token", "NotificationsTraktSettingsAuthUser": "Auth User", "NotificationsTraktSettingsAuthenticateWithTrakt": "Authenticate with Trakt", diff --git a/src/NzbDrone.Core/Notifications/Telegram/Telegram.cs b/src/NzbDrone.Core/Notifications/Telegram/Telegram.cs index a4b9ffd6c..4d23c3ac9 100644 --- a/src/NzbDrone.Core/Notifications/Telegram/Telegram.cs +++ b/src/NzbDrone.Core/Notifications/Telegram/Telegram.cs @@ -20,73 +20,77 @@ namespace NzbDrone.Core.Notifications.Telegram public override void OnGrab(GrabMessage grabMessage) { var title = Settings.IncludeAppNameInTitle ? EPISODE_GRABBED_TITLE_BRANDED : EPISODE_GRABBED_TITLE; + var links = GetLinks(grabMessage.Series); - _proxy.SendNotification(title, grabMessage.Message, Settings); + _proxy.SendNotification(title, grabMessage.Message, links, Settings); } public override void OnDownload(DownloadMessage message) { var title = Settings.IncludeAppNameInTitle ? EPISODE_DOWNLOADED_TITLE_BRANDED : EPISODE_DOWNLOADED_TITLE; + var links = GetLinks(message.Series); - _proxy.SendNotification(title, message.Message, Settings); + _proxy.SendNotification(title, message.Message, links, Settings); } public override void OnImportComplete(ImportCompleteMessage message) { var title = Settings.IncludeAppNameInTitle ? EPISODE_DOWNLOADED_TITLE_BRANDED : EPISODE_DOWNLOADED_TITLE; + var links = GetLinks(message.Series); - _proxy.SendNotification(title, message.Message, Settings); + _proxy.SendNotification(title, message.Message, links, Settings); } public override void OnEpisodeFileDelete(EpisodeDeleteMessage deleteMessage) { var title = Settings.IncludeAppNameInTitle ? EPISODE_DELETED_TITLE_BRANDED : EPISODE_DELETED_TITLE; + var links = GetLinks(deleteMessage.Series); - _proxy.SendNotification(title, deleteMessage.Message, Settings); + _proxy.SendNotification(title, deleteMessage.Message, links, Settings); } public override void OnSeriesAdd(SeriesAddMessage message) { var title = Settings.IncludeAppNameInTitle ? SERIES_ADDED_TITLE_BRANDED : SERIES_ADDED_TITLE; - var text = FormatMessageWithLink(message.Message, message.Series); + var links = GetLinks(message.Series); - _proxy.SendNotification(title, text, Settings); + _proxy.SendNotification(title, message.Message, links, Settings); } public override void OnSeriesDelete(SeriesDeleteMessage deleteMessage) { var title = Settings.IncludeAppNameInTitle ? SERIES_DELETED_TITLE_BRANDED : SERIES_DELETED_TITLE; - var text = FormatMessageWithLink(deleteMessage.Message, deleteMessage.Series); + var links = GetLinks(deleteMessage.Series); - _proxy.SendNotification(title, text, Settings); + _proxy.SendNotification(title, deleteMessage.Message, links, Settings); } public override void OnHealthIssue(HealthCheck.HealthCheck healthCheck) { var title = Settings.IncludeAppNameInTitle ? HEALTH_ISSUE_TITLE_BRANDED : HEALTH_ISSUE_TITLE; - _proxy.SendNotification(title, healthCheck.Message, Settings); + _proxy.SendNotification(title, healthCheck.Message, null, Settings); } public override void OnHealthRestored(HealthCheck.HealthCheck previousCheck) { var title = Settings.IncludeAppNameInTitle ? HEALTH_RESTORED_TITLE_BRANDED : HEALTH_RESTORED_TITLE; - _proxy.SendNotification(title, $"The following issue is now resolved: {previousCheck.Message}", Settings); + _proxy.SendNotification(title, $"The following issue is now resolved: {previousCheck.Message}", null, Settings); } public override void OnApplicationUpdate(ApplicationUpdateMessage updateMessage) { var title = Settings.IncludeAppNameInTitle ? APPLICATION_UPDATE_TITLE_BRANDED : APPLICATION_UPDATE_TITLE; - _proxy.SendNotification(title, updateMessage.Message, Settings); + _proxy.SendNotification(title, updateMessage.Message, null, Settings); } public override void OnManualInteractionRequired(ManualInteractionRequiredMessage message) { var title = Settings.IncludeAppNameInTitle ? MANUAL_INTERACTION_REQUIRED_TITLE_BRANDED : MANUAL_INTERACTION_REQUIRED_TITLE; - _proxy.SendNotification(title, message.Message, Settings); + _proxy.SendNotification(title, message.Message, null, Settings); } public override ValidationResult Test() @@ -98,36 +102,36 @@ namespace NzbDrone.Core.Notifications.Telegram return new ValidationResult(failures); } - private string FormatMessageWithLink(string message, Series series) + private List GetLinks(Series series) { - var linkType = Settings.MetadataLinkType; + var links = new List(); - if (linkType == MetadataLinkType.None) + foreach (var link in Settings.MetadataLinks) { - return message; + var linkType = (MetadataLinkType)link; + + if (linkType == MetadataLinkType.Imdb && series.ImdbId.IsNotNullOrWhiteSpace()) + { + links.Add(new TelegramLink("IMDb", $"https://www.imdb.com/title/{series.ImdbId}")); + } + + if (linkType == MetadataLinkType.Tvdb && series.TvdbId > 0) + { + links.Add(new TelegramLink("TVDb", $"http://www.thetvdb.com/?tab=series&id={series.TvdbId}")); + } + + if (linkType == MetadataLinkType.Trakt && series.TvdbId > 0) + { + links.Add(new TelegramLink("TVMaze", $"http://trakt.tv/search/tvdb/{series.TvdbId}?id_type=show")); + } + + if (linkType == MetadataLinkType.Tvmaze && series.TvMazeId > 0) + { + links.Add(new TelegramLink("Trakt", $"http://www.tvmaze.com/shows/{series.TvMazeId}/_")); + } } - if (linkType == MetadataLinkType.Imdb && series.ImdbId.IsNotNullOrWhiteSpace()) - { - return $"[{message}](https://www.imdb.com/title/{series.ImdbId})"; - } - - if (linkType == MetadataLinkType.Tvdb && series.TvdbId > 0) - { - return $"[{message}](http://www.thetvdb.com/?tab=series&id={series.TvdbId})"; - } - - if (linkType == MetadataLinkType.Trakt && series.TvdbId > 0) - { - return $"[{message}](http://trakt.tv/search/tvdb/{series.TvdbId}?id_type=show)"; - } - - if (linkType == MetadataLinkType.Tvmaze && series.TvMazeId > 0) - { - return $"[{message}](http://www.tvmaze.com/shows/{series.TvMazeId}/_)"; - } - - return message; + return links; } } } diff --git a/src/NzbDrone.Core/Notifications/Telegram/TelegramLink.cs b/src/NzbDrone.Core/Notifications/Telegram/TelegramLink.cs new file mode 100644 index 000000000..ac131b483 --- /dev/null +++ b/src/NzbDrone.Core/Notifications/Telegram/TelegramLink.cs @@ -0,0 +1,14 @@ +namespace NzbDrone.Core.Notifications.Telegram +{ + public class TelegramLink + { + public string Label { get; set; } + public string Link { get; set; } + + public TelegramLink(string label, string link) + { + Label = label; + Link = link; + } + } +} diff --git a/src/NzbDrone.Core/Notifications/Telegram/TelegramProxy.cs b/src/NzbDrone.Core/Notifications/Telegram/TelegramProxy.cs index 465aff9ed..48f70761e 100644 --- a/src/NzbDrone.Core/Notifications/Telegram/TelegramProxy.cs +++ b/src/NzbDrone.Core/Notifications/Telegram/TelegramProxy.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Net; +using System.Text; using System.Web; using FluentValidation.Results; using NLog; @@ -13,7 +14,7 @@ namespace NzbDrone.Core.Notifications.Telegram { public interface ITelegramProxy { - void SendNotification(string title, string message, TelegramSettings settings); + void SendNotification(string title, string message, List links, TelegramSettings settings); ValidationFailure Test(TelegramSettings settings); } @@ -32,16 +33,22 @@ namespace NzbDrone.Core.Notifications.Telegram _logger = logger; } - public void SendNotification(string title, string message, TelegramSettings settings) + public void SendNotification(string title, string message, List links, TelegramSettings settings) { - // Format text to add the title before and bold using markdown - var text = $"*{HttpUtility.HtmlEncode(title)}*\n{HttpUtility.HtmlEncode(message)}"; + var text = new StringBuilder($"{HttpUtility.HtmlEncode(title)}\n"); + + text.AppendLine(HttpUtility.HtmlEncode(message)); + + foreach (var link in links) + { + text.AppendLine($"{HttpUtility.HtmlEncode(link.Label)}"); + } var requestBuilder = new HttpRequestBuilder(URL).Resource("bot{token}/sendmessage").Post(); var request = requestBuilder.SetSegment("token", settings.BotToken) .AddFormParameter("chat_id", settings.ChatId) - .AddFormParameter("parse_mode", "MarkdownV2") + .AddFormParameter("parse_mode", "HTML") .AddFormParameter("text", text) .AddFormParameter("disable_notification", settings.SendSilently) .AddFormParameter("message_thread_id", settings.TopicId) @@ -58,7 +65,12 @@ namespace NzbDrone.Core.Notifications.Telegram const string title = "Test Notification"; const string body = "This is a test message from Sonarr"; - SendNotification(settings.IncludeAppNameInTitle ? brandedTitle : title, body, settings); + var links = new List + { + new TelegramLink("Sonarr.tv", "https://sonarr.tv") + }; + + SendNotification(settings.IncludeAppNameInTitle ? brandedTitle : title, body, links, settings); } catch (Exception ex) { diff --git a/src/NzbDrone.Core/Notifications/Telegram/TelegramSettings.cs b/src/NzbDrone.Core/Notifications/Telegram/TelegramSettings.cs index 4ff9d9573..6ec3d4d15 100644 --- a/src/NzbDrone.Core/Notifications/Telegram/TelegramSettings.cs +++ b/src/NzbDrone.Core/Notifications/Telegram/TelegramSettings.cs @@ -1,4 +1,6 @@ using System; +using System.Collections.Generic; +using System.Linq; using FluentValidation; using NzbDrone.Core.Annotations; using NzbDrone.Core.Validation; @@ -12,11 +14,14 @@ namespace NzbDrone.Core.Notifications.Telegram RuleFor(c => c.ChatId).NotEmpty(); RuleFor(c => c.TopicId).Must(topicId => !topicId.HasValue || topicId > 1) .WithMessage("Topic ID must be greater than 1 or empty"); - RuleFor(c => c.MetadataLinkType).Custom((metadataLinkType, context) => + RuleFor(c => c.MetadataLinks).Custom((links, context) => { - if (!Enum.IsDefined(typeof(MetadataLinkType), metadataLinkType)) + foreach (var link in links) { - context.AddFailure($"MetadataLinkType is not valid: {0}"); + if (!Enum.IsDefined(typeof(MetadataLinkType), link)) + { + context.AddFailure("MetadataLinks", $"MetadataLink is not valid: {link}"); + } } }); } @@ -26,6 +31,11 @@ namespace NzbDrone.Core.Notifications.Telegram { private static readonly TelegramSettingsValidator Validator = new (); + public TelegramSettings() + { + MetadataLinks = Enumerable.Empty(); + } + [FieldDefinition(0, Label = "NotificationsTelegramSettingsBotToken", Privacy = PrivacyLevel.ApiKey, HelpLink = "https://core.telegram.org/bots")] public string BotToken { get; set; } @@ -41,8 +51,8 @@ namespace NzbDrone.Core.Notifications.Telegram [FieldDefinition(4, Label = "NotificationsTelegramSettingsIncludeAppName", Type = FieldType.Checkbox, HelpText = "NotificationsTelegramSettingsIncludeAppNameHelpText")] public bool IncludeAppNameInTitle { get; set; } - [FieldDefinition(5, Label = "NotificationsTelegramSettingsMetadataLinkType", Type = FieldType.Select, SelectOptions = typeof(MetadataLinkType), HelpText = "NotificationsTelegramSettingsMetadataLinkType")] - public MetadataLinkType MetadataLinkType { get; set; } + [FieldDefinition(5, Label = "NotificationsTelegramSettingsMetadataLinks", Type = FieldType.Select, SelectOptions = typeof(MetadataLinkType), HelpText = "NotificationsTelegramSettingsMetadataLinksHelpText")] + public IEnumerable MetadataLinks { get; set; } public override NzbDroneValidationResult Validate() { @@ -52,14 +62,15 @@ namespace NzbDrone.Core.Notifications.Telegram public enum MetadataLinkType { - [FieldOption(Label = "None")] - None = 0, [FieldOption(Label = "IMDb")] Imdb, + [FieldOption(Label = "TVDb")] Tvdb, + [FieldOption(Label = "TVMaze")] Tvmaze, + [FieldOption(Label = "Trakt")] Trakt, }