mirror of
https://github.com/beetbox/beets.git
synced 2025-12-24 01:25:47 +01:00
recommendation is now a "real" enumeration
This commit is contained in:
parent
ebcd944bd5
commit
151177ab95
4 changed files with 29 additions and 35 deletions
|
|
@ -25,8 +25,7 @@ from beets.util import sorted_walk, ancestry, displayable_path
|
|||
from .hooks import AlbumInfo, TrackInfo, AlbumMatch, TrackMatch
|
||||
from .match import AutotagError
|
||||
from .match import tag_item, tag_album
|
||||
from .match import \
|
||||
RECOMMEND_STRONG, RECOMMEND_MEDIUM, RECOMMEND_LOW, RECOMMEND_NONE
|
||||
from .match import recommendation
|
||||
|
||||
# Global logger.
|
||||
log = logging.getLogger('beets')
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ from unidecode import unidecode
|
|||
from beets import plugins
|
||||
from beets import config
|
||||
from beets.util import levenshtein, plurality
|
||||
from beets.util.enumeration import enum
|
||||
from beets.autotag import hooks
|
||||
|
||||
# Distance parameters.
|
||||
|
|
@ -71,11 +72,8 @@ SD_REPLACE = [
|
|||
(r'&', 'and'),
|
||||
]
|
||||
|
||||
# Recommendation constants.
|
||||
RECOMMEND_STRONG = 'RECOMMEND_STRONG'
|
||||
RECOMMEND_MEDIUM = 'RECOMMEND_MEDIUM'
|
||||
RECOMMEND_LOW = 'RECOMMEND_LOW'
|
||||
RECOMMEND_NONE = 'RECOMMEND_NONE'
|
||||
# Recommendation enumeration.
|
||||
recommendation = enum('none', 'low', 'medium', 'strong', name='recommendation')
|
||||
|
||||
# Artist signals that indicate "various artists". These are used at the
|
||||
# album level to determine whether a given release is likely a VA
|
||||
|
|
@ -322,37 +320,36 @@ def match_by_id(items):
|
|||
log.debug('No album ID consensus.')
|
||||
return None
|
||||
|
||||
def recommendation(results):
|
||||
def _recommendation(results):
|
||||
"""Given a sorted list of AlbumMatch or TrackMatch objects, return a
|
||||
recommendation flag (RECOMMEND_STRONG, RECOMMEND_MEDIUM,
|
||||
RECOMMEND_NONE) based on the results' distances.
|
||||
recommendation based on the results' distances.
|
||||
"""
|
||||
if not results:
|
||||
# No candidates: no recommendation.
|
||||
rec = RECOMMEND_NONE
|
||||
rec = recommendation.none
|
||||
else:
|
||||
min_dist = results[0].distance
|
||||
if min_dist < config['match']['strong_rec_thresh'].as_number():
|
||||
# Partial matches get downgraded to "medium".
|
||||
if isinstance(results[0], hooks.AlbumMatch) and \
|
||||
(results[0].extra_items or results[0].extra_tracks):
|
||||
rec = RECOMMEND_MEDIUM
|
||||
rec = recommendation.medium
|
||||
else:
|
||||
# Strong recommendation level.
|
||||
rec = RECOMMEND_STRONG
|
||||
rec = recommendation.strong
|
||||
elif min_dist <= config['match']['medium_rec_thresh'].as_number():
|
||||
# Medium recommendation level.
|
||||
rec = RECOMMEND_MEDIUM
|
||||
rec = recommendation.medium
|
||||
elif len(results) == 1:
|
||||
# Only a single candidate.
|
||||
rec = RECOMMEND_LOW
|
||||
rec = recommendation.low
|
||||
elif results[1].distance - min_dist >= \
|
||||
config['match']['rec_gap_thresh'].as_number():
|
||||
# Gap between first two candidates is large.
|
||||
rec = RECOMMEND_LOW
|
||||
rec = recommendation.low
|
||||
else:
|
||||
# No conclusion.
|
||||
rec = RECOMMEND_NONE
|
||||
rec = recommendation.none
|
||||
return rec
|
||||
|
||||
def _add_candidate(items, results, info):
|
||||
|
|
@ -386,10 +383,7 @@ def tag_album(items, search_artist=None, search_album=None,
|
|||
- The current album.
|
||||
- A list of AlbumMatch objects. The candidates are sorted by
|
||||
distance (i.e., best match first).
|
||||
- A recommendation, one of RECOMMEND_STRONG, RECOMMEND_MEDIUM,
|
||||
or RECOMMEND_NONE; indicating that the first candidate is
|
||||
very likely, it is somewhat likely, or no conclusion could
|
||||
be reached.
|
||||
- A recommendation.
|
||||
If search_artist and search_album or search_id are provided, then
|
||||
they are used as search terms in place of the current metadata.
|
||||
May raise an AutotagError if existing metadata is insufficient.
|
||||
|
|
@ -410,13 +404,13 @@ def tag_album(items, search_artist=None, search_album=None,
|
|||
id_info = match_by_id(items)
|
||||
if id_info:
|
||||
_add_candidate(items, candidates, id_info)
|
||||
rec = recommendation(candidates.values())
|
||||
rec = _recommendation(candidates.values())
|
||||
log.debug('Album ID match recommendation is ' + str(rec))
|
||||
if candidates and not config['import']['timid']:
|
||||
# If we have a very good MBID match, return immediately.
|
||||
# Otherwise, this match will compete against metadata-based
|
||||
# matches.
|
||||
if rec == RECOMMEND_STRONG:
|
||||
if rec == recommendation.strong:
|
||||
log.debug('ID match.')
|
||||
return cur_artist, cur_album, candidates.values(), rec
|
||||
|
||||
|
|
@ -425,7 +419,7 @@ def tag_album(items, search_artist=None, search_album=None,
|
|||
if candidates:
|
||||
return cur_artist, cur_album, candidates.values(), rec
|
||||
else:
|
||||
return cur_artist, cur_album, [], RECOMMEND_NONE
|
||||
return cur_artist, cur_album, [], recommendation.none
|
||||
|
||||
# Search terms.
|
||||
if not (search_artist and search_album):
|
||||
|
|
@ -448,7 +442,7 @@ def tag_album(items, search_artist=None, search_album=None,
|
|||
|
||||
# Sort and get the recommendation.
|
||||
candidates = sorted(candidates.itervalues())
|
||||
rec = recommendation(candidates)
|
||||
rec = _recommendation(candidates)
|
||||
return cur_artist, cur_album, candidates, rec
|
||||
|
||||
def tag_item(item, search_artist=None, search_title=None,
|
||||
|
|
@ -473,8 +467,8 @@ def tag_item(item, search_artist=None, search_title=None,
|
|||
candidates[track_info.track_id] = \
|
||||
hooks.TrackMatch(dist, track_info)
|
||||
# If this is a good match, then don't keep searching.
|
||||
rec = recommendation(candidates.values())
|
||||
if rec == RECOMMEND_STRONG and not config['import']['timid']:
|
||||
rec = _recommendation(candidates.values())
|
||||
if rec == recommendation.strong and not config['import']['timid']:
|
||||
log.debug('Track ID match.')
|
||||
return candidates.values(), rec
|
||||
|
||||
|
|
@ -483,7 +477,7 @@ def tag_item(item, search_artist=None, search_title=None,
|
|||
if candidates:
|
||||
return candidates.values(), rec
|
||||
else:
|
||||
return [], RECOMMEND_NONE
|
||||
return [], recommendation.none
|
||||
|
||||
# Search terms.
|
||||
if not (search_artist and search_title):
|
||||
|
|
@ -498,5 +492,5 @@ def tag_item(item, search_artist=None, search_title=None,
|
|||
# Sort by distance and return with recommendation.
|
||||
log.debug('Found %i candidates.' % len(candidates))
|
||||
candidates = sorted(candidates.itervalues())
|
||||
rec = recommendation(candidates)
|
||||
rec = _recommendation(candidates)
|
||||
return candidates, rec
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ import beets
|
|||
from beets import ui
|
||||
from beets.ui import print_, input_, decargs
|
||||
from beets import autotag
|
||||
from beets.autotag import recommendation
|
||||
from beets import plugins
|
||||
from beets import importer
|
||||
from beets.util import syspath, normpath, ancestry, displayable_path
|
||||
|
|
@ -277,7 +278,7 @@ def _summary_judment(rec):
|
|||
made.
|
||||
"""
|
||||
if config['import']['quiet']:
|
||||
if rec == autotag.RECOMMEND_STRONG:
|
||||
if rec == recommendation.strong:
|
||||
return importer.action.APPLY
|
||||
else:
|
||||
action = config['import']['quiet_fallback'].as_choice({
|
||||
|
|
@ -285,7 +286,7 @@ def _summary_judment(rec):
|
|||
'asis': importer.action.ASIS,
|
||||
})
|
||||
|
||||
elif rec == autotag.RECOMMEND_NONE:
|
||||
elif rec == recommendation.none:
|
||||
action = config['import']['none_rec_action'].as_choice({
|
||||
'skip': importer.action.SKIP,
|
||||
'asis': importer.action.ASIS,
|
||||
|
|
@ -352,13 +353,13 @@ def choose_candidate(candidates, singleton, rec, cur_artist=None,
|
|||
|
||||
# Is the change good enough?
|
||||
bypass_candidates = False
|
||||
if rec != autotag.RECOMMEND_NONE:
|
||||
if rec != recommendation.none:
|
||||
match = candidates[0]
|
||||
bypass_candidates = True
|
||||
|
||||
while True:
|
||||
# Display and choose from candidates.
|
||||
require = rec in (autotag.RECOMMEND_NONE, autotag.RECOMMEND_LOW)
|
||||
require = rec <= recommendation.low
|
||||
|
||||
if not bypass_candidates:
|
||||
# Display list of candidates.
|
||||
|
|
@ -441,7 +442,7 @@ def choose_candidate(candidates, singleton, rec, cur_artist=None,
|
|||
show_change(cur_artist, cur_album, match)
|
||||
|
||||
# Exact match => tag automatically if we're not in timid mode.
|
||||
if rec == autotag.RECOMMEND_STRONG and not config['import']['timid']:
|
||||
if rec == recommendation.strong and not config['import']['timid']:
|
||||
return match
|
||||
|
||||
# Ask for confirmation.
|
||||
|
|
|
|||
|
|
@ -455,7 +455,7 @@ class AutotagTest(_common.TestCase):
|
|||
'path',
|
||||
[_common.item()],
|
||||
)
|
||||
task.set_candidates('artist', 'album', [], autotag.RECOMMEND_NONE)
|
||||
task.set_candidates('artist', 'album', [], autotag.recommendation.none)
|
||||
session = _common.import_session(cli=True)
|
||||
res = session.choose_match(task)
|
||||
self.assertEqual(res, result)
|
||||
|
|
|
|||
Loading…
Reference in a new issue