From 375e335002725e85f8a4df84ed6a9b47c600f8a3 Mon Sep 17 00:00:00 2001 From: Adrian Sampson Date: Fri, 15 Apr 2011 20:14:30 -0700 Subject: [PATCH] manual searching for singletons (Still on a plane.) --- beets/autotag/__init__.py | 19 +++++++++++++------ beets/ui/commands.py | 34 ++++++++++++++++++++++++++-------- test/test_ui.py | 2 +- 3 files changed, 40 insertions(+), 15 deletions(-) diff --git a/beets/autotag/__init__.py b/beets/autotag/__init__.py index 3a82dca93..0827da6b6 100644 --- a/beets/autotag/__init__.py +++ b/beets/autotag/__init__.py @@ -482,7 +482,7 @@ def tag_album(items, search_artist=None, search_album=None): if not (search_artist and search_album): # No explicit search terms -- use current metadata. search_artist, search_album = cur_artist, cur_album - log.debug('Search terms: %s - %s' % (search_artist, search_album)) + log.debug(u'Search terms: %s - %s' % (search_artist, search_album)) # Get candidate metadata from search. if search_artist and search_album: @@ -496,7 +496,7 @@ def tag_album(items, search_artist=None, search_album=None): if search_album and ((not artist_consensus) or \ (search_artist.lower() in VA_ARTISTS) or \ any(item.comp for item in items)): - log.debug('Possibly Various Artists; adding matches.') + log.debug(u'Possibly Various Artists; adding matches.') candidates.extend(mb.match_album(None, search_album, len(items), MAX_CANDIDATES)) @@ -504,7 +504,7 @@ def tag_album(items, search_artist=None, search_album=None): candidates.extend(plugins.candidates(items)) # Get the distance to each candidate. - log.debug('Evaluating %i candidates.' % len(candidates)) + log.debug(u'Evaluating %i candidates.' % len(candidates)) for info in candidates: validate_candidate(items, out_tuples, info) @@ -515,10 +515,12 @@ def tag_album(items, search_artist=None, search_album=None): rec = recommendation(out_tuples) return cur_artist, cur_album, out_tuples, rec -def tag_item(item): +def tag_item(item, search_artist=None, search_title=None): """Attempts to find metadata for a single track. Returns a `(candidates, recommendation)` pair where `candidates` is a list - of `(distance, track_info)` pairs. + of `(distance, track_info)` pairs. `search_artist` and + `search_title` may be used to override the current metadata for + the purposes of the MusicBrainz category. """ candidates = [] @@ -534,9 +536,14 @@ def tag_item(item): if rec == RECOMMEND_STRONG: log.debug('Track ID match.') return candidates, rec + + # Search terms. + if not (search_artist and search_title): + search_artist, search_title = item.artist, item.title + log.debug(u'Item search terms: %s - %s' % (search_artist, search_title)) # Candidate metadata from search. - for track_info in mb.match_track(item.artist, item.title): + for track_info in mb.match_track(search_artist, search_title): dist = track_distance(item, track_info, incl_artist=True) candidates.append((dist, track_info)) diff --git a/beets/ui/commands.py b/beets/ui/commands.py index 2595286a5..372cb5f9b 100755 --- a/beets/ui/commands.py +++ b/beets/ui/commands.py @@ -294,11 +294,14 @@ def choose_candidate(candidates, singleton, rec, color, elif sel == 'b': raise importer.ImportAbort() -def manual_search(): - """Input an artist and album for manual search.""" +def manual_search(singleton): + """Input either an artist and album (for full albums) or artist and + track name (for singletons) for manual search. + """ artist = raw_input('Artist: ').decode(sys.stdin.encoding) - album = raw_input('Album: ').decode(sys.stdin.encoding) - return artist.strip(), album.strip() + name = raw_input('Track: ' if singleton else 'Album: ') \ + .decode(sys.stdin.encoding) + return artist.strip(), name.strip() def choose_match(task, config): """Given an initial autotagging of items, go through an interactive @@ -332,7 +335,7 @@ def choose_match(task, config): return choice elif choice is importer.action.MANUAL: # Try again with manual search terms. - search_artist, search_album = manual_search() + search_artist, search_album = manual_search(False) try: _, _, candidates, rec = \ autotag.tag_album(items, search_artist, search_album) @@ -341,6 +344,7 @@ def choose_match(task, config): else: # We have a candidate! Finish tagging. Here, choice is # an (info, items) pair as desired. + assert not isinstance(choice, importer.action) return choice def choose_item(task, config): @@ -362,10 +366,24 @@ def choose_item(task, config): else: return _quiet_fall_back(config) - else: + while True: # Ask for a choice. - return choose_candidate(candidates, True, rec, config.color, - item=task.items[0]) + choice = choose_candidate(candidates, True, rec, config.color, + item=task.items[0]) + + if choice in (importer.action.SKIP, importer.action.ASIS): + return choice + elif choice == importer.action.TRACKS: + assert False # TRACKS is only legal for albums. + elif choice == importer.action.MANUAL: + # Continue in the loop with a new set of candidates. + search_artist, search_title = manual_search(False) + candidates, rec = autotag.tag_item(task.items[0], search_artist, + search_title) + else: + # Chose a candidate. + assert not isinstance(choice, importer.action) + return choice # The import command. diff --git a/test/test_ui.py b/test/test_ui.py index be6d4c944..756198855 100644 --- a/test/test_ui.py +++ b/test/test_ui.py @@ -174,7 +174,7 @@ class InputTest(unittest.TestCase): def test_manual_search_gets_unicode(self): self.io.addinput('\xc3\x82me') self.io.addinput('\xc3\x82me') - artist, album = commands.manual_search() + artist, album = commands.manual_search(False) self.assertEqual(artist, u'\xc2me') self.assertEqual(album, u'\xc2me')