From ef0a15890012dc2be890404d80e489ce4e269239 Mon Sep 17 00:00:00 2001 From: Kalon Shannon-Innes Date: Fri, 19 Dec 2025 12:06:54 +0000 Subject: [PATCH 1/3] New: Add instance name setting to Gotify Notifications --- .../GotifyTests/GotifyServiceFixture.cs | 68 +++++++++++++++++++ src/NzbDrone.Core/Localization/Core/en.json | 4 +- .../Notifications/Gotify/Gotify.cs | 17 ++++- .../Notifications/Gotify/GotifySettings.cs | 7 +- 4 files changed, 91 insertions(+), 5 deletions(-) create mode 100644 src/NzbDrone.Core.Test/NotificationTests/GotifyTests/GotifyServiceFixture.cs diff --git a/src/NzbDrone.Core.Test/NotificationTests/GotifyTests/GotifyServiceFixture.cs b/src/NzbDrone.Core.Test/NotificationTests/GotifyTests/GotifyServiceFixture.cs new file mode 100644 index 0000000000..9a2766bf26 --- /dev/null +++ b/src/NzbDrone.Core.Test/NotificationTests/GotifyTests/GotifyServiceFixture.cs @@ -0,0 +1,68 @@ +using System; +using System.Linq; +using Moq; +using NUnit.Framework; +using NzbDrone.Core.Configuration; +using NzbDrone.Core.Movies; +using NzbDrone.Core.Notifications; +using NzbDrone.Core.Notifications.Gotify; +using NzbDrone.Core.Test.Framework; + +namespace NzbDrone.Core.Test.NotificationTests +{ + [TestFixture] + public class GotifyServiceFixture : CoreTest + { + [SetUp] + public void Setup() + { + Subject.Definition = new NotificationDefinition + { + Settings = new GotifySettings + { + Server = "https://example.invalid", + AppToken = "token", + Priority = 5, + IncludeMoviePoster = false, + IncludeInstanceNameInTitle = false, + MetadataLinks = Enumerable.Empty(), + PreferredMetadataLink = (int)MetadataLinkType.Tmdb + } + }; + } + + [TestCase(false, "MyRadarr", false)] + [TestCase(true, "MyRadarr", true)] + [TestCase(true, "", false)] + [TestCase(true, " ", false)] + public void OnDownload_should_append_instance_name_to_title_only_when_enabled_and_non_empty(bool includeInstanceNameInTitle, string instanceName, bool shouldAppendInstanceName) + { + ((GotifySettings)Subject.Definition.Settings).IncludeInstanceNameInTitle = includeInstanceNameInTitle; + + Mocker.GetMock() + .SetupGet(c => c.InstanceName) + .Returns(instanceName); + + var message = new DownloadMessage + { + Movie = new Movie { Title = "Movie" }, + Message = "downloaded" + }; + + Subject.OnDownload(message); + + var suffix = $" - {instanceName}"; + + Predicate titleHasCorrectSuffix = m => + shouldAppendInstanceName + ? m.Title.EndsWith(suffix) + : !m.Title.EndsWith(" - ") && !m.Title.EndsWith(suffix); + + Mocker.GetMock() + .Verify(p => p.SendNotification( + It.Is(m => titleHasCorrectSuffix(m)), + It.IsAny()), + Times.Once()); + } + } +} diff --git a/src/NzbDrone.Core/Localization/Core/en.json b/src/NzbDrone.Core/Localization/Core/en.json index 23a3b71ab8..d910e42f68 100644 --- a/src/NzbDrone.Core/Localization/Core/en.json +++ b/src/NzbDrone.Core/Localization/Core/en.json @@ -1282,6 +1282,8 @@ "NotificationsGotifySettingsPriorityHelpText": "Priority of the notification", "NotificationsGotifySettingsServer": "Gotify Server", "NotificationsGotifySettingsServerHelpText": "Gotify server URL, including http(s):// and port if needed", + "NotificationsGotifySettingsIncludeAppName": "Include {appName} in Title", + "NotificationsGotifySettingsIncludeAppNameHelpText": "Optionally suffix message title with {appName} to differentiate notifications from different applications", "NotificationsJoinSettingsApiKeyHelpText": "The API Key from your Join account settings (click Join API button).", "NotificationsJoinSettingsDeviceIds": "Device IDs", "NotificationsJoinSettingsDeviceIdsHelpText": "Deprecated, use Device Names instead. Comma separated list of Device IDs you'd like to send notifications to. If unset, all devices will receive notifications.", @@ -1383,7 +1385,7 @@ "NotificationsTelegramSettingsChatId": "Chat ID", "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", + "NotificationsTelegramSettingsIncludeAppNameHelpText": "Optionally suffix message title with {appName} to differentiate notifications from different applications", "NotificationsTelegramSettingsIncludeInstanceName": "Include Instance Name in Title", "NotificationsTelegramSettingsIncludeInstanceNameHelpText": "Optionally include Instance name in notification", "NotificationsTelegramSettingsMetadataLinks": "Metadata Links", diff --git a/src/NzbDrone.Core/Notifications/Gotify/Gotify.cs b/src/NzbDrone.Core/Notifications/Gotify/Gotify.cs index ca889e1c7b..6d8d6073f4 100644 --- a/src/NzbDrone.Core/Notifications/Gotify/Gotify.cs +++ b/src/NzbDrone.Core/Notifications/Gotify/Gotify.cs @@ -5,6 +5,7 @@ using FluentValidation.Results; using NLog; using NzbDrone.Common.Extensions; +using NzbDrone.Core.Configuration; using NzbDrone.Core.Localization; using NzbDrone.Core.MediaCover; using NzbDrone.Core.Movies; @@ -18,12 +19,14 @@ public class Gotify : NotificationBase private readonly IGotifyProxy _proxy; private readonly ILocalizationService _localizationService; private readonly Logger _logger; + private readonly IConfigFileProvider _configFileProvider; - public Gotify(IGotifyProxy proxy, ILocalizationService localizationService, Logger logger) + public Gotify(IGotifyProxy proxy, ILocalizationService localizationService, Logger logger, IConfigFileProvider configFileProvider) { _proxy = proxy; _localizationService = localizationService; _logger = logger; + _configFileProvider = configFileProvider; } public override string Name => "Gotify"; @@ -81,11 +84,16 @@ public override ValidationResult Test() try { var isMarkdown = false; - const string title = "Test Notification"; + var title = "Test Notification"; var sb = new StringBuilder(); sb.AppendLine("This is a test message from Radarr"); + if (Settings.IncludeInstanceNameInTitle && _configFileProvider.InstanceName.IsNotNullOrWhiteSpace()) + { + title = $"{title} - {_configFileProvider.InstanceName}"; + } + var payload = new GotifyMessage { Title = title, @@ -130,6 +138,11 @@ private void SendNotification(string title, string message, Movie movie) sb.AppendLine(message); + if (Settings.IncludeInstanceNameInTitle && _configFileProvider.InstanceName.IsNotNullOrWhiteSpace()) + { + title = $"{title} - {_configFileProvider.InstanceName}"; + } + var payload = new GotifyMessage { Title = title, diff --git a/src/NzbDrone.Core/Notifications/Gotify/GotifySettings.cs b/src/NzbDrone.Core/Notifications/Gotify/GotifySettings.cs index 9920fe9fdf..ecffd44745 100644 --- a/src/NzbDrone.Core/Notifications/Gotify/GotifySettings.cs +++ b/src/NzbDrone.Core/Notifications/Gotify/GotifySettings.cs @@ -64,10 +64,13 @@ public GotifySettings() [FieldDefinition(3, Label = "NotificationsGotifySettingIncludeMoviePoster", Type = FieldType.Checkbox, HelpText = "NotificationsGotifySettingIncludeMoviePosterHelpText")] public bool IncludeMoviePoster { get; set; } - [FieldDefinition(4, Label = "NotificationsGotifySettingsMetadataLinks", Type = FieldType.Select, SelectOptions = typeof(MetadataLinkType), HelpText = "NotificationsGotifySettingsMetadataLinksMovieHelpText")] + [FieldDefinition(4, Label = "NotificationsTelegramSettingsIncludeAppName", Type = FieldType.Checkbox, HelpText = "NotificationsTelegramSettingsIncludeAppNameHelpText")] + public bool IncludeInstanceNameInTitle { get; set; } + + [FieldDefinition(5, Label = "NotificationsGotifySettingsMetadataLinks", Type = FieldType.Select, SelectOptions = typeof(MetadataLinkType), HelpText = "NotificationsGotifySettingsMetadataLinksMovieHelpText")] public IEnumerable MetadataLinks { get; set; } - [FieldDefinition(5, Label = "NotificationsGotifySettingsPreferredMetadataLink", Type = FieldType.Select, SelectOptions = typeof(MetadataLinkType), HelpText = "NotificationsGotifySettingsPreferredMetadataLinkHelpText")] + [FieldDefinition(6, Label = "NotificationsGotifySettingsPreferredMetadataLink", Type = FieldType.Select, SelectOptions = typeof(MetadataLinkType), HelpText = "NotificationsGotifySettingsPreferredMetadataLinkHelpText")] public int PreferredMetadataLink { get; set; } public override NzbDroneValidationResult Validate() From 20842cd37f72fb0bb80860aa206fc90da8dd2937 Mon Sep 17 00:00:00 2001 From: Kalon Shannon-Innes Date: Fri, 19 Dec 2025 13:00:53 +0000 Subject: [PATCH 2/3] Fix: Remove unnecessary formatting and correct the import order. --- .../NotificationTests/GotifyTests/GotifyServiceFixture.cs | 6 +++--- src/NzbDrone.Core/Notifications/Gotify/Gotify.cs | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/NzbDrone.Core.Test/NotificationTests/GotifyTests/GotifyServiceFixture.cs b/src/NzbDrone.Core.Test/NotificationTests/GotifyTests/GotifyServiceFixture.cs index 9a2766bf26..d1de668fd7 100644 --- a/src/NzbDrone.Core.Test/NotificationTests/GotifyTests/GotifyServiceFixture.cs +++ b/src/NzbDrone.Core.Test/NotificationTests/GotifyTests/GotifyServiceFixture.cs @@ -32,9 +32,9 @@ public void Setup() } [TestCase(false, "MyRadarr", false)] - [TestCase(true, "MyRadarr", true)] - [TestCase(true, "", false)] - [TestCase(true, " ", false)] + [TestCase(true, "MyRadarr", true)] + [TestCase(true, "", false)] + [TestCase(true, " ", false)] public void OnDownload_should_append_instance_name_to_title_only_when_enabled_and_non_empty(bool includeInstanceNameInTitle, string instanceName, bool shouldAppendInstanceName) { ((GotifySettings)Subject.Definition.Settings).IncludeInstanceNameInTitle = includeInstanceNameInTitle; diff --git a/src/NzbDrone.Core/Notifications/Gotify/Gotify.cs b/src/NzbDrone.Core/Notifications/Gotify/Gotify.cs index 6d8d6073f4..37250eb86d 100644 --- a/src/NzbDrone.Core/Notifications/Gotify/Gotify.cs +++ b/src/NzbDrone.Core/Notifications/Gotify/Gotify.cs @@ -18,15 +18,15 @@ public class Gotify : NotificationBase private readonly IGotifyProxy _proxy; private readonly ILocalizationService _localizationService; - private readonly Logger _logger; private readonly IConfigFileProvider _configFileProvider; + private readonly Logger _logger; - public Gotify(IGotifyProxy proxy, ILocalizationService localizationService, Logger logger, IConfigFileProvider configFileProvider) + public Gotify(IGotifyProxy proxy, ILocalizationService localizationService, IConfigFileProvider configFileProvider, Logger logger) { _proxy = proxy; _localizationService = localizationService; - _logger = logger; _configFileProvider = configFileProvider; + _logger = logger; } public override string Name => "Gotify"; From 00ab58232c17c7bb7c37c3d26ef2086932329ad5 Mon Sep 17 00:00:00 2001 From: Kalon Shannon-Innes Date: Thu, 19 Feb 2026 00:22:55 +0000 Subject: [PATCH 3/3] Simplify title concatenation --- src/NzbDrone.Core/Notifications/Gotify/Gotify.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/NzbDrone.Core/Notifications/Gotify/Gotify.cs b/src/NzbDrone.Core/Notifications/Gotify/Gotify.cs index 37250eb86d..9973cf2802 100644 --- a/src/NzbDrone.Core/Notifications/Gotify/Gotify.cs +++ b/src/NzbDrone.Core/Notifications/Gotify/Gotify.cs @@ -91,7 +91,7 @@ public override ValidationResult Test() if (Settings.IncludeInstanceNameInTitle && _configFileProvider.InstanceName.IsNotNullOrWhiteSpace()) { - title = $"{title} - {_configFileProvider.InstanceName}"; + title += $" - {_configFileProvider.InstanceName}"; } var payload = new GotifyMessage @@ -140,7 +140,7 @@ private void SendNotification(string title, string message, Movie movie) if (Settings.IncludeInstanceNameInTitle && _configFileProvider.InstanceName.IsNotNullOrWhiteSpace()) { - title = $"{title} - {_configFileProvider.InstanceName}"; + title += $" - {_configFileProvider.InstanceName}"; } var payload = new GotifyMessage