From 99bd9c4db6794c499ec4a9195e1e6f95fdc53da5 Mon Sep 17 00:00:00 2001 From: dcicco Date: Sun, 21 Sep 2025 19:25:26 -0400 Subject: [PATCH 1/4] Add search alias functionality for artists - Introduced SearchAliasInput component for managing search aliases in artist forms. - Updated artist-related components to include aliases and searchAlias properties. - Added database migration to support searchAlias in the Artists table. --- .../src/Artist/Edit/EditArtistModalContent.js | 14 +++++ .../Edit/EditArtistModalContentConnector.js | 8 ++- frontend/src/Artist/Edit/SearchAliasInput.js | 53 +++++++++++++++++++ .../Search/Artist/AddNewArtistModalContent.js | 4 ++ .../AddNewArtistModalContentConnector.js | 3 ++ .../Search/Artist/AddNewArtistSearchResult.js | 3 ++ .../src/Search/Common/AddArtistOptionsForm.js | 20 +++++++ frontend/src/Store/Actions/searchActions.js | 1 + src/Lidarr.Api.V1/Artist/ArtistResource.cs | 8 ++- .../081_add_search_alias_to_artists.cs | 15 ++++++ .../Definitions/AlbumSearchCriteria.cs | 2 +- .../Definitions/SearchCriteriaBase.cs | 2 +- src/NzbDrone.Core/Localization/Core/en.json | 2 + src/NzbDrone.Core/Music/Model/Artist.cs | 6 +++ 14 files changed, 136 insertions(+), 5 deletions(-) create mode 100644 frontend/src/Artist/Edit/SearchAliasInput.js create mode 100644 src/NzbDrone.Core/Datastore/Migration/081_add_search_alias_to_artists.cs diff --git a/frontend/src/Artist/Edit/EditArtistModalContent.js b/frontend/src/Artist/Edit/EditArtistModalContent.js index bca6e3ea6..ca725d672 100644 --- a/frontend/src/Artist/Edit/EditArtistModalContent.js +++ b/frontend/src/Artist/Edit/EditArtistModalContent.js @@ -17,6 +17,7 @@ import ModalHeader from 'Components/Modal/ModalHeader'; import Popover from 'Components/Tooltip/Popover'; import { icons, inputTypes, kinds, sizes, tooltipPositions } from 'Helpers/Props'; import translate from 'Utilities/String/translate'; +import SearchAliasInput from './SearchAliasInput'; import styles from './EditArtistModalContent.css'; class EditArtistModalContent extends Component { @@ -133,6 +134,19 @@ class EditArtistModalContent extends Component { /> + + + {translate('SearchAlias')} + + + + + {translate('QualityProfile')} diff --git a/frontend/src/Artist/Edit/EditArtistModalContentConnector.js b/frontend/src/Artist/Edit/EditArtistModalContentConnector.js index bd9592d42..0171cff46 100644 --- a/frontend/src/Artist/Edit/EditArtistModalContentConnector.js +++ b/frontend/src/Artist/Edit/EditArtistModalContentConnector.js @@ -43,7 +43,8 @@ function createMapStateToProps() { 'qualityProfileId', 'metadataProfileId', 'path', - 'tags' + 'tags', + 'searchAlias' ]); const settings = selectSettings(artistSettings, pendingChanges, saveError); @@ -54,7 +55,10 @@ function createMapStateToProps() { saveError, isPathChanging, originalPath: artist.path, - item: settings.settings, + item: { + ...settings.settings, + aliases: artist.aliases + }, showMetadataProfile: metadataProfiles.items.length > 1, ...settings }; diff --git a/frontend/src/Artist/Edit/SearchAliasInput.js b/frontend/src/Artist/Edit/SearchAliasInput.js new file mode 100644 index 000000000..9f7487fba --- /dev/null +++ b/frontend/src/Artist/Edit/SearchAliasInput.js @@ -0,0 +1,53 @@ +import PropTypes from 'prop-types'; +import React, { useCallback } from 'react'; +import FormInputGroup from 'Components/Form/FormInputGroup'; +import { inputTypes } from 'Helpers/Props'; +import translate from 'Utilities/String/translate'; + +function SearchAliasInput({ aliases, artistName, value, onChange, onInputChange }) { + const onSearchAliasChange = useCallback( + ({ value: newValue }) => { + onInputChange({ + name: 'searchAlias', + value: newValue === artistName ? null : newValue + }); + }, + [onInputChange, artistName] + ); + + if (!aliases || aliases.length === 0) { + return null; + } + + // Create options: deduplicate aliases and filter out empty ones + const uniqueAliases = [...new Set(aliases.filter((alias) => alias && alias.trim().length > 0))]; + const searchOptions = uniqueAliases.map((alias) => ({ key: alias, value: alias, text: alias })); + + // If no aliases available after filtering, don't show the control + if (searchOptions.length === 0) { + return null; + } + + const displayValue = value || artistName; + + return ( + + ); +} + +SearchAliasInput.propTypes = { + aliases: PropTypes.arrayOf(PropTypes.string), + artistName: PropTypes.string.isRequired, + value: PropTypes.string, + onChange: PropTypes.func, + onInputChange: PropTypes.func.isRequired +}; + +export default SearchAliasInput; diff --git a/frontend/src/Search/Artist/AddNewArtistModalContent.js b/frontend/src/Search/Artist/AddNewArtistModalContent.js index 9719985f6..a7d38e88c 100644 --- a/frontend/src/Search/Artist/AddNewArtistModalContent.js +++ b/frontend/src/Search/Artist/AddNewArtistModalContent.js @@ -31,6 +31,7 @@ class AddNewArtistModalContent extends Component { disambiguation, overview, images, + aliases, searchForMissingAlbums, isAdding, isSmallScreen, @@ -83,6 +84,8 @@ class AddNewArtistModalContent extends Component { @@ -125,6 +128,7 @@ AddNewArtistModalContent.propTypes = { disambiguation: PropTypes.string.isRequired, overview: PropTypes.string, images: PropTypes.arrayOf(PropTypes.object).isRequired, + aliases: PropTypes.arrayOf(PropTypes.string), isAdding: PropTypes.bool.isRequired, addError: PropTypes.object, searchForMissingAlbums: PropTypes.object.isRequired, diff --git a/frontend/src/Search/Artist/AddNewArtistModalContentConnector.js b/frontend/src/Search/Artist/AddNewArtistModalContentConnector.js index a33c4bbf7..2ccfcab11 100644 --- a/frontend/src/Search/Artist/AddNewArtistModalContentConnector.js +++ b/frontend/src/Search/Artist/AddNewArtistModalContentConnector.js @@ -64,6 +64,7 @@ class AddNewArtistModalContentConnector extends Component { qualityProfileId, metadataProfileId, searchForMissingAlbums, + searchAlias, tags } = this.props; @@ -75,6 +76,7 @@ class AddNewArtistModalContentConnector extends Component { qualityProfileId: qualityProfileId.value, metadataProfileId: metadataProfileId.value, searchForMissingAlbums: searchForMissingAlbums.value, + searchAlias: searchAlias.value, tags: tags.value }); }; @@ -101,6 +103,7 @@ AddNewArtistModalContentConnector.propTypes = { qualityProfileId: PropTypes.object, metadataProfileId: PropTypes.object, searchForMissingAlbums: PropTypes.object.isRequired, + searchAlias: PropTypes.object.isRequired, tags: PropTypes.object.isRequired, onModalClose: PropTypes.func.isRequired, setAddDefault: PropTypes.func.isRequired, diff --git a/frontend/src/Search/Artist/AddNewArtistSearchResult.js b/frontend/src/Search/Artist/AddNewArtistSearchResult.js index 83e287b5e..81f84cefd 100644 --- a/frontend/src/Search/Artist/AddNewArtistSearchResult.js +++ b/frontend/src/Search/Artist/AddNewArtistSearchResult.js @@ -79,6 +79,7 @@ class AddNewArtistSearchResult extends Component { ratings, folder, images, + aliases, isExistingArtist, isSmallScreen } = this.props; @@ -211,6 +212,7 @@ class AddNewArtistSearchResult extends Component { overview={overview} folder={folder} images={images} + aliases={aliases} onModalClose={this.onAddArtistModalClose} /> @@ -229,6 +231,7 @@ AddNewArtistSearchResult.propTypes = { ratings: PropTypes.object.isRequired, folder: PropTypes.string.isRequired, images: PropTypes.arrayOf(PropTypes.object).isRequired, + aliases: PropTypes.arrayOf(PropTypes.string), isExistingArtist: PropTypes.bool.isRequired, isSmallScreen: PropTypes.bool.isRequired }; diff --git a/frontend/src/Search/Common/AddArtistOptionsForm.js b/frontend/src/Search/Common/AddArtistOptionsForm.js index bcbbfe795..db60ebaed 100644 --- a/frontend/src/Search/Common/AddArtistOptionsForm.js +++ b/frontend/src/Search/Common/AddArtistOptionsForm.js @@ -11,6 +11,7 @@ import Icon from 'Components/Icon'; import Popover from 'Components/Tooltip/Popover'; import { icons, inputTypes, tooltipPositions } from 'Helpers/Props'; import translate from 'Utilities/String/translate'; +import SearchAliasInput from 'Artist/Edit/SearchAliasInput'; import styles from './AddArtistOptionsForm.css'; class AddArtistOptionsForm extends Component { @@ -41,6 +42,9 @@ class AddArtistOptionsForm extends Component { folder, tags, isWindows, + aliases, + artistName, + searchAlias, onInputChange, ...otherProps } = this.props; @@ -120,6 +124,19 @@ class AddArtistOptionsForm extends Component { /> + + + {translate('SearchAlias')} + + + + + {translate('QualityProfile')} @@ -189,6 +206,9 @@ AddArtistOptionsForm.propTypes = { includeNoneMetadataProfile: PropTypes.bool.isRequired, folder: PropTypes.string.isRequired, tags: PropTypes.object.isRequired, + aliases: PropTypes.arrayOf(PropTypes.string), + artistName: PropTypes.string.isRequired, + searchAlias: PropTypes.object.isRequired, isWindows: PropTypes.bool.isRequired, onInputChange: PropTypes.func.isRequired }; diff --git a/frontend/src/Store/Actions/searchActions.js b/frontend/src/Store/Actions/searchActions.js index c2af6f47b..271c5984d 100644 --- a/frontend/src/Store/Actions/searchActions.js +++ b/frontend/src/Store/Actions/searchActions.js @@ -38,6 +38,7 @@ export const defaultState = { metadataProfileId: 0, searchForMissingAlbums: false, searchForNewAlbum: false, + searchAlias: null, tags: [] } }; diff --git a/src/Lidarr.Api.V1/Artist/ArtistResource.cs b/src/Lidarr.Api.V1/Artist/ArtistResource.cs index dc6b32343..f88d25527 100644 --- a/src/Lidarr.Api.V1/Artist/ArtistResource.cs +++ b/src/Lidarr.Api.V1/Artist/ArtistResource.cs @@ -57,6 +57,8 @@ 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 string SearchAlias { get; set; } public HashSet Tags { get; set; } public DateTime Added { get; set; } public AddArtistOptions AddOptions { get; set; } @@ -101,6 +103,8 @@ public static ArtistResource ToResource(this NzbDrone.Core.Music.Artist model) CleanName = model.CleanName, ForeignArtistId = model.Metadata.Value.ForeignArtistId, + Aliases = model.Metadata.Value.Aliases, + SearchAlias = model.SearchAlias, // Root folder path is now calculated from the artist path // RootFolderPath = model.RootFolderPath, @@ -133,7 +137,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 @@ -147,6 +152,7 @@ public static NzbDrone.Core.Music.Artist ToModel(this ArtistResource resource) CleanName = resource.CleanName, RootFolderPath = resource.RootFolderPath, + SearchAlias = resource.SearchAlias, Tags = resource.Tags, Added = resource.Added, diff --git a/src/NzbDrone.Core/Datastore/Migration/081_add_search_alias_to_artists.cs b/src/NzbDrone.Core/Datastore/Migration/081_add_search_alias_to_artists.cs new file mode 100644 index 000000000..cefd9c6c0 --- /dev/null +++ b/src/NzbDrone.Core/Datastore/Migration/081_add_search_alias_to_artists.cs @@ -0,0 +1,15 @@ +using FluentMigrator; +using NzbDrone.Core.Datastore.Migration.Framework; + +namespace NzbDrone.Core.Datastore.Migration +{ + [Migration(081)] + public class add_search_alias_to_artists : NzbDroneMigrationBase + { + protected override void MainDbUpgrade() + { + Alter.Table("Artists") + .AddColumn("SearchAlias").AsString().Nullable(); + } + } +} 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..d3bd91cf1 100644 --- a/src/NzbDrone.Core/IndexerSearch/Definitions/SearchCriteriaBase.cs +++ b/src/NzbDrone.Core/IndexerSearch/Definitions/SearchCriteriaBase.cs @@ -20,7 +20,7 @@ public abstract class SearchCriteriaBase public List Albums { get; set; } public List Tracks { get; set; } - public string ArtistQuery => Artist.Name; + public string ArtistQuery => Artist.SearchName; public string CleanArtistQuery => GetQueryTitle(ArtistQuery); public static string GetQueryTitle(string title) diff --git a/src/NzbDrone.Core/Localization/Core/en.json b/src/NzbDrone.Core/Localization/Core/en.json index 2b1605702..4d8671135 100644 --- a/src/NzbDrone.Core/Localization/Core/en.json +++ b/src/NzbDrone.Core/Localization/Core/en.json @@ -1111,6 +1111,8 @@ "Search": "Search", "SearchAlbum": "Search Album", "SearchAll": "Search All", + "SearchAlias": "Search Alias", + "SearchAliasHelpText": "Choose which name to use when searching for releases by this artist", "SearchBoxPlaceHolder": "eg. Breaking Benjamin, lidarr:854a1807-025b-42a8-ba8c-2a39717f1d25", "SearchForAllCutoffUnmetAlbums": "Search for all Cutoff Unmet albums", "SearchForAllCutoffUnmetAlbumsConfirmationCount": "Are you sure you want to search for all {totalRecords} Cutoff Unmet albums?", diff --git a/src/NzbDrone.Core/Music/Model/Artist.cs b/src/NzbDrone.Core/Music/Model/Artist.cs index eb60e2140..e603ed214 100644 --- a/src/NzbDrone.Core/Music/Model/Artist.cs +++ b/src/NzbDrone.Core/Music/Model/Artist.cs @@ -20,6 +20,7 @@ public Artist() public int ArtistMetadataId { get; set; } public string CleanName { get; set; } public string SortName { get; set; } + public string SearchAlias { get; set; } public bool Monitored { get; set; } public NewItemMonitorTypes MonitorNewItems { get; set; } public DateTime? LastInfoSync { get; set; } @@ -55,6 +56,9 @@ public string ForeignArtistId get { return Metadata.Value.ForeignArtistId; } set { Metadata.Value.ForeignArtistId = value; } } + [MemberwiseEqualityIgnore] + public string SearchName => !string.IsNullOrEmpty(SearchAlias) ? SearchAlias : Name; + public override string ToString() { return string.Format("[{0}][{1}]", Metadata.Value.ForeignArtistId.NullSafe(), Metadata.Value.Name.NullSafe()); @@ -80,6 +84,7 @@ public override void UseDbFieldsFrom(Artist other) MetadataProfileId = other.MetadataProfileId; Tags = other.Tags; AddOptions = other.AddOptions; + SearchAlias = other.SearchAlias; } public override void ApplyChanges(Artist other) @@ -96,6 +101,7 @@ public override void ApplyChanges(Artist other) RootFolderPath = other.RootFolderPath; Monitored = other.Monitored; MonitorNewItems = other.MonitorNewItems; + SearchAlias = other.SearchAlias; } } } From 731779e8a3c433fce43c75402406485d94ce6249 Mon Sep 17 00:00:00 2001 From: dcicco Date: Sun, 21 Sep 2025 19:59:36 -0400 Subject: [PATCH 2/4] update sorting --- frontend/src/Search/Common/AddArtistOptionsForm.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/Search/Common/AddArtistOptionsForm.js b/frontend/src/Search/Common/AddArtistOptionsForm.js index db60ebaed..d09f94b98 100644 --- a/frontend/src/Search/Common/AddArtistOptionsForm.js +++ b/frontend/src/Search/Common/AddArtistOptionsForm.js @@ -3,6 +3,7 @@ import React, { Component } from 'react'; import ArtistMetadataProfilePopoverContent from 'AddArtist/ArtistMetadataProfilePopoverContent'; import ArtistMonitoringOptionsPopoverContent from 'AddArtist/ArtistMonitoringOptionsPopoverContent'; import ArtistMonitorNewItemsOptionsPopoverContent from 'AddArtist/ArtistMonitorNewItemsOptionsPopoverContent'; +import SearchAliasInput from 'Artist/Edit/SearchAliasInput'; import Form from 'Components/Form/Form'; import FormGroup from 'Components/Form/FormGroup'; import FormInputGroup from 'Components/Form/FormInputGroup'; @@ -11,7 +12,6 @@ import Icon from 'Components/Icon'; import Popover from 'Components/Tooltip/Popover'; import { icons, inputTypes, tooltipPositions } from 'Helpers/Props'; import translate from 'Utilities/String/translate'; -import SearchAliasInput from 'Artist/Edit/SearchAliasInput'; import styles from './AddArtistOptionsForm.css'; class AddArtistOptionsForm extends Component { From 3e7e0e7004f12a7f61ad38634ed04755453d897b Mon Sep 17 00:00:00 2001 From: dcicco Date: Mon, 22 Sep 2025 20:24:53 -0400 Subject: [PATCH 3/4] Remove frontend components for aliases --- .../src/Artist/Edit/EditArtistModalContent.js | 14 ----- .../Edit/EditArtistModalContentConnector.js | 8 +-- frontend/src/Artist/Edit/SearchAliasInput.js | 53 ------------------- .../Search/Artist/AddNewArtistModalContent.js | 4 -- .../AddNewArtistModalContentConnector.js | 3 -- .../Search/Artist/AddNewArtistSearchResult.js | 3 -- .../src/Search/Common/AddArtistOptionsForm.js | 20 ------- frontend/src/Store/Actions/searchActions.js | 1 - src/NzbDrone.Core/Localization/Core/en.json | 2 - 9 files changed, 2 insertions(+), 106 deletions(-) delete mode 100644 frontend/src/Artist/Edit/SearchAliasInput.js diff --git a/frontend/src/Artist/Edit/EditArtistModalContent.js b/frontend/src/Artist/Edit/EditArtistModalContent.js index ca725d672..bca6e3ea6 100644 --- a/frontend/src/Artist/Edit/EditArtistModalContent.js +++ b/frontend/src/Artist/Edit/EditArtistModalContent.js @@ -17,7 +17,6 @@ import ModalHeader from 'Components/Modal/ModalHeader'; import Popover from 'Components/Tooltip/Popover'; import { icons, inputTypes, kinds, sizes, tooltipPositions } from 'Helpers/Props'; import translate from 'Utilities/String/translate'; -import SearchAliasInput from './SearchAliasInput'; import styles from './EditArtistModalContent.css'; class EditArtistModalContent extends Component { @@ -134,19 +133,6 @@ class EditArtistModalContent extends Component { /> - - - {translate('SearchAlias')} - - - - - {translate('QualityProfile')} diff --git a/frontend/src/Artist/Edit/EditArtistModalContentConnector.js b/frontend/src/Artist/Edit/EditArtistModalContentConnector.js index 0171cff46..bd9592d42 100644 --- a/frontend/src/Artist/Edit/EditArtistModalContentConnector.js +++ b/frontend/src/Artist/Edit/EditArtistModalContentConnector.js @@ -43,8 +43,7 @@ function createMapStateToProps() { 'qualityProfileId', 'metadataProfileId', 'path', - 'tags', - 'searchAlias' + 'tags' ]); const settings = selectSettings(artistSettings, pendingChanges, saveError); @@ -55,10 +54,7 @@ function createMapStateToProps() { saveError, isPathChanging, originalPath: artist.path, - item: { - ...settings.settings, - aliases: artist.aliases - }, + item: settings.settings, showMetadataProfile: metadataProfiles.items.length > 1, ...settings }; diff --git a/frontend/src/Artist/Edit/SearchAliasInput.js b/frontend/src/Artist/Edit/SearchAliasInput.js deleted file mode 100644 index 9f7487fba..000000000 --- a/frontend/src/Artist/Edit/SearchAliasInput.js +++ /dev/null @@ -1,53 +0,0 @@ -import PropTypes from 'prop-types'; -import React, { useCallback } from 'react'; -import FormInputGroup from 'Components/Form/FormInputGroup'; -import { inputTypes } from 'Helpers/Props'; -import translate from 'Utilities/String/translate'; - -function SearchAliasInput({ aliases, artistName, value, onChange, onInputChange }) { - const onSearchAliasChange = useCallback( - ({ value: newValue }) => { - onInputChange({ - name: 'searchAlias', - value: newValue === artistName ? null : newValue - }); - }, - [onInputChange, artistName] - ); - - if (!aliases || aliases.length === 0) { - return null; - } - - // Create options: deduplicate aliases and filter out empty ones - const uniqueAliases = [...new Set(aliases.filter((alias) => alias && alias.trim().length > 0))]; - const searchOptions = uniqueAliases.map((alias) => ({ key: alias, value: alias, text: alias })); - - // If no aliases available after filtering, don't show the control - if (searchOptions.length === 0) { - return null; - } - - const displayValue = value || artistName; - - return ( - - ); -} - -SearchAliasInput.propTypes = { - aliases: PropTypes.arrayOf(PropTypes.string), - artistName: PropTypes.string.isRequired, - value: PropTypes.string, - onChange: PropTypes.func, - onInputChange: PropTypes.func.isRequired -}; - -export default SearchAliasInput; diff --git a/frontend/src/Search/Artist/AddNewArtistModalContent.js b/frontend/src/Search/Artist/AddNewArtistModalContent.js index a7d38e88c..9719985f6 100644 --- a/frontend/src/Search/Artist/AddNewArtistModalContent.js +++ b/frontend/src/Search/Artist/AddNewArtistModalContent.js @@ -31,7 +31,6 @@ class AddNewArtistModalContent extends Component { disambiguation, overview, images, - aliases, searchForMissingAlbums, isAdding, isSmallScreen, @@ -84,8 +83,6 @@ class AddNewArtistModalContent extends Component { @@ -128,7 +125,6 @@ AddNewArtistModalContent.propTypes = { disambiguation: PropTypes.string.isRequired, overview: PropTypes.string, images: PropTypes.arrayOf(PropTypes.object).isRequired, - aliases: PropTypes.arrayOf(PropTypes.string), isAdding: PropTypes.bool.isRequired, addError: PropTypes.object, searchForMissingAlbums: PropTypes.object.isRequired, diff --git a/frontend/src/Search/Artist/AddNewArtistModalContentConnector.js b/frontend/src/Search/Artist/AddNewArtistModalContentConnector.js index 2ccfcab11..a33c4bbf7 100644 --- a/frontend/src/Search/Artist/AddNewArtistModalContentConnector.js +++ b/frontend/src/Search/Artist/AddNewArtistModalContentConnector.js @@ -64,7 +64,6 @@ class AddNewArtistModalContentConnector extends Component { qualityProfileId, metadataProfileId, searchForMissingAlbums, - searchAlias, tags } = this.props; @@ -76,7 +75,6 @@ class AddNewArtistModalContentConnector extends Component { qualityProfileId: qualityProfileId.value, metadataProfileId: metadataProfileId.value, searchForMissingAlbums: searchForMissingAlbums.value, - searchAlias: searchAlias.value, tags: tags.value }); }; @@ -103,7 +101,6 @@ AddNewArtistModalContentConnector.propTypes = { qualityProfileId: PropTypes.object, metadataProfileId: PropTypes.object, searchForMissingAlbums: PropTypes.object.isRequired, - searchAlias: PropTypes.object.isRequired, tags: PropTypes.object.isRequired, onModalClose: PropTypes.func.isRequired, setAddDefault: PropTypes.func.isRequired, diff --git a/frontend/src/Search/Artist/AddNewArtistSearchResult.js b/frontend/src/Search/Artist/AddNewArtistSearchResult.js index 81f84cefd..83e287b5e 100644 --- a/frontend/src/Search/Artist/AddNewArtistSearchResult.js +++ b/frontend/src/Search/Artist/AddNewArtistSearchResult.js @@ -79,7 +79,6 @@ class AddNewArtistSearchResult extends Component { ratings, folder, images, - aliases, isExistingArtist, isSmallScreen } = this.props; @@ -212,7 +211,6 @@ class AddNewArtistSearchResult extends Component { overview={overview} folder={folder} images={images} - aliases={aliases} onModalClose={this.onAddArtistModalClose} /> @@ -231,7 +229,6 @@ AddNewArtistSearchResult.propTypes = { ratings: PropTypes.object.isRequired, folder: PropTypes.string.isRequired, images: PropTypes.arrayOf(PropTypes.object).isRequired, - aliases: PropTypes.arrayOf(PropTypes.string), isExistingArtist: PropTypes.bool.isRequired, isSmallScreen: PropTypes.bool.isRequired }; diff --git a/frontend/src/Search/Common/AddArtistOptionsForm.js b/frontend/src/Search/Common/AddArtistOptionsForm.js index d09f94b98..bcbbfe795 100644 --- a/frontend/src/Search/Common/AddArtistOptionsForm.js +++ b/frontend/src/Search/Common/AddArtistOptionsForm.js @@ -3,7 +3,6 @@ import React, { Component } from 'react'; import ArtistMetadataProfilePopoverContent from 'AddArtist/ArtistMetadataProfilePopoverContent'; import ArtistMonitoringOptionsPopoverContent from 'AddArtist/ArtistMonitoringOptionsPopoverContent'; import ArtistMonitorNewItemsOptionsPopoverContent from 'AddArtist/ArtistMonitorNewItemsOptionsPopoverContent'; -import SearchAliasInput from 'Artist/Edit/SearchAliasInput'; import Form from 'Components/Form/Form'; import FormGroup from 'Components/Form/FormGroup'; import FormInputGroup from 'Components/Form/FormInputGroup'; @@ -42,9 +41,6 @@ class AddArtistOptionsForm extends Component { folder, tags, isWindows, - aliases, - artistName, - searchAlias, onInputChange, ...otherProps } = this.props; @@ -124,19 +120,6 @@ class AddArtistOptionsForm extends Component { /> - - - {translate('SearchAlias')} - - - - - {translate('QualityProfile')} @@ -206,9 +189,6 @@ AddArtistOptionsForm.propTypes = { includeNoneMetadataProfile: PropTypes.bool.isRequired, folder: PropTypes.string.isRequired, tags: PropTypes.object.isRequired, - aliases: PropTypes.arrayOf(PropTypes.string), - artistName: PropTypes.string.isRequired, - searchAlias: PropTypes.object.isRequired, isWindows: PropTypes.bool.isRequired, onInputChange: PropTypes.func.isRequired }; diff --git a/frontend/src/Store/Actions/searchActions.js b/frontend/src/Store/Actions/searchActions.js index 271c5984d..c2af6f47b 100644 --- a/frontend/src/Store/Actions/searchActions.js +++ b/frontend/src/Store/Actions/searchActions.js @@ -38,7 +38,6 @@ export const defaultState = { metadataProfileId: 0, searchForMissingAlbums: false, searchForNewAlbum: false, - searchAlias: null, tags: [] } }; diff --git a/src/NzbDrone.Core/Localization/Core/en.json b/src/NzbDrone.Core/Localization/Core/en.json index 4d8671135..2b1605702 100644 --- a/src/NzbDrone.Core/Localization/Core/en.json +++ b/src/NzbDrone.Core/Localization/Core/en.json @@ -1111,8 +1111,6 @@ "Search": "Search", "SearchAlbum": "Search Album", "SearchAll": "Search All", - "SearchAlias": "Search Alias", - "SearchAliasHelpText": "Choose which name to use when searching for releases by this artist", "SearchBoxPlaceHolder": "eg. Breaking Benjamin, lidarr:854a1807-025b-42a8-ba8c-2a39717f1d25", "SearchForAllCutoffUnmetAlbums": "Search for all Cutoff Unmet albums", "SearchForAllCutoffUnmetAlbumsConfirmationCount": "Are you sure you want to search for all {totalRecords} Cutoff Unmet albums?", From f0f02bd9245d358f02f1915cf56fd4d2abd5f6c1 Mon Sep 17 00:00:00 2001 From: dcicco Date: Thu, 25 Sep 2025 00:03:23 -0400 Subject: [PATCH 4/4] re-worked the backend searches to mock the way Radarr does its Alternate Title searching - for all indexers that support it --- src/Lidarr.Api.V1/Artist/ArtistResource.cs | 3 - .../081_add_search_alias_to_artists.cs | 15 ----- .../Definitions/SearchCriteriaBase.cs | 3 + .../IndexerSearch/ReleaseSearchService.cs | 18 ++++++ .../FileList/FileListRequestGenerator.cs | 16 +++-- .../Gazelle/GazelleRequestGenerator.cs | 22 +++++-- .../Headphones/HeadphonesRequestGenerator.cs | 22 ++++--- .../Newznab/NewznabRequestGenerator.cs | 64 +++++++++++-------- .../Indexers/Nyaa/NyaaRequestGenerator.cs | 16 +++-- .../Redacted/RedactedRequestGenerator.cs | 22 +++++-- src/NzbDrone.Core/Music/Model/Artist.cs | 5 +- 11 files changed, 124 insertions(+), 82 deletions(-) delete mode 100644 src/NzbDrone.Core/Datastore/Migration/081_add_search_alias_to_artists.cs diff --git a/src/Lidarr.Api.V1/Artist/ArtistResource.cs b/src/Lidarr.Api.V1/Artist/ArtistResource.cs index f88d25527..89b51f9eb 100644 --- a/src/Lidarr.Api.V1/Artist/ArtistResource.cs +++ b/src/Lidarr.Api.V1/Artist/ArtistResource.cs @@ -58,7 +58,6 @@ public class ArtistResource : RestResource public string CleanName { get; set; } public string SortName { get; set; } public List Aliases { get; set; } - public string SearchAlias { get; set; } public HashSet Tags { get; set; } public DateTime Added { get; set; } public AddArtistOptions AddOptions { get; set; } @@ -104,7 +103,6 @@ public static ArtistResource ToResource(this NzbDrone.Core.Music.Artist model) CleanName = model.CleanName, ForeignArtistId = model.Metadata.Value.ForeignArtistId, Aliases = model.Metadata.Value.Aliases, - SearchAlias = model.SearchAlias, // Root folder path is now calculated from the artist path // RootFolderPath = model.RootFolderPath, @@ -152,7 +150,6 @@ public static NzbDrone.Core.Music.Artist ToModel(this ArtistResource resource) CleanName = resource.CleanName, RootFolderPath = resource.RootFolderPath, - SearchAlias = resource.SearchAlias, Tags = resource.Tags, Added = resource.Added, diff --git a/src/NzbDrone.Core/Datastore/Migration/081_add_search_alias_to_artists.cs b/src/NzbDrone.Core/Datastore/Migration/081_add_search_alias_to_artists.cs deleted file mode 100644 index cefd9c6c0..000000000 --- a/src/NzbDrone.Core/Datastore/Migration/081_add_search_alias_to_artists.cs +++ /dev/null @@ -1,15 +0,0 @@ -using FluentMigrator; -using NzbDrone.Core.Datastore.Migration.Framework; - -namespace NzbDrone.Core.Datastore.Migration -{ - [Migration(081)] - public class add_search_alias_to_artists : NzbDroneMigrationBase - { - protected override void MainDbUpgrade() - { - Alter.Table("Artists") - .AddColumn("SearchAlias").AsString().Nullable(); - } - } -} diff --git a/src/NzbDrone.Core/IndexerSearch/Definitions/SearchCriteriaBase.cs b/src/NzbDrone.Core/IndexerSearch/Definitions/SearchCriteriaBase.cs index d3bd91cf1..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.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 e603ed214..4006b5fbf 100644 --- a/src/NzbDrone.Core/Music/Model/Artist.cs +++ b/src/NzbDrone.Core/Music/Model/Artist.cs @@ -20,7 +20,6 @@ public Artist() public int ArtistMetadataId { get; set; } public string CleanName { get; set; } public string SortName { get; set; } - public string SearchAlias { get; set; } public bool Monitored { get; set; } public NewItemMonitorTypes MonitorNewItems { get; set; } public DateTime? LastInfoSync { get; set; } @@ -57,7 +56,7 @@ public string ForeignArtistId } [MemberwiseEqualityIgnore] - public string SearchName => !string.IsNullOrEmpty(SearchAlias) ? SearchAlias : Name; + public string SearchName => Name; public override string ToString() { @@ -84,7 +83,6 @@ public override void UseDbFieldsFrom(Artist other) MetadataProfileId = other.MetadataProfileId; Tags = other.Tags; AddOptions = other.AddOptions; - SearchAlias = other.SearchAlias; } public override void ApplyChanges(Artist other) @@ -101,7 +99,6 @@ public override void ApplyChanges(Artist other) RootFolderPath = other.RootFolderPath; Monitored = other.Monitored; MonitorNewItems = other.MonitorNewItems; - SearchAlias = other.SearchAlias; } } }