Cleanup and multiple links

This commit is contained in:
Mark McDowall 2024-04-13 09:26:59 -07:00
parent 6fec6edc3b
commit bc97e884a3
5 changed files with 93 additions and 52 deletions

View File

@ -1429,12 +1429,12 @@
"NotificationsTelegramSettingsChatIdHelpText": "You must start a conversation with the bot or add it to your group to receive messages", "NotificationsTelegramSettingsChatIdHelpText": "You must start a conversation with the bot or add it to your group to receive messages",
"NotificationsTelegramSettingsIncludeAppName": "Include {appName} in Title", "NotificationsTelegramSettingsIncludeAppName": "Include {appName} in Title",
"NotificationsTelegramSettingsIncludeAppNameHelpText": "Optionally prefix message title with {appName} to differentiate notifications from different applications", "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", "NotificationsTelegramSettingsSendSilently": "Send Silently",
"NotificationsTelegramSettingsSendSilentlyHelpText": "Sends the message silently. Users will receive a notification with no sound", "NotificationsTelegramSettingsSendSilentlyHelpText": "Sends the message silently. Users will receive a notification with no sound",
"NotificationsTelegramSettingsTopicId": "Topic ID", "NotificationsTelegramSettingsTopicId": "Topic ID",
"NotificationsTelegramSettingsTopicIdHelpText": "Specify a Topic ID to send notifications to that topic. Leave blank to use the general topic (Supergroups only)", "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", "NotificationsTraktSettingsAccessToken": "Access Token",
"NotificationsTraktSettingsAuthUser": "Auth User", "NotificationsTraktSettingsAuthUser": "Auth User",
"NotificationsTraktSettingsAuthenticateWithTrakt": "Authenticate with Trakt", "NotificationsTraktSettingsAuthenticateWithTrakt": "Authenticate with Trakt",

View File

@ -20,73 +20,77 @@ namespace NzbDrone.Core.Notifications.Telegram
public override void OnGrab(GrabMessage grabMessage) public override void OnGrab(GrabMessage grabMessage)
{ {
var title = Settings.IncludeAppNameInTitle ? EPISODE_GRABBED_TITLE_BRANDED : EPISODE_GRABBED_TITLE; 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) public override void OnDownload(DownloadMessage message)
{ {
var title = Settings.IncludeAppNameInTitle ? EPISODE_DOWNLOADED_TITLE_BRANDED : EPISODE_DOWNLOADED_TITLE; 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) public override void OnImportComplete(ImportCompleteMessage message)
{ {
var title = Settings.IncludeAppNameInTitle ? EPISODE_DOWNLOADED_TITLE_BRANDED : EPISODE_DOWNLOADED_TITLE; 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) public override void OnEpisodeFileDelete(EpisodeDeleteMessage deleteMessage)
{ {
var title = Settings.IncludeAppNameInTitle ? EPISODE_DELETED_TITLE_BRANDED : EPISODE_DELETED_TITLE; 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) public override void OnSeriesAdd(SeriesAddMessage message)
{ {
var title = Settings.IncludeAppNameInTitle ? SERIES_ADDED_TITLE_BRANDED : SERIES_ADDED_TITLE; 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) public override void OnSeriesDelete(SeriesDeleteMessage deleteMessage)
{ {
var title = Settings.IncludeAppNameInTitle ? SERIES_DELETED_TITLE_BRANDED : SERIES_DELETED_TITLE; 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) public override void OnHealthIssue(HealthCheck.HealthCheck healthCheck)
{ {
var title = Settings.IncludeAppNameInTitle ? HEALTH_ISSUE_TITLE_BRANDED : HEALTH_ISSUE_TITLE; 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) public override void OnHealthRestored(HealthCheck.HealthCheck previousCheck)
{ {
var title = Settings.IncludeAppNameInTitle ? HEALTH_RESTORED_TITLE_BRANDED : HEALTH_RESTORED_TITLE; 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) public override void OnApplicationUpdate(ApplicationUpdateMessage updateMessage)
{ {
var title = Settings.IncludeAppNameInTitle ? APPLICATION_UPDATE_TITLE_BRANDED : APPLICATION_UPDATE_TITLE; 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) public override void OnManualInteractionRequired(ManualInteractionRequiredMessage message)
{ {
var title = Settings.IncludeAppNameInTitle ? MANUAL_INTERACTION_REQUIRED_TITLE_BRANDED : MANUAL_INTERACTION_REQUIRED_TITLE; 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() public override ValidationResult Test()
@ -98,36 +102,36 @@ namespace NzbDrone.Core.Notifications.Telegram
return new ValidationResult(failures); return new ValidationResult(failures);
} }
private string FormatMessageWithLink(string message, Series series) private List<TelegramLink> GetLinks(Series series)
{ {
var linkType = Settings.MetadataLinkType; var links = new List<TelegramLink>();
if (linkType == MetadataLinkType.None) foreach (var link in Settings.MetadataLinks)
{ {
return message; var linkType = (MetadataLinkType)link;
}
if (linkType == MetadataLinkType.Imdb && series.ImdbId.IsNotNullOrWhiteSpace()) if (linkType == MetadataLinkType.Imdb && series.ImdbId.IsNotNullOrWhiteSpace())
{ {
return $"[{message}](https://www.imdb.com/title/{series.ImdbId})"; links.Add(new TelegramLink("IMDb", $"https://www.imdb.com/title/{series.ImdbId}"));
} }
if (linkType == MetadataLinkType.Tvdb && series.TvdbId > 0) if (linkType == MetadataLinkType.Tvdb && series.TvdbId > 0)
{ {
return $"[{message}](http://www.thetvdb.com/?tab=series&id={series.TvdbId})"; links.Add(new TelegramLink("TVDb", $"http://www.thetvdb.com/?tab=series&id={series.TvdbId}"));
} }
if (linkType == MetadataLinkType.Trakt && series.TvdbId > 0) if (linkType == MetadataLinkType.Trakt && series.TvdbId > 0)
{ {
return $"[{message}](http://trakt.tv/search/tvdb/{series.TvdbId}?id_type=show)"; links.Add(new TelegramLink("TVMaze", $"http://trakt.tv/search/tvdb/{series.TvdbId}?id_type=show"));
} }
if (linkType == MetadataLinkType.Tvmaze && series.TvMazeId > 0) if (linkType == MetadataLinkType.Tvmaze && series.TvMazeId > 0)
{ {
return $"[{message}](http://www.tvmaze.com/shows/{series.TvMazeId}/_)"; links.Add(new TelegramLink("Trakt", $"http://www.tvmaze.com/shows/{series.TvMazeId}/_"));
}
} }
return message; return links;
} }
} }
} }

View File

@ -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;
}
}
}

View File

@ -1,6 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Net; using System.Net;
using System.Text;
using System.Web; using System.Web;
using FluentValidation.Results; using FluentValidation.Results;
using NLog; using NLog;
@ -13,7 +14,7 @@ namespace NzbDrone.Core.Notifications.Telegram
{ {
public interface ITelegramProxy public interface ITelegramProxy
{ {
void SendNotification(string title, string message, TelegramSettings settings); void SendNotification(string title, string message, List<TelegramLink> links, TelegramSettings settings);
ValidationFailure Test(TelegramSettings settings); ValidationFailure Test(TelegramSettings settings);
} }
@ -32,16 +33,22 @@ namespace NzbDrone.Core.Notifications.Telegram
_logger = logger; _logger = logger;
} }
public void SendNotification(string title, string message, TelegramSettings settings) public void SendNotification(string title, string message, List<TelegramLink> links, TelegramSettings settings)
{ {
// Format text to add the title before and bold using markdown var text = new StringBuilder($"<b>{HttpUtility.HtmlEncode(title)}</b>\n");
var text = $"*{HttpUtility.HtmlEncode(title)}*\n{HttpUtility.HtmlEncode(message)}";
text.AppendLine(HttpUtility.HtmlEncode(message));
foreach (var link in links)
{
text.AppendLine($"<a href=\"{link.Link}\">{HttpUtility.HtmlEncode(link.Label)}</a>");
}
var requestBuilder = new HttpRequestBuilder(URL).Resource("bot{token}/sendmessage").Post(); var requestBuilder = new HttpRequestBuilder(URL).Resource("bot{token}/sendmessage").Post();
var request = requestBuilder.SetSegment("token", settings.BotToken) var request = requestBuilder.SetSegment("token", settings.BotToken)
.AddFormParameter("chat_id", settings.ChatId) .AddFormParameter("chat_id", settings.ChatId)
.AddFormParameter("parse_mode", "MarkdownV2") .AddFormParameter("parse_mode", "HTML")
.AddFormParameter("text", text) .AddFormParameter("text", text)
.AddFormParameter("disable_notification", settings.SendSilently) .AddFormParameter("disable_notification", settings.SendSilently)
.AddFormParameter("message_thread_id", settings.TopicId) .AddFormParameter("message_thread_id", settings.TopicId)
@ -58,7 +65,12 @@ namespace NzbDrone.Core.Notifications.Telegram
const string title = "Test Notification"; const string title = "Test Notification";
const string body = "This is a test message from Sonarr"; const string body = "This is a test message from Sonarr";
SendNotification(settings.IncludeAppNameInTitle ? brandedTitle : title, body, settings); var links = new List<TelegramLink>
{
new TelegramLink("Sonarr.tv", "https://sonarr.tv")
};
SendNotification(settings.IncludeAppNameInTitle ? brandedTitle : title, body, links, settings);
} }
catch (Exception ex) catch (Exception ex)
{ {

View File

@ -1,4 +1,6 @@
using System; using System;
using System.Collections.Generic;
using System.Linq;
using FluentValidation; using FluentValidation;
using NzbDrone.Core.Annotations; using NzbDrone.Core.Annotations;
using NzbDrone.Core.Validation; using NzbDrone.Core.Validation;
@ -12,11 +14,14 @@ namespace NzbDrone.Core.Notifications.Telegram
RuleFor(c => c.ChatId).NotEmpty(); RuleFor(c => c.ChatId).NotEmpty();
RuleFor(c => c.TopicId).Must(topicId => !topicId.HasValue || topicId > 1) RuleFor(c => c.TopicId).Must(topicId => !topicId.HasValue || topicId > 1)
.WithMessage("Topic ID must be greater than 1 or empty"); .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 (); private static readonly TelegramSettingsValidator Validator = new ();
public TelegramSettings()
{
MetadataLinks = Enumerable.Empty<int>();
}
[FieldDefinition(0, Label = "NotificationsTelegramSettingsBotToken", Privacy = PrivacyLevel.ApiKey, HelpLink = "https://core.telegram.org/bots")] [FieldDefinition(0, Label = "NotificationsTelegramSettingsBotToken", Privacy = PrivacyLevel.ApiKey, HelpLink = "https://core.telegram.org/bots")]
public string BotToken { get; set; } public string BotToken { get; set; }
@ -41,8 +51,8 @@ namespace NzbDrone.Core.Notifications.Telegram
[FieldDefinition(4, Label = "NotificationsTelegramSettingsIncludeAppName", Type = FieldType.Checkbox, HelpText = "NotificationsTelegramSettingsIncludeAppNameHelpText")] [FieldDefinition(4, Label = "NotificationsTelegramSettingsIncludeAppName", Type = FieldType.Checkbox, HelpText = "NotificationsTelegramSettingsIncludeAppNameHelpText")]
public bool IncludeAppNameInTitle { get; set; } public bool IncludeAppNameInTitle { get; set; }
[FieldDefinition(5, Label = "NotificationsTelegramSettingsMetadataLinkType", Type = FieldType.Select, SelectOptions = typeof(MetadataLinkType), HelpText = "NotificationsTelegramSettingsMetadataLinkType")] [FieldDefinition(5, Label = "NotificationsTelegramSettingsMetadataLinks", Type = FieldType.Select, SelectOptions = typeof(MetadataLinkType), HelpText = "NotificationsTelegramSettingsMetadataLinksHelpText")]
public MetadataLinkType MetadataLinkType { get; set; } public IEnumerable<int> MetadataLinks { get; set; }
public override NzbDroneValidationResult Validate() public override NzbDroneValidationResult Validate()
{ {
@ -52,14 +62,15 @@ namespace NzbDrone.Core.Notifications.Telegram
public enum MetadataLinkType public enum MetadataLinkType
{ {
[FieldOption(Label = "None")]
None = 0,
[FieldOption(Label = "IMDb")] [FieldOption(Label = "IMDb")]
Imdb, Imdb,
[FieldOption(Label = "TVDb")] [FieldOption(Label = "TVDb")]
Tvdb, Tvdb,
[FieldOption(Label = "TVMaze")] [FieldOption(Label = "TVMaze")]
Tvmaze, Tvmaze,
[FieldOption(Label = "Trakt")] [FieldOption(Label = "Trakt")]
Trakt, Trakt,
} }