mpdupdate plugin (and config system for plugins)

This commit is contained in:
Adrian Sampson 2010-09-21 10:40:39 -07:00
parent 8c159fa2f0
commit ed89394368
4 changed files with 124 additions and 3 deletions

6
NEWS
View file

@ -7,13 +7,17 @@
plugin to work; documentation is forthcoming.)
* To support the above, there's also a new system for extending the
autotagger via plugins. Plugins can currently add components to the
track distance function.
track and album distance functions as well as augment the MusicBrainz
search.
* New event system for plugins (thanks, Jeff!). Plugins can now get
callbacks from beets when certain events occur in the core.
* The BPD plugin is now disabled by default. This greatly simplifies
installation of the beets core, which has no compiled dependencies
now. To use BPD, though, you'll need to set "plugins: bpd" in your
.beetsconfig.
* There's a new "mpdupdate" plugin that will automatically update your
MPD index whenever your beets library changes. Documentation on this
is forthcoming as well.
* Fixed bug that completely broke non-autotagged imports ("import -A").
* Fixed bug that logged the wrong paths when using "import -l".
* A new "-v" command line switch enables debugging output.

View file

@ -57,6 +57,12 @@ class BeetsPlugin(object):
"""
return ()
def configure(self, config):
"""This method is called with the ConfigParser object after
the CLI starts up.
"""
pass
listeners = None
@classmethod
def listen(cls, event):
@ -117,7 +123,7 @@ def find_plugins():
return plugins
# Plugin commands.
# Communication with plugins.
def commands():
"""Returns a list of Subcommand objects from all loaded plugins.
@ -157,6 +163,11 @@ def candidates(items):
out.extend(plugin.candidates(items))
return out
def configure(config):
"""Sends the configuration object to each plugin."""
for plugin in find_plugins():
plugin.configure(config)
# Event dispatch.

View file

@ -408,6 +408,7 @@ def main():
plugins.load_plugins(plugnames.split())
plugins.load_listeners()
plugins.send("pluginload")
plugins.configure(config)
# Construct the root parser.
commands = list(default_commands)
@ -452,4 +453,3 @@ def main():
except UserError, exc:
message = exc.args[0] if exc.args else None
subcommand.parser.error(message)

106
beetsplug/mpdupdate.py Normal file
View file

@ -0,0 +1,106 @@
# This file is part of beets.
# Copyright 2010, Adrian Sampson.
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
"""Updates an MPD index whenever the library is changed.
Put something like the following in your .beetsconfig to configure:
[mpdupdate]
host = localhost
port = 6600
password = seekrit
"""
from beets.plugins import BeetsPlugin
from beets import ui
import socket
# 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
# easier.
class BufferedSocket(object):
"""Socket abstraction that allows reading by line."""
def __init__(self, sep='\n'):
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.buf = ''
self.sep = sep
def connect(self, host, port):
self.sock.connect((host, port))
def readline(self):
while self.sep not in self.buf:
data = self.sock.recv(1024)
if not data:
break
self.buf += data
if '\n' in self.buf:
res, self.buf = self.buf.split(self.sep, 1)
return res + self.sep
else:
return ''
def send(self, data):
self.sock.send(data)
def close(self):
self.sock.close()
def update_mpd(host='localhost', port=6600, password=None):
"""Sends the "update" command to the MPD server indicated,
possibly authenticating with a password first.
"""
print 'Updating MPD database...'
s = BufferedSocket()
s.connect(host, port)
resp = s.readline()
if 'OK MPD' not in resp:
print 'MPD connection failed:', repr(resp)
return
if password:
s.send('password "%s"\n' % password)
resp = s.readline()
if 'OK' not in resp:
print 'Authentication failed:', repr(resp)
s.send('close\n')
s.close()
return
s.send('update\n')
resp = s.readline()
if 'updating_db' not in resp:
print 'Update failed:', repr(resp)
s.send('close\n')
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', '')
@MPDUpdatePlugin.listen('save')
def update(lib=None):
update_mpd(options['host'], options['port'], options['password'])