public TrackMapping MapReleaseTracks(List <LocalTrack> localTracks, List <Track> mbTracks)
        {
            var distances = new Distance[localTracks.Count, mbTracks.Count];
            var costs     = new double[localTracks.Count, mbTracks.Count];

            for (int col = 0; col < mbTracks.Count; col++)
            {
                var totalTrackNumber = GetTotalTrackNumber(mbTracks[col], mbTracks);
                for (int row = 0; row < localTracks.Count; row++)
                {
                    distances[row, col] = TrackDistance(localTracks[row], mbTracks[col], totalTrackNumber, false);
                    costs[row, col]     = distances[row, col].NormalizedDistance();
                }
            }

            var m = new Munkres(costs);

            m.Run();

            var result = new TrackMapping();

            foreach (var pair in m.Solution)
            {
                result.Mapping.Add(localTracks[pair.Item1], Tuple.Create(mbTracks[pair.Item2], distances[pair.Item1, pair.Item2]));
                _logger.Trace("Mapped {0} to {1}, dist: {2}", localTracks[pair.Item1], mbTracks[pair.Item2], costs[pair.Item1, pair.Item2]);
            }

            result.LocalExtra = localTracks.Except(result.Mapping.Keys).ToList();
            _logger.Trace($"Unmapped files:\n{string.Join("\n", result.LocalExtra)}");

            result.MBExtra = mbTracks.Except(result.Mapping.Values.Select(x => x.Item1)).ToList();
            _logger.Trace($"Missing tracks:\n{string.Join("\n", result.MBExtra)}");

            return(result);
        }
Beispiel #2
0
        private TrackMapping GivenMapping(List <LocalTrack> local, List <Track> remote)
        {
            var mapping   = new TrackMapping();
            var distances = local.Zip(remote, (l, r) => Tuple.Create(r, Subject.TrackDistance(l, r, Subject.GetTotalTrackNumber(r, remote))));

            mapping.Mapping    = local.Zip(distances, (l, r) => new { l, r }).ToDictionary(x => x.l, x => x.r);
            mapping.LocalExtra = local.Except(mapping.Mapping.Keys).ToList();
            mapping.MBExtra    = remote.Except(mapping.Mapping.Values.Select(x => x.Item1)).ToList();

            return(mapping);
        }
Beispiel #3
0
 public bool Equals(FilterResult other)
 {
     if (ReferenceEquals(null, other))
     {
         return(false);
     }
     if (ReferenceEquals(this, other))
     {
         return(true);
     }
     return(Id.Equals(other.Id) &&
            Uid.Equals(other.Uid) &&
            string.Equals(Name, other.Name) &&
            string.Equals(Description, other.Description) &&
            StartUtc.Equals(other.StartUtc) &&
            EndUtc.Equals(other.EndUtc) &&
            OnMachineDesignId == other.OnMachineDesignId &&
            OnMachineDesignName == other.OnMachineDesignName &&
            AssetIDs.ScrambledEquals(other.AssetIDs) &&
            VibeStateOn == other.VibeStateOn &&
            CompactorDataOnly.Equals(other.CompactorDataOnly) &&
            ElevationType == other.ElevationType &&
            PolygonLL.ScrambledEquals(other.PolygonLL) &&
            PolygonGrid.ScrambledEquals(other.PolygonGrid) &&
            ForwardDirection == other.ForwardDirection &&
            (AlignmentFile == null ? other.AlignmentFile == null : AlignmentFile.Equals(other.AlignmentFile)) &&
            StartStation.Equals(other.StartStation) &&
            EndStation.Equals(other.EndStation) &&
            LeftOffset.Equals(other.LeftOffset) &&
            RightOffset.Equals(other.RightOffset) &&
            LayerType.Equals(other.LayerType) &&
            (LayerDesignOrAlignmentFile == null
        ? other.LayerDesignOrAlignmentFile == null
        : LayerDesignOrAlignmentFile.Equals(other.LayerDesignOrAlignmentFile)) &&
            BenchElevation.Equals(other.BenchElevation) &&
            LayerNumber == other.LayerNumber &&
            LayerThickness.Equals(other.LayerThickness) &&
            ContributingMachines.ScrambledEquals(other.ContributingMachines) &&
            SurveyedSurfaceExclusionList.ScrambledEquals(other.SurveyedSurfaceExclusionList) &&
            ExcludedSurveyedSurfaceUids.ScrambledEquals(other.ExcludedSurveyedSurfaceUids) &&
            ReturnEarliest.Equals(other.ReturnEarliest) &&
            GpsAccuracy.Equals(other.GpsAccuracy) &&
            GpsAccuracyIsInclusive.Equals(other.GpsAccuracyIsInclusive) &&
            BladeOnGround.Equals(other.BladeOnGround) &&
            TrackMapping.Equals(other.TrackMapping) &&
            WheelTracking.Equals(other.WheelTracking) &&
            (DesignFile == null ? other.DesignFile == null : DesignFile.Equals(other.DesignFile)) &&
            AutomaticsType == other.AutomaticsType &&
            TemperatureRangeMin.Equals(other.TemperatureRangeMin) &&
            TemperatureRangeMax.Equals(other.TemperatureRangeMax) &&
            PassCountRangeMin.Equals(other.PassCountRangeMin) &&
            PassCountRangeMax.Equals(other.PassCountRangeMax));
 }
        public Distance AlbumReleaseDistance(List <LocalTrack> localTracks, AlbumRelease release, TrackMapping mapping)
        {
            var dist = new Distance();

            if (!VariousArtistIds.Contains(release.Album.Value.ArtistMetadata.Value.ForeignArtistId))
            {
                var artist = MostCommon(localTracks.Select(x => x.FileTrackInfo.ArtistTitle)) ?? "";
                dist.AddString("artist", artist, release.Album.Value.ArtistMetadata.Value.Name);
                _logger.Trace("artist: {0} vs {1}; {2}", artist, release.Album.Value.ArtistMetadata.Value.Name, dist.NormalizedDistance());
            }

            var title = MostCommon(localTracks.Select(x => x.FileTrackInfo.AlbumTitle)) ?? "";

            // Use the album title since the differences in release titles can cause confusion and
            // aren't always correct in the tags
            dist.AddString("album", title, release.Album.Value.Title);
            _logger.Trace("album: {0} vs {1}; {2}", title, release.Title, dist.NormalizedDistance());

            // Number of discs, either as tagged or the max disc number seen
            var discCount = MostCommon(localTracks.Select(x => x.FileTrackInfo.DiscCount));

            discCount = discCount != 0 ? discCount : localTracks.Max(x => x.FileTrackInfo.DiscNumber);
            if (discCount > 0)
            {
                dist.AddNumber("media_count", discCount, release.Media.Count);
                _logger.Trace("media_count: {0} vs {1}; {2}", discCount, release.Media.Count, dist.NormalizedDistance());
            }

            // Media format
            if (release.Media.Select(x => x.Format).Contains("Unknown"))
            {
                dist.Add("media_format", 1.0);
            }

            // Year
            var localYear = MostCommon(localTracks.Select(x => x.FileTrackInfo.Year));

            if (localYear > 0 && (release.Album.Value.ReleaseDate.HasValue || release.ReleaseDate.HasValue))
            {
                var albumYear   = release.Album.Value.ReleaseDate?.Year ?? 0;
                var releaseYear = release.ReleaseDate?.Year ?? 0;
                if (localYear == albumYear || localYear == releaseYear)
                {
                    dist.Add("year", 0.0);
                }
                else
                {
                    var remoteYear = albumYear > 0 ? albumYear : releaseYear;
                    var diff       = Math.Abs(localYear - remoteYear);
                    var diff_max   = Math.Abs(DateTime.Now.Year - remoteYear);
                    dist.AddRatio("year", diff, diff_max);
                }
                _logger.Trace($"year: {localYear} vs {release.Album.Value.ReleaseDate?.Year} or {release.ReleaseDate?.Year}; {dist.NormalizedDistance()}");
            }

            // If we parsed a country from the files use that, otherwise use our preference
            var country = MostCommon(localTracks.Select(x => x.FileTrackInfo.Country));

            if (release.Country.Count > 0)
            {
                if (country != null)
                {
                    dist.AddEquality("country", country.Name, release.Country);
                    _logger.Trace("country: {0} vs {1}; {2}", country.Name, string.Join(", ", release.Country), dist.NormalizedDistance());
                }
                else if (preferredCountries.Count > 0)
                {
                    dist.AddPriority("country", release.Country, preferredCountries.Select(x => x.Name).ToList());
                    _logger.Trace("country priority: {0} vs {1}; {2}", string.Join(", ", preferredCountries.Select(x => x.Name)), string.Join(", ", release.Country), dist.NormalizedDistance());
                }
            }
            else
            {
                // full penalty if MusicBrainz release is missing a country
                dist.Add("country", 1.0);
            }

            var label = MostCommon(localTracks.Select(x => x.FileTrackInfo.Label));

            if (label.IsNotNullOrWhiteSpace())
            {
                dist.AddEquality("label", label, release.Label);
                _logger.Trace("label: {0} vs {1}; {2}", label, string.Join(", ", release.Label), dist.NormalizedDistance());
            }

            var disambig = MostCommon(localTracks.Select(x => x.FileTrackInfo.Disambiguation));

            if (disambig.IsNotNullOrWhiteSpace())
            {
                dist.AddString("album_disambiguation", disambig, release.Disambiguation);
                _logger.Trace("album_disambiguation: {0} vs {1}; {2}", disambig, release.Disambiguation, dist.NormalizedDistance());
            }

            var mbAlbumId = MostCommon(localTracks.Select(x => x.FileTrackInfo.ReleaseMBId));

            if (mbAlbumId.IsNotNullOrWhiteSpace())
            {
                dist.AddBool("album_id", mbAlbumId != release.ForeignReleaseId && !release.OldForeignReleaseIds.Contains(mbAlbumId));
                _logger.Trace("album_id: {0} vs {1} or {2}; {3}", mbAlbumId, release.ForeignReleaseId, string.Join(", ", release.OldForeignReleaseIds), dist.NormalizedDistance());
            }

            // tracks
            foreach (var pair in mapping.Mapping)
            {
                dist.Add("tracks", pair.Value.Item2.NormalizedDistance());
            }
            _logger.Trace("after trackMapping: {0}", dist.NormalizedDistance());

            // missing tracks
            foreach (var track in mapping.MBExtra.Take(localTracks.Count))
            {
                dist.Add("missing_tracks", 1.0);
            }
            _logger.Trace("after missing tracks: {0}", dist.NormalizedDistance());

            // unmatched tracks
            foreach (var track in mapping.LocalExtra.Take(localTracks.Count))
            {
                dist.Add("unmatched_tracks", 1.0);
            }
            _logger.Trace("after unmatched tracks: {0}", dist.NormalizedDistance());

            return(dist);
        }