finish confit-ifying all the plugins

This commit is contained in:
Adrian Sampson 2012-12-13 17:14:19 -08:00
parent 6c94358b13
commit 3ef9e006f4
17 changed files with 259 additions and 244 deletions

View file

@ -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():

View file

@ -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)

View file

@ -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)

View file

@ -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])

View file

@ -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)

View file

@ -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

View file

@ -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)

View file

@ -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)

View file

@ -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]

View file

@ -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),
)

View file

@ -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')

View file

@ -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.

View file

@ -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)

View file

@ -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)

View file

@ -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''

View file

@ -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]

View file

@ -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):