diff --git a/frontend/src/Settings/Notifications/Notifications/Notification.js b/frontend/src/Settings/Notifications/Notifications/Notification.js
index 9e2e881c4..14ab5f300 100644
--- a/frontend/src/Settings/Notifications/Notifications/Notification.js
+++ b/frontend/src/Settings/Notifications/Notifications/Notification.js
@@ -67,6 +67,7 @@ class Notification extends Component {
onImportFailure,
onTrackRetag,
onApplicationUpdate,
+ onManualInteractionRequired,
supportsOnGrab,
supportsOnReleaseImport,
supportsOnUpgrade,
@@ -78,7 +79,8 @@ class Notification extends Component {
supportsOnDownloadFailure,
supportsOnImportFailure,
supportsOnTrackRetag,
- supportsOnApplicationUpdate
+ supportsOnApplicationUpdate,
+ supportsOnManualInteractionRequired
} = this.props;
return (
@@ -177,14 +179,22 @@ class Notification extends Component {
}
{
- !onGrab && !onReleaseImport && !onRename && !onTrackRetag && !onAlbumDelete && !onArtistDelete &&
- !onHealthIssue && !onHealthRestored && !onDownloadFailure && !onImportFailure && !onApplicationUpdate &&
-
+ supportsOnManualInteractionRequired && onManualInteractionRequired ?
+ :
+ null
+ }
+
+ {
+ !onGrab && !onReleaseImport && !onRename && !onTrackRetag && !onAlbumDelete && !onArtistDelete && !onHealthIssue && !onHealthRestored && !onDownloadFailure && !onImportFailure && !onApplicationUpdate && !onManualInteractionRequired ?
+ :
+ null
}
}
+
+
+
+
diff --git a/frontend/src/Store/Actions/Settings/notifications.js b/frontend/src/Store/Actions/Settings/notifications.js
index b6a38022d..16fa5ceb1 100644
--- a/frontend/src/Store/Actions/Settings/notifications.js
+++ b/frontend/src/Store/Actions/Settings/notifications.js
@@ -111,6 +111,7 @@ export default {
selectedSchema.onImportFailure = selectedSchema.supportsOnImportFailure;
selectedSchema.onTrackRetag = selectedSchema.supportsOnTrackRetag;
selectedSchema.onApplicationUpdate = selectedSchema.supportsOnApplicationUpdate;
+ selectedSchema.onManualInteractionRequired = selectedSchema.supportsOnManualInteractionRequired;
return selectedSchema;
});
diff --git a/src/Lidarr.Api.V1/Notifications/NotificationResource.cs b/src/Lidarr.Api.V1/Notifications/NotificationResource.cs
index df705d42d..c3605c2c4 100644
--- a/src/Lidarr.Api.V1/Notifications/NotificationResource.cs
+++ b/src/Lidarr.Api.V1/Notifications/NotificationResource.cs
@@ -17,6 +17,7 @@ namespace Lidarr.Api.V1.Notifications
public bool OnImportFailure { get; set; }
public bool OnTrackRetag { get; set; }
public bool OnApplicationUpdate { get; set; }
+ public bool OnManualInteractionRequired { get; set; }
public bool SupportsOnGrab { get; set; }
public bool SupportsOnReleaseImport { get; set; }
public bool SupportsOnUpgrade { get; set; }
@@ -30,6 +31,7 @@ namespace Lidarr.Api.V1.Notifications
public bool SupportsOnImportFailure { get; set; }
public bool SupportsOnTrackRetag { get; set; }
public bool SupportsOnApplicationUpdate { get; set; }
+ public bool SupportsOnManualInteractionRequired { get; set; }
public string TestCommand { get; set; }
}
@@ -56,6 +58,7 @@ namespace Lidarr.Api.V1.Notifications
resource.OnImportFailure = definition.OnImportFailure;
resource.OnTrackRetag = definition.OnTrackRetag;
resource.OnApplicationUpdate = definition.OnApplicationUpdate;
+ resource.OnManualInteractionRequired = definition.OnManualInteractionRequired;
resource.SupportsOnGrab = definition.SupportsOnGrab;
resource.SupportsOnReleaseImport = definition.SupportsOnReleaseImport;
resource.SupportsOnUpgrade = definition.SupportsOnUpgrade;
@@ -69,6 +72,7 @@ namespace Lidarr.Api.V1.Notifications
resource.SupportsOnImportFailure = definition.SupportsOnImportFailure;
resource.SupportsOnTrackRetag = definition.SupportsOnTrackRetag;
resource.SupportsOnApplicationUpdate = definition.SupportsOnApplicationUpdate;
+ resource.SupportsOnManualInteractionRequired = definition.SupportsOnManualInteractionRequired;
return resource;
}
@@ -94,6 +98,7 @@ namespace Lidarr.Api.V1.Notifications
definition.OnImportFailure = resource.OnImportFailure;
definition.OnTrackRetag = resource.OnTrackRetag;
definition.OnApplicationUpdate = resource.OnApplicationUpdate;
+ definition.OnManualInteractionRequired = resource.OnManualInteractionRequired;
definition.SupportsOnGrab = resource.SupportsOnGrab;
definition.SupportsOnReleaseImport = resource.SupportsOnReleaseImport;
definition.SupportsOnUpgrade = resource.SupportsOnUpgrade;
@@ -107,6 +112,7 @@ namespace Lidarr.Api.V1.Notifications
definition.SupportsOnImportFailure = resource.SupportsOnImportFailure;
definition.SupportsOnTrackRetag = resource.SupportsOnTrackRetag;
definition.SupportsOnApplicationUpdate = resource.SupportsOnApplicationUpdate;
+ definition.SupportsOnManualInteractionRequired = resource.SupportsOnManualInteractionRequired;
return definition;
}
diff --git a/src/NzbDrone.Core.Test/Download/CompletedDownloadServiceTests/ProcessFixture.cs b/src/NzbDrone.Core.Test/Download/CompletedDownloadServiceTests/ProcessFixture.cs
index 593fd7dd0..5c87612c3 100644
--- a/src/NzbDrone.Core.Test/Download/CompletedDownloadServiceTests/ProcessFixture.cs
+++ b/src/NzbDrone.Core.Test/Download/CompletedDownloadServiceTests/ProcessFixture.cs
@@ -50,8 +50,8 @@ namespace NzbDrone.Core.Test.Download.CompletedDownloadServiceTests
.Returns((DownloadClientItem item, DownloadClientItem previous) => item);
Mocker.GetMock()
- .Setup(s => s.MostRecentForDownloadId(_trackedDownload.DownloadItem.DownloadId))
- .Returns(new EntityHistory());
+ .Setup(s => s.FindByDownloadId(_trackedDownload.DownloadItem.DownloadId))
+ .Returns(new List());
Mocker.GetMock()
.Setup(s => s.GetArtist("Drone.S01E01.HDTV"))
@@ -70,8 +70,8 @@ namespace NzbDrone.Core.Test.Download.CompletedDownloadServiceTests
private void GivenNoGrabbedHistory()
{
Mocker.GetMock()
- .Setup(s => s.MostRecentForDownloadId(_trackedDownload.DownloadItem.DownloadId))
- .Returns((EntityHistory)null);
+ .Setup(s => s.FindByDownloadId(_trackedDownload.DownloadItem.DownloadId))
+ .Returns(new List());
}
private void GivenArtistMatch()
@@ -86,8 +86,11 @@ namespace NzbDrone.Core.Test.Download.CompletedDownloadServiceTests
_trackedDownload.DownloadItem.DownloadId = "1234";
_trackedDownload.DownloadItem.Title = "Droned Pilot"; // Set a badly named download
Mocker.GetMock()
- .Setup(s => s.MostRecentForDownloadId(It.Is(i => i == "1234")))
- .Returns(new EntityHistory() { SourceTitle = "Droned S01E01" });
+ .Setup(s => s.FindByDownloadId(It.Is(i => i == "1234")))
+ .Returns(new List
+ {
+ new EntityHistory() { SourceTitle = "Droned S01E01", EventType = EntityHistoryEventType.Grabbed }
+ });
Mocker.GetMock()
.Setup(s => s.GetArtist(It.IsAny()))
@@ -151,9 +154,6 @@ namespace NzbDrone.Core.Test.Download.CompletedDownloadServiceTests
GivenABadlyNamedDownload();
_trackedDownload.RemoteAlbum.Artist = null;
- Mocker.GetMock()
- .Setup(s => s.MostRecentForDownloadId(It.Is(i => i == "1234")));
-
Subject.Check(_trackedDownload);
AssertNotReadyToImport();
diff --git a/src/NzbDrone.Core.Test/MediaFiles/TrackImport/Specifications/MatchesGrabSpecificationFixture.cs b/src/NzbDrone.Core.Test/MediaFiles/TrackImport/Specifications/MatchesGrabSpecificationFixture.cs
new file mode 100644
index 000000000..f2929dea8
--- /dev/null
+++ b/src/NzbDrone.Core.Test/MediaFiles/TrackImport/Specifications/MatchesGrabSpecificationFixture.cs
@@ -0,0 +1,125 @@
+// using System.Collections.Generic;
+// using System.Linq;
+// using FizzWare.NBuilder;
+// using FluentAssertions;
+// using Moq;
+// using NUnit.Framework;
+// using NzbDrone.Common.Extensions;
+// using NzbDrone.Core.Download;
+// using NzbDrone.Core.History;
+// using NzbDrone.Core.MediaFiles.EpisodeImport.Specifications;
+// using NzbDrone.Core.Music;
+// using NzbDrone.Core.Parser.Model;
+// using NzbDrone.Core.Test.Framework;
+// using NzbDrone.Test.Common;
+//
+// namespace NzbDrone.Core.Test.MediaFiles.EpisodeImport.Specifications
+// {
+// [TestFixture]
+// public class MatchesGrabSpecificationFixture : CoreTest
+// {
+// private Episode _episode1;
+// private Episode _episode2;
+// private Episode _episode3;
+// private LocalEpisode _localEpisode;
+// private DownloadClientItem _downloadClientItem;
+//
+// [SetUp]
+// public void Setup()
+// {
+// _episode1 = Builder.CreateNew()
+// .With(e => e.Id = 1)
+// .Build();
+//
+// _episode2 = Builder.CreateNew()
+// .With(e => e.Id = 2)
+// .Build();
+//
+// _episode3 = Builder.CreateNew()
+// .With(e => e.Id = 3)
+// .Build();
+//
+// _localEpisode = Builder.CreateNew()
+// .With(l => l.Path = @"C:\Test\Unsorted\Series.Title.S01E01.720p.HDTV-Sonarr\S01E05.mkv".AsOsAgnostic())
+// .With(l => l.Episodes = new List { _episode1 })
+// .With(l => l.Release = null)
+// .Build();
+//
+// _downloadClientItem = Builder.CreateNew().Build();
+// }
+//
+// private void GivenHistoryForEpisodes(params Episode[] episodes)
+// {
+// if (episodes.Empty())
+// {
+// return;
+// }
+//
+// var grabbedHistories = Builder.CreateListOfSize(episodes.Length)
+// .All()
+// .With(h => h.EventType == EpisodeHistoryEventType.Grabbed)
+// .BuildList();
+//
+// for (var i = 0; i < grabbedHistories.Count; i++)
+// {
+// grabbedHistories[i].EpisodeId = episodes[i].Id;
+// }
+//
+// _localEpisode.Release = new GrabbedReleaseInfo(grabbedHistories);
+// }
+//
+// [Test]
+// public void should_be_accepted_for_existing_file()
+// {
+// _localEpisode.ExistingFile = true;
+//
+// Subject.IsSatisfiedBy(_localEpisode, null).Accepted.Should().BeTrue();
+// }
+//
+// [Test]
+// public void should_be_accepted_if_no_download_client_item()
+// {
+// Subject.IsSatisfiedBy(_localEpisode, null).Accepted.Should().BeTrue();
+// }
+//
+// [Test]
+// public void should_be_accepted_if_no_grabbed_release_info()
+// {
+// GivenHistoryForEpisodes();
+//
+// Subject.IsSatisfiedBy(_localEpisode, _downloadClientItem).Accepted.Should().BeTrue();
+// }
+//
+// [Test]
+// public void should_be_accepted_if_file_episode_matches_single_grabbed_release_info()
+// {
+// GivenHistoryForEpisodes(_episode1);
+//
+// Subject.IsSatisfiedBy(_localEpisode, _downloadClientItem).Accepted.Should().BeTrue();
+// }
+//
+// [Test]
+// public void should_be_accepted_if_file_episode_is_in_multi_episode_grabbed_release_info()
+// {
+// GivenHistoryForEpisodes(_episode1, _episode2);
+//
+// Subject.IsSatisfiedBy(_localEpisode, _downloadClientItem).Accepted.Should().BeTrue();
+// }
+//
+// [Test]
+// public void should_be_rejected_if_file_episode_does_not_match_single_grabbed_release_info()
+// {
+// GivenHistoryForEpisodes(_episode2);
+//
+// Subject.IsSatisfiedBy(_localEpisode, _downloadClientItem).Accepted.Should().BeFalse();
+// }
+//
+// [Test]
+// public void should_be_rejected_if_file_episode_is_not_in_multi_episode_grabbed_release_info()
+// {
+// GivenHistoryForEpisodes(_episode2, _episode3);
+//
+// Subject.IsSatisfiedBy(_localEpisode, _downloadClientItem).Accepted.Should().BeFalse();
+// }
+// }
+// }
diff --git a/src/NzbDrone.Core.Test/NotificationTests/NotificationBaseFixture.cs b/src/NzbDrone.Core.Test/NotificationTests/NotificationBaseFixture.cs
index 7e7f0647c..518d8c00f 100644
--- a/src/NzbDrone.Core.Test/NotificationTests/NotificationBaseFixture.cs
+++ b/src/NzbDrone.Core.Test/NotificationTests/NotificationBaseFixture.cs
@@ -103,6 +103,11 @@ namespace NzbDrone.Core.Test.NotificationTests
{
TestLogger.Info("OnApplicationUpdate was called");
}
+
+ public override void OnManualInteractionRequired(ManualInteractionRequiredMessage message)
+ {
+ TestLogger.Info("OnManualInteractionRequired was called");
+ }
}
private class TestNotificationWithNoEvents : NotificationBase
@@ -143,6 +148,7 @@ namespace NzbDrone.Core.Test.NotificationTests
notification.SupportsOnImportFailure.Should().BeTrue();
notification.SupportsOnTrackRetag.Should().BeTrue();
notification.SupportsOnApplicationUpdate.Should().BeTrue();
+ notification.SupportsOnManualInteractionRequired.Should().BeTrue();
notification.SupportsOnAlbumDelete.Should().BeTrue();
notification.SupportsOnArtistDelete.Should().BeTrue();
}
@@ -162,6 +168,7 @@ namespace NzbDrone.Core.Test.NotificationTests
notification.SupportsOnImportFailure.Should().BeFalse();
notification.SupportsOnTrackRetag.Should().BeFalse();
notification.SupportsOnApplicationUpdate.Should().BeFalse();
+ notification.SupportsOnManualInteractionRequired.Should().BeFalse();
notification.SupportsOnAlbumDelete.Should().BeFalse();
notification.SupportsOnArtistDelete.Should().BeFalse();
}
diff --git a/src/NzbDrone.Core/Datastore/Migration/067_add_on_manual_interaction_required_to_notifications.cs b/src/NzbDrone.Core/Datastore/Migration/067_add_on_manual_interaction_required_to_notifications.cs
new file mode 100644
index 000000000..783adf47b
--- /dev/null
+++ b/src/NzbDrone.Core/Datastore/Migration/067_add_on_manual_interaction_required_to_notifications.cs
@@ -0,0 +1,14 @@
+using FluentMigrator;
+using NzbDrone.Core.Datastore.Migration.Framework;
+
+namespace NzbDrone.Core.Datastore.Migration
+{
+ [Migration(067)]
+ public class add_on_manual_interaction_required_to_notifications : NzbDroneMigrationBase
+ {
+ protected override void MainDbUpgrade()
+ {
+ Alter.Table("Notifications").AddColumn("OnManualInteractionRequired").AsBoolean().WithDefaultValue(false);
+ }
+ }
+}
diff --git a/src/NzbDrone.Core/Datastore/TableMapping.cs b/src/NzbDrone.Core/Datastore/TableMapping.cs
index ca9052f58..cb8ee6183 100644
--- a/src/NzbDrone.Core/Datastore/TableMapping.cs
+++ b/src/NzbDrone.Core/Datastore/TableMapping.cs
@@ -91,7 +91,8 @@ namespace NzbDrone.Core.Datastore
.Ignore(i => i.SupportsOnDownloadFailure)
.Ignore(i => i.SupportsOnImportFailure)
.Ignore(i => i.SupportsOnTrackRetag)
- .Ignore(i => i.SupportsOnApplicationUpdate);
+ .Ignore(i => i.SupportsOnApplicationUpdate)
+ .Ignore(i => i.SupportsOnManualInteractionRequired);
Mapper.Entity("Metadata").RegisterModel()
.Ignore(x => x.ImplementationName)
diff --git a/src/NzbDrone.Core/Download/CompletedDownloadService.cs b/src/NzbDrone.Core/Download/CompletedDownloadService.cs
index 0f27bda99..59b96a262 100644
--- a/src/NzbDrone.Core/Download/CompletedDownloadService.cs
+++ b/src/NzbDrone.Core/Download/CompletedDownloadService.cs
@@ -69,7 +69,8 @@ namespace NzbDrone.Core.Download
return;
}
- var historyItem = _historyService.MostRecentForDownloadId(trackedDownload.DownloadItem.DownloadId);
+ var grabbedHistories = _historyService.FindByDownloadId(trackedDownload.DownloadItem.DownloadId).Where(h => h.EventType == EntityHistoryEventType.Grabbed).ToList();
+ var historyItem = grabbedHistories.MaxBy(h => h.Date);
if (historyItem == null && trackedDownload.DownloadItem.Category.IsNullOrWhiteSpace())
{
diff --git a/src/NzbDrone.Core/Download/ManualInteractionRequiredEvent.cs b/src/NzbDrone.Core/Download/ManualInteractionRequiredEvent.cs
new file mode 100644
index 000000000..fc0b2395f
--- /dev/null
+++ b/src/NzbDrone.Core/Download/ManualInteractionRequiredEvent.cs
@@ -0,0 +1,20 @@
+using NzbDrone.Common.Messaging;
+using NzbDrone.Core.Download.TrackedDownloads;
+using NzbDrone.Core.Parser.Model;
+
+namespace NzbDrone.Core.Download
+{
+ public class ManualInteractionRequiredEvent : IEvent
+ {
+ public RemoteAlbum Album { get; private set; }
+ public TrackedDownload TrackedDownload { get; private set; }
+ public GrabbedReleaseInfo Release { get; private set; }
+
+ public ManualInteractionRequiredEvent(TrackedDownload trackedDownload, GrabbedReleaseInfo release)
+ {
+ TrackedDownload = trackedDownload;
+ Album = trackedDownload.RemoteAlbum;
+ Release = release;
+ }
+ }
+}
diff --git a/src/NzbDrone.Core/Download/TrackedDownloads/DownloadMonitoringService.cs b/src/NzbDrone.Core/Download/TrackedDownloads/DownloadMonitoringService.cs
index 79ec696b8..fc80a7b43 100644
--- a/src/NzbDrone.Core/Download/TrackedDownloads/DownloadMonitoringService.cs
+++ b/src/NzbDrone.Core/Download/TrackedDownloads/DownloadMonitoringService.cs
@@ -15,6 +15,7 @@ namespace NzbDrone.Core.Download.TrackedDownloads
IExecute,
IHandle,
IHandle,
+ IHandle,
IHandle,
IHandle
{
@@ -166,6 +167,11 @@ namespace NzbDrone.Core.Download.TrackedDownloads
_refreshDebounce.Execute();
}
+ public void Handle(ManualInteractionRequiredEvent message)
+ {
+ _refreshDebounce.Execute();
+ }
+
public void Handle(TrackImportedEvent message)
{
_refreshDebounce.Execute();
diff --git a/src/NzbDrone.Core/Download/TrackedDownloads/TrackedDownload.cs b/src/NzbDrone.Core/Download/TrackedDownloads/TrackedDownload.cs
index e12949bd1..7acc81d3c 100644
--- a/src/NzbDrone.Core/Download/TrackedDownloads/TrackedDownload.cs
+++ b/src/NzbDrone.Core/Download/TrackedDownloads/TrackedDownload.cs
@@ -1,3 +1,4 @@
+using System;
using NzbDrone.Core.Indexers;
using NzbDrone.Core.Parser.Model;
@@ -15,10 +16,11 @@ namespace NzbDrone.Core.Download.TrackedDownloads
public DownloadProtocol Protocol { get; set; }
public string Indexer { get; set; }
public bool IsTrackable { get; set; }
+ public bool HasNotifiedManualInteractionRequired { get; set; }
public TrackedDownload()
{
- StatusMessages = System.Array.Empty();
+ StatusMessages = Array.Empty();
}
public void Warn(string message, params object[] args)
diff --git a/src/NzbDrone.Core/Download/TrackedDownloads/TrackedDownloadService.cs b/src/NzbDrone.Core/Download/TrackedDownloads/TrackedDownloadService.cs
index 6de46407c..9a8caa6b6 100644
--- a/src/NzbDrone.Core/Download/TrackedDownloads/TrackedDownloadService.cs
+++ b/src/NzbDrone.Core/Download/TrackedDownloads/TrackedDownloadService.cs
@@ -108,7 +108,8 @@ namespace NzbDrone.Core.Download.TrackedDownloads
DownloadClient = downloadClient.Id,
DownloadItem = downloadItem,
Protocol = downloadClient.Protocol,
- IsTrackable = true
+ IsTrackable = true,
+ HasNotifiedManualInteractionRequired = existingItem?.HasNotifiedManualInteractionRequired ?? false
};
try
diff --git a/src/NzbDrone.Core/MediaFiles/TrackImport/Aggregation/Aggregators/AggregateReleaseInfo.cs b/src/NzbDrone.Core/MediaFiles/TrackImport/Aggregation/Aggregators/AggregateReleaseInfo.cs
new file mode 100644
index 000000000..b43ab28ea
--- /dev/null
+++ b/src/NzbDrone.Core/MediaFiles/TrackImport/Aggregation/Aggregators/AggregateReleaseInfo.cs
@@ -0,0 +1,39 @@
+using System.Linq;
+using NzbDrone.Common.Extensions;
+using NzbDrone.Core.Download;
+using NzbDrone.Core.History;
+using NzbDrone.Core.Parser.Model;
+
+namespace NzbDrone.Core.MediaFiles.TrackImport.Aggregation.Aggregators
+{
+ // public class AggregateReleaseInfo : IAggregateLocalEpisode
+ // {
+ // private readonly IHistoryService _historyService;
+ //
+ // public AggregateReleaseInfo(IHistoryService historyService)
+ // {
+ // _historyService = historyService;
+ // }
+ //
+ // public LocalTrack Aggregate(LocalTrack localTrack, DownloadClientItem downloadClientItem)
+ // {
+ // if (downloadClientItem == null)
+ // {
+ // return localTrack;
+ // }
+ //
+ // var grabbedHistories = _historyService.FindByDownloadId(downloadClientItem.DownloadId)
+ // .Where(h => h.EventType == TrackHistoryEventType.Grabbed)
+ // .ToList();
+ //
+ // if (grabbedHistories.Empty())
+ // {
+ // return localTrack;
+ // }
+ //
+ // localTrack.Release = new GrabbedReleaseInfo(grabbedHistories);
+ //
+ // return localTrack;
+ // }
+ // }
+}
diff --git a/src/NzbDrone.Core/Notifications/Apprise/Apprise.cs b/src/NzbDrone.Core/Notifications/Apprise/Apprise.cs
index 59dc96f4f..b830a8935 100644
--- a/src/NzbDrone.Core/Notifications/Apprise/Apprise.cs
+++ b/src/NzbDrone.Core/Notifications/Apprise/Apprise.cs
@@ -62,6 +62,11 @@ namespace NzbDrone.Core.Notifications.Apprise
_proxy.SendNotification(APPLICATION_UPDATE_TITLE, updateMessage.Message, Settings);
}
+ public override void OnManualInteractionRequired(ManualInteractionRequiredMessage message)
+ {
+ _proxy.SendNotification(MANUAL_INTERACTION_REQUIRED_TITLE, message.Message, Settings);
+ }
+
public override ValidationResult Test()
{
var failures = new List();
diff --git a/src/NzbDrone.Core/Notifications/Boxcar/Boxcar.cs b/src/NzbDrone.Core/Notifications/Boxcar/Boxcar.cs
index 9607ce326..ed9d5feaf 100644
--- a/src/NzbDrone.Core/Notifications/Boxcar/Boxcar.cs
+++ b/src/NzbDrone.Core/Notifications/Boxcar/Boxcar.cs
@@ -61,6 +61,11 @@ namespace NzbDrone.Core.Notifications.Boxcar
_proxy.SendNotification(APPLICATION_UPDATE_TITLE, message.Message, Settings);
}
+ public override void OnManualInteractionRequired(ManualInteractionRequiredMessage message)
+ {
+ _proxy.SendNotification(MANUAL_INTERACTION_REQUIRED_TITLE, message.Message, Settings);
+ }
+
public override ValidationResult Test()
{
var failures = new List();
diff --git a/src/NzbDrone.Core/Notifications/CustomScript/CustomScript.cs b/src/NzbDrone.Core/Notifications/CustomScript/CustomScript.cs
index 83aac352c..e1c14ff41 100644
--- a/src/NzbDrone.Core/Notifications/CustomScript/CustomScript.cs
+++ b/src/NzbDrone.Core/Notifications/CustomScript/CustomScript.cs
@@ -258,6 +258,27 @@ namespace NzbDrone.Core.Notifications.CustomScript
ExecuteScript(environmentVariables);
}
+ public override void OnManualInteractionRequired(ManualInteractionRequiredMessage message)
+ {
+ var artist = message.Artist;
+ var environmentVariables = new StringDictionary();
+
+ environmentVariables.Add("Lidarr_EventType", "ManualInteractionRequired");
+ environmentVariables.Add("Lidarr_InstanceName", _configFileProvider.InstanceName);
+ environmentVariables.Add("Lidarr_ApplicationUrl", _configService.ApplicationUrl);
+ environmentVariables.Add("Lidarr_Artist_Id", artist.Id.ToString());
+ environmentVariables.Add("Lidarr_Artist_Name", artist.Metadata.Value.Name);
+ environmentVariables.Add("Lidarr_Artist_MBId", artist.Metadata.Value.ForeignArtistId);
+ environmentVariables.Add("Lidarr_Artist_Type", artist.Metadata.Value.Type);
+ environmentVariables.Add("Lidarr_Download_Client", message.DownloadClientName ?? string.Empty);
+ environmentVariables.Add("Lidarr_Download_Client_Type", message.DownloadClientType ?? string.Empty);
+ environmentVariables.Add("Lidarr_Download_Id", message.DownloadId ?? string.Empty);
+ environmentVariables.Add("Lidarr_Download_Size", message.TrackedDownload.DownloadItem.TotalSize.ToString());
+ environmentVariables.Add("Lidarr_Download_Title", message.TrackedDownload.DownloadItem.Title);
+
+ 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
index 865951f6b..e7b12c93e 100644
--- a/src/NzbDrone.Core/Notifications/Discord/Discord.cs
+++ b/src/NzbDrone.Core/Notifications/Discord/Discord.cs
@@ -408,6 +408,97 @@ namespace NzbDrone.Core.Notifications.Discord
_proxy.SendPayload(payload, Settings);
}
+ public override void OnManualInteractionRequired(ManualInteractionRequiredMessage message)
+ {
+ var artist = message.Artist;
+ var albums = message.RemoteAlbum.Albums;
+ var artistMetadata = message.Artist.Metadata.Value;
+
+ var embed = new Embed
+ {
+ Author = new DiscordAuthor
+ {
+ Name = Settings.Author.IsNullOrWhiteSpace() ? Environment.MachineName : Settings.Author,
+ IconUrl = "https://raw.githubusercontent.com/Lidarr/Lidarr/develop/Logo/256.png"
+ },
+ Url = $"https://musicbrainz.org/artist/{artist.ForeignArtistId}",
+ Description = "Manual interaction needed",
+ Title = GetTitle(artist, albums),
+ Color = (int)DiscordColors.Standard,
+ Fields = new List(),
+ Timestamp = DateTime.UtcNow.ToString("yyyy-MM-ddTHH:mm:ss.fffZ")
+ };
+
+ if (Settings.ManualInteractionFields.Contains((int)DiscordGrabFieldType.Poster))
+ {
+ embed.Thumbnail = new DiscordImage
+ {
+ Url = albums.First().Images.FirstOrDefault(x => x.CoverType == MediaCoverTypes.Poster)?.Url
+ };
+ }
+
+ if (Settings.ManualInteractionFields.Contains((int)DiscordGrabFieldType.Fanart))
+ {
+ embed.Image = new DiscordImage
+ {
+ Url = artistMetadata.Images.FirstOrDefault(x => x.CoverType == MediaCoverTypes.Fanart)?.Url
+ };
+ }
+
+ foreach (var field in Settings.ManualInteractionFields)
+ {
+ var discordField = new DiscordField();
+
+ switch ((DiscordManualInteractionFieldType)field)
+ {
+ case DiscordManualInteractionFieldType.Overview:
+ var overview = albums.First().Overview ?? "";
+ discordField.Name = "Overview";
+ discordField.Value = overview.Length <= 300 ? overview : $"{overview.AsSpan(0, 300)}...";
+ break;
+ case DiscordManualInteractionFieldType.Rating:
+ discordField.Name = "Rating";
+ discordField.Value = albums.First().Ratings.Value.ToString();
+ break;
+ case DiscordManualInteractionFieldType.Genres:
+ discordField.Name = "Genres";
+ discordField.Value = albums.First().Genres.Take(5).Join(", ");
+ break;
+ case DiscordManualInteractionFieldType.Quality:
+ discordField.Name = "Quality";
+ discordField.Inline = true;
+ discordField.Value = message.Quality.Quality.Name;
+ break;
+ case DiscordManualInteractionFieldType.Group:
+ discordField.Name = "Group";
+ discordField.Value = message.RemoteAlbum.ParsedAlbumInfo.ReleaseGroup;
+ break;
+ case DiscordManualInteractionFieldType.Size:
+ discordField.Name = "Size";
+ discordField.Value = BytesToString(message.RemoteAlbum.Release.Size);
+ discordField.Inline = true;
+ break;
+ case DiscordManualInteractionFieldType.DownloadTitle:
+ discordField.Name = "Download";
+ discordField.Value = string.Format("```{0}```", message.TrackedDownload.DownloadItem.Title);
+ break;
+ case DiscordManualInteractionFieldType.Links:
+ discordField.Name = "Links";
+ discordField.Value = GetLinksString(artist);
+ break;
+ }
+
+ if (discordField.Name.IsNotNullOrWhiteSpace() && discordField.Value.IsNotNullOrWhiteSpace())
+ {
+ embed.Fields.Add(discordField);
+ }
+ }
+
+ var payload = CreatePayload(null, new List