Merge pull request #17424 from Shadowghost/add-audiodb-search
Implement AudioDb artist search
This commit is contained in:
@@ -1038,6 +1038,11 @@ namespace MediaBrowser.Providers.Manager
|
||||
target.OriginalTitle = source.OriginalTitle;
|
||||
}
|
||||
|
||||
if (replaceData || string.IsNullOrEmpty(target.HomePageUrl))
|
||||
{
|
||||
target.HomePageUrl = source.HomePageUrl;
|
||||
}
|
||||
|
||||
if (replaceData || string.IsNullOrEmpty(target.OriginalLanguage))
|
||||
{
|
||||
target.OriginalLanguage = source.OriginalLanguage;
|
||||
|
||||
@@ -3,32 +3,24 @@
|
||||
#pragma warning disable CS1591
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Net.Http;
|
||||
using System.Text.Json;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Jellyfin.Extensions.Json;
|
||||
using MediaBrowser.Common.Net;
|
||||
using MediaBrowser.Controller.Configuration;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Entities.Audio;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.IO;
|
||||
using MediaBrowser.Model.Providers;
|
||||
|
||||
namespace MediaBrowser.Providers.Plugins.AudioDb
|
||||
{
|
||||
public class AudioDbArtistImageProvider : IRemoteImageProvider, IHasOrder
|
||||
{
|
||||
private readonly IServerConfigurationManager _config;
|
||||
private readonly IHttpClientFactory _httpClientFactory;
|
||||
private readonly JsonSerializerOptions _jsonOptions = JsonDefaults.Options;
|
||||
|
||||
public AudioDbArtistImageProvider(IServerConfigurationManager config, IHttpClientFactory httpClientFactory)
|
||||
public AudioDbArtistImageProvider(IHttpClientFactory httpClientFactory)
|
||||
{
|
||||
_config = config;
|
||||
_httpClientFactory = httpClientFactory;
|
||||
}
|
||||
|
||||
@@ -54,22 +46,14 @@ namespace MediaBrowser.Providers.Plugins.AudioDb
|
||||
/// <inheritdoc />
|
||||
public async Task<IEnumerable<RemoteImageInfo>> GetImages(BaseItem item, CancellationToken cancellationToken)
|
||||
{
|
||||
if (item.TryGetProviderId(MetadataProvider.MusicBrainzArtist, out var id))
|
||||
item.TryGetProviderId(MetadataProvider.MusicBrainzArtist, out var musicBrainzId);
|
||||
item.TryGetProviderId(MetadataProvider.AudioDbArtist, out var audioDbId);
|
||||
|
||||
var artist = await AudioDbArtistProvider.Current.GetArtist(musicBrainzId, audioDbId, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
if (artist is not null)
|
||||
{
|
||||
await AudioDbArtistProvider.Current.EnsureArtistInfo(id, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
var path = AudioDbArtistProvider.GetArtistInfoPath(_config.ApplicationPaths, id);
|
||||
|
||||
FileStream jsonStream = AsyncFile.OpenRead(path);
|
||||
await using (jsonStream.ConfigureAwait(false))
|
||||
{
|
||||
var obj = await JsonSerializer.DeserializeAsync<AudioDbArtistProvider.RootObject>(jsonStream, _jsonOptions, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
if (obj is not null && obj.artists is not null && obj.artists.Count > 0)
|
||||
{
|
||||
return GetImages(obj.artists[0]);
|
||||
}
|
||||
}
|
||||
return GetImages(artist);
|
||||
}
|
||||
|
||||
return [];
|
||||
|
||||
@@ -4,9 +4,11 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Json;
|
||||
using System.Text.Json;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
@@ -52,45 +54,176 @@ namespace MediaBrowser.Providers.Plugins.AudioDb
|
||||
public int Order => 1;
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<IEnumerable<RemoteSearchResult>> GetSearchResults(ArtistInfo searchInfo, CancellationToken cancellationToken)
|
||||
=> Task.FromResult(Enumerable.Empty<RemoteSearchResult>());
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<MetadataResult<MusicArtist>> GetMetadata(ArtistInfo info, CancellationToken cancellationToken)
|
||||
public async Task<IEnumerable<RemoteSearchResult>> GetSearchResults(ArtistInfo searchInfo, CancellationToken cancellationToken)
|
||||
{
|
||||
var result = new MetadataResult<MusicArtist>();
|
||||
var id = info.GetMusicBrainzArtistId();
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(id))
|
||||
// Prefer a known TheAudioDB artist id.
|
||||
var audioDbId = searchInfo.GetProviderId(MetadataProvider.AudioDbArtist);
|
||||
if (!string.IsNullOrWhiteSpace(audioDbId))
|
||||
{
|
||||
await EnsureArtistInfo(id, cancellationToken).ConfigureAwait(false);
|
||||
var artists = await FetchArtists(BaseUrl + "/artist.php?i=" + audioDbId, cancellationToken).ConfigureAwait(false);
|
||||
return artists.Select(ToRemoteSearchResult);
|
||||
}
|
||||
|
||||
var path = GetArtistInfoPath(_config.ApplicationPaths, id);
|
||||
// Fall back to the MusicBrainz artist id, reusing the on-disk cache also used by GetMetadata.
|
||||
var musicBrainzId = searchInfo.GetMusicBrainzArtistId();
|
||||
if (!string.IsNullOrWhiteSpace(musicBrainzId))
|
||||
{
|
||||
await EnsureArtistInfo(musicBrainzId, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
var path = GetArtistInfoPath(_config.ApplicationPaths, musicBrainzId);
|
||||
|
||||
FileStream jsonStream = AsyncFile.OpenRead(path);
|
||||
await using (jsonStream.ConfigureAwait(false))
|
||||
{
|
||||
var obj = await JsonSerializer.DeserializeAsync<RootObject>(jsonStream, _jsonOptions, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
if (obj is not null && obj.artists is not null && obj.artists.Count > 0)
|
||||
if (obj is not null && obj.artists is not null)
|
||||
{
|
||||
result.Item = new MusicArtist();
|
||||
result.HasMetadata = true;
|
||||
ProcessResult(result.Item, obj.artists[0], info.MetadataLanguage);
|
||||
return obj.artists.Select(ToRemoteSearchResult);
|
||||
}
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
// Finally, search by name.
|
||||
if (!string.IsNullOrWhiteSpace(searchInfo.Name))
|
||||
{
|
||||
var artists = await FetchArtists(BaseUrl + "/search.php?s=" + Uri.EscapeDataString(searchInfo.Name), cancellationToken).ConfigureAwait(false);
|
||||
return artists.Select(ToRemoteSearchResult);
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
private async Task<List<Artist>> FetchArtists(string url, CancellationToken cancellationToken)
|
||||
{
|
||||
using var response = await _httpClientFactory.CreateClient(NamedClient.Default).GetAsync(url, cancellationToken).ConfigureAwait(false);
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
var obj = await response.Content.ReadFromJsonAsync<RootObject>(_jsonOptions, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
return obj?.artists ?? [];
|
||||
}
|
||||
|
||||
private RemoteSearchResult ToRemoteSearchResult(Artist artist)
|
||||
{
|
||||
var result = new RemoteSearchResult
|
||||
{
|
||||
Name = artist.strArtist,
|
||||
ImageUrl = artist.strArtistThumb,
|
||||
SearchProviderName = Name,
|
||||
Overview = (artist.strBiographyEN ?? string.Empty).StripHtml()
|
||||
};
|
||||
|
||||
if (!string.IsNullOrEmpty(artist.idArtist))
|
||||
{
|
||||
result.SetProviderId(MetadataProvider.AudioDbArtist, artist.idArtist);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(artist.strMusicBrainzID))
|
||||
{
|
||||
result.SetProviderId(MetadataProvider.MusicBrainzArtist, artist.strMusicBrainzID);
|
||||
}
|
||||
|
||||
if (int.TryParse(artist.intFormedYear, NumberStyles.Integer, CultureInfo.InvariantCulture, out var formedYear))
|
||||
{
|
||||
result.ProductionYear = formedYear;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<MetadataResult<MusicArtist>> GetMetadata(ArtistInfo info, CancellationToken cancellationToken)
|
||||
{
|
||||
var result = new MetadataResult<MusicArtist>();
|
||||
|
||||
var artist = await GetArtist(
|
||||
info.GetMusicBrainzArtistId(),
|
||||
info.GetProviderId(MetadataProvider.AudioDbArtist),
|
||||
cancellationToken).ConfigureAwait(false);
|
||||
|
||||
if (artist is not null)
|
||||
{
|
||||
result.Item = new MusicArtist();
|
||||
result.HasMetadata = true;
|
||||
ProcessResult(result.Item, artist, info.MetadataLanguage);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resolves the cached AudioDB artist, preferring the MusicBrainz id and falling back to the AudioDB id.
|
||||
/// </summary>
|
||||
/// <param name="musicBrainzId">The MusicBrainz artist id, if known.</param>
|
||||
/// <param name="audioDbId">The TheAudioDB artist id, if known.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>The matching artist, or <c>null</c> if none could be resolved.</returns>
|
||||
internal async Task<Artist> GetArtist(string musicBrainzId, string audioDbId, CancellationToken cancellationToken)
|
||||
{
|
||||
string path;
|
||||
if (!string.IsNullOrWhiteSpace(musicBrainzId))
|
||||
{
|
||||
await EnsureArtistInfo(musicBrainzId, cancellationToken).ConfigureAwait(false);
|
||||
path = GetArtistInfoPath(_config.ApplicationPaths, musicBrainzId);
|
||||
}
|
||||
else if (!string.IsNullOrWhiteSpace(audioDbId))
|
||||
{
|
||||
await EnsureArtistInfoByAudioDbId(audioDbId, cancellationToken).ConfigureAwait(false);
|
||||
path = GetArtistInfoPath(_config.ApplicationPaths, audioDbId);
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
FileStream jsonStream = AsyncFile.OpenRead(path);
|
||||
await using (jsonStream.ConfigureAwait(false))
|
||||
{
|
||||
var obj = await JsonSerializer.DeserializeAsync<RootObject>(jsonStream, _jsonOptions, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
if (obj is not null && obj.artists is not null && obj.artists.Count > 0)
|
||||
{
|
||||
return obj.artists[0];
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private void ProcessResult(MusicArtist item, Artist result, string preferredLanguage)
|
||||
{
|
||||
// item.HomePageUrl = result.strWebsite;
|
||||
|
||||
if (!string.IsNullOrEmpty(result.strGenre))
|
||||
if (!string.IsNullOrWhiteSpace(result.strWebsite))
|
||||
{
|
||||
item.Genres = new[] { result.strGenre };
|
||||
item.HomePageUrl = result.strWebsite;
|
||||
}
|
||||
|
||||
var genres = new List<string>();
|
||||
if (!string.IsNullOrWhiteSpace(result.strGenre))
|
||||
{
|
||||
genres.Add(result.strGenre);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(result.strSubGenre))
|
||||
{
|
||||
genres.Add(result.strSubGenre);
|
||||
}
|
||||
|
||||
if (genres.Count > 0)
|
||||
{
|
||||
item.Genres = genres.ToArray();
|
||||
}
|
||||
|
||||
if (int.TryParse(result.intFormedYear, NumberStyles.Integer, CultureInfo.InvariantCulture, out var formedYear))
|
||||
{
|
||||
item.ProductionYear = formedYear;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(result.strCountry))
|
||||
{
|
||||
item.ProductionLocations = new[] { result.strCountry };
|
||||
}
|
||||
|
||||
item.SetProviderId(MetadataProvider.AudioDbArtist, result.idArtist);
|
||||
@@ -150,13 +283,32 @@ namespace MediaBrowser.Providers.Plugins.AudioDb
|
||||
|
||||
internal async Task DownloadArtistInfo(string musicBrainzId, CancellationToken cancellationToken)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
var url = BaseUrl + "/artist-mb.php?i=" + musicBrainzId;
|
||||
await DownloadArtistInfo(url, GetArtistInfoPath(_config.ApplicationPaths, musicBrainzId), cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
internal async Task EnsureArtistInfoByAudioDbId(string audioDbId, CancellationToken cancellationToken)
|
||||
{
|
||||
var xmlPath = GetArtistInfoPath(_config.ApplicationPaths, audioDbId);
|
||||
|
||||
var fileInfo = _fileSystem.GetFileSystemInfo(xmlPath);
|
||||
|
||||
if (fileInfo.Exists
|
||||
&& (DateTime.UtcNow - _fileSystem.GetLastWriteTimeUtc(fileInfo)).TotalDays <= 2)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var url = BaseUrl + "/artist.php?i=" + audioDbId;
|
||||
await DownloadArtistInfo(url, xmlPath, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private async Task DownloadArtistInfo(string url, string path, CancellationToken cancellationToken)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
using var response = await _httpClientFactory.CreateClient(NamedClient.Default).GetAsync(url, cancellationToken).ConfigureAwait(false);
|
||||
response.EnsureSuccessStatusCode();
|
||||
var path = GetArtistInfoPath(_config.ApplicationPaths, musicBrainzId);
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(path));
|
||||
|
||||
var fileStreamOptions = AsyncFile.WriteOptions;
|
||||
|
||||
@@ -155,7 +155,6 @@ public class MusicBrainzAlbumProvider : IRemoteMetadataProvider<MusicAlbum, Albu
|
||||
/// <inheritdoc />
|
||||
public async Task<MetadataResult<MusicAlbum>> GetMetadata(AlbumInfo info, CancellationToken cancellationToken)
|
||||
{
|
||||
// TODO: This sets essentially nothing. As-is, it's mostly useless. Make it actually pull metadata and use it.
|
||||
var query = MusicBrainz.Plugin.Instance!.MusicBrainzQuery;
|
||||
var releaseId = info.GetReleaseId();
|
||||
var releaseGroupId = info.GetReleaseGroupId();
|
||||
@@ -169,13 +168,8 @@ public class MusicBrainzAlbumProvider : IRemoteMetadataProvider<MusicAlbum, Albu
|
||||
if (string.IsNullOrWhiteSpace(releaseId) && !string.IsNullOrWhiteSpace(releaseGroupId))
|
||||
{
|
||||
// TODO: Actually try to match the release. Simply taking the first result is stupid.
|
||||
var releaseGroup = await query.LookupReleaseGroupAsync(new Guid(releaseGroupId), Include.None, null, cancellationToken).ConfigureAwait(false);
|
||||
var release = releaseGroup.Releases?.Count > 0 ? releaseGroup.Releases[0] : null;
|
||||
if (release is not null)
|
||||
{
|
||||
releaseId = release.Id.ToString();
|
||||
result.HasMetadata = true;
|
||||
}
|
||||
var releaseGroupLookup = await query.LookupReleaseGroupAsync(new Guid(releaseGroupId), Include.None, null, cancellationToken).ConfigureAwait(false);
|
||||
releaseId = releaseGroupLookup.Releases?.Count > 0 ? releaseGroupLookup.Releases[0].Id.ToString() : null;
|
||||
}
|
||||
|
||||
// If there is no release ID, lookup a release with the info we have
|
||||
@@ -205,43 +199,106 @@ public class MusicBrainzAlbumProvider : IRemoteMetadataProvider<MusicAlbum, Albu
|
||||
{
|
||||
releaseGroupId = releaseResult.ReleaseGroup.Id.ToString();
|
||||
}
|
||||
|
||||
result.HasMetadata = true;
|
||||
result.Item.ProductionYear = releaseResult.Date?.Year;
|
||||
result.Item.Overview = releaseResult.Annotation;
|
||||
}
|
||||
}
|
||||
|
||||
// If we have a release ID but not a release group ID, lookup the release group
|
||||
if (!string.IsNullOrWhiteSpace(releaseId) && string.IsNullOrWhiteSpace(releaseGroupId))
|
||||
if (string.IsNullOrWhiteSpace(releaseId) && string.IsNullOrWhiteSpace(releaseGroupId))
|
||||
{
|
||||
var release = await query.LookupReleaseAsync(new Guid(releaseId), Include.ReleaseGroups, cancellationToken).ConfigureAwait(false);
|
||||
releaseGroupId = release.ReleaseGroup?.Id.ToString();
|
||||
result.HasMetadata = true;
|
||||
return result;
|
||||
}
|
||||
|
||||
// If we have a release ID and a release group ID
|
||||
if (!string.IsNullOrWhiteSpace(releaseId) || !string.IsNullOrWhiteSpace(releaseGroupId))
|
||||
// Fetch the full release (and its release group) so we can populate everything MusicBrainz returns.
|
||||
IRelease? release = null;
|
||||
if (!string.IsNullOrWhiteSpace(releaseId))
|
||||
{
|
||||
result.HasMetadata = true;
|
||||
}
|
||||
release = await query.LookupReleaseAsync(
|
||||
new Guid(releaseId),
|
||||
Include.Artists | Include.ReleaseGroups | Include.Labels | Include.Genres | Include.Tags,
|
||||
cancellationToken).ConfigureAwait(false);
|
||||
|
||||
if (result.HasMetadata)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(releaseId))
|
||||
if (string.IsNullOrWhiteSpace(releaseGroupId) && release?.ReleaseGroup?.Id is not null)
|
||||
{
|
||||
result.Item.SetProviderId(MetadataProvider.MusicBrainzAlbum, releaseId);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(releaseGroupId))
|
||||
{
|
||||
result.Item.SetProviderId(MetadataProvider.MusicBrainzReleaseGroup, releaseGroupId);
|
||||
releaseGroupId = release.ReleaseGroup.Id.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
IReleaseGroup? releaseGroup = null;
|
||||
if (!string.IsNullOrWhiteSpace(releaseGroupId))
|
||||
{
|
||||
releaseGroup = await query.LookupReleaseGroupAsync(
|
||||
new Guid(releaseGroupId),
|
||||
Include.Artists | Include.Genres | Include.Tags,
|
||||
null,
|
||||
cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
result.HasMetadata = true;
|
||||
|
||||
if (!string.IsNullOrEmpty(releaseId))
|
||||
{
|
||||
result.Item.SetProviderId(MetadataProvider.MusicBrainzAlbum, releaseId);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(releaseGroupId))
|
||||
{
|
||||
result.Item.SetProviderId(MetadataProvider.MusicBrainzReleaseGroup, releaseGroupId);
|
||||
}
|
||||
|
||||
Populate(result.Item, release, releaseGroup);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static void Populate(MusicAlbum item, IRelease? release, IReleaseGroup? releaseGroup)
|
||||
{
|
||||
// Prefer the release group (album-level) data, falling back to the specific release.
|
||||
// The release group's first release date is the original album date.
|
||||
var date = releaseGroup?.FirstReleaseDate ?? release?.Date;
|
||||
if (date is not null)
|
||||
{
|
||||
item.PremiereDate = date.NearestDate;
|
||||
item.ProductionYear = date.Year;
|
||||
}
|
||||
|
||||
var artistCredit = release?.ArtistCredit ?? releaseGroup?.ArtistCredit;
|
||||
if (artistCredit is not null && artistCredit.Count > 0)
|
||||
{
|
||||
item.AlbumArtists = artistCredit
|
||||
.Select(credit => credit.Name)
|
||||
.Where(name => !string.IsNullOrWhiteSpace(name))
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
var genres = releaseGroup?.Genres ?? release?.Genres;
|
||||
if (genres is not null && genres.Count > 0)
|
||||
{
|
||||
item.Genres = genres
|
||||
.OrderByDescending(genre => genre.VoteCount)
|
||||
.Select(genre => genre.Name)
|
||||
.Where(name => !string.IsNullOrWhiteSpace(name))
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
var tags = releaseGroup?.Tags ?? release?.Tags;
|
||||
if (tags is not null && tags.Count > 0)
|
||||
{
|
||||
item.Tags = tags
|
||||
.OrderByDescending(tag => tag.VoteCount)
|
||||
.Select(tag => tag.Name)
|
||||
.Where(name => !string.IsNullOrWhiteSpace(name))
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
if (release?.LabelInfo is not null && release.LabelInfo.Count > 0)
|
||||
{
|
||||
item.Studios = release.LabelInfo
|
||||
.Where(labelInfo => !string.IsNullOrWhiteSpace(labelInfo.Label?.Name))
|
||||
.Select(labelInfo => labelInfo.Label!.Name!)
|
||||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||
.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<HttpResponseMessage> GetImageResponse(string url, CancellationToken cancellationToken)
|
||||
{
|
||||
|
||||
@@ -40,6 +40,11 @@ public class MusicBrainzArtistProvider : IRemoteMetadataProvider<MusicArtist, Ar
|
||||
return GetResultFromResponse(artistResult).SingleItemAsEnumerable();
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(searchInfo.Name))
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
var artistSearchResults = await query.FindArtistsAsync($"\"{searchInfo.Name}\"", null, null, false, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
if (artistSearchResults.Results.Count > 0)
|
||||
@@ -58,7 +63,7 @@ public class MusicBrainzArtistProvider : IRemoteMetadataProvider<MusicArtist, Ar
|
||||
}
|
||||
}
|
||||
|
||||
return Enumerable.Empty<RemoteSearchResult>();
|
||||
return [];
|
||||
}
|
||||
|
||||
private IEnumerable<RemoteSearchResult> GetResultsFromResponse(IEnumerable<ISearchResult<IArtist>>? releaseSearchResults)
|
||||
@@ -96,28 +101,67 @@ public class MusicBrainzArtistProvider : IRemoteMetadataProvider<MusicArtist, Ar
|
||||
|
||||
var musicBrainzId = info.GetMusicBrainzArtistId();
|
||||
|
||||
// If we don't have an id yet, resolve one by name so we can look the artist up.
|
||||
if (string.IsNullOrWhiteSpace(musicBrainzId))
|
||||
{
|
||||
var searchResults = await GetSearchResults(info, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
var singleResult = searchResults.FirstOrDefault();
|
||||
|
||||
if (singleResult is not null)
|
||||
{
|
||||
musicBrainzId = singleResult.GetProviderId(MetadataProvider.MusicBrainzArtist);
|
||||
result.Item.Overview = singleResult.Overview;
|
||||
|
||||
if (Plugin.Instance!.Configuration.ReplaceArtistName)
|
||||
{
|
||||
result.Item.Name = singleResult.Name;
|
||||
}
|
||||
}
|
||||
musicBrainzId = searchResults.FirstOrDefault()?.GetProviderId(MetadataProvider.MusicBrainzArtist);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(musicBrainzId))
|
||||
if (string.IsNullOrWhiteSpace(musicBrainzId))
|
||||
{
|
||||
result.HasMetadata = true;
|
||||
result.Item.SetProviderId(MetadataProvider.MusicBrainzArtist, musicBrainzId);
|
||||
return result;
|
||||
}
|
||||
|
||||
var query = Plugin.Instance!.MusicBrainzQuery;
|
||||
var artist = await query.LookupArtistAsync(new Guid(musicBrainzId), Include.Genres | Include.Tags, null, null, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
if (artist is null)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
result.HasMetadata = true;
|
||||
result.Item.SetProviderId(MetadataProvider.MusicBrainzArtist, artist.Id.ToString());
|
||||
|
||||
if (Plugin.Instance!.Configuration.ReplaceArtistName && !string.IsNullOrWhiteSpace(artist.Name))
|
||||
{
|
||||
result.Item.Name = artist.Name;
|
||||
}
|
||||
|
||||
if (artist.LifeSpan?.Begin is not null)
|
||||
{
|
||||
result.Item.PremiereDate = artist.LifeSpan.Begin.NearestDate;
|
||||
result.Item.ProductionYear = artist.LifeSpan.Begin.Year;
|
||||
}
|
||||
|
||||
if (artist.LifeSpan?.End is not null)
|
||||
{
|
||||
result.Item.EndDate = artist.LifeSpan.End.NearestDate;
|
||||
}
|
||||
|
||||
var location = string.IsNullOrWhiteSpace(artist.Area?.Name) ? artist.Country : artist.Area!.Name;
|
||||
if (!string.IsNullOrWhiteSpace(location))
|
||||
{
|
||||
result.Item.ProductionLocations = [location];
|
||||
}
|
||||
|
||||
if (artist.Genres is not null && artist.Genres.Count > 0)
|
||||
{
|
||||
result.Item.Genres = artist.Genres
|
||||
.OrderByDescending(genre => genre.VoteCount)
|
||||
.Select(genre => genre.Name)
|
||||
.Where(name => !string.IsNullOrWhiteSpace(name))
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
if (artist.Tags is not null && artist.Tags.Count > 0)
|
||||
{
|
||||
result.Item.Tags = artist.Tags
|
||||
.OrderByDescending(tag => tag.VoteCount)
|
||||
.Select(tag => tag.Name)
|
||||
.Where(name => !string.IsNullOrWhiteSpace(name))
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
Reference in New Issue
Block a user