< Summary - Jellyfin

Information
Class: MediaBrowser.Providers.Plugins.MusicBrainz.MusicBrainzArtistProvider
Assembly: MediaBrowser.Providers
File(s): /srv/git/jellyfin/MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzArtistProvider.cs
Line coverage
0%
Covered lines: 0
Uncovered lines: 72
Coverable lines: 72
Total lines: 175
Line coverage: 0%
Branch coverage
0%
Covered branches: 0
Total branches: 56
Branch coverage: 0%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Coverage history

Coverage history 0 25 50 75 100 5/6/2026 - 12:15:23 AM Line coverage: 26.7% (19/71) Branch coverage: 9.3% (3/32) Total lines: 1905/7/2026 - 12:15:44 AM Line coverage: 0% (0/48) Branch coverage: 0% (0/28) Total lines: 1317/29/2026 - 12:15:53 AM Line coverage: 0% (0/72) Branch coverage: 0% (0/56) Total lines: 175 5/6/2026 - 12:15:23 AM Line coverage: 26.7% (19/71) Branch coverage: 9.3% (3/32) Total lines: 1905/7/2026 - 12:15:44 AM Line coverage: 0% (0/48) Branch coverage: 0% (0/28) Total lines: 1317/29/2026 - 12:15:53 AM Line coverage: 0% (0/72) Branch coverage: 0% (0/56) Total lines: 175

Coverage delta

Coverage delta 27 -27

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
get_Name()100%210%
get_Order()100%210%
GetSearchResults()0%110100%
GetResultsFromResponse()0%2040%
GetResultFromResponse(...)0%7280%
GetMetadata()0%1190340%
GetImageResponse(...)100%210%

File(s)

/srv/git/jellyfin/MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzArtistProvider.cs

#LineLine coverage
 1using System;
 2using System.Collections.Generic;
 3using System.Linq;
 4using System.Net.Http;
 5using System.Threading;
 6using System.Threading.Tasks;
 7using Jellyfin.Extensions;
 8using MediaBrowser.Controller.Entities.Audio;
 9using MediaBrowser.Controller.Providers;
 10using MediaBrowser.Model.Entities;
 11using MediaBrowser.Model.Providers;
 12using MediaBrowser.Providers.Music;
 13using MetaBrainz.MusicBrainz;
 14using MetaBrainz.MusicBrainz.Interfaces.Entities;
 15using MetaBrainz.MusicBrainz.Interfaces.Searches;
 16
 17namespace MediaBrowser.Providers.Plugins.MusicBrainz;
 18
 19/// <summary>
 20/// MusicBrainz artist provider.
 21/// </summary>
 22public class MusicBrainzArtistProvider : IRemoteMetadataProvider<MusicArtist, ArtistInfo>, IHasOrder
 23{
 24    /// <inheritdoc />
 025    public string Name => "MusicBrainz";
 26
 27    /// <inheritdoc />
 28    /// Runs first to populate the MusicBrainz artist ID used by downstream providers.
 029    public int Order => 0;
 30
 31    /// <inheritdoc />
 32    public async Task<IEnumerable<RemoteSearchResult>> GetSearchResults(ArtistInfo searchInfo, CancellationToken cancell
 33    {
 034        var query = MusicBrainz.Plugin.Instance!.MusicBrainzQuery;
 035        var artistId = searchInfo.GetMusicBrainzArtistId();
 36
 037        if (!string.IsNullOrWhiteSpace(artistId))
 38        {
 039            var artistResult = await query.LookupArtistAsync(new Guid(artistId), Include.Aliases, null, null, cancellati
 040            return GetResultFromResponse(artistResult).SingleItemAsEnumerable();
 41        }
 42
 043        if (string.IsNullOrWhiteSpace(searchInfo.Name))
 44        {
 045            return [];
 46        }
 47
 048        var artistSearchResults = await query.FindArtistsAsync($"\"{searchInfo.Name}\"", null, null, false, cancellation
 049            .ConfigureAwait(false);
 050        if (artistSearchResults.Results.Count > 0)
 51        {
 052            return GetResultsFromResponse(artistSearchResults.Results);
 53        }
 54
 055        if (searchInfo.Name.HasDiacritics())
 56        {
 57            // Try again using the search with an accented characters query
 058            var artistAccentsSearchResults = await query.FindArtistsAsync($"artistaccent:\"{searchInfo.Name}\"", null, n
 059                .ConfigureAwait(false);
 060            if (artistAccentsSearchResults.Results.Count > 0)
 61            {
 062                return GetResultsFromResponse(artistAccentsSearchResults.Results);
 63            }
 64        }
 65
 066        return [];
 067    }
 68
 69    private IEnumerable<RemoteSearchResult> GetResultsFromResponse(IEnumerable<ISearchResult<IArtist>>? releaseSearchRes
 70    {
 071        if (releaseSearchResults is null)
 72        {
 073            yield break;
 74        }
 75
 076        foreach (var result in releaseSearchResults)
 77        {
 078            yield return GetResultFromResponse(result.Item);
 79        }
 080    }
 81
 82    private RemoteSearchResult GetResultFromResponse(IArtist artist)
 83    {
 084        var searchResult = new RemoteSearchResult
 085        {
 086            Name = artist.Name,
 087            ProductionYear = artist.LifeSpan?.Begin?.Year,
 088            PremiereDate = artist.LifeSpan?.Begin?.NearestDate,
 089            SearchProviderName = Name,
 090        };
 91
 092        searchResult.SetProviderId(MetadataProvider.MusicBrainzArtist, artist.Id.ToString());
 93
 094        return searchResult;
 95    }
 96
 97    /// <inheritdoc />
 98    public async Task<MetadataResult<MusicArtist>> GetMetadata(ArtistInfo info, CancellationToken cancellationToken)
 99    {
 0100        var result = new MetadataResult<MusicArtist> { Item = new MusicArtist() };
 101
 0102        var musicBrainzId = info.GetMusicBrainzArtistId();
 103
 104        // If we don't have an id yet, resolve one by name so we can look the artist up.
 0105        if (string.IsNullOrWhiteSpace(musicBrainzId))
 106        {
 0107            var searchResults = await GetSearchResults(info, cancellationToken).ConfigureAwait(false);
 0108            musicBrainzId = searchResults.FirstOrDefault()?.GetProviderId(MetadataProvider.MusicBrainzArtist);
 109        }
 110
 0111        if (string.IsNullOrWhiteSpace(musicBrainzId))
 112        {
 0113            return result;
 114        }
 115
 0116        var query = Plugin.Instance!.MusicBrainzQuery;
 0117        var artist = await query.LookupArtistAsync(new Guid(musicBrainzId), Include.Genres | Include.Tags, null, null, c
 118
 0119        if (artist is null)
 120        {
 0121            return result;
 122        }
 123
 0124        result.HasMetadata = true;
 0125        result.Item.SetProviderId(MetadataProvider.MusicBrainzArtist, artist.Id.ToString());
 126
 0127        if (Plugin.Instance!.Configuration.ReplaceArtistName && !string.IsNullOrWhiteSpace(artist.Name))
 128        {
 0129            result.Item.Name = artist.Name;
 130        }
 131
 0132        if (artist.LifeSpan?.Begin is not null)
 133        {
 0134            result.Item.PremiereDate = artist.LifeSpan.Begin.NearestDate;
 0135            result.Item.ProductionYear = artist.LifeSpan.Begin.Year;
 136        }
 137
 0138        if (artist.LifeSpan?.End is not null)
 139        {
 0140            result.Item.EndDate = artist.LifeSpan.End.NearestDate;
 141        }
 142
 0143        var location = string.IsNullOrWhiteSpace(artist.Area?.Name) ? artist.Country : artist.Area!.Name;
 0144        if (!string.IsNullOrWhiteSpace(location))
 145        {
 0146            result.Item.ProductionLocations = [location];
 147        }
 148
 0149        if (artist.Genres is not null && artist.Genres.Count > 0)
 150        {
 0151            result.Item.Genres = artist.Genres
 0152                .OrderByDescending(genre => genre.VoteCount)
 0153                .Select(genre => genre.Name)
 0154                .Where(name => !string.IsNullOrWhiteSpace(name))
 0155                .ToArray();
 156        }
 157
 0158        if (artist.Tags is not null && artist.Tags.Count > 0)
 159        {
 0160            result.Item.Tags = artist.Tags
 0161                .OrderByDescending(tag => tag.VoteCount)
 0162                .Select(tag => tag.Name)
 0163                .Where(name => !string.IsNullOrWhiteSpace(name))
 0164                .ToArray();
 165        }
 166
 0167        return result;
 0168    }
 169
 170    /// <inheritdoc />
 171    public Task<HttpResponseMessage> GetImageResponse(string url, CancellationToken cancellationToken)
 172    {
 0173        throw new NotImplementedException();
 174    }
 175}