From d96775a4a326a05c633475c9a21a519326732983 Mon Sep 17 00:00:00 2001 From: Thomas White Date: Mon, 18 Jul 2022 22:25:48 +0100 Subject: [PATCH] Fixed: "Specific Book" setting for lidarr list import Fixes #2435 (cherry picked from commit 466876da624843f62c849dfb28ac9515b6fe3a2c) --- .../ImportListSyncServiceFixture.cs | 35 ++++++ .../ImportLists/ImportListSyncService.cs | 115 ++++++++++-------- .../ImportLists/Lidarr/LidarrAPIResource.cs | 12 ++ .../ImportLists/Lidarr/LidarrImport.cs | 19 ++- .../ImportLists/Lidarr/LidarrV1Proxy.cs | 6 + .../Music/Services/AlbumMonitoredService.cs | 4 +- 6 files changed, 134 insertions(+), 57 deletions(-) diff --git a/src/NzbDrone.Core.Test/ImportListTests/ImportListSyncServiceFixture.cs b/src/NzbDrone.Core.Test/ImportListTests/ImportListSyncServiceFixture.cs index 285623b347..58cea4fe79 100644 --- a/src/NzbDrone.Core.Test/ImportListTests/ImportListSyncServiceFixture.cs +++ b/src/NzbDrone.Core.Test/ImportListTests/ImportListSyncServiceFixture.cs @@ -73,6 +73,18 @@ private void WithAlbumId() _importListReports.First().AlbumMusicBrainzId = "09474d62-17dd-3a4f-98fb-04c65f38a479"; } + private void WithSecondBook() + { + var importListItem2 = new ImportListItemInfo + { + Artist = "Linkin Park", + ArtistMusicBrainzId = "f59c5520-5f46-4d2c-b2c4-822eabf53419", + Album = "Meteora 2", + AlbumMusicBrainzId = "madeup" + }; + _importListReports.Add(importListItem2); + } + private void WithExistingArtist() { Mocker.GetMock() @@ -275,5 +287,28 @@ public void should_not_add_album_if_excluded_artist() Mocker.GetMock() .Verify(v => v.AddAlbums(It.Is>(t => t.Count == 0), false, It.IsAny())); } + + [TestCase(ImportListMonitorType.None, 0, false)] + [TestCase(ImportListMonitorType.SpecificAlbum, 2, true)] + [TestCase(ImportListMonitorType.EntireArtist, 0, true)] + public void should_add_two_albums(ImportListMonitorType monitor, int expectedAlbumsMonitored, bool expectedArtistMonitored) + { + WithAlbum(); + WithAlbumId(); + WithSecondBook(); + WithArtistId(); + WithMonitorType(monitor); + + Subject.Execute(new ImportListSyncCommand()); + + Mocker.GetMock() + .Verify(v => v.AddAlbums(It.Is>(t => t.Count == 2), false, true)); + Mocker.GetMock() + .Verify(v => v.AddArtists(It.Is>(t => t.Count == 1 && + t.First().AddOptions.AlbumsToMonitor.Count == expectedAlbumsMonitored && + t.First().Monitored == expectedArtistMonitored), + false, + true)); + } } } diff --git a/src/NzbDrone.Core/ImportLists/ImportListSyncService.cs b/src/NzbDrone.Core/ImportLists/ImportListSyncService.cs index a3bd29a546..b8eca4c3c0 100644 --- a/src/NzbDrone.Core/ImportLists/ImportListSyncService.cs +++ b/src/NzbDrone.Core/ImportLists/ImportListSyncService.cs @@ -104,7 +104,7 @@ private List ProcessReports(List reports) MapAlbumReport(report); } - ProcessAlbumReport(importList, report, listExclusions, albumsToAdd); + ProcessAlbumReport(importList, report, listExclusions, albumsToAdd, artistsToAdd); } else if (report.Artist.IsNotNullOrWhiteSpace() || report.ArtistMusicBrainzId.IsNotNullOrWhiteSpace()) { @@ -147,11 +147,11 @@ private void MapAlbumReport(ImportListItemInfo report) report.AlbumMusicBrainzId = mappedAlbum.ForeignAlbumId; report.Album = mappedAlbum.Title; - report.Artist = mappedAlbum.ArtistMetadata?.Value?.Name; - report.ArtistMusicBrainzId = mappedAlbum.ArtistMetadata?.Value?.ForeignArtistId; + report.Artist ??= mappedAlbum.ArtistMetadata?.Value?.Name; + report.ArtistMusicBrainzId ??= mappedAlbum.ArtistMetadata?.Value?.ForeignArtistId; } - private void ProcessAlbumReport(ImportListDefinition importList, ImportListItemInfo report, List listExclusions, List albumsToAdd) + private void ProcessAlbumReport(ImportListDefinition importList, ImportListItemInfo report, List listExclusions, List albumsToAdd, List artistsToAdd) { if (report.AlbumMusicBrainzId == null) { @@ -169,13 +169,13 @@ private void ProcessAlbumReport(ImportListDefinition importList, ImportListItemI if (excludedAlbum != null) { - _logger.Debug("{0} [{1}] Rejected due to list exlcusion", report.AlbumMusicBrainzId, report.Album); + _logger.Debug("{0} [{1}] Rejected due to list exclusion", report.AlbumMusicBrainzId, report.Album); return; } if (excludedArtist != null) { - _logger.Debug("{0} [{1}] Rejected due to list exlcusion for parent artist", report.AlbumMusicBrainzId, report.Album); + _logger.Debug("{0} [{1}] Rejected due to list exclusion for parent artist", report.AlbumMusicBrainzId, report.Album); return; } @@ -211,25 +211,32 @@ private void ProcessAlbumReport(ImportListDefinition importList, ImportListItemI { var monitored = importList.ShouldMonitor != ImportListMonitorType.None; + var toAddArtist = new Artist + { + Monitored = monitored, + RootFolderPath = importList.RootFolderPath, + QualityProfileId = importList.ProfileId, + MetadataProfileId = importList.MetadataProfileId, + Tags = importList.Tags, + AddOptions = new AddArtistOptions + { + SearchForMissingAlbums = monitored, + Monitored = monitored, + Monitor = monitored ? MonitorTypes.All : MonitorTypes.None + } + }; + + if (report.ArtistMusicBrainzId != null && report.Artist != null) + { + toAddArtist = ProcessArtistReport(importList, report, listExclusions, artistsToAdd); + } + var toAdd = new Album { ForeignAlbumId = report.AlbumMusicBrainzId, Monitored = monitored, AnyReleaseOk = true, - Artist = new Artist - { - Monitored = monitored, - RootFolderPath = importList.RootFolderPath, - QualityProfileId = importList.ProfileId, - MetadataProfileId = importList.MetadataProfileId, - Tags = importList.Tags, - AddOptions = new AddArtistOptions - { - SearchForMissingAlbums = monitored, - Monitored = monitored, - Monitor = monitored ? MonitorTypes.All : MonitorTypes.None - } - }, + Artist = toAddArtist, AddOptions = new AddAlbumOptions { SearchForNewAlbum = monitored @@ -238,7 +245,7 @@ private void ProcessAlbumReport(ImportListDefinition importList, ImportListItemI if (importList.ShouldMonitor == ImportListMonitorType.SpecificAlbum) { - toAdd.Artist.Value.AddOptions.AlbumsToMonitor.Add(toAdd.ForeignAlbumId); + toAddArtist.AddOptions.AlbumsToMonitor.Add(toAdd.ForeignAlbumId); } albumsToAdd.Add(toAdd); @@ -253,11 +260,11 @@ private void MapArtistReport(ImportListItemInfo report) report.Artist = mappedArtist?.Metadata.Value?.Name; } - private void ProcessArtistReport(ImportListDefinition importList, ImportListItemInfo report, List listExclusions, List artistsToAdd) + private Artist ProcessArtistReport(ImportListDefinition importList, ImportListItemInfo report, List listExclusions, List artistsToAdd) { if (report.ArtistMusicBrainzId == null) { - return; + return null; } // Check to see if artist in DB @@ -266,15 +273,18 @@ private void ProcessArtistReport(ImportListDefinition importList, ImportListItem // Check to see if artist excluded var excludedArtist = listExclusions.Where(s => s.ForeignId == report.ArtistMusicBrainzId).SingleOrDefault(); + // Check to see if artist in import + var existingImportArtist = artistsToAdd.Find(i => i.ForeignArtistId == report.ArtistMusicBrainzId); + if (excludedArtist != null) { - _logger.Debug("{0} [{1}] Rejected due to list exlcusion", report.ArtistMusicBrainzId, report.Artist); - return; + _logger.Debug("{0} [{1}] Rejected due to list exclusion", report.ArtistMusicBrainzId, report.Artist); + return null; } if (existingArtist != null) { - _logger.Debug("{0} [{1}] Rejected, Author Exists in DB. Ensuring Author monitored", report.ArtistMusicBrainzId, report.Artist); + _logger.Debug("{0} [{1}] Rejected, artist exists in DB. Ensuring artist monitored", report.ArtistMusicBrainzId, report.Artist); if (!existingArtist.Monitored) { @@ -282,35 +292,42 @@ private void ProcessArtistReport(ImportListDefinition importList, ImportListItem _artistService.UpdateArtist(existingArtist); } - return; + return existingArtist; } - // Append Artist if not already in DB or already on add list - if (artistsToAdd.All(s => s.Metadata.Value.ForeignArtistId != report.ArtistMusicBrainzId)) + if (existingImportArtist != null) { - var monitored = importList.ShouldMonitor != ImportListMonitorType.None; + _logger.Debug("{0} [{1}] Rejected, artist exists in Import.", report.ArtistMusicBrainzId, report.Artist); + + return existingImportArtist; + } + + var monitored = importList.ShouldMonitor != ImportListMonitorType.None; - artistsToAdd.Add(new Artist + var toAdd = new Artist + { + Metadata = new ArtistMetadata { - Metadata = new ArtistMetadata - { - ForeignArtistId = report.ArtistMusicBrainzId, - Name = report.Artist - }, + ForeignArtistId = report.ArtistMusicBrainzId, + Name = report.Artist + }, + Monitored = monitored, + MonitorNewItems = importList.MonitorNewItems, + RootFolderPath = importList.RootFolderPath, + QualityProfileId = importList.ProfileId, + MetadataProfileId = importList.MetadataProfileId, + Tags = importList.Tags, + AddOptions = new AddArtistOptions + { + SearchForMissingAlbums = monitored, Monitored = monitored, - MonitorNewItems = importList.MonitorNewItems, - RootFolderPath = importList.RootFolderPath, - QualityProfileId = importList.ProfileId, - MetadataProfileId = importList.MetadataProfileId, - Tags = importList.Tags, - AddOptions = new AddArtistOptions - { - SearchForMissingAlbums = monitored, - Monitored = monitored, - Monitor = monitored ? MonitorTypes.All : MonitorTypes.None - } - }); - } + Monitor = monitored ? MonitorTypes.All : MonitorTypes.None + } + }; + + artistsToAdd.Add(toAdd); + + return toAdd; } public void Execute(ImportListSyncCommand message) diff --git a/src/NzbDrone.Core/ImportLists/Lidarr/LidarrAPIResource.cs b/src/NzbDrone.Core/ImportLists/Lidarr/LidarrAPIResource.cs index 0634e8ab90..6ba3b81e0d 100644 --- a/src/NzbDrone.Core/ImportLists/Lidarr/LidarrAPIResource.cs +++ b/src/NzbDrone.Core/ImportLists/Lidarr/LidarrAPIResource.cs @@ -4,6 +4,7 @@ namespace NzbDrone.Core.ImportLists.Lidarr { public class LidarrArtist { + public int Id { get; set; } public string ArtistName { get; set; } public string ForeignArtistId { get; set; } public string Overview { get; set; } @@ -13,6 +14,17 @@ public class LidarrArtist public HashSet Tags { get; set; } } + public class LidarrAlbum + { + public int ArtistId { get; set; } + public string Title { get; set; } + public string ForeignAlbumId { get; set; } + public string Overview { get; set; } + public List Images { get; set; } + public bool Monitored { get; set; } + public LidarrArtist Artist { get; set; } + } + public class LidarrProfile { public string Name { get; set; } diff --git a/src/NzbDrone.Core/ImportLists/Lidarr/LidarrImport.cs b/src/NzbDrone.Core/ImportLists/Lidarr/LidarrImport.cs index 1aebdbeb18..209969410d 100644 --- a/src/NzbDrone.Core/ImportLists/Lidarr/LidarrImport.cs +++ b/src/NzbDrone.Core/ImportLists/Lidarr/LidarrImport.cs @@ -30,21 +30,28 @@ public class LidarrImport : ImportListBase public override IList Fetch() { - var artists = new List(); + var artistsAndAlbums = new List(); try { + var remoteAlbums = _lidarrV1Proxy.GetAlbums(Settings); var remoteArtists = _lidarrV1Proxy.GetArtists(Settings); - foreach (var remoteArtist in remoteArtists) + var artistDict = remoteArtists.ToDictionary(x => x.Id); + + foreach (var remoteAlbum in remoteAlbums) { + var remoteArtist = artistDict[remoteAlbum.ArtistId]; if ((!Settings.ProfileIds.Any() || Settings.ProfileIds.Contains(remoteArtist.QualityProfileId)) && - (!Settings.TagIds.Any() || Settings.TagIds.Any(x => remoteArtist.Tags.Any(y => y == x)))) + (!Settings.TagIds.Any() || Settings.TagIds.Any(x => remoteArtist.Tags.Any(y => y == x))) && + remoteAlbum.Monitored && remoteArtist.Monitored) { - artists.Add(new ImportListItemInfo + artistsAndAlbums.Add(new ImportListItemInfo { ArtistMusicBrainzId = remoteArtist.ForeignArtistId, - Artist = remoteArtist.ArtistName + Artist = remoteArtist.ArtistName, + AlbumMusicBrainzId = remoteAlbum.ForeignAlbumId, + Album = remoteAlbum.Title }); } } @@ -56,7 +63,7 @@ public override IList Fetch() _importListStatusService.RecordFailure(Definition.Id); } - return CleanupListItems(artists); + return CleanupListItems(artistsAndAlbums); } public override object RequestAction(string action, IDictionary query) diff --git a/src/NzbDrone.Core/ImportLists/Lidarr/LidarrV1Proxy.cs b/src/NzbDrone.Core/ImportLists/Lidarr/LidarrV1Proxy.cs index 6d4459a625..a3ebacb652 100644 --- a/src/NzbDrone.Core/ImportLists/Lidarr/LidarrV1Proxy.cs +++ b/src/NzbDrone.Core/ImportLists/Lidarr/LidarrV1Proxy.cs @@ -12,6 +12,7 @@ namespace NzbDrone.Core.ImportLists.Lidarr public interface ILidarrV1Proxy { List GetArtists(LidarrSettings settings); + List GetAlbums(LidarrSettings settings); List GetProfiles(LidarrSettings settings); List GetTags(LidarrSettings settings); ValidationFailure Test(LidarrSettings settings); @@ -33,6 +34,11 @@ public List GetArtists(LidarrSettings settings) return Execute("/api/v1/artist", settings); } + public List GetAlbums(LidarrSettings settings) + { + return Execute("/api/v1/album", settings); + } + public List GetProfiles(LidarrSettings settings) { return Execute("/api/v1/qualityprofile", settings); diff --git a/src/NzbDrone.Core/Music/Services/AlbumMonitoredService.cs b/src/NzbDrone.Core/Music/Services/AlbumMonitoredService.cs index 137d0ac554..4b747074b5 100644 --- a/src/NzbDrone.Core/Music/Services/AlbumMonitoredService.cs +++ b/src/NzbDrone.Core/Music/Services/AlbumMonitoredService.cs @@ -41,9 +41,9 @@ public void SetAlbumMonitoredStatus(Artist artist, MonitoringOptions monitoringO if (monitoredAlbums.Any()) { ToggleAlbumsMonitoredState( - albums.Where(s => monitoredAlbums.Any(t => t == s.ForeignAlbumId)), true); + albums.Where(s => monitoredAlbums.Contains(s.ForeignAlbumId)), true); ToggleAlbumsMonitoredState( - albums.Where(s => monitoredAlbums.Any(t => t != s.ForeignAlbumId)), false); + albums.Where(s => !monitoredAlbums.Contains(s.ForeignAlbumId)), false); } else {