diff --git a/beets/autotag/match.py b/beets/autotag/match.py index 63aa6450f..aacb64d10 100644 --- a/beets/autotag/match.py +++ b/beets/autotag/match.py @@ -333,19 +333,19 @@ 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. + # Partial matches get downgraded to "medium". 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: - # Only a single candidate. Medium recommendation. - rec = RECOMMEND_MEDIUM + rec = RECOMMEND_MEDIUM + else: + # Strong recommendation level. + rec = RECOMMEND_STRONG elif min_dist <= config['match']['medium_rec_thresh'].as_number(): # Medium recommendation level. rec = RECOMMEND_MEDIUM + elif len(results) == 1: + # Only a single candidate. + rec = RECOMMEND_LOW elif results[1].distance - min_dist >= \ config['match']['rec_gap_thresh'].as_number(): # Gap between first two candidates is large. diff --git a/beets/config_default.yaml b/beets/config_default.yaml index 56f1a0055..84969a371 100644 --- a/beets/config_default.yaml +++ b/beets/config_default.yaml @@ -14,7 +14,7 @@ import: autotag: yes quiet: no singletons: no - confirm_partial: no + default_action: apply ignore: [".*", "*~"] replace: diff --git a/beets/ui/commands.py b/beets/ui/commands.py index 7b279fae6..15c689e91 100644 --- a/beets/ui/commands.py +++ b/beets/ui/commands.py @@ -323,8 +323,9 @@ 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. + require = rec in (autotag.RECOMMEND_NONE, autotag.RECOMMEND_LOW) + if not bypass_candidates: # Display list of candidates. if singleton: @@ -388,12 +389,10 @@ def choose_candidate(candidates, singleton, rec, cur_artist=None, elif sel == 'i': return importer.action.MANUAL_ID else: # Numerical selection. - if singleton: - match = candidates[sel - 1] - else: - match = candidates[sel - 1] - # Require selection (no default). + match = candidates[sel - 1] if sel != 1: + # When choosing anything but the first match, + # disable the default action. require = True bypass_candidates = False @@ -414,10 +413,15 @@ 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') - if config['import']['confirm_partial'].get(bool) and \ - match.extra_items or match.extra_tracks: - require = True - sel = ui.input_options(opts, require=require) + default = config['import']['default_action'].as_choice({ + 'apply': 'a', + 'skip': 's', + 'asis': 'u', + 'none': None, + }) + if default is None: + require = True + sel = ui.input_options(opts, require=require, default=default) if sel == 'a': return match elif sel == 'm': diff --git a/beets/util/confit.py b/beets/util/confit.py index a21455c42..7d65a4023 100644 --- a/beets/util/confit.py +++ b/beets/util/confit.py @@ -337,16 +337,22 @@ class ConfigView(object): def as_choice(self, choices): """Ensure that the value is among a collection of choices and - return it. + return it. If `choices` is a dictionary, then return the + corresponding value rather than the value itself (the key). """ value = self.get() + if value not in choices: raise ConfigValueError( '{0} must be one of {1}, not {2}'.format( self.name, repr(value), repr(list(choices)) ) ) - return value + + if isinstance(choices, dict): + return choices[value] + else: + return value def as_number(self): """Ensure that a value is of numeric type.""" diff --git a/docs/changelog.rst b/docs/changelog.rst index 2023501a9..eeeab8788 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -4,11 +4,26 @@ Changelog 1.1b2 (in development) ---------------------- +New configuration options: + +* :ref:`default_action` lets you determine the default (just-hit-return) option + is when considering a candidate. + +Other new stuff: + * Support for Windows Media/ASF audio files. Thanks to Dave Hayes. * Two new plugin events were added: *database_change* and *cli_exit*. Thanks to Dang Mai Hai. * Track titles in the importer's difference display are now broken across two lines for readability. Thanks to mrmachine. +* Some changes to the way candidates are recommended for selection, thanks to + mrmachine: + * Partial album matches are never "strong" recommendations. + * When a match isn't great but is either better than all the others or the + only match, it is given a "low" (rather than "medium") recommendation. + * There is no prompt default (i.e., input is required) when matches are + bad: "low" or "none" recommendations or when choosing a candidate + other than the first. 1.1b1 (January 29, 2013) ------------------------ diff --git a/docs/reference/config.rst b/docs/reference/config.rst index 02a5714f5..484781ea1 100644 --- a/docs/reference/config.rst +++ b/docs/reference/config.rst @@ -265,14 +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 -~~~~~~~~~~~~~~~ +.. _default_action: -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``. +default_action +~~~~~~~~~~~~~~ + +One of ``apply``, ``skip``, ``asis``, or ``none``, indicating which option +should be the *default* when selecting an action for a given match. This is the +action that will be taken when you type return without an option letter. The +default is ``apply``. .. _musicbrainz-config: