def calc_distance(track_info, track_name, artist_name): dist = hooks.Distance() dist.add_string('track_title', track_name, track_info.title) if track_info.artist: dist.add_string('track_artist', artist_name, track_info.artist) return dist.distance
def distance(items, album_info, mapping): """Determines how "significant" an album metadata change would be. Returns a Distance object. `album_info` is an AlbumInfo object reflecting the album to be compared. `items` is a sequence of all Item objects that will be matched (order is not important). `mapping` is a dictionary mapping Items to TrackInfo objects; the keys are a subset of `items` and the values are a subset of `album_info.tracks`. """ likelies, consensus = current_metadata(items) dist = hooks.Distance() # Artist, if not various. if not album_info.va: dist.add_string('artist', likelies['artist'], album_info.artist) # Album. dist.add_string('album', likelies['album'], album_info.album) # Current or preferred media. if album_info.media: # Preferred media options. patterns = config['match']['preferred']['media'].as_str_seq() options = [re.compile(r'(\d+x)?(%s)' % pat, re.I) for pat in patterns] if options: dist.add_priority('media', album_info.media, options) # Current media. elif likelies['media']: dist.add_equality('media', album_info.media, likelies['media']) # Mediums. if likelies['disctotal'] and album_info.mediums: dist.add_number('mediums', likelies['disctotal'], album_info.mediums) # Prefer earliest release. if album_info.year and config['match']['preferred']['original_year']: # Assume 1889 (earliest first gramophone discs) if we don't know the # original year. original = album_info.original_year or 1889 diff = abs(album_info.year - original) diff_max = abs(datetime.date.today().year - original) dist.add_ratio('year', diff, diff_max) # Year. elif likelies['year'] and album_info.year: if likelies['year'] in (album_info.year, album_info.original_year): # No penalty for matching release or original year. dist.add('year', 0.0) elif album_info.original_year: # Prefer matchest closest to the release year. diff = abs(likelies['year'] - album_info.year) diff_max = abs(datetime.date.today().year - album_info.original_year) dist.add_ratio('year', diff, diff_max) else: # Full penalty when there is no original year. dist.add('year', 1.0) # Preferred countries. patterns = config['match']['preferred']['countries'].as_str_seq() options = [re.compile(pat, re.I) for pat in patterns] if album_info.country and options: dist.add_priority('country', album_info.country, options) # Country. elif likelies['country'] and album_info.country: dist.add_string('country', likelies['country'], album_info.country) # Label. if likelies['label'] and album_info.label: dist.add_string('label', likelies['label'], album_info.label) # Catalog number. if likelies['catalognum'] and album_info.catalognum: dist.add_string('catalognum', likelies['catalognum'], album_info.catalognum) # Disambiguation. if likelies['albumdisambig'] and album_info.albumdisambig: dist.add_string('albumdisambig', likelies['albumdisambig'], album_info.albumdisambig) # Album ID. if likelies['mb_albumid']: dist.add_equality('album_id', likelies['mb_albumid'], album_info.album_id) # Tracks. dist.tracks = {} for item, track in mapping.items(): dist.tracks[track] = track_distance(item, track, album_info.va) dist.add('tracks', dist.tracks[track].distance) # Track totals medium_totals = {} for track in album_info.tracks: if track.medium_total and track.medium not in medium_totals: medium_totals[track.medium] = track.medium_total medium_all_total = sum(medium_totals.values()) # If we have a consensus, and it's the same as the all-disc total, # short-circuit the logic and take the simple approach. if consensus and likelies['tracktotal'] and likelies['tracktotal'] == medium_all_total: pass else: # The imported track may have tags for per disc numbering or not, # so check for both. def item_disc(i): return i.disc or 0 items_by_disc = sorted(mapping.keys(), key=item_disc) grouped_items = groupby(items_by_disc, item_disc) for disc, disc_items in grouped_items: medium_total = medium_totals.get(disc, 0) tracktotals = set(i.tracktotal for i in disc_items if i.tracktotal) for tracktotal in tracktotals: if tracktotal != medium_all_total and medium_total: dist.add_number('tracktotal', medium_total, tracktotal) # Missing tracks. for i in range(len(album_info.tracks) - len(mapping)): dist.add('missing_tracks', 1.0) # Unmatched tracks. for i in range(len(items) - len(mapping)): dist.add('unmatched_tracks', 1.0) # Plugins. dist.update(plugins.album_distance(items, album_info, mapping)) return dist
def track_distance(self, session, info): dist = hooks.Distance() if self.config['filter_on_import'] and not self._has_work_id(info.track_id): dist.add('work_id', 1) return dist