Translate Notifications settings

This commit is contained in:
Stevie Robinson 2024-01-03 21:41:16 +01:00 committed by GitHub
parent cd2ce34f10
commit 8f7f23c938
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
52 changed files with 457 additions and 194 deletions

View File

@ -1085,8 +1085,178 @@
"NotificationStatusSingleClientHealthCheckMessage": "Notifications unavailable due to failures: {notificationNames}", "NotificationStatusSingleClientHealthCheckMessage": "Notifications unavailable due to failures: {notificationNames}",
"NotificationTriggers": "Notification Triggers", "NotificationTriggers": "Notification Triggers",
"NotificationTriggersHelpText": "Select which events should trigger this notification", "NotificationTriggersHelpText": "Select which events should trigger this notification",
"NotificationsAppriseSettingsConfigurationKey": "Apprise Configuration Key",
"NotificationsAppriseSettingsConfigurationKeyHelpText": "Configuration Key for the Persistent Storage Solution. Leave empty if Stateless URLs is used.",
"NotificationsAppriseSettingsNotificationType": "Apprise Notification Type",
"NotificationsAppriseSettingsPasswordHelpText": "HTTP Basic Auth Password",
"NotificationsAppriseSettingsServerUrl": "Apprise Server URL",
"NotificationsAppriseSettingsServerUrlHelpText": "Apprise server URL, including http(s):// and port if needed",
"NotificationsAppriseSettingsStatelessUrls": "Apprise Stateless URLs",
"NotificationsAppriseSettingsStatelessUrlsHelpText": "One or more URLs separated by commas identifying where the notification should be sent to. Leave empty if Persistent Storage is used.",
"NotificationsAppriseSettingsTags": "Apprise Tags",
"NotificationsAppriseSettingsTagsHelpText": "Optionally notify only those tagged accordingly.",
"NotificationsAppriseSettingsUsernameHelpText": "HTTP Basic Auth Username",
"NotificationsCustomScriptSettingsArguments": "Arguments",
"NotificationsCustomScriptSettingsArgumentsHelpText": "Arguments to pass to the script",
"NotificationsCustomScriptSettingsName": "Custom Script",
"NotificationsCustomScriptSettingsProviderMessage": "Testing will execute the script with the EventType set to {eventTypeTest}, ensure your script handles this correctly",
"NotificationsCustomScriptValidationFileDoesNotExist": "File does not exist",
"NotificationsDiscordSettingsAuthor": "Author",
"NotificationsDiscordSettingsAuthorHelpText": "Override the embed author that shows for this notification. Blank is instance name",
"NotificationsDiscordSettingsAvatar": "Avatar",
"NotificationsDiscordSettingsAvatarHelpText": "Change the avatar that is used for messages from this integration",
"NotificationsDiscordSettingsOnGrabFields": "On Grab Fields",
"NotificationsDiscordSettingsOnGrabFieldsHelpText": "Change the fields that are passed in for this 'on grab' notification",
"NotificationsDiscordSettingsOnImportFields": "On Import Fields",
"NotificationsDiscordSettingsOnImportFieldsHelpText": "Change the fields that are passed in for this 'on import' notification",
"NotificationsDiscordSettingsOnManualInteractionFields": "On Manual Interaction Fields",
"NotificationsDiscordSettingsOnManualInteractionFieldsHelpText": "Change the fields that are passed in for this 'on manual interation' notification",
"NotificationsDiscordSettingsUsernameHelpText": "The username to post as, defaults to Discord webhook default",
"NotificationsDiscordSettingsWebhookUrlHelpText": "Discord channel webhook url",
"NotificationsEmailSettingsBccAddress": "BCC Address(es)",
"NotificationsEmailSettingsBccAddressHelpText": "Comma separated list of email bcc recipients",
"NotificationsEmailSettingsCcAddress": "CC Address(es)",
"NotificationsEmailSettingsCcAddressHelpText": "Comma separated list of email cc recipients",
"NotificationsEmailSettingsFromAddress": "From Address",
"NotificationsEmailSettingsName": "Email",
"NotificationsEmailSettingsRecipientAddress": "Recipient Address(es)",
"NotificationsEmailSettingsRecipientAddressHelpText": "Comma separated list of email recipients",
"NotificationsEmailSettingsRequireEncryption": "Require Encryption",
"NotificationsEmailSettingsRequireEncryptionHelpText": "Require SSL (Port 465 only) or StartTLS (any other port)",
"NotificationsEmailSettingsServer": "Server",
"NotificationsEmailSettingsServerHelpText": "Hostname or IP of Email server",
"NotificationsEmbySettingsSendNotifications": "Send Notifications",
"NotificationsEmbySettingsSendNotificationsHelpText": "Have MediaBrowser send notifications to configured providers",
"NotificationsEmbySettingsUpdateLibraryHelpText": "Update Library on Import, Rename, or Delete?",
"NotificationsGotifySettingIncludeSeriesPoster": "Include Series Poster",
"NotificationsGotifySettingIncludeSeriesPosterHelpText": "Include series poster in message",
"NotificationsGotifySettingsAppToken": "App Token",
"NotificationsGotifySettingsAppTokenHelpText": "The Application Token generated by Gotify",
"NotificationsGotifySettingsPriorityHelpText": "Priority of the notification",
"NotificationsGotifySettingsServer": "Gotify Server",
"NotificationsGotifySettingsServerHelpText": "Gotify server URL, including http(s):// and port if needed",
"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.",
"NotificationsJoinSettingsDeviceNames": "Device Names",
"NotificationsJoinSettingsDeviceNamesHelpText": "Comma separated list of full or partial device names you'd like to send notifications to. If unset, all devices will receive notifications.",
"NotificationsJoinSettingsNotificationPriority": "Notification Priority",
"NotificationsJoinValidationInvalidDeviceId": "Device IDs appear invalid.",
"NotificationsKodiSettingAlwaysUpdate": "Always Update",
"NotificationsKodiSettingAlwaysUpdateHelpText": "Update library even when a video is playing?",
"NotificationsKodiSettingsCleanLibrary": "Clean Library",
"NotificationsKodiSettingsCleanLibraryHelpText": "Clean library after update",
"NotificationsKodiSettingsDisplayTime": "Display Time",
"NotificationsKodiSettingsDisplayTimeHelpText": "How long the notification will be displayed for (In seconds)",
"NotificationsKodiSettingsGuiNotification": "GUI Notification",
"NotificationsKodiSettingsUpdateLibraryHelpText": "Update library on Import & Rename?",
"NotificationsLoadError": "Unable to load Notifications", "NotificationsLoadError": "Unable to load Notifications",
"NotificationsMailgunSettingsApiKeyHelpText": "The API key generated from MailGun",
"NotificationsMailgunSettingsSenderDomain": "Sender Domain",
"NotificationsMailgunSettingsUseEuEndpoint": "Use EU Endpoint",
"NotificationsMailgunSettingsUseEuEndpointHelpText": "Enable to use the EU MailGun endpoint",
"NotificationsNotifiarrSettingsApiKeyHelpText": "Your API key from your profile",
"NotificationsNtfySettingsAccessToken": "Access Token",
"NotificationsNtfySettingsAccessTokenHelpText": "Optional token-based authorization. Takes priority over username/password",
"NotificationsNtfySettingsClickUrl": "Click Url",
"NotificationsNtfySettingsClickUrlHelpText": "Optional link when user clicks notification",
"NotificationsNtfySettingsPasswordHelpText": "Optional password",
"NotificationsNtfySettingsServerUrl": "Server URL",
"NotificationsNtfySettingsServerUrlHelpText": "Leave blank to use public server ({url})",
"NotificationsNtfySettingsTagsEmojis": "Ntfy Tags and Emojis",
"NotificationsNtfySettingsTagsEmojisHelpText": "Optional list of tags or emojis to use",
"NotificationsNtfySettingsTopics": "Topics",
"NotificationsNtfySettingsTopicsHelpText": "List of Topics to send notifications to",
"NotificationsNtfySettingsUsernameHelpText": "Optional username",
"NotificationsNtfyValidationAuthorizationRequired": "Authorization is required",
"NotificationsPlexSettingsAuthToken": "Auth Token",
"NotificationsPlexSettingsAuthenticateWithPlexTv": "Authenticate with Plex.tv",
"NotificationsPlexValidationNoTvLibraryFound": "At least one TV library is required",
"NotificationsPushBulletSettingSenderId": "Sender ID",
"NotificationsPushBulletSettingSenderIdHelpText": "The device ID to send notifications from, use device_iden in the device's URL on pushbullet.com (leave blank to send from yourself)",
"NotificationsPushBulletSettingsAccessToken": "Access Token",
"NotificationsPushBulletSettingsChannelTags": "Channel Tags",
"NotificationsPushBulletSettingsChannelTagsHelpText": "List of Channel Tags to send notifications to",
"NotificationsPushBulletSettingsDeviceIds": "Device IDs",
"NotificationsPushBulletSettingsDeviceIdsHelpText": "List of device IDs (leave blank to send to all devices)",
"NotificationsPushcutSettingsApiKeyHelpText": "API Keys can be managed in the Account view of the Pushcut app",
"NotificationsPushcutSettingsNotificationName": "Notification Name",
"NotificationsPushcutSettingsNotificationNameHelpText": "Notification name from Notifications tab of the Pushcut app",
"NotificationsPushcutSettingsTimeSensitive": "Time Sensitive",
"NotificationsPushcutSettingsTimeSensitiveHelpText": "Enable to mark the notification as \"Time Sensitive\"",
"NotificationsPushoverSettingsDevices": "Devices",
"NotificationsPushoverSettingsDevicesHelpText": "List of device names (leave blank to send to all devices)",
"NotificationsPushoverSettingsExpire": "Expire",
"NotificationsPushoverSettingsExpireHelpText": "Maximum time to retry Emergency alerts, maximum 86400 seconds\"",
"NotificationsPushoverSettingsRetry": "Retry",
"NotificationsPushoverSettingsRetryHelpText": "Interval to retry Emergency alerts, minimum 30 seconds",
"NotificationsPushoverSettingsSound": "Sound",
"NotificationsPushoverSettingsSoundHelpText": "Notification sound, leave blank to use the default",
"NotificationsPushoverSettingsUserKey": "User Key",
"NotificationsSendGridSettingsApiKeyHelpText": "The API Key generated by SendGrid",
"NotificationsSettingsUpdateLibrary": "Update Library",
"NotificationsSettingsUpdateMapPathsFrom": "Map Paths From",
"NotificationsSettingsUpdateMapPathsFromHelpText": "{appName} path, used to modify series paths when {serviceName} sees library path location differently from {appName} (Requires 'Update Library')",
"NotificationsSettingsUpdateMapPathsTo": "Map Paths To",
"NotificationsSettingsUpdateMapPathsToHelpText": "{serviceName} path, used to modify series paths when {serviceName} sees library path location differently from {appName} (Requires 'Update Library')",
"NotificationsSettingsUseSslHelpText": "Connect to {serviceName} over HTTPS instead of HTTP",
"NotificationsSettingsWebhookMethod": "Method",
"NotificationsSettingsWebhookMethodHelpText": "Which HTTP method to use submit to the Webservice",
"NotificationsSettingsWebhookUrl": "Webhook URL",
"NotificationsSignalSettingsGroupIdPhoneNumber": "Group ID / Phone Number",
"NotificationsSignalSettingsGroupIdPhoneNumberHelpText": "Group ID / Phone Number of the receiver",
"NotificationsSignalSettingsPasswordHelpText": "Password used to authenticate requests toward signal-api",
"NotificationsSignalSettingsSenderNumber": "Sender Number",
"NotificationsSignalSettingsSenderNumberHelpText": "Phone number of the sender register in signal-api",
"NotificationsSignalSettingsUsernameHelpText": "Username used to authenticate requests toward signal-api",
"NotificationsSignalValidationSslRequired": "SSL seems to be required",
"NotificationsSimplepushSettingsEvent": "Event",
"NotificationsSimplepushSettingsEventHelpText": "Customize the behavior of push notifications",
"NotificationsSimplepushSettingsKey": "Key",
"NotificationsSlackSettingsChannel": "Channel",
"NotificationsSlackSettingsChannelHelpText": "Overrides the default channel for the incoming webhook (#other-channel)",
"NotificationsSlackSettingsIcon": "Icon",
"NotificationsSlackSettingsIconHelpText": "Change the icon that is used for messages posted to Slack (Emoji or URL)",
"NotificationsSlackSettingsUsernameHelpText": "Username to post to Slack as",
"NotificationsSlackSettingsWebhookUrlHelpText": "Slack channel webhook url",
"NotificationsSynologySettingsUpdateLibraryHelpText": "Call synoindex on localhost to update a library file",
"NotificationsSynologyValidationInvalidOs": "Must be a Synology",
"NotificationsSynologyValidationTestFailed": "Not a Synology or synoindex not available",
"NotificationsTagsSeriesHelpText": "Only send notifications for series with at least one matching tag", "NotificationsTagsSeriesHelpText": "Only send notifications for series with at least one matching tag",
"NotificationsTelegramSettingsBotToken": "Bot Token",
"NotificationsTelegramSettingsChatId": "Chat ID",
"NotificationsTelegramSettingsChatIdHelpText": "You must start a conversation with the bot or add it to your group to receive messages",
"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)",
"NotificationsTraktSettingsAccessToken": "Access Token",
"NotificationsTraktSettingsAuthUser": "Auth User",
"NotificationsTraktSettingsAuthenticateWithTrakt": "Authenticate with Trakt",
"NotificationsTraktSettingsExpires": "Expires",
"NotificationsTraktSettingsRefreshToken": "Refresh Token",
"NotificationsTwitterSettingsAccessToken": "Access Token",
"NotificationsTwitterSettingsAccessTokenSecret": "Access Token Secret",
"NotificationsTwitterSettingsConnectToTwitter": "Connect to Twitter / X",
"NotificationsTwitterSettingsConsumerKey": "Consumer Key",
"NotificationsTwitterSettingsConsumerKeyHelpText": "Consumer key from a Twitter application",
"NotificationsTwitterSettingsConsumerSecret": "Consumer Secret",
"NotificationsTwitterSettingsConsumerSecretHelpText": "Consumer secret from a Twitter application",
"NotificationsTwitterSettingsDirectMessage": "Direct Message",
"NotificationsTwitterSettingsDirectMessageHelpText": "Send a direct message instead of a public message",
"NotificationsTwitterSettingsMention": "Mention",
"NotificationsTwitterSettingsMentionHelpText": "Mention this user in sent tweets",
"NotificationsValidationInvalidAccessToken": "Access Token is invalid",
"NotificationsValidationInvalidApiKey": "API Key is invalid",
"NotificationsValidationInvalidApiKeyExceptionMessage": "API Key is invalid: {exceptionMessage}",
"NotificationsValidationInvalidAuthenticationToken": "Authentication Token is invalid",
"NotificationsValidationInvalidHttpCredentials": "HTTP Auth credentials are invalid: {exceptionMessage}",
"NotificationsValidationInvalidUsernamePassword": "Invalid username or password",
"NotificationsValidationUnableToConnect": "Unable to connect: {exceptionMessage}",
"NotificationsValidationUnableToConnectToApi": "Unable to connect to {service} API. Server connection failed: ({responseCode}) {exceptionMessage}",
"NotificationsValidationUnableToConnectToService": "Unable to connect to {serviceName}",
"NotificationsValidationUnableToSendTestMessage": "Unable to send test message: {exceptionMessage}",
"NotificationsValidationUnableToSendTestMessageApiResponse": "Unable to send test message. Response from API: {error}",
"NzbgetHistoryItemMessage": "PAR Status: {parStatus} - Unpack Status: {unpackStatus} - Move Status: {moveStatus} - Script Status: {scriptStatus} - Delete Status: {deleteStatus} - Mark Status: {markStatus}", "NzbgetHistoryItemMessage": "PAR Status: {parStatus} - Unpack Status: {unpackStatus} - Move Status: {moveStatus} - Script Status: {scriptStatus} - Delete Status: {deleteStatus} - Mark Status: {markStatus}",
"Ok": "Ok", "Ok": "Ok",
"OnApplicationUpdate": "On Application Update", "OnApplicationUpdate": "On Application Update",

View File

@ -1,4 +1,5 @@
using System; using System;
using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Net; using System.Net;
using FluentValidation.Results; using FluentValidation.Results;
@ -6,6 +7,7 @@ using NLog;
using NzbDrone.Common.Extensions; using NzbDrone.Common.Extensions;
using NzbDrone.Common.Http; using NzbDrone.Common.Http;
using NzbDrone.Common.Serializer; using NzbDrone.Common.Serializer;
using NzbDrone.Core.Localization;
namespace NzbDrone.Core.Notifications.Apprise namespace NzbDrone.Core.Notifications.Apprise
{ {
@ -18,11 +20,13 @@ namespace NzbDrone.Core.Notifications.Apprise
public class AppriseProxy : IAppriseProxy public class AppriseProxy : IAppriseProxy
{ {
private readonly IHttpClient _httpClient; private readonly IHttpClient _httpClient;
private readonly ILocalizationService _localizationService;
private readonly Logger _logger; private readonly Logger _logger;
public AppriseProxy(IHttpClient httpClient, Logger logger) public AppriseProxy(IHttpClient httpClient, ILocalizationService localizationService, Logger logger)
{ {
_httpClient = httpClient; _httpClient = httpClient;
_localizationService = localizationService;
_logger = logger; _logger = logger;
} }
@ -92,7 +96,7 @@ namespace NzbDrone.Core.Notifications.Apprise
if (httpException.Response.StatusCode == HttpStatusCode.Unauthorized) if (httpException.Response.StatusCode == HttpStatusCode.Unauthorized)
{ {
_logger.Error(ex, $"HTTP Auth credentials are invalid: {0}", ex.Message); _logger.Error(ex, $"HTTP Auth credentials are invalid: {0}", ex.Message);
return new ValidationFailure("AuthUsername", $"HTTP Auth credentials are invalid: {ex.Message}"); return new ValidationFailure("AuthUsername", _localizationService.GetLocalizedString("NotificationsValidationInvalidHttpCredentials", new Dictionary<string, object> { { "exceptionMessage", ex.Message } }));
} }
if (httpException.Response.Content.IsNotNullOrWhiteSpace()) if (httpException.Response.Content.IsNotNullOrWhiteSpace())
@ -100,16 +104,16 @@ namespace NzbDrone.Core.Notifications.Apprise
var error = Json.Deserialize<AppriseError>(httpException.Response.Content); var error = Json.Deserialize<AppriseError>(httpException.Response.Content);
_logger.Error(ex, $"Unable to send test message. Response from API: {0}", error.Error); _logger.Error(ex, $"Unable to send test message. Response from API: {0}", error.Error);
return new ValidationFailure(string.Empty, $"Unable to send test message. Response from API: {error.Error}"); return new ValidationFailure(string.Empty, _localizationService.GetLocalizedString("NotificationsValidationUnableToSendTestMessageApiResponse", new Dictionary<string, object> { { "error", error.Error } }));
} }
_logger.Error(ex, "Unable to send test message. Server connection failed: ({0}) {1}", httpException.Response.StatusCode, ex.Message); _logger.Error(ex, "Unable to send test message. Server connection failed: ({0}) {1}", httpException.Response.StatusCode, ex.Message);
return new ValidationFailure("Url", $"Unable to connect to Apprise API. Server connection failed: ({httpException.Response.StatusCode}) {ex.Message}"); return new ValidationFailure("Url", _localizationService.GetLocalizedString("NotificationsValidationUnableToConnectToApi", new Dictionary<string, object> { { "service", "Apprise" }, { "responseCode", httpException.Response.StatusCode }, { "exceptionMessage", ex.Message } }));
} }
catch (Exception ex) catch (Exception ex)
{ {
_logger.Error(ex, "Unable to send test message: {0}", ex.Message); _logger.Error(ex, "Unable to send test message: {0}", ex.Message);
return new ValidationFailure("Url", $"Unable to send test message: {ex.Message}"); return new ValidationFailure("Url", _localizationService.GetLocalizedString("NotificationsValidationUnableToSendTestMessage", new Dictionary<string, object> { { "exceptionMessage", ex.Message } }));
} }
return null; return null;

View File

@ -45,25 +45,25 @@ namespace NzbDrone.Core.Notifications.Apprise
Tags = Array.Empty<string>(); Tags = Array.Empty<string>();
} }
[FieldDefinition(1, Label = "Apprise Server URL", Type = FieldType.Url, Placeholder = "http://localhost:8000", HelpText = "Apprise server URL, including http(s):// and port if needed", HelpLink = "https://github.com/caronc/apprise-api")] [FieldDefinition(1, Label = "NotificationsAppriseSettingsServerUrl", Type = FieldType.Url, Placeholder = "http://localhost:8000", HelpText = "NotificationsAppriseSettingsServerUrlHelpText", HelpLink = "https://github.com/caronc/apprise-api")]
public string ServerUrl { get; set; } public string ServerUrl { get; set; }
[FieldDefinition(2, Label = "Apprise Configuration Key", Type = FieldType.Textbox, HelpText = "Configuration Key for the Persistent Storage Solution. Leave empty if Stateless URLs is used.", HelpLink = "https://github.com/caronc/apprise-api#persistent-storage-solution")] [FieldDefinition(2, Label = "NotificationsAppriseSettingsConfigurationKey", Type = FieldType.Textbox, HelpText = "NotificationsAppriseSettingsConfigurationKeyHelpText", HelpLink = "https://github.com/caronc/apprise-api#persistent-storage-solution")]
public string ConfigurationKey { get; set; } public string ConfigurationKey { get; set; }
[FieldDefinition(3, Label = "Apprise Stateless URLs", Type = FieldType.Textbox, HelpText = "One or more URLs separated by commas identifying where the notification should be sent to. Leave empty if Persistent Storage is used.", HelpLink = "https://github.com/caronc/apprise#productivity-based-notifications")] [FieldDefinition(3, Label = "NotificationsAppriseSettingsStatelessUrls", Type = FieldType.Textbox, HelpText = "NotificationsAppriseSettingsStatelessUrlsHelpText", HelpLink = "https://github.com/caronc/apprise#productivity-based-notifications")]
public string StatelessUrls { get; set; } public string StatelessUrls { get; set; }
[FieldDefinition(4, Label = "Apprise Notification Type", Type = FieldType.Select, SelectOptions = typeof(AppriseNotificationType))] [FieldDefinition(4, Label = "NotificationsAppriseSettingsNotificationType", Type = FieldType.Select, SelectOptions = typeof(AppriseNotificationType))]
public int NotificationType { get; set; } public int NotificationType { get; set; }
[FieldDefinition(5, Label = "Apprise Tags", Type = FieldType.Tag, HelpText = "Optionally notify only those tagged accordingly.")] [FieldDefinition(5, Label = "NotificationsAppriseSettingsTags", Type = FieldType.Tag, HelpText = "")]
public IEnumerable<string> Tags { get; set; } public IEnumerable<string> Tags { get; set; }
[FieldDefinition(6, Label = "Username", Type = FieldType.Textbox, HelpText = "HTTP Basic Auth Username", Privacy = PrivacyLevel.UserName)] [FieldDefinition(6, Label = "Username", Type = FieldType.Textbox, HelpText = "NotificationsAppriseSettingsUsernameHelpText", Privacy = PrivacyLevel.UserName)]
public string AuthUsername { get; set; } public string AuthUsername { get; set; }
[FieldDefinition(7, Label = "Password", Type = FieldType.Password, HelpText = "HTTP Basic Auth Password", Privacy = PrivacyLevel.Password)] [FieldDefinition(7, Label = "Password", Type = FieldType.Password, HelpText = "NotificationsAppriseSettingsPasswordHelpText", Privacy = PrivacyLevel.Password)]
public string AuthPassword { get; set; } public string AuthPassword { get; set; }
public NzbDroneValidationResult Validate() public NzbDroneValidationResult Validate()

View File

@ -10,6 +10,7 @@ using NzbDrone.Common.Extensions;
using NzbDrone.Common.Processes; using NzbDrone.Common.Processes;
using NzbDrone.Core.Configuration; using NzbDrone.Core.Configuration;
using NzbDrone.Core.HealthCheck; using NzbDrone.Core.HealthCheck;
using NzbDrone.Core.Localization;
using NzbDrone.Core.MediaFiles; using NzbDrone.Core.MediaFiles;
using NzbDrone.Core.MediaFiles.MediaInfo; using NzbDrone.Core.MediaFiles.MediaInfo;
using NzbDrone.Core.Parser; using NzbDrone.Core.Parser;
@ -27,6 +28,7 @@ namespace NzbDrone.Core.Notifications.CustomScript
private readonly IDiskProvider _diskProvider; private readonly IDiskProvider _diskProvider;
private readonly IProcessProvider _processProvider; private readonly IProcessProvider _processProvider;
private readonly ITagRepository _tagRepository; private readonly ITagRepository _tagRepository;
private readonly ILocalizationService _localizationService;
private readonly Logger _logger; private readonly Logger _logger;
public CustomScript(IConfigFileProvider configFileProvider, public CustomScript(IConfigFileProvider configFileProvider,
@ -34,6 +36,7 @@ namespace NzbDrone.Core.Notifications.CustomScript
IDiskProvider diskProvider, IDiskProvider diskProvider,
IProcessProvider processProvider, IProcessProvider processProvider,
ITagRepository tagRepository, ITagRepository tagRepository,
ILocalizationService localizationService,
Logger logger) Logger logger)
{ {
_configFileProvider = configFileProvider; _configFileProvider = configFileProvider;
@ -41,14 +44,15 @@ namespace NzbDrone.Core.Notifications.CustomScript
_diskProvider = diskProvider; _diskProvider = diskProvider;
_processProvider = processProvider; _processProvider = processProvider;
_tagRepository = tagRepository; _tagRepository = tagRepository;
_localizationService = localizationService;
_logger = logger; _logger = logger;
} }
public override string Name => "Custom Script"; public override string Name => _localizationService.GetLocalizedString("NotificationsCustomScriptSettingsName");
public override string Link => "https://wiki.servarr.com/sonarr/settings#connections"; public override string Link => "https://wiki.servarr.com/sonarr/settings#connections";
public override ProviderMessage Message => new ProviderMessage("Testing will execute the script with the EventType set to Test, ensure your script handles this correctly", ProviderMessageType.Warning); public override ProviderMessage Message => new ProviderMessage(_localizationService.GetLocalizedString("NotificationsCustomScriptSettingsProviderMessage", new Dictionary<string, object> { { "eventTypeTest", "Test" } }), ProviderMessageType.Warning);
public override void OnGrab(GrabMessage message) public override void OnGrab(GrabMessage message)
{ {
@ -360,7 +364,7 @@ namespace NzbDrone.Core.Notifications.CustomScript
if (!_diskProvider.FileExists(Settings.Path)) if (!_diskProvider.FileExists(Settings.Path))
{ {
failures.Add(new NzbDroneValidationFailure("Path", "File does not exist")); failures.Add(new NzbDroneValidationFailure("Path", _localizationService.GetLocalizedString("NotificationsCustomScriptValidationFileDoesNotExist")));
} }
if (failures.Empty()) if (failures.Empty())

View File

@ -23,7 +23,7 @@ namespace NzbDrone.Core.Notifications.CustomScript
[FieldDefinition(0, Label = "Path", Type = FieldType.FilePath)] [FieldDefinition(0, Label = "Path", Type = FieldType.FilePath)]
public string Path { get; set; } public string Path { get; set; }
[FieldDefinition(1, Label = "Arguments", HelpText = "Arguments to pass to the script", Hidden = HiddenType.HiddenIfNotSet)] [FieldDefinition(1, Label = "NotificationsCustomScriptSettingsArguments", HelpText = "NotificationsCustomScriptSettingsArgumentsHelpText", Hidden = HiddenType.HiddenIfNotSet)]
public string Arguments { get; set; } public string Arguments { get; set; }
public NzbDroneValidationResult Validate() public NzbDroneValidationResult Validate()

View File

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using FluentValidation.Results; using FluentValidation.Results;
using NzbDrone.Common.Extensions; using NzbDrone.Common.Extensions;
using NzbDrone.Core.Localization;
using NzbDrone.Core.MediaCover; using NzbDrone.Core.MediaCover;
using NzbDrone.Core.MediaFiles; using NzbDrone.Core.MediaFiles;
using NzbDrone.Core.MediaFiles.MediaInfo; using NzbDrone.Core.MediaFiles.MediaInfo;
@ -15,10 +16,12 @@ namespace NzbDrone.Core.Notifications.Discord
public class Discord : NotificationBase<DiscordSettings> public class Discord : NotificationBase<DiscordSettings>
{ {
private readonly IDiscordProxy _proxy; private readonly IDiscordProxy _proxy;
private readonly ILocalizationService _localizationService;
public Discord(IDiscordProxy proxy) public Discord(IDiscordProxy proxy, ILocalizationService localizationService)
{ {
_proxy = proxy; _proxy = proxy;
_localizationService = localizationService;
} }
public override string Name => "Discord"; public override string Name => "Discord";
@ -538,7 +541,7 @@ namespace NzbDrone.Core.Notifications.Discord
} }
catch (DiscordException ex) catch (DiscordException ex)
{ {
return new NzbDroneValidationFailure("Unable to post", ex.Message); return new NzbDroneValidationFailure(string.Empty, _localizationService.GetLocalizedString("NotificationsValidationUnableToSendTestMessage", new Dictionary<string, object> { { "exceptionMessage", ex.Message } }));
} }
return null; return null;

View File

@ -68,25 +68,25 @@ namespace NzbDrone.Core.Notifications.Discord
private static readonly DiscordSettingsValidator Validator = new (); private static readonly DiscordSettingsValidator Validator = new ();
[FieldDefinition(0, Label = "Webhook URL", HelpText = "Discord channel webhook url")] [FieldDefinition(0, Label = "NotificationsSettingsWebhookUrl", HelpText = "NotificationsDiscordSettingsWebhookUrlHelpText")]
public string WebHookUrl { get; set; } public string WebHookUrl { get; set; }
[FieldDefinition(1, Label = "Username", Privacy = PrivacyLevel.UserName, HelpText = "The username to post as, defaults to Discord webhook default")] [FieldDefinition(1, Label = "Username", Privacy = PrivacyLevel.UserName, HelpText = "NotificationsDiscordSettingsUsernameHelpText")]
public string Username { get; set; } public string Username { get; set; }
[FieldDefinition(2, Label = "Avatar", HelpText = "Change the avatar that is used for messages from this integration", Type = FieldType.Textbox)] [FieldDefinition(2, Label = "NotificationsDiscordSettingsAvatar", HelpText = "NotificationsDiscordSettingsAvatarHelpText", Type = FieldType.Textbox)]
public string Avatar { get; set; } public string Avatar { get; set; }
[FieldDefinition(3, Label = "Author", Advanced = true, HelpText = "Override the embed author that shows for this notification, Blank is instance name", Type = FieldType.Textbox)] [FieldDefinition(3, Label = "NotificationsDiscordSettingsAuthor", Advanced = true, HelpText = "NotificationsDiscordSettingsAuthorHelpText", Type = FieldType.Textbox)]
public string Author { get; set; } public string Author { get; set; }
[FieldDefinition(4, Label = "On Grab Fields", Advanced = true, SelectOptions = typeof(DiscordGrabFieldType), HelpText = "Change the fields that are passed in for this 'on grab' notification", Type = FieldType.Select)] [FieldDefinition(4, Label = "NotificationsDiscordSettingsOnGrabFields", Advanced = true, SelectOptions = typeof(DiscordGrabFieldType), HelpText = "NotificationsDiscordSettingsOnGrabFieldsHelpText", Type = FieldType.Select)]
public IEnumerable<int> GrabFields { get; set; } public IEnumerable<int> GrabFields { get; set; }
[FieldDefinition(5, Label = "On Import Fields", Advanced = true, SelectOptions = typeof(DiscordImportFieldType), HelpText = "Change the fields that are passed for this 'on import' notification", Type = FieldType.Select)] [FieldDefinition(5, Label = "NotificationsDiscordSettingsOnImportFields", Advanced = true, SelectOptions = typeof(DiscordImportFieldType), HelpText = "NotificationsDiscordSettingsOnImportFieldsHelpText", Type = FieldType.Select)]
public IEnumerable<int> ImportFields { get; set; } public IEnumerable<int> ImportFields { get; set; }
[FieldDefinition(6, Label = "On Manual Interaction Fields", Advanced = true, SelectOptions = typeof(DiscordManualInteractionFieldType), HelpText = "Change the fields that are passed for this 'on manual interaction' notification", Type = FieldType.Select)] [FieldDefinition(6, Label = "NotificationsDiscordSettingsOnManualInteractionFields", Advanced = true, SelectOptions = typeof(DiscordManualInteractionFieldType), HelpText = "NotificationsDiscordSettingsOnManualInteractionFieldsHelpText", Type = FieldType.Select)]
public IEnumerable<int> ManualInteractionFields { get; set; } public IEnumerable<int> ManualInteractionFields { get; set; }
public NzbDroneValidationResult Validate() public NzbDroneValidationResult Validate()

View File

@ -8,19 +8,22 @@ using MimeKit;
using NLog; using NLog;
using NzbDrone.Common.Extensions; using NzbDrone.Common.Extensions;
using NzbDrone.Common.Http.Dispatchers; using NzbDrone.Common.Http.Dispatchers;
using NzbDrone.Core.Localization;
namespace NzbDrone.Core.Notifications.Email namespace NzbDrone.Core.Notifications.Email
{ {
public class Email : NotificationBase<EmailSettings> public class Email : NotificationBase<EmailSettings>
{ {
private readonly ICertificateValidationService _certificateValidationService; private readonly ICertificateValidationService _certificateValidationService;
private readonly ILocalizationService _localizationService;
private readonly Logger _logger; private readonly Logger _logger;
public override string Name => "Email"; public override string Name => _localizationService.GetLocalizedString("NotificationsEmailSettingsName");
public Email(ICertificateValidationService certificateValidationService, Logger logger) public Email(ICertificateValidationService certificateValidationService, ILocalizationService localizationService, Logger logger)
{ {
_certificateValidationService = certificateValidationService; _certificateValidationService = certificateValidationService;
_localizationService = localizationService;
_logger = logger; _logger = logger;
} }
@ -180,7 +183,7 @@ namespace NzbDrone.Core.Notifications.Email
catch (Exception ex) catch (Exception ex)
{ {
_logger.Error(ex, "Unable to send test email"); _logger.Error(ex, "Unable to send test email");
return new ValidationFailure("Server", "Unable to send test email"); return new ValidationFailure("Server", _localizationService.GetLocalizedString("NotificationsValidationUnableToSendTestMessage", new Dictionary<string, object> { { "exceptionMessage", ex.Message } }));
} }
return null; return null;

View File

@ -39,13 +39,13 @@ namespace NzbDrone.Core.Notifications.Email
Bcc = Array.Empty<string>(); Bcc = Array.Empty<string>();
} }
[FieldDefinition(0, Label = "Server", HelpText = "Hostname or IP of Email server")] [FieldDefinition(0, Label = "NotificationsEmailSettingsServer", HelpText = "NotificationsEmailSettingsServerHelpText")]
public string Server { get; set; } public string Server { get; set; }
[FieldDefinition(1, Label = "Port")] [FieldDefinition(1, Label = "Port")]
public int Port { get; set; } public int Port { get; set; }
[FieldDefinition(2, Label = "Require Encryption", HelpText = "Require SSL (Port 465 only) or StartTLS (any other port)", Type = FieldType.Checkbox)] [FieldDefinition(2, Label = "NotificationsEmailSettingsRequireEncryption", HelpText = "NotificationsEmailSettingsRequireEncryptionHelpText", Type = FieldType.Checkbox)]
public bool RequireEncryption { get; set; } public bool RequireEncryption { get; set; }
[FieldDefinition(3, Label = "Username", Privacy = PrivacyLevel.UserName)] [FieldDefinition(3, Label = "Username", Privacy = PrivacyLevel.UserName)]
@ -54,16 +54,16 @@ namespace NzbDrone.Core.Notifications.Email
[FieldDefinition(4, Label = "Password", Type = FieldType.Password, Privacy = PrivacyLevel.Password)] [FieldDefinition(4, Label = "Password", Type = FieldType.Password, Privacy = PrivacyLevel.Password)]
public string Password { get; set; } public string Password { get; set; }
[FieldDefinition(5, Label = "From Address")] [FieldDefinition(5, Label = "NotificationsEmailSettingsFromAddress")]
public string From { get; set; } public string From { get; set; }
[FieldDefinition(6, Label = "Recipient Address(es)", HelpText = "Comma separated list of email recipients")] [FieldDefinition(6, Label = "NotificationsEmailSettingsRecipientAddress", HelpText = "NotificationsEmailSettingsRecipientAddressHelpText")]
public IEnumerable<string> To { get; set; } public IEnumerable<string> To { get; set; }
[FieldDefinition(7, Label = "CC Address(es)", HelpText = "Comma separated list of email cc recipients", Advanced = true)] [FieldDefinition(7, Label = "NotificationsEmailSettingsCcAddress", HelpText = "NotificationsEmailSettingsCcAddressHelpText", Advanced = true)]
public IEnumerable<string> Cc { get; set; } public IEnumerable<string> Cc { get; set; }
[FieldDefinition(8, Label = "BCC Address(es)", HelpText = "Comma separated list of email bcc recipients", Advanced = true)] [FieldDefinition(8, Label = "NotificationsEmailSettingsBccAddress", HelpText = "NotificationsEmailSettingsBccAddressHelpText", Advanced = true)]
public IEnumerable<string> Bcc { get; set; } public IEnumerable<string> Bcc { get; set; }
public NzbDroneValidationResult Validate() public NzbDroneValidationResult Validate()

View File

@ -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.Core.Localization;
using NzbDrone.Core.MediaCover; using NzbDrone.Core.MediaCover;
using NzbDrone.Core.Tv; using NzbDrone.Core.Tv;
@ -12,11 +13,13 @@ namespace NzbDrone.Core.Notifications.Gotify
public class Gotify : NotificationBase<GotifySettings> public class Gotify : NotificationBase<GotifySettings>
{ {
private readonly IGotifyProxy _proxy; private readonly IGotifyProxy _proxy;
private readonly ILocalizationService _localizationService;
private readonly Logger _logger; private readonly Logger _logger;
public Gotify(IGotifyProxy proxy, Logger logger) public Gotify(IGotifyProxy proxy, ILocalizationService localizationService, Logger logger)
{ {
_proxy = proxy; _proxy = proxy;
_localizationService = localizationService;
_logger = logger; _logger = logger;
} }
@ -101,7 +104,7 @@ namespace NzbDrone.Core.Notifications.Gotify
catch (Exception ex) catch (Exception ex)
{ {
_logger.Error(ex, "Unable to send test message"); _logger.Error(ex, "Unable to send test message");
failures.Add(new ValidationFailure("", "Unable to send test message")); failures.Add(new ValidationFailure(string.Empty, _localizationService.GetLocalizedString("NotificationsValidationUnableToSendTestMessage", new Dictionary<string, object> { { "exceptionMessage", ex.Message } })));
} }
return new ValidationResult(failures); return new ValidationResult(failures);

View File

@ -23,16 +23,16 @@ namespace NzbDrone.Core.Notifications.Gotify
Priority = 5; Priority = 5;
} }
[FieldDefinition(0, Label = "Gotify Server", HelpText = "Gotify server URL, including http(s):// and port if needed")] [FieldDefinition(0, Label = "NotificationsGotifySettingsServer", HelpText = "")]
public string Server { get; set; } public string Server { get; set; }
[FieldDefinition(1, Label = "App Token", Privacy = PrivacyLevel.ApiKey, HelpText = "The Application Token generated by Gotify")] [FieldDefinition(1, Label = "NotificationsGotifySettingsAppToken", Privacy = PrivacyLevel.ApiKey, HelpText = "NotificationsGotifySettingsAppTokenHelpText")]
public string AppToken { get; set; } public string AppToken { get; set; }
[FieldDefinition(2, Label = "Priority", Type = FieldType.Select, SelectOptions = typeof(GotifyPriority), HelpText = "Priority of the notification")] [FieldDefinition(2, Label = "Priority", Type = FieldType.Select, SelectOptions = typeof(GotifyPriority), HelpText = "NotificationsGotifySettingsPriorityHelpText")]
public int Priority { get; set; } public int Priority { get; set; }
[FieldDefinition(3, Label = "Include Series Poster", Type = FieldType.Checkbox, HelpText = "Include series poster in message")] [FieldDefinition(3, Label = "NotificationsGotifySettingIncludeSeriesPoster", Type = FieldType.Checkbox, HelpText = "NotificationsGotifySettingIncludeSeriesPosterHelpText")]
public bool IncludeSeriesPoster { get; set; } public bool IncludeSeriesPoster { get; set; }
public NzbDroneValidationResult Validate() public NzbDroneValidationResult Validate()

View File

@ -1,10 +1,12 @@
using System; using System;
using System.Collections.Generic;
using System.Net.Http; using System.Net.Http;
using FluentValidation.Results; using FluentValidation.Results;
using NLog; using NLog;
using NzbDrone.Common.Extensions; using NzbDrone.Common.Extensions;
using NzbDrone.Common.Http; using NzbDrone.Common.Http;
using NzbDrone.Common.Serializer; using NzbDrone.Common.Serializer;
using NzbDrone.Core.Localization;
namespace NzbDrone.Core.Notifications.Join namespace NzbDrone.Core.Notifications.Join
{ {
@ -19,11 +21,13 @@ namespace NzbDrone.Core.Notifications.Join
private const string URL = "https://joinjoaomgcd.appspot.com/_ah/api/messaging/v1/sendPush?"; private const string URL = "https://joinjoaomgcd.appspot.com/_ah/api/messaging/v1/sendPush?";
private readonly IHttpClient _httpClient; private readonly IHttpClient _httpClient;
private readonly ILocalizationService _localizationService;
private readonly Logger _logger; private readonly Logger _logger;
public JoinProxy(IHttpClient httpClient, Logger logger) public JoinProxy(IHttpClient httpClient, ILocalizationService localizationService, Logger logger)
{ {
_httpClient = httpClient; _httpClient = httpClient;
_localizationService = localizationService;
_logger = logger; _logger = logger;
} }
@ -55,22 +59,22 @@ namespace NzbDrone.Core.Notifications.Join
catch (JoinInvalidDeviceException ex) catch (JoinInvalidDeviceException ex)
{ {
_logger.Error(ex, "Unable to send test Join message. Invalid Device IDs supplied."); _logger.Error(ex, "Unable to send test Join message. Invalid Device IDs supplied.");
return new ValidationFailure("DeviceIds", "Device IDs appear invalid."); return new ValidationFailure("DeviceIds", _localizationService.GetLocalizedString("NotificationsJoinValidationInvalidDeviceId"));
} }
catch (JoinException ex) catch (JoinException ex)
{ {
_logger.Error(ex, "Unable to send test Join message."); _logger.Error(ex, "Unable to send test Join message.");
return new ValidationFailure("ApiKey", ex.Message); return new ValidationFailure("ApiKey", _localizationService.GetLocalizedString("NotificationsValidationUnableToSendTestMessage", new Dictionary<string, object> { { "exceptionMessage", ex.Message } }));
} }
catch (HttpException ex) catch (HttpException ex)
{ {
_logger.Error(ex, "Unable to send test Join message. Server connection failed."); _logger.Error(ex, "Unable to send test Join message. Server connection failed.");
return new ValidationFailure("ApiKey", "Unable to connect to Join API. Please try again later."); return new ValidationFailure("ApiKey", _localizationService.GetLocalizedString("NotificationsValidationUnableToSendTestMessage", new Dictionary<string, object> { { "service", "Join" }, { "responseCode", ex.Response.StatusCode }, { "exceptionMessage", ex.Message } }));
} }
catch (Exception ex) catch (Exception ex)
{ {
_logger.Error(ex, "Unable to send test Join message. Unknown error."); _logger.Error(ex, "Unable to send test Join message. Unknown error.");
return new ValidationFailure("ApiKey", ex.Message); return new ValidationFailure("ApiKey", _localizationService.GetLocalizedString("NotificationsValidationUnableToSendTestMessage", new Dictionary<string, object> { { "exceptionMessage", ex.Message } }));
} }
} }

View File

@ -23,16 +23,16 @@ namespace NzbDrone.Core.Notifications.Join
private static readonly JoinSettingsValidator Validator = new JoinSettingsValidator(); private static readonly JoinSettingsValidator Validator = new JoinSettingsValidator();
[FieldDefinition(0, Label = "API Key", HelpText = "The API Key from your Join account settings (click Join API button).", HelpLink = "https://joinjoaomgcd.appspot.com/")] [FieldDefinition(0, Label = "ApiKey", HelpText = "NotificationsJoinSettingsApiKeyHelpText", HelpLink = "https://joinjoaomgcd.appspot.com/")]
public string ApiKey { get; set; } public string ApiKey { get; set; }
[FieldDefinition(1, Label = "Device IDs", HelpText = "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.")] [FieldDefinition(1, Label = "NotificationsJoinSettingsDeviceIds", HelpText = "NotificationsJoinSettingsDeviceIdsHelpText", Hidden = HiddenType.HiddenIfNotSet)]
public string DeviceIds { get; set; } public string DeviceIds { get; set; }
[FieldDefinition(2, Label = "Device Names", HelpText = "Comma separated list of full or partial device names you'd like to send notifications to. If unset, all devices will receive notifications.", HelpLink = "https://joaoapps.com/join/api/")] [FieldDefinition(2, Label = "NotificationsJoinSettingsDeviceNames", HelpText = "NotificationsJoinSettingsDeviceNamesHelpText", HelpLink = "https://joaoapps.com/join/api/")]
public string DeviceNames { get; set; } public string DeviceNames { get; set; }
[FieldDefinition(3, Label = "Notification Priority", Type = FieldType.Select, SelectOptions = typeof(JoinPriority))] [FieldDefinition(3, Label = "NotificationsJoinSettingsNotificationPriority", Type = FieldType.Select, SelectOptions = typeof(JoinPriority))]
public int Priority { get; set; } public int Priority { get; set; }
public NzbDroneValidationResult Validate() public NzbDroneValidationResult Validate()

View File

@ -2,17 +2,20 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using FluentValidation.Results; using FluentValidation.Results;
using NLog; using NLog;
using NzbDrone.Core.Localization;
namespace NzbDrone.Core.Notifications.Mailgun namespace NzbDrone.Core.Notifications.Mailgun
{ {
public class MailGun : NotificationBase<MailgunSettings> public class MailGun : NotificationBase<MailgunSettings>
{ {
private readonly IMailgunProxy _proxy; private readonly IMailgunProxy _proxy;
private readonly ILocalizationService _localizationService;
private readonly Logger _logger; private readonly Logger _logger;
public MailGun(IMailgunProxy proxy, Logger logger) public MailGun(IMailgunProxy proxy, ILocalizationService localizationService, Logger logger)
{ {
_proxy = proxy; _proxy = proxy;
_localizationService = localizationService;
_logger = logger; _logger = logger;
} }
@ -85,7 +88,7 @@ namespace NzbDrone.Core.Notifications.Mailgun
catch (Exception ex) catch (Exception ex)
{ {
_logger.Error(ex, "Unable to send test message though Mailgun."); _logger.Error(ex, "Unable to send test message though Mailgun.");
failures.Add(new ValidationFailure("", "Unable to send test message though Mailgun.")); failures.Add(new ValidationFailure(string.Empty, _localizationService.GetLocalizedString("NotificationsValidationUnableToSendTestMessage", new Dictionary<string, object> { { "exceptionMessage", ex.Message } })));
} }
return new ValidationResult(failures); return new ValidationResult(failures);

View File

@ -26,19 +26,19 @@ namespace NzbDrone.Core.Notifications.Mailgun
Recipients = Array.Empty<string>(); Recipients = Array.Empty<string>();
} }
[FieldDefinition(0, Label = "API Key", HelpText = "The API key generated from MailGun")] [FieldDefinition(0, Label = "ApiKey", HelpText = "NotificationsMailgunSettingsApiKeyHelpText")]
public string ApiKey { get; set; } public string ApiKey { get; set; }
[FieldDefinition(1, Label = "Use EU Endpoint?", HelpText = "You can choose to use the EU MailGun endpoint with this", Type = FieldType.Checkbox)] [FieldDefinition(1, Label = "NotificationsMailgunSettingsUseEuEndpoint", HelpText = "NotificationsMailgunSettingsUseEuEndpointHelpText", Type = FieldType.Checkbox)]
public bool UseEuEndpoint { get; set; } public bool UseEuEndpoint { get; set; }
[FieldDefinition(2, Label = "From Address")] [FieldDefinition(2, Label = "NotificationsEmailSettingsFromAddress")]
public string From { get; set; } public string From { get; set; }
[FieldDefinition(3, Label = "Sender Domain")] [FieldDefinition(3, Label = "NotificationsMailgunSettingsSenderDomain")]
public string SenderDomain { get; set; } public string SenderDomain { get; set; }
[FieldDefinition(4, Label = "Recipient Address(es)", Type = FieldType.Tag)] [FieldDefinition(4, Label = "NotificationsEmailSettingsRecipientAddress", Type = FieldType.Tag)]
public IEnumerable<string> Recipients { get; set; } public IEnumerable<string> Recipients { get; set; }
public NzbDroneValidationResult Validate() public NzbDroneValidationResult Validate()

View File

@ -6,6 +6,7 @@ using NLog;
using NzbDrone.Common.Disk; using NzbDrone.Common.Disk;
using NzbDrone.Common.Extensions; using NzbDrone.Common.Extensions;
using NzbDrone.Common.Http; using NzbDrone.Common.Http;
using NzbDrone.Core.Localization;
using NzbDrone.Core.Tv; using NzbDrone.Core.Tv;
namespace NzbDrone.Core.Notifications.Emby namespace NzbDrone.Core.Notifications.Emby
@ -20,11 +21,13 @@ namespace NzbDrone.Core.Notifications.Emby
public class MediaBrowserService : IMediaBrowserService public class MediaBrowserService : IMediaBrowserService
{ {
private readonly MediaBrowserProxy _proxy; private readonly MediaBrowserProxy _proxy;
private readonly ILocalizationService _localizationService;
private readonly Logger _logger; private readonly Logger _logger;
public MediaBrowserService(MediaBrowserProxy proxy, Logger logger) public MediaBrowserService(MediaBrowserProxy proxy, ILocalizationService localizationService, Logger logger)
{ {
_proxy = proxy; _proxy = proxy;
_localizationService = localizationService;
_logger = logger; _logger = logger;
} }
@ -66,13 +69,13 @@ namespace NzbDrone.Core.Notifications.Emby
{ {
if (ex.Response.StatusCode == HttpStatusCode.Unauthorized) if (ex.Response.StatusCode == HttpStatusCode.Unauthorized)
{ {
return new ValidationFailure("ApiKey", "API Key is incorrect"); return new ValidationFailure("ApiKey", _localizationService.GetLocalizedString("NotificationsValidationInvalidApiKey"));
} }
} }
catch (Exception ex) catch (Exception ex)
{ {
_logger.Error(ex, "Unable to send test message"); _logger.Error(ex, "Unable to send test message");
return new ValidationFailure("Host", "Unable to send test message: " + ex.Message); return new ValidationFailure("Host", _localizationService.GetLocalizedString("NotificationsValidationUnableToSendTestMessage", new Dictionary<string, object> { { "exceptionMessage", ex.Message } }));
} }
return null; return null;

View File

@ -33,22 +33,25 @@ namespace NzbDrone.Core.Notifications.Emby
[FieldDefinition(1, Label = "Port")] [FieldDefinition(1, Label = "Port")]
public int Port { get; set; } public int Port { get; set; }
[FieldDefinition(2, Label = "Use SSL", Type = FieldType.Checkbox, HelpText = "Connect to Emby/Jellyfin over HTTPS instead of HTTP")] [FieldDefinition(2, Label = "UseSsl", Type = FieldType.Checkbox, HelpText = "NotificationsSettingsUseSslHelpText")]
[FieldToken(TokenField.HelpText, "UseSsl", "serviceName", "Emby/Jellyfin")]
public bool UseSsl { get; set; } public bool UseSsl { get; set; }
[FieldDefinition(3, Label = "API Key", Privacy = PrivacyLevel.ApiKey)] [FieldDefinition(3, Label = "ApiKey", Privacy = PrivacyLevel.ApiKey)]
public string ApiKey { get; set; } public string ApiKey { get; set; }
[FieldDefinition(4, Label = "Send Notifications", HelpText = "Have MediaBrowser send notifications to configured providers", Type = FieldType.Checkbox)] [FieldDefinition(4, Label = "NotificationsEmbySettingsSendNotifications", HelpText = "NotificationsEmbySettingsSendNotificationsHelpText", Type = FieldType.Checkbox)]
public bool Notify { get; set; } public bool Notify { get; set; }
[FieldDefinition(5, Label = "Update Library", HelpText = "Update Library on Import, Rename, or Delete?", Type = FieldType.Checkbox)] [FieldDefinition(5, Label = "NotificationsSettingsUpdateLibrary", HelpText = "NotificationsEmbySettingsUpdateLibraryHelpText", Type = FieldType.Checkbox)]
public bool UpdateLibrary { get; set; } public bool UpdateLibrary { get; set; }
[FieldDefinition(6, Label = "Map Paths From", HelpText = "Sonarr path, used to modify series paths when Emby/Jellyfin sees library path location differently from Sonarr(Requires 'UpdateLibrary')", Type = FieldType.Textbox, Advanced = true)] [FieldDefinition(6, Label = "NotificationsSettingsUpdateMapPathsFrom", HelpText = "NotificationsSettingsUpdateMapPathsFromHelpText", Type = FieldType.Textbox, Advanced = true)]
[FieldToken(TokenField.HelpText, "NotificationsSettingsUpdateMapPathsFrom", "serviceName", "Emby/Jellyfin")]
public string MapFrom { get; set; } public string MapFrom { get; set; }
[FieldDefinition(7, Label = "Map Paths To", HelpText = "Emby/Jellyfin path, used to modify series paths when Emby/Jellyfin sees library path location differently from Sonarr(Requires 'UpdateLibrary')", Type = FieldType.Textbox, Advanced = true)] [FieldDefinition(7, Label = "NotificationsSettingsUpdateMapPathsTo", HelpText = "NotificationsSettingsUpdateMapPathsToHelpText", Type = FieldType.Textbox, Advanced = true)]
[FieldToken(TokenField.HelpText, "NotificationsSettingsUpdateMapPathsTo", "serviceName", "Emby/Jellyfin")]
public string MapTo { get; set; } public string MapTo { get; set; }
[JsonIgnore] [JsonIgnore]

View File

@ -2,6 +2,7 @@ using System.Collections.Generic;
using FluentValidation.Results; using FluentValidation.Results;
using NzbDrone.Common.Extensions; using NzbDrone.Common.Extensions;
using NzbDrone.Core.Configuration; using NzbDrone.Core.Configuration;
using NzbDrone.Core.Localization;
using NzbDrone.Core.MediaFiles; using NzbDrone.Core.MediaFiles;
using NzbDrone.Core.Notifications.Webhook; using NzbDrone.Core.Notifications.Webhook;
using NzbDrone.Core.Tv; using NzbDrone.Core.Tv;
@ -13,8 +14,8 @@ namespace NzbDrone.Core.Notifications.Notifiarr
{ {
private readonly INotifiarrProxy _proxy; private readonly INotifiarrProxy _proxy;
public Notifiarr(INotifiarrProxy proxy, IConfigFileProvider configFileProvider, IConfigService configService) public Notifiarr(INotifiarrProxy proxy, IConfigFileProvider configFileProvider, IConfigService configService, ILocalizationService localizationService)
: base(configFileProvider, configService) : base(configFileProvider, configService, localizationService)
{ {
_proxy = proxy; _proxy = proxy;
} }
@ -89,7 +90,7 @@ namespace NzbDrone.Core.Notifications.Notifiarr
} }
catch (NotifiarrException ex) catch (NotifiarrException ex)
{ {
return new NzbDroneValidationFailure("APIKey", ex.Message); return new NzbDroneValidationFailure("APIKey", _localizationService.GetLocalizedString("NotificationsValidationUnableToSendTestMessage", new Dictionary<string, object> { { "exceptionMessage", ex.Message } }));
} }
return null; return null;

View File

@ -17,7 +17,7 @@ namespace NzbDrone.Core.Notifications.Notifiarr
{ {
private static readonly NotifiarrSettingsValidator Validator = new NotifiarrSettingsValidator(); private static readonly NotifiarrSettingsValidator Validator = new NotifiarrSettingsValidator();
[FieldDefinition(0, Label = "API Key", Privacy = PrivacyLevel.ApiKey, HelpText = "Your API key from your profile", HelpLink = "https://notifiarr.com")] [FieldDefinition(0, Label = "ApiKey", Privacy = PrivacyLevel.ApiKey, HelpText = "NotificationsNotifiarrSettingsApiKeyHelpText", HelpLink = "https://notifiarr.com")]
public string ApiKey { get; set; } public string ApiKey { get; set; }
public NzbDroneValidationResult Validate() public NzbDroneValidationResult Validate()

View File

@ -1,4 +1,5 @@
using System; using System;
using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Net; using System.Net;
@ -6,6 +7,7 @@ using FluentValidation.Results;
using NLog; using NLog;
using NzbDrone.Common.Extensions; using NzbDrone.Common.Extensions;
using NzbDrone.Common.Http; using NzbDrone.Common.Http;
using NzbDrone.Core.Localization;
namespace NzbDrone.Core.Notifications.Ntfy namespace NzbDrone.Core.Notifications.Ntfy
{ {
@ -21,12 +23,13 @@ namespace NzbDrone.Core.Notifications.Ntfy
private const string DEFAULT_PUSH_URL = "https://ntfy.sh"; private const string DEFAULT_PUSH_URL = "https://ntfy.sh";
private readonly IHttpClient _httpClient; private readonly IHttpClient _httpClient;
private readonly ILocalizationService _localizationService;
private readonly Logger _logger; private readonly Logger _logger;
public NtfyProxy(IHttpClient httpClient, Logger logger) public NtfyProxy(IHttpClient httpClient, ILocalizationService localizationService, Logger logger)
{ {
_httpClient = httpClient; _httpClient = httpClient;
_localizationService = localizationService;
_logger = logger; _logger = logger;
} }
@ -83,26 +86,26 @@ namespace NzbDrone.Core.Notifications.Ntfy
if (!settings.AccessToken.IsNullOrWhiteSpace()) if (!settings.AccessToken.IsNullOrWhiteSpace())
{ {
_logger.Error(ex, "Invalid token"); _logger.Error(ex, "Invalid token");
return new ValidationFailure("AccessToken", "Invalid token"); return new ValidationFailure("AccessToken", _localizationService.GetLocalizedString("NotificationsValidationInvalidAccessToken"));
} }
if (!settings.UserName.IsNullOrWhiteSpace() && !settings.Password.IsNullOrWhiteSpace()) if (!settings.UserName.IsNullOrWhiteSpace() && !settings.Password.IsNullOrWhiteSpace())
{ {
_logger.Error(ex, "Invalid username or password"); _logger.Error(ex, "Invalid username or password");
return new ValidationFailure("UserName", "Invalid username or password"); return new ValidationFailure("UserName", _localizationService.GetLocalizedString("NotificationsValidationInvalidUsernamePassword"));
} }
_logger.Error(ex, "Authorization is required"); _logger.Error(ex, "Authorization is required");
return new ValidationFailure("AccessToken", "Authorization is required"); return new ValidationFailure("AccessToken", _localizationService.GetLocalizedString("NotificationsNtfyValidationAuthorizationRequired"));
} }
_logger.Error(ex, "Unable to send test message"); _logger.Error(ex, "Unable to send test message");
return new ValidationFailure("ServerUrl", "Unable to send test message"); return new ValidationFailure("ServerUrl", _localizationService.GetLocalizedString("NotificationsValidationUnableToSendTestMessage", new Dictionary<string, object> { { "exceptionMessage", ex.Message } }));
} }
catch (Exception ex) catch (Exception ex)
{ {
_logger.Error(ex, "Unable to send test message"); _logger.Error(ex, "Unable to send test message");
return new ValidationFailure("", "Unable to send test message"); return new ValidationFailure(string.Empty, _localizationService.GetLocalizedString("NotificationsValidationUnableToSendTestMessage", new Dictionary<string, object> { { "exceptionMessage", ex.Message } }));
} }
return null; return null;

View File

@ -34,28 +34,29 @@ namespace NzbDrone.Core.Notifications.Ntfy
Priority = 3; Priority = 3;
} }
[FieldDefinition(0, Label = "Server Url", Type = FieldType.Url, HelpLink = "https://ntfy.sh/docs/install/", HelpText = "Leave blank to use public server (https://ntfy.sh)")] [FieldDefinition(0, Label = "NotificationsNtfySettingsServerUrl", Type = FieldType.Url, HelpLink = "https://ntfy.sh/docs/install/", HelpText = "NotificationsNtfySettingsServerUrlHelpText")]
[FieldToken(TokenField.HelpText, "NotificationsNtfySettingsServerUrl", "url", "https://ntfy.sh")]
public string ServerUrl { get; set; } public string ServerUrl { get; set; }
[FieldDefinition(1, Label = "Access Token", Type = FieldType.Password, Privacy = PrivacyLevel.ApiKey, HelpText = "Optional token-based authorization. Takes priority over username/password", HelpLink = "https://docs.ntfy.sh/config/#access-tokens")] [FieldDefinition(1, Label = "NotificationsNtfySettingsAccessToken", Type = FieldType.Password, Privacy = PrivacyLevel.ApiKey, HelpText = "NotificationsNtfySettingsAccessTokenHelpText", HelpLink = "https://docs.ntfy.sh/config/#access-tokens")]
public string AccessToken { get; set; } public string AccessToken { get; set; }
[FieldDefinition(2, Label = "User Name", HelpText = "Optional Authorization", Privacy = PrivacyLevel.UserName)] [FieldDefinition(2, Label = "Username", HelpText = "NotificationsNtfySettingsUsernameHelpText", Privacy = PrivacyLevel.UserName)]
public string UserName { get; set; } public string UserName { get; set; }
[FieldDefinition(3, Label = "Password", Type = FieldType.Password, HelpText = "Optional Password", Privacy = PrivacyLevel.Password)] [FieldDefinition(3, Label = "Password", Type = FieldType.Password, HelpText = "NotificationsNtfySettingsPasswordHelpText", Privacy = PrivacyLevel.Password)]
public string Password { get; set; } public string Password { get; set; }
[FieldDefinition(4, Label = "Priority", Type = FieldType.Select, SelectOptions = typeof(NtfyPriority))] [FieldDefinition(4, Label = "Priority", Type = FieldType.Select, SelectOptions = typeof(NtfyPriority))]
public int Priority { get; set; } public int Priority { get; set; }
[FieldDefinition(5, Label = "Topics", HelpText = "List of Topics to send notifications to", Type = FieldType.Tag)] [FieldDefinition(5, Label = "NotificationsNtfySettingsTopics", HelpText = "NotificationsNtfySettingsTopicsHelpText", Type = FieldType.Tag)]
public IEnumerable<string> Topics { get; set; } public IEnumerable<string> Topics { get; set; }
[FieldDefinition(6, Label = "Ntfy Tags and Emojis", Type = FieldType.Tag, HelpText = "Optional list of tags or emojis to use", HelpLink = "https://ntfy.sh/docs/emojis/")] [FieldDefinition(6, Label = "NotificationsNtfySettingsTagsEmojis", Type = FieldType.Tag, HelpText = "", HelpLink = "https://ntfy.sh/docs/emojis/")]
public IEnumerable<string> Tags { get; set; } public IEnumerable<string> Tags { get; set; }
[FieldDefinition(7, Label = "Click URL", Type = FieldType.Url, HelpText = "Optional link when user clicks notification")] [FieldDefinition(7, Label = "NotificationsNtfySettingsClickUrl", Type = FieldType.Url, HelpText = "NotificationsNtfySettingsClickUrlHelpText")]
public string ClickUrl { get; set; } public string ClickUrl { get; set; }
public NzbDroneValidationResult Validate() public NzbDroneValidationResult Validate()

View File

@ -8,6 +8,7 @@ using NLog;
using NzbDrone.Common.Cache; using NzbDrone.Common.Cache;
using NzbDrone.Common.Disk; using NzbDrone.Common.Disk;
using NzbDrone.Common.Extensions; using NzbDrone.Common.Extensions;
using NzbDrone.Core.Localization;
using NzbDrone.Core.RootFolders; using NzbDrone.Core.RootFolders;
using NzbDrone.Core.Tv; using NzbDrone.Core.Tv;
using NzbDrone.Core.Validation; using NzbDrone.Core.Validation;
@ -26,13 +27,15 @@ namespace NzbDrone.Core.Notifications.Plex.Server
private readonly ICached<Version> _versionCache; private readonly ICached<Version> _versionCache;
private readonly IPlexServerProxy _plexServerProxy; private readonly IPlexServerProxy _plexServerProxy;
private readonly IRootFolderService _rootFolderService; private readonly IRootFolderService _rootFolderService;
private readonly ILocalizationService _localizationService;
private readonly Logger _logger; private readonly Logger _logger;
public PlexServerService(ICacheManager cacheManager, IPlexServerProxy plexServerProxy, IRootFolderService rootFolderService, Logger logger) public PlexServerService(ICacheManager cacheManager, IPlexServerProxy plexServerProxy, IRootFolderService rootFolderService, ILocalizationService localizationService, Logger logger)
{ {
_versionCache = cacheManager.GetCache<Version>(GetType(), "versionCache"); _versionCache = cacheManager.GetCache<Version>(GetType(), "versionCache");
_plexServerProxy = plexServerProxy; _plexServerProxy = plexServerProxy;
_rootFolderService = rootFolderService; _rootFolderService = rootFolderService;
_localizationService = localizationService;
_logger = logger; _logger = logger;
} }
@ -154,23 +157,23 @@ namespace NzbDrone.Core.Notifications.Plex.Server
if (sections.Empty()) if (sections.Empty())
{ {
return new ValidationFailure("Host", "At least one TV library is required"); return new ValidationFailure("Host", _localizationService.GetLocalizedString("NotificationsPlexValidationNoTvLibraryFound"));
} }
} }
catch (PlexAuthenticationException ex) catch (PlexAuthenticationException ex)
{ {
_logger.Error(ex, "Unable to connect to Plex Media Server"); _logger.Error(ex, "Unable to connect to Plex Media Server");
return new ValidationFailure("AuthToken", "Invalid authentication token"); return new ValidationFailure("AuthToken", _localizationService.GetLocalizedString("NotificationsValidationInvalidAuthenticationToken"));
} }
catch (PlexException ex) catch (PlexException ex)
{ {
return new NzbDroneValidationFailure("Host", ex.Message); return new NzbDroneValidationFailure("Host", _localizationService.GetLocalizedString("NotificationsValidationUnableToConnect", new Dictionary<string, object> { { "exceptionMessage", ex.Message } }));
} }
catch (Exception ex) catch (Exception ex)
{ {
_logger.Error(ex, "Unable to connect to Plex Media Server"); _logger.Error(ex, "Unable to connect to Plex Media Server");
return new NzbDroneValidationFailure("Host", "Unable to connect to Plex Media Server") return new NzbDroneValidationFailure("Host", _localizationService.GetLocalizedString("NotificationsValidationUnableToConnectToService", new Dictionary<string, object> { { "serviceName", "Plex Media Server" } }))
{ {
DetailedDescription = ex.Message DetailedDescription = ex.Message
}; };

View File

@ -34,22 +34,25 @@ namespace NzbDrone.Core.Notifications.Plex.Server
[FieldDefinition(1, Label = "Port")] [FieldDefinition(1, Label = "Port")]
public int Port { get; set; } public int Port { get; set; }
[FieldDefinition(2, Label = "Use SSL", Type = FieldType.Checkbox, HelpText = "Connect to Plex over HTTPS instead of HTTP")] [FieldDefinition(2, Label = "UseSsl", Type = FieldType.Checkbox, HelpText = "NotificationsSettingsUseSslHelpText")]
[FieldToken(TokenField.HelpText, "UseSsl", "serviceName", "Plex")]
public bool UseSsl { get; set; } public bool UseSsl { get; set; }
[FieldDefinition(3, Label = "Auth Token", Type = FieldType.Textbox, Privacy = PrivacyLevel.ApiKey, Advanced = true)] [FieldDefinition(3, Label = "NotificationsPlexSettingsAuthToken", Type = FieldType.Textbox, Privacy = PrivacyLevel.ApiKey, Advanced = true)]
public string AuthToken { get; set; } public string AuthToken { get; set; }
[FieldDefinition(4, Label = "Authenticate with Plex.tv", Type = FieldType.OAuth)] [FieldDefinition(4, Label = "NotificationsPlexSettingsAuthenticateWithPlexTv", Type = FieldType.OAuth)]
public string SignIn { get; set; } public string SignIn { get; set; }
[FieldDefinition(5, Label = "Update Library", Type = FieldType.Checkbox)] [FieldDefinition(5, Label = "NotificationsSettingsUpdateLibrary", Type = FieldType.Checkbox)]
public bool UpdateLibrary { get; set; } public bool UpdateLibrary { get; set; }
[FieldDefinition(6, Label = "Map Paths From", Type = FieldType.Textbox, Advanced = true, HelpText = "Sonarr path, used to modify series paths when Plex sees library path location differently from Sonarr")] [FieldDefinition(6, Label = "NotificationsSettingsUpdateMapPathsFrom", Type = FieldType.Textbox, Advanced = true, HelpText = "NotificationsSettingsUpdateMapPathsFromHelpText")]
[FieldToken(TokenField.HelpText, "NotificationsSettingsUpdateMapPathsFrom", "serviceName", "Plex")]
public string MapFrom { get; set; } public string MapFrom { get; set; }
[FieldDefinition(7, Label = "Map Paths To", Type = FieldType.Textbox, Advanced = true, HelpText = "Plex path, used to modify series paths when Plex sees library path location differently from Sonarr")] [FieldDefinition(7, Label = "NotificationsSettingsUpdateMapPathsTo", Type = FieldType.Textbox, Advanced = true, HelpText = "NotificationsSettingsUpdateMapPathsToHelpText")]
[FieldToken(TokenField.HelpText, "NotificationsSettingsUpdateMapPathsTo", "serviceName", "Plex")]
public string MapTo { get; set; } public string MapTo { get; set; }
public bool IsValid => !string.IsNullOrWhiteSpace(Host); public bool IsValid => !string.IsNullOrWhiteSpace(Host);

View File

@ -1,9 +1,11 @@
using System; using System;
using System.Collections.Generic;
using System.Net; using System.Net;
using FluentValidation.Results; using FluentValidation.Results;
using NLog; using NLog;
using NzbDrone.Common.EnvironmentInfo; using NzbDrone.Common.EnvironmentInfo;
using NzbDrone.Common.Http; using NzbDrone.Common.Http;
using NzbDrone.Core.Localization;
namespace NzbDrone.Core.Notifications.Prowl namespace NzbDrone.Core.Notifications.Prowl
{ {
@ -17,11 +19,13 @@ namespace NzbDrone.Core.Notifications.Prowl
{ {
private const string PUSH_URL = "https://api.prowlapp.com/publicapi/add"; private const string PUSH_URL = "https://api.prowlapp.com/publicapi/add";
private readonly IHttpClient _httpClient; private readonly IHttpClient _httpClient;
private readonly ILocalizationService _localizationService;
private readonly Logger _logger; private readonly Logger _logger;
public ProwlProxy(IHttpClient httpClient, Logger logger) public ProwlProxy(IHttpClient httpClient, ILocalizationService localizationService, Logger logger)
{ {
_httpClient = httpClient; _httpClient = httpClient;
_localizationService = localizationService;
_logger = logger; _logger = logger;
} }
@ -68,7 +72,7 @@ namespace NzbDrone.Core.Notifications.Prowl
} }
catch (Exception ex) catch (Exception ex)
{ {
return new ValidationFailure("ApiKey", ex.Message); return new ValidationFailure("ApiKey", _localizationService.GetLocalizedString("NotificationsValidationUnableToSendTestMessage", new Dictionary<string, object> { { "exceptionMessage", ex.Message } }));
} }
return null; return null;

View File

@ -17,7 +17,7 @@ namespace NzbDrone.Core.Notifications.Prowl
{ {
private static readonly ProwlSettingsValidator Validator = new ProwlSettingsValidator(); private static readonly ProwlSettingsValidator Validator = new ProwlSettingsValidator();
[FieldDefinition(0, Label = "API Key", Privacy = PrivacyLevel.ApiKey, HelpLink = "https://www.prowlapp.com/api_settings.php")] [FieldDefinition(0, Label = "ApiKey", Privacy = PrivacyLevel.ApiKey, HelpLink = "https://www.prowlapp.com/api_settings.php")]
public string ApiKey { get; set; } public string ApiKey { get; set; }
[FieldDefinition(1, Label = "Priority", Type = FieldType.Select, SelectOptions = typeof(ProwlPriority))] [FieldDefinition(1, Label = "Priority", Type = FieldType.Select, SelectOptions = typeof(ProwlPriority))]

View File

@ -8,6 +8,7 @@ using NLog;
using NzbDrone.Common.Extensions; using NzbDrone.Common.Extensions;
using NzbDrone.Common.Http; using NzbDrone.Common.Http;
using NzbDrone.Common.Serializer; using NzbDrone.Common.Serializer;
using NzbDrone.Core.Localization;
namespace NzbDrone.Core.Notifications.PushBullet namespace NzbDrone.Core.Notifications.PushBullet
{ {
@ -23,11 +24,13 @@ namespace NzbDrone.Core.Notifications.PushBullet
private const string PUSH_URL = "https://api.pushbullet.com/v2/pushes"; private const string PUSH_URL = "https://api.pushbullet.com/v2/pushes";
private const string DEVICE_URL = "https://api.pushbullet.com/v2/devices"; private const string DEVICE_URL = "https://api.pushbullet.com/v2/devices";
private readonly IHttpClient _httpClient; private readonly IHttpClient _httpClient;
private readonly ILocalizationService _localizationService;
private readonly Logger _logger; private readonly Logger _logger;
public PushBulletProxy(IHttpClient httpClient, Logger logger) public PushBulletProxy(IHttpClient httpClient, ILocalizationService localizationService, Logger logger)
{ {
_httpClient = httpClient; _httpClient = httpClient;
_localizationService = localizationService;
_logger = logger; _logger = logger;
} }
@ -134,16 +137,16 @@ namespace NzbDrone.Core.Notifications.PushBullet
if (ex.Response.StatusCode == HttpStatusCode.Unauthorized) if (ex.Response.StatusCode == HttpStatusCode.Unauthorized)
{ {
_logger.Error(ex, "API Key is invalid"); _logger.Error(ex, "API Key is invalid");
return new ValidationFailure("ApiKey", "API Key is invalid"); return new ValidationFailure("ApiKey", _localizationService.GetLocalizedString("NotificationsValidationInvalidApiKey"));
} }
_logger.Error(ex, "Unable to send test message"); _logger.Error(ex, "Unable to send test message");
return new ValidationFailure("ApiKey", "Unable to send test message"); return new ValidationFailure("ApiKey", _localizationService.GetLocalizedString("NotificationsValidationUnableToSendTestMessage", new Dictionary<string, object> { { "exceptionMessage", ex.Message } }));
} }
catch (Exception ex) catch (Exception ex)
{ {
_logger.Error(ex, "Unable to send test message"); _logger.Error(ex, "Unable to send test message");
return new ValidationFailure("", "Unable to send test message"); return new ValidationFailure("", _localizationService.GetLocalizedString("NotificationsValidationUnableToSendTestMessage", new Dictionary<string, object> { { "exceptionMessage", ex.Message } }));
} }
return null; return null;

View File

@ -25,16 +25,16 @@ namespace NzbDrone.Core.Notifications.PushBullet
ChannelTags = Array.Empty<string>(); ChannelTags = Array.Empty<string>();
} }
[FieldDefinition(0, Label = "Access Token", Privacy = PrivacyLevel.ApiKey, HelpLink = "https://www.pushbullet.com/#settings/account")] [FieldDefinition(0, Label = "NotificationsPushBulletSettingsAccessToken", Privacy = PrivacyLevel.ApiKey, HelpLink = "https://www.pushbullet.com/#settings/account")]
public string ApiKey { get; set; } public string ApiKey { get; set; }
[FieldDefinition(1, Label = "Device IDs", HelpText = "List of device IDs (leave blank to send to all devices)", Type = FieldType.Device)] [FieldDefinition(1, Label = "NotificationsPushBulletSettingsDeviceIds", HelpText = "NotificationsPushBulletSettingsDeviceIdsHelpText", Type = FieldType.Device)]
public IEnumerable<string> DeviceIds { get; set; } public IEnumerable<string> DeviceIds { get; set; }
[FieldDefinition(2, Label = "Channel Tags", HelpText = "List of Channel Tags to send notifications to", Type = FieldType.Tag)] [FieldDefinition(2, Label = "NotificationsPushBulletSettingsChannelTags", HelpText = "NotificationsPushBulletSettingsChannelTagsHelpText", Type = FieldType.Tag)]
public IEnumerable<string> ChannelTags { get; set; } public IEnumerable<string> ChannelTags { get; set; }
[FieldDefinition(3, Label = "Sender ID", HelpText = "The device ID to send notifications from, use device_iden in the device's URL on pushbullet.com (leave blank to send from yourself)")] [FieldDefinition(3, Label = "NotificationsPushBulletSettingSenderId", HelpText = "NotificationsPushBulletSettingSenderIdHelpText")]
public string SenderId { get; set; } public string SenderId { get; set; }
public NzbDroneValidationResult Validate() public NzbDroneValidationResult Validate()

View File

@ -1,3 +1,4 @@
using System.Collections.Generic;
using System.Net; using System.Net;
using System.Net.Http; using System.Net.Http;
using FluentValidation.Results; using FluentValidation.Results;
@ -5,6 +6,7 @@ using NLog;
using NzbDrone.Common.Extensions; using NzbDrone.Common.Extensions;
using NzbDrone.Common.Http; using NzbDrone.Common.Http;
using NzbDrone.Common.Serializer; using NzbDrone.Common.Serializer;
using NzbDrone.Core.Localization;
namespace NzbDrone.Core.Notifications.Pushcut namespace NzbDrone.Core.Notifications.Pushcut
{ {
@ -17,11 +19,13 @@ namespace NzbDrone.Core.Notifications.Pushcut
public class PushcutProxy : IPushcutProxy public class PushcutProxy : IPushcutProxy
{ {
private readonly IHttpClient _httpClient; private readonly IHttpClient _httpClient;
private readonly ILocalizationService _localizationService;
private readonly Logger _logger; private readonly Logger _logger;
public PushcutProxy(IHttpClient httpClient, Logger logger) public PushcutProxy(IHttpClient httpClient, ILocalizationService localizationService, Logger logger)
{ {
_httpClient = httpClient; _httpClient = httpClient;
_localizationService = localizationService;
_logger = logger; _logger = logger;
} }
@ -67,7 +71,7 @@ namespace NzbDrone.Core.Notifications.Pushcut
if (httpException.Response.StatusCode == HttpStatusCode.Forbidden) if (httpException.Response.StatusCode == HttpStatusCode.Forbidden)
{ {
_logger.Error(pushcutException, "API Key is invalid: {0}", pushcutException.Message); _logger.Error(pushcutException, "API Key is invalid: {0}", pushcutException.Message);
return new ValidationFailure("API Key", $"API Key is invalid: {pushcutException.Message}"); return new ValidationFailure("API Key", _localizationService.GetLocalizedString("NotificationsValidationInvalidApiKeyExceptionMessage", new Dictionary<string, object> { { "exceptionMessage", pushcutException.Message } }));
} }
if (httpException.Response.Content.IsNotNullOrWhiteSpace()) if (httpException.Response.Content.IsNotNullOrWhiteSpace())
@ -75,11 +79,11 @@ namespace NzbDrone.Core.Notifications.Pushcut
var response = Json.Deserialize<PushcutResponse>(httpException.Response.Content); var response = Json.Deserialize<PushcutResponse>(httpException.Response.Content);
_logger.Error(pushcutException, "Unable to send test notification. Response from Pushcut: {0}", response.Error); _logger.Error(pushcutException, "Unable to send test notification. Response from Pushcut: {0}", response.Error);
return new ValidationFailure("Url", $"Unable to send test notification. Response from Pushcut: {response.Error}"); return new ValidationFailure("Url", _localizationService.GetLocalizedString("NotificationsValidationUnableToSendTestMessageApiResponse", new Dictionary<string, object> { { "error", response.Error } }));
} }
_logger.Error(pushcutException, "Unable to connect to Pushcut API. Server connection failed: ({0}) {1}", httpException.Response.StatusCode, pushcutException.Message); _logger.Error(pushcutException, "Unable to connect to Pushcut API. Server connection failed: ({0}) {1}", httpException.Response.StatusCode, pushcutException.Message);
return new ValidationFailure("Host", $"Unable to connect to Pushcut API. Server connection failed: ({httpException.Response.StatusCode}) {pushcutException.Message}"); return new ValidationFailure("Host", _localizationService.GetLocalizedString("NotificationsValidationUnableToConnectToApi", new Dictionary<string, object> { { "responseCode", httpException.Response.StatusCode }, { "exceptionMessage", pushcutException.Message } }));
} }
return null; return null;

View File

@ -18,13 +18,13 @@ namespace NzbDrone.Core.Notifications.Pushcut
{ {
private static readonly PushcutSettingsValidator Validator = new (); private static readonly PushcutSettingsValidator Validator = new ();
[FieldDefinition(0, Label = "Notification name", Type = FieldType.Textbox, HelpText = "Notification name from Notifications tab of the Pushcut app.")] [FieldDefinition(0, Label = "NotificationsPushcutSettingsNotificationName", Type = FieldType.Textbox, HelpText = "")]
public string NotificationName { get; set; } public string NotificationName { get; set; }
[FieldDefinition(1, Label = "API Key", Type = FieldType.Textbox, Privacy = PrivacyLevel.ApiKey, HelpText = "API Keys can be managed in the Account view of the Pushcut app.")] [FieldDefinition(1, Label = "ApiKey", Type = FieldType.Textbox, Privacy = PrivacyLevel.ApiKey, HelpText = "NotificationsPushcutSettingsApiKeyHelpText")]
public string ApiKey { get; set; } public string ApiKey { get; set; }
[FieldDefinition(2, Label = "Time sensitive", Type = FieldType.Checkbox, HelpText = "Check to mark the notification as \"Time-Sensitive\"")] [FieldDefinition(2, Label = "NotificationsPushcutSettingsTimeSensitive", Type = FieldType.Checkbox, HelpText = "NotificationsPushcutSettingsTimeSensitiveHelpText")]
public bool TimeSensitive { get; set; } public bool TimeSensitive { get; set; }
public NzbDroneValidationResult Validate() public NzbDroneValidationResult Validate()

View File

@ -1,8 +1,10 @@
using System; using System;
using System.Collections.Generic;
using FluentValidation.Results; using FluentValidation.Results;
using NLog; using NLog;
using NzbDrone.Common.Extensions; using NzbDrone.Common.Extensions;
using NzbDrone.Common.Http; using NzbDrone.Common.Http;
using NzbDrone.Core.Localization;
namespace NzbDrone.Core.Notifications.Pushover namespace NzbDrone.Core.Notifications.Pushover
{ {
@ -17,11 +19,13 @@ namespace NzbDrone.Core.Notifications.Pushover
private const string URL = "https://api.pushover.net/1/messages.json"; private const string URL = "https://api.pushover.net/1/messages.json";
private readonly IHttpClient _httpClient; private readonly IHttpClient _httpClient;
private readonly ILocalizationService _localizationService;
private readonly Logger _logger; private readonly Logger _logger;
public PushoverProxy(IHttpClient httpClient, Logger logger) public PushoverProxy(IHttpClient httpClient, ILocalizationService localizationService, Logger logger)
{ {
_httpClient = httpClient; _httpClient = httpClient;
_localizationService = localizationService;
_logger = logger; _logger = logger;
} }
@ -64,7 +68,7 @@ namespace NzbDrone.Core.Notifications.Pushover
catch (Exception ex) catch (Exception ex)
{ {
_logger.Error(ex, "Unable to send test message"); _logger.Error(ex, "Unable to send test message");
return new ValidationFailure("ApiKey", "Unable to send test message"); return new ValidationFailure("ApiKey", _localizationService.GetLocalizedString("NotificationsValidationUnableToSendTestMessage", new Dictionary<string, object> { { "exceptionMessage", ex.Message } }));
} }
return null; return null;

View File

@ -28,25 +28,25 @@ namespace NzbDrone.Core.Notifications.Pushover
} }
// TODO: Get Pushover to change our app name (or create a new app) when we have a new logo // TODO: Get Pushover to change our app name (or create a new app) when we have a new logo
[FieldDefinition(0, Label = "API Key", Privacy = PrivacyLevel.ApiKey, HelpLink = "https://pushover.net/apps/clone/sonarr")] [FieldDefinition(0, Label = "ApiKey", Privacy = PrivacyLevel.ApiKey, HelpLink = "https://pushover.net/apps/clone/sonarr")]
public string ApiKey { get; set; } public string ApiKey { get; set; }
[FieldDefinition(1, Label = "User Key", Privacy = PrivacyLevel.UserName, HelpLink = "https://pushover.net/")] [FieldDefinition(1, Label = "NotificationsPushoverSettingsUserKey", Privacy = PrivacyLevel.UserName, HelpLink = "https://pushover.net/")]
public string UserKey { get; set; } public string UserKey { get; set; }
[FieldDefinition(2, Label = "Devices", HelpText = "List of device names (leave blank to send to all devices)", Type = FieldType.Tag)] [FieldDefinition(2, Label = "NotificationsPushoverSettingsDevices", HelpText = "NotificationsPushoverSettingsDevicesHelpText", Type = FieldType.Tag)]
public IEnumerable<string> Devices { get; set; } public IEnumerable<string> Devices { get; set; }
[FieldDefinition(3, Label = "Priority", Type = FieldType.Select, SelectOptions = typeof(PushoverPriority))] [FieldDefinition(3, Label = "Priority", Type = FieldType.Select, SelectOptions = typeof(PushoverPriority))]
public int Priority { get; set; } public int Priority { get; set; }
[FieldDefinition(4, Label = "Retry", Type = FieldType.Textbox, HelpText = "Interval to retry Emergency alerts, minimum 30 seconds")] [FieldDefinition(4, Label = "NotificationsPushoverSettingsRetry", Type = FieldType.Textbox, HelpText = "NotificationsPushoverSettingsRetryHelpText")]
public int Retry { get; set; } public int Retry { get; set; }
[FieldDefinition(5, Label = "Expire", Type = FieldType.Textbox, HelpText = "Maximum time to retry Emergency alerts, maximum 86400 seconds")] [FieldDefinition(5, Label = "NotificationsPushoverSettingsExpire", Type = FieldType.Textbox, HelpText = "NotificationsPushoverSettingsExpireHelpText")]
public int Expire { get; set; } public int Expire { get; set; }
[FieldDefinition(6, Label = "Sound", Type = FieldType.Textbox, HelpText = "Notification sound, leave blank to use the default", HelpLink = "https://pushover.net/api#sounds")] [FieldDefinition(6, Label = "NotificationsPushoverSettingsSound", Type = FieldType.Textbox, HelpText = "NotificationsPushoverSettingsSoundHelpText", HelpLink = "https://pushover.net/api#sounds")]
public string Sound { get; set; } public string Sound { get; set; }
public bool IsValid => !string.IsNullOrWhiteSpace(UserKey) && Priority >= -1 && Priority <= 2; public bool IsValid => !string.IsNullOrWhiteSpace(UserKey) && Priority >= -1 && Priority <= 2;

View File

@ -2,17 +2,20 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using FluentValidation.Results; using FluentValidation.Results;
using NLog; using NLog;
using NzbDrone.Core.Localization;
namespace NzbDrone.Core.Notifications.SendGrid namespace NzbDrone.Core.Notifications.SendGrid
{ {
public class SendGrid : NotificationBase<SendGridSettings> public class SendGrid : NotificationBase<SendGridSettings>
{ {
private readonly ISendGridProxy _proxy; private readonly ISendGridProxy _proxy;
private readonly ILocalizationService _localizationService;
private readonly Logger _logger; private readonly Logger _logger;
public SendGrid(ISendGridProxy proxy, Logger logger) public SendGrid(ISendGridProxy proxy, ILocalizationService localizationService, Logger logger)
{ {
_proxy = proxy; _proxy = proxy;
_localizationService = localizationService;
_logger = logger; _logger = logger;
} }
@ -78,7 +81,7 @@ namespace NzbDrone.Core.Notifications.SendGrid
catch (Exception ex) catch (Exception ex)
{ {
_logger.Error(ex, "Unable to send test message"); _logger.Error(ex, "Unable to send test message");
failures.Add(new ValidationFailure("", "Unable to send test message")); failures.Add(new ValidationFailure("", _localizationService.GetLocalizedString("NotificationsValidationUnableToSendTestMessage", new Dictionary<string, object> { { "exceptionMessage", ex.Message } })));
} }
return new ValidationResult(failures); return new ValidationResult(failures);

View File

@ -30,13 +30,13 @@ namespace NzbDrone.Core.Notifications.SendGrid
public string BaseUrl { get; set; } public string BaseUrl { get; set; }
[FieldDefinition(1, Label = "API Key", HelpText = "The API Key generated by SendGrid", HelpLink = "https://sendgrid.com/docs/ui/account-and-settings/api-keys/#creating-an-api-key")] [FieldDefinition(1, Label = "ApiKey", HelpText = "NotificationsSendGridSettingsApiKeyHelpText", HelpLink = "https://sendgrid.com/docs/ui/account-and-settings/api-keys/#creating-an-api-key")]
public string ApiKey { get; set; } public string ApiKey { get; set; }
[FieldDefinition(2, Label = "From Address")] [FieldDefinition(2, Label = "NotificationsEmailSettingsFromAddress")]
public string From { get; set; } public string From { get; set; }
[FieldDefinition(3, Label = "Recipient Address(es)", Type = FieldType.Tag)] [FieldDefinition(3, Label = "NotificationsEmailSettingsRecipientAddress", Type = FieldType.Tag)]
public IEnumerable<string> Recipients { get; set; } public IEnumerable<string> Recipients { get; set; }
public NzbDroneValidationResult Validate() public NzbDroneValidationResult Validate()

View File

@ -1,4 +1,5 @@
using System; using System;
using System.Collections.Generic;
using System.Net; using System.Net;
using System.Text; using System.Text;
using FluentValidation.Results; using FluentValidation.Results;
@ -6,6 +7,7 @@ using NLog;
using NzbDrone.Common.Extensions; using NzbDrone.Common.Extensions;
using NzbDrone.Common.Http; using NzbDrone.Common.Http;
using NzbDrone.Common.Serializer; using NzbDrone.Common.Serializer;
using NzbDrone.Core.Localization;
namespace NzbDrone.Core.Notifications.Signal namespace NzbDrone.Core.Notifications.Signal
{ {
@ -18,11 +20,13 @@ namespace NzbDrone.Core.Notifications.Signal
public class SignalProxy : ISignalProxy public class SignalProxy : ISignalProxy
{ {
private readonly IHttpClient _httpClient; private readonly IHttpClient _httpClient;
private readonly ILocalizationService _localizationService;
private readonly Logger _logger; private readonly Logger _logger;
public SignalProxy(IHttpClient httpClient, Logger logger) public SignalProxy(IHttpClient httpClient, ILocalizationService localizationService, Logger logger)
{ {
_httpClient = httpClient; _httpClient = httpClient;
_localizationService = localizationService;
_logger = logger; _logger = logger;
} }
@ -71,7 +75,7 @@ namespace NzbDrone.Core.Notifications.Signal
catch (WebException ex) catch (WebException ex)
{ {
_logger.Error(ex, "Unable to send test message: {0}", ex.Message); _logger.Error(ex, "Unable to send test message: {0}", ex.Message);
return new ValidationFailure("Host", $"Unable to send test message: {ex.Message}"); return new ValidationFailure("Host", _localizationService.GetLocalizedString("NotificationsValidationUnableToSendTestMessage", new Dictionary<string, object> { { "exceptionMessage", ex.Message } }));
} }
catch (HttpException ex) catch (HttpException ex)
{ {
@ -81,7 +85,7 @@ namespace NzbDrone.Core.Notifications.Signal
{ {
if (ex.Response.Content.ContainsIgnoreCase("400 The plain HTTP request was sent to HTTPS port")) if (ex.Response.Content.ContainsIgnoreCase("400 The plain HTTP request was sent to HTTPS port"))
{ {
return new ValidationFailure("UseSsl", "SSL seems to be required"); return new ValidationFailure("UseSsl", _localizationService.GetLocalizedString("NotificationsSignalValidationSslRequired"));
} }
var error = Json.Deserialize<SignalError>(ex.Response.Content); var error = Json.Deserialize<SignalError>(ex.Response.Content);
@ -97,20 +101,20 @@ namespace NzbDrone.Core.Notifications.Signal
property = "SenderNumber"; property = "SenderNumber";
} }
return new ValidationFailure(property, $"Unable to send test message: {error.Error}"); return new ValidationFailure(property, _localizationService.GetLocalizedString("NotificationsValidationUnableToSendTestMessage", new Dictionary<string, object> { { "exceptionMessage", error.Error } }));
} }
if (ex.Response.StatusCode == HttpStatusCode.Unauthorized) if (ex.Response.StatusCode == HttpStatusCode.Unauthorized)
{ {
return new ValidationFailure("AuthUsername", "Login/Password invalid"); return new ValidationFailure("AuthUsername", _localizationService.GetLocalizedString("NotificationsValidationInvalidUsernamePassword"));
} }
return new ValidationFailure("Host", $"Unable to send test message: {ex.Message}"); return new ValidationFailure("Host", _localizationService.GetLocalizedString("NotificationsValidationUnableToSendTestMessage", new Dictionary<string, object> { { "exceptionMessage", ex.Message } }));
} }
catch (Exception ex) catch (Exception ex)
{ {
_logger.Error(ex, "Unable to send test message: {0}", ex.Message); _logger.Error(ex, "Unable to send test message: {0}", ex.Message);
return new ValidationFailure("Host", $"Unable to send test message: {ex.Message}"); return new ValidationFailure("Host", _localizationService.GetLocalizedString("NotificationsValidationUnableToSendTestMessage", new Dictionary<string, object> { { "exceptionMessage", ex.Message } }));
} }
return null; return null;

View File

@ -20,25 +20,26 @@ namespace NzbDrone.Core.Notifications.Signal
{ {
private static readonly SignalSettingsValidator Validator = new (); private static readonly SignalSettingsValidator Validator = new ();
[FieldDefinition(0, Label = "Host", Type = FieldType.Textbox, HelpText = "localhost")] [FieldDefinition(0, Label = "Host", Type = FieldType.Textbox, Placeholder = "localhost")]
public string Host { get; set; } public string Host { get; set; }
[FieldDefinition(1, Label = "Port", Type = FieldType.Textbox, HelpText = "8080")] [FieldDefinition(1, Label = "Port", Type = FieldType.Textbox, Placeholder = "8080")]
public int Port { get; set; } public int Port { get; set; }
[FieldDefinition(2, Label = "Use SSL", Type = FieldType.Checkbox, HelpText = "Use a secure connection.")] [FieldDefinition(2, Label = "UseSsl", Type = FieldType.Checkbox, HelpText = "NotificationsSettingsUseSslHelpText")]
[FieldToken(TokenField.HelpText, "UseSsl", "serviceName", "Signal")]
public bool UseSsl { get; set; } public bool UseSsl { get; set; }
[FieldDefinition(3, Label = "Sender Number", Privacy = PrivacyLevel.ApiKey, HelpText = "Phone number of the sender register in signal-api")] [FieldDefinition(3, Label = "NotificationsSignalSettingsSenderNumber", Privacy = PrivacyLevel.ApiKey, HelpText = "NotificationsSignalSettingsSenderNumberHelpText")]
public string SenderNumber { get; set; } public string SenderNumber { get; set; }
[FieldDefinition(4, Label = "Group ID / PhoneNumber", HelpText = "GroupID / PhoneNumber of the receiver")] [FieldDefinition(4, Label = "NotificationsSignalSettingsGroupIdPhoneNumber", HelpText = "NotificationsSignalSettingsGroupIdPhoneNumberHelpText")]
public string ReceiverId { get; set; } public string ReceiverId { get; set; }
[FieldDefinition(5, Label = "Login", Privacy = PrivacyLevel.UserName, HelpText = "Username used to authenticate requests toward signal-api")] [FieldDefinition(5, Label = "Username", Privacy = PrivacyLevel.UserName, HelpText = "NotificationsSignalSettingsUsernameHelpText")]
public string AuthUsername { get; set; } public string AuthUsername { get; set; }
[FieldDefinition(6, Label = "Password", Type = FieldType.Password, Privacy = PrivacyLevel.Password, HelpText = "Password used to authenticate requests toward signal-api")] [FieldDefinition(6, Label = "Password", Type = FieldType.Password, Privacy = PrivacyLevel.Password, HelpText = "NotificationsSignalSettingsPasswordHelpText")]
public string AuthPassword { get; set; } public string AuthPassword { get; set; }
public NzbDroneValidationResult Validate() public NzbDroneValidationResult Validate()

View File

@ -1,7 +1,9 @@
using System; using System;
using System.Collections.Generic;
using FluentValidation.Results; using FluentValidation.Results;
using NLog; using NLog;
using NzbDrone.Common.Http; using NzbDrone.Common.Http;
using NzbDrone.Core.Localization;
namespace NzbDrone.Core.Notifications.Simplepush namespace NzbDrone.Core.Notifications.Simplepush
{ {
@ -15,11 +17,13 @@ namespace NzbDrone.Core.Notifications.Simplepush
{ {
private const string URL = "https://api.simplepush.io/send"; private const string URL = "https://api.simplepush.io/send";
private readonly IHttpClient _httpClient; private readonly IHttpClient _httpClient;
private readonly ILocalizationService _localizationService;
private readonly Logger _logger; private readonly Logger _logger;
public SimplepushProxy(IHttpClient httpClient, Logger logger) public SimplepushProxy(IHttpClient httpClient, ILocalizationService localizationService, Logger logger)
{ {
_httpClient = httpClient; _httpClient = httpClient;
_localizationService = localizationService;
_logger = logger; _logger = logger;
} }
@ -49,7 +53,7 @@ namespace NzbDrone.Core.Notifications.Simplepush
catch (Exception ex) catch (Exception ex)
{ {
_logger.Error(ex, "Unable to send test message"); _logger.Error(ex, "Unable to send test message");
return new ValidationFailure("ApiKey", "Unable to send test message"); return new ValidationFailure("ApiKey", _localizationService.GetLocalizedString("NotificationsValidationUnableToSendTestMessage", new Dictionary<string, object> { { "exceptionMessage", ex.Message } }));
} }
return null; return null;

View File

@ -17,10 +17,10 @@ namespace NzbDrone.Core.Notifications.Simplepush
{ {
private static readonly SimplepushSettingsValidator Validator = new SimplepushSettingsValidator(); private static readonly SimplepushSettingsValidator Validator = new SimplepushSettingsValidator();
[FieldDefinition(0, Label = "Key", Privacy = PrivacyLevel.ApiKey, HelpLink = "https://simplepush.io/features")] [FieldDefinition(0, Label = "NotificationsSimplepushSettingsKey", Privacy = PrivacyLevel.ApiKey, HelpLink = "https://simplepush.io/features")]
public string Key { get; set; } public string Key { get; set; }
[FieldDefinition(1, Label = "Event", HelpText = "Customize the behavior of push notifications", HelpLink = "https://simplepush.io/features")] [FieldDefinition(1, Label = "NotificationsSimplepushSettingsEvent", HelpText = "NotificationsSimplepushSettingsEventHelpText", HelpLink = "https://simplepush.io/features")]
public string Event { get; set; } public string Event { get; set; }
public bool IsValid => !string.IsNullOrWhiteSpace(Key); public bool IsValid => !string.IsNullOrWhiteSpace(Key);

View File

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using FluentValidation.Results; using FluentValidation.Results;
using NzbDrone.Common.Extensions; using NzbDrone.Common.Extensions;
using NzbDrone.Core.Localization;
using NzbDrone.Core.MediaFiles; using NzbDrone.Core.MediaFiles;
using NzbDrone.Core.Notifications.Slack.Payloads; using NzbDrone.Core.Notifications.Slack.Payloads;
using NzbDrone.Core.Tv; using NzbDrone.Core.Tv;
@ -13,10 +14,12 @@ namespace NzbDrone.Core.Notifications.Slack
public class Slack : NotificationBase<SlackSettings> public class Slack : NotificationBase<SlackSettings>
{ {
private readonly ISlackProxy _proxy; private readonly ISlackProxy _proxy;
private readonly ILocalizationService _localizationService;
public Slack(ISlackProxy proxy) public Slack(ISlackProxy proxy, ILocalizationService localizationService)
{ {
_proxy = proxy; _proxy = proxy;
_localizationService = localizationService;
} }
public override string Name => "Slack"; public override string Name => "Slack";
@ -205,7 +208,7 @@ namespace NzbDrone.Core.Notifications.Slack
} }
catch (SlackExeption ex) catch (SlackExeption ex)
{ {
return new NzbDroneValidationFailure("Unable to post", ex.Message); return new NzbDroneValidationFailure("Unable to post", _localizationService.GetLocalizedString("NotificationsValidationUnableToSendTestMessage", new Dictionary<string, object> { { "exceptionMessage", ex.Message } }));
} }
return null; return null;

View File

@ -18,16 +18,16 @@ namespace NzbDrone.Core.Notifications.Slack
{ {
private static readonly SlackSettingsValidator Validator = new SlackSettingsValidator(); private static readonly SlackSettingsValidator Validator = new SlackSettingsValidator();
[FieldDefinition(0, Label = "Webhook URL", HelpText = "Slack channel webhook url", Type = FieldType.Url, HelpLink = "https://my.slack.com/services/new/incoming-webhook/")] [FieldDefinition(0, Label = "NotificationsSettingsWebhookUrl", HelpText = "NotificationsSlackSettingsWebhookUrlHelpText", Type = FieldType.Url, HelpLink = "https://my.slack.com/services/new/incoming-webhook/")]
public string WebHookUrl { get; set; } public string WebHookUrl { get; set; }
[FieldDefinition(1, Label = "Username", Privacy = PrivacyLevel.UserName, HelpText = "Choose the username that this integration will post as", Type = FieldType.Textbox)] [FieldDefinition(1, Label = "Username", Privacy = PrivacyLevel.UserName, HelpText = "NotificationsSlackSettingsUsernameHelpText", Type = FieldType.Textbox)]
public string Username { get; set; } public string Username { get; set; }
[FieldDefinition(2, Label = "Icon", HelpText = "Change the icon that is used for messages from this integration (Emoji or URL)", Type = FieldType.Textbox, HelpLink = "http://www.emoji-cheat-sheet.com/")] [FieldDefinition(2, Label = "NotificationsSlackSettingsIcon", HelpText = "NotificationsSlackSettingsIconHelpText", Type = FieldType.Textbox, HelpLink = "http://www.emoji-cheat-sheet.com/")]
public string Icon { get; set; } public string Icon { get; set; }
[FieldDefinition(3, Label = "Channel", HelpText = "Overrides the default channel for the incoming webhook (#other-channel)", Type = FieldType.Textbox)] [FieldDefinition(3, Label = "NotificationsSlackSettingsChannel", HelpText = "NotificationsSlackSettingsChannelHelpText", Type = FieldType.Textbox)]
public string Channel { get; set; } public string Channel { get; set; }
public NzbDroneValidationResult Validate() public NzbDroneValidationResult Validate()

View File

@ -3,6 +3,7 @@ using System.IO;
using FluentValidation.Results; using FluentValidation.Results;
using NzbDrone.Common.EnvironmentInfo; using NzbDrone.Common.EnvironmentInfo;
using NzbDrone.Common.Extensions; using NzbDrone.Common.Extensions;
using NzbDrone.Core.Localization;
using NzbDrone.Core.MediaFiles; using NzbDrone.Core.MediaFiles;
using NzbDrone.Core.Tv; using NzbDrone.Core.Tv;
@ -11,10 +12,12 @@ namespace NzbDrone.Core.Notifications.Synology
public class SynologyIndexer : NotificationBase<SynologyIndexerSettings> public class SynologyIndexer : NotificationBase<SynologyIndexerSettings>
{ {
private readonly ISynologyIndexerProxy _indexerProxy; private readonly ISynologyIndexerProxy _indexerProxy;
private readonly ILocalizationService _localizationService;
public SynologyIndexer(ISynologyIndexerProxy indexerProxy) public SynologyIndexer(ISynologyIndexerProxy indexerProxy, ILocalizationService localizationService)
{ {
_indexerProxy = indexerProxy; _indexerProxy = indexerProxy;
_localizationService = localizationService;
} }
public override string Link => "https://www.synology.com"; public override string Link => "https://www.synology.com";
@ -88,12 +91,12 @@ namespace NzbDrone.Core.Notifications.Synology
{ {
if (!OsInfo.IsLinux) if (!OsInfo.IsLinux)
{ {
return new ValidationFailure(null, "Must be a Synology"); return new ValidationFailure(string.Empty, _localizationService.GetLocalizedString("NotificationsSynologyValidationInvalidOs"));
} }
if (!_indexerProxy.Test()) if (!_indexerProxy.Test())
{ {
return new ValidationFailure(null, "Not a Synology or synoindex not available"); return new ValidationFailure(string.Empty, _localizationService.GetLocalizedString("NotificationsSynologyValidationTestFailed"));
} }
return null; return null;

View File

@ -18,7 +18,7 @@ namespace NzbDrone.Core.Notifications.Synology
UpdateLibrary = true; UpdateLibrary = true;
} }
[FieldDefinition(0, Label = "Update Library", Type = FieldType.Checkbox, HelpText = "Call synoindex on localhost to update a library file")] [FieldDefinition(0, Label = "NotificationsSettingsUpdateLibrary", Type = FieldType.Checkbox, HelpText = "NotificationsSynologySettingsUpdateLibraryHelpText")]
public bool UpdateLibrary { get; set; } public bool UpdateLibrary { get; set; }
public NzbDroneValidationResult Validate() public NzbDroneValidationResult Validate()

View File

@ -1,4 +1,5 @@
using System; using System;
using System.Collections.Generic;
using System.Net; using System.Net;
using System.Web; using System.Web;
using FluentValidation.Results; using FluentValidation.Results;
@ -6,6 +7,7 @@ using NLog;
using NzbDrone.Common.Extensions; using NzbDrone.Common.Extensions;
using NzbDrone.Common.Http; using NzbDrone.Common.Http;
using NzbDrone.Common.Serializer; using NzbDrone.Common.Serializer;
using NzbDrone.Core.Localization;
namespace NzbDrone.Core.Notifications.Telegram namespace NzbDrone.Core.Notifications.Telegram
{ {
@ -20,11 +22,13 @@ namespace NzbDrone.Core.Notifications.Telegram
private const string URL = "https://api.telegram.org"; private const string URL = "https://api.telegram.org";
private readonly IHttpClient _httpClient; private readonly IHttpClient _httpClient;
private readonly ILocalizationService _localizationService;
private readonly Logger _logger; private readonly Logger _logger;
public TelegramProxy(IHttpClient httpClient, Logger logger) public TelegramProxy(IHttpClient httpClient, ILocalizationService localizationService, Logger logger)
{ {
_httpClient = httpClient; _httpClient = httpClient;
_localizationService = localizationService;
_logger = logger; _logger = logger;
} }
@ -61,7 +65,7 @@ namespace NzbDrone.Core.Notifications.Telegram
if (ex is WebException webException) if (ex is WebException webException)
{ {
return new ValidationFailure("Connection", $"{webException.Status.ToString()}: {webException.Message}"); return new ValidationFailure("Connection", _localizationService.GetLocalizedString("NotificationsValidationUnableToConnectToApi", new Dictionary<string, object> { { "service", "Telegram" }, { "responseCode", webException.Status.ToString() }, { "exceptionMessage", webException.Message } }));
} }
else if (ex is Common.Http.HttpException restException && restException.Response.StatusCode == HttpStatusCode.BadRequest) else if (ex is Common.Http.HttpException restException && restException.Response.StatusCode == HttpStatusCode.BadRequest)
{ {
@ -77,10 +81,10 @@ namespace NzbDrone.Core.Notifications.Telegram
property = "TopicId"; property = "TopicId";
} }
return new ValidationFailure(property, error.Description); return new ValidationFailure(property, _localizationService.GetLocalizedString("NotificationsValidationUnableToConnect", new Dictionary<string, object> { { "exceptionMessage", error.Description } }));
} }
return new ValidationFailure("BotToken", "Unable to send test message"); return new ValidationFailure("BotToken", _localizationService.GetLocalizedString("NotificationsValidationUnableToConnect", new Dictionary<string, object> { { "exceptionMessage", ex.Message } }));
} }
return null; return null;

View File

@ -20,16 +20,16 @@ namespace NzbDrone.Core.Notifications.Telegram
{ {
private static readonly TelegramSettingsValidator Validator = new TelegramSettingsValidator(); private static readonly TelegramSettingsValidator Validator = new TelegramSettingsValidator();
[FieldDefinition(0, Label = "Bot Token", 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; }
[FieldDefinition(1, Label = "Chat ID", HelpLink = "http://stackoverflow.com/a/37396871/882971", HelpText = "You must start a conversation with the bot or add it to your group to receive messages")] [FieldDefinition(1, Label = "NotificationsTelegramSettingsChatId", HelpLink = "http://stackoverflow.com/a/37396871/882971", HelpText = "NotificationsTelegramSettingsChatIdHelpText")]
public string ChatId { get; set; } public string ChatId { get; set; }
[FieldDefinition(2, Label = "Topic ID", HelpLink = "https://stackoverflow.com/a/75178418", HelpText = "Specify a Topic ID to send notifications to that topic. Leave blank to use the general topic (Supergroups only)")] [FieldDefinition(2, Label = "NotificationsTelegramSettingsTopicId", HelpLink = "https://stackoverflow.com/a/75178418", HelpText = "NotificationsTelegramSettingsTopicIdHelpText")]
public int? TopicId { get; set; } public int? TopicId { get; set; }
[FieldDefinition(3, Label = "Send Silently", Type = FieldType.Checkbox, HelpText = "Sends the message silently. Users will receive a notification with no sound")] [FieldDefinition(3, Label = "NotificationsTelegramSettingsSendSilently", Type = FieldType.Checkbox, HelpText = "NotificationsTelegramSettingsSendSilentlyHelpText")]
public bool SendSilently { get; set; } public bool SendSilently { get; set; }
public NzbDroneValidationResult Validate() public NzbDroneValidationResult Validate()

View File

@ -5,6 +5,7 @@ using FluentValidation.Results;
using NLog; using NLog;
using NzbDrone.Common.Extensions; using NzbDrone.Common.Extensions;
using NzbDrone.Common.Http; using NzbDrone.Common.Http;
using NzbDrone.Core.Localization;
using NzbDrone.Core.MediaFiles; using NzbDrone.Core.MediaFiles;
using NzbDrone.Core.MediaFiles.MediaInfo; using NzbDrone.Core.MediaFiles.MediaInfo;
using NzbDrone.Core.Notifications.Trakt.Resource; using NzbDrone.Core.Notifications.Trakt.Resource;
@ -18,12 +19,14 @@ namespace NzbDrone.Core.Notifications.Trakt
{ {
private readonly ITraktProxy _proxy; private readonly ITraktProxy _proxy;
private readonly INotificationRepository _notificationRepository; private readonly INotificationRepository _notificationRepository;
private readonly ILocalizationService _localizationService;
private readonly Logger _logger; private readonly Logger _logger;
public Trakt(ITraktProxy proxy, INotificationRepository notificationRepository, Logger logger) public Trakt(ITraktProxy proxy, INotificationRepository notificationRepository, ILocalizationService localizationService, Logger logger)
{ {
_proxy = proxy; _proxy = proxy;
_notificationRepository = notificationRepository; _notificationRepository = notificationRepository;
_localizationService = localizationService;
_logger = logger; _logger = logger;
} }
@ -70,20 +73,20 @@ namespace NzbDrone.Core.Notifications.Trakt
{ {
_logger.Error(ex, "Access Token is invalid: " + ex.Message); _logger.Error(ex, "Access Token is invalid: " + ex.Message);
failures.Add(new ValidationFailure("Token", "Access Token is invalid")); failures.Add(new ValidationFailure("Token", _localizationService.GetLocalizedString("NotificationsValidationInvalidAccessToken")));
} }
else else
{ {
_logger.Error(ex, "Unable to send test message: " + ex.Message); _logger.Error(ex, "Unable to send test message: " + ex.Message);
failures.Add(new ValidationFailure("Token", "Unable to send test message")); failures.Add(new ValidationFailure("Token", _localizationService.GetLocalizedString("NotificationsValidationUnableToSendTestMessage", new Dictionary<string, object> { { "exceptionMessage", ex.Message } })));
} }
} }
catch (Exception ex) catch (Exception ex)
{ {
_logger.Error(ex, "Unable to send test message: " + ex.Message); _logger.Error(ex, "Unable to send test message: " + ex.Message);
failures.Add(new ValidationFailure("", "Unable to send test message")); failures.Add(new ValidationFailure("", _localizationService.GetLocalizedString("NotificationsValidationUnableToSendTestMessage", new Dictionary<string, object> { { "exceptionMessage", ex.Message } })));
} }
return new ValidationResult(failures); return new ValidationResult(failures);

View File

@ -25,19 +25,19 @@ namespace NzbDrone.Core.Notifications.Trakt
SignIn = "startOAuth"; SignIn = "startOAuth";
} }
[FieldDefinition(0, Label = "Access Token", Type = FieldType.Textbox, Hidden = HiddenType.Hidden)] [FieldDefinition(0, Label = "NotificationsTraktSettingsAccessToken", Type = FieldType.Textbox, Hidden = HiddenType.Hidden)]
public string AccessToken { get; set; } public string AccessToken { get; set; }
[FieldDefinition(1, Label = "Refresh Token", Type = FieldType.Textbox, Hidden = HiddenType.Hidden)] [FieldDefinition(1, Label = "NotificationsTraktSettingsRefreshToken", Type = FieldType.Textbox, Hidden = HiddenType.Hidden)]
public string RefreshToken { get; set; } public string RefreshToken { get; set; }
[FieldDefinition(2, Label = "Expires", Type = FieldType.Textbox, Hidden = HiddenType.Hidden)] [FieldDefinition(2, Label = "NotificationsTraktSettingsExpires", Type = FieldType.Textbox, Hidden = HiddenType.Hidden)]
public DateTime Expires { get; set; } public DateTime Expires { get; set; }
[FieldDefinition(3, Label = "Auth User", Type = FieldType.Textbox, Hidden = HiddenType.Hidden)] [FieldDefinition(3, Label = "NotificationsTraktSettingsAuthUser", Type = FieldType.Textbox, Hidden = HiddenType.Hidden)]
public string AuthUser { get; set; } public string AuthUser { get; set; }
[FieldDefinition(4, Label = "Authenticate with Trakt", Type = FieldType.OAuth)] [FieldDefinition(4, Label = "NotificationsTraktSettingsAuthenticateWithTrakt", Type = FieldType.OAuth)]
public string SignIn { get; set; } public string SignIn { get; set; }
public NzbDroneValidationResult Validate() public NzbDroneValidationResult Validate()

View File

@ -1,9 +1,11 @@
using System; using System;
using System.Collections.Generic;
using System.IO; using System.IO;
using System.Net; using System.Net;
using FluentValidation.Results; using FluentValidation.Results;
using NLog; using NLog;
using NzbDrone.Common.Extensions; using NzbDrone.Common.Extensions;
using NzbDrone.Core.Localization;
namespace NzbDrone.Core.Notifications.Twitter namespace NzbDrone.Core.Notifications.Twitter
{ {
@ -18,11 +20,13 @@ namespace NzbDrone.Core.Notifications.Twitter
public class TwitterService : ITwitterService public class TwitterService : ITwitterService
{ {
private readonly ITwitterProxy _twitterProxy; private readonly ITwitterProxy _twitterProxy;
private readonly ILocalizationService _localizationService;
private readonly Logger _logger; private readonly Logger _logger;
public TwitterService(ITwitterProxy twitterProxy, Logger logger) public TwitterService(ITwitterProxy twitterProxy, ILocalizationService localizationService, Logger logger)
{ {
_twitterProxy = twitterProxy; _twitterProxy = twitterProxy;
_localizationService = localizationService;
_logger = logger; _logger = logger;
} }
@ -96,7 +100,7 @@ namespace NzbDrone.Core.Notifications.Twitter
catch (Exception ex) catch (Exception ex)
{ {
_logger.Error(ex, "Unable to send test message"); _logger.Error(ex, "Unable to send test message");
return new ValidationFailure("Host", "Unable to send test message"); return new ValidationFailure("Host", _localizationService.GetLocalizedString("NotificationsValidationUnableToSendTestMessage", new Dictionary<string, object> { { "exceptionMessage", ex.Message } }));
} }
return null; return null;

View File

@ -38,25 +38,25 @@ namespace NzbDrone.Core.Notifications.Twitter
AuthorizeNotification = "startOAuth"; AuthorizeNotification = "startOAuth";
} }
[FieldDefinition(0, Label = "Consumer Key", Privacy = PrivacyLevel.ApiKey, HelpText = "Consumer key from a Twitter application", HelpLink = "https://wiki.servarr.com/useful-tools#twitter-connect")] [FieldDefinition(0, Label = "NotificationsTwitterSettingsConsumerKey", Privacy = PrivacyLevel.ApiKey, HelpText = "NotificationsTwitterSettingsConsumerKeyHelpText", HelpLink = "https://wiki.servarr.com/useful-tools#twitter-connect")]
public string ConsumerKey { get; set; } public string ConsumerKey { get; set; }
[FieldDefinition(1, Label = "Consumer Secret", Privacy = PrivacyLevel.ApiKey, HelpText = "Consumer secret from a Twitter application", HelpLink = "https://wiki.servarr.com/useful-tools#twitter-connect")] [FieldDefinition(1, Label = "NotificationsTwitterSettingsConsumerSecret", Privacy = PrivacyLevel.ApiKey, HelpText = "NotificationsTwitterSettingsConsumerSecretHelpText", HelpLink = "https://wiki.servarr.com/useful-tools#twitter-connect")]
public string ConsumerSecret { get; set; } public string ConsumerSecret { get; set; }
[FieldDefinition(2, Label = "Access Token", Privacy = PrivacyLevel.ApiKey, Advanced = true)] [FieldDefinition(2, Label = "NotificationsTwitterSettingsAccessToken", Privacy = PrivacyLevel.ApiKey, Advanced = true)]
public string AccessToken { get; set; } public string AccessToken { get; set; }
[FieldDefinition(3, Label = "Access Token Secret", Privacy = PrivacyLevel.ApiKey, Advanced = true)] [FieldDefinition(3, Label = "NotificationsTwitterSettingsAccessTokenSecret", Privacy = PrivacyLevel.ApiKey, Advanced = true)]
public string AccessTokenSecret { get; set; } public string AccessTokenSecret { get; set; }
[FieldDefinition(4, Label = "Mention", HelpText = "Mention this user in sent tweets")] [FieldDefinition(4, Label = "NotificationsTwitterSettingsMention", HelpText = "NotificationsTwitterSettingsMentionHelpText")]
public string Mention { get; set; } public string Mention { get; set; }
[FieldDefinition(5, Label = "Direct Message", Type = FieldType.Checkbox, HelpText = "Send a direct message instead of a public message")] [FieldDefinition(5, Label = "NotificationsTwitterSettingsDirectMessage", Type = FieldType.Checkbox, HelpText = "NotificationsTwitterSettingsDirectMessageHelpText")]
public bool DirectMessage { get; set; } public bool DirectMessage { get; set; }
[FieldDefinition(6, Label = "Connect to Twitter", Type = FieldType.OAuth)] [FieldDefinition(6, Label = "NotificationsTwitterSettingsConnectToTwitter", Type = FieldType.OAuth)]
public string AuthorizeNotification { get; set; } public string AuthorizeNotification { get; set; }
public NzbDroneValidationResult Validate() public NzbDroneValidationResult Validate()

View File

@ -2,6 +2,7 @@ using System.Collections.Generic;
using FluentValidation.Results; using FluentValidation.Results;
using NzbDrone.Common.Extensions; using NzbDrone.Common.Extensions;
using NzbDrone.Core.Configuration; using NzbDrone.Core.Configuration;
using NzbDrone.Core.Localization;
using NzbDrone.Core.MediaFiles; using NzbDrone.Core.MediaFiles;
using NzbDrone.Core.Tv; using NzbDrone.Core.Tv;
using NzbDrone.Core.Validation; using NzbDrone.Core.Validation;
@ -12,8 +13,8 @@ namespace NzbDrone.Core.Notifications.Webhook
{ {
private readonly IWebhookProxy _proxy; private readonly IWebhookProxy _proxy;
public Webhook(IWebhookProxy proxy, IConfigFileProvider configFileProvider, IConfigService configService) public Webhook(IWebhookProxy proxy, IConfigFileProvider configFileProvider, IConfigService configService, ILocalizationService localizationService)
: base(configFileProvider, configService) : base(configFileProvider, configService, localizationService)
{ {
_proxy = proxy; _proxy = proxy;
} }
@ -89,7 +90,7 @@ namespace NzbDrone.Core.Notifications.Webhook
} }
catch (WebhookException ex) catch (WebhookException ex)
{ {
return new NzbDroneValidationFailure("Url", ex.Message); return new NzbDroneValidationFailure("Url", _localizationService.GetLocalizedString("NotificationsValidationUnableToSendTestMessage", new Dictionary<string, object> { { "exceptionMessage", ex.Message } }));
} }
return null; return null;

View File

@ -2,6 +2,7 @@ using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using NzbDrone.Core.Configuration; using NzbDrone.Core.Configuration;
using NzbDrone.Core.Localization;
using NzbDrone.Core.MediaFiles; using NzbDrone.Core.MediaFiles;
using NzbDrone.Core.ThingiProvider; using NzbDrone.Core.ThingiProvider;
using NzbDrone.Core.Tv; using NzbDrone.Core.Tv;
@ -13,11 +14,13 @@ namespace NzbDrone.Core.Notifications.Webhook
{ {
private readonly IConfigFileProvider _configFileProvider; private readonly IConfigFileProvider _configFileProvider;
private readonly IConfigService _configService; private readonly IConfigService _configService;
protected readonly ILocalizationService _localizationService;
protected WebhookBase(IConfigFileProvider configFileProvider, IConfigService configService) protected WebhookBase(IConfigFileProvider configFileProvider, IConfigService configService, ILocalizationService localizationService)
{ {
_configFileProvider = configFileProvider; _configFileProvider = configFileProvider;
_configService = configService; _configService = configService;
_localizationService = localizationService;
} }
protected WebhookGrabPayload BuildOnGrabPayload(GrabMessage message) protected WebhookGrabPayload BuildOnGrabPayload(GrabMessage message)

View File

@ -23,10 +23,10 @@ namespace NzbDrone.Core.Notifications.Webhook
Method = Convert.ToInt32(WebhookMethod.POST); Method = Convert.ToInt32(WebhookMethod.POST);
} }
[FieldDefinition(0, Label = "URL", Type = FieldType.Url)] [FieldDefinition(0, Label = "NotificationsSettingsWebhookUrl", Type = FieldType.Url)]
public string Url { get; set; } public string Url { get; set; }
[FieldDefinition(1, Label = "Method", Type = FieldType.Select, SelectOptions = typeof(WebhookMethod), HelpText = "Which HTTP method to use submit to the Webservice")] [FieldDefinition(1, Label = "NotificationsSettingsWebhookMethod", Type = FieldType.Select, SelectOptions = typeof(WebhookMethod), HelpText = "NotificationsSettingsWebhookMethodHelpText")]
public int Method { get; set; } public int Method { get; set; }
[FieldDefinition(2, Label = "Username", Privacy = PrivacyLevel.UserName)] [FieldDefinition(2, Label = "Username", Privacy = PrivacyLevel.UserName)]

View File

@ -1,7 +1,9 @@
using System; using System;
using System.Collections.Generic;
using System.Linq; using System.Linq;
using FluentValidation.Results; using FluentValidation.Results;
using NLog; using NLog;
using NzbDrone.Core.Localization;
using NzbDrone.Core.Tv; using NzbDrone.Core.Tv;
namespace NzbDrone.Core.Notifications.Xbmc namespace NzbDrone.Core.Notifications.Xbmc
@ -17,12 +19,13 @@ namespace NzbDrone.Core.Notifications.Xbmc
public class XbmcService : IXbmcService public class XbmcService : IXbmcService
{ {
private readonly IXbmcJsonApiProxy _proxy; private readonly IXbmcJsonApiProxy _proxy;
private readonly ILocalizationService _localizationService;
private readonly Logger _logger; private readonly Logger _logger;
public XbmcService(IXbmcJsonApiProxy proxy, public XbmcService(IXbmcJsonApiProxy proxy, ILocalizationService localizationService, Logger logger)
Logger logger)
{ {
_proxy = proxy; _proxy = proxy;
_localizationService = localizationService;
_logger = logger; _logger = logger;
} }
@ -130,7 +133,7 @@ namespace NzbDrone.Core.Notifications.Xbmc
catch (Exception ex) catch (Exception ex)
{ {
_logger.Error(ex, "Unable to send test message"); _logger.Error(ex, "Unable to send test message");
return new ValidationFailure("Host", "Unable to send test message"); return new ValidationFailure("Host", _localizationService.GetLocalizedString("NotificationsValidationUnableToSendTestMessage", new Dictionary<string, object> { { "exceptionMessage", ex.Message } }));
} }
return null; return null;

View File

@ -33,7 +33,8 @@ namespace NzbDrone.Core.Notifications.Xbmc
[FieldDefinition(1, Label = "Port")] [FieldDefinition(1, Label = "Port")]
public int Port { get; set; } public int Port { get; set; }
[FieldDefinition(2, Label = "Use SSL", Type = FieldType.Checkbox, HelpText = "Connect to Kodi over HTTPS instead of HTTP")] [FieldDefinition(2, Label = "UseSsl", Type = FieldType.Checkbox, HelpText = "NotificationsSettingsUseSslHelpText")]
[FieldToken(TokenField.HelpText, "UseSsl", "serviceName", "Kodi")]
public bool UseSsl { get; set; } public bool UseSsl { get; set; }
[FieldDefinition(3, Label = "Username", Privacy = PrivacyLevel.UserName)] [FieldDefinition(3, Label = "Username", Privacy = PrivacyLevel.UserName)]
@ -43,19 +44,19 @@ namespace NzbDrone.Core.Notifications.Xbmc
public string Password { get; set; } public string Password { get; set; }
[DefaultValue(5)] [DefaultValue(5)]
[FieldDefinition(5, Label = "Display Time", HelpText = "How long the notification will be displayed for (In seconds)")] [FieldDefinition(5, Label = "NotificationsKodiSettingsDisplayTime", HelpText = "NotificationsKodiSettingsDisplayTimeHelpText")]
public int DisplayTime { get; set; } public int DisplayTime { get; set; }
[FieldDefinition(6, Label = "GUI Notification", Type = FieldType.Checkbox)] [FieldDefinition(6, Label = "NotificationsKodiSettingsGuiNotification", Type = FieldType.Checkbox)]
public bool Notify { get; set; } public bool Notify { get; set; }
[FieldDefinition(7, Label = "Update Library", HelpText = "Update Library on Import & Rename?", Type = FieldType.Checkbox)] [FieldDefinition(7, Label = "NotificationsSettingsUpdateLibrary", HelpText = "NotificationsKodiSettingsUpdateLibraryHelpText", Type = FieldType.Checkbox)]
public bool UpdateLibrary { get; set; } public bool UpdateLibrary { get; set; }
[FieldDefinition(8, Label = "Clean Library", HelpText = "Clean Library after update?", Type = FieldType.Checkbox)] [FieldDefinition(8, Label = "NotificationsKodiSettingsCleanLibrary", HelpText = "NotificationsKodiSettingsCleanLibraryHelpText", Type = FieldType.Checkbox)]
public bool CleanLibrary { get; set; } public bool CleanLibrary { get; set; }
[FieldDefinition(9, Label = "Always Update", HelpText = "Update Library even when a video is playing?", Type = FieldType.Checkbox)] [FieldDefinition(9, Label = "NotificationsKodiSettingAlwaysUpdate", HelpText = "NotificationsKodiSettingAlwaysUpdateHelpText", Type = FieldType.Checkbox)]
public bool AlwaysUpdate { get; set; } public bool AlwaysUpdate { get; set; }
[JsonIgnore] [JsonIgnore]