From 4dc4025b5f5e692f8a265ca7817bd5acb1eb877a Mon Sep 17 00:00:00 2001 From: Simon Chopin Date: Tue, 22 Nov 2011 12:25:10 +0100 Subject: [PATCH] autotag: Can now compute the distance for incomplete albums If the user has some songs from a specific album, but not all of them, the real solution is immediately discarded. This commit is the first of a series that will implement support for these incomplete albums. The point of this patch is to make sure missing commits are taken into account when calculating the distance between an album and its canonical data. Note that in order not to break API compatibility, the album_distance call for the plugins receives a purged version of both the items and the album info, resulting in some potential accuracy if the plugin bases itself on the index of a track in album_info.tracks. --- beets/autotag/match.py | 26 +++++++++++++++++++++----- test/test_autotag.py | 15 +++++++++++++++ 2 files changed, 36 insertions(+), 5 deletions(-) diff --git a/beets/autotag/match.py b/beets/autotag/match.py index 435e6fb03..bc6a506f6 100644 --- a/beets/autotag/match.py +++ b/beets/autotag/match.py @@ -17,6 +17,7 @@ releases and tracks. """ import logging import re +import copy from munkres import Munkres from unidecode import unidecode @@ -31,6 +32,8 @@ ARTIST_WEIGHT = 3.0 ALBUM_WEIGHT = 3.0 # The weight of the entire distance calculated for a given track. TRACK_WEIGHT = 1.0 +# The weight of a missing track. +MISSING_WEIGHT = 0.3 # These distances are components of the track distance (that is, they # compete against each other but not ARTIST_WEIGHT and ALBUM_WEIGHT; # the overall TRACK_WEIGHT does that). @@ -161,7 +164,7 @@ def current_metadata(items): likelies = {} consensus = {} for key in keys: - values = [getattr(item, key) for item in items] + values = [getattr(item, key) for item in items if item] likelies[key], freq = plurality(values) consensus[key] = (freq == len(values)) return likelies['artist'], likelies['album'], consensus['artist'] @@ -269,12 +272,25 @@ def distance(items, album_info): # Track distances. for i, (item, track_info) in enumerate(zip(items, album_info.tracks)): - dist += track_distance(item, track_info, i+1, album_info.va) * \ - TRACK_WEIGHT - dist_max += TRACK_WEIGHT + if item: + dist += track_distance(item, track_info, i+1, album_info.va) * \ + TRACK_WEIGHT + dist_max += TRACK_WEIGHT + else: + dist += MISSING_WEIGHT + dist_max += MISSING_WEIGHT # Plugin distances. - plugin_d, plugin_dm = plugins.album_distance(items, album_info) + # In order not to break compatibility, send purged lists + purged_items, purged_tracks = [], [] + for i, t in zip(items, album_info.tracks): + if i: + purged_items.append(i) + purged_tracks.append(t) + purged_album_info = copy.copy(album_info) + purged_album_info.tracks = purged_tracks + + plugin_d, plugin_dm = plugins.album_distance(purged_items, purged_album_info) dist += plugin_d dist_max += plugin_dm diff --git a/test/test_autotag.py b/test/test_autotag.py index e2f71d94a..0b5ccc535 100644 --- a/test/test_autotag.py +++ b/test/test_autotag.py @@ -94,6 +94,21 @@ class AlbumDistanceTest(unittest.TestCase): ) self.assertEqual(match.distance(items, info), 0) + def test_incomplete_album(self): + items = [] + items.append(self.item('one', 1)) + items.append(self.item('three', 3)) + info = AlbumInfo( + artist = 'some artist', + album = 'some album', + tracks = self.trackinfo(), + va = False, + album_id = None, artist_id = None, + ) + self.assertNotEqual(match.distance(items, info), 0) + # Make sure the distance is not too great + self.assertTrue(match.distance(items, info) < 0.2) + def test_global_artists_differ(self): items = [] items.append(self.item('one', 1))