< Summary - Jellyfin

Information
Class: MediaBrowser.Providers.Plugins.AudioDb.AudioDbAlbumProvider
Assembly: MediaBrowser.Providers
File(s): /srv/git/jellyfin/MediaBrowser.Providers/Plugins/AudioDb/AudioDbAlbumProvider.cs
Line coverage
6%
Covered lines: 6
Uncovered lines: 87
Coverable lines: 93
Total lines: 315
Line coverage: 6.4%
Branch coverage
0%
Covered branches: 0
Total branches: 95
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/16/2026 - 12:15:55 AM Line coverage: 7.5% (6/80) Branch coverage: 0% (0/46) Total lines: 3036/14/2026 - 12:16:28 AM Line coverage: 7.3% (6/82) Branch coverage: 0% (0/48) Total lines: 30710/29/2026 - 12:17:11 AM Line coverage: 6.4% (6/93) Branch coverage: 0% (0/95) Total lines: 315 5/16/2026 - 12:15:55 AM Line coverage: 7.5% (6/80) Branch coverage: 0% (0/46) Total lines: 3036/14/2026 - 12:16:28 AM Line coverage: 7.3% (6/82) Branch coverage: 0% (0/48) Total lines: 30710/29/2026 - 12:17:11 AM Line coverage: 6.4% (6/93) Branch coverage: 0% (0/95) Total lines: 315

Coverage delta

Coverage delta 1 -1

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%11100%
get_Name()100%210%
get_Order()100%210%
GetSearchResults(...)100%210%
GetMetadata()0%7280%
ProcessResult(...)0%272160%
GetDescription(...)0%3782610%
EnsureInfo()0%2040%
DownloadInfo()0%4260%
GetAlbumDataPath(...)100%210%
GetAlbumDataPath(...)100%210%
GetAlbumInfoPath(...)100%210%
GetImageResponse(...)100%210%

File(s)

/srv/git/jellyfin/MediaBrowser.Providers/Plugins/AudioDb/AudioDbAlbumProvider.cs

#LineLine coverage
 1#nullable disable
 2
 3#pragma warning disable CA1002, CS1591, SA1300
 4
 5using System;
 6using System.Collections.Generic;
 7using System.Globalization;
 8using System.IO;
 9using System.Linq;
 10using System.Net.Http;
 11using System.Text.Json;
 12using System.Threading;
 13using System.Threading.Tasks;
 14using Jellyfin.Extensions.Json;
 15using MediaBrowser.Common.Configuration;
 16using MediaBrowser.Common.Extensions;
 17using MediaBrowser.Common.Net;
 18using MediaBrowser.Controller.Configuration;
 19using MediaBrowser.Controller.Entities.Audio;
 20using MediaBrowser.Controller.Providers;
 21using MediaBrowser.Model.Entities;
 22using MediaBrowser.Model.IO;
 23using MediaBrowser.Model.Providers;
 24using MediaBrowser.Providers.Manager;
 25using MediaBrowser.Providers.Music;
 26
 27namespace MediaBrowser.Providers.Plugins.AudioDb
 28{
 29    public class AudioDbAlbumProvider : IRemoteMetadataProvider<MusicAlbum, AlbumInfo>, IHasOrder
 30    {
 31        private readonly IServerConfigurationManager _config;
 32        private readonly IFileSystem _fileSystem;
 33        private readonly IHttpClientFactory _httpClientFactory;
 2734        private readonly JsonSerializerOptions _jsonOptions = JsonDefaults.Options;
 35
 36#pragma warning disable SA1401, CA2211
 37        public static AudioDbAlbumProvider Current;
 38#pragma warning restore SA1401, CA2211
 39
 40        public AudioDbAlbumProvider(IServerConfigurationManager config, IFileSystem fileSystem, IHttpClientFactory httpC
 41        {
 2742            _config = config;
 2743            _fileSystem = fileSystem;
 2744            _httpClientFactory = httpClientFactory;
 45
 2746            Current = this;
 2747        }
 48
 49        /// <inheritdoc />
 050        public string Name => "TheAudioDB";
 51
 52        /// <inheritdoc />
 53        // After music brainz
 054        public int Order => 1;
 55
 56        /// <inheritdoc />
 57        public Task<IEnumerable<RemoteSearchResult>> GetSearchResults(AlbumInfo searchInfo, CancellationToken cancellati
 058            => Task.FromResult(Enumerable.Empty<RemoteSearchResult>());
 59
 60        /// <inheritdoc />
 61        public async Task<MetadataResult<MusicAlbum>> GetMetadata(AlbumInfo info, CancellationToken cancellationToken)
 62        {
 063            var result = new MetadataResult<MusicAlbum>();
 064            var id = info.GetReleaseGroupId();
 65
 066            if (!string.IsNullOrWhiteSpace(id))
 67            {
 068                await EnsureInfo(id, cancellationToken).ConfigureAwait(false);
 69
 070                var path = GetAlbumInfoPath(_config.ApplicationPaths, id);
 71
 072                FileStream jsonStream = AsyncFile.OpenRead(path);
 073                await using (jsonStream.ConfigureAwait(false))
 74                {
 075                    var obj = await JsonSerializer.DeserializeAsync<RootObject>(jsonStream, _jsonOptions, cancellationTo
 76
 077                    if (obj is not null && obj.album is not null && obj.album.Count > 0)
 78                    {
 079                        result.Item = new MusicAlbum();
 080                        result.HasMetadata = true;
 081                        ProcessResult(result, obj.album[0], info.MetadataLanguage);
 82                    }
 83                }
 84            }
 85
 086            return result;
 087        }
 88
 89        private void ProcessResult(MetadataResult<MusicAlbum> metadataResult, Album result, string preferredLanguage)
 90        {
 091            var item = metadataResult.Item;
 92
 093            if (Plugin.Instance.Configuration.ReplaceAlbumName && !string.IsNullOrWhiteSpace(result.strAlbum))
 94            {
 095                item.Album = result.strAlbum;
 96            }
 97
 098            if (!string.IsNullOrWhiteSpace(result.strArtist))
 99            {
 0100                item.AlbumArtists = [result.strArtist];
 101            }
 102
 0103            if (!string.IsNullOrEmpty(result.intYearReleased))
 104            {
 0105                item.ProductionYear = int.Parse(result.intYearReleased, CultureInfo.InvariantCulture);
 106            }
 107
 0108            if (!string.IsNullOrEmpty(result.strGenre))
 109            {
 0110                item.Genres = [result.strGenre];
 111            }
 112
 0113            item.SetProviderId(MetadataProvider.AudioDbArtist, result.idArtist);
 0114            item.SetProviderId(MetadataProvider.AudioDbAlbum, result.idAlbum);
 115
 0116            item.SetProviderId(MetadataProvider.MusicBrainzAlbumArtist, result.strMusicBrainzArtistID);
 0117            item.SetProviderId(MetadataProvider.MusicBrainzReleaseGroup, result.strMusicBrainzID);
 118
 0119            var language = MetadataLanguageUtils.GetLanguageSubtag(preferredLanguage);
 0120            var overview = GetDescription(result, language);
 121
 0122            if (string.IsNullOrWhiteSpace(overview))
 123            {
 0124                overview = string.IsNullOrWhiteSpace(result.strDescriptionEN)
 0125                    ? result.strDescription
 0126                    : result.strDescriptionEN;
 127
 128                // The description is not in the requested language, mark it as English so it does not
 129                // block a provider further down the list that can serve the requested language
 0130                metadataResult.ResultLanguage = "en";
 131            }
 132            else
 133            {
 0134                metadataResult.ResultLanguage = language;
 135            }
 136
 0137            item.Overview = (overview ?? string.Empty).StripHtml();
 0138        }
 139
 140        private static string GetDescription(Album result, string language)
 0141            => language switch
 0142            {
 0143                "de" => result.strDescriptionDE,
 0144                "en" => result.strDescriptionEN,
 0145                "es" => result.strDescriptionES,
 0146                "fr" => result.strDescriptionFR,
 0147                "he" => result.strDescriptionIL,
 0148                "hu" => result.strDescriptionHU,
 0149                "it" => result.strDescriptionIT,
 0150                "ja" => result.strDescriptionJP,
 0151                "nl" => result.strDescriptionNL,
 0152                "no" or "nb" or "nn" => result.strDescriptionNO,
 0153                "pl" => result.strDescriptionPL,
 0154                "pt" => result.strDescriptionPT,
 0155                "ru" => result.strDescriptionRU,
 0156                "sv" => result.strDescriptionSE,
 0157                "zh" => result.strDescriptionCN,
 0158                _ => null
 0159            };
 160
 161        internal async Task EnsureInfo(string musicBrainzReleaseGroupId, CancellationToken cancellationToken)
 162        {
 0163            var xmlPath = GetAlbumInfoPath(_config.ApplicationPaths, musicBrainzReleaseGroupId);
 164
 0165            var fileInfo = _fileSystem.GetFileSystemInfo(xmlPath);
 166
 0167            if (fileInfo.Exists
 0168                && (DateTime.UtcNow - _fileSystem.GetLastWriteTimeUtc(fileInfo)).TotalDays <= 2)
 169            {
 0170                return;
 171            }
 172
 0173            await DownloadInfo(musicBrainzReleaseGroupId, cancellationToken).ConfigureAwait(false);
 0174        }
 175
 176        internal async Task DownloadInfo(string musicBrainzReleaseGroupId, CancellationToken cancellationToken)
 177        {
 0178            cancellationToken.ThrowIfCancellationRequested();
 179
 0180            var url = AudioDbArtistProvider.BaseUrl + "/album-mb.php?i=" + musicBrainzReleaseGroupId;
 181
 0182            var path = GetAlbumInfoPath(_config.ApplicationPaths, musicBrainzReleaseGroupId);
 0183            var fileInfo = _fileSystem.GetFileSystemInfo(path);
 0184            if (fileInfo.Exists && (DateTime.UtcNow - _fileSystem.GetLastWriteTimeUtc(fileInfo)).TotalDays <= 2)
 185            {
 0186                return;
 187            }
 188
 0189            Directory.CreateDirectory(Path.GetDirectoryName(path));
 190
 0191            using var response = await _httpClientFactory.CreateClient(NamedClient.Default).GetAsync(url, cancellationTo
 0192            var fileStreamOptions = AsyncFile.WriteOptions;
 0193            fileStreamOptions.Mode = FileMode.Create;
 0194            var fs = new FileStream(path, fileStreamOptions);
 0195            await using (fs.ConfigureAwait(false))
 196            {
 0197                await response.Content.CopyToAsync(fs, cancellationToken).ConfigureAwait(false);
 198            }
 0199        }
 200
 201        private static string GetAlbumDataPath(IApplicationPaths appPaths, string musicBrainzReleaseGroupId)
 202        {
 0203            var dataPath = Path.Combine(GetAlbumDataPath(appPaths), musicBrainzReleaseGroupId);
 204
 0205            return dataPath;
 206        }
 207
 208        private static string GetAlbumDataPath(IApplicationPaths appPaths)
 209        {
 0210            var dataPath = Path.Combine(appPaths.CachePath, "audiodb-album");
 211
 0212            return dataPath;
 213        }
 214
 215        internal static string GetAlbumInfoPath(IApplicationPaths appPaths, string musicBrainzReleaseGroupId)
 216        {
 0217            var dataPath = GetAlbumDataPath(appPaths, musicBrainzReleaseGroupId);
 218
 0219            return Path.Combine(dataPath, "album.json");
 220        }
 221
 222        /// <inheritdoc />
 223        public Task<HttpResponseMessage> GetImageResponse(string url, CancellationToken cancellationToken)
 224        {
 0225            throw new NotImplementedException();
 226        }
 227
 228#pragma warning disable CA1034, CA2227
 229        public class Album
 230        {
 231            public string idAlbum { get; set; }
 232
 233            public string idArtist { get; set; }
 234
 235            public string strAlbum { get; set; }
 236
 237            public string strArtist { get; set; }
 238
 239            public string intYearReleased { get; set; }
 240
 241            public string strGenre { get; set; }
 242
 243            public string strSubGenre { get; set; }
 244
 245            public string strReleaseFormat { get; set; }
 246
 247            public string intSales { get; set; }
 248
 249            public string strAlbumThumb { get; set; }
 250
 251            public string strAlbumCDart { get; set; }
 252
 253            public string strDescription { get; set; }
 254
 255            public string strDescriptionEN { get; set; }
 256
 257            public string strDescriptionDE { get; set; }
 258
 259            public string strDescriptionFR { get; set; }
 260
 261            public string strDescriptionCN { get; set; }
 262
 263            public string strDescriptionIT { get; set; }
 264
 265            public string strDescriptionJP { get; set; }
 266
 267            public string strDescriptionRU { get; set; }
 268
 269            public string strDescriptionES { get; set; }
 270
 271            public string strDescriptionPT { get; set; }
 272
 273            public string strDescriptionSE { get; set; }
 274
 275            public string strDescriptionNL { get; set; }
 276
 277            public string strDescriptionHU { get; set; }
 278
 279            public string strDescriptionNO { get; set; }
 280
 281            public string strDescriptionIL { get; set; }
 282
 283            public string strDescriptionPL { get; set; }
 284
 285            public object intLoved { get; set; }
 286
 287            public object intScore { get; set; }
 288
 289            public string strReview { get; set; }
 290
 291            public object strMood { get; set; }
 292
 293            public object strTheme { get; set; }
 294
 295            public object strSpeed { get; set; }
 296
 297            public object strLocation { get; set; }
 298
 299            public string strMusicBrainzID { get; set; }
 300
 301            public string strMusicBrainzArtistID { get; set; }
 302
 303            public object strItunesID { get; set; }
 304
 305            public object strAmazonID { get; set; }
 306
 307            public string strLocked { get; set; }
 308        }
 309
 310        public class RootObject
 311        {
 312            public List<Album> album { get; set; }
 313        }
 314    }
 315}