diff --git a/beets/autotag/__init__.py b/beets/autotag/__init__.py index 1e7e7a2dd..45238db8f 100644 --- a/beets/autotag/__init__.py +++ b/beets/autotag/__init__.py @@ -25,7 +25,8 @@ 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_NONE +from .match import \ + RECOMMEND_STRONG, RECOMMEND_MEDIUM, RECOMMEND_LOW, RECOMMEND_NONE # Global logger. log = logging.getLogger('beets') diff --git a/beets/autotag/match.py b/beets/autotag/match.py index 4b80a4111..63aa6450f 100644 --- a/beets/autotag/match.py +++ b/beets/autotag/match.py @@ -74,6 +74,7 @@ SD_REPLACE = [ # Recommendation constants. RECOMMEND_STRONG = 'RECOMMEND_STRONG' RECOMMEND_MEDIUM = 'RECOMMEND_MEDIUM' +RECOMMEND_LOW = 'RECOMMEND_LOW' RECOMMEND_NONE = 'RECOMMEND_NONE' # Artist signals that indicate "various artists". These are used at the @@ -332,6 +333,11 @@ def recommendation(results): else: min_dist = results[0].distance if min_dist < config['match']['strong_rec_thresh'].as_number(): + # Reduce to medium rec if partial releases are not allowed. + if isinstance(results[0], hooks.AlbumMatch) and \ + config['import']['confirm_partial'] and \ + (results[0].extra_items or results[0].extra_tracks): + return RECOMMEND_MEDIUM # Strong recommendation level. rec = RECOMMEND_STRONG elif len(results) == 1: @@ -343,7 +349,7 @@ def recommendation(results): elif results[1].distance - min_dist >= \ config['match']['rec_gap_thresh'].as_number(): # Gap between first two candidates is large. - rec = RECOMMEND_MEDIUM + rec = RECOMMEND_LOW else: # No conclusion. rec = RECOMMEND_NONE diff --git a/beets/config_default.yaml b/beets/config_default.yaml index c91a8ce95..56f1a0055 100644 --- a/beets/config_default.yaml +++ b/beets/config_default.yaml @@ -14,6 +14,7 @@ import: autotag: yes quiet: no singletons: no + confirm_partial: no ignore: [".*", "*~"] replace: diff --git a/beets/ui/commands.py b/beets/ui/commands.py index 66669f7b9..7b279fae6 100644 --- a/beets/ui/commands.py +++ b/beets/ui/commands.py @@ -323,6 +323,7 @@ def choose_candidate(candidates, singleton, rec, cur_artist=None, bypass_candidates = True while True: + require = rec in (autotag.RECOMMEND_NONE, autotag.RECOMMEND_LOW) # Display and choose from candidates. if not bypass_candidates: # Display list of candidates. @@ -391,6 +392,9 @@ def choose_candidate(candidates, singleton, rec, cur_artist=None, match = candidates[sel - 1] else: match = candidates[sel - 1] + # Require selection (no default). + if sel != 1: + require = True bypass_candidates = False # Show what we're about to do. @@ -410,7 +414,10 @@ def choose_candidate(candidates, singleton, rec, cur_artist=None, else: opts = ('Apply', 'More candidates', 'Skip', 'Use as-is', 'as Tracks', 'Enter search', 'enter Id', 'aBort') - sel = ui.input_options(opts) + if config['import']['confirm_partial'].get(bool) and \ + match.extra_items or match.extra_tracks: + require = True + sel = ui.input_options(opts, require=require) if sel == 'a': return match elif sel == 'm': diff --git a/docs/reference/config.rst b/docs/reference/config.rst index 73bca4001..02a5714f5 100644 --- a/docs/reference/config.rst +++ b/docs/reference/config.rst @@ -265,6 +265,15 @@ Specifies a filename where the importer's log should be kept. By default, no log is written. This can be overridden with the ``-l`` flag to ``import``. +confirm_partial +~~~~~~~~~~~~~~~ + +Either ``yes`` or ``no``. If ``yes``, strong recommendations for partial +matches will be downgraded to medium so that they are not auto-tagged and must +be confirmed. The default selection on confirmation prompts for partial matches +will also be removed, so that the user must actually make a choice and cannot +accidentally apply changes. The default is ``no``. + .. _musicbrainz-config: MusicBrainz Options