internal async Task <Data> RetrieveMetaData(Disc d)
        {
            var inc = MB.Include.Artists | MB.Include.Labels | MB.Include.Recordings | MB.Include.ReleaseGroups | MB.Include.UrlRelationships;

            MB.Query             query    = null;
            MB.CoverArt.CoverArt coverArt = null;
            try
            {
                var lengths = d.StandardizedCDTableOfContents();
                if (lengths != null)
                {
                    if (lengths2Name.TryGetValue(lengths, out string name))
                    {
                        return(discs[name]);
                    }
                    int frameCount = lengths.Length;
                    MB.Interfaces.Entities.IDisc      disc   = null;
                    MB.Interfaces.IDiscIdLookupResult result = null;
                    int[]  queryTOCArray   = null;
                    int[]  firstTrackLBAs  = MetaDataProvider.CDCommonFirstTrackLBAs;
                    string graceNoteDiscID = (d as DiscSonyBD)?.DiscIDData?.GraceNoteDiscID;
                    if (graceNoteDiscID != null)
                    {
                        int spaceIndex = graceNoteDiscID.IndexOf(' ');
                        if (spaceIndex > 0 && Int32.TryParse(graceNoteDiscID.Substring(0, spaceIndex), out int firstTrackLBA))
                        {
                            firstTrackLBAs = new int[] { firstTrackLBA }
                        }
                        ;
                    }
                    foreach (int initial in firstTrackLBAs)
                    {
                        //                    int initial = 150;
                        var cumulative = lengths.Aggregate(new List <int>(frameCount + 4)
                        {
                            1, frameCount, 0, initial
                        }, (c, nxt) => { c.Add(c.Last() + nxt); return(c); });
                        int total = cumulative.Last();
                        cumulative[2] = total;
                        var queryTOC = cumulative.Take(frameCount + 3);
                        var discTOC  = MB.DiscId.TableOfContents.SimulateDisc(1, (byte)frameCount, queryTOC.Skip(2).ToArray());
                        queryTOCArray = queryTOC.ToArray();
                        query         = new MB.Query("DiscChangerApp");
                        result        = await query.LookupDiscIdAsync(discTOC.DiscId, queryTOCArray, inc, true, true);

                        disc = result.Disc;
                        if (disc != null)
                        {
                            break;
                        }
                    }
                    coverArt = new MB.CoverArt.CoverArt("DiscChanger.NET", "0.1", "*****@*****.**");
                    IReadOnlyList <MB.Interfaces.Entities.IRelease> releases = disc != null ? disc.Releases : result.Releases;
                    if (releases == null || releases.Count == 0)
                    {
                        return(null);
                    }
                    Data data = new Data();
                    data.ArtRelPath = musicBrainzArtRelPath;
                    data.Lengths    = lengths;
                    data.DiscID     = disc?.Id;
                    data.QueryTOC   = queryTOCArray;
                    int?trackCount = (d as DiscSony)?.DiscData?.TrackCount();
                    var rm         = releases.Select(r =>
                    {
                        var m_discs    = r.Media?.Where(m => m.Discs != null && m.Discs.Any());
                        var ml         = m_discs?.Where(m => m.Discs.Any(md => disc != null ? md.Id == disc.Id : discMatch(md, lengths)));
                        var mt         = ml?.Where(m => m.Tracks != null && m.Tracks.Any());
                        var m          = mt?.FirstOrDefault(m => m.TrackCount == trackCount);
                        ulong min_diff = 0UL;
                        if (m == null)
                        {
                            m = mt?.FirstOrDefault();
                        }
                        if (m == null)
                        {
                            var m_diff = m_discs?.Select(m => Tuple.Create(m, Enumerable.Min(m.Discs.Select(md => discDiff(md, lengths))))).OrderByDescending(t => t.Item2);
                            var t      = m_diff?.FirstOrDefault();
                            min_diff   = t?.Item2 ?? Int64.MaxValue;
                            m          = t?.Item1;
                        }
                        return(Tuple.Create(r, min_diff, m?.Tracks));
                    }).OrderBy(t => t.Item2);

                    //                var selectedReleases = rm.Where(t => t.Item2 < Int64.MaxValue).Select(t => t.Item1);
                    var selectedReleases = rm.Where(t => t.Item2 < Int64.MaxValue).Where(t => t.Item2 == rm.FirstOrDefault()?.Item2).Select(t => t.Item1);
                    data.ReleaseIDs = selectedReleases.Select(r => r.Id).ToArray();
                    data.Tracks     = rm.FirstOrDefault()?.Item3?.Select(t => new Track(t.Id, t.Length, t.Position, t.Title)).ToArray();
                    data.Artist     = rm.FirstOrDefault(t => t.Item1.ArtistCredit.Count > 0)?.Item1.ArtistCredit.First().Name.Trim();
                    data.Title      = rm.FirstOrDefault(t => !String.IsNullOrEmpty(t.Item1.Title))?.Item1.Title.Trim();
                    var URLs = selectedReleases.SelectMany(r => r.Relationships.Select(rel => rel.Url?.Resource?.AbsoluteUri).Where(s => !String.IsNullOrEmpty(s))).Distinct().ToArray();
                    data.URLs = URLs.Length > 0 ? URLs : null;
                    string fileNameArtist = MetaDataProvider.RemoveBlacklistedCharacters(data.Artist ?? "ArtistUnk", 40);
                    string fileNameTitle  = MetaDataProvider.RemoveBlacklistedCharacters(data.Title ?? "TitleUnk", 80);
                    string fileNameBaseK  = fileNameArtist + '_' + fileNameTitle;
                    string fileNameBase   = fileNameBaseK;
                    int    i = 1;
                    while (discs.ContainsKey(fileNameBase))
                    {
                        fileNameBase = fileNameBaseK + "_(" + i.ToString() + ')'; i++;
                    }

                    var releasesWithFront = selectedReleases.Where(rel => rel.CoverArtArchive.Front);
                    var artRelease        = releasesWithFront.FirstOrDefault(r => r.Quality.ToLower() == "normal" && r.Packaging != null && r.Packaging.ToLower().Contains("jewel")) ?? releasesWithFront.FirstOrDefault();
                    var id = artRelease?.Id;
                    if (id != null)
                    {
                        //try
                        //{
                        var ca = coverArt.FetchFront(id.Value);
                        data.ArtReleaseID = id;
                        var ext         = MimeTypeMap.GetExtension(ca.ContentType);
                        var fileNameArt = Path.ChangeExtension("CoverArtFront_" + fileNameBase, ext);
                        data.ArtContentType = ca.ContentType;
                        data.ArtFileName    = fileNameArt;
                        using (var f = System.IO.File.OpenWrite(Path.Combine(this.musicBrainzArtPath, fileNameArt)))
                        {
                            ca.Data.Seek(0, System.IO.SeekOrigin.Begin);
                            ca.Data.CopyTo(f);
                        }
                        //}
                        //catch (WebException e)
                        //{
                        //    System.Diagnostics.Debug.WriteLine($"FetchFront {id.Value} Exception {e}");
                        //}
                    }

                    var fileName = Path.ChangeExtension(fileNameBase, "json");
                    using (var f = File.Create(Path.Combine(musicBrainzPath, fileName)))
                    {
                        var w = new Utf8JsonWriter(f, new JsonWriterOptions {
                            Indented = true
                        });
                        JsonSerializer.Serialize(w, data);
                        f.Close();
                    }
                    discs[fileNameBase]   = data;
                    lengths2Name[lengths] = fileNameBase;
                    return(data);
                }
                return(null);
            }
            finally
            {
                if (query != null)
                {
                    query.Dispose();
                }
            }
        }