mirror of
https://github.com/beetbox/beets.git
synced 2026-01-04 15:03:22 +01:00
"info dictionaries" replaced with AlbumInfo and TrackInfo
This commit is contained in:
parent
de2ee7e447
commit
95f38dbe52
12 changed files with 275 additions and 274 deletions
|
|
@ -22,6 +22,7 @@ from beets.util import sorted_walk
|
|||
|
||||
# Parts of external interface.
|
||||
from .hooks import AlbumInfo, TrackInfo
|
||||
from .match import AutotagError
|
||||
from .match import tag_item, tag_album
|
||||
from .match import RECOMMEND_STRONG, RECOMMEND_MEDIUM, RECOMMEND_NONE
|
||||
from .match import STRONG_REC_THRESH, MEDIUM_REC_THRESH, REC_GAP_THRESH
|
||||
|
|
@ -55,54 +56,54 @@ def albums_in_dir(path):
|
|||
if items:
|
||||
yield root, items
|
||||
|
||||
def apply_item_metadata(item, track_data):
|
||||
"""Set an item's metadata from its matched info dictionary.
|
||||
def apply_item_metadata(item, track_info):
|
||||
"""Set an item's metadata from its matched TrackInfo object.
|
||||
"""
|
||||
item.artist = track_data['artist']
|
||||
item.title = track_data['title']
|
||||
item.mb_trackid = track_data['id']
|
||||
if 'artist_id' in track_data:
|
||||
item.mb_artistid = track_data['artist_id']
|
||||
item.artist = track_info.artist
|
||||
item.title = track_info.title
|
||||
item.mb_trackid = track_info.track_id
|
||||
if track_info.artist_id:
|
||||
item.mb_artistid = track_info.artist_id
|
||||
# At the moment, the other metadata is left intact (including album
|
||||
# and track number). Perhaps these should be emptied?
|
||||
|
||||
def apply_metadata(items, info):
|
||||
"""Set the items' metadata to match the data given in info. The
|
||||
list of items must be ordered.
|
||||
def apply_metadata(items, album_info):
|
||||
"""Set the items' metadata to match an AlbumInfo object. The list
|
||||
of items must be ordered.
|
||||
"""
|
||||
for index, (item, track_data) in enumerate(zip(items, info['tracks'])):
|
||||
for index, (item, track_info) in enumerate(zip(items, album_info.tracks)):
|
||||
# Album, artist, track count.
|
||||
if 'artist' in track_data:
|
||||
item.artist = track_data['artist']
|
||||
if track_info.artist:
|
||||
item.artist = track_info.artist
|
||||
else:
|
||||
item.artist = info['artist']
|
||||
item.albumartist = info['artist']
|
||||
item.album = info['album']
|
||||
item.artist = album_info.artist
|
||||
item.albumartist = album_info.artist
|
||||
item.album = album_info.album
|
||||
item.tracktotal = len(items)
|
||||
|
||||
# Release date.
|
||||
if 'year' in info:
|
||||
item.year = info['year']
|
||||
if 'month' in info:
|
||||
item.month = info['month']
|
||||
if 'day' in info:
|
||||
item.day = info['day']
|
||||
if album_info.year:
|
||||
item.year = album_info.year
|
||||
if album_info.month:
|
||||
item.month = album_info.month
|
||||
if album_info.day:
|
||||
item.day = album_info.day
|
||||
|
||||
# Title and track index.
|
||||
item.title = track_data['title']
|
||||
item.title = track_info.title
|
||||
item.track = index + 1
|
||||
|
||||
# MusicBrainz IDs.
|
||||
item.mb_trackid = track_data['id']
|
||||
item.mb_albumid = info['album_id']
|
||||
if 'artist_id' in track_data:
|
||||
item.mb_artistid = track_data['artist_id']
|
||||
item.mb_trackid = track_info.track_id
|
||||
item.mb_albumid = album_info.album_id
|
||||
if track_info.artist_id:
|
||||
item.mb_artistid = track_info.artist_id
|
||||
else:
|
||||
item.mb_artistid = info['artist_id']
|
||||
item.mb_albumartistid = info['artist_id']
|
||||
item.albumtype = info['albumtype']
|
||||
if 'label' in info:
|
||||
item.label = info['label']
|
||||
item.mb_artistid = album_info.artist_id
|
||||
item.mb_albumartistid = album_info.artist_id
|
||||
item.albumtype = album_info.albumtype
|
||||
if album_info.label:
|
||||
item.label = album_info.label
|
||||
|
||||
# Compilation flag.
|
||||
item.comp = info['va']
|
||||
item.comp = album_info.va
|
||||
|
|
|
|||
|
|
@ -89,9 +89,9 @@ def art_for_album(album, path):
|
|||
if out:
|
||||
return out
|
||||
|
||||
if album['asin']:
|
||||
log.debug('Fetching album art for ASIN %s.' % album['asin'])
|
||||
return art_for_asin(album['asin'])
|
||||
if album.asin:
|
||||
log.debug('Fetching album art for ASIN %s.' % album.asin)
|
||||
return art_for_asin(album.asin)
|
||||
else:
|
||||
log.debug('No ASIN available: no art found.')
|
||||
return None
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@
|
|||
"""Glue between metadata sources and the matching logic."""
|
||||
|
||||
from beets import plugins
|
||||
from . import mb
|
||||
from beets.autotag import mb
|
||||
|
||||
# Classes used to represent candidate options.
|
||||
|
||||
|
|
@ -40,7 +40,8 @@ class AlbumInfo(object):
|
|||
optional and may be None.
|
||||
"""
|
||||
def __init__(self, album, album_id, artist, artist_id, tracks, asin=None,
|
||||
albumtype=None, va=False, year=None, month=None, day=None):
|
||||
albumtype=None, va=False, year=None, month=None, day=None,
|
||||
label=None):
|
||||
self.album = album
|
||||
self.album_id = album_id
|
||||
self.artist = artist
|
||||
|
|
@ -52,6 +53,7 @@ class AlbumInfo(object):
|
|||
self.year = year
|
||||
self.month = month
|
||||
self.day = day
|
||||
self.label = label
|
||||
|
||||
class TrackInfo(object):
|
||||
"""Describes a canonical track present on a release. Appears as part
|
||||
|
|
@ -71,7 +73,7 @@ class TrackInfo(object):
|
|||
self.title = title
|
||||
self.track_id = track_id
|
||||
self.artist = artist
|
||||
self.artist_id = artist
|
||||
self.artist_id = artist_id
|
||||
self.length = length
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -192,10 +192,10 @@ def order_items(items, trackinfo):
|
|||
ordered_items[canon_idx] = items[cur_idx]
|
||||
return ordered_items
|
||||
|
||||
def track_distance(item, track_data, track_index=None, incl_artist=False):
|
||||
def track_distance(item, track_info, track_index=None, incl_artist=False):
|
||||
"""Determines the significance of a track metadata change. Returns
|
||||
a float in [0.0,1.0]. `track_index` is the track number of the
|
||||
`track_data` metadata set. If `track_index` is provided and
|
||||
`track_info` metadata set. If `track_index` is provided and
|
||||
item.track is set, then these indices are used as a component of
|
||||
the distance calculation. `incl_artist` indicates that a distance
|
||||
component should be included for the track artist (i.e., for
|
||||
|
|
@ -205,26 +205,26 @@ def track_distance(item, track_data, track_index=None, incl_artist=False):
|
|||
dist, dist_max = 0.0, 0.0
|
||||
|
||||
# Check track length.
|
||||
if 'length' not in track_data:
|
||||
if not track_info.length:
|
||||
# If there's no length to check, assume the worst.
|
||||
dist += TRACK_LENGTH_WEIGHT
|
||||
else:
|
||||
diff = abs(item.length - track_data['length'])
|
||||
diff = abs(item.length - track_info.length)
|
||||
diff = max(diff - TRACK_LENGTH_GRACE, 0.0)
|
||||
diff = min(diff, TRACK_LENGTH_MAX)
|
||||
dist += (diff / TRACK_LENGTH_MAX) * TRACK_LENGTH_WEIGHT
|
||||
dist_max += TRACK_LENGTH_WEIGHT
|
||||
|
||||
# Track title.
|
||||
dist += string_dist(item.title, track_data['title']) * TRACK_TITLE_WEIGHT
|
||||
dist += string_dist(item.title, track_info.title) * TRACK_TITLE_WEIGHT
|
||||
dist_max += TRACK_TITLE_WEIGHT
|
||||
|
||||
# Track artist, if included.
|
||||
# Attention: MB DB does not have artist info for all compilations,
|
||||
# so only check artist distance if there is actually an artist in
|
||||
# the MB track data.
|
||||
if incl_artist and 'artist' in track_data:
|
||||
dist += string_dist(item.artist, track_data['artist']) * \
|
||||
if incl_artist and track_info.artist:
|
||||
dist += string_dist(item.artist, track_info.artist) * \
|
||||
TRACK_ARTIST_WEIGHT
|
||||
dist_max += TRACK_ARTIST_WEIGHT
|
||||
|
||||
|
|
@ -236,18 +236,18 @@ def track_distance(item, track_data, track_index=None, incl_artist=False):
|
|||
|
||||
# MusicBrainz track ID.
|
||||
if item.mb_trackid:
|
||||
if item.mb_trackid != track_data['id']:
|
||||
if item.mb_trackid != track_info.track_id:
|
||||
dist += TRACK_ID_WEIGHT
|
||||
dist_max += TRACK_ID_WEIGHT
|
||||
|
||||
# Plugin distances.
|
||||
plugin_d, plugin_dm = plugins.track_distance(item, track_data)
|
||||
plugin_d, plugin_dm = plugins.track_distance(item, track_info)
|
||||
dist += plugin_d
|
||||
dist_max += plugin_dm
|
||||
|
||||
return dist / dist_max
|
||||
|
||||
def distance(items, info):
|
||||
def distance(items, album_info):
|
||||
"""Determines how "significant" an album metadata change would be.
|
||||
Returns a float in [0.0,1.0]. The list of items must be ordered.
|
||||
"""
|
||||
|
|
@ -261,20 +261,20 @@ def distance(items, info):
|
|||
dist_max = 0.0
|
||||
|
||||
# Artist/album metadata.
|
||||
if not info['va']:
|
||||
dist += string_dist(cur_artist, info['artist']) * ARTIST_WEIGHT
|
||||
if not album_info.va:
|
||||
dist += string_dist(cur_artist, album_info.artist) * ARTIST_WEIGHT
|
||||
dist_max += ARTIST_WEIGHT
|
||||
dist += string_dist(cur_album, info['album']) * ALBUM_WEIGHT
|
||||
dist += string_dist(cur_album, album_info.album) * ALBUM_WEIGHT
|
||||
dist_max += ALBUM_WEIGHT
|
||||
|
||||
# Track distances.
|
||||
for i, (item, track_data) in enumerate(zip(items, info['tracks'])):
|
||||
dist += track_distance(item, track_data, i+1, info['va']) * \
|
||||
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
|
||||
|
||||
# Plugin distances.
|
||||
plugin_d, plugin_dm = plugins.album_distance(items, info)
|
||||
plugin_d, plugin_dm = plugins.album_distance(items, album_info)
|
||||
dist += plugin_d
|
||||
dist_max += plugin_dm
|
||||
|
||||
|
|
@ -340,20 +340,20 @@ def validate_candidate(items, tuple_dict, info):
|
|||
the track count, ordering the items, checking for duplicates, and
|
||||
calculating the distance.
|
||||
"""
|
||||
log.debug('Candidate: %s - %s' % (info['artist'], info['album']))
|
||||
log.debug('Candidate: %s - %s' % (info.artist, info.album))
|
||||
|
||||
# Don't duplicate.
|
||||
if info['album_id'] in tuple_dict:
|
||||
if info.album_id in tuple_dict:
|
||||
log.debug('Duplicate.')
|
||||
return
|
||||
|
||||
# Make sure the album has the correct number of tracks.
|
||||
if len(items) != len(info['tracks']):
|
||||
if len(items) != len(info.tracks):
|
||||
log.debug('Track count mismatch.')
|
||||
return
|
||||
|
||||
# Put items in order.
|
||||
ordered = order_items(items, info['tracks'])
|
||||
ordered = order_items(items, info.tracks)
|
||||
if not ordered:
|
||||
log.debug('Not orderable.')
|
||||
return
|
||||
|
|
@ -362,7 +362,7 @@ def validate_candidate(items, tuple_dict, info):
|
|||
dist = distance(ordered, info)
|
||||
log.debug('Success. Distance: %f' % dist)
|
||||
|
||||
tuple_dict[info['album_id']] = dist, ordered, info
|
||||
tuple_dict[info.album_id] = dist, ordered, info
|
||||
|
||||
def tag_album(items, timid=False, search_artist=None, search_album=None,
|
||||
search_id=None):
|
||||
|
|
|
|||
|
|
@ -30,6 +30,8 @@ from musicbrainz2.model import Release
|
|||
from threading import Lock
|
||||
from musicbrainz2.model import VARIOUS_ARTISTS_ID
|
||||
|
||||
import beets.autotag.hooks
|
||||
|
||||
SEARCH_LIMIT = 5
|
||||
VARIOUS_ARTISTS_ID = VARIOUS_ARTISTS_ID.rsplit('/', 1)[1]
|
||||
|
||||
|
|
@ -115,7 +117,7 @@ def _query_wrap(fun, *args, **kwargs):
|
|||
|
||||
def get_releases(**params):
|
||||
"""Given a list of parameters to ReleaseFilter, executes the
|
||||
query and yields release dicts (complete with tracks).
|
||||
query and yields AlbumInfo objects.
|
||||
"""
|
||||
# Replace special cases.
|
||||
if 'artistName' in params:
|
||||
|
|
@ -135,7 +137,7 @@ def get_releases(**params):
|
|||
for result in results:
|
||||
release = result.release
|
||||
tracks, _ = release_info(release.id)
|
||||
yield release_dict(release, tracks)
|
||||
yield album_info(release, tracks)
|
||||
|
||||
def release_info(release_id):
|
||||
"""Given a MusicBrainz release ID, fetch a list of tracks on the
|
||||
|
|
@ -173,9 +175,9 @@ def _lucene_query(criteria):
|
|||
return u' '.join(query_parts)
|
||||
|
||||
def find_releases(criteria, limit=SEARCH_LIMIT):
|
||||
"""Get a list of release dictionaries from the MusicBrainz
|
||||
database that match `criteria`. The latter is a dictionary whose
|
||||
keys are MusicBrainz field names and whose values are search terms
|
||||
"""Get a list of AlbumInfo objects from the MusicBrainz database
|
||||
that match `criteria`. The latter is a dictionary whose keys are
|
||||
MusicBrainz field names and whose values are search terms
|
||||
for those fields.
|
||||
|
||||
The field names are from MusicBrainz's Lucene query syntax, which
|
||||
|
|
@ -196,7 +198,7 @@ def find_releases(criteria, limit=SEARCH_LIMIT):
|
|||
return get_releases(limit=limit, query=query)
|
||||
|
||||
def find_tracks(criteria, limit=SEARCH_LIMIT):
|
||||
"""Get a sequence of track dictionaries from MusicBrainz that match
|
||||
"""Get a sequence of TrackInfo objects from MusicBrainz that match
|
||||
`criteria`, a search term dictionary similar to the one passed to
|
||||
`find_releases`.
|
||||
"""
|
||||
|
|
@ -210,43 +212,44 @@ def find_tracks(criteria, limit=SEARCH_LIMIT):
|
|||
results = ()
|
||||
for result in results:
|
||||
track = result.track
|
||||
yield track_dict(track)
|
||||
yield track_info(track)
|
||||
|
||||
def track_dict(track):
|
||||
"""Produces a dictionary summarizing a MusicBrainz `Track` object.
|
||||
def track_info(track):
|
||||
"""Translates a MusicBrainz ``Track`` object into a beets
|
||||
``TrackInfo`` object.
|
||||
"""
|
||||
t = {'title': track.title,
|
||||
'id': track.id.rsplit('/', 1)[1]}
|
||||
info = beets.autotag.hooks.TrackInfo(track.title,
|
||||
track.id.rsplit('/', 1)[1])
|
||||
if track.artist is not None:
|
||||
# Track artists will only be present for releases with
|
||||
# multiple artists.
|
||||
t['artist'] = track.artist.name
|
||||
t['artist_id'] = track.artist.id.rsplit('/', 1)[1]
|
||||
info.artist = track.artist.name
|
||||
info.artist_id = track.artist.id.rsplit('/', 1)[1]
|
||||
if track.duration is not None:
|
||||
# Duration not always present.
|
||||
t['length'] = track.duration/(1000.0)
|
||||
return t
|
||||
info.length = track.duration/(1000.0)
|
||||
return info
|
||||
|
||||
def release_dict(release, tracks=None):
|
||||
"""Takes a MusicBrainz `Release` object and returns a dictionary
|
||||
containing the interesting data about that release. A list of
|
||||
`Track` objects may also be provided as `tracks`; they are then
|
||||
included in the resulting dictionary.
|
||||
def album_info(release, tracks):
|
||||
"""Takes a MusicBrainz ``Release`` object and returns a beets
|
||||
AlbumInfo object containing the interesting data about that release.
|
||||
``tracks`` is a list of ``Track`` objects that make up the album.
|
||||
"""
|
||||
# Basic info.
|
||||
out = {'album': release.title,
|
||||
'album_id': release.id.rsplit('/', 1)[1],
|
||||
'artist': release.artist.name,
|
||||
'artist_id': release.artist.id.rsplit('/', 1)[1],
|
||||
'asin': release.asin,
|
||||
'albumtype': '',
|
||||
}
|
||||
out['va'] = out['artist_id'] == VARIOUS_ARTISTS_ID
|
||||
info = beets.autotag.hooks.AlbumInfo(
|
||||
release.title,
|
||||
release.id.rsplit('/', 1)[1],
|
||||
release.artist.name,
|
||||
release.artist.id.rsplit('/', 1)[1],
|
||||
[track_info(track) for track in tracks],
|
||||
release.asin
|
||||
)
|
||||
info.va = info.artist_id == VARIOUS_ARTISTS_ID
|
||||
|
||||
# Release type not always populated.
|
||||
for releasetype in release.types:
|
||||
if releasetype in RELEASE_TYPES:
|
||||
out['albumtype'] = releasetype.split('#')[1].lower()
|
||||
info.albumtype = releasetype.split('#')[1].lower()
|
||||
break
|
||||
|
||||
# Release date and label.
|
||||
|
|
@ -255,7 +258,7 @@ def release_dict(release, tracks=None):
|
|||
except:
|
||||
# The python-musicbrainz2 module has a bug that will raise an
|
||||
# exception when there is no release date to be found. In this
|
||||
# case, we just skip adding a release date to the dict.
|
||||
# case, we just skip adding a release date to the result.
|
||||
pass
|
||||
else:
|
||||
if event:
|
||||
|
|
@ -265,25 +268,20 @@ def release_dict(release, tracks=None):
|
|||
date_parts = date_str.split('-')
|
||||
for key in ('year', 'month', 'day'):
|
||||
if date_parts:
|
||||
out[key] = int(date_parts.pop(0))
|
||||
setattr(info, key, int(date_parts.pop(0)))
|
||||
|
||||
# Label name.
|
||||
label = event.getLabel()
|
||||
if label:
|
||||
name = label.getName()
|
||||
if name and name != '[no label]':
|
||||
out['label'] = name
|
||||
info.label = name
|
||||
|
||||
# Tracks.
|
||||
if tracks is not None:
|
||||
out['tracks'] = map(track_dict, tracks)
|
||||
|
||||
return out
|
||||
return info
|
||||
|
||||
def match_album(artist, album, tracks=None, limit=SEARCH_LIMIT):
|
||||
"""Searches for a single album ("release" in MusicBrainz parlance)
|
||||
and returns an iterator over dictionaries of information (as
|
||||
returned by `release_dict`).
|
||||
and returns an iterator over AlbumInfo objects.
|
||||
|
||||
The query consists of an artist name, an album name, and,
|
||||
optionally, a number of tracks on the album.
|
||||
|
|
@ -302,8 +300,8 @@ def match_album(artist, album, tracks=None, limit=SEARCH_LIMIT):
|
|||
return find_releases(criteria, limit)
|
||||
|
||||
def match_track(artist, title):
|
||||
"""Searches for a single track and returns an iterable of track
|
||||
info dictionaries (as returned by `track_dict`).
|
||||
"""Searches for a single track and returns an iterable of TrackInfo
|
||||
objects.
|
||||
"""
|
||||
return find_tracks({
|
||||
'artist': artist,
|
||||
|
|
@ -311,8 +309,8 @@ def match_track(artist, title):
|
|||
})
|
||||
|
||||
def album_for_id(albumid):
|
||||
"""Fetches an album by its MusicBrainz ID and returns an
|
||||
information dictionary. If no match is found, returns None.
|
||||
"""Fetches an album by its MusicBrainz ID and returns an AlbumInfo
|
||||
object or None if the album is not found.
|
||||
"""
|
||||
query = mbws.Query()
|
||||
try:
|
||||
|
|
@ -322,11 +320,11 @@ def album_for_id(albumid):
|
|||
except (mbws.ResourceNotFoundError, mbws.RequestError), exc:
|
||||
log.debug('Album ID match failed: ' + str(exc))
|
||||
return None
|
||||
return release_dict(album, album.tracks)
|
||||
return album_info(album, album.tracks)
|
||||
|
||||
def track_for_id(trackid):
|
||||
"""Fetches a track by its MusicBrainz ID. Returns a track info
|
||||
dictionary or None if no track is found.
|
||||
"""Fetches a track by its MusicBrainz ID. Returns a TrackInfo object
|
||||
or None if no track is found.
|
||||
"""
|
||||
query = mbws.Query()
|
||||
try:
|
||||
|
|
@ -336,4 +334,4 @@ def track_for_id(trackid):
|
|||
except (mbws.ResourceNotFoundError, mbws.RequestError), exc:
|
||||
log.debug('Track ID match failed: ' + str(exc))
|
||||
return None
|
||||
return track_dict(track)
|
||||
return track_info(track)
|
||||
|
|
|
|||
|
|
@ -91,8 +91,8 @@ def _duplicate_check(lib, task, recent=None):
|
|||
artist = task.cur_artist
|
||||
album = task.cur_album
|
||||
elif task.choice_flag is action.APPLY:
|
||||
artist = task.info['artist']
|
||||
album = task.info['album']
|
||||
artist = task.info.artist
|
||||
album = task.info.album
|
||||
else:
|
||||
return False
|
||||
|
||||
|
|
@ -125,8 +125,8 @@ def _item_duplicate_check(lib, task, recent=None):
|
|||
artist = task.item.artist
|
||||
title = task.item.title
|
||||
elif task.choice_flag is action.APPLY:
|
||||
artist = task.info['artist']
|
||||
title = task.info['title']
|
||||
artist = task.info.artist
|
||||
title = task.info.title
|
||||
else:
|
||||
return False
|
||||
|
||||
|
|
|
|||
|
|
@ -55,14 +55,14 @@ class BeetsPlugin(object):
|
|||
return 0.0, 0.0
|
||||
|
||||
def candidates(self, items):
|
||||
"""Should return a sequence of MusicBrainz info dictionaries
|
||||
that match the album whose items are provided.
|
||||
"""Should return a sequence of AlbumInfo objects that match the
|
||||
album whose items are provided.
|
||||
"""
|
||||
return ()
|
||||
|
||||
def item_candidates(self, item):
|
||||
"""Should return a sequence of MusicBrainz track info
|
||||
dictionaries that match the item provided.
|
||||
"""Should return a sequence of TrackInfo objects that match the
|
||||
item provided.
|
||||
"""
|
||||
return ()
|
||||
|
||||
|
|
|
|||
|
|
@ -130,10 +130,10 @@ def show_change(cur_artist, cur_album, items, info, dist, color=True):
|
|||
print_(' (unknown album)')
|
||||
|
||||
# Identify the album in question.
|
||||
if cur_artist != info['artist'] or \
|
||||
(cur_album != info['album'] and info['album'] != VARIOUS_ARTISTS):
|
||||
artist_l, artist_r = cur_artist or '', info['artist']
|
||||
album_l, album_r = cur_album or '', info['album']
|
||||
if cur_artist != info.artist or \
|
||||
(cur_album != info.album and info.album != VARIOUS_ARTISTS):
|
||||
artist_l, artist_r = cur_artist or '', info.artist
|
||||
album_l, album_r = cur_album or '', info.album
|
||||
if artist_r == VARIOUS_ARTISTS:
|
||||
# Hide artists for VA releases.
|
||||
artist_l, artist_r = u'', u''
|
||||
|
|
@ -147,17 +147,17 @@ def show_change(cur_artist, cur_album, items, info, dist, color=True):
|
|||
print_("To:")
|
||||
show_album(artist_r, album_r)
|
||||
else:
|
||||
print_("Tagging: %s - %s" % (info['artist'], info['album']))
|
||||
print_("Tagging: %s - %s" % (info.artist, info.album))
|
||||
|
||||
# Distance/similarity.
|
||||
print_('(Similarity: %s)' % dist_string(dist, color))
|
||||
|
||||
# Tracks.
|
||||
for i, (item, track_data) in enumerate(zip(items, info['tracks'])):
|
||||
for i, (item, track_info) in enumerate(zip(items, info.tracks)):
|
||||
cur_track = str(item.track)
|
||||
new_track = str(i+1)
|
||||
cur_title = item.title
|
||||
new_title = track_data['title']
|
||||
new_title = track_info.title
|
||||
|
||||
# Possibly colorize changes.
|
||||
if color:
|
||||
|
|
@ -183,8 +183,8 @@ def show_item_change(item, info, dist, color):
|
|||
"""Print out the change that would occur by tagging `item` with the
|
||||
metadata from `info`.
|
||||
"""
|
||||
cur_artist, new_artist = item.artist, info['artist']
|
||||
cur_title, new_title = item.title, info['title']
|
||||
cur_artist, new_artist = item.artist, info.artist
|
||||
cur_title, new_title = item.title, info.title
|
||||
|
||||
if cur_artist != new_artist or cur_title != new_title:
|
||||
if color:
|
||||
|
|
@ -228,7 +228,7 @@ def choose_candidate(candidates, singleton, rec, color, timid,
|
|||
|
||||
Returns the result of the choice, which may SKIP, ASIS, TRACKS, or
|
||||
MANUAL or a candidate. For albums, a candidate is a `(info, items)`
|
||||
pair; for items, it is just an `info` dictionary.
|
||||
pair; for items, it is just a TrackInfo object.
|
||||
"""
|
||||
# Sanity check.
|
||||
if singleton:
|
||||
|
|
@ -462,7 +462,7 @@ def choose_match(task, config):
|
|||
|
||||
def choose_item(task, config):
|
||||
"""Ask the user for a choice about tagging a single item. Returns
|
||||
either an action constant or a track info dictionary.
|
||||
either an action constant or a TrackInfo object.
|
||||
"""
|
||||
print_()
|
||||
print_(task.item.path)
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ import unittest
|
|||
|
||||
import _common
|
||||
from beets.autotag import art
|
||||
from beets.autotag import AlbumInfo
|
||||
import os
|
||||
import shutil
|
||||
|
||||
|
|
@ -76,25 +77,25 @@ class CombinedTest(unittest.TestCase):
|
|||
|
||||
def test_main_interface_returns_amazon_art(self):
|
||||
art.urllib.urlretrieve = MockUrlRetrieve('anotherpath', 'image/jpeg')
|
||||
album = {'asin': 'xxxx'}
|
||||
album = AlbumInfo(None, None, None, None, None, asin='xxxx')
|
||||
artpath = art.art_for_album(album, None)
|
||||
self.assertEqual(artpath, 'anotherpath')
|
||||
|
||||
def test_main_interface_returns_none_for_missing_asin_and_path(self):
|
||||
album = {'asin': None}
|
||||
album = AlbumInfo(None, None, None, None, None, asin=None)
|
||||
artpath = art.art_for_album(album, None)
|
||||
self.assertEqual(artpath, None)
|
||||
|
||||
def test_main_interface_gives_precedence_to_fs_art(self):
|
||||
_common.touch(os.path.join(self.dpath, 'a.jpg'))
|
||||
art.urllib.urlretrieve = MockUrlRetrieve('anotherpath', 'image/jpeg')
|
||||
album = {'asin': 'xxxx'}
|
||||
album = AlbumInfo(None, None, None, None, None, asin='xxxx')
|
||||
artpath = art.art_for_album(album, self.dpath)
|
||||
self.assertEqual(artpath, os.path.join(self.dpath, 'a.jpg'))
|
||||
|
||||
def test_main_interface_falls_back_to_amazon(self):
|
||||
art.urllib.urlretrieve = MockUrlRetrieve('anotherpath', 'image/jpeg')
|
||||
album = {'asin': 'xxxx'}
|
||||
album = AlbumInfo(None, None, None, None, None, asin='xxxx')
|
||||
artpath = art.art_for_album(album, self.dpath)
|
||||
self.assertEqual(artpath, 'anotherpath')
|
||||
|
||||
|
|
|
|||
|
|
@ -18,12 +18,14 @@ import unittest
|
|||
import os
|
||||
import shutil
|
||||
import re
|
||||
import copy
|
||||
|
||||
import _common
|
||||
from beets import autotag
|
||||
from beets.autotag import match
|
||||
from beets.library import Item
|
||||
from beets.util import plurality
|
||||
from beets.autotag import AlbumInfo, TrackInfo
|
||||
|
||||
class PluralityTest(unittest.TestCase):
|
||||
def test_plurality_consensus(self):
|
||||
|
|
@ -73,12 +75,9 @@ class AlbumDistanceTest(unittest.TestCase):
|
|||
|
||||
def trackinfo(self):
|
||||
ti = []
|
||||
ti.append({'title': 'one', 'artist': 'some artist',
|
||||
'track': 1, 'length': 1})
|
||||
ti.append({'title': 'two', 'artist': 'some artist',
|
||||
'track': 2, 'length': 1})
|
||||
ti.append({'title': 'three', 'artist': 'some artist',
|
||||
'track': 3, 'length': 1})
|
||||
ti.append(TrackInfo('one', None, 'some artist', length=1))
|
||||
ti.append(TrackInfo('two', None, 'some artist', length=1))
|
||||
ti.append(TrackInfo('three', None, 'some artist', length=1))
|
||||
return ti
|
||||
|
||||
def test_identical_albums(self):
|
||||
|
|
@ -86,12 +85,13 @@ class AlbumDistanceTest(unittest.TestCase):
|
|||
items.append(self.item('one', 1))
|
||||
items.append(self.item('two', 2))
|
||||
items.append(self.item('three', 3))
|
||||
info = {
|
||||
'artist': 'some artist',
|
||||
'album': 'some album',
|
||||
'tracks': self.trackinfo(),
|
||||
'va': False,
|
||||
}
|
||||
info = AlbumInfo(
|
||||
artist = 'some artist',
|
||||
album = 'some album',
|
||||
tracks = self.trackinfo(),
|
||||
va = False,
|
||||
album_id = None, artist_id = None,
|
||||
)
|
||||
self.assertEqual(match.distance(items, info), 0)
|
||||
|
||||
def test_global_artists_differ(self):
|
||||
|
|
@ -99,12 +99,13 @@ class AlbumDistanceTest(unittest.TestCase):
|
|||
items.append(self.item('one', 1))
|
||||
items.append(self.item('two', 2))
|
||||
items.append(self.item('three', 3))
|
||||
info = {
|
||||
'artist': 'someone else',
|
||||
'album': 'some album',
|
||||
'tracks': self.trackinfo(),
|
||||
'va': False,
|
||||
}
|
||||
info = AlbumInfo(
|
||||
artist = 'someone else',
|
||||
album = 'some album',
|
||||
tracks = self.trackinfo(),
|
||||
va = False,
|
||||
album_id = None, artist_id = None,
|
||||
)
|
||||
self.assertNotEqual(match.distance(items, info), 0)
|
||||
|
||||
def test_comp_track_artists_match(self):
|
||||
|
|
@ -112,12 +113,13 @@ class AlbumDistanceTest(unittest.TestCase):
|
|||
items.append(self.item('one', 1))
|
||||
items.append(self.item('two', 2))
|
||||
items.append(self.item('three', 3))
|
||||
info = {
|
||||
'artist': 'should be ignored',
|
||||
'album': 'some album',
|
||||
'tracks': self.trackinfo(),
|
||||
'va': True,
|
||||
}
|
||||
info = AlbumInfo(
|
||||
artist = 'should be ignored',
|
||||
album = 'some album',
|
||||
tracks = self.trackinfo(),
|
||||
va = True,
|
||||
album_id = None, artist_id = None,
|
||||
)
|
||||
self.assertEqual(match.distance(items, info), 0)
|
||||
|
||||
def test_comp_no_track_artists(self):
|
||||
|
|
@ -126,15 +128,16 @@ class AlbumDistanceTest(unittest.TestCase):
|
|||
items.append(self.item('one', 1))
|
||||
items.append(self.item('two', 2))
|
||||
items.append(self.item('three', 3))
|
||||
info = {
|
||||
'artist': 'should be ignored',
|
||||
'album': 'some album',
|
||||
'tracks': self.trackinfo(),
|
||||
'va': True,
|
||||
}
|
||||
del info['tracks'][0]['artist']
|
||||
del info['tracks'][1]['artist']
|
||||
del info['tracks'][2]['artist']
|
||||
info = AlbumInfo(
|
||||
artist = 'should be ignored',
|
||||
album = 'some album',
|
||||
tracks = self.trackinfo(),
|
||||
va = True,
|
||||
album_id = None, artist_id = None,
|
||||
)
|
||||
info.tracks[0].artist = None
|
||||
info.tracks[1].artist = None
|
||||
info.tracks[2].artist = None
|
||||
self.assertEqual(match.distance(items, info), 0)
|
||||
|
||||
def test_comp_track_artists_do_not_match(self):
|
||||
|
|
@ -142,12 +145,13 @@ class AlbumDistanceTest(unittest.TestCase):
|
|||
items.append(self.item('one', 1))
|
||||
items.append(self.item('two', 2, 'someone else'))
|
||||
items.append(self.item('three', 3))
|
||||
info = {
|
||||
'artist': 'some artist',
|
||||
'album': 'some album',
|
||||
'tracks': self.trackinfo(),
|
||||
'va': True,
|
||||
}
|
||||
info = AlbumInfo(
|
||||
artist = 'some artist',
|
||||
album = 'some album',
|
||||
tracks = self.trackinfo(),
|
||||
va = True,
|
||||
album_id = None, artist_id = None,
|
||||
)
|
||||
self.assertNotEqual(match.distance(items, info), 0)
|
||||
|
||||
def _mkmp3(path):
|
||||
|
|
@ -206,9 +210,9 @@ class OrderingTest(unittest.TestCase):
|
|||
items.append(self.item('three', 2))
|
||||
items.append(self.item('two', 3))
|
||||
trackinfo = []
|
||||
trackinfo.append({'title': 'one', 'track': 1})
|
||||
trackinfo.append({'title': 'two', 'track': 2})
|
||||
trackinfo.append({'title': 'three', 'track': 3})
|
||||
trackinfo.append(TrackInfo('one', None))
|
||||
trackinfo.append(TrackInfo('two', None))
|
||||
trackinfo.append(TrackInfo('three', None))
|
||||
ordered = match.order_items(items, trackinfo)
|
||||
self.assertEqual(ordered[0].title, 'one')
|
||||
self.assertEqual(ordered[1].title, 'two')
|
||||
|
|
@ -220,9 +224,9 @@ class OrderingTest(unittest.TestCase):
|
|||
items.append(self.item('three', 1))
|
||||
items.append(self.item('two', 1))
|
||||
trackinfo = []
|
||||
trackinfo.append({'title': 'one', 'track': 1})
|
||||
trackinfo.append({'title': 'two', 'track': 2})
|
||||
trackinfo.append({'title': 'three', 'track': 3})
|
||||
trackinfo.append(TrackInfo('one', None))
|
||||
trackinfo.append(TrackInfo('two', None))
|
||||
trackinfo.append(TrackInfo('three', None))
|
||||
ordered = match.order_items(items, trackinfo)
|
||||
self.assertEqual(ordered[0].title, 'one')
|
||||
self.assertEqual(ordered[1].title, 'two')
|
||||
|
|
@ -233,7 +237,7 @@ class OrderingTest(unittest.TestCase):
|
|||
items.append(self.item('one', 1))
|
||||
items.append(self.item('two', 2))
|
||||
trackinfo = []
|
||||
trackinfo.append({'title': 'one', 'track': 1})
|
||||
trackinfo.append(TrackInfo('one', None))
|
||||
ordered = match.order_items(items, trackinfo)
|
||||
self.assertEqual(ordered, None)
|
||||
|
||||
|
|
@ -263,10 +267,7 @@ class OrderingTest(unittest.TestCase):
|
|||
items.append(item(12, 186.45916150485752))
|
||||
|
||||
def info(title, length):
|
||||
return {
|
||||
'title': title,
|
||||
'length': length,
|
||||
}
|
||||
return TrackInfo(title, None, length=length)
|
||||
trackinfo = []
|
||||
trackinfo.append(info('Alone', 238.893))
|
||||
trackinfo.append(info('The Woman in You', 341.44))
|
||||
|
|
@ -291,23 +292,19 @@ class ApplyTest(unittest.TestCase):
|
|||
self.items.append(Item({}))
|
||||
self.items.append(Item({}))
|
||||
trackinfo = []
|
||||
trackinfo.append({
|
||||
'title': 'oneNew',
|
||||
'id': 'dfa939ec-118c-4d0f-84a0-60f3d1e6522c',
|
||||
})
|
||||
trackinfo.append({
|
||||
'title': 'twoNew',
|
||||
'id': '40130ed1-a27c-42fd-a328-1ebefb6caef4',
|
||||
})
|
||||
self.info = {
|
||||
'tracks': trackinfo,
|
||||
'artist': 'artistNew',
|
||||
'album': 'albumNew',
|
||||
'album_id': '7edb51cb-77d6-4416-a23c-3a8c2994a2c7',
|
||||
'artist_id': 'a6623d39-2d8e-4f70-8242-0a9553b91e50',
|
||||
'albumtype': 'album',
|
||||
'va': False,
|
||||
}
|
||||
trackinfo.append(TrackInfo('oneNew',
|
||||
'dfa939ec-118c-4d0f-84a0-60f3d1e6522c'))
|
||||
trackinfo.append(TrackInfo('twoNew',
|
||||
'40130ed1-a27c-42fd-a328-1ebefb6caef4'))
|
||||
self.info = AlbumInfo(
|
||||
tracks = trackinfo,
|
||||
artist = 'artistNew',
|
||||
album = 'albumNew',
|
||||
album_id = '7edb51cb-77d6-4416-a23c-3a8c2994a2c7',
|
||||
artist_id = 'a6623d39-2d8e-4f70-8242-0a9553b91e50',
|
||||
albumtype = 'album',
|
||||
va = False,
|
||||
)
|
||||
|
||||
def test_titles_applied(self):
|
||||
autotag.apply_metadata(self.items, self.info)
|
||||
|
|
@ -352,17 +349,15 @@ class ApplyTest(unittest.TestCase):
|
|||
self.assertEqual(self.items[1].albumtype, 'album')
|
||||
|
||||
def test_album_artist_overrides_empty_track_artist(self):
|
||||
my_info = dict(self.info)
|
||||
my_info['tracks'] = [dict(t) for t in self.info['tracks']]
|
||||
my_info = copy.deepcopy(self.info)
|
||||
autotag.apply_metadata(self.items, my_info)
|
||||
self.assertEqual(self.items[0].artist, 'artistNew')
|
||||
self.assertEqual(self.items[0].artist, 'artistNew')
|
||||
|
||||
def test_album_artist_overriden_by_nonempty_track_artist(self):
|
||||
my_info = dict(self.info)
|
||||
my_info['tracks'] = [dict(t) for t in self.info['tracks']]
|
||||
my_info['tracks'][0]['artist'] = 'artist1!'
|
||||
my_info['tracks'][1]['artist'] = 'artist2!'
|
||||
my_info = copy.deepcopy(self.info)
|
||||
my_info.tracks[0].artist = 'artist1!'
|
||||
my_info.tracks[1].artist = 'artist2!'
|
||||
autotag.apply_metadata(self.items, my_info)
|
||||
self.assertEqual(self.items[0].artist, 'artist1!')
|
||||
self.assertEqual(self.items[1].artist, 'artist2!')
|
||||
|
|
@ -373,27 +368,27 @@ class ApplyCompilationTest(unittest.TestCase):
|
|||
self.items.append(Item({}))
|
||||
self.items.append(Item({}))
|
||||
trackinfo = []
|
||||
trackinfo.append({
|
||||
'title': 'oneNew',
|
||||
'id': 'dfa939ec-118c-4d0f-84a0-60f3d1e6522c',
|
||||
'artist': 'artistOneNew',
|
||||
'artist_id': 'a05686fc-9db2-4c23-b99e-77f5db3e5282',
|
||||
})
|
||||
trackinfo.append({
|
||||
'title': 'twoNew',
|
||||
'id': '40130ed1-a27c-42fd-a328-1ebefb6caef4',
|
||||
'artist': 'artistTwoNew',
|
||||
'artist_id': '80b3cf5e-18fe-4c59-98c7-e5bb87210710',
|
||||
})
|
||||
self.info = {
|
||||
'tracks': trackinfo,
|
||||
'artist': 'variousNew',
|
||||
'album': 'albumNew',
|
||||
'album_id': '3b69ea40-39b8-487f-8818-04b6eff8c21a',
|
||||
'artist_id': '89ad4ac3-39f7-470e-963a-56509c546377',
|
||||
'albumtype': 'compilation',
|
||||
'va': False,
|
||||
}
|
||||
trackinfo.append(TrackInfo(
|
||||
'oneNew',
|
||||
'dfa939ec-118c-4d0f-84a0-60f3d1e6522c',
|
||||
'artistOneNew',
|
||||
'a05686fc-9db2-4c23-b99e-77f5db3e5282',
|
||||
))
|
||||
trackinfo.append(TrackInfo(
|
||||
'twoNew',
|
||||
'40130ed1-a27c-42fd-a328-1ebefb6caef4',
|
||||
'artistTwoNew',
|
||||
'80b3cf5e-18fe-4c59-98c7-e5bb87210710',
|
||||
))
|
||||
self.info = AlbumInfo(
|
||||
tracks = trackinfo,
|
||||
artist = 'variousNew',
|
||||
album = 'albumNew',
|
||||
album_id = '3b69ea40-39b8-487f-8818-04b6eff8c21a',
|
||||
artist_id = '89ad4ac3-39f7-470e-963a-56509c546377',
|
||||
albumtype = 'compilation',
|
||||
va = False,
|
||||
)
|
||||
|
||||
def test_album_and_track_artists_separate(self):
|
||||
autotag.apply_metadata(self.items, self.info)
|
||||
|
|
@ -419,8 +414,8 @@ class ApplyCompilationTest(unittest.TestCase):
|
|||
self.assertFalse(self.items[1].comp)
|
||||
|
||||
def test_va_flag_sets_comp(self):
|
||||
va_info = dict(self.info) # make a copy
|
||||
va_info['va'] = True
|
||||
va_info = copy.deepcopy(self.info)
|
||||
va_info.va = True
|
||||
autotag.apply_metadata(self.items, va_info)
|
||||
self.assertTrue(self.items[0].comp)
|
||||
self.assertTrue(self.items[1].comp)
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ import _common
|
|||
from beets import library
|
||||
from beets import importer
|
||||
from beets import mediafile
|
||||
from beets.autotag import AlbumInfo, TrackInfo
|
||||
|
||||
TEST_TITLES = ('The Opener', 'The Second Track', 'The Last Track')
|
||||
class NonAutotaggedImportTest(unittest.TestCase):
|
||||
|
|
@ -173,17 +174,17 @@ class ImportApplyTest(unittest.TestCase, _common.ExtraAsserts):
|
|||
self.i = library.Item.from_path(self.srcpath)
|
||||
self.i.comp = False
|
||||
|
||||
trackinfo = {'title': 'one', 'artist': 'some artist',
|
||||
'track': 1, 'length': 1, 'id': 'trackid'}
|
||||
self.info = {
|
||||
'artist': 'some artist',
|
||||
'album': 'some album',
|
||||
'tracks': [trackinfo],
|
||||
'va': False,
|
||||
'album_id': 'albumid',
|
||||
'artist_id': 'artistid',
|
||||
'albumtype': 'soundtrack',
|
||||
}
|
||||
trackinfo = TrackInfo('one', 'trackid', 'some artist',
|
||||
'artistid', 1)
|
||||
self.info = AlbumInfo(
|
||||
artist = 'some artist',
|
||||
album = 'some album',
|
||||
tracks = [trackinfo],
|
||||
va = False,
|
||||
album_id = 'albumid',
|
||||
artist_id = 'artistid',
|
||||
albumtype = 'soundtrack',
|
||||
)
|
||||
|
||||
def tearDown(self):
|
||||
shutil.rmtree(self.libdir)
|
||||
|
|
@ -227,7 +228,7 @@ class ImportApplyTest(unittest.TestCase, _common.ExtraAsserts):
|
|||
coro.next() # Prime coroutine.
|
||||
|
||||
task = importer.ImportTask.item_task(self.i)
|
||||
task.set_choice(self.info['tracks'][0])
|
||||
task.set_choice(self.info.tracks[0])
|
||||
coro.send(task)
|
||||
|
||||
self.assertExists(
|
||||
|
|
@ -559,7 +560,10 @@ class DuplicateCheckTest(unittest.TestCase):
|
|||
if asis:
|
||||
task.set_choice(importer.action.ASIS)
|
||||
else:
|
||||
task.set_choice(({'artist': artist, 'album': album}, [item]))
|
||||
task.set_choice((
|
||||
AlbumInfo(album, None, artist, None, None),
|
||||
[item]
|
||||
))
|
||||
return task
|
||||
|
||||
def _item_task(self, asis, artist=None, title=None, existing=False):
|
||||
|
|
@ -576,7 +580,7 @@ class DuplicateCheckTest(unittest.TestCase):
|
|||
item.title = title
|
||||
task.set_choice(importer.action.ASIS)
|
||||
else:
|
||||
task.set_choice({'artist': artist, 'title': title})
|
||||
task.set_choice(TrackInfo(title, None, artist))
|
||||
return task
|
||||
|
||||
def test_duplicate_album_apply(self):
|
||||
|
|
|
|||
|
|
@ -100,7 +100,7 @@ class MBQueryErrorTest(unittest.TestCase):
|
|||
with self.assertRaises(mb.ServerBusyError):
|
||||
mb._query_wrap(raise_func(exc))
|
||||
|
||||
class MBReleaseDictTest(unittest.TestCase):
|
||||
class MBAlbumInfoTest(unittest.TestCase):
|
||||
def _make_release(self, date_str='2009'):
|
||||
release = musicbrainz2.model.Release()
|
||||
release.title = 'ALBUM TITLE'
|
||||
|
|
@ -128,68 +128,68 @@ class MBReleaseDictTest(unittest.TestCase):
|
|||
|
||||
def test_parse_release_with_year(self):
|
||||
release = self._make_release('1984')
|
||||
d = mb.release_dict(release)
|
||||
self.assertEqual(d['album'], 'ALBUM TITLE')
|
||||
self.assertEqual(d['album_id'], 'ALBUM ID')
|
||||
self.assertEqual(d['artist'], 'ARTIST NAME')
|
||||
self.assertEqual(d['artist_id'], 'ARTIST ID')
|
||||
self.assertEqual(d['year'], 1984)
|
||||
d = mb.album_info(release, [])
|
||||
self.assertEqual(d.album, 'ALBUM TITLE')
|
||||
self.assertEqual(d.album_id, 'ALBUM ID')
|
||||
self.assertEqual(d.artist, 'ARTIST NAME')
|
||||
self.assertEqual(d.artist_id, 'ARTIST ID')
|
||||
self.assertEqual(d.year, 1984)
|
||||
|
||||
def test_parse_release_type(self):
|
||||
release = self._make_release('1984')
|
||||
d = mb.release_dict(release)
|
||||
self.assertEqual(d['albumtype'], 'album')
|
||||
d = mb.album_info(release, [])
|
||||
self.assertEqual(d.albumtype, 'album')
|
||||
|
||||
def test_parse_release_full_date(self):
|
||||
release = self._make_release('1987-03-31')
|
||||
d = mb.release_dict(release)
|
||||
self.assertEqual(d['year'], 1987)
|
||||
self.assertEqual(d['month'], 3)
|
||||
self.assertEqual(d['day'], 31)
|
||||
d = mb.album_info(release, [])
|
||||
self.assertEqual(d.year, 1987)
|
||||
self.assertEqual(d.month, 3)
|
||||
self.assertEqual(d.day, 31)
|
||||
|
||||
def test_parse_tracks(self):
|
||||
release = self._make_release()
|
||||
tracks = [self._make_track('TITLE ONE', 'dom/ID ONE', 100.0 * 1000.0),
|
||||
self._make_track('TITLE TWO', 'dom/ID TWO', 200.0 * 1000.0)]
|
||||
d = mb.release_dict(release, tracks)
|
||||
t = d['tracks']
|
||||
d = mb.album_info(release, tracks)
|
||||
t = d.tracks
|
||||
self.assertEqual(len(t), 2)
|
||||
self.assertEqual(t[0]['title'], 'TITLE ONE')
|
||||
self.assertEqual(t[0]['id'], 'ID ONE')
|
||||
self.assertEqual(t[0]['length'], 100.0)
|
||||
self.assertEqual(t[1]['title'], 'TITLE TWO')
|
||||
self.assertEqual(t[1]['id'], 'ID TWO')
|
||||
self.assertEqual(t[1]['length'], 200.0)
|
||||
self.assertEqual(t[0].title, 'TITLE ONE')
|
||||
self.assertEqual(t[0].track_id, 'ID ONE')
|
||||
self.assertEqual(t[0].length, 100.0)
|
||||
self.assertEqual(t[1].title, 'TITLE TWO')
|
||||
self.assertEqual(t[1].track_id, 'ID TWO')
|
||||
self.assertEqual(t[1].length, 200.0)
|
||||
|
||||
def test_parse_release_year_month_only(self):
|
||||
release = self._make_release('1987-03')
|
||||
d = mb.release_dict(release)
|
||||
self.assertEqual(d['year'], 1987)
|
||||
self.assertEqual(d['month'], 3)
|
||||
d = mb.album_info(release, [])
|
||||
self.assertEqual(d.year, 1987)
|
||||
self.assertEqual(d.month, 3)
|
||||
|
||||
def test_no_durations(self):
|
||||
release = self._make_release()
|
||||
tracks = [self._make_track('TITLE', 'dom/ID', None)]
|
||||
d = mb.release_dict(release, tracks)
|
||||
self.assertFalse('length' in d['tracks'][0])
|
||||
d = mb.album_info(release, tracks)
|
||||
self.assertEqual(d.tracks[0].length, None)
|
||||
|
||||
def test_no_release_date(self):
|
||||
release = self._make_release(None)
|
||||
d = mb.release_dict(release)
|
||||
self.assertFalse('year' in d)
|
||||
self.assertFalse('month' in d)
|
||||
self.assertFalse('day' in d)
|
||||
d = mb.album_info(release, [])
|
||||
self.assertFalse(d.year)
|
||||
self.assertFalse(d.month)
|
||||
self.assertFalse(d.day)
|
||||
|
||||
def test_various_artists_defaults_false(self):
|
||||
release = self._make_release(None)
|
||||
d = mb.release_dict(release)
|
||||
self.assertFalse(d['va'])
|
||||
d = mb.album_info(release, [])
|
||||
self.assertFalse(d.va)
|
||||
|
||||
def test_detect_various_artists(self):
|
||||
release = self._make_release(None)
|
||||
release.artist.id = musicbrainz2.model.VARIOUS_ARTISTS_ID
|
||||
d = mb.release_dict(release)
|
||||
self.assertTrue(d['va'])
|
||||
d = mb.album_info(release, [])
|
||||
self.assertTrue(d.va)
|
||||
|
||||
class QuerySanitationTest(unittest.TestCase):
|
||||
def test_special_char_escaped(self):
|
||||
|
|
|
|||
Loading…
Reference in a new issue