From 01ce5b2041eb5ee0cd7feb26bdb810eab1dc9cb2 Mon Sep 17 00:00:00 2001 From: Daniel Tolnai Date: Sun, 24 Mar 2024 17:10:51 +0100 Subject: [PATCH] Implement option to skip sending webhooks with an empty message body (#202) --- .../Configuration/Web/config.html | 4 ++++ .../Configuration/Web/config.js | 2 ++ .../Destinations/BaseClient.cs | 21 +++++++++++++++++++ .../Destinations/BaseOption.cs | 5 +++++ .../Destinations/Discord/DiscordClient.cs | 5 +++++ .../Destinations/Generic/GenericClient.cs | 5 +++++ .../GenericForm/GenericFormClient.cs | 5 +++++ .../Destinations/Gotify/GotifyClient.cs | 5 +++++ .../Destinations/Mqtt/MqttClient.cs | 5 +++++ .../Pushbullet/PushbulletClient.cs | 5 +++++ .../Destinations/Pushover/PushoverClient.cs | 5 +++++ .../Destinations/Slack/SlackClient.cs | 5 +++++ .../Destinations/Smtp/SmtpClient.cs | 9 +++++--- 13 files changed, 78 insertions(+), 3 deletions(-) diff --git a/Jellyfin.Plugin.Webhook/Configuration/Web/config.html b/Jellyfin.Plugin.Webhook/Configuration/Web/config.html index e7ec7bb..88e78f0 100644 --- a/Jellyfin.Plugin.Webhook/Configuration/Web/config.html +++ b/Jellyfin.Plugin.Webhook/Configuration/Web/config.html @@ -116,6 +116,10 @@ Send All Properties (ignores template) +
diff --git a/Jellyfin.Plugin.Webhook/Configuration/Web/config.js b/Jellyfin.Plugin.Webhook/Configuration/Web/config.js index d271f41..562590b 100644 --- a/Jellyfin.Plugin.Webhook/Configuration/Web/config.js +++ b/Jellyfin.Plugin.Webhook/Configuration/Web/config.js @@ -162,6 +162,7 @@ element.querySelector("[data-name=txtWebhookName]").value = config.WebhookName || ""; element.querySelector("[data-name=txtWebhookUri]").value = config.WebhookUri || ""; element.querySelector("[data-name=chkSendAllProperties]").checked = config.SendAllProperties || false; + element.querySelector("[data-name=chkSkipEmptyMessageBody]").checked = config.SkipEmptyMessageBody || false; element.querySelector("[data-name=txtTemplate]").value = Webhook.atou(config.Template || ""); const notificationTypeContainer = element.querySelector("[data-name=notificationTypeContainer]"); @@ -182,6 +183,7 @@ config.WebhookName = element.querySelector("[data-name=txtWebhookName]").value || ""; config.WebhookUri = element.querySelector("[data-name=txtWebhookUri]").value || ""; config.SendAllProperties = element.querySelector("[data-name=chkSendAllProperties]").checked || false; + config.SkipEmptyMessageBody = element.querySelector("[data-name=chkSkipEmptyMessageBody]").checked || false; config.Template = Webhook.utoa(element.querySelector("[data-name=txtTemplate]").value || ""); config.NotificationTypes = []; diff --git a/Jellyfin.Plugin.Webhook/Destinations/BaseClient.cs b/Jellyfin.Plugin.Webhook/Destinations/BaseClient.cs index 2ac5fbd..0ce4892 100644 --- a/Jellyfin.Plugin.Webhook/Destinations/BaseClient.cs +++ b/Jellyfin.Plugin.Webhook/Destinations/BaseClient.cs @@ -36,4 +36,25 @@ public class BaseClient return true; } + + /// + /// Determines whether the client should send the webhook with the given message body. + /// + /// Instance of the interface. + /// The sender option. + /// The message body. + /// Whether the client should send the webhook. + protected bool SendMessageBody( + ILogger logger, + BaseOption option, + string body) + { + if (option.SkipEmptyMessageBody && string.IsNullOrWhiteSpace(body)) + { + logger.LogDebug("Skip sending empty message body"); + return false; + } + + return true; + } } diff --git a/Jellyfin.Plugin.Webhook/Destinations/BaseOption.cs b/Jellyfin.Plugin.Webhook/Destinations/BaseOption.cs index c51a0f7..7837edd 100644 --- a/Jellyfin.Plugin.Webhook/Destinations/BaseOption.cs +++ b/Jellyfin.Plugin.Webhook/Destinations/BaseOption.cs @@ -67,6 +67,11 @@ public abstract class BaseOption /// public bool SendAllProperties { get; set; } + /// + /// Gets or sets a value indicating whether to skip sending an empty message body. + /// + public bool SkipEmptyMessageBody { get; set; } + /// /// Gets or sets the handlebars template. /// diff --git a/Jellyfin.Plugin.Webhook/Destinations/Discord/DiscordClient.cs b/Jellyfin.Plugin.Webhook/Destinations/Discord/DiscordClient.cs index 3ccc1a8..7aced48 100644 --- a/Jellyfin.Plugin.Webhook/Destinations/Discord/DiscordClient.cs +++ b/Jellyfin.Plugin.Webhook/Destinations/Discord/DiscordClient.cs @@ -64,6 +64,11 @@ public class DiscordClient : BaseClient, IWebhookClient } var body = option.GetMessageBody(data); + if (!SendMessageBody(_logger, option, body)) + { + return; + } + _logger.LogDebug("SendAsync Body: {@Body}", body); using var content = new StringContent(body, Encoding.UTF8, MediaTypeNames.Application.Json); using var response = await _httpClientFactory diff --git a/Jellyfin.Plugin.Webhook/Destinations/Generic/GenericClient.cs b/Jellyfin.Plugin.Webhook/Destinations/Generic/GenericClient.cs index 17a212e..a3af9c0 100644 --- a/Jellyfin.Plugin.Webhook/Destinations/Generic/GenericClient.cs +++ b/Jellyfin.Plugin.Webhook/Destinations/Generic/GenericClient.cs @@ -53,6 +53,11 @@ public class GenericClient : BaseClient, IWebhookClient } var body = option.GetMessageBody(data); + if (!SendMessageBody(_logger, option, body)) + { + return; + } + _logger.LogDebug("SendAsync Body: {@Body}", body); using var httpRequestMessage = new HttpRequestMessage(HttpMethod.Post, option.WebhookUri); var contentType = MediaTypeNames.Text.Plain; diff --git a/Jellyfin.Plugin.Webhook/Destinations/GenericForm/GenericFormClient.cs b/Jellyfin.Plugin.Webhook/Destinations/GenericForm/GenericFormClient.cs index 1036b81..05a65c7 100644 --- a/Jellyfin.Plugin.Webhook/Destinations/GenericForm/GenericFormClient.cs +++ b/Jellyfin.Plugin.Webhook/Destinations/GenericForm/GenericFormClient.cs @@ -50,6 +50,11 @@ public class GenericFormClient : BaseClient, IWebhookClient } var body = option.GetMessageBody(data); + if (!SendMessageBody(_logger, option, body)) + { + return; + } + var dictionaryBody = JsonSerializer.Deserialize>(body); if (dictionaryBody is null) { diff --git a/Jellyfin.Plugin.Webhook/Destinations/Gotify/GotifyClient.cs b/Jellyfin.Plugin.Webhook/Destinations/Gotify/GotifyClient.cs index 808a155..5089d23 100644 --- a/Jellyfin.Plugin.Webhook/Destinations/Gotify/GotifyClient.cs +++ b/Jellyfin.Plugin.Webhook/Destinations/Gotify/GotifyClient.cs @@ -48,6 +48,11 @@ public class GotifyClient : BaseClient, IWebhookClient data["Priority"] = option.Priority; var body = option.GetMessageBody(data); + if (!SendMessageBody(_logger, option, body)) + { + return; + } + _logger.LogDebug("SendAsync Body: {@Body}", body); using var content = new StringContent(body, Encoding.UTF8, MediaTypeNames.Application.Json); using var response = await _httpClientFactory diff --git a/Jellyfin.Plugin.Webhook/Destinations/Mqtt/MqttClient.cs b/Jellyfin.Plugin.Webhook/Destinations/Mqtt/MqttClient.cs index 17e5d98..4b21701 100644 --- a/Jellyfin.Plugin.Webhook/Destinations/Mqtt/MqttClient.cs +++ b/Jellyfin.Plugin.Webhook/Destinations/Mqtt/MqttClient.cs @@ -36,6 +36,11 @@ public class MqttClient : BaseClient, IWebhookClient } var body = option.GetMessageBody(data); + if (!SendMessageBody(_logger, option, body)) + { + return; + } + var client = _mqttClients.GetClient(option.Guid); if (client?.IsConnected != true) { diff --git a/Jellyfin.Plugin.Webhook/Destinations/Pushbullet/PushbulletClient.cs b/Jellyfin.Plugin.Webhook/Destinations/Pushbullet/PushbulletClient.cs index b1e79a4..cff91ba 100644 --- a/Jellyfin.Plugin.Webhook/Destinations/Pushbullet/PushbulletClient.cs +++ b/Jellyfin.Plugin.Webhook/Destinations/Pushbullet/PushbulletClient.cs @@ -45,6 +45,11 @@ public class PushbulletClient : BaseClient, IWebhookClient data["PushbulletChannel"] = option.Channel; var body = option.GetMessageBody(data); + if (!SendMessageBody(_logger, option, body)) + { + return; + } + _logger.LogDebug("SendAsync Body: {@Body}", body); using var requestOptions = new HttpRequestMessage(HttpMethod.Post, string.IsNullOrEmpty(option.WebhookUri) ? PushbulletOption.ApiUrl : option.WebhookUri); diff --git a/Jellyfin.Plugin.Webhook/Destinations/Pushover/PushoverClient.cs b/Jellyfin.Plugin.Webhook/Destinations/Pushover/PushoverClient.cs index e6b7ffd..aaa7f6d 100644 --- a/Jellyfin.Plugin.Webhook/Destinations/Pushover/PushoverClient.cs +++ b/Jellyfin.Plugin.Webhook/Destinations/Pushover/PushoverClient.cs @@ -72,6 +72,11 @@ public class PushoverClient : BaseClient, IWebhookClient } var body = option.GetMessageBody(data); + if (!SendMessageBody(_logger, option, body)) + { + return; + } + _logger.LogDebug("SendAsync Body: {@Body}", body); using var content = new StringContent(body, Encoding.UTF8, MediaTypeNames.Application.Json); using var response = await _httpClientFactory diff --git a/Jellyfin.Plugin.Webhook/Destinations/Slack/SlackClient.cs b/Jellyfin.Plugin.Webhook/Destinations/Slack/SlackClient.cs index 2b505a1..df17770 100644 --- a/Jellyfin.Plugin.Webhook/Destinations/Slack/SlackClient.cs +++ b/Jellyfin.Plugin.Webhook/Destinations/Slack/SlackClient.cs @@ -49,6 +49,11 @@ public class SlackClient : BaseClient, IWebhookClient data["SlackIconUrl"] = option.IconUrl; var body = option.GetMessageBody(data); + if (!SendMessageBody(_logger, option, body)) + { + return; + } + _logger.LogDebug("SendAsync Body: {@Body}", body); using var content = new StringContent(body, Encoding.UTF8, MediaTypeNames.Application.Json); using var response = await _httpClientFactory diff --git a/Jellyfin.Plugin.Webhook/Destinations/Smtp/SmtpClient.cs b/Jellyfin.Plugin.Webhook/Destinations/Smtp/SmtpClient.cs index 190e6e6..1ad360e 100644 --- a/Jellyfin.Plugin.Webhook/Destinations/Smtp/SmtpClient.cs +++ b/Jellyfin.Plugin.Webhook/Destinations/Smtp/SmtpClient.cs @@ -37,10 +37,13 @@ public class SmtpClient : BaseClient, IWebhookClient message.To.Add(new MailboxAddress(option.ReceiverAddress, option.ReceiverAddress)); message.Subject = option.GetCompiledSubjectTemplate()(data); - message.Body = new TextPart(option.IsHtml ? "html" : "plain") + var body = option.GetMessageBody(data); + if (!SendMessageBody(_logger, option, body)) { - Text = option.GetMessageBody(data) - }; + return; + } + + message.Body = new TextPart(option.IsHtml ? "html" : "plain") { Text = body }; using var smtpClient = new MailKit.Net.Smtp.SmtpClient(); await smtpClient.ConnectAsync(option.SmtpServer, option.SmtpPort, option.UseSsl)