diff --git a/src/Lidarr.Api.V1/Artist/ArtistResource.cs b/src/Lidarr.Api.V1/Artist/ArtistResource.cs index dc6b32343..89b51f9eb 100644 --- a/src/Lidarr.Api.V1/Artist/ArtistResource.cs +++ b/src/Lidarr.Api.V1/Artist/ArtistResource.cs @@ -57,6 +57,7 @@ public class ArtistResource : RestResource public List Genres { get; set; } public string CleanName { get; set; } public string SortName { get; set; } + public List Aliases { get; set; } public HashSet Tags { get; set; } public DateTime Added { get; set; } public AddArtistOptions AddOptions { get; set; } @@ -101,6 +102,7 @@ public static ArtistResource ToResource(this NzbDrone.Core.Music.Artist model) CleanName = model.CleanName, ForeignArtistId = model.Metadata.Value.ForeignArtistId, + Aliases = model.Metadata.Value.Aliases, // Root folder path is now calculated from the artist path // RootFolderPath = model.RootFolderPath, @@ -133,7 +135,8 @@ public static NzbDrone.Core.Music.Artist ToModel(this ArtistResource resource) Images = resource.Images, Genres = resource.Genres, Ratings = resource.Ratings, - Type = resource.ArtistType + Type = resource.ArtistType, + Aliases = resource.Aliases }, // AlternateTitles diff --git a/src/NzbDrone.Core/IndexerSearch/Definitions/AlbumSearchCriteria.cs b/src/NzbDrone.Core/IndexerSearch/Definitions/AlbumSearchCriteria.cs index e66726149..47594ff13 100644 --- a/src/NzbDrone.Core/IndexerSearch/Definitions/AlbumSearchCriteria.cs +++ b/src/NzbDrone.Core/IndexerSearch/Definitions/AlbumSearchCriteria.cs @@ -13,7 +13,7 @@ public class AlbumSearchCriteria : SearchCriteriaBase public override string ToString() { - return $"[{Artist.Name} - {AlbumTitle}{(Disambiguation.IsNullOrWhiteSpace() ? string.Empty : $" ({Disambiguation})")} ({AlbumYear})]"; + return $"[{Artist.SearchName} - {AlbumTitle}{(Disambiguation.IsNullOrWhiteSpace() ? string.Empty : $" ({Disambiguation})")} ({AlbumYear})]"; } } } diff --git a/src/NzbDrone.Core/IndexerSearch/Definitions/SearchCriteriaBase.cs b/src/NzbDrone.Core/IndexerSearch/Definitions/SearchCriteriaBase.cs index b6e0b5a53..bcb8cd1d2 100644 --- a/src/NzbDrone.Core/IndexerSearch/Definitions/SearchCriteriaBase.cs +++ b/src/NzbDrone.Core/IndexerSearch/Definitions/SearchCriteriaBase.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Linq; using System.Text.RegularExpressions; using NzbDrone.Common.EnsureThat; using NzbDrone.Common.Extensions; @@ -19,9 +20,11 @@ public abstract class SearchCriteriaBase public Artist Artist { get; set; } public List Albums { get; set; } public List Tracks { get; set; } + public List ArtistTitles { get; set; } - public string ArtistQuery => Artist.Name; + public string ArtistQuery => Artist.SearchName; public string CleanArtistQuery => GetQueryTitle(ArtistQuery); + public List CleanArtistTitles => ArtistTitles?.Select(GetQueryTitle).Distinct().ToList() ?? new List { CleanArtistQuery }; public static string GetQueryTitle(string title) { diff --git a/src/NzbDrone.Core/IndexerSearch/ReleaseSearchService.cs b/src/NzbDrone.Core/IndexerSearch/ReleaseSearchService.cs index f8da27d52..904e61f5a 100644 --- a/src/NzbDrone.Core/IndexerSearch/ReleaseSearchService.cs +++ b/src/NzbDrone.Core/IndexerSearch/ReleaseSearchService.cs @@ -106,6 +106,15 @@ private TSpec Get(Artist artist, List albums, bool userInvokedSear spec.UserInvokedSearch = userInvokedSearch; spec.InteractiveSearch = interactiveSearch; + var artistTitles = new List { artist.Name }; + + if (artist.Metadata?.Value?.Aliases != null) + { + artistTitles.AddRange(artist.Metadata.Value.Aliases.Where(a => !string.IsNullOrWhiteSpace(a))); + } + + spec.ArtistTitles = artistTitles.Distinct(StringComparer.InvariantCultureIgnoreCase).ToList(); + return spec; } @@ -117,6 +126,15 @@ private static TSpec Get(Artist artist, bool userInvokedSearch, bool inte spec.UserInvokedSearch = userInvokedSearch; spec.InteractiveSearch = interactiveSearch; + var artistTitles = new List { artist.Name }; + + if (artist.Metadata?.Value?.Aliases != null) + { + artistTitles.AddRange(artist.Metadata.Value.Aliases.Where(a => !string.IsNullOrWhiteSpace(a))); + } + + spec.ArtistTitles = artistTitles.Distinct(StringComparer.InvariantCultureIgnoreCase).ToList(); + return spec; } diff --git a/src/NzbDrone.Core/Indexers/FileList/FileListRequestGenerator.cs b/src/NzbDrone.Core/Indexers/FileList/FileListRequestGenerator.cs index 653a94f9c..9a0fc0185 100644 --- a/src/NzbDrone.Core/Indexers/FileList/FileListRequestGenerator.cs +++ b/src/NzbDrone.Core/Indexers/FileList/FileListRequestGenerator.cs @@ -23,11 +23,13 @@ public virtual IndexerPageableRequestChain GetRecentRequests() public IndexerPageableRequestChain GetSearchRequests(AlbumSearchCriteria searchCriteria) { var pageableRequests = new IndexerPageableRequestChain(); - - var artistQuery = searchCriteria.CleanArtistQuery.Replace("+", " ").Trim(); var albumQuery = searchCriteria.CleanAlbumQuery.Replace("+", " ").Trim(); - pageableRequests.Add(GetRequest("search-torrents", Settings.Categories, string.Format("&type=name&query={0}+{1}", Uri.EscapeDataString(artistQuery), Uri.EscapeDataString(albumQuery)))); + foreach (var artistTitle in searchCriteria.CleanArtistTitles) + { + var artistQuery = artistTitle.Replace("+", " ").Trim(); + pageableRequests.Add(GetRequest("search-torrents", Settings.Categories, string.Format("&type=name&query={0}+{1}", Uri.EscapeDataString(artistQuery), Uri.EscapeDataString(albumQuery)))); + } return pageableRequests; } @@ -36,9 +38,11 @@ public IndexerPageableRequestChain GetSearchRequests(ArtistSearchCriteria search { var pageableRequests = new IndexerPageableRequestChain(); - var artistQuery = searchCriteria.CleanArtistQuery.Replace("+", " ").Trim(); - - pageableRequests.Add(GetRequest("search-torrents", Settings.Categories, string.Format("&type=name&query={0}", Uri.EscapeDataString(artistQuery)))); + foreach (var artistTitle in searchCriteria.CleanArtistTitles) + { + var artistQuery = artistTitle.Replace("+", " ").Trim(); + pageableRequests.Add(GetRequest("search-torrents", Settings.Categories, string.Format("&type=name&query={0}", Uri.EscapeDataString(artistQuery)))); + } return pageableRequests; } diff --git a/src/NzbDrone.Core/Indexers/Gazelle/GazelleRequestGenerator.cs b/src/NzbDrone.Core/Indexers/Gazelle/GazelleRequestGenerator.cs index ee3b553ef..5b5559ef0 100644 --- a/src/NzbDrone.Core/Indexers/Gazelle/GazelleRequestGenerator.cs +++ b/src/NzbDrone.Core/Indexers/Gazelle/GazelleRequestGenerator.cs @@ -32,13 +32,16 @@ public IndexerPageableRequestChain GetSearchRequests(AlbumSearchCriteria searchC { var pageableRequests = new IndexerPageableRequestChain(); - if (searchCriteria.CleanArtistQuery == "VA") + foreach (var artistTitle in searchCriteria.CleanArtistTitles) { - pageableRequests.Add(GetRequest(string.Format("&groupname={0}", searchCriteria.CleanAlbumQuery))); - } - else - { - pageableRequests.Add(GetRequest(string.Format("&artistname={0}&groupname={1}", searchCriteria.CleanArtistQuery, searchCriteria.CleanAlbumQuery))); + if (artistTitle == "VA") + { + pageableRequests.Add(GetRequest(string.Format("&groupname={0}", searchCriteria.CleanAlbumQuery))); + } + else + { + pageableRequests.Add(GetRequest(string.Format("&artistname={0}&groupname={1}", artistTitle, searchCriteria.CleanAlbumQuery))); + } } return pageableRequests; @@ -47,7 +50,12 @@ public IndexerPageableRequestChain GetSearchRequests(AlbumSearchCriteria searchC public IndexerPageableRequestChain GetSearchRequests(ArtistSearchCriteria searchCriteria) { var pageableRequests = new IndexerPageableRequestChain(); - pageableRequests.Add(GetRequest(string.Format("&artistname={0}", searchCriteria.CleanArtistQuery))); + + foreach (var artistTitle in searchCriteria.CleanArtistTitles) + { + pageableRequests.Add(GetRequest(string.Format("&artistname={0}", artistTitle))); + } + return pageableRequests; } diff --git a/src/NzbDrone.Core/Indexers/Headphones/HeadphonesRequestGenerator.cs b/src/NzbDrone.Core/Indexers/Headphones/HeadphonesRequestGenerator.cs index 71e5b8e53..1cba361ef 100644 --- a/src/NzbDrone.Core/Indexers/Headphones/HeadphonesRequestGenerator.cs +++ b/src/NzbDrone.Core/Indexers/Headphones/HeadphonesRequestGenerator.cs @@ -37,10 +37,13 @@ public virtual IndexerPageableRequestChain GetSearchRequests(AlbumSearchCriteria pageableRequests.AddTier(); - pageableRequests.Add(GetPagedRequests(MaxPages, - Settings.Categories, - "search", - $"&q={NewsnabifyTitle(searchCriteria.CleanArtistQuery)}+{NewsnabifyTitle(searchCriteria.CleanAlbumQuery)}")); + foreach (var artistTitle in searchCriteria.CleanArtistTitles) + { + pageableRequests.Add(GetPagedRequests(MaxPages, + Settings.Categories, + "search", + $"&q={NewsnabifyTitle(artistTitle)}+{NewsnabifyTitle(searchCriteria.CleanAlbumQuery)}")); + } return pageableRequests; } @@ -51,10 +54,13 @@ public virtual IndexerPageableRequestChain GetSearchRequests(ArtistSearchCriteri pageableRequests.AddTier(); - pageableRequests.Add(GetPagedRequests(MaxPages, - Settings.Categories, - "search", - $"&q={NewsnabifyTitle(searchCriteria.CleanArtistQuery)}")); + foreach (var artistTitle in searchCriteria.CleanArtistTitles) + { + pageableRequests.Add(GetPagedRequests(MaxPages, + Settings.Categories, + "search", + $"&q={NewsnabifyTitle(artistTitle)}")); + } return pageableRequests; } diff --git a/src/NzbDrone.Core/Indexers/Newznab/NewznabRequestGenerator.cs b/src/NzbDrone.Core/Indexers/Newznab/NewznabRequestGenerator.cs index 14379613c..5a0ec19e2 100644 --- a/src/NzbDrone.Core/Indexers/Newznab/NewznabRequestGenerator.cs +++ b/src/NzbDrone.Core/Indexers/Newznab/NewznabRequestGenerator.cs @@ -90,39 +90,45 @@ public virtual IndexerPageableRequestChain GetSearchRequests(AlbumSearchCriteria if (SupportsAudioSearch) { - var artistQuery = AudioTextSearchEngine == "raw" ? searchCriteria.ArtistQuery : searchCriteria.CleanArtistQuery; + var artistTitles = AudioTextSearchEngine == "raw" ? new List { searchCriteria.ArtistQuery } : searchCriteria.CleanArtistTitles; var albumQuery = AudioTextSearchEngine == "raw" ? searchCriteria.AlbumQuery : searchCriteria.CleanAlbumQuery; - var searchQuery = $"&artist={NewsnabifyTitle(artistQuery)}&album={NewsnabifyTitle(albumQuery)}"; - - if (artistQuery == albumQuery && searchCriteria.AlbumYear > 0) + foreach (var artistTitle in artistTitles) { - searchQuery = $"&artist={NewsnabifyTitle(artistQuery)}&album={NewsnabifyTitle(albumQuery)}&year={searchCriteria.AlbumYear}"; - } + var searchQuery = $"&artist={NewsnabifyTitle(artistTitle)}&album={NewsnabifyTitle(albumQuery)}"; - AddAudioPageableRequests(pageableRequests, - searchCriteria, - searchQuery); + if (artistTitle == albumQuery && searchCriteria.AlbumYear > 0) + { + searchQuery = $"&artist={NewsnabifyTitle(artistTitle)}&album={NewsnabifyTitle(albumQuery)}&year={searchCriteria.AlbumYear}"; + } + + AddAudioPageableRequests(pageableRequests, + searchCriteria, + searchQuery); + } } if (SupportsSearch) { pageableRequests.AddTier(); - var artistQuery = TextSearchEngine == "raw" ? searchCriteria.ArtistQuery : searchCriteria.CleanArtistQuery; + var artistTitles = TextSearchEngine == "raw" ? new List { searchCriteria.ArtistQuery } : searchCriteria.CleanArtistTitles; var albumQuery = TextSearchEngine == "raw" ? searchCriteria.AlbumQuery : searchCriteria.CleanAlbumQuery; - var searchQuery = $"{artistQuery}+{albumQuery}"; - - if (artistQuery == albumQuery) + foreach (var artistTitle in artistTitles) { - searchQuery = $"{artistQuery}+{albumQuery}+{searchCriteria.AlbumYear}"; - } + var searchQuery = $"{artistTitle}+{albumQuery}"; - pageableRequests.Add(GetPagedRequests(MaxPages, - Settings.Categories, - "search", - $"&q={NewsnabifyTitle(searchQuery)}")); + if (artistTitle == albumQuery) + { + searchQuery = $"{artistTitle}+{albumQuery}+{searchCriteria.AlbumYear}"; + } + + pageableRequests.Add(GetPagedRequests(MaxPages, + Settings.Categories, + "search", + $"&q={NewsnabifyTitle(searchQuery)}")); + } } return pageableRequests; @@ -134,22 +140,28 @@ public virtual IndexerPageableRequestChain GetSearchRequests(ArtistSearchCriteri if (SupportsAudioSearch) { - var queryTitle = AudioTextSearchEngine == "raw" ? searchCriteria.ArtistQuery : searchCriteria.CleanArtistQuery; + var queryTitles = AudioTextSearchEngine == "raw" ? new List { searchCriteria.ArtistQuery } : searchCriteria.CleanArtistTitles; - AddAudioPageableRequests(pageableRequests, - searchCriteria, - $"&artist={NewsnabifyTitle(queryTitle)}"); + foreach (var queryTitle in queryTitles) + { + AddAudioPageableRequests(pageableRequests, + searchCriteria, + $"&artist={NewsnabifyTitle(queryTitle)}"); + } } if (SupportsSearch) { pageableRequests.AddTier(); - var queryTitle = TextSearchEngine == "raw" ? searchCriteria.ArtistQuery : searchCriteria.CleanArtistQuery; + var queryTitles = TextSearchEngine == "raw" ? new List { searchCriteria.ArtistQuery } : searchCriteria.CleanArtistTitles; - pageableRequests.Add(GetPagedRequests(MaxPages, + foreach (var queryTitle in queryTitles) + { + pageableRequests.Add(GetPagedRequests(MaxPages, Settings.Categories, "search", $"&q={NewsnabifyTitle(queryTitle)}")); + } } return pageableRequests; @@ -159,7 +171,7 @@ private void AddAudioPageableRequests(IndexerPageableRequestChain chain, SearchC { chain.AddTier(); - chain.Add(GetPagedRequests(MaxPages, Settings.Categories, "music", $"&q={parameters}")); + chain.Add(GetPagedRequests(MaxPages, Settings.Categories, "music", parameters)); } private IEnumerable GetPagedRequests(int maxPages, IEnumerable categories, string searchType, string parameters) diff --git a/src/NzbDrone.Core/Indexers/Nyaa/NyaaRequestGenerator.cs b/src/NzbDrone.Core/Indexers/Nyaa/NyaaRequestGenerator.cs index 7e7b16604..719110a2f 100644 --- a/src/NzbDrone.Core/Indexers/Nyaa/NyaaRequestGenerator.cs +++ b/src/NzbDrone.Core/Indexers/Nyaa/NyaaRequestGenerator.cs @@ -21,11 +21,13 @@ public virtual IndexerPageableRequestChain GetRecentRequests() public virtual IndexerPageableRequestChain GetSearchRequests(AlbumSearchCriteria searchCriteria) { var pageableRequests = new IndexerPageableRequestChain(); - - var artistQuery = searchCriteria.CleanArtistQuery.Replace("+", " ").Trim(); var albumQuery = searchCriteria.CleanAlbumQuery.Replace("+", " ").Trim(); - pageableRequests.Add(GetPagedRequests(PrepareQuery($"{artistQuery} {albumQuery}"))); + foreach (var artistTitle in searchCriteria.CleanArtistTitles) + { + var artistQuery = artistTitle.Replace("+", " ").Trim(); + pageableRequests.Add(GetPagedRequests(PrepareQuery($"{artistQuery} {albumQuery}"))); + } return pageableRequests; } @@ -34,9 +36,11 @@ public virtual IndexerPageableRequestChain GetSearchRequests(ArtistSearchCriteri { var pageableRequests = new IndexerPageableRequestChain(); - var artistQuery = searchCriteria.CleanArtistQuery.Replace("+", " ").Trim(); - - pageableRequests.Add(GetPagedRequests(PrepareQuery(artistQuery))); + foreach (var artistTitle in searchCriteria.CleanArtistTitles) + { + var artistQuery = artistTitle.Replace("+", " ").Trim(); + pageableRequests.Add(GetPagedRequests(PrepareQuery(artistQuery))); + } return pageableRequests; } diff --git a/src/NzbDrone.Core/Indexers/Redacted/RedactedRequestGenerator.cs b/src/NzbDrone.Core/Indexers/Redacted/RedactedRequestGenerator.cs index 754a1ef3c..d7adf3e67 100644 --- a/src/NzbDrone.Core/Indexers/Redacted/RedactedRequestGenerator.cs +++ b/src/NzbDrone.Core/Indexers/Redacted/RedactedRequestGenerator.cs @@ -27,13 +27,16 @@ public IndexerPageableRequestChain GetSearchRequests(AlbumSearchCriteria searchC { var pageableRequests = new IndexerPageableRequestChain(); - if (searchCriteria.CleanArtistQuery == "VA") + foreach (var artistTitle in searchCriteria.CleanArtistTitles) { - pageableRequests.Add(GetRequest($"groupname={searchCriteria.CleanAlbumQuery}")); - } - else - { - pageableRequests.Add(GetRequest($"artistname={searchCriteria.CleanArtistQuery}&groupname={searchCriteria.CleanAlbumQuery}")); + if (artistTitle == "VA") + { + pageableRequests.Add(GetRequest($"groupname={searchCriteria.CleanAlbumQuery}")); + } + else + { + pageableRequests.Add(GetRequest($"artistname={artistTitle}&groupname={searchCriteria.CleanAlbumQuery}")); + } } return pageableRequests; @@ -42,7 +45,12 @@ public IndexerPageableRequestChain GetSearchRequests(AlbumSearchCriteria searchC public IndexerPageableRequestChain GetSearchRequests(ArtistSearchCriteria searchCriteria) { var pageableRequests = new IndexerPageableRequestChain(); - pageableRequests.Add(GetRequest($"artistname={searchCriteria.CleanArtistQuery}")); + + foreach (var artistTitle in searchCriteria.CleanArtistTitles) + { + pageableRequests.Add(GetRequest($"artistname={artistTitle}")); + } + return pageableRequests; } diff --git a/src/NzbDrone.Core/Music/Model/Artist.cs b/src/NzbDrone.Core/Music/Model/Artist.cs index eb60e2140..4006b5fbf 100644 --- a/src/NzbDrone.Core/Music/Model/Artist.cs +++ b/src/NzbDrone.Core/Music/Model/Artist.cs @@ -55,6 +55,9 @@ public string ForeignArtistId get { return Metadata.Value.ForeignArtistId; } set { Metadata.Value.ForeignArtistId = value; } } + [MemberwiseEqualityIgnore] + public string SearchName => Name; + public override string ToString() { return string.Format("[{0}][{1}]", Metadata.Value.ForeignArtistId.NullSafe(), Metadata.Value.Name.NullSafe());