using System; using System.Collections.Generic; using System.Linq; using System.Net.Http; using System.Threading; using System.Threading.Tasks; using Jellyfin.Extensions; using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Providers; using MediaBrowser.Providers.Music; using MetaBrainz.MusicBrainz; using MetaBrainz.MusicBrainz.Interfaces.Entities; using MetaBrainz.MusicBrainz.Interfaces.Searches; using Microsoft.Extensions.Logging; namespace MediaBrowser.Providers.Plugins.MusicBrainz; /// /// MusicBrainz artist provider. /// public class MusicBrainzArtistProvider : IRemoteMetadataProvider, IDisposable { private readonly ILogger _logger; private readonly Query _musicBrainzQuery; private readonly string _musicBrainzDefaultUri = "https://musicbrainz.org"; /// /// Initializes a new instance of the class. /// /// The logger. public MusicBrainzArtistProvider(ILogger logger) { _logger = logger; MusicBrainz.Plugin.Instance!.ConfigurationChanged += (_, _) => { if (Uri.TryCreate(MusicBrainz.Plugin.Instance.Configuration.Server, UriKind.Absolute, out var server)) { Query.DefaultServer = server.Host; Query.DefaultPort = server.Port; Query.DefaultUrlScheme = server.Scheme; } else { // Fallback to official server _logger.LogWarning("Invalid MusicBrainz server specified, falling back to official server"); var defaultServer = new Uri(_musicBrainzDefaultUri); Query.DefaultServer = defaultServer.Host; Query.DefaultPort = defaultServer.Port; Query.DefaultUrlScheme = defaultServer.Scheme; } Query.DelayBetweenRequests = MusicBrainz.Plugin.Instance.Configuration.RateLimit; }; _musicBrainzQuery = new Query(); } /// public string Name => "MusicBrainz"; /// public async Task> GetSearchResults(ArtistInfo searchInfo, CancellationToken cancellationToken) { var artistId = searchInfo.GetMusicBrainzArtistId(); if (!string.IsNullOrWhiteSpace(artistId)) { var artistResult = await _musicBrainzQuery.LookupArtistAsync(new Guid(artistId), Include.Aliases, null, null, cancellationToken).ConfigureAwait(false); return GetResultFromResponse(artistResult).SingleItemAsEnumerable(); } var artistSearchResults = await _musicBrainzQuery.FindArtistsAsync($"\"{searchInfo.Name}\"", null, null, false, cancellationToken) .ConfigureAwait(false); if (artistSearchResults.Results.Count > 0) { return GetResultsFromResponse(artistSearchResults.Results); } if (searchInfo.Name.HasDiacritics()) { // Try again using the search with an accented characters query var artistAccentsSearchResults = await _musicBrainzQuery.FindArtistsAsync($"artistaccent:\"{searchInfo.Name}\"", null, null, false, cancellationToken) .ConfigureAwait(false); if (artistAccentsSearchResults.Results.Count > 0) { return GetResultsFromResponse(artistAccentsSearchResults.Results); } } return Enumerable.Empty(); } private IEnumerable GetResultsFromResponse(IEnumerable>? releaseSearchResults) { if (releaseSearchResults is null) { yield break; } foreach (var result in releaseSearchResults) { yield return GetResultFromResponse(result.Item); } } private RemoteSearchResult GetResultFromResponse(IArtist artist) { var searchResult = new RemoteSearchResult { Name = artist.Name, ProductionYear = artist.LifeSpan?.Begin?.Year, PremiereDate = artist.LifeSpan?.Begin?.NearestDate }; searchResult.SetProviderId(MetadataProvider.MusicBrainzArtist, artist.Id.ToString()); return searchResult; } /// public async Task> GetMetadata(ArtistInfo info, CancellationToken cancellationToken) { var result = new MetadataResult { Item = new MusicArtist() }; var musicBrainzId = info.GetMusicBrainzArtistId(); 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; } } } if (!string.IsNullOrWhiteSpace(musicBrainzId)) { result.HasMetadata = true; result.Item.SetProviderId(MetadataProvider.MusicBrainzArtist, musicBrainzId); } return result; } /// public Task GetImageResponse(string url, CancellationToken cancellationToken) { throw new NotImplementedException(); } /// public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } /// /// Dispose all resources. /// /// Whether to dispose. protected virtual void Dispose(bool disposing) { if (disposing) { _musicBrainzQuery.Dispose(); } } }