diff --git a/beets/autotag/__init__.py b/beets/autotag/__init__.py index 0ceb1dfab..74568b8f5 100644 --- a/beets/autotag/__init__.py +++ b/beets/autotag/__init__.py @@ -18,7 +18,7 @@ import os import logging import re -from beets import library, mediafile +from beets import library, mediafile, config from beets.util import sorted_walk, ancestry # Parts of external interface. @@ -115,7 +115,7 @@ def apply_item_metadata(item, track_info): # At the moment, the other metadata is left intact (including album # and track number). Perhaps these should be emptied? -def apply_metadata(album_info, mapping, per_disc_numbering=False): +def apply_metadata(album_info, mapping): """Set the items' metadata to match an AlbumInfo object using a mapping from Items to TrackInfo objects. If `per_disc_numbering`, then the track numbers are per-disc instead of per-release. @@ -148,7 +148,7 @@ def apply_metadata(album_info, mapping, per_disc_numbering=False): # Title. item.title = track_info.title - if per_disc_numbering: + if config['per_disc_numbering']: item.track = track_info.medium_index else: item.track = track_info.index diff --git a/beets/autotag/match.py b/beets/autotag/match.py index a0121f293..0708671c2 100644 --- a/beets/autotag/match.py +++ b/beets/autotag/match.py @@ -23,6 +23,7 @@ from munkres import Munkres from unidecode import unidecode from beets import plugins +from beets import config from beets.util import levenshtein, plurality from beets.autotag import hooks @@ -373,7 +374,7 @@ def _add_candidate(items, results, info): results[info.album_id] = hooks.AlbumMatch(dist, info, mapping, extra_items, extra_tracks) -def tag_album(items, timid=False, search_artist=None, search_album=None, +def tag_album(items, search_artist=None, search_album=None, search_id=None): """Bundles together the functionality used to infer tags for a set of items comprised by an album. Returns everything relevant: @@ -407,7 +408,7 @@ def tag_album(items, timid=False, search_artist=None, search_album=None, _add_candidate(items, candidates, id_info) rec = recommendation(candidates.values()) log.debug('Album ID match recommendation is ' + str(rec)) - if candidates and not timid: + 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. @@ -446,7 +447,7 @@ def tag_album(items, timid=False, search_artist=None, search_album=None, rec = recommendation(candidates) return cur_artist, cur_album, candidates, rec -def tag_item(item, timid=False, search_artist=None, search_title=None, +def tag_item(item, search_artist=None, search_title=None, search_id=None): """Attempts to find metadata for a single track. Returns a `(candidates, recommendation)` pair where `candidates` is a list of @@ -469,7 +470,7 @@ def tag_item(item, timid=False, search_artist=None, search_title=None, 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 timid: + if rec == RECOMMEND_STRONG and not config['import_timid'].get(bool): log.debug('Track ID match.') return candidates.values(), rec diff --git a/beets/config_default.yaml b/beets/config_default.yaml index 195139398..ebea06a4f 100644 --- a/beets/config_default.yaml +++ b/beets/config_default.yaml @@ -1,14 +1,20 @@ library: ~/.beetsmusic.blb directory: ~/Music -import_write: yes -import_copy: yes -import_move: no -import_resume: ask -import_incremental: yes -import_quiet_fallback: skip -import_timid: no -import_log: +import: + write: yes + copy: yes + move: no + resume: ask + incremental: no + quiet_fallback: skip + timid: no + log: + autotag: yes + quiet: no + + # Typically only set from the command line. + singletons: no ignore: [".*", "*~"] replace: diff --git a/beets/importer.py b/beets/importer.py index 8a8418656..17c15429d 100644 --- a/beets/importer.py +++ b/beets/importer.py @@ -26,6 +26,7 @@ from beets import autotag from beets import library from beets import plugins from beets import util +from beets import config from beets.util import pipeline from beets.util import syspath, normpath, displayable_path from beets.util.enumeration import enum @@ -451,13 +452,13 @@ class ImportTask(object): # Full-album pipeline stages. -def read_tasks(config): +def read_tasks(): """A generator yielding all the albums (as ImportTask objects) found in the user-specified list of paths. In the case of a singleton import, yields single-item tasks instead. """ # Look for saved progress. - progress = config.resume is not False + progress = config['import']['resume'] is not False # FIXME if progress: resume_dirs = {} for path in config.paths: @@ -465,7 +466,7 @@ def read_tasks(config): if resume_dir: # Either accept immediately or prompt for input to decide. - if config.resume: + if config['import']['resume']: do_resume = True log.warn('Resuming interrupted import of %s' % path) else: @@ -478,13 +479,14 @@ def read_tasks(config): progress_set(path, None) # Look for saved incremental directories. - if config.incremental: + if config['import']['incremental']: incremental_skipped = 0 history_dirs = history_get() for toppath in config.paths: # Check whether the path is to a file. - if config.singletons and not os.path.isdir(syspath(toppath)): + if config['import']['singletons'] and \ + not os.path.isdir(syspath(toppath)): item = library.Item.from_path(toppath) yield ImportTask.item_task(item) continue @@ -503,14 +505,14 @@ def read_tasks(config): continue # When incremental, skip paths in the history. - if config.incremental and path in history_dirs: + if config['import']['incremental'] and path in history_dirs: log.debug(u'Skipping previously-imported path: %s' % displayable_path(path)) incremental_skipped += 1 continue # Yield all the necessary tasks. - if config.singletons: + if config['import']['singletons']: for item in items: yield ImportTask.item_task(item) yield ImportTask.progress_sentinel(toppath, path) @@ -521,16 +523,16 @@ def read_tasks(config): yield ImportTask.done_sentinel(toppath) # Show skipped directories. - if config.incremental and incremental_skipped: + if config['import']['incremental'] and incremental_skipped: log.info(u'Incremental import: skipped %i directories.' % incremental_skipped) -def query_tasks(config): +def query_tasks(): """A generator that works as a drop-in-replacement for read_tasks. Instead of finding files from the filesystem, a query is used to match items from the library. """ - if config.singletons: + if config['import']['singletons']: # Search for items. for item in config.lib.items(config.query): yield ImportTask.item_task(item) @@ -543,7 +545,7 @@ def query_tasks(config): items = list(album.items()) yield ImportTask(None, album.item_dir(), items) -def initial_lookup(config): +def initial_lookup(): """A coroutine for performing the initial MusicBrainz lookup for an album. It accepts lists of Items and yields (items, cur_artist, cur_album, candidates, rec) tuples. If no match @@ -555,15 +557,16 @@ def initial_lookup(config): if task.sentinel: continue - plugins.send('import_task_start', task=task, config=config) + plugins.send('import_task_start', task=task) log.debug('Looking up: %s' % task.path) try: - task.set_candidates(*autotag.tag_album(task.items, config.timid)) + task.set_candidates(*autotag.tag_album(task.items, + config['import']['timid'])) except autotag.AutotagError: task.set_null_candidates() -def user_query(config): +def user_query(): """A coroutine for interfacing with the user about the tagging process. lib is the Library to import into and logfile may be a file-like object for logging the import process. The coroutine @@ -580,7 +583,7 @@ def user_query(config): choice = config.choose_match_func(task, config) task.set_choice(choice) log_choice(config, task) - plugins.send('import_task_choice', task=task, config=config) + plugins.send('import_task_choice', task=task) # As-tracks: transition to singleton workflow. if choice is action.TRACKS: @@ -594,8 +597,8 @@ def user_query(config): while True: item_task = yield item_tasks.append(item_task) - ipl = pipeline.Pipeline((emitter(), item_lookup(config), - item_query(config), collector())) + ipl = pipeline.Pipeline((emitter(), item_lookup(), + item_query(), collector())) ipl.run_sequential() task = pipeline.multiple(item_tasks) continue @@ -607,11 +610,11 @@ def user_query(config): # imported albums -- those that haven't reached the database # yet. if ident in recent or _duplicate_check(config.lib, task): - config.resolve_duplicate_func(task, config) + config.resolve_duplicate_func(task) log_choice(config, task, True) recent.add(ident) -def show_progress(config): +def show_progress(): """This stage replaces the initial_lookup and user_query stages when the importer is run without autotagging. It displays the album name and artist as the files are added. @@ -628,7 +631,7 @@ def show_progress(config): task.set_null_candidates() task.set_choice(action.ASIS) -def apply_choices(config): +def apply_choices(): """A coroutine for applying changes to albums and singletons during the autotag process. """ @@ -648,12 +651,11 @@ def apply_choices(config): if task.should_write_tags(): if task.is_album: autotag.apply_metadata( - task.match.info, task.match.mapping, - per_disc_numbering=config.per_disc_numbering + task.match.info, task.match.mapping ) else: autotag.apply_item_metadata(task.item, task.match.info) - plugins.send('import_task_apply', config=config, task=task) + plugins.send('import_task_apply', task=task) # Infer album-level fields. if task.is_album: @@ -715,7 +717,7 @@ def apply_choices(config): for item in items: config.lib.add(item) -def plugin_stage(config, func): +def plugin_stage(func): """A coroutine (pipeline stage) that calls the given function with each non-skipped import task. These stages occur between applying metadata changes and moving/copying/writing files. @@ -725,9 +727,9 @@ def plugin_stage(config, func): task = yield task if task.should_skip(): continue - func(config, task) + func(task) -def manipulate_files(config): +def manipulate_files(): """A coroutine (pipeline stage) that performs necessary file manipulations *after* items have been added to the library. """ @@ -741,12 +743,12 @@ def manipulate_files(config): items = task.imported_items() task.old_paths = [item.path for item in items] # For deletion. for item in items: - if config.move: + if config['import']['move']: # Just move the file. old_path = item.path config.lib.move(item, False) task.prune(old_path) - elif config.copy: + elif config['import']['copy']: # If it's a reimport, move in-library files and copy # out-of-library files. Otherwise, copy and keep track # of the old path. @@ -766,7 +768,7 @@ def manipulate_files(config): # old paths. config.lib.move(item, True) - if config.write and task.should_write_tags(): + if config['import']['write '] and task.should_write_tags(): item.write() # Save new paths. @@ -775,9 +777,9 @@ def manipulate_files(config): config.lib.store(item) # Plugin event. - plugins.send('import_task_files', config=config, task=task) + plugins.send('import_task_files', task=task) -def finalize(config): +def finalize(): """A coroutine that finishes up importer tasks. In particular, the coroutine sends plugin events, deletes old files, and saves progress. This is a "terminal" coroutine (it yields None). @@ -785,9 +787,9 @@ def finalize(config): while True: task = yield if task.should_skip(): - if config.resume is not False: + if config['import']['resume ']is not False: task.save_progress() - if config.incremental: + if config['import']['incremental']: task.save_history() continue @@ -797,14 +799,14 @@ def finalize(config): if task.is_album: album = config.lib.get_album(task.album_id) plugins.send('album_imported', - lib=config.lib, album=album, config=config) + lib=config.lib, album=album) else: for item in items: plugins.send('item_imported', - lib=config.lib, item=item, config=config) + lib=config.lib, item=item) # Finally, delete old files. - if config.copy and config.delete: + if config['import']['copy'] and config['import']['delete']: new_paths = [os.path.realpath(item.path) for item in items] for old_path in task.old_paths: # Only delete files that were actually copied. @@ -813,15 +815,15 @@ def finalize(config): task.prune(old_path) # Update progress. - if config.resume is not False: + if config['import']['resume'] is not False: task.save_progress() - if config.incremental: + if config['import']['incremental']: task.save_history() # Singleton pipeline stages. -def item_lookup(config): +def item_lookup(): """A coroutine used to perform the initial MusicBrainz lookup for an item task. """ @@ -831,11 +833,11 @@ def item_lookup(config): if task.sentinel: continue - plugins.send('import_task_start', task=task, config=config) + plugins.send('import_task_start', task=task) - task.set_item_candidates(*autotag.tag_item(task.item, config.timid)) + task.set_item_candidates(*autotag.tag_item(task.item)) -def item_query(config): +def item_query(): """A coroutine that queries the user for input on single-item lookups. """ @@ -846,20 +848,20 @@ def item_query(config): if task.sentinel: continue - choice = config.choose_item_func(task, config) + choice = config.choose_item_func(task) task.set_choice(choice) log_choice(config, task) - plugins.send('import_task_choice', task=task, config=config) + plugins.send('import_task_choice', task=task) # Duplicate check. if task.choice_flag in (action.ASIS, action.APPLY): ident = task.chosen_ident() if ident in recent or _item_duplicate_check(config.lib, task): - config.resolve_duplicate_func(task, config) + config.resolve_duplicate_func(task) log_choice(config, task, True) recent.add(ident) -def item_progress(config): +def item_progress(): """Skips the lookup and query stages in a non-autotagged singleton import. Just shows progress. """ @@ -877,41 +879,38 @@ def item_progress(config): # Main driver. -def run_import(**kwargs): - """Run an import. The keyword arguments are the same as those to - ImportConfig. +def run_import(): + """Run an import task. """ - config = ImportConfig(**kwargs) - # Set up the pipeline. if config.query is None: - stages = [read_tasks(config)] + stages = [read_tasks()] else: - stages = [query_tasks(config)] - if config.singletons: + stages = [query_tasks()] + if config['import']['singletons']: # Singleton importer. - if config.autot: - stages += [item_lookup(config), item_query(config)] + if config['import']['autotag']: + stages += [item_lookup(), item_query()] else: - stages += [item_progress(config)] + stages += [item_progress()] else: # Whole-album importer. - if config.autot: + if config['import']['autotag']: # Only look up and query the user when autotagging. - stages += [initial_lookup(config), user_query(config)] + stages += [initial_lookup(), user_query()] else: # When not autotagging, just display progress. - stages += [show_progress(config)] - stages += [apply_choices(config)] + stages += [show_progress()] + stages += [apply_choices()] for stage_func in plugins.import_stages(): - stages.append(plugin_stage(config, stage_func)) - stages += [manipulate_files(config)] - stages += [finalize(config)] + stages.append(plugin_stage(stage_func)) + stages += [manipulate_files()] + stages += [finalize()] pl = pipeline.Pipeline(stages) # Run the pipeline. try: - if config.threaded: + if config['threaded']: pl.run_parallel(QUEUE_SIZE) else: pl.run_sequential() diff --git a/beets/ui/__init__.py b/beets/ui/__init__.py index 0429ac058..17461994e 100644 --- a/beets/ui/__init__.py +++ b/beets/ui/__init__.py @@ -48,27 +48,10 @@ if sys.platform == 'win32': # Constants. -CONFIG_PATH_VAR = 'BEETSCONFIG' -DEFAULT_CONFIG_FILENAME_UNIX = '.beetsconfig' -DEFAULT_CONFIG_FILENAME_WINDOWS = 'beetsconfig.ini' -DEFAULT_LIBRARY_FILENAME_UNIX = '.beetsmusic.blb' -DEFAULT_LIBRARY_FILENAME_WINDOWS = 'beetsmusic.blb' -DEFAULT_DIRECTORY_NAME = 'Music' -WINDOWS_BASEDIR = os.environ.get('APPDATA') or '~' PF_KEY_QUERIES = { 'comp': 'comp:true', 'singleton': 'singleton:true', } -DEFAULT_PATH_FORMATS = [ - (library.PF_KEY_DEFAULT, - Template('$albumartist/$album%aunique{}/$track $title')), - (PF_KEY_QUERIES['singleton'], - Template('Non-Album/$artist/$title')), - (PF_KEY_QUERIES['comp'], - Template('Compilations/$album%aunique{}/$track $title')), -] -DEFAULT_ART_FILENAME = 'cover' -DEFAULT_TIMEOUT = 5.0 # UI exception. Commands should throw this in order to display # nonrecoverable errors to the user. @@ -134,7 +117,7 @@ def input_(prompt=None): return resp.decode(sys.stdin.encoding, 'ignore') def input_options(options, require=False, prompt=None, fallback_prompt=None, - numrange=None, default=None, color=False, max_width=72): + numrange=None, default=None, max_width=72): """Prompts a user for input. The sequence of `options` defines the choices the user has. A single-letter shortcut is inferred for each option; the user's choice is returned as that single, lower-case @@ -192,7 +175,7 @@ def input_options(options, require=False, prompt=None, fallback_prompt=None, is_default = False # Possibly colorize the letter shortcut. - if color: + if config['color'].get(bool): color = 'turquoise' if is_default else 'blue' show_letter = colorize(color, show_letter) diff --git a/beets/ui/commands.py b/beets/ui/commands.py index 09abe7d05..84da85c3d 100644 --- a/beets/ui/commands.py +++ b/beets/ui/commands.py @@ -100,35 +100,18 @@ default_commands.append(fields_cmd) # import: Autotagger and importer. -DEFAULT_IMPORT_COPY = True -DEFAULT_IMPORT_MOVE = False -DEFAULT_IMPORT_WRITE = True -DEFAULT_IMPORT_DELETE = False -DEFAULT_IMPORT_AUTOT = True -DEFAULT_IMPORT_TIMID = False -DEFAULT_IMPORT_QUIET = False -DEFAULT_IMPORT_QUIET_FALLBACK = 'skip' -DEFAULT_IMPORT_RESUME = None # "ask" -DEFAULT_IMPORT_INCREMENTAL = False -DEFAULT_THREADED = True -DEFAULT_COLOR = True -DEFAULT_IGNORE = [ - '.*', '*~', -] -DEFAULT_PER_DISC_NUMBERING = False - VARIOUS_ARTISTS = u'Various Artists' PARTIAL_MATCH_MESSAGE = u'(partial match!)' # Importer utilities and support. -def dist_string(dist, color): +def dist_string(dist): """Formats a distance (a float) as a similarity percentage string. The string is colorized if color is True. """ out = '%.1f%%' % ((1 - dist) * 100) - if color: + if config['color'].get(bool): if dist <= autotag.STRONG_REC_THRESH: out = ui.colorize('green', out) elif dist <= autotag.MEDIUM_REC_THRESH: @@ -137,8 +120,7 @@ def dist_string(dist, color): out = ui.colorize('red', out) return out -def show_change(cur_artist, cur_album, match, color=True, - per_disc_numbering=False): +def show_change(cur_artist, cur_album, match): """Print out a representation of the changes that will be made if an album's tags are changed according to `match`, which must be an AlbumMatch object. @@ -156,7 +138,7 @@ def show_change(cur_artist, cur_album, match, color=True, warning = PARTIAL_MATCH_MESSAGE else: warning = None - if color and warning: + if config['color'].get(bool) and warning: warning = ui.colorize('yellow', warning) out = album_description @@ -168,7 +150,7 @@ def show_change(cur_artist, cur_album, match, color=True, """Return a string representing the track index of the given TrackInfo object. """ - if per_disc_numbering: + if config['per_disc_numbering'].get(bool): if match.info.mediums > 1: return u'{0}-{1}'.format(track_info.medium, track_info.medium_index) @@ -187,7 +169,7 @@ def show_change(cur_artist, cur_album, match, color=True, # Hide artists for VA releases. artist_l, artist_r = u'', u'' - if color: + if config['color'].get(bool): artist_l, artist_r = ui.colordiff(artist_l, artist_r) album_l, album_r = ui.colordiff(album_l, album_r) @@ -199,13 +181,13 @@ def show_change(cur_artist, cur_album, match, color=True, message = u"Tagging: %s - %s" % (match.info.artist, match.info.album) if match.extra_items or match.extra_tracks: warning = PARTIAL_MATCH_MESSAGE - if color: + if config['color'].get(bool): warning = ui.colorize('yellow', PARTIAL_MATCH_MESSAGE) message += u' ' + warning print_(message) # Distance/similarity. - print_('(Similarity: %s)' % dist_string(match.distance, color)) + print_('(Similarity: %s)' % dist_string(match.distance)) # Tracks. pairs = match.mapping.items() @@ -221,12 +203,12 @@ def show_change(cur_artist, cur_album, match, color=True, if item.length and track_info.length: cur_length = ui.human_seconds_short(item.length) new_length = ui.human_seconds_short(track_info.length) - if color: + if config['color'].get(bool): cur_length = ui.colorize('red', cur_length) new_length = ui.colorize('red', new_length) # Possibly colorize changes. - if color: + if config['color'].get(bool): cur_title, new_title = ui.colordiff(cur_title, new_title) cur_track = ui.colorize('red', cur_track) new_track = ui.colorize('red', new_track) @@ -258,16 +240,16 @@ def show_change(cur_artist, cur_album, match, color=True, for track_info in match.extra_tracks: line = u' * Missing track: {0} ({1})'.format(track_info.title, format_index(track_info)) - if color: + if config['color'].get(bool): line = ui.colorize('yellow', line) print_(line) for item in match.extra_items: line = u' * Unmatched track: {0} ({1})'.format(item.title, item.track) - if color: + if config['color'].get(bool): line = ui.colorize('yellow', line) print_(line) -def show_item_change(item, match, color): +def show_item_change(item, match): """Print out the change that would occur by tagging `item` with the metadata from `match`, a TrackMatch object. """ @@ -275,7 +257,7 @@ def show_item_change(item, match, color): cur_title, new_title = item.title, match.info.title if cur_artist != new_artist or cur_title != new_title: - if color: + if config['color'].get(): cur_artist, new_artist = ui.colordiff(cur_artist, new_artist) cur_title, new_title = ui.colordiff(cur_title, new_title) @@ -287,7 +269,7 @@ def show_item_change(item, match, color): else: print_("Tagging track: %s - %s" % (cur_artist, cur_title)) - print_('(Similarity: %s)' % dist_string(match.distance, color)) + print_('(Similarity: %s)' % dist_string(match.distance)) def should_resume(config, path): return ui.input_yn("Import of the directory:\n%s" @@ -305,9 +287,8 @@ def _quiet_fall_back(config): assert(False) return config.quiet_fallback -def choose_candidate(candidates, singleton, rec, color, timid, - cur_artist=None, cur_album=None, item=None, - itemcount=None, per_disc_numbering=False): +def choose_candidate(candidates, singleton, rec, cur_artist=None, + cur_album=None, item=None, itemcount=None): """Given a sorted list of candidates, ask the user for a selection of which candidate to use. Applies to both full albums and singletons (tracks). Candidates are either AlbumMatch or TrackMatch @@ -338,7 +319,7 @@ def choose_candidate(candidates, singleton, rec, color, timid, 'https://github.com/sampsyo/beets/wiki/FAQ#wiki-nomatch') opts = ('Use as-is', 'as Tracks', 'Skip', 'Enter search', 'enter Id', 'aBort') - sel = ui.input_options(opts, color=color) + sel = ui.input_options(opts) if sel == 'u': return importer.action.ASIS elif sel == 't': @@ -372,7 +353,7 @@ def choose_candidate(candidates, singleton, rec, color, timid, for i, match in enumerate(candidates): print_('%i. %s - %s (%s)' % (i + 1, match.info.artist, match.info.title, - dist_string(match.distance, color))) + dist_string(match.distance))) else: print_('Finding tags for album "%s - %s".' % (cur_artist, cur_album)) @@ -394,12 +375,12 @@ def choose_candidate(candidates, singleton, rec, color, timid, elif year: line += u' [%s]' % year - line += ' (%s)' % dist_string(match.distance, color) + line += ' (%s)' % dist_string(match.distance) # Point out the partial matches. if match.extra_items or match.extra_tracks: warning = PARTIAL_MATCH_MESSAGE - if color: + if config['color'].get(bool): warning = ui.colorize('yellow', warning) line += u' %s' % warning @@ -412,8 +393,7 @@ def choose_candidate(candidates, singleton, rec, color, timid, else: opts = ('Skip', 'Use as-is', 'as Tracks', 'Enter search', 'enter Id', 'aBort') - sel = ui.input_options(opts, numrange=(1, len(candidates)), - color=color) + sel = ui.input_options(opts, numrange=(1, len(candidates))) if sel == 's': return importer.action.SKIP elif sel == 'u': @@ -436,13 +416,12 @@ def choose_candidate(candidates, singleton, rec, color, timid, # Show what we're about to do. if singleton: - show_item_change(item, match, color) + show_item_change(item, match) else: - show_change(cur_artist, cur_album, match, color, - per_disc_numbering) + 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 timid: + if rec == autotag.RECOMMEND_STRONG and not config['import']['timid']: return match # Ask for confirmation. @@ -452,7 +431,7 @@ def choose_candidate(candidates, singleton, rec, color, timid, else: opts = ('Apply', 'More candidates', 'Skip', 'Use as-is', 'as Tracks', 'Enter search', 'enter Id', 'aBort') - sel = ui.input_options(opts, color=color) + sel = ui.input_options(opts) if sel == 'a': return match elif sel == 'm': @@ -508,7 +487,7 @@ def choose_match(task, config): # No input; just make a decision. if task.rec == autotag.RECOMMEND_STRONG: match = task.candidates[0] - show_change(task.cur_artist, task.cur_album, match, config.color) + show_change(task.cur_artist, task.cur_album, match) return match else: return _quiet_fall_back(config) @@ -517,10 +496,8 @@ def choose_match(task, config): candidates, rec = task.candidates, task.rec while True: # Ask for a choice from the user. - choice = choose_candidate(candidates, False, rec, config.color, - config.timid, task.cur_artist, - task.cur_album, itemcount=len(task.items), - per_disc_numbering=config.per_disc_numbering) + choice = choose_candidate(candidates, False, rec, task.cur_artist, + task.cur_album, itemcount=len(task.items)) # Choose which tags to use. if choice in (importer.action.SKIP, importer.action.ASIS, @@ -532,8 +509,7 @@ def choose_match(task, config): search_artist, search_album = manual_search(False) try: _, _, candidates, rec = \ - autotag.tag_album(task.items, config.timid, search_artist, - search_album) + autotag.tag_album(task.items, search_artist, search_album) except autotag.AutotagError: candidates, rec = None, None elif choice is importer.action.MANUAL_ID: @@ -542,8 +518,7 @@ def choose_match(task, config): if search_id: try: _, _, candidates, rec = \ - autotag.tag_album(task.items, config.timid, - search_id=search_id) + autotag.tag_album(task.items, search_id=search_id) except autotag.AutotagError: candidates, rec = None, None else: @@ -564,15 +539,14 @@ def choose_item(task, config): # Quiet mode; make a decision. if rec == autotag.RECOMMEND_STRONG: match = candidates[0] - show_item_change(task.item, match, config.color) + show_item_change(task.item, match) return match else: return _quiet_fall_back(config) while True: # Ask for a choice. - choice = choose_candidate(candidates, True, rec, config.color, - config.timid, item=task.item) + choice = choose_candidate(candidates, True, rec, item=task.item) if choice in (importer.action.SKIP, importer.action.ASIS): return choice @@ -581,13 +555,13 @@ def choose_item(task, config): elif choice == importer.action.MANUAL: # Continue in the loop with a new set of candidates. search_artist, search_title = manual_search(True) - candidates, rec = autotag.tag_item(task.item, config.timid, - search_artist, search_title) + candidates, rec = autotag.tag_item(task.item, search_artist, + search_title) elif choice == importer.action.MANUAL_ID: # Ask for a track ID. search_id = manual_id(True) if search_id: - candidates, rec = autotag.tag_item(task.item, config.timid, + candidates, rec = autotag.tag_item(task.item, search_id=search_id) else: # Chose a candidate. @@ -607,8 +581,7 @@ def resolve_duplicate(task, config): sel = 's' else: sel = ui.input_options( - ('Skip new', 'Keep both', 'Remove old'), - color=config.color + ('Skip new', 'Keep both', 'Remove old') ) if sel == 's': @@ -1139,7 +1112,7 @@ def modify_func(lib, config, opts, args): if not mods: raise ui.UserError('no modifications specified') write = opts.write if opts.write is not None else \ - config['import_write'].get(bool) + config['import']['write'].get(bool) modify_items(lib, mods, query, write, opts.move, opts.album, not opts.yes) modify_cmd.func = modify_func default_commands.append(modify_cmd)