diff --git a/beetsplug/chroma.py b/beetsplug/chroma.py index 53cdf82b2..b128ebc25 100644 --- a/beetsplug/chroma.py +++ b/beetsplug/chroma.py @@ -163,7 +163,7 @@ class AcoustidPlugin(plugins.BeetsPlugin): # Hooks into import process. @AcoustidPlugin.listen('import_task_start') -def fingerprint_task(task): +def fingerprint_task(task, session): """Fingerprint each item in the task for later use during the autotagging candidate search. """ @@ -172,7 +172,7 @@ def fingerprint_task(task): acoustid_match(item.path) @AcoustidPlugin.listen('import_task_apply') -def apply_acoustid_metadata(task): +def apply_acoustid_metadata(task, session): """Apply Acoustid metadata (fingerprint and ID) to the task's items. """ for item in task.imported_items(): diff --git a/beetsplug/fuzzy_search.py b/beetsplug/fuzzy_search.py index 37a664ac7..3531a832c 100644 --- a/beetsplug/fuzzy_search.py +++ b/beetsplug/fuzzy_search.py @@ -14,12 +14,18 @@ """Like beet list, but with fuzzy matching """ -import beets from beets.plugins import BeetsPlugin from beets.ui import Subcommand, decargs, print_obj from beets.util.functemplate import Template +from beets import config import difflib +config.add({ + 'fuzzy': { + 'threshold': 0.7, + } +}) + # THRESHOLD = 0.7 @@ -42,7 +48,7 @@ def is_match(queryMatcher, item, album=False, verbose=False, threshold=0.7): return s >= threshold -def fuzzy_list(lib, config, opts, args): +def fuzzy_list(lib, opts, args): query = decargs(args) query = ' '.join(query).lower() queryMatcher = difflib.SequenceMatcher(b=query) @@ -50,7 +56,7 @@ def fuzzy_list(lib, config, opts, args): if opts.threshold is not None: threshold = float(opts.threshold) else: - threshold = float(conf['threshold']) + threshold = config['fuzzy']['threshold'].as_number() if opts.path: fmt = '$path' @@ -67,9 +73,10 @@ def fuzzy_list(lib, config, opts, args): threshold=threshold), objs) for item in items: - print_obj(item, lib, config, template) + print_obj(item, lib, template) if opts.verbose: - print(is_match(queryMatcher, i, album=opts.album, verbose=True)[1]) + print(is_match(queryMatcher, item, + album=opts.album, verbose=True)[1]) fuzzy_cmd = Subcommand('fuzzy', @@ -87,13 +94,7 @@ fuzzy_cmd.parser.add_option('-t', '--threshold', action='store', (default is 0.7)', default=None) fuzzy_cmd.func = fuzzy_list -conf = {} - class Fuzzy(BeetsPlugin): def commands(self): return [fuzzy_cmd] - - def configure(self, config): - conf['threshold'] = beets.ui.config_val(config, 'fuzzy', - 'threshold', 0.7) diff --git a/beetsplug/ihate.py b/beetsplug/ihate.py index eb427a825..a0231b8d0 100644 --- a/beetsplug/ihate.py +++ b/beetsplug/ihate.py @@ -17,7 +17,7 @@ import re import logging from beets.plugins import BeetsPlugin -from beets import ui +from beets import config from beets.importer import action @@ -25,6 +25,20 @@ __author__ = 'baobab@heresiarch.info' __version__ = '1.0' +config.add({ + 'ihate': { + 'warn_genre': [], + 'warn_artist': [], + 'warn_album': [], + 'warn_whitelist': [], + 'skip_genre': [], + 'skip_artist': [], + 'skip_album': [], + 'skip_whitelist': [], + } +}) + + class IHatePlugin(BeetsPlugin): _instance = None @@ -45,40 +59,6 @@ class IHatePlugin(BeetsPlugin): cls).__new__(cls, *args, **kwargs) return cls._instance - def __str__(self): - return ('(\n warn_genre = {0}\n' - ' warn_artist = {1}\n' - ' warn_album = {2}\n' - ' warn_whitelist = {3}\n' - ' skip_genre = {4}\n' - ' skip_artist = {5}\n' - ' skip_album = {6}\n' - ' skip_whitelist = {7} )\n' - .format(self.warn_genre, self.warn_artist, self.warn_album, - self.warn_whitelist, self.skip_genre, self.skip_artist, - self.skip_album, self.skip_whitelist)) - - def configure(self, config): - if not config.has_section('ihate'): - self._log.debug('[ihate] plugin is not configured') - return - self.warn_genre = ui.config_val(config, 'ihate', 'warn_genre', - '').split() - self.warn_artist = ui.config_val(config, 'ihate', 'warn_artist', - '').split() - self.warn_album = ui.config_val(config, 'ihate', 'warn_album', - '').split() - self.warn_whitelist = ui.config_val(config, 'ihate', 'warn_whitelist', - '').split() - self.skip_genre = ui.config_val(config, 'ihate', 'skip_genre', - '').split() - self.skip_artist = ui.config_val(config, 'ihate', 'skip_artist', - '').split() - self.skip_album = ui.config_val(config, 'ihate', 'skip_album', - '').split() - self.skip_whitelist = ui.config_val(config, 'ihate', 'skip_whitelist', - '').split() - @classmethod def match_patterns(cls, s, patterns): """Check if string is matching any of the patterns in the list.""" @@ -99,44 +79,51 @@ class IHatePlugin(BeetsPlugin): except: genre = u'' if genre and genre_patterns: - if IHatePlugin.match_patterns(genre, genre_patterns): + if cls.match_patterns(genre, genre_patterns): hate = True if not hate and task.cur_album and album_patterns: - if IHatePlugin.match_patterns(task.cur_album, album_patterns): + if cls.match_patterns(task.cur_album, album_patterns): hate = True if not hate and task.cur_artist and artist_patterns: - if IHatePlugin.match_patterns(task.cur_artist, artist_patterns): + if cls.match_patterns(task.cur_artist, artist_patterns): hate = True if hate and whitelist_patterns: - if IHatePlugin.match_patterns(task.cur_artist, whitelist_patterns): + if cls.match_patterns(task.cur_artist, whitelist_patterns): hate = False return hate def job_to_do(self): """Return True if at least one pattern is defined.""" - return any([self.warn_genre, self.warn_artist, self.warn_album, - self.skip_genre, self.skip_artist, self.skip_album]) + return any(config['ihate'][l].get(list) for l in + ('warn_genre', 'warn_artist', 'warn_album', + 'skip_genre', 'skip_artist', 'skip_album')) def import_task_choice_event(self, task, config): if task.choice_flag == action.APPLY: - if self.job_to_do: + if self.job_to_do(): self._log.debug('[ihate] processing your hate') - if self.do_i_hate_this(task, self.skip_genre, self.skip_artist, - self.skip_album, self.skip_whitelist): + if self.do_i_hate_this(task, + config['ihate']['skip_genre'].get(list), + config['ihate']['skip_artist'].get(list), + config['ihate']['skip_album'].get(list), + config['ihate']['skip_whitelist'].get(list)): task.choice_flag = action.SKIP self._log.info(u'[ihate] skipped: {0} - {1}' .format(task.cur_artist, task.cur_album)) return - if self.do_i_hate_this(task, self.warn_genre, self.warn_artist, - self.warn_album, self.warn_whitelist): + if self.do_i_hate_this(task, + config['ihate']['warn_genre'].get(list), + config['ihate']['warn_artist'].get(list), + config['ihate']['warn_album'].get(list), + config['ihate']['warn_whitelist'].get(list)): self._log.info(u'[ihate] you maybe hate this: {0} - {1}' .format(task.cur_artist, task.cur_album)) else: self._log.debug('[ihate] nothing to do') else: - self._log.debug('[ihate] user make a decision, nothing to do') + self._log.debug('[ihate] user made a decision, nothing to do') @IHatePlugin.listen('import_task_choice') -def ihate_import_task_choice(task, config): +def ihate_import_task_choice(task, session): IHatePlugin().import_task_choice_event(task, config) diff --git a/beetsplug/importfeeds.py b/beetsplug/importfeeds.py index 0f9b89a07..8c7429cdf 100644 --- a/beetsplug/importfeeds.py +++ b/beetsplug/importfeeds.py @@ -19,26 +19,30 @@ import datetime import os import re -from beets import ui from beets.plugins import BeetsPlugin from beets.util import normpath, syspath, bytestring_path +from beets import config M3U_DEFAULT_NAME = 'imported.m3u' -class ImportFeedsPlugin(BeetsPlugin): - def configure(self, config): - global _feeds_formats, _feeds_dir, _m3u_name +config.add({ + 'importfeeds': { + 'formats': [], + 'm3u_name': u'imported.m3u', + 'dir': None, + } +}) - _feeds_formats = ui.config_val(config, 'importfeeds', 'feeds_formats', - '').split() - _m3u_name = ui.config_val(config, 'importfeeds', 'm3u_name', - M3U_DEFAULT_NAME) - _feeds_dir = ui.config_val(config, 'importfeeds', 'feeds_dir', None) +class ImportFeedsPlugin(BeetsPlugin): + def __init__(self): + super(ImportFeedsPlugin, self).__init__() - if _feeds_dir: - _feeds_dir = os.path.expanduser(bytestring_path(_feeds_dir)) - if not os.path.exists(_feeds_dir): - os.makedirs(syspath(_feeds_dir)) + feeds_dir = config['importfeeds']['dir'].get() + if feeds_dir: + config['importfeeds']['dir'] = \ + os.path.expanduser(bytestring_path(feeds_dir)) + if not os.path.exists(syspath(feeds_dir)): + os.makedirs(syspath(feeds_dir)) def _get_feeds_dir(lib): """Given a Library object, return the path to the feeds directory to be @@ -59,7 +63,10 @@ def _build_m3u_filename(basename): basename = re.sub(r"[\s,'\"]", '_', basename) date = datetime.datetime.now().strftime("%Y%m%d_%Hh%M") - path = normpath(os.path.join(_feeds_dir, date+'_'+basename+'.m3u')) + path = normpath(os.path.join( + config['importfeeds']['dir'].as_filename(), + date + '_' + basename + '.m3u' + )) return path def _write_m3u(m3u_path, items_paths): @@ -72,35 +79,39 @@ def _write_m3u(m3u_path, items_paths): def _record_items(lib, basename, items): """Records relative paths to the given items for each feed format """ - + feedsdir = config['importfeeds']['dir'].as_filename() + formats = config['importfeeds']['formats'].get(list) + paths = [] for item in items: - paths.append(os.path.relpath(item.path, _feeds_dir)) + paths.append(os.path.relpath( + item.path, feedsdir + )) - if 'm3u' in _feeds_formats: - m3u_path = os.path.join(_feeds_dir, _m3u_name) + if 'm3u' in formats: + basename = config['importfeeds']['m3u_name'].get(unicode).encode('utf8') + m3u_path = os.path.join(feedsdir, basename) _write_m3u(m3u_path, paths) - if 'm3u_multi' in _feeds_formats: + if 'm3u_multi' in formats: m3u_path = _build_m3u_filename(basename) _write_m3u(m3u_path, paths) - if 'link' in _feeds_formats: + if 'link' in formats: for path in paths: - dest = os.path.join(_feeds_dir, os.path.basename(path)) + dest = os.path.join(feedsdir, os.path.basename(path)) if not os.path.exists(dest): os.symlink(path, dest) @ImportFeedsPlugin.listen('library_opened') def library_opened(lib): - global _feeds_dir - if not _feeds_dir: - _feeds_dir = _get_feeds_dir(lib) + if config['importfeeds']['dir'].get() is None: + config['importfeeds']['dir'] = _get_feeds_dir(lib) @ImportFeedsPlugin.listen('album_imported') -def album_imported(lib, album, config): +def album_imported(lib, album): _record_items(lib, album.album, album.items()) @ImportFeedsPlugin.listen('item_imported') -def item_imported(lib, item, config): +def item_imported(lib, item): _record_items(lib, item.title, [item]) diff --git a/beetsplug/info.py b/beetsplug/info.py index b9fe393e7..de4b4d651 100644 --- a/beetsplug/info.py +++ b/beetsplug/info.py @@ -58,7 +58,7 @@ def info(paths): class InfoPlugin(BeetsPlugin): def commands(self): cmd = ui.Subcommand('info', help='show file metadata') - def func(lib, config, opts, args): + def func(lib, opts, args): if not args: raise ui.UserError('no file specified') info(args) diff --git a/beetsplug/inline.py b/beetsplug/inline.py index d2f19bfda..b3d67fc43 100644 --- a/beetsplug/inline.py +++ b/beetsplug/inline.py @@ -18,6 +18,11 @@ import logging import traceback from beets.plugins import BeetsPlugin +from beets import config + +config.add({ + 'pathfields': [], +}) log = logging.getLogger('beets') @@ -54,13 +59,12 @@ def compile_expr(expr): class InlinePlugin(BeetsPlugin): template_fields = {} - def configure(self, config): - cls = type(self) + def __init__(self): + super(InlinePlugin, self).__init__() # Add field expressions. - if config.has_section('pathfields'): - for key, value in config.items('pathfields', True): - log.debug(u'adding template field %s' % key) - func = compile_expr(value) - if func is not None: - cls.template_fields[key] = func + for key, value in config['pathfields'].as_pairs(): + log.debug(u'adding template field %s' % key) + func = compile_expr(value) + if func is not None: + InlinePlugin.template_fields[key] = func diff --git a/beetsplug/lastgenre/__init__.py b/beetsplug/lastgenre/__init__.py index b915f815c..890e0f1ba 100644 --- a/beetsplug/lastgenre/__init__.py +++ b/beetsplug/lastgenre/__init__.py @@ -27,16 +27,24 @@ https://gist.github.com/1241307 import logging import pylast import os +import yaml from beets import plugins from beets import ui from beets.util import normpath -from beets.ui import commands +from beets import config + +config.add({ + 'lastgenre': { + 'whitelist': os.path.join(os.path.dirname(__file__), 'genres.txt'), + 'fallback': None, + 'canonical': None, + } +}) log = logging.getLogger('beets') LASTFM = pylast.LastFMNetwork(api_key=plugins.LASTFM_KEY) -DEFAULT_WHITELIST = os.path.join(os.path.dirname(__file__), 'genres.txt') C14N_TREE = os.path.join(os.path.dirname(__file__), 'genres-tree.yaml') PYLAST_EXCEPTIONS = ( @@ -125,23 +133,13 @@ options = { 'branches': None, 'c14n': False, } -fallback_str = None class LastGenrePlugin(plugins.BeetsPlugin): def __init__(self): super(LastGenrePlugin, self).__init__() self.import_stages = [self.imported] - def configure(self, config): - global fallback_str - - wl_filename = ui.config_val(config, 'lastgenre', 'whitelist', None) - if not wl_filename: - # No filename specified. Instead, use the whitelist that's included - # with the plugin (inside the package). - wl_filename = DEFAULT_WHITELIST - wl_filename = normpath(wl_filename) - # Read the whitelist file. + wl_filename = config['lastgenre']['whitelist'].as_filename() whitelist = set() with open(wl_filename) as f: for line in f: @@ -151,29 +149,25 @@ class LastGenrePlugin(plugins.BeetsPlugin): options['whitelist'] = whitelist # Read the genres tree for canonicalization if enabled. - c14n_filename = ui.config_val(config, 'lastgenre', 'canonical', None) + c14n_filename = config['lastgenre']['canonical'].get() if c14n_filename is not None: c14n_filename = c14n_filename.strip() if not c14n_filename: c14n_filename = C14N_TREE c14n_filename = normpath(c14n_filename) - from yaml import load - genres_tree = load(open(c14n_filename, 'r')) + genres_tree = yaml.load(open(c14n_filename, 'r')) branches = [] flatten_tree(genres_tree, [], branches) options['branches'] = branches options['c14n'] = True - fallback_str = ui.config_val(config, 'lastgenre', 'fallback_str', None) - def commands(self): lastgenre_cmd = ui.Subcommand('lastgenre', help='fetch genres') def lastgenre_func(lib, config, opts, args): # The "write to files" option corresponds to the # import_write config value. - write = ui.config_val(config, 'beets', 'import_write', - commands.DEFAULT_IMPORT_WRITE, bool) + write = config['import']['write'].get(bool) for album in lib.albums(ui.decargs(args)): tags = [] lastfm_obj = LASTFM.get_album(album.albumartist, album.album) @@ -183,6 +177,7 @@ class LastGenrePlugin(plugins.BeetsPlugin): tags.extend(_tags_for(lastfm_obj)) genre = _tags_to_genre(tags) + fallback_str = config['lastgenre']['fallback'].get() if not genre and fallback_str != None: genre = fallback_str log.debug(u'no last.fm genre found: fallback to %s' % genre) @@ -196,10 +191,10 @@ class LastGenrePlugin(plugins.BeetsPlugin): lastgenre_cmd.func = lastgenre_func return [lastgenre_cmd] - def imported(self, config, task): + def imported(self, session, task): tags = [] if task.is_album: - album = config.lib.get_album(task.album_id) + album = session.lib.get_album(task.album_id) lastfm_obj = LASTFM.get_album(album.albumartist, album.album) if album.genre: tags.append(album.genre) @@ -212,6 +207,7 @@ class LastGenrePlugin(plugins.BeetsPlugin): tags.extend(_tags_for(lastfm_obj)) genre = _tags_to_genre(tags) + fallback_str = config['lastgenre']['fallback'].get() if not genre and fallback_str != None: genre = fallback_str log.debug(u'no last.fm genre found: fallback to %s' % genre) @@ -220,8 +216,8 @@ class LastGenrePlugin(plugins.BeetsPlugin): log.debug(u'adding last.fm album genre: %s' % genre) if task.is_album: - album = config.lib.get_album(task.album_id) + album = session.lib.get_album(task.album_id) album.genre = genre else: item.genre = genre - config.lib.store(item) + session.lib.store(item) diff --git a/beetsplug/lyrics.py b/beetsplug/lyrics.py index eadb5d6b6..1fc7e1572 100644 --- a/beetsplug/lyrics.py +++ b/beetsplug/lyrics.py @@ -22,7 +22,13 @@ import logging from beets.plugins import BeetsPlugin from beets import ui -from beets.ui import commands +from beets import config + +config.add({ + 'lyrics': { + 'auto': True, + } +}) # Global logger. @@ -203,11 +209,10 @@ class LyricsPlugin(BeetsPlugin): cmd.parser.add_option('-p', '--print', dest='printlyr', action='store_true', default=False, help='print lyrics to console') - def func(lib, config, opts, args): + def func(lib, opts, args): # The "write to files" option corresponds to the # import_write config value. - write = ui.config_val(config, 'beets', 'import_write', - commands.DEFAULT_IMPORT_WRITE, bool) + write = config['import']['write'].get(bool) for item in lib.items(ui.decargs(args)): fetch_item_lyrics(lib, logging.INFO, item, write) if opts.printlyr and item.lyrics: @@ -215,12 +220,8 @@ class LyricsPlugin(BeetsPlugin): cmd.func = func return [cmd] - def configure(self, config): - global AUTOFETCH - AUTOFETCH = ui.config_val(config, 'lyrics', 'autofetch', True, bool) - # Auto-fetch lyrics on import. - def imported(self, config, task): - if AUTOFETCH: + def imported(self, session, task): + if config['lyrics']['auto']: for item in task.imported_items(): - fetch_item_lyrics(config.lib, logging.DEBUG, item, False) + fetch_item_lyrics(session.lib, logging.DEBUG, item, False) diff --git a/beetsplug/mbcollection.py b/beetsplug/mbcollection.py index a79e0242a..90e2d3578 100644 --- a/beetsplug/mbcollection.py +++ b/beetsplug/mbcollection.py @@ -17,6 +17,7 @@ from __future__ import print_function from beets.plugins import BeetsPlugin from beets.ui import Subcommand from beets import ui +from beets import config import musicbrainzngs from musicbrainzngs import musicbrainz @@ -35,7 +36,7 @@ def submit_albums(collection_id, release_ids): # A non-empty request body is required to avoid a 411 "Length # Required" error from the MB server. -def update_collection(lib, config, opts, args): +def update_collection(lib, opts, args): # Get the collection to modify. collections = musicbrainz._mb_request('collection', 'GET', True, True) if not collections['collection-list']: @@ -55,10 +56,12 @@ update_mb_collection_cmd = Subcommand('mbupdate', update_mb_collection_cmd.func = update_collection class MusicBrainzCollectionPlugin(BeetsPlugin): - def configure(self, config): - username = ui.config_val(config, 'musicbrainz', 'user', '') - password = ui.config_val(config, 'musicbrainz', 'pass', '') - musicbrainzngs.auth(username, password) + def __init__(self): + super(MusicBrainzCollectionPlugin, self).__init__() + musicbrainzngs.auth( + config['musicbrainz']['user'].get(unicode), + config['musicbrainz']['pass'].get(unicode) + ) def commands(self): return [update_mb_collection_cmd] diff --git a/beetsplug/mpdupdate.py b/beetsplug/mpdupdate.py index ab00373e0..95d828596 100644 --- a/beetsplug/mpdupdate.py +++ b/beetsplug/mpdupdate.py @@ -23,8 +23,16 @@ Put something like the following in your .beetsconfig to configure: from __future__ import print_function from beets.plugins import BeetsPlugin -from beets import ui import socket +from beets import config + +config.add({ + 'mpdupdate': { + 'host': u'localhost', + 'port': 6600, + 'password': u'', + } +}) # No need to introduce a dependency on an MPD library for such a # simple use case. Here's a simple socket abstraction to make things @@ -88,20 +96,13 @@ def update_mpd(host='localhost', port=6600, password=None): s.close() print('... updated.') -options = { - 'host': 'localhost', - 'port': 6600, - 'password': None, -} class MPDUpdatePlugin(BeetsPlugin): - def configure(self, config): - options['host'] = \ - ui.config_val(config, 'mpdupdate', 'host', 'localhost') - options['port'] = \ - int(ui.config_val(config, 'mpdupdate', 'port', '6600')) - options['password'] = \ - ui.config_val(config, 'mpdupdate', 'password', '') + pass @MPDUpdatePlugin.listen('import') def update(lib=None, paths=None): - update_mpd(options['host'], options['port'], options['password']) + update_mpd( + config['mpdupdate']['host'].get(unicode), + config['mpdupdate']['port'].get(int), + config['mpdupdate']['password'].get(unicode), + ) diff --git a/beetsplug/rdm.py b/beetsplug/rdm.py index 6eebba0bd..98e008232 100644 --- a/beetsplug/rdm.py +++ b/beetsplug/rdm.py @@ -19,7 +19,7 @@ from beets.ui import Subcommand, decargs, print_obj from beets.util.functemplate import Template import random -def random_item(lib, config, opts, args): +def random_item(lib, opts, args): query = decargs(args) if opts.path: fmt = '$path' @@ -35,7 +35,7 @@ def random_item(lib, config, opts, args): objs = random.sample(objs, number) for item in objs: - print_obj(item, lib, config, template) + print_obj(item, lib, template) random_cmd = Subcommand('random', help='chose a random track or album') diff --git a/beetsplug/replaygain.py b/beetsplug/replaygain.py index c84226b4c..2625ec42d 100644 --- a/beetsplug/replaygain.py +++ b/beetsplug/replaygain.py @@ -19,11 +19,22 @@ import os from beets import ui from beets.plugins import BeetsPlugin from beets.util import syspath, command_output -from beets.ui import commands +from beets import config + +config.add({ + 'replaygain': { + 'overwrite': False, + 'albumgain': False, + 'noclip': True, + 'apply_gain': False, + 'targetlevel': 89, + 'auto': True, + 'command': u'', + } +}) log = logging.getLogger('beets') -DEFAULT_REFERENCE_LOUDNESS = 89 SAMPLE_MAX = 1 << 15 class ReplayGainError(Exception): @@ -68,23 +79,15 @@ class ReplayGainPlugin(BeetsPlugin): super(ReplayGainPlugin, self).__init__() self.import_stages = [self.imported] - def configure(self, config): - self.overwrite = ui.config_val(config, 'replaygain', - 'overwrite', False, bool) - self.albumgain = ui.config_val(config, 'replaygain', - 'albumgain', False, bool) - self.noclip = ui.config_val(config, 'replaygain', - 'noclip', True, bool) - self.apply_gain = ui.config_val(config, 'replaygain', - 'apply_gain', False, bool) - target_level = float(ui.config_val(config, 'replaygain', - 'targetlevel', - DEFAULT_REFERENCE_LOUDNESS)) - self.gain_offset = int(target_level - DEFAULT_REFERENCE_LOUDNESS) - self.automatic = ui.config_val(config, 'replaygain', - 'automatic', True, bool) + self.overwrite = config['replaygain']['overwrite'].get(bool) + self.albumgain = config['replaygain']['albumgain'].get(bool) + self.noclip = config['replaygain']['noclip'].get(bool) + self.apply_gain = config['replaygain']['apply_gain'].get(bool) + target_level = config['replaygain']['targetlevel'].as_number() + self.gain_offset = int(target_level - 89) + self.automatic = config['replaygain']['auto'].get(bool) + self.command = config['replaygain']['command'].get(unicode) - self.command = ui.config_val(config,'replaygain','command', None) if self.command: # Explicit executable path. if not os.path.isfile(self.command): @@ -106,27 +109,26 @@ class ReplayGainPlugin(BeetsPlugin): 'no replaygain command found: install mp3gain or aacgain' ) - def imported(self, config, task): + def imported(self, session, task): """Our import stage function.""" if not self.automatic: return if task.is_album: - album = config.lib.get_album(task.album_id) + album = session.lib.get_album(task.album_id) items = list(album.items()) else: items = [task.item] results = self.compute_rgain(items, task.is_album) if results: - self.store_gain(config.lib, items, results, + self.store_gain(session.lib, items, results, album if task.is_album else None) def commands(self): """Provide a ReplayGain command.""" - def func(lib, config, opts, args): - write = ui.config_val(config, 'beets', 'import_write', - commands.DEFAULT_IMPORT_WRITE, bool) + def func(lib, opts, args): + write = config['import']['write'].get(bool) if opts.album: # Analyze albums. diff --git a/beetsplug/rewrite.py b/beetsplug/rewrite.py index 3cbc8bc64..9bbce86dc 100644 --- a/beetsplug/rewrite.py +++ b/beetsplug/rewrite.py @@ -22,6 +22,11 @@ from collections import defaultdict from beets.plugins import BeetsPlugin from beets import ui from beets import library +from beets import config + +config.add({ + 'rewrite': {}, +}) log = logging.getLogger('beets') @@ -41,16 +46,13 @@ def rewriter(field, rules): return fieldfunc class RewritePlugin(BeetsPlugin): - template_fields = {} - - def configure(self, config): - cls = type(self) + def __init__(self): + super(BeetsPlugin, self).__init__() + BeetsPlugin.template_fields = {} # Gather all the rewrite rules for each field. rules = defaultdict(list) - if not config.has_section('rewrite'): - return - for key, value in config.items('rewrite', True): + for key, value in config['rewrite'].items(): try: fieldname, pattern = key.split(None, 1) except ValueError: @@ -68,4 +70,5 @@ class RewritePlugin(BeetsPlugin): # Replace each template field with the new rewriter function. for fieldname, fieldrules in rules.iteritems(): - cls.template_fields[fieldname] = rewriter(fieldname, fieldrules) + RewritePlugin.template_fields[fieldname] = \ + rewriter(fieldname, fieldrules) diff --git a/beetsplug/scrub.py b/beetsplug/scrub.py index 5fd495c20..70f639631 100644 --- a/beetsplug/scrub.py +++ b/beetsplug/scrub.py @@ -20,10 +20,16 @@ import logging from beets.plugins import BeetsPlugin from beets import ui from beets import util +from beets import config + +config.add({ + 'scrub': { + 'auto': True, + } +}) log = logging.getLogger('beets') -AUTOSCRUB_KEY = 'autoscrub' _MUTAGEN_FORMATS = { 'asf': 'ASF', 'apev2': 'APEv2File', @@ -42,17 +48,10 @@ _MUTAGEN_FORMATS = { scrubbing = False -options = { - AUTOSCRUB_KEY: True, -} class ScrubPlugin(BeetsPlugin): """Removes extraneous metadata from files' tags.""" - def configure(self, config): - options[AUTOSCRUB_KEY] = \ - ui.config_val(config, 'scrub', AUTOSCRUB_KEY, True, bool) - def commands(self): - def scrub_func(lib, config, opts, args): + def scrub_func(lib, opts, args): # This is a little bit hacky, but we set a global flag to # avoid autoscrubbing when we're also explicitly scrubbing. global scrubbing @@ -107,6 +106,6 @@ def _scrub(path): # Automatically embed art into imported albums. @ScrubPlugin.listen('write') def write_item(item): - if not scrubbing and options[AUTOSCRUB_KEY]: + if not scrubbing and config['scrub']['auto']: log.debug(u'auto-scrubbing %s' % util.displayable_path(item.path)) _scrub(item.path) diff --git a/beetsplug/the.py b/beetsplug/the.py index da9450f7e..d26692f7c 100644 --- a/beetsplug/the.py +++ b/beetsplug/the.py @@ -17,7 +17,17 @@ import re import logging from beets.plugins import BeetsPlugin -from beets import ui +from beets import config + +config.add({ + 'the': { + 'the': True, + 'a': True, + 'format': u'{0}, {1}', + 'strip': False, + 'patterns': [], + } +}) __author__ = 'baobab@heresiarch.info' @@ -44,21 +54,10 @@ class ThePlugin(BeetsPlugin): cls).__new__(cls, *args, **kwargs) return cls._instance - def __str__(self): - return ('[the]\n the = {0}\n a = {1}\n format = {2}\n' - ' strip = {3}\n patterns = {4}' - .format(self.the, self.a, self.format, self.strip, - self.patterns)) + def __init__(self): + super(ThePlugin, self).__init__() - def configure(self, config): - if not config.has_section('the'): - self._log.debug(u'[the] plugin is not configured, using defaults') - return - self.the = ui.config_val(config, 'the', 'the', True, bool) - self.a = ui.config_val(config, 'the', 'a', True, bool) - self.format = ui.config_val(config, 'the', 'format', FORMAT) - self.strip = ui.config_val(config, 'the', 'strip', False, bool) - self.patterns = ui.config_val(config, 'the', 'patterns', '').split() + self.patterns = config['the']['patterns'].get(list) for p in self.patterns: if p: try: @@ -69,9 +68,9 @@ class ThePlugin(BeetsPlugin): if not (p.startswith('^') or p.endswith('$')): self._log.warn(u'[the] warning: \"{0}\" will not ' 'match string start/end'.format(p)) - if self.a: + if config['the']['a']: self.patterns = [PATTERN_A] + self.patterns - if self.the: + if config['the']['the']: self.patterns = [PATTERN_THE] + self.patterns if not self.patterns: self._log.warn(u'[the] no patterns defined!') @@ -93,10 +92,11 @@ class ThePlugin(BeetsPlugin): return text else: r = re.sub(r, '', text).strip() - if self.strip: + if config['the']['strip']: return r else: - return self.format.format(r, t.strip()).strip() + fmt = config['the']['format'].get(unicode) + return fmt.format(r, t.strip()).strip() else: return u'' diff --git a/beetsplug/web/__init__.py b/beetsplug/web/__init__.py index 33074b212..58fe2191a 100644 --- a/beetsplug/web/__init__.py +++ b/beetsplug/web/__init__.py @@ -16,13 +16,18 @@ from beets.plugins import BeetsPlugin from beets import ui from beets import util +from beets import config import beets.library import flask from flask import g import os -DEFAULT_HOST = '' -DEFAULT_PORT = 8337 +config.add({ + 'web': { + 'host': u'', + 'port': 8337, + } +}) # Utilities. @@ -126,14 +131,15 @@ class WebPlugin(BeetsPlugin): cmd = ui.Subcommand('web', help='start a Web interface') cmd.parser.add_option('-d', '--debug', action='store_true', default=False, help='debug mode') - def func(lib, config, opts, args): - host = args.pop(0) if args else \ - beets.ui.config_val(config, 'web', 'host', DEFAULT_HOST) - port = args.pop(0) if args else \ - beets.ui.config_val(config, 'web', 'port', str(DEFAULT_PORT)) - port = int(port) + def func(lib, opts, args): + if args: + config['web']['host'] = args.pop(0) + if args: + config['web']['port'] = int(args.pop(0)) app.config['lib'] = lib - app.run(host=host, port=port, debug=opts.debug, threaded=True) + app.run(host=config['web']['host'].get(unicode), + port=config['web']['port'].get(int), + debug=opts.debug, threaded=True) cmd.func = func return [cmd] diff --git a/beetsplug/zero.py b/beetsplug/zero.py index 9c22b6d2d..e3d00f0de 100644 --- a/beetsplug/zero.py +++ b/beetsplug/zero.py @@ -17,9 +17,16 @@ import re import logging from beets.plugins import BeetsPlugin -from beets import ui from beets.library import ITEM_KEYS from beets.importer import action +from beets import config +from beets.util import confit + +config.add({ + 'zero': { + 'fields': [], + } +}) __author__ = 'baobab@heresiarch.info' @@ -31,36 +38,30 @@ class ZeroPlugin(BeetsPlugin): _instance = None _log = logging.getLogger('beets') - fields = [] - patterns = {} - warned = False - def __new__(cls, *args, **kwargs): if cls._instance is None: cls._instance = super(ZeroPlugin, cls).__new__(cls, *args, **kwargs) return cls._instance - def __str__(self): - return ('[zero]\n fields = {0}\n patterns = {1}\n warned = {2}' - .format(self.fields, self.patterns, self.warned)) + def __init__(self): + super(ZeroPlugin, self).__init__() - def configure(self, config): - if not config.has_section('zero'): - self._log.debug('[zero] plugin is not configured') - return - for f in ui.config_val(config, 'zero', 'fields', '').split(): + self.fields = [] + self.patterns = {} + self.warned = False + + for f in config['zero']['fields'].get(list): if f not in ITEM_KEYS: self._log.error('[zero] invalid field: {0}'.format(f)) else: self.fields.append(f) - p = ui.config_val(config, 'zero', f, '').split() - if p: - self.patterns[f] = p - else: - self.patterns[f] = ['.'] + try: + self.patterns[f] = config['zero'][f].get(list) + except confit.NotFoundError: + self.patterns[f] = [u''] - def import_task_choice_event(self, task, config): + def import_task_choice_event(self, task): """Listen for import_task_choice event.""" if task.choice_flag == action.ASIS and not self.warned: self._log.warn('[zero] cannot zero in \"as-is\" mode') @@ -73,7 +74,7 @@ class ZeroPlugin(BeetsPlugin): the list. """ for p in patterns: - if re.findall(p, unicode(field), flags=re.IGNORECASE): + if re.search(p, unicode(field), flags=re.IGNORECASE): return True return False @@ -100,8 +101,8 @@ class ZeroPlugin(BeetsPlugin): @ZeroPlugin.listen('import_task_choice') -def zero_choice(task, config): - ZeroPlugin().import_task_choice_event(task, config) +def zero_choice(session, task): + ZeroPlugin().import_task_choice_event(task) @ZeroPlugin.listen('write') def zero_write(item):