|  | @@ -1,5 +1,6 @@
 | 
	
		
			
				|  |  |  using System;
 | 
	
		
			
				|  |  |  using System.Collections.Generic;
 | 
	
		
			
				|  |  | +using System.Globalization;
 | 
	
		
			
				|  |  |  using System.Linq;
 | 
	
		
			
				|  |  |  using System.Threading;
 | 
	
		
			
				|  |  |  using System.Threading.Tasks;
 | 
	
	
		
			
				|  | @@ -151,198 +152,212 @@ namespace MediaBrowser.Providers.MediaInfo
 | 
	
		
			
				|  |  |          /// <param name="tryExtractEmbeddedLyrics">Whether to extract embedded lyrics to lrc file. </param>
 | 
	
		
			
				|  |  |          private async Task FetchDataFromTags(Audio audio, Model.MediaInfo.MediaInfo mediaInfo, MetadataRefreshOptions options, bool tryExtractEmbeddedLyrics)
 | 
	
		
			
				|  |  |          {
 | 
	
		
			
				|  |  | -            using var file = TagLib.File.Create(audio.Path);
 | 
	
		
			
				|  |  | -            var tagTypes = file.TagTypesOnDisk;
 | 
	
		
			
				|  |  |              Tag? tags = null;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -            if (tagTypes.HasFlag(TagTypes.Id3v2))
 | 
	
		
			
				|  |  | -            {
 | 
	
		
			
				|  |  | -                tags = file.GetTag(TagTypes.Id3v2);
 | 
	
		
			
				|  |  | -            }
 | 
	
		
			
				|  |  | -            else if (tagTypes.HasFlag(TagTypes.Ape))
 | 
	
		
			
				|  |  | -            {
 | 
	
		
			
				|  |  | -                tags = file.GetTag(TagTypes.Ape);
 | 
	
		
			
				|  |  | -            }
 | 
	
		
			
				|  |  | -            else if (tagTypes.HasFlag(TagTypes.FlacMetadata))
 | 
	
		
			
				|  |  | -            {
 | 
	
		
			
				|  |  | -                tags = file.GetTag(TagTypes.FlacMetadata);
 | 
	
		
			
				|  |  | -            }
 | 
	
		
			
				|  |  | -            else if (tagTypes.HasFlag(TagTypes.Apple))
 | 
	
		
			
				|  |  | +            try
 | 
	
		
			
				|  |  |              {
 | 
	
		
			
				|  |  | -                tags = file.GetTag(TagTypes.Apple);
 | 
	
		
			
				|  |  | -            }
 | 
	
		
			
				|  |  | -            else if (tagTypes.HasFlag(TagTypes.Xiph))
 | 
	
		
			
				|  |  | -            {
 | 
	
		
			
				|  |  | -                tags = file.GetTag(TagTypes.Xiph);
 | 
	
		
			
				|  |  | -            }
 | 
	
		
			
				|  |  | -            else if (tagTypes.HasFlag(TagTypes.AudibleMetadata))
 | 
	
		
			
				|  |  | -            {
 | 
	
		
			
				|  |  | -                tags = file.GetTag(TagTypes.AudibleMetadata);
 | 
	
		
			
				|  |  | +                using var file = TagLib.File.Create(audio.Path);
 | 
	
		
			
				|  |  | +                var tagTypes = file.TagTypesOnDisk;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                if (tagTypes.HasFlag(TagTypes.Id3v2))
 | 
	
		
			
				|  |  | +                {
 | 
	
		
			
				|  |  | +                    tags = file.GetTag(TagTypes.Id3v2);
 | 
	
		
			
				|  |  | +                }
 | 
	
		
			
				|  |  | +                else if (tagTypes.HasFlag(TagTypes.Ape))
 | 
	
		
			
				|  |  | +                {
 | 
	
		
			
				|  |  | +                    tags = file.GetTag(TagTypes.Ape);
 | 
	
		
			
				|  |  | +                }
 | 
	
		
			
				|  |  | +                else if (tagTypes.HasFlag(TagTypes.FlacMetadata))
 | 
	
		
			
				|  |  | +                {
 | 
	
		
			
				|  |  | +                    tags = file.GetTag(TagTypes.FlacMetadata);
 | 
	
		
			
				|  |  | +                }
 | 
	
		
			
				|  |  | +                else if (tagTypes.HasFlag(TagTypes.Apple))
 | 
	
		
			
				|  |  | +                {
 | 
	
		
			
				|  |  | +                    tags = file.GetTag(TagTypes.Apple);
 | 
	
		
			
				|  |  | +                }
 | 
	
		
			
				|  |  | +                else if (tagTypes.HasFlag(TagTypes.Xiph))
 | 
	
		
			
				|  |  | +                {
 | 
	
		
			
				|  |  | +                    tags = file.GetTag(TagTypes.Xiph);
 | 
	
		
			
				|  |  | +                }
 | 
	
		
			
				|  |  | +                else if (tagTypes.HasFlag(TagTypes.AudibleMetadata))
 | 
	
		
			
				|  |  | +                {
 | 
	
		
			
				|  |  | +                    tags = file.GetTag(TagTypes.AudibleMetadata);
 | 
	
		
			
				|  |  | +                }
 | 
	
		
			
				|  |  | +                else if (tagTypes.HasFlag(TagTypes.Id3v1))
 | 
	
		
			
				|  |  | +                {
 | 
	
		
			
				|  |  | +                    tags = file.GetTag(TagTypes.Id3v1);
 | 
	
		
			
				|  |  | +                }
 | 
	
		
			
				|  |  |              }
 | 
	
		
			
				|  |  | -            else if (tagTypes.HasFlag(TagTypes.Id3v1))
 | 
	
		
			
				|  |  | +            catch (Exception e)
 | 
	
		
			
				|  |  |              {
 | 
	
		
			
				|  |  | -                tags = file.GetTag(TagTypes.Id3v1);
 | 
	
		
			
				|  |  | +                _logger.LogWarning(e, "TagLib-Sharp does not support this audio");
 | 
	
		
			
				|  |  |              }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -            if (tags is not null)
 | 
	
		
			
				|  |  | +            tags ??= new TagLib.Id3v2.Tag();
 | 
	
		
			
				|  |  | +            tags.AlbumArtists ??= mediaInfo.AlbumArtists;
 | 
	
		
			
				|  |  | +            tags.Album ??= mediaInfo.Album;
 | 
	
		
			
				|  |  | +            tags.Title ??= mediaInfo.Name;
 | 
	
		
			
				|  |  | +            tags.Year = tags.Year == 0U ? Convert.ToUInt32(mediaInfo.ProductionYear, CultureInfo.InvariantCulture) : tags.Year;
 | 
	
		
			
				|  |  | +            tags.Performers ??= mediaInfo.Artists;
 | 
	
		
			
				|  |  | +            tags.Genres ??= mediaInfo.Genres;
 | 
	
		
			
				|  |  | +            tags.Track = tags.Track == 0U ? Convert.ToUInt32(mediaInfo.IndexNumber, CultureInfo.InvariantCulture) : tags.Track;
 | 
	
		
			
				|  |  | +            tags.Disc = tags.Disc == 0U ? Convert.ToUInt32(mediaInfo.ParentIndexNumber, CultureInfo.InvariantCulture) : tags.Disc;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            if (audio.SupportsPeople && !audio.LockedFields.Contains(MetadataField.Cast))
 | 
	
		
			
				|  |  |              {
 | 
	
		
			
				|  |  | -                if (audio.SupportsPeople && !audio.LockedFields.Contains(MetadataField.Cast))
 | 
	
		
			
				|  |  | +                var people = new List<PersonInfo>();
 | 
	
		
			
				|  |  | +                var albumArtists = tags.AlbumArtists;
 | 
	
		
			
				|  |  | +                foreach (var albumArtist in albumArtists)
 | 
	
		
			
				|  |  |                  {
 | 
	
		
			
				|  |  | -                    var people = new List<PersonInfo>();
 | 
	
		
			
				|  |  | -                    var albumArtists = tags.AlbumArtists;
 | 
	
		
			
				|  |  | -                    foreach (var albumArtist in albumArtists)
 | 
	
		
			
				|  |  | +                    if (!string.IsNullOrEmpty(albumArtist))
 | 
	
		
			
				|  |  |                      {
 | 
	
		
			
				|  |  | -                        if (!string.IsNullOrEmpty(albumArtist))
 | 
	
		
			
				|  |  | +                        PeopleHelper.AddPerson(people, new PersonInfo
 | 
	
		
			
				|  |  |                          {
 | 
	
		
			
				|  |  | -                            PeopleHelper.AddPerson(people, new PersonInfo
 | 
	
		
			
				|  |  | -                            {
 | 
	
		
			
				|  |  | -                                Name = albumArtist,
 | 
	
		
			
				|  |  | -                                Type = PersonKind.AlbumArtist
 | 
	
		
			
				|  |  | -                            });
 | 
	
		
			
				|  |  | -                        }
 | 
	
		
			
				|  |  | +                            Name = albumArtist,
 | 
	
		
			
				|  |  | +                            Type = PersonKind.AlbumArtist
 | 
	
		
			
				|  |  | +                        });
 | 
	
		
			
				|  |  |                      }
 | 
	
		
			
				|  |  | +                }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -                    var performers = tags.Performers;
 | 
	
		
			
				|  |  | -                    foreach (var performer in performers)
 | 
	
		
			
				|  |  | +                var performers = tags.Performers;
 | 
	
		
			
				|  |  | +                foreach (var performer in performers)
 | 
	
		
			
				|  |  | +                {
 | 
	
		
			
				|  |  | +                    if (!string.IsNullOrEmpty(performer))
 | 
	
		
			
				|  |  |                      {
 | 
	
		
			
				|  |  | -                        if (!string.IsNullOrEmpty(performer))
 | 
	
		
			
				|  |  | +                        PeopleHelper.AddPerson(people, new PersonInfo
 | 
	
		
			
				|  |  |                          {
 | 
	
		
			
				|  |  | -                            PeopleHelper.AddPerson(people, new PersonInfo
 | 
	
		
			
				|  |  | -                            {
 | 
	
		
			
				|  |  | -                                Name = performer,
 | 
	
		
			
				|  |  | -                                Type = PersonKind.Artist
 | 
	
		
			
				|  |  | -                            });
 | 
	
		
			
				|  |  | -                        }
 | 
	
		
			
				|  |  | +                            Name = performer,
 | 
	
		
			
				|  |  | +                            Type = PersonKind.Artist
 | 
	
		
			
				|  |  | +                        });
 | 
	
		
			
				|  |  |                      }
 | 
	
		
			
				|  |  | +                }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -                    foreach (var composer in tags.Composers)
 | 
	
		
			
				|  |  | +                foreach (var composer in tags.Composers)
 | 
	
		
			
				|  |  | +                {
 | 
	
		
			
				|  |  | +                    if (!string.IsNullOrEmpty(composer))
 | 
	
		
			
				|  |  |                      {
 | 
	
		
			
				|  |  | -                        if (!string.IsNullOrEmpty(composer))
 | 
	
		
			
				|  |  | +                        PeopleHelper.AddPerson(people, new PersonInfo
 | 
	
		
			
				|  |  |                          {
 | 
	
		
			
				|  |  | -                            PeopleHelper.AddPerson(people, new PersonInfo
 | 
	
		
			
				|  |  | -                            {
 | 
	
		
			
				|  |  | -                                Name = composer,
 | 
	
		
			
				|  |  | -                                Type = PersonKind.Composer
 | 
	
		
			
				|  |  | -                            });
 | 
	
		
			
				|  |  | -                        }
 | 
	
		
			
				|  |  | -                    }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -                    _libraryManager.UpdatePeople(audio, people);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -                    if (options.ReplaceAllMetadata && performers.Length != 0)
 | 
	
		
			
				|  |  | -                    {
 | 
	
		
			
				|  |  | -                        audio.Artists = performers;
 | 
	
		
			
				|  |  | -                    }
 | 
	
		
			
				|  |  | -                    else if (!options.ReplaceAllMetadata
 | 
	
		
			
				|  |  | -                             && (audio.Artists is null || audio.Artists.Count == 0))
 | 
	
		
			
				|  |  | -                    {
 | 
	
		
			
				|  |  | -                        audio.Artists = performers;
 | 
	
		
			
				|  |  | -                    }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -                    if (albumArtists.Length == 0)
 | 
	
		
			
				|  |  | -                    {
 | 
	
		
			
				|  |  | -                        // Album artists not provided, fall back to performers (artists).
 | 
	
		
			
				|  |  | -                        albumArtists = performers;
 | 
	
		
			
				|  |  | -                    }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -                    if (options.ReplaceAllMetadata && albumArtists.Length != 0)
 | 
	
		
			
				|  |  | -                    {
 | 
	
		
			
				|  |  | -                        audio.AlbumArtists = albumArtists;
 | 
	
		
			
				|  |  | -                    }
 | 
	
		
			
				|  |  | -                    else if (!options.ReplaceAllMetadata
 | 
	
		
			
				|  |  | -                             && (audio.AlbumArtists is null || audio.AlbumArtists.Count == 0))
 | 
	
		
			
				|  |  | -                    {
 | 
	
		
			
				|  |  | -                        audio.AlbumArtists = albumArtists;
 | 
	
		
			
				|  |  | +                            Name = composer,
 | 
	
		
			
				|  |  | +                            Type = PersonKind.Composer
 | 
	
		
			
				|  |  | +                        });
 | 
	
		
			
				|  |  |                      }
 | 
	
		
			
				|  |  |                  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -                if (!audio.LockedFields.Contains(MetadataField.Name) && !string.IsNullOrEmpty(tags.Title))
 | 
	
		
			
				|  |  | -                {
 | 
	
		
			
				|  |  | -                    audio.Name = tags.Title;
 | 
	
		
			
				|  |  | -                }
 | 
	
		
			
				|  |  | +                _libraryManager.UpdatePeople(audio, people);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -                if (options.ReplaceAllMetadata)
 | 
	
		
			
				|  |  | +                if (options.ReplaceAllMetadata && performers.Length != 0)
 | 
	
		
			
				|  |  |                  {
 | 
	
		
			
				|  |  | -                    audio.Album = tags.Album;
 | 
	
		
			
				|  |  | -                    audio.IndexNumber = Convert.ToInt32(tags.Track);
 | 
	
		
			
				|  |  | -                    audio.ParentIndexNumber = Convert.ToInt32(tags.Disc);
 | 
	
		
			
				|  |  | +                    audio.Artists = performers;
 | 
	
		
			
				|  |  |                  }
 | 
	
		
			
				|  |  | -                else
 | 
	
		
			
				|  |  | +                else if (!options.ReplaceAllMetadata
 | 
	
		
			
				|  |  | +                         && (audio.Artists is null || audio.Artists.Count == 0))
 | 
	
		
			
				|  |  |                  {
 | 
	
		
			
				|  |  | -                    audio.Album ??= tags.Album;
 | 
	
		
			
				|  |  | -                    audio.IndexNumber ??= Convert.ToInt32(tags.Track);
 | 
	
		
			
				|  |  | -                    audio.ParentIndexNumber ??= Convert.ToInt32(tags.Disc);
 | 
	
		
			
				|  |  | +                    audio.Artists = performers;
 | 
	
		
			
				|  |  |                  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -                if (tags.Year != 0)
 | 
	
		
			
				|  |  | +                if (albumArtists.Length == 0)
 | 
	
		
			
				|  |  |                  {
 | 
	
		
			
				|  |  | -                    var year = Convert.ToInt32(tags.Year);
 | 
	
		
			
				|  |  | -                    audio.ProductionYear = year;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -                    if (!audio.PremiereDate.HasValue)
 | 
	
		
			
				|  |  | -                    {
 | 
	
		
			
				|  |  | -                        try
 | 
	
		
			
				|  |  | -                        {
 | 
	
		
			
				|  |  | -                            audio.PremiereDate = new DateTime(year, 01, 01);
 | 
	
		
			
				|  |  | -                        }
 | 
	
		
			
				|  |  | -                        catch (ArgumentOutOfRangeException ex)
 | 
	
		
			
				|  |  | -                        {
 | 
	
		
			
				|  |  | -                            _logger.LogError(ex, "Error parsing YEAR tag in {File}. '{TagValue}' is an invalid year.", audio.Path, tags.Year);
 | 
	
		
			
				|  |  | -                        }
 | 
	
		
			
				|  |  | -                    }
 | 
	
		
			
				|  |  | +                    // Album artists not provided, fall back to performers (artists).
 | 
	
		
			
				|  |  | +                    albumArtists = performers;
 | 
	
		
			
				|  |  |                  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -                if (!audio.LockedFields.Contains(MetadataField.Genres))
 | 
	
		
			
				|  |  | +                if (options.ReplaceAllMetadata && albumArtists.Length != 0)
 | 
	
		
			
				|  |  |                  {
 | 
	
		
			
				|  |  | -                    audio.Genres = options.ReplaceAllMetadata || audio.Genres == null || audio.Genres.Length == 0
 | 
	
		
			
				|  |  | -                        ? tags.Genres.Distinct(StringComparer.OrdinalIgnoreCase).ToArray()
 | 
	
		
			
				|  |  | -                        : audio.Genres;
 | 
	
		
			
				|  |  | +                    audio.AlbumArtists = albumArtists;
 | 
	
		
			
				|  |  |                  }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -                if (!double.IsNaN(tags.ReplayGainTrackGain))
 | 
	
		
			
				|  |  | +                else if (!options.ReplaceAllMetadata
 | 
	
		
			
				|  |  | +                         && (audio.AlbumArtists is null || audio.AlbumArtists.Count == 0))
 | 
	
		
			
				|  |  |                  {
 | 
	
		
			
				|  |  | -                    audio.NormalizationGain = (float)tags.ReplayGainTrackGain;
 | 
	
		
			
				|  |  | -                }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -                if (options.ReplaceAllMetadata || !audio.TryGetProviderId(MetadataProvider.MusicBrainzArtist, out _))
 | 
	
		
			
				|  |  | -                {
 | 
	
		
			
				|  |  | -                    audio.SetProviderId(MetadataProvider.MusicBrainzArtist, tags.MusicBrainzArtistId);
 | 
	
		
			
				|  |  | +                    audio.AlbumArtists = albumArtists;
 | 
	
		
			
				|  |  |                  }
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -                if (options.ReplaceAllMetadata || !audio.TryGetProviderId(MetadataProvider.MusicBrainzAlbumArtist, out _))
 | 
	
		
			
				|  |  | -                {
 | 
	
		
			
				|  |  | -                    audio.SetProviderId(MetadataProvider.MusicBrainzAlbumArtist, tags.MusicBrainzReleaseArtistId);
 | 
	
		
			
				|  |  | -                }
 | 
	
		
			
				|  |  | +            if (!audio.LockedFields.Contains(MetadataField.Name) && !string.IsNullOrEmpty(tags.Title))
 | 
	
		
			
				|  |  | +            {
 | 
	
		
			
				|  |  | +                audio.Name = tags.Title;
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -                if (options.ReplaceAllMetadata || !audio.TryGetProviderId(MetadataProvider.MusicBrainzAlbum, out _))
 | 
	
		
			
				|  |  | -                {
 | 
	
		
			
				|  |  | -                    audio.SetProviderId(MetadataProvider.MusicBrainzAlbum, tags.MusicBrainzReleaseId);
 | 
	
		
			
				|  |  | -                }
 | 
	
		
			
				|  |  | +            if (options.ReplaceAllMetadata)
 | 
	
		
			
				|  |  | +            {
 | 
	
		
			
				|  |  | +                audio.Album = tags.Album;
 | 
	
		
			
				|  |  | +                audio.IndexNumber = Convert.ToInt32(tags.Track);
 | 
	
		
			
				|  |  | +                audio.ParentIndexNumber = Convert.ToInt32(tags.Disc);
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +            else
 | 
	
		
			
				|  |  | +            {
 | 
	
		
			
				|  |  | +                audio.Album ??= tags.Album;
 | 
	
		
			
				|  |  | +                audio.IndexNumber ??= Convert.ToInt32(tags.Track);
 | 
	
		
			
				|  |  | +                audio.ParentIndexNumber ??= Convert.ToInt32(tags.Disc);
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -                if (options.ReplaceAllMetadata || !audio.TryGetProviderId(MetadataProvider.MusicBrainzReleaseGroup, out _))
 | 
	
		
			
				|  |  | -                {
 | 
	
		
			
				|  |  | -                    audio.SetProviderId(MetadataProvider.MusicBrainzReleaseGroup, tags.MusicBrainzReleaseGroupId);
 | 
	
		
			
				|  |  | -                }
 | 
	
		
			
				|  |  | +            if (tags.Year != 0)
 | 
	
		
			
				|  |  | +            {
 | 
	
		
			
				|  |  | +                var year = Convert.ToInt32(tags.Year);
 | 
	
		
			
				|  |  | +                audio.ProductionYear = year;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -                if (options.ReplaceAllMetadata || !audio.TryGetProviderId(MetadataProvider.MusicBrainzTrack, out _))
 | 
	
		
			
				|  |  | +                if (!audio.PremiereDate.HasValue)
 | 
	
		
			
				|  |  |                  {
 | 
	
		
			
				|  |  | -                    // Fallback to ffprobe as TagLib incorrectly provides recording MBID in `tags.MusicBrainzTrackId`.
 | 
	
		
			
				|  |  | -                    // See https://github.com/mono/taglib-sharp/issues/304
 | 
	
		
			
				|  |  | -                    var trackMbId = mediaInfo.GetProviderId(MetadataProvider.MusicBrainzTrack);
 | 
	
		
			
				|  |  | -                    if (trackMbId is not null)
 | 
	
		
			
				|  |  | +                    try
 | 
	
		
			
				|  |  |                      {
 | 
	
		
			
				|  |  | -                        audio.SetProviderId(MetadataProvider.MusicBrainzTrack, trackMbId);
 | 
	
		
			
				|  |  | +                        audio.PremiereDate = new DateTime(year, 01, 01);
 | 
	
		
			
				|  |  | +                    }
 | 
	
		
			
				|  |  | +                    catch (ArgumentOutOfRangeException ex)
 | 
	
		
			
				|  |  | +                    {
 | 
	
		
			
				|  |  | +                        _logger.LogError(ex, "Error parsing YEAR tag in {File}. '{TagValue}' is an invalid year", audio.Path, tags.Year);
 | 
	
		
			
				|  |  |                      }
 | 
	
		
			
				|  |  |                  }
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            if (!audio.LockedFields.Contains(MetadataField.Genres))
 | 
	
		
			
				|  |  | +            {
 | 
	
		
			
				|  |  | +                audio.Genres = options.ReplaceAllMetadata || audio.Genres == null || audio.Genres.Length == 0
 | 
	
		
			
				|  |  | +                    ? tags.Genres.Distinct(StringComparer.OrdinalIgnoreCase).ToArray()
 | 
	
		
			
				|  |  | +                    : audio.Genres;
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            if (!double.IsNaN(tags.ReplayGainTrackGain))
 | 
	
		
			
				|  |  | +            {
 | 
	
		
			
				|  |  | +                audio.NormalizationGain = (float)tags.ReplayGainTrackGain;
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            if (options.ReplaceAllMetadata || !audio.TryGetProviderId(MetadataProvider.MusicBrainzArtist, out _))
 | 
	
		
			
				|  |  | +            {
 | 
	
		
			
				|  |  | +                audio.SetProviderId(MetadataProvider.MusicBrainzArtist, tags.MusicBrainzArtistId);
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            if (options.ReplaceAllMetadata || !audio.TryGetProviderId(MetadataProvider.MusicBrainzAlbumArtist, out _))
 | 
	
		
			
				|  |  | +            {
 | 
	
		
			
				|  |  | +                audio.SetProviderId(MetadataProvider.MusicBrainzAlbumArtist, tags.MusicBrainzReleaseArtistId);
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            if (options.ReplaceAllMetadata || !audio.TryGetProviderId(MetadataProvider.MusicBrainzAlbum, out _))
 | 
	
		
			
				|  |  | +            {
 | 
	
		
			
				|  |  | +                audio.SetProviderId(MetadataProvider.MusicBrainzAlbum, tags.MusicBrainzReleaseId);
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            if (options.ReplaceAllMetadata || !audio.TryGetProviderId(MetadataProvider.MusicBrainzReleaseGroup, out _))
 | 
	
		
			
				|  |  | +            {
 | 
	
		
			
				|  |  | +                audio.SetProviderId(MetadataProvider.MusicBrainzReleaseGroup, tags.MusicBrainzReleaseGroupId);
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -                // Save extracted lyrics if they exist,
 | 
	
		
			
				|  |  | -                // and if the audio doesn't yet have lyrics.
 | 
	
		
			
				|  |  | -                if (!string.IsNullOrWhiteSpace(tags.Lyrics)
 | 
	
		
			
				|  |  | -                    && tryExtractEmbeddedLyrics)
 | 
	
		
			
				|  |  | +            if (options.ReplaceAllMetadata || !audio.TryGetProviderId(MetadataProvider.MusicBrainzTrack, out _))
 | 
	
		
			
				|  |  | +            {
 | 
	
		
			
				|  |  | +                // Fallback to ffprobe as TagLib incorrectly provides recording MBID in `tags.MusicBrainzTrackId`.
 | 
	
		
			
				|  |  | +                // See https://github.com/mono/taglib-sharp/issues/304
 | 
	
		
			
				|  |  | +                var trackMbId = mediaInfo.GetProviderId(MetadataProvider.MusicBrainzTrack);
 | 
	
		
			
				|  |  | +                if (trackMbId is not null)
 | 
	
		
			
				|  |  |                  {
 | 
	
		
			
				|  |  | -                    await _lyricManager.SaveLyricAsync(audio, "lrc", tags.Lyrics).ConfigureAwait(false);
 | 
	
		
			
				|  |  | +                    audio.SetProviderId(MetadataProvider.MusicBrainzTrack, trackMbId);
 | 
	
		
			
				|  |  |                  }
 | 
	
		
			
				|  |  |              }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            // Save extracted lyrics if they exist,
 | 
	
		
			
				|  |  | +            // and if the audio doesn't yet have lyrics.
 | 
	
		
			
				|  |  | +            if (!string.IsNullOrWhiteSpace(tags.Lyrics)
 | 
	
		
			
				|  |  | +                && tryExtractEmbeddedLyrics)
 | 
	
		
			
				|  |  | +            {
 | 
	
		
			
				|  |  | +                await _lyricManager.SaveLyricAsync(audio, "lrc", tags.Lyrics).ConfigureAwait(false);
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          private void AddExternalLyrics(
 |