From d4d91465997d87296d137f83002de2e405aa0c3a Mon Sep 17 00:00:00 2001 From: Qstick Date: Thu, 21 Mar 2019 20:47:54 -0400 Subject: [PATCH] New: Health Check Failure Notifications (#609) * New: Health Check Failure Notifications Fixes #295 * New: OnDownloadFailure and OnImportFailure Notification * New: On Retag notifications * Fixed: XBMC notification test * New: Discord Notifications Closes #1511 * On Download to On Import on card * Remove OnDownload, Rename OnAlbumDownload -> OnReleaseImported * Fixed: Webhook OnReleaseImport notification * Respect OnUpgrade and fix missing schema items for frontend * New: Simplify Notification Modal UI * Fixed: PlexHomeTheater OnReleaseImport notification --- .../EditNotificationModalContent.js | 82 +------- .../Notifications/Notification.js | 70 +++++-- .../Notifications/NotificationEventItems.css | 4 + .../Notifications/NotificationEventItems.js | 160 +++++++++++++++ .../Store/Actions/Settings/notifications.js | 6 +- .../Notifications/NotificationModule.cs | 4 +- .../Notifications/NotificationResource.cs | 45 +++-- .../NotificationBaseFixture.cs | 50 +++-- .../SynologyIndexerFixture.cs | 4 +- .../Xbmc/Json/UpdateFixture.cs | 10 +- ...adFixture.cs => OnReleaseImportFixture.cs} | 20 +- .../NzbDrone.Core.Test.csproj | 2 +- .../029_health_issue_notification.cs | 23 +++ src/NzbDrone.Core/Datastore/TableMapping.cs | 10 +- .../HealthCheck/HealthCheckFailedEvent.cs | 14 ++ .../HealthCheck/HealthCheckService.cs | 6 + .../Notifications/Boxcar/Boxcar.cs | 18 +- .../CustomScript/CustomScript.cs | 85 ++++---- .../Notifications/Discord/Discord.cs | 190 ++++++++++++++++++ .../Notifications/Discord/DiscordColors.cs | 9 + .../Notifications/Discord/DiscordException.cs | 16 ++ .../Notifications/Discord/DiscordProxy.cs | 46 +++++ .../Notifications/Discord/DiscordSettings.cs | 35 ++++ .../Discord/Payloads/DiscordPayload.cs | 17 ++ .../Notifications/Discord/Payloads/Embed.cs | 10 + .../Notifications/DownloadFailedMessage.cs | 22 ++ .../Notifications/Email/Email.cs | 18 +- .../Notifications/Growl/Growl.cs | 18 +- .../Notifications/INotification.cs | 14 +- src/NzbDrone.Core/Notifications/Join/Join.cs | 8 +- .../MediaBrowser/MediaBrowser.cs | 21 +- .../Notifications/NotificationBase.cs | 40 +++- .../Notifications/NotificationDefinition.cs | 17 +- .../Notifications/NotificationFactory.cs | 43 +++- .../Notifications/NotificationRepository.cs | 5 +- .../Notifications/NotificationService.cs | 186 +++++++++++------ .../Plex/HomeTheater/PlexClient.cs | 8 +- .../Plex/HomeTheater/PlexHomeTheater.cs | 4 +- .../Notifications/Plex/Server/PlexServer.cs | 10 +- .../Notifications/Prowl/Prowl.cs | 8 +- .../Notifications/PushBullet/PushBullet.cs | 18 +- .../Notifications/Pushover/Pushover.cs | 18 +- .../Notifications/Slack/Slack.cs | 94 ++++++--- .../Notifications/Subsonic/Subsonic.cs | 16 +- .../Notifications/Synology/SynologyIndexer.cs | 10 +- .../Notifications/Telegram/Telegram.cs | 18 +- ...ownloadMessage.cs => TrackRetagMessage.cs} | 9 +- .../Notifications/Twitter/Twitter.cs | 16 +- .../Notifications/Webhook/Webhook.cs | 27 ++- .../Webhook/WebhookImportPayload.cs | 2 +- src/NzbDrone.Core/Notifications/Xbmc/Xbmc.cs | 23 ++- src/NzbDrone.Core/NzbDrone.Core.csproj | 12 +- 52 files changed, 1228 insertions(+), 393 deletions(-) create mode 100644 frontend/src/Settings/Notifications/Notifications/NotificationEventItems.css create mode 100644 frontend/src/Settings/Notifications/Notifications/NotificationEventItems.js rename src/NzbDrone.Core.Test/NotificationTests/Xbmc/{OnDownloadFixture.cs => OnReleaseImportFixture.cs} (72%) create mode 100644 src/NzbDrone.Core/Datastore/Migration/029_health_issue_notification.cs create mode 100644 src/NzbDrone.Core/HealthCheck/HealthCheckFailedEvent.cs create mode 100644 src/NzbDrone.Core/Notifications/Discord/Discord.cs create mode 100644 src/NzbDrone.Core/Notifications/Discord/DiscordColors.cs create mode 100644 src/NzbDrone.Core/Notifications/Discord/DiscordException.cs create mode 100644 src/NzbDrone.Core/Notifications/Discord/DiscordProxy.cs create mode 100644 src/NzbDrone.Core/Notifications/Discord/DiscordSettings.cs create mode 100644 src/NzbDrone.Core/Notifications/Discord/Payloads/DiscordPayload.cs create mode 100644 src/NzbDrone.Core/Notifications/Discord/Payloads/Embed.cs create mode 100644 src/NzbDrone.Core/Notifications/DownloadFailedMessage.cs rename src/NzbDrone.Core/Notifications/{TrackDownloadMessage.cs => TrackRetagMessage.cs} (66%) diff --git a/frontend/src/Settings/Notifications/Notifications/EditNotificationModalContent.js b/frontend/src/Settings/Notifications/Notifications/EditNotificationModalContent.js index ad699532c..c328b77d8 100644 --- a/frontend/src/Settings/Notifications/Notifications/EditNotificationModalContent.js +++ b/frontend/src/Settings/Notifications/Notifications/EditNotificationModalContent.js @@ -14,6 +14,7 @@ import FormGroup from 'Components/Form/FormGroup'; import FormLabel from 'Components/Form/FormLabel'; import FormInputGroup from 'Components/Form/FormInputGroup'; import ProviderFieldFormGroup from 'Components/Form/ProviderFieldFormGroup'; +import NotificationEventItems from './NotificationEventItems'; import styles from './EditNotificationModalContent.css'; function EditNotificationModalContent(props) { @@ -38,16 +39,6 @@ function EditNotificationModalContent(props) { id, implementationName, name, - onGrab, - onDownload, - onAlbumDownload, - onUpgrade, - onRename, - supportsOnGrab, - supportsOnDownload, - supportsOnAlbumDownload, - supportsOnUpgrade, - supportsOnRename, tags, fields, message @@ -94,73 +85,10 @@ function EditNotificationModalContent(props) { /> - - On Grab - - - - - - On Album Import - - - - - - On Track Import - - - - - { - onDownload.value && - - On Track Upgrade - - - - } - - - On Rename - - - + Tags diff --git a/frontend/src/Settings/Notifications/Notifications/Notification.js b/frontend/src/Settings/Notifications/Notifications/Notification.js index 184a71e97..5385ecc45 100644 --- a/frontend/src/Settings/Notifications/Notifications/Notification.js +++ b/frontend/src/Settings/Notifications/Notifications/Notification.js @@ -55,15 +55,21 @@ class Notification extends Component { id, name, onGrab, - onDownload, - onAlbumDownload, + onReleaseImport, onUpgrade, onRename, + onHealthIssue, + onDownloadFailure, + onImportFailure, + onTrackRetag, supportsOnGrab, - supportsOnDownload, - supportsOnAlbumDownload, + supportsOnReleaseImport, supportsOnUpgrade, - supportsOnRename + supportsOnRename, + supportsOnHealthIssue, + supportsOnDownloadFailure, + supportsOnImportFailure, + supportsOnTrackRetag } = this.props; return ( @@ -84,35 +90,57 @@ class Notification extends Component { } { - supportsOnAlbumDownload && onAlbumDownload && + supportsOnReleaseImport && onReleaseImport && } { - supportsOnDownload && onDownload && + supportsOnUpgrade && onReleaseImport && onUpgrade && } { - supportsOnUpgrade && onDownload && onUpgrade && + supportsOnRename && onRename && } { - supportsOnRename && onRename && + supportsOnTrackRetag && onTrackRetag && + } + + { + supportsOnHealthIssue && onHealthIssue && + + } + + { + supportsOnDownloadFailure && onDownloadFailure && + + } + + { + supportsOnImportFailure && onImportFailure && + } { - !onGrab && !onAlbumDownload && !onDownload && !onRename && + !onGrab && !onReleaseImport && !onRename && !onTrackRetag && + !onHealthIssue && !onDownloadFailure && !onImportFailure && + ); +} + +NotificationEventItems.propTypes = { + item: PropTypes.object.isRequired, + onInputChange: PropTypes.func.isRequired +}; + +export default NotificationEventItems; diff --git a/frontend/src/Store/Actions/Settings/notifications.js b/frontend/src/Store/Actions/Settings/notifications.js index b2c28dac9..9a267a930 100644 --- a/frontend/src/Store/Actions/Settings/notifications.js +++ b/frontend/src/Store/Actions/Settings/notifications.js @@ -103,9 +103,13 @@ export default { [SELECT_NOTIFICATION_SCHEMA]: (state, { payload }) => { return selectProviderSchema(state, section, payload, (selectedSchema) => { selectedSchema.onGrab = selectedSchema.supportsOnGrab; - selectedSchema.onDownload = selectedSchema.supportsOnDownload; + selectedSchema.onReleaseImport = selectedSchema.supportsOnReleaseImport; selectedSchema.onUpgrade = selectedSchema.supportsOnUpgrade; selectedSchema.onRename = selectedSchema.supportsOnRename; + selectedSchema.onHealthIssue = selectedSchema.supportsOnHealthIssue; + selectedSchema.onDownloadFailure = selectedSchema.supportsOnDownloadFailure; + selectedSchema.onImportFailure = selectedSchema.supportsOnImportFailure; + selectedSchema.onTrackRetag = selectedSchema.supportsOnTrackRetag; return selectedSchema; }); diff --git a/src/Lidarr.Api.V1/Notifications/NotificationModule.cs b/src/Lidarr.Api.V1/Notifications/NotificationModule.cs index ed1dd2ee6..10e67e3de 100644 --- a/src/Lidarr.Api.V1/Notifications/NotificationModule.cs +++ b/src/Lidarr.Api.V1/Notifications/NotificationModule.cs @@ -13,8 +13,8 @@ namespace Lidarr.Api.V1.Notifications protected override void Validate(NotificationDefinition definition, bool includeWarnings) { - if (!definition.OnGrab && !definition.OnDownload) return; + if (!definition.Enable) return; base.Validate(definition, includeWarnings); } } -} \ No newline at end of file +} diff --git a/src/Lidarr.Api.V1/Notifications/NotificationResource.cs b/src/Lidarr.Api.V1/Notifications/NotificationResource.cs index e66ce1834..95fc55b6c 100644 --- a/src/Lidarr.Api.V1/Notifications/NotificationResource.cs +++ b/src/Lidarr.Api.V1/Notifications/NotificationResource.cs @@ -6,15 +6,22 @@ namespace Lidarr.Api.V1.Notifications { public string Link { get; set; } public bool OnGrab { get; set; } - public bool OnDownload { get; set; } - public bool OnAlbumDownload { get; set; } + public bool OnReleaseImport { get; set; } public bool OnUpgrade { get; set; } public bool OnRename { get; set; } + public bool OnHealthIssue { get; set; } + public bool OnDownloadFailure { get; set; } + public bool OnImportFailure { get; set; } + public bool OnTrackRetag { get; set; } public bool SupportsOnGrab { get; set; } - public bool SupportsOnDownload { get; set; } - public bool SupportsOnAlbumDownload { get; set; } + public bool SupportsOnReleaseImport { get; set; } public bool SupportsOnUpgrade { get; set; } public bool SupportsOnRename { get; set; } + public bool SupportsOnHealthIssue { get; set; } + public bool IncludeHealthWarnings { get; set; } + public bool SupportsOnDownloadFailure { get; set; } + public bool SupportsOnImportFailure { get; set; } + public bool SupportsOnTrackRetag { get; set; } public string TestCommand { get; set; } } @@ -27,15 +34,22 @@ namespace Lidarr.Api.V1.Notifications var resource = base.ToResource(definition); resource.OnGrab = definition.OnGrab; - resource.OnDownload = definition.OnDownload; - resource.OnAlbumDownload = definition.OnAlbumDownload; + resource.OnReleaseImport = definition.OnReleaseImport; resource.OnUpgrade = definition.OnUpgrade; resource.OnRename = definition.OnRename; + resource.OnHealthIssue = definition.OnHealthIssue; + resource.OnDownloadFailure = definition.OnDownloadFailure; + resource.OnImportFailure = definition.OnImportFailure; + resource.OnTrackRetag = definition.OnTrackRetag; resource.SupportsOnGrab = definition.SupportsOnGrab; - resource.SupportsOnDownload = definition.SupportsOnDownload; - resource.SupportsOnAlbumDownload = definition.SupportsOnAlbumDownload; + resource.SupportsOnReleaseImport = definition.SupportsOnReleaseImport; resource.SupportsOnUpgrade = definition.SupportsOnUpgrade; resource.SupportsOnRename = definition.SupportsOnRename; + resource.SupportsOnHealthIssue = definition.SupportsOnHealthIssue; + resource.IncludeHealthWarnings = definition.IncludeHealthWarnings; + resource.SupportsOnDownloadFailure = definition.SupportsOnDownloadFailure; + resource.SupportsOnImportFailure = definition.SupportsOnImportFailure; + resource.SupportsOnTrackRetag = definition.SupportsOnTrackRetag; return resource; } @@ -47,15 +61,22 @@ namespace Lidarr.Api.V1.Notifications var definition = base.ToModel(resource); definition.OnGrab = resource.OnGrab; - definition.OnDownload = resource.OnDownload; - definition.OnAlbumDownload = resource.OnAlbumDownload; + definition.OnReleaseImport = resource.OnReleaseImport; definition.OnUpgrade = resource.OnUpgrade; definition.OnRename = resource.OnRename; + definition.OnHealthIssue = resource.OnHealthIssue; + definition.OnDownloadFailure = resource.OnDownloadFailure; + definition.OnImportFailure = resource.OnImportFailure; + definition.OnTrackRetag = resource.OnTrackRetag; definition.SupportsOnGrab = resource.SupportsOnGrab; - definition.SupportsOnDownload = resource.SupportsOnDownload; - definition.SupportsOnAlbumDownload = resource.SupportsOnAlbumDownload; + definition.SupportsOnReleaseImport = resource.SupportsOnReleaseImport; definition.SupportsOnUpgrade = resource.SupportsOnUpgrade; definition.SupportsOnRename = resource.SupportsOnRename; + definition.SupportsOnHealthIssue = resource.SupportsOnHealthIssue; + definition.IncludeHealthWarnings = resource.IncludeHealthWarnings; + definition.SupportsOnDownloadFailure = resource.SupportsOnDownloadFailure; + definition.SupportsOnImportFailure = resource.SupportsOnImportFailure; + definition.SupportsOnTrackRetag = resource.SupportsOnTrackRetag; return definition; } diff --git a/src/NzbDrone.Core.Test/NotificationTests/NotificationBaseFixture.cs b/src/NzbDrone.Core.Test/NotificationTests/NotificationBaseFixture.cs index 07bb299cd..a7898e103 100644 --- a/src/NzbDrone.Core.Test/NotificationTests/NotificationBaseFixture.cs +++ b/src/NzbDrone.Core.Test/NotificationTests/NotificationBaseFixture.cs @@ -21,7 +21,7 @@ namespace NzbDrone.Core.Test.NotificationTests } } - class TestNotificationWithOnDownload : NotificationBase + class TestNotificationWithOnReleaseImport : NotificationBase { public override string Name => "TestNotification"; public override string Link => ""; @@ -32,7 +32,7 @@ namespace NzbDrone.Core.Test.NotificationTests throw new NotImplementedException(); } - public override void OnDownload(TrackDownloadMessage trackDownloadMessage) + public override void OnReleaseImport(AlbumDownloadMessage message) { TestLogger.Info("OnDownload was called"); } @@ -55,12 +55,7 @@ namespace NzbDrone.Core.Test.NotificationTests TestLogger.Info("OnGrab was called"); } - public override void OnDownload(TrackDownloadMessage message) - { - TestLogger.Info("OnDownload was called"); - } - - public override void OnAlbumDownload(AlbumDownloadMessage message) + public override void OnReleaseImport(AlbumDownloadMessage message) { TestLogger.Info("OnAlbumDownload was called"); } @@ -70,6 +65,25 @@ namespace NzbDrone.Core.Test.NotificationTests TestLogger.Info("OnRename was called"); } + public override void OnHealthIssue(NzbDrone.Core.HealthCheck.HealthCheck artist) + { + TestLogger.Info("OnHealthIssue was called"); + } + + public override void OnDownloadFailure(DownloadFailedMessage message) + { + TestLogger.Info("OnDownloadFailure was called"); + } + + public override void OnImportFailure(AlbumDownloadMessage message) + { + TestLogger.Info("OnImportFailure was called"); + } + + public override void OnTrackRetag(TrackRetagMessage message) + { + TestLogger.Info("OnTrackRetag was called"); + } } class TestNotificationWithNoEvents : NotificationBase @@ -87,11 +101,11 @@ namespace NzbDrone.Core.Test.NotificationTests } [Test] - public void should_support_OnUpgrade_should_link_to_OnDownload() + public void should_support_OnUpgrade_should_link_to_OnReleaseImport() { - var notification = new TestNotificationWithOnDownload(); + var notification = new TestNotificationWithOnReleaseImport(); - notification.SupportsOnDownload.Should().BeTrue(); + notification.SupportsOnReleaseImport.Should().BeTrue(); notification.SupportsOnUpgrade.Should().BeTrue(); notification.SupportsOnGrab.Should().BeFalse(); @@ -104,10 +118,13 @@ namespace NzbDrone.Core.Test.NotificationTests var notification = new TestNotificationWithAllEvents(); notification.SupportsOnGrab.Should().BeTrue(); - notification.SupportsOnDownload.Should().BeTrue(); - notification.SupportsOnAlbumDownload.Should().BeTrue(); + notification.SupportsOnReleaseImport.Should().BeTrue(); notification.SupportsOnUpgrade.Should().BeTrue(); notification.SupportsOnRename.Should().BeTrue(); + notification.SupportsOnHealthIssue.Should().BeTrue(); + notification.SupportsOnDownloadFailure.Should().BeTrue(); + notification.SupportsOnImportFailure.Should().BeTrue(); + notification.SupportsOnTrackRetag.Should().BeTrue(); } @@ -117,10 +134,13 @@ namespace NzbDrone.Core.Test.NotificationTests var notification = new TestNotificationWithNoEvents(); notification.SupportsOnGrab.Should().BeFalse(); - notification.SupportsOnDownload.Should().BeFalse(); - notification.SupportsOnAlbumDownload.Should().BeFalse(); + notification.SupportsOnReleaseImport.Should().BeFalse(); notification.SupportsOnUpgrade.Should().BeFalse(); notification.SupportsOnRename.Should().BeFalse(); + notification.SupportsOnHealthIssue.Should().BeFalse(); + notification.SupportsOnDownloadFailure.Should().BeFalse(); + notification.SupportsOnImportFailure.Should().BeFalse(); + notification.SupportsOnTrackRetag.Should().BeFalse(); } } diff --git a/src/NzbDrone.Core.Test/NotificationTests/SynologyIndexerFixture.cs b/src/NzbDrone.Core.Test/NotificationTests/SynologyIndexerFixture.cs index 9c834b36b..d80090859 100644 --- a/src/NzbDrone.Core.Test/NotificationTests/SynologyIndexerFixture.cs +++ b/src/NzbDrone.Core.Test/NotificationTests/SynologyIndexerFixture.cs @@ -73,7 +73,7 @@ namespace NzbDrone.Core.Test.NotificationTests [Test] public void should_remove_old_episodes_on_upgrade() { - Subject.OnAlbumDownload(_upgrade); + Subject.OnReleaseImport(_upgrade); Mocker.GetMock() .Verify(v => v.DeleteFile(@"C:\Test\file1.S01E01.mkv".AsOsAgnostic()), Times.Once()); @@ -85,7 +85,7 @@ namespace NzbDrone.Core.Test.NotificationTests [Test] public void should_add_new_episode_on_upgrade() { - Subject.OnAlbumDownload(_upgrade); + Subject.OnReleaseImport(_upgrade); Mocker.GetMock() .Verify(v => v.AddFile(@"C:\Test\file1.S01E01E02.mkv".AsOsAgnostic()), Times.Once()); diff --git a/src/NzbDrone.Core.Test/NotificationTests/Xbmc/Json/UpdateFixture.cs b/src/NzbDrone.Core.Test/NotificationTests/Xbmc/Json/UpdateFixture.cs index 32d247242..7dfc9ee1b 100644 --- a/src/NzbDrone.Core.Test/NotificationTests/Xbmc/Json/UpdateFixture.cs +++ b/src/NzbDrone.Core.Test/NotificationTests/Xbmc/Json/UpdateFixture.cs @@ -24,10 +24,12 @@ namespace NzbDrone.Core.Test.NotificationTests.Xbmc.Json .Build(); _xbmcArtist = Builder.CreateListOfSize(3) - .TheFirst(1) - .With(s => s.MusicbrainzArtistId = new List { MB_ID.ToString()}) - .Build() - .ToList(); + .TheFirst(1) + .With(s => s.MusicbrainzArtistId = new List { MB_ID.ToString()}) + .TheNext(2) + .With(s => s.MusicbrainzArtistId = new List()) + .Build() + .ToList(); Mocker.GetMock() .Setup(s => s.GetArtist(_settings)) diff --git a/src/NzbDrone.Core.Test/NotificationTests/Xbmc/OnDownloadFixture.cs b/src/NzbDrone.Core.Test/NotificationTests/Xbmc/OnReleaseImportFixture.cs similarity index 72% rename from src/NzbDrone.Core.Test/NotificationTests/Xbmc/OnDownloadFixture.cs rename to src/NzbDrone.Core.Test/NotificationTests/Xbmc/OnReleaseImportFixture.cs index ae0dc8efb..56b80b878 100644 --- a/src/NzbDrone.Core.Test/NotificationTests/Xbmc/OnDownloadFixture.cs +++ b/src/NzbDrone.Core.Test/NotificationTests/Xbmc/OnReleaseImportFixture.cs @@ -12,9 +12,9 @@ using NzbDrone.Core.Music; namespace NzbDrone.Core.Test.NotificationTests.Xbmc { [TestFixture] - public class OnDownloadFixture : CoreTest + public class OnReleaseImportFixture : CoreTest { - private TrackDownloadMessage _trackDownloadMessage; + private AlbumDownloadMessage _albumDownloadMessage; [SetUp] public void Setup() @@ -25,11 +25,11 @@ namespace NzbDrone.Core.Test.NotificationTests.Xbmc var trackFile = Builder.CreateNew() .Build(); - _trackDownloadMessage = Builder.CreateNew() - .With(d => d.Artist = artist) - .With(d => d.TrackFile = trackFile) - .With(d => d.OldFiles = new List()) - .Build(); + _albumDownloadMessage = Builder.CreateNew() + .With(d => d.Artist = artist) + .With(d => d.TrackFiles = new List { trackFile }) + .With(d => d.OldFiles = new List()) + .Build(); Subject.Definition = new NotificationDefinition(); Subject.Definition.Settings = new XbmcSettings @@ -40,7 +40,7 @@ namespace NzbDrone.Core.Test.NotificationTests.Xbmc private void GivenOldFiles() { - _trackDownloadMessage.OldFiles = Builder.CreateListOfSize(1) + _albumDownloadMessage.OldFiles = Builder.CreateListOfSize(1) .Build() .ToList(); @@ -54,7 +54,7 @@ namespace NzbDrone.Core.Test.NotificationTests.Xbmc [Test] public void should_not_clean_if_no_episode_was_replaced() { - Subject.OnDownload(_trackDownloadMessage); + Subject.OnReleaseImport(_albumDownloadMessage); Mocker.GetMock().Verify(v => v.Clean(It.IsAny()), Times.Never()); } @@ -63,7 +63,7 @@ namespace NzbDrone.Core.Test.NotificationTests.Xbmc public void should_clean_if_episode_was_replaced() { GivenOldFiles(); - Subject.OnDownload(_trackDownloadMessage); + Subject.OnReleaseImport(_albumDownloadMessage); Mocker.GetMock().Verify(v => v.Clean(It.IsAny()), Times.Once()); } diff --git a/src/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj b/src/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj index d76b32a14..11b1045e4 100644 --- a/src/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj +++ b/src/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj @@ -357,7 +357,7 @@ - + diff --git a/src/NzbDrone.Core/Datastore/Migration/029_health_issue_notification.cs b/src/NzbDrone.Core/Datastore/Migration/029_health_issue_notification.cs new file mode 100644 index 000000000..9456f8544 --- /dev/null +++ b/src/NzbDrone.Core/Datastore/Migration/029_health_issue_notification.cs @@ -0,0 +1,23 @@ +using FluentMigrator; + +using NzbDrone.Core.Datastore.Migration.Framework; + +namespace NzbDrone.Core.Datastore.Migration +{ + [Migration(29)] + public class health_issue_notification : NzbDroneMigrationBase + { + protected override void MainDbUpgrade() + { + Alter.Table("Notifications").AddColumn("OnHealthIssue").AsBoolean().WithDefaultValue(0); + Alter.Table("Notifications").AddColumn("IncludeHealthWarnings").AsBoolean().WithDefaultValue(0); + Alter.Table("Notifications").AddColumn("OnDownloadFailure").AsBoolean().WithDefaultValue(0); + Alter.Table("Notifications").AddColumn("OnImportFailure").AsBoolean().WithDefaultValue(0); + Alter.Table("Notifications").AddColumn("OnTrackRetag").AsBoolean().WithDefaultValue(0); + + Delete.Column("OnDownload").FromTable("Notifications"); + + Rename.Column("OnAlbumDownload").OnTable("Notifications").To("OnReleaseImport"); + } + } +} diff --git a/src/NzbDrone.Core/Datastore/TableMapping.cs b/src/NzbDrone.Core/Datastore/TableMapping.cs index 23060b636..f2eab0ca2 100644 --- a/src/NzbDrone.Core/Datastore/TableMapping.cs +++ b/src/NzbDrone.Core/Datastore/TableMapping.cs @@ -30,7 +30,6 @@ using NzbDrone.Core.ArtistStats; using NzbDrone.Core.Tags; using NzbDrone.Core.ThingiProvider; using NzbDrone.Common.Disk; -using NzbDrone.Common.Serializer; using NzbDrone.Core.Authentication; using NzbDrone.Core.CustomFilters; using NzbDrone.Core.Extras.Metadata; @@ -73,10 +72,13 @@ namespace NzbDrone.Core.Datastore Mapper.Entity().RegisterDefinition("Notifications") .Ignore(i => i.SupportsOnGrab) - .Ignore(i => i.SupportsOnDownload) - .Ignore(i => i.SupportsOnAlbumDownload) + .Ignore(i => i.SupportsOnReleaseImport) .Ignore(i => i.SupportsOnUpgrade) - .Ignore(i => i.SupportsOnRename); + .Ignore(i => i.SupportsOnRename) + .Ignore(i => i.SupportsOnHealthIssue) + .Ignore(i => i.SupportsOnDownloadFailure) + .Ignore(i => i.SupportsOnImportFailure) + .Ignore(i => i.SupportsOnTrackRetag); Mapper.Entity().RegisterDefinition("Metadata") .Ignore(d => d.Tags); diff --git a/src/NzbDrone.Core/HealthCheck/HealthCheckFailedEvent.cs b/src/NzbDrone.Core/HealthCheck/HealthCheckFailedEvent.cs new file mode 100644 index 000000000..1fc2af1a9 --- /dev/null +++ b/src/NzbDrone.Core/HealthCheck/HealthCheckFailedEvent.cs @@ -0,0 +1,14 @@ +using NzbDrone.Common.Messaging; + +namespace NzbDrone.Core.HealthCheck +{ + public class HealthCheckFailedEvent : IEvent + { + public HealthCheck HealthCheck { get; private set; } + + public HealthCheckFailedEvent(HealthCheck healthCheck) + { + HealthCheck = healthCheck; + } + } +} diff --git a/src/NzbDrone.Core/HealthCheck/HealthCheckService.cs b/src/NzbDrone.Core/HealthCheck/HealthCheckService.cs index f49caa498..5ab1c5416 100644 --- a/src/NzbDrone.Core/HealthCheck/HealthCheckService.cs +++ b/src/NzbDrone.Core/HealthCheck/HealthCheckService.cs @@ -80,7 +80,13 @@ namespace NzbDrone.Core.HealthCheck else { + if (_healthCheckResults.Find(result.Source.Name) == null) + { + _eventAggregator.PublishEvent(new HealthCheckFailedEvent(result)); + } + _healthCheckResults.Set(result.Source.Name, result); + } } diff --git a/src/NzbDrone.Core/Notifications/Boxcar/Boxcar.cs b/src/NzbDrone.Core/Notifications/Boxcar/Boxcar.cs index 97a98e632..f493c7f96 100644 --- a/src/NzbDrone.Core/Notifications/Boxcar/Boxcar.cs +++ b/src/NzbDrone.Core/Notifications/Boxcar/Boxcar.cs @@ -21,14 +21,24 @@ namespace NzbDrone.Core.Notifications.Boxcar _proxy.SendNotification(ALBUM_GRABBED_TITLE, grabMessage.Message, Settings); } - public override void OnDownload(TrackDownloadMessage message) + public override void OnReleaseImport(AlbumDownloadMessage message) { - _proxy.SendNotification(TRACK_DOWNLOADED_TITLE , message.Message, Settings); + _proxy.SendNotification(ALBUM_DOWNLOADED_TITLE, message.Message, Settings); } - public override void OnAlbumDownload(AlbumDownloadMessage message) + public override void OnHealthIssue(HealthCheck.HealthCheck message) { - _proxy.SendNotification(TRACK_DOWNLOADED_TITLE, message.Message, Settings); + _proxy.SendNotification(HEALTH_ISSUE_TITLE, message.Message, Settings); + } + + public override void OnDownloadFailure(DownloadFailedMessage message) + { + _proxy.SendNotification(DOWNLOAD_FAILURE_TITLE, message.Message, Settings); + } + + public override void OnImportFailure(AlbumDownloadMessage message) + { + _proxy.SendNotification(IMPORT_FAILURE_TITLE, message.Message, Settings); } public override ValidationResult Test() diff --git a/src/NzbDrone.Core/Notifications/CustomScript/CustomScript.cs b/src/NzbDrone.Core/Notifications/CustomScript/CustomScript.cs index a902feef3..e78f63811 100644 --- a/src/NzbDrone.Core/Notifications/CustomScript/CustomScript.cs +++ b/src/NzbDrone.Core/Notifications/CustomScript/CustomScript.cs @@ -6,6 +6,7 @@ using FluentValidation.Results; using NLog; using NzbDrone.Common.Disk; using NzbDrone.Common.Processes; +using NzbDrone.Common.Serializer; using NzbDrone.Core.Music; using NzbDrone.Core.Validation; @@ -55,17 +56,14 @@ namespace NzbDrone.Core.Notifications.CustomScript ExecuteScript(environmentVariables); } - public override void OnDownload(TrackDownloadMessage message) + public override void OnReleaseImport(AlbumDownloadMessage message) { var artist = message.Artist; var album = message.Album; var release = message.Release; - var trackFile = message.TrackFile; - var sourcePath = message.SourcePath; var environmentVariables = new StringDictionary(); - environmentVariables.Add("Lidarr_EventType", "Download"); - environmentVariables.Add("Lidarr_IsUpgrade", message.OldFiles.Any().ToString()); + environmentVariables.Add("Lidarr_EventType", "AlbumDownload"); environmentVariables.Add("Lidarr_Artist_Id", artist.Id.ToString()); environmentVariables.Add("Lidarr_Artist_Name", artist.Metadata.Value.Name); environmentVariables.Add("Lidarr_Artist_Path", artist.Path); @@ -76,21 +74,15 @@ namespace NzbDrone.Core.Notifications.CustomScript environmentVariables.Add("Lidarr_Album_MBId", album.ForeignAlbumId); environmentVariables.Add("Lidarr_AlbumRelease_MBId", release.ForeignReleaseId); environmentVariables.Add("Lidarr_Album_ReleaseDate", album.ReleaseDate.ToString()); - environmentVariables.Add("Lidarr_TrackFile_Id", trackFile.Id.ToString()); - environmentVariables.Add("Lidarr_TrackFile_TrackCount", trackFile.Tracks.Value.Count.ToString()); - environmentVariables.Add("Lidarr_TrackFile_RelativePath", trackFile.RelativePath); - environmentVariables.Add("Lidarr_TrackFile_Path", Path.Combine(artist.Path, trackFile.RelativePath)); - environmentVariables.Add("Lidarr_TrackFile_TrackNumbers", string.Join(",", trackFile.Tracks.Value.Select(e => e.TrackNumber))); - environmentVariables.Add("Lidarr_TrackFile_TrackTitles", string.Join("|", trackFile.Tracks.Value.Select(e => e.Title))); - environmentVariables.Add("Lidarr_TrackFile_Quality", trackFile.Quality.Quality.Name); - environmentVariables.Add("Lidarr_TrackFile_QualityVersion", trackFile.Quality.Revision.Version.ToString()); - environmentVariables.Add("Lidarr_TrackFile_ReleaseGroup", trackFile.ReleaseGroup ?? string.Empty); - environmentVariables.Add("Lidarr_TrackFile_SceneName", trackFile.SceneName ?? string.Empty); - environmentVariables.Add("Lidarr_TrackFile_SourcePath", sourcePath); - environmentVariables.Add("Lidarr_TrackFile_SourceFolder", Path.GetDirectoryName(sourcePath)); environmentVariables.Add("Lidarr_Download_Client", message.DownloadClient ?? string.Empty); environmentVariables.Add("Lidarr_Download_Id", message.DownloadId ?? string.Empty); + if (message.TrackFiles.Any()) + { + environmentVariables.Add("Lidarr_AddedTrackRelativePaths", string.Join("|", message.TrackFiles.Select(e => e.RelativePath))); + environmentVariables.Add("Lidarr_AddedTrackPaths", string.Join("|", message.TrackFiles.Select(e => Path.Combine(artist.Path, e.RelativePath)))); + } + if (message.OldFiles.Any()) { environmentVariables.Add("Lidarr_DeletedRelativePaths", string.Join("|", message.OldFiles.Select(e => e.RelativePath))); @@ -100,14 +92,29 @@ namespace NzbDrone.Core.Notifications.CustomScript ExecuteScript(environmentVariables); } - public override void OnAlbumDownload(AlbumDownloadMessage message) + public override void OnRename(Artist artist) + { + var environmentVariables = new StringDictionary(); + + environmentVariables.Add("Lidarr_EventType", "Rename"); + environmentVariables.Add("Lidarr_Artist_Id", artist.Id.ToString()); + environmentVariables.Add("Lidarr_Artist_Name", artist.Metadata.Value.Name); + environmentVariables.Add("Lidarr_Artist_Path", artist.Path); + environmentVariables.Add("Lidarr_Artist_MBId", artist.Metadata.Value.ForeignArtistId); + environmentVariables.Add("Lidarr_Artist_Type", artist.Metadata.Value.Type); + + ExecuteScript(environmentVariables); + } + + public override void OnTrackRetag(TrackRetagMessage message) { var artist = message.Artist; var album = message.Album; var release = message.Release; + var trackFile = message.TrackFile; var environmentVariables = new StringDictionary(); - environmentVariables.Add("Lidarr_EventType", "AlbumDownload"); + environmentVariables.Add("Lidarr_EventType", "TrackRetag"); environmentVariables.Add("Lidarr_Artist_Id", artist.Id.ToString()); environmentVariables.Add("Lidarr_Artist_Name", artist.Metadata.Value.Name); environmentVariables.Add("Lidarr_Artist_Path", artist.Path); @@ -118,39 +125,35 @@ namespace NzbDrone.Core.Notifications.CustomScript environmentVariables.Add("Lidarr_Album_MBId", album.ForeignAlbumId); environmentVariables.Add("Lidarr_AlbumRelease_MBId", release.ForeignReleaseId); environmentVariables.Add("Lidarr_Album_ReleaseDate", album.ReleaseDate.ToString()); - environmentVariables.Add("Lidarr_Download_Client", message.DownloadClient ?? string.Empty); - environmentVariables.Add("Lidarr_Download_Id", message.DownloadId ?? string.Empty); - - if (message.TrackFiles.Any()) - { - environmentVariables.Add("Lidarr_AddedTrackRelativePaths", string.Join("|", message.TrackFiles.Select(e => e.RelativePath))); - environmentVariables.Add("Lidarr_AddedTrackPaths", string.Join("|", message.TrackFiles.Select(e => Path.Combine(artist.Path, e.RelativePath)))); - } - - if (message.OldFiles.Any()) - { - environmentVariables.Add("Lidarr_DeletedRelativePaths", string.Join("|", message.OldFiles.Select(e => e.RelativePath))); - environmentVariables.Add("Lidarr_DeletedPaths", string.Join("|", message.OldFiles.Select(e => Path.Combine(artist.Path, e.RelativePath)))); - } + environmentVariables.Add("Lidarr_TrackFile_Id", trackFile.Id.ToString()); + environmentVariables.Add("Lidarr_TrackFile_TrackCount", trackFile.Tracks.Value.Count.ToString()); + environmentVariables.Add("Lidarr_TrackFile_RelativePath", trackFile.RelativePath); + environmentVariables.Add("Lidarr_TrackFile_Path", Path.Combine(artist.Path, trackFile.RelativePath)); + environmentVariables.Add("Lidarr_TrackFile_TrackNumbers", string.Join(",", trackFile.Tracks.Value.Select(e => e.TrackNumber))); + environmentVariables.Add("Lidarr_TrackFile_TrackTitles", string.Join("|", trackFile.Tracks.Value.Select(e => e.Title))); + environmentVariables.Add("Lidarr_TrackFile_Quality", trackFile.Quality.Quality.Name); + environmentVariables.Add("Lidarr_TrackFile_QualityVersion", trackFile.Quality.Revision.Version.ToString()); + environmentVariables.Add("Lidarr_TrackFile_ReleaseGroup", trackFile.ReleaseGroup ?? string.Empty); + environmentVariables.Add("Lidarr_TrackFile_SceneName", trackFile.SceneName ?? string.Empty); + environmentVariables.Add("Lidarr_Tags_Diff", message.Diff.ToJson()); + environmentVariables.Add("Lidarr_Tags_Scrubbed", message.Scrubbed.ToString()); ExecuteScript(environmentVariables); } - public override void OnRename(Artist artist) + public override void OnHealthIssue(HealthCheck.HealthCheck healthCheck) { var environmentVariables = new StringDictionary(); - environmentVariables.Add("Lidarr_EventType", "Rename"); - environmentVariables.Add("Lidarr_Artist_Id", artist.Id.ToString()); - environmentVariables.Add("Lidarr_Artist_Name", artist.Metadata.Value.Name); - environmentVariables.Add("Lidarr_Artist_Path", artist.Path); - environmentVariables.Add("Lidarr_Artist_MBId", artist.Metadata.Value.ForeignArtistId); - environmentVariables.Add("Lidarr_Artist_Type", artist.Metadata.Value.Type); + environmentVariables.Add("Lidarr_EventType", "HealthIssue"); + environmentVariables.Add("Lidarr_Health_Issue_Level", nameof(healthCheck.Type)); + environmentVariables.Add("Lidarr_Health_Issue_Message", healthCheck.Message); + environmentVariables.Add("Lidarr_Health_Issue_Type", healthCheck.Source.Name); + environmentVariables.Add("Lidarr_Health_Issue_Wiki", healthCheck.WikiUrl.ToString() ?? string.Empty); ExecuteScript(environmentVariables); } - public override ValidationResult Test() { var failures = new List(); diff --git a/src/NzbDrone.Core/Notifications/Discord/Discord.cs b/src/NzbDrone.Core/Notifications/Discord/Discord.cs new file mode 100644 index 000000000..42a5a5729 --- /dev/null +++ b/src/NzbDrone.Core/Notifications/Discord/Discord.cs @@ -0,0 +1,190 @@ +using System; +using System.Collections.Generic; +using FluentValidation.Results; +using NzbDrone.Common.Extensions; +using NzbDrone.Core.Notifications.Discord.Payloads; +using NzbDrone.Core.Music; +using NzbDrone.Core.Validation; + +namespace NzbDrone.Core.Notifications.Discord +{ + public class Discord : NotificationBase + { + private readonly IDiscordProxy _proxy; + + public Discord(IDiscordProxy proxy) + { + _proxy = proxy; + } + + public override string Name => "Discord"; + public override string Link => "https://support.discordapp.com/hc/en-us/articles/228383668-Intro-to-Webhooks"; + + public override void OnGrab(GrabMessage message) + { + var embeds = new List + { + new Embed + { + Description = message.Message, + Title = message.Artist.Name, + Text = message.Message, + Color = (int)DiscordColors.Warning + } + }; + var payload = CreatePayload($"Grabbed: {message.Message}", embeds); + + _proxy.SendPayload(payload, Settings); + } + + public override void OnReleaseImport(AlbumDownloadMessage message) + { + var attachments = new List + { + new Embed + { + Description = message.Message, + Title = message.Artist.Name, + Text = message.Message, + Color = (int)DiscordColors.Success + } + }; + var payload = CreatePayload($"Imported: {message.Message}", attachments); + + _proxy.SendPayload(payload, Settings); + } + + public override void OnRename(Artist artist) + { + var attachments = new List + { + new Embed + { + Title = artist.Name, + } + }; + + var payload = CreatePayload("Renamed", attachments); + + _proxy.SendPayload(payload, Settings); + } + + public override void OnHealthIssue(HealthCheck.HealthCheck healthCheck) + { + var attachments = new List + { + new Embed + { + Title = healthCheck.Source.Name, + Text = healthCheck.Message, + Color = healthCheck.Type == HealthCheck.HealthCheckResult.Warning ? (int)DiscordColors.Warning : (int)DiscordColors.Danger + } + }; + + var payload = CreatePayload("Health Issue", attachments); + + _proxy.SendPayload(payload, Settings); + } + + public override void OnTrackRetag(TrackRetagMessage message) + { + var attachments = new List + { + new Embed + { + Title = TRACK_RETAGGED_TITLE, + Text = message.Message + } + }; + + var payload = CreatePayload($"Track file tags updated: {message.Message}", attachments); + + _proxy.SendPayload(payload, Settings); + } + + public override void OnDownloadFailure(DownloadFailedMessage message) + { + var attachments = new List + { + new Embed + { + Description = message.Message, + Title = message.SourceTitle, + Text = message.Message, + Color = (int)DiscordColors.Danger + } + }; + var payload = CreatePayload($"Download Failed: {message.Message}", attachments); + + _proxy.SendPayload(payload, Settings); + } + + public override void OnImportFailure(AlbumDownloadMessage message) + { + var attachments = new List + { + new Embed + { + Description = message.Message, + Title = message.Album.Title, + Text = message.Message, + Color = (int)DiscordColors.Warning + } + }; + var payload = CreatePayload($"Import Failed: {message.Message}", attachments); + + _proxy.SendPayload(payload, Settings); + } + + public override ValidationResult Test() + { + var failures = new List(); + + failures.AddIfNotNull(TestMessage()); + + return new ValidationResult(failures); + } + + public ValidationFailure TestMessage() + { + try + { + var message = $"Test message from Lidarr posted at {DateTime.Now}"; + var payload = CreatePayload(message); + + _proxy.SendPayload(payload, Settings); + + } + catch (DiscordException ex) + { + return new NzbDroneValidationFailure("Unable to post", ex.Message); + } + + return null; + } + + private DiscordPayload CreatePayload(string message, List embeds = null) + { + var avatar = Settings.Avatar; + + var payload = new DiscordPayload + { + Username = Settings.Username, + Content = message, + Embeds = embeds + }; + + if (avatar.IsNotNullOrWhiteSpace()) + { + payload.AvatarUrl = avatar; + } + + if (Settings.Username.IsNotNullOrWhiteSpace()) + { + payload.Username = Settings.Username; + } + + return payload; + } + } +} diff --git a/src/NzbDrone.Core/Notifications/Discord/DiscordColors.cs b/src/NzbDrone.Core/Notifications/Discord/DiscordColors.cs new file mode 100644 index 000000000..16590aade --- /dev/null +++ b/src/NzbDrone.Core/Notifications/Discord/DiscordColors.cs @@ -0,0 +1,9 @@ +namespace NzbDrone.Core.Notifications.Discord +{ + public enum DiscordColors + { + Danger = 15749200, + Success = 2605644, + Warning = 16753920 + } +} diff --git a/src/NzbDrone.Core/Notifications/Discord/DiscordException.cs b/src/NzbDrone.Core/Notifications/Discord/DiscordException.cs new file mode 100644 index 000000000..1bc0d6294 --- /dev/null +++ b/src/NzbDrone.Core/Notifications/Discord/DiscordException.cs @@ -0,0 +1,16 @@ +using System; +using NzbDrone.Common.Exceptions; + +namespace NzbDrone.Core.Notifications.Discord +{ + class DiscordException : NzbDroneException + { + public DiscordException(string message) : base(message) + { + } + + public DiscordException(string message, Exception innerException, params object[] args) : base(message, innerException, args) + { + } + } +} diff --git a/src/NzbDrone.Core/Notifications/Discord/DiscordProxy.cs b/src/NzbDrone.Core/Notifications/Discord/DiscordProxy.cs new file mode 100644 index 000000000..425364253 --- /dev/null +++ b/src/NzbDrone.Core/Notifications/Discord/DiscordProxy.cs @@ -0,0 +1,46 @@ +using NLog; +using NzbDrone.Common.Http; +using NzbDrone.Common.Serializer; +using NzbDrone.Core.Notifications.Discord.Payloads; +using NzbDrone.Core.Rest; + +namespace NzbDrone.Core.Notifications.Discord +{ + public interface IDiscordProxy + { + void SendPayload(DiscordPayload payload, DiscordSettings settings); + } + + public class DiscordProxy : IDiscordProxy + { + private readonly IHttpClient _httpClient; + private readonly Logger _logger; + + public DiscordProxy(IHttpClient httpClient, Logger logger) + { + _httpClient = httpClient; + _logger = logger; + } + + public void SendPayload(DiscordPayload payload, DiscordSettings settings) + { + try + { + var request = new HttpRequestBuilder(settings.WebHookUrl) + .Accept(HttpAccept.Json) + .Build(); + + request.Method = HttpMethod.POST; + request.Headers.ContentType = "application/json"; + request.SetContent(payload.ToJson()); + + _httpClient.Execute(request); + } + catch (RestException ex) + { + _logger.Error(ex, "Unable to post payload {0}", payload); + throw new DiscordException("Unable to post payload", ex); + } + } + } +} diff --git a/src/NzbDrone.Core/Notifications/Discord/DiscordSettings.cs b/src/NzbDrone.Core/Notifications/Discord/DiscordSettings.cs new file mode 100644 index 000000000..e4ba51571 --- /dev/null +++ b/src/NzbDrone.Core/Notifications/Discord/DiscordSettings.cs @@ -0,0 +1,35 @@ +using FluentValidation; +using NzbDrone.Core.Annotations; +using NzbDrone.Core.ThingiProvider; +using NzbDrone.Core.Validation; + +namespace NzbDrone.Core.Notifications.Discord +{ + public class DiscordSettingsValidator : AbstractValidator + { + public DiscordSettingsValidator() + { + RuleFor(c => c.WebHookUrl).IsValidUrl(); + } + } + + public class DiscordSettings : IProviderConfig + { + private static readonly DiscordSettingsValidator Validator = new DiscordSettingsValidator(); + + [FieldDefinition(0, Label = "Webhook URL", HelpText = "Discord channel webhook url")] + public string WebHookUrl { get; set; } + + [FieldDefinition(1, Label = "Username", HelpText = "The username to post as, defaults to Discord webhook default")] + public string Username { get; set; } + + [FieldDefinition(2, Label = "Avatar", HelpText = "Change the avatar that is used for messages from this integration", Type = FieldType.Textbox)] + public string Avatar { get; set; } + + + public NzbDroneValidationResult Validate() + { + return new NzbDroneValidationResult(Validator.Validate(this)); + } + } +} diff --git a/src/NzbDrone.Core/Notifications/Discord/Payloads/DiscordPayload.cs b/src/NzbDrone.Core/Notifications/Discord/Payloads/DiscordPayload.cs new file mode 100644 index 000000000..37f1f1c3d --- /dev/null +++ b/src/NzbDrone.Core/Notifications/Discord/Payloads/DiscordPayload.cs @@ -0,0 +1,17 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace NzbDrone.Core.Notifications.Discord.Payloads +{ + public class DiscordPayload + { + public string Content { get; set; } + + public string Username { get; set; } + + [JsonProperty("avatar_url")] + public string AvatarUrl { get; set; } + + public List Embeds { get; set; } + } +} diff --git a/src/NzbDrone.Core/Notifications/Discord/Payloads/Embed.cs b/src/NzbDrone.Core/Notifications/Discord/Payloads/Embed.cs new file mode 100644 index 000000000..50e27914b --- /dev/null +++ b/src/NzbDrone.Core/Notifications/Discord/Payloads/Embed.cs @@ -0,0 +1,10 @@ +namespace NzbDrone.Core.Notifications.Discord.Payloads +{ + public class Embed + { + public string Description { get; set; } + public string Title { get; set; } + public string Text { get; set; } + public int Color { get; set; } + } +} diff --git a/src/NzbDrone.Core/Notifications/DownloadFailedMessage.cs b/src/NzbDrone.Core/Notifications/DownloadFailedMessage.cs new file mode 100644 index 000000000..3bae0e1f3 --- /dev/null +++ b/src/NzbDrone.Core/Notifications/DownloadFailedMessage.cs @@ -0,0 +1,22 @@ +using NzbDrone.Core.Parser.Model; +using NzbDrone.Core.Qualities; +using NzbDrone.Core.Music; +using NzbDrone.Core.Languages; + +namespace NzbDrone.Core.Notifications +{ + public class DownloadFailedMessage + { + public string Message { get; set; } + public string SourceTitle { get; set; } + public QualityModel Quality { get; set; } + public Language Language { get; set; } + public string DownloadClient { get; set; } + public string DownloadId { get; set; } + + public override string ToString() + { + return Message; + } + } +} diff --git a/src/NzbDrone.Core/Notifications/Email/Email.cs b/src/NzbDrone.Core/Notifications/Email/Email.cs index b43cb8bf4..3ecc2f11a 100644 --- a/src/NzbDrone.Core/Notifications/Email/Email.cs +++ b/src/NzbDrone.Core/Notifications/Email/Email.cs @@ -25,18 +25,26 @@ namespace NzbDrone.Core.Notifications.Email _emailService.SendEmail(Settings, ALBUM_GRABBED_TITLE_BRANDED, body); } - public override void OnDownload(TrackDownloadMessage message) + public override void OnReleaseImport(AlbumDownloadMessage message) { var body = $"{message.Message} Downloaded and sorted."; - _emailService.SendEmail(Settings, TRACK_DOWNLOADED_TITLE_BRANDED, body); + _emailService.SendEmail(Settings, ALBUM_DOWNLOADED_TITLE_BRANDED, body); } - public override void OnAlbumDownload(AlbumDownloadMessage message) + public override void OnHealthIssue(HealthCheck.HealthCheck message) { - var body = $"{message.Message} Downloaded and sorted."; + _emailService.SendEmail(Settings, HEALTH_ISSUE_TITLE_BRANDED, message.Message); + } - _emailService.SendEmail(Settings, ALBUM_DOWNLOADED_TITLE_BRANDED, body); + public override void OnDownloadFailure(DownloadFailedMessage message) + { + _emailService.SendEmail(Settings, DOWNLOAD_FAILURE_TITLE_BRANDED, message.Message); + } + + public override void OnImportFailure(AlbumDownloadMessage message) + { + _emailService.SendEmail(Settings, IMPORT_FAILURE_TITLE_BRANDED, message.Message); } public override ValidationResult Test() diff --git a/src/NzbDrone.Core/Notifications/Growl/Growl.cs b/src/NzbDrone.Core/Notifications/Growl/Growl.cs index 3f6ff6f9f..6ae211cee 100644 --- a/src/NzbDrone.Core/Notifications/Growl/Growl.cs +++ b/src/NzbDrone.Core/Notifications/Growl/Growl.cs @@ -23,14 +23,24 @@ namespace NzbDrone.Core.Notifications.Growl _growlService.SendNotification(ALBUM_GRABBED_TITLE, grabMessage.Message, "GRAB", Settings.Host, Settings.Port, Settings.Password); } - public override void OnDownload(TrackDownloadMessage message) + public override void OnReleaseImport(AlbumDownloadMessage message) { - _growlService.SendNotification(TRACK_DOWNLOADED_TITLE, message.Message, "TRACKDOWNLOAD", Settings.Host, Settings.Port, Settings.Password); + _growlService.SendNotification(ALBUM_DOWNLOADED_TITLE, message.Message, "ALBUMDOWNLOAD", Settings.Host, Settings.Port, Settings.Password); } - public override void OnAlbumDownload(AlbumDownloadMessage message) + public override void OnHealthIssue(HealthCheck.HealthCheck message) { - _growlService.SendNotification(ALBUM_DOWNLOADED_TITLE, message.Message, "ALBUMDOWNLOAD", Settings.Host, Settings.Port, Settings.Password); + _growlService.SendNotification(HEALTH_ISSUE_TITLE, message.Message, "HEALTHISSUE", Settings.Host, Settings.Port, Settings.Password); + } + + public override void OnDownloadFailure(DownloadFailedMessage message) + { + _growlService.SendNotification(DOWNLOAD_FAILURE_TITLE, message.Message, "DOWNLOADFAILURE", Settings.Host, Settings.Port, Settings.Password); + } + + public override void OnImportFailure(AlbumDownloadMessage message) + { + _growlService.SendNotification(IMPORT_FAILURE_TITLE, message.Message, "IMPORTFAILURE", Settings.Host, Settings.Port, Settings.Password); } public override ValidationResult Test() diff --git a/src/NzbDrone.Core/Notifications/INotification.cs b/src/NzbDrone.Core/Notifications/INotification.cs index 29fb8288f..c5ec56f0e 100644 --- a/src/NzbDrone.Core/Notifications/INotification.cs +++ b/src/NzbDrone.Core/Notifications/INotification.cs @@ -8,13 +8,19 @@ namespace NzbDrone.Core.Notifications string Link { get; } void OnGrab(GrabMessage grabMessage); - void OnDownload(TrackDownloadMessage message); - void OnAlbumDownload(AlbumDownloadMessage message); + void OnReleaseImport(AlbumDownloadMessage message); void OnRename(Artist artist); + void OnHealthIssue(HealthCheck.HealthCheck healthCheck); + void OnDownloadFailure(DownloadFailedMessage message); + void OnImportFailure(AlbumDownloadMessage message); + void OnTrackRetag(TrackRetagMessage message); bool SupportsOnGrab { get; } - bool SupportsOnDownload { get; } - bool SupportsOnAlbumDownload { get; } + bool SupportsOnReleaseImport { get; } bool SupportsOnUpgrade { get; } bool SupportsOnRename { get; } + bool SupportsOnHealthIssue { get; } + bool SupportsOnDownloadFailure { get; } + bool SupportsOnImportFailure { get; } + bool SupportsOnTrackRetag { get; } } } diff --git a/src/NzbDrone.Core/Notifications/Join/Join.cs b/src/NzbDrone.Core/Notifications/Join/Join.cs index d4926138d..a61c71581 100644 --- a/src/NzbDrone.Core/Notifications/Join/Join.cs +++ b/src/NzbDrone.Core/Notifications/Join/Join.cs @@ -22,14 +22,14 @@ namespace NzbDrone.Core.Notifications.Join _proxy.SendNotification(ALBUM_GRABBED_TITLE_BRANDED, message.Message, Settings); } - public override void OnDownload(TrackDownloadMessage message) + public override void OnReleaseImport(AlbumDownloadMessage message) { - _proxy.SendNotification(TRACK_DOWNLOADED_TITLE_BRANDED, message.Message, Settings); + _proxy.SendNotification(ALBUM_DOWNLOADED_TITLE_BRANDED, message.Message, Settings); } - public override void OnAlbumDownload(AlbumDownloadMessage message) + public override void OnHealthIssue(HealthCheck.HealthCheck message) { - _proxy.SendNotification(ALBUM_DOWNLOADED_TITLE_BRANDED, message.Message, Settings); + _proxy.SendNotification(HEALTH_ISSUE_TITLE_BRANDED, message.Message, Settings); } public override ValidationResult Test() diff --git a/src/NzbDrone.Core/Notifications/MediaBrowser/MediaBrowser.cs b/src/NzbDrone.Core/Notifications/MediaBrowser/MediaBrowser.cs index 2b5dc52f6..ad2ff5bea 100644 --- a/src/NzbDrone.Core/Notifications/MediaBrowser/MediaBrowser.cs +++ b/src/NzbDrone.Core/Notifications/MediaBrowser/MediaBrowser.cs @@ -26,7 +26,7 @@ namespace NzbDrone.Core.Notifications.Emby } } - public override void OnAlbumDownload(AlbumDownloadMessage message) + public override void OnReleaseImport(AlbumDownloadMessage message) { if (Settings.Notify) { @@ -39,22 +39,29 @@ namespace NzbDrone.Core.Notifications.Emby } } - public override void OnDownload(TrackDownloadMessage message) + public override void OnRename(Artist artist) { - if (Settings.Notify) + if (Settings.UpdateLibrary) { - _mediaBrowserService.Notify(Settings, TRACK_DOWNLOADED_TITLE_BRANDED, message.Message); + _mediaBrowserService.Update(Settings, artist); } } - public override void OnRename(Artist artist) + public override void OnHealthIssue(HealthCheck.HealthCheck message) { - if (Settings.UpdateLibrary) + if (Settings.Notify) { - _mediaBrowserService.Update(Settings, artist); + _mediaBrowserService.Notify(Settings, HEALTH_ISSUE_TITLE_BRANDED, message.Message); } } + public override void OnTrackRetag(TrackRetagMessage message) + { + if (Settings.Notify) + { + _mediaBrowserService.Notify(Settings, TRACK_RETAGGED_TITLE_BRANDED, message.Message); + } + } public override ValidationResult Test() { diff --git a/src/NzbDrone.Core/Notifications/NotificationBase.cs b/src/NzbDrone.Core/Notifications/NotificationBase.cs index ac4e802c2..f7b91b49d 100644 --- a/src/NzbDrone.Core/Notifications/NotificationBase.cs +++ b/src/NzbDrone.Core/Notifications/NotificationBase.cs @@ -9,12 +9,18 @@ namespace NzbDrone.Core.Notifications public abstract class NotificationBase : INotification where TSettings : IProviderConfig, new() { protected const string ALBUM_GRABBED_TITLE = "Album Grabbed"; - protected const string TRACK_DOWNLOADED_TITLE = "Track Downloaded"; protected const string ALBUM_DOWNLOADED_TITLE = "Album Downloaded"; + protected const string HEALTH_ISSUE_TITLE = "Health Check Failure"; + protected const string DOWNLOAD_FAILURE_TITLE = "Download Failed"; + protected const string IMPORT_FAILURE_TITLE = "Import Failed"; + protected const string TRACK_RETAGGED_TITLE = "Track File Tags Updated"; protected const string ALBUM_GRABBED_TITLE_BRANDED = "Lidarr - " + ALBUM_GRABBED_TITLE; - protected const string TRACK_DOWNLOADED_TITLE_BRANDED = "Lidarr - " + TRACK_DOWNLOADED_TITLE; protected const string ALBUM_DOWNLOADED_TITLE_BRANDED = "Lidarr - " + ALBUM_DOWNLOADED_TITLE; + protected const string HEALTH_ISSUE_TITLE_BRANDED = "Lidarr - " + HEALTH_ISSUE_TITLE; + protected const string DOWNLOAD_FAILURE_TITLE_BRANDED = "Lidarr - " + DOWNLOAD_FAILURE_TITLE; + protected const string IMPORT_FAILURE_TITLE_BRANDED = "Lidarr - " + IMPORT_FAILURE_TITLE; + protected const string TRACK_RETAGGED_TITLE_BRANDED = "Lidarr - " + TRACK_RETAGGED_TITLE; public abstract string Name { get; } @@ -34,26 +40,44 @@ namespace NzbDrone.Core.Notifications } - public virtual void OnDownload(TrackDownloadMessage message) + public virtual void OnReleaseImport(AlbumDownloadMessage message) { } - public virtual void OnAlbumDownload(AlbumDownloadMessage message) + public virtual void OnRename(Artist artist) { } - public virtual void OnRename(Artist artist) + public virtual void OnHealthIssue(HealthCheck.HealthCheck healthCheck) + { + + } + + public virtual void OnDownloadFailure(DownloadFailedMessage message) + { + + } + + public virtual void OnImportFailure(AlbumDownloadMessage message) + { + + } + + public virtual void OnTrackRetag(TrackRetagMessage message) { } public bool SupportsOnGrab => HasConcreteImplementation("OnGrab"); public bool SupportsOnRename => HasConcreteImplementation("OnRename"); - public bool SupportsOnDownload => HasConcreteImplementation("OnDownload"); - public bool SupportsOnAlbumDownload => HasConcreteImplementation("OnAlbumDownload"); - public bool SupportsOnUpgrade => SupportsOnDownload; + public bool SupportsOnReleaseImport => HasConcreteImplementation("OnReleaseImport"); + public bool SupportsOnUpgrade => SupportsOnReleaseImport; + public bool SupportsOnHealthIssue => HasConcreteImplementation("OnHealthIssue"); + public bool SupportsOnDownloadFailure => HasConcreteImplementation("OnDownloadFailure"); + public bool SupportsOnImportFailure => HasConcreteImplementation("OnImportFailure"); + public bool SupportsOnTrackRetag => HasConcreteImplementation("OnTrackRetag"); protected TSettings Settings => (TSettings)Definition.Settings; diff --git a/src/NzbDrone.Core/Notifications/NotificationDefinition.cs b/src/NzbDrone.Core/Notifications/NotificationDefinition.cs index 6b29f2cac..350ddda61 100644 --- a/src/NzbDrone.Core/Notifications/NotificationDefinition.cs +++ b/src/NzbDrone.Core/Notifications/NotificationDefinition.cs @@ -6,16 +6,23 @@ namespace NzbDrone.Core.Notifications { public bool OnGrab { get; set; } - public bool OnDownload { get; set; } - public bool OnAlbumDownload { get; set; } + public bool OnReleaseImport { get; set; } public bool OnUpgrade { get; set; } public bool OnRename { get; set; } + public bool OnHealthIssue { get; set; } + public bool OnDownloadFailure { get; set; } + public bool OnImportFailure { get; set; } + public bool OnTrackRetag { get; set; } public bool SupportsOnGrab { get; set; } - public bool SupportsOnDownload { get; set; } - public bool SupportsOnAlbumDownload { get; set; } + public bool SupportsOnReleaseImport { get; set; } public bool SupportsOnUpgrade { get; set; } public bool SupportsOnRename { get; set; } + public bool SupportsOnHealthIssue { get; set; } + public bool IncludeHealthWarnings { get; set; } + public bool SupportsOnDownloadFailure { get; set; } + public bool SupportsOnImportFailure { get; set; } + public bool SupportsOnTrackRetag { get; set; } - public override bool Enable => OnGrab || OnDownload || OnAlbumDownload || (OnDownload && OnUpgrade); + public override bool Enable => OnGrab || OnReleaseImport || (OnReleaseImport && OnUpgrade) || OnHealthIssue || OnDownloadFailure || OnImportFailure || OnTrackRetag; } } diff --git a/src/NzbDrone.Core/Notifications/NotificationFactory.cs b/src/NzbDrone.Core/Notifications/NotificationFactory.cs index 9879638b5..3d4fbb74b 100644 --- a/src/NzbDrone.Core/Notifications/NotificationFactory.cs +++ b/src/NzbDrone.Core/Notifications/NotificationFactory.cs @@ -10,10 +10,13 @@ namespace NzbDrone.Core.Notifications public interface INotificationFactory : IProviderFactory { List OnGrabEnabled(); - List OnDownloadEnabled(); - List OnAlbumDownloadEnabled(); + List OnReleaseImportEnabled(); List OnUpgradeEnabled(); List OnRenameEnabled(); + List OnHealthIssueEnabled(); + List OnDownloadFailureEnabled(); + List OnImportFailureEnabled(); + List OnTrackRetagEnabled(); } public class NotificationFactory : ProviderFactory, INotificationFactory @@ -28,14 +31,9 @@ namespace NzbDrone.Core.Notifications return GetAvailableProviders().Where(n => ((NotificationDefinition)n.Definition).OnGrab).ToList(); } - public List OnDownloadEnabled() + public List OnReleaseImportEnabled() { - return GetAvailableProviders().Where(n => ((NotificationDefinition)n.Definition).OnDownload).ToList(); - } - - public List OnAlbumDownloadEnabled() - { - return GetAvailableProviders().Where(n => ((NotificationDefinition)n.Definition).OnAlbumDownload).ToList(); + return GetAvailableProviders().Where(n => ((NotificationDefinition)n.Definition).OnReleaseImport).ToList(); } public List OnUpgradeEnabled() @@ -48,15 +46,38 @@ namespace NzbDrone.Core.Notifications return GetAvailableProviders().Where(n => ((NotificationDefinition)n.Definition).OnRename).ToList(); } + public List OnHealthIssueEnabled() + { + return GetAvailableProviders().Where(n => ((NotificationDefinition)n.Definition).OnHealthIssue).ToList(); + } + + public List OnDownloadFailureEnabled() + { + return GetAvailableProviders().Where(n => ((NotificationDefinition)n.Definition).OnDownloadFailure).ToList(); + } + + public List OnImportFailureEnabled() + { + return GetAvailableProviders().Where(n => ((NotificationDefinition)n.Definition).OnImportFailure).ToList(); + } + + public List OnTrackRetagEnabled() + { + return GetAvailableProviders().Where(n => ((NotificationDefinition)n.Definition).OnTrackRetag).ToList(); + } + public override void SetProviderCharacteristics(INotification provider, NotificationDefinition definition) { base.SetProviderCharacteristics(provider, definition); definition.SupportsOnGrab = provider.SupportsOnGrab; - definition.SupportsOnDownload = provider.SupportsOnDownload; - definition.SupportsOnAlbumDownload = provider.SupportsOnAlbumDownload; + definition.SupportsOnReleaseImport = provider.SupportsOnReleaseImport; definition.SupportsOnUpgrade = provider.SupportsOnUpgrade; definition.SupportsOnRename = provider.SupportsOnRename; + definition.SupportsOnHealthIssue = provider.SupportsOnHealthIssue; + definition.SupportsOnDownloadFailure = provider.SupportsOnDownloadFailure; + definition.SupportsOnImportFailure = provider.SupportsOnImportFailure; + definition.SupportsOnTrackRetag = provider.SupportsOnTrackRetag; } } } diff --git a/src/NzbDrone.Core/Notifications/NotificationRepository.cs b/src/NzbDrone.Core/Notifications/NotificationRepository.cs index b012bd620..d163e1946 100644 --- a/src/NzbDrone.Core/Notifications/NotificationRepository.cs +++ b/src/NzbDrone.Core/Notifications/NotificationRepository.cs @@ -1,4 +1,4 @@ -using NzbDrone.Core.Datastore; +using NzbDrone.Core.Datastore; using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.ThingiProvider; @@ -7,7 +7,6 @@ namespace NzbDrone.Core.Notifications { public interface INotificationRepository : IProviderRepository { - } public class NotificationRepository : ProviderRepository, INotificationRepository @@ -17,4 +16,4 @@ namespace NzbDrone.Core.Notifications { } } -} \ No newline at end of file +} diff --git a/src/NzbDrone.Core/Notifications/NotificationService.cs b/src/NzbDrone.Core/Notifications/NotificationService.cs index 4a8b428d5..f1344dcbf 100644 --- a/src/NzbDrone.Core/Notifications/NotificationService.cs +++ b/src/NzbDrone.Core/Notifications/NotificationService.cs @@ -10,15 +10,19 @@ using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Qualities; using NzbDrone.Core.ThingiProvider; using NzbDrone.Core.Music; -using NzbDrone.Core.Parser.Model; +using NzbDrone.Core.HealthCheck; +using System.IO; namespace NzbDrone.Core.Notifications { public class NotificationService : IHandle, - IHandle, IHandle, - IHandle + IHandle, + IHandle, + IHandle, + IHandle, + IHandle { private readonly INotificationFactory _notificationFactory; private readonly Logger _logger; @@ -47,24 +51,6 @@ namespace NzbDrone.Core.Notifications qualityString); } - private string GetTrackMessage(Artist artist, List tracks, QualityModel quality) - { - var qualityString = quality.Quality.ToString(); - - if (quality.Revision.Version > 1) - { - qualityString += " Proper"; - } - - - var trackTitles = string.Join(" + ", tracks.Select(e => e.Title)); - - return string.Format("{0} - {1} - [{2}]", - artist.Name, - trackTitles, - qualityString); - } - private string GetAlbumDownloadMessage(Artist artist, Album album, List tracks) { return string.Format("{0} - {1} ({2} Tracks Imported)", @@ -73,6 +59,25 @@ namespace NzbDrone.Core.Notifications tracks.Count); } + private string GetAlbumIncompleteImportMessage(string source) + { + return string.Format("Lidarr failed to Import all tracks for {0}", + source); + } + + private string FormatMissing(object value) + { + var text = value?.ToString(); + return text.IsNullOrWhiteSpace() ? "" : text; + } + + private string GetTrackRetagMessage(Artist artist, TrackFile trackFile, Dictionary> diff) + { + return string.Format("{0}:\n{1}", + Path.Combine(artist.Path, trackFile.RelativePath), + string.Join("\n", diff.Select(x => $"{x.Key}: {FormatMissing(x.Value.Item1)} → {FormatMissing(x.Value.Item2)}"))); + } + private bool ShouldHandleArtist(ProviderDefinition definition, Artist artist) { if (definition.Tags.Empty()) @@ -92,6 +97,21 @@ namespace NzbDrone.Core.Notifications return false; } + private bool ShouldHandleHealthFailure(HealthCheck.HealthCheck healthCheck, bool includeWarnings) + { + if (healthCheck.Type == HealthCheckResult.Error) + { + return true; + } + + if (healthCheck.Type == HealthCheckResult.Warning && includeWarnings) + { + return true; + } + + return false; + } + public void Handle(AlbumGrabbedEvent message) { var grabMessage = new GrabMessage @@ -119,99 +139,141 @@ namespace NzbDrone.Core.Notifications } } - public void Handle(TrackImportedEvent message) + public void Handle(AlbumImportedEvent message) { if (!message.NewDownload) { return; } - var downloadMessage = new TrackDownloadMessage + var downloadMessage = new AlbumDownloadMessage { - Message = GetTrackMessage(message.TrackInfo.Artist, message.TrackInfo.Tracks, message.TrackInfo.Quality), - Artist = message.TrackInfo.Artist, - Album = message.TrackInfo.Album, - Release = message.TrackInfo.Release, - TrackFile = message.ImportedTrack, - OldFiles = message.OldFiles, - SourcePath = message.TrackInfo.Path, + Message = GetAlbumDownloadMessage(message.Artist, message.Album, message.ImportedTracks), + Artist = message.Artist, + Album = message.Album, + Release = message.AlbumRelease, DownloadClient = message.DownloadClient, - DownloadId = message.DownloadId + DownloadId = message.DownloadId, + TrackFiles = message.ImportedTracks, + OldFiles = message.OldFiles, }; - foreach (var notification in _notificationFactory.OnDownloadEnabled()) + foreach (var notification in _notificationFactory.OnReleaseImportEnabled()) { try { - if (ShouldHandleArtist(notification.Definition, message.TrackInfo.Artist)) + if (ShouldHandleArtist(notification.Definition, message.Artist)) { if (downloadMessage.OldFiles.Empty() || ((NotificationDefinition)notification.Definition).OnUpgrade) { - notification.OnDownload(downloadMessage); + notification.OnReleaseImport(downloadMessage); } } } catch (Exception ex) { - _logger.Warn(ex, "Unable to send OnDownload notification to: " + notification.Definition.Name); + _logger.Warn(ex, "Unable to send OnReleaseImport notification to: " + notification.Definition.Name); } } } - public void Handle(AlbumImportedEvent message) + public void Handle(ArtistRenamedEvent message) { - if (!message.NewDownload) - { - return; - } - - var downloadMessage = new AlbumDownloadMessage - - { - Message = GetAlbumDownloadMessage(message.Artist, message.Album, message.ImportedTracks), - Artist = message.Artist, - Album = message.Album, - Release = message.AlbumRelease, - DownloadClient = message.DownloadClient, - DownloadId = message.DownloadId, - TrackFiles = message.ImportedTracks, - OldFiles = message.OldFiles, - }; - - foreach (var notification in _notificationFactory.OnAlbumDownloadEnabled()) + foreach (var notification in _notificationFactory.OnRenameEnabled()) { try { if (ShouldHandleArtist(notification.Definition, message.Artist)) { - notification.OnAlbumDownload(downloadMessage); + notification.OnRename(message.Artist); } } catch (Exception ex) { - _logger.Warn(ex, "Unable to send OnDownload notification to: " + notification.Definition.Name); + _logger.Warn(ex, "Unable to send OnRename notification to: " + notification.Definition.Name); } } } - public void Handle(ArtistRenamedEvent message) + public void Handle(HealthCheckFailedEvent message) { - foreach (var notification in _notificationFactory.OnRenameEnabled()) + foreach (var notification in _notificationFactory.OnHealthIssueEnabled()) { try { - if (ShouldHandleArtist(notification.Definition, message.Artist)) + if (ShouldHandleHealthFailure(message.HealthCheck, ((NotificationDefinition)notification.Definition).IncludeHealthWarnings)) { - notification.OnRename(message.Artist); + notification.OnHealthIssue(message.HealthCheck); } } catch (Exception ex) { - _logger.Warn(ex, "Unable to send OnRename notification to: " + notification.Definition.Name); + _logger.Warn(ex, "Unable to send OnHealthIssue notification to: " + notification.Definition.Name); + } + } + } + + public void Handle(DownloadFailedEvent message) + { + var downloadFailedMessage = new DownloadFailedMessage + { + DownloadId = message.DownloadId, + DownloadClient = message.DownloadClient, + Quality = message.Quality, + Language = message.Language, + SourceTitle = message.SourceTitle, + Message = message.Message + + }; + + foreach (var notification in _notificationFactory.OnDownloadFailureEnabled()) + { + if (ShouldHandleArtist(notification.Definition, message.TrackedDownload.RemoteAlbum.Artist)) + { + notification.OnDownloadFailure(downloadFailedMessage); + } + } + } + + public void Handle(AlbumImportIncompleteEvent message) + { + // TODO: Build out this message so that we can pass on what failed and what was successful + var downloadMessage = new AlbumDownloadMessage + { + Message = GetAlbumIncompleteImportMessage(message.TrackedDownload.RemoteAlbum.Release.Title), + }; + + foreach (var notification in _notificationFactory.OnDownloadFailureEnabled()) + { + if (ShouldHandleArtist(notification.Definition, message.TrackedDownload.RemoteAlbum.Artist)) + { + notification.OnImportFailure(downloadMessage); + } + } + } + + public void Handle(TrackFileRetaggedEvent message) + { + var retagMessage = new TrackRetagMessage + { + Message = GetTrackRetagMessage(message.Artist, message.TrackFile, message.Diff), + Artist = message.Artist, + Album = message.TrackFile.Album, + Release = message.TrackFile.Tracks.Value.First().AlbumRelease.Value, + TrackFile = message.TrackFile, + Diff = message.Diff, + Scrubbed = message.Scrubbed + }; + + foreach (var notification in _notificationFactory.OnTrackRetagEnabled()) + { + if (ShouldHandleArtist(notification.Definition, message.Artist)) + { + notification.OnTrackRetag(retagMessage); } } } diff --git a/src/NzbDrone.Core/Notifications/Plex/HomeTheater/PlexClient.cs b/src/NzbDrone.Core/Notifications/Plex/HomeTheater/PlexClient.cs index f6ed23f5a..78dacf1fe 100644 --- a/src/NzbDrone.Core/Notifications/Plex/HomeTheater/PlexClient.cs +++ b/src/NzbDrone.Core/Notifications/Plex/HomeTheater/PlexClient.cs @@ -21,14 +21,14 @@ namespace NzbDrone.Core.Notifications.Plex.HomeTheater _plexClientService.Notify(Settings, ALBUM_GRABBED_TITLE_BRANDED, grabMessage.Message); } - public override void OnDownload(TrackDownloadMessage message) + public override void OnReleaseImport(AlbumDownloadMessage message) { - _plexClientService.Notify(Settings, TRACK_DOWNLOADED_TITLE_BRANDED, message.Message); + _plexClientService.Notify(Settings, ALBUM_DOWNLOADED_TITLE_BRANDED, message.Message); } - public override void OnAlbumDownload(AlbumDownloadMessage message) + public override void OnHealthIssue(HealthCheck.HealthCheck message) { - _plexClientService.Notify(Settings, ALBUM_DOWNLOADED_TITLE_BRANDED, message.Message); + _plexClientService.Notify(Settings, HEALTH_ISSUE_TITLE_BRANDED, message.Message); } public override ValidationResult Test() diff --git a/src/NzbDrone.Core/Notifications/Plex/HomeTheater/PlexHomeTheater.cs b/src/NzbDrone.Core/Notifications/Plex/HomeTheater/PlexHomeTheater.cs index 4dc3e3226..41720a502 100644 --- a/src/NzbDrone.Core/Notifications/Plex/HomeTheater/PlexHomeTheater.cs +++ b/src/NzbDrone.Core/Notifications/Plex/HomeTheater/PlexHomeTheater.cs @@ -26,9 +26,9 @@ namespace NzbDrone.Core.Notifications.Plex.HomeTheater Notify(ALBUM_GRABBED_TITLE_BRANDED, grabMessage.Message); } - public override void OnDownload(TrackDownloadMessage message) + public override void OnReleaseImport(AlbumDownloadMessage message) { - Notify(TRACK_DOWNLOADED_TITLE_BRANDED, message.Message); + Notify(ALBUM_DOWNLOADED_TITLE_BRANDED, message.Message); } public override ValidationResult Test() diff --git a/src/NzbDrone.Core/Notifications/Plex/Server/PlexServer.cs b/src/NzbDrone.Core/Notifications/Plex/Server/PlexServer.cs index 3be451a7d..636f85997 100644 --- a/src/NzbDrone.Core/Notifications/Plex/Server/PlexServer.cs +++ b/src/NzbDrone.Core/Notifications/Plex/Server/PlexServer.cs @@ -23,19 +23,19 @@ namespace NzbDrone.Core.Notifications.Plex.Server public override string Link => "https://www.plex.tv/"; public override string Name => "Plex Media Server"; - public override void OnDownload(TrackDownloadMessage message) + public override void OnReleaseImport(AlbumDownloadMessage message) { UpdateIfEnabled(message.Artist); } - public override void OnAlbumDownload(AlbumDownloadMessage message) + public override void OnRename(Artist artist) { - UpdateIfEnabled(message.Artist); + UpdateIfEnabled(artist); } - public override void OnRename(Artist artist) + public override void OnTrackRetag(TrackRetagMessage message) { - UpdateIfEnabled(artist); + UpdateIfEnabled(message.Artist); } private void UpdateIfEnabled(Artist artist) diff --git a/src/NzbDrone.Core/Notifications/Prowl/Prowl.cs b/src/NzbDrone.Core/Notifications/Prowl/Prowl.cs index 967639fd9..505f4e099 100644 --- a/src/NzbDrone.Core/Notifications/Prowl/Prowl.cs +++ b/src/NzbDrone.Core/Notifications/Prowl/Prowl.cs @@ -22,14 +22,14 @@ namespace NzbDrone.Core.Notifications.Prowl _prowlService.SendNotification(ALBUM_GRABBED_TITLE, grabMessage.Message, Settings.ApiKey, (NotificationPriority)Settings.Priority); } - public override void OnDownload(TrackDownloadMessage message) + public override void OnReleaseImport(AlbumDownloadMessage message) { - _prowlService.SendNotification(TRACK_DOWNLOADED_TITLE, message.Message, Settings.ApiKey, (NotificationPriority)Settings.Priority); + _prowlService.SendNotification(ALBUM_DOWNLOADED_TITLE, message.Message, Settings.ApiKey, (NotificationPriority)Settings.Priority); } - public override void OnAlbumDownload(AlbumDownloadMessage message) + public override void OnHealthIssue(HealthCheck.HealthCheck message) { - _prowlService.SendNotification(ALBUM_DOWNLOADED_TITLE, message.Message, Settings.ApiKey, (NotificationPriority)Settings.Priority); + _prowlService.SendNotification(HEALTH_ISSUE_TITLE, message.Message, Settings.ApiKey, (NotificationPriority)Settings.Priority); } public override ValidationResult Test() diff --git a/src/NzbDrone.Core/Notifications/PushBullet/PushBullet.cs b/src/NzbDrone.Core/Notifications/PushBullet/PushBullet.cs index feaae84fd..843cffd60 100644 --- a/src/NzbDrone.Core/Notifications/PushBullet/PushBullet.cs +++ b/src/NzbDrone.Core/Notifications/PushBullet/PushBullet.cs @@ -24,14 +24,24 @@ namespace NzbDrone.Core.Notifications.PushBullet _proxy.SendNotification(ALBUM_GRABBED_TITLE_BRANDED, grabMessage.Message, Settings); } - public override void OnDownload(TrackDownloadMessage message) + public override void OnReleaseImport(AlbumDownloadMessage message) { - _proxy.SendNotification(TRACK_DOWNLOADED_TITLE_BRANDED, message.Message, Settings); + _proxy.SendNotification(ALBUM_DOWNLOADED_TITLE_BRANDED, message.Message, Settings); } - public override void OnAlbumDownload(AlbumDownloadMessage message) + public override void OnHealthIssue(HealthCheck.HealthCheck healthCheck) { - _proxy.SendNotification(ALBUM_DOWNLOADED_TITLE_BRANDED, message.Message, Settings); + _proxy.SendNotification(HEALTH_ISSUE_TITLE_BRANDED, healthCheck.Message, Settings); + } + + public override void OnDownloadFailure(DownloadFailedMessage message) + { + _proxy.SendNotification(DOWNLOAD_FAILURE_TITLE_BRANDED, message.Message, Settings); + } + + public override void OnImportFailure(AlbumDownloadMessage message) + { + _proxy.SendNotification(IMPORT_FAILURE_TITLE_BRANDED, message.Message, Settings); } public override ValidationResult Test() diff --git a/src/NzbDrone.Core/Notifications/Pushover/Pushover.cs b/src/NzbDrone.Core/Notifications/Pushover/Pushover.cs index dadac64d0..f9d7e662e 100644 --- a/src/NzbDrone.Core/Notifications/Pushover/Pushover.cs +++ b/src/NzbDrone.Core/Notifications/Pushover/Pushover.cs @@ -21,14 +21,24 @@ namespace NzbDrone.Core.Notifications.Pushover _proxy.SendNotification(ALBUM_GRABBED_TITLE, grabMessage.Message, Settings); } - public override void OnDownload(TrackDownloadMessage message) + public override void OnReleaseImport(AlbumDownloadMessage message) { - _proxy.SendNotification(TRACK_DOWNLOADED_TITLE, message.Message, Settings); + _proxy.SendNotification(ALBUM_DOWNLOADED_TITLE, message.Message, Settings); } - public override void OnAlbumDownload(AlbumDownloadMessage message) + public override void OnHealthIssue(HealthCheck.HealthCheck healthCheck) { - _proxy.SendNotification(ALBUM_DOWNLOADED_TITLE, message.Message, Settings); + _proxy.SendNotification(HEALTH_ISSUE_TITLE, healthCheck.Message, Settings); + } + + public override void OnDownloadFailure(DownloadFailedMessage message) + { + _proxy.SendNotification(DOWNLOAD_FAILURE_TITLE, message.Message, Settings); + } + + public override void OnImportFailure(AlbumDownloadMessage message) + { + _proxy.SendNotification(IMPORT_FAILURE_TITLE, message.Message, Settings); } public override ValidationResult Test() diff --git a/src/NzbDrone.Core/Notifications/Slack/Slack.cs b/src/NzbDrone.Core/Notifications/Slack/Slack.cs index d44e6b6c0..78507e5b2 100644 --- a/src/NzbDrone.Core/Notifications/Slack/Slack.cs +++ b/src/NzbDrone.Core/Notifications/Slack/Slack.cs @@ -1,15 +1,11 @@ using System; using System.Collections.Generic; using FluentValidation.Results; -using NLog; using NzbDrone.Common.Extensions; -using NzbDrone.Common.Http; -using NzbDrone.Common.Serializer; using NzbDrone.Core.Notifications.Slack.Payloads; using NzbDrone.Core.Rest; using NzbDrone.Core.Music; using NzbDrone.Core.Validation; -using RestSharp; namespace NzbDrone.Core.Notifications.Slack @@ -17,12 +13,10 @@ namespace NzbDrone.Core.Notifications.Slack public class Slack : NotificationBase { private readonly ISlackProxy _proxy; - private readonly Logger _logger; - public Slack(ISlackProxy proxy, Logger logger) + public Slack(ISlackProxy proxy) { _proxy = proxy; - _logger = logger; } public override string Name => "Slack"; @@ -45,24 +39,7 @@ namespace NzbDrone.Core.Notifications.Slack _proxy.SendPayload(payload, Settings); } - public override void OnDownload(TrackDownloadMessage message) - { - var attachments = new List - { - new Attachment - { - Fallback = message.Message, - Title = message.Artist.Name, - Text = message.Message, - Color = "good" - } - }; - var payload = CreatePayload($"Imported: {message.Message}", attachments); - - _proxy.SendPayload(payload, Settings); - } - - public override void OnAlbumDownload(AlbumDownloadMessage message) + public override void OnReleaseImport(AlbumDownloadMessage message) { var attachments = new List { @@ -94,6 +71,73 @@ namespace NzbDrone.Core.Notifications.Slack _proxy.SendPayload(payload, Settings); } + public override void OnHealthIssue(HealthCheck.HealthCheck healthCheck) + { + var attachments = new List + { + new Attachment + { + Title = healthCheck.Source.Name, + Text = healthCheck.Message, + Color = healthCheck.Type == HealthCheck.HealthCheckResult.Warning ? "warning" : "danger" + } + }; + + var payload = CreatePayload("Health Issue", attachments); + + _proxy.SendPayload(payload, Settings); + } + + public override void OnTrackRetag(TrackRetagMessage message) + { + var attachments = new List + { + new Attachment + { + Title = TRACK_RETAGGED_TITLE, + Text = message.Message + } + }; + + var payload = CreatePayload(TRACK_RETAGGED_TITLE, attachments); + + _proxy.SendPayload(payload, Settings); + } + + public override void OnDownloadFailure(DownloadFailedMessage message) + { + var attachments = new List + { + new Attachment + { + Fallback = message.Message, + Title = message.SourceTitle, + Text = message.Message, + Color = "danger" + } + }; + var payload = CreatePayload($"Download Failed: {message.Message}", attachments); + + _proxy.SendPayload(payload, Settings); + } + + public override void OnImportFailure(AlbumDownloadMessage message) + { + var attachments = new List + { + new Attachment + { + Fallback = message.Message, + Title = message.Album.Title, + Text = message.Message, + Color = "warning" + } + }; + var payload = CreatePayload($"Import Failed: {message.Message}", attachments); + + _proxy.SendPayload(payload, Settings); + } + public override ValidationResult Test() { var failures = new List(); diff --git a/src/NzbDrone.Core/Notifications/Subsonic/Subsonic.cs b/src/NzbDrone.Core/Notifications/Subsonic/Subsonic.cs index 66f30a9e5..f65864e20 100644 --- a/src/NzbDrone.Core/Notifications/Subsonic/Subsonic.cs +++ b/src/NzbDrone.Core/Notifications/Subsonic/Subsonic.cs @@ -28,7 +28,7 @@ namespace NzbDrone.Core.Notifications.Subsonic Notify(Settings, header, grabMessage.Message); } - public override void OnAlbumDownload(AlbumDownloadMessage message) + public override void OnReleaseImport(AlbumDownloadMessage message) { const string header = "Lidarr - Downloaded"; @@ -36,17 +36,19 @@ namespace NzbDrone.Core.Notifications.Subsonic Update(); } - public override void OnDownload(TrackDownloadMessage message) + public override void OnRename(Artist artist) { - const string header = "Lidarr - Downloaded"; + Update(); + } - Notify(Settings, header, message.Message); - + public override void OnHealthIssue(HealthCheck.HealthCheck healthCheck) + { + Notify(Settings, HEALTH_ISSUE_TITLE_BRANDED, healthCheck.Message); } - public override void OnRename(Artist artist) + public override void OnTrackRetag(TrackRetagMessage message) { - Update(); + Notify(Settings, TRACK_RETAGGED_TITLE_BRANDED, message.Message); } public override string Name => "Subsonic"; diff --git a/src/NzbDrone.Core/Notifications/Synology/SynologyIndexer.cs b/src/NzbDrone.Core/Notifications/Synology/SynologyIndexer.cs index a08f66843..dd90807a7 100644 --- a/src/NzbDrone.Core/Notifications/Synology/SynologyIndexer.cs +++ b/src/NzbDrone.Core/Notifications/Synology/SynologyIndexer.cs @@ -20,8 +20,7 @@ namespace NzbDrone.Core.Notifications.Synology public override string Link => "https://www.synology.com"; public override string Name => "Synology Indexer"; - - public override void OnAlbumDownload(AlbumDownloadMessage message) + public override void OnReleaseImport(AlbumDownloadMessage message) { if (Settings.UpdateLibrary) { @@ -49,6 +48,13 @@ namespace NzbDrone.Core.Notifications.Synology } } + public override void OnTrackRetag(TrackRetagMessage message) + { + if (Settings.UpdateLibrary) + { + _indexerProxy.UpdateFolder(message.Artist.Path); + } + } public override ValidationResult Test() { diff --git a/src/NzbDrone.Core/Notifications/Telegram/Telegram.cs b/src/NzbDrone.Core/Notifications/Telegram/Telegram.cs index 8f14f2d84..670cc1d6d 100644 --- a/src/NzbDrone.Core/Notifications/Telegram/Telegram.cs +++ b/src/NzbDrone.Core/Notifications/Telegram/Telegram.cs @@ -21,14 +21,24 @@ namespace NzbDrone.Core.Notifications.Telegram _proxy.SendNotification(ALBUM_GRABBED_TITLE, grabMessage.Message, Settings); } - public override void OnDownload(TrackDownloadMessage message) + public override void OnReleaseImport(AlbumDownloadMessage message) { - _proxy.SendNotification(TRACK_DOWNLOADED_TITLE, message.Message, Settings); + _proxy.SendNotification(ALBUM_DOWNLOADED_TITLE, message.Message, Settings); } - public override void OnAlbumDownload(AlbumDownloadMessage message) + public override void OnHealthIssue(HealthCheck.HealthCheck healthCheck) { - _proxy.SendNotification(TRACK_DOWNLOADED_TITLE, message.Message, Settings); + _proxy.SendNotification(HEALTH_ISSUE_TITLE, healthCheck.Message, Settings); + } + + public override void OnDownloadFailure(DownloadFailedMessage message) + { + _proxy.SendNotification(DOWNLOAD_FAILURE_TITLE, message.Message, Settings); + } + + public override void OnImportFailure(AlbumDownloadMessage message) + { + _proxy.SendNotification(IMPORT_FAILURE_TITLE, message.Message, Settings); } public override ValidationResult Test() diff --git a/src/NzbDrone.Core/Notifications/TrackDownloadMessage.cs b/src/NzbDrone.Core/Notifications/TrackRetagMessage.cs similarity index 66% rename from src/NzbDrone.Core/Notifications/TrackDownloadMessage.cs rename to src/NzbDrone.Core/Notifications/TrackRetagMessage.cs index e23a5c300..6f6702544 100644 --- a/src/NzbDrone.Core/Notifications/TrackDownloadMessage.cs +++ b/src/NzbDrone.Core/Notifications/TrackRetagMessage.cs @@ -1,20 +1,19 @@ +using System; using System.Collections.Generic; using NzbDrone.Core.MediaFiles; using NzbDrone.Core.Music; namespace NzbDrone.Core.Notifications { - public class TrackDownloadMessage + public class TrackRetagMessage { public string Message { get; set; } public Artist Artist { get; set; } public Album Album { get; set; } public AlbumRelease Release { get; set; } public TrackFile TrackFile { get; set; } - public List OldFiles { get; set; } - public string SourcePath { get; set; } - public string DownloadClient { get; set; } - public string DownloadId { get; set; } + public Dictionary> Diff { get; set; } + public bool Scrubbed { get; set; } public override string ToString() { diff --git a/src/NzbDrone.Core/Notifications/Twitter/Twitter.cs b/src/NzbDrone.Core/Notifications/Twitter/Twitter.cs index 2eae0ecde..a8f5e06c2 100644 --- a/src/NzbDrone.Core/Notifications/Twitter/Twitter.cs +++ b/src/NzbDrone.Core/Notifications/Twitter/Twitter.cs @@ -24,14 +24,24 @@ namespace NzbDrone.Core.Notifications.Twitter _twitterService.SendNotification($"Grabbed: {message.Message}", Settings); } - public override void OnDownload(TrackDownloadMessage message) + public override void OnReleaseImport(AlbumDownloadMessage message) { _twitterService.SendNotification($"Imported: {message.Message}", Settings); } - public override void OnAlbumDownload(AlbumDownloadMessage message) + public override void OnHealthIssue(HealthCheck.HealthCheck healthCheck) { - _twitterService.SendNotification($"Imported: {message.Message}", Settings); + _twitterService.SendNotification($"Health Issue: {healthCheck.Message}", Settings); + } + + public override void OnDownloadFailure(DownloadFailedMessage message) + { + _twitterService.SendNotification($"Download Failed: {message.Message}", Settings); + } + + public override void OnImportFailure(AlbumDownloadMessage message) + { + _twitterService.SendNotification($"Import Failed: {message.Message}", Settings); } public override object RequestAction(string action, IDictionary query) diff --git a/src/NzbDrone.Core/Notifications/Webhook/Webhook.cs b/src/NzbDrone.Core/Notifications/Webhook/Webhook.cs index 3f3a667c6..595d2d348 100644 --- a/src/NzbDrone.Core/Notifications/Webhook/Webhook.cs +++ b/src/NzbDrone.Core/Notifications/Webhook/Webhook.cs @@ -41,23 +41,23 @@ namespace NzbDrone.Core.Notifications.Webhook _proxy.SendWebhook(payload, Settings); } - public override void OnDownload(TrackDownloadMessage message) + public override void OnReleaseImport(AlbumDownloadMessage message) { - var trackFile = message.TrackFile; + var trackFiles = message.TrackFiles; var payload = new WebhookImportPayload { EventType = "Download", Artist = new WebhookArtist(message.Artist), - Tracks = trackFile.Tracks.Value.ConvertAll(x => new WebhookTrack(x) + Tracks = trackFiles.SelectMany(x => x.Tracks.Value.Select(y => new WebhookTrack(y) { // TODO: Stop passing these parameters inside an episode v3 - Quality = trackFile.Quality.Quality.Name, - QualityVersion = trackFile.Quality.Revision.Version, - ReleaseGroup = trackFile.ReleaseGroup - }), - TrackFile = new WebhookTrackFile(trackFile), + Quality = x.Quality.Quality.Name, + QualityVersion = x.Quality.Revision.Version, + ReleaseGroup = x.ReleaseGroup + })).ToList(), + TrackFiles = trackFiles.ConvertAll(x => new WebhookTrackFile(x)), IsUpgrade = message.OldFiles.Any() }; @@ -75,6 +75,17 @@ namespace NzbDrone.Core.Notifications.Webhook _proxy.SendWebhook(payload, Settings); } + public override void OnTrackRetag(TrackRetagMessage message) + { + var payload = new WebhookPayload + { + EventType = "Retag", + Artist = new WebhookArtist(message.Artist) + }; + + _proxy.SendWebhook(payload, Settings); + } + public override string Name => "Webhook"; public override ValidationResult Test() diff --git a/src/NzbDrone.Core/Notifications/Webhook/WebhookImportPayload.cs b/src/NzbDrone.Core/Notifications/Webhook/WebhookImportPayload.cs index d3cfd0ed3..ec19633d7 100644 --- a/src/NzbDrone.Core/Notifications/Webhook/WebhookImportPayload.cs +++ b/src/NzbDrone.Core/Notifications/Webhook/WebhookImportPayload.cs @@ -5,7 +5,7 @@ namespace NzbDrone.Core.Notifications.Webhook public class WebhookImportPayload : WebhookPayload { public List Tracks { get; set; } - public WebhookTrackFile TrackFile { get; set; } + public List TrackFiles { get; set; } public bool IsUpgrade { get; set; } } } diff --git a/src/NzbDrone.Core/Notifications/Xbmc/Xbmc.cs b/src/NzbDrone.Core/Notifications/Xbmc/Xbmc.cs index e2a64e5f4..c3c9eb911 100644 --- a/src/NzbDrone.Core/Notifications/Xbmc/Xbmc.cs +++ b/src/NzbDrone.Core/Notifications/Xbmc/Xbmc.cs @@ -28,24 +28,27 @@ namespace NzbDrone.Core.Notifications.Xbmc Notify(Settings, header, grabMessage.Message); } - public override void OnAlbumDownload(AlbumDownloadMessage message) + public override void OnReleaseImport(AlbumDownloadMessage message) { const string header = "Lidarr - Downloaded"; Notify(Settings, header, message.Message); + UpdateAndClean(message.Artist, message.OldFiles.Any()); } - public override void OnDownload(TrackDownloadMessage message) + public override void OnRename(Artist artist) { - const string header = "Lidarr - Downloaded"; + UpdateAndClean(artist); + } - Notify(Settings, header, message.Message); - UpdateAndClean(message.Artist, message.OldFiles.Any()); + public override void OnHealthIssue(HealthCheck.HealthCheck healthCheck) + { + Notify(Settings, HEALTH_ISSUE_TITLE_BRANDED, healthCheck.Message); } - public override void OnRename(Artist artist) + public override void OnTrackRetag(TrackRetagMessage message) { - UpdateAndClean(artist); + UpdateAndClean(message.Artist); } public override string Name => "Kodi (XBMC)"; @@ -54,7 +57,7 @@ namespace NzbDrone.Core.Notifications.Xbmc { var failures = new List(); - failures.AddIfNotNull(_xbmcService.Test(Settings, "Success! XBMC has been successfully configured!")); + failures.AddIfNotNull(_xbmcService.Test(Settings, "Success! Kodi has been successfully configured!")); return new ValidationResult(failures); } @@ -70,7 +73,7 @@ namespace NzbDrone.Core.Notifications.Xbmc } catch (SocketException ex) { - var logMessage = string.Format("Unable to connect to XBMC Host: {0}:{1}", Settings.Host, Settings.Port); + var logMessage = string.Format("Unable to connect to Kodi Host: {0}:{1}", Settings.Host, Settings.Port); _logger.Debug(ex, logMessage); } } @@ -91,7 +94,7 @@ namespace NzbDrone.Core.Notifications.Xbmc } catch (SocketException ex) { - var logMessage = string.Format("Unable to connect to XBMC Host: {0}:{1}", Settings.Host, Settings.Port); + var logMessage = string.Format("Unable to connect to Kodi Host: {0}:{1}", Settings.Host, Settings.Port); _logger.Debug(ex, logMessage); } } diff --git a/src/NzbDrone.Core/NzbDrone.Core.csproj b/src/NzbDrone.Core/NzbDrone.Core.csproj index b80d60df1..944db1eaf 100644 --- a/src/NzbDrone.Core/NzbDrone.Core.csproj +++ b/src/NzbDrone.Core/NzbDrone.Core.csproj @@ -183,6 +183,7 @@ + @@ -508,6 +509,7 @@ + @@ -711,6 +713,13 @@ + + + + + + + @@ -922,6 +931,7 @@ + @@ -1050,7 +1060,7 @@ - + Code