From 8ccc8e1ccd2831756990e4fc700af7461a2493d1 Mon Sep 17 00:00:00 2001 From: Adrian Sampson Date: Thu, 8 Jul 2010 17:09:07 -0700 Subject: [PATCH] move bpd and dadd commands to plugins --HG-- rename : beets/player/bpd.py => beetsplug/bpd/__init__.py rename : beets/player/gstplayer.py => beetsplug/bpd/gstplayer.py rename : beets/device.py => beetsplug/device.py --- beets/player/__init__.py | 0 beets/plugins.py | 10 ++- beets/ui/__init__.py | 24 +++---- beets/ui/commands.py | 63 ------------------- .../bpd.py => beetsplug/bpd/__init__.py | 55 ++++++++++++++-- {beets/player => beetsplug/bpd}/gstplayer.py | 0 {beets => beetsplug}/device.py | 22 +++++++ 7 files changed, 89 insertions(+), 85 deletions(-) delete mode 100644 beets/player/__init__.py rename beets/player/bpd.py => beetsplug/bpd/__init__.py (95%) rename {beets/player => beetsplug/bpd}/gstplayer.py (100%) rename {beets => beetsplug}/device.py (83%) diff --git a/beets/player/__init__.py b/beets/player/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/beets/plugins.py b/beets/plugins.py index ebed3b271..3a7049c10 100644 --- a/beets/plugins.py +++ b/beets/plugins.py @@ -21,7 +21,7 @@ import itertools log = logging.getLogger('beets') PLUGIN_NAMESPACE = 'beetsplug' -DEFAULT_PLUGINS = [] +DEFAULT_PLUGINS = ['bpd'] class BeetsPlugin(object): """The base class for all beets plugins. Plugins provide @@ -45,8 +45,12 @@ def load_plugins(names=()): modname = '%s.%s' % (PLUGIN_NAMESPACE, name) try: __import__(modname, None, None) - except: - log.warn('plugin %s not found' % name) + except ImportError, exc: + # Again, this is hacky: + if exc.args[0].endswith(modname): + log.warn('plugin %s not found' % name) + else: + raise _instances = {} def find_plugins(): diff --git a/beets/ui/__init__.py b/beets/ui/__init__.py index 50d34ea73..29546c79a 100644 --- a/beets/ui/__init__.py +++ b/beets/ui/__init__.py @@ -350,8 +350,6 @@ def main(): help="destination music directory") parser.add_option('-p', '--pathformat', dest='path_format', help="destination path format string") - parser.add_option('-i', '--device', dest='device', - help="name of the device library to use") # Parse the command-line! options, subcommand, suboptions, subargs = parser.parse_args() @@ -361,19 +359,15 @@ def main(): config.read(CONFIG_FILE) # Open library file. - if options.device: - from beets.device import PodLibrary - lib = PodLibrary.by_name(self.options.device) - else: - libpath = options.libpath or \ - config_val(config, 'beets', 'library', DEFAULT_LIBRARY) - directory = options.directory or \ - config_val(config, 'beets', 'directory', DEFAULT_DIRECTORY) - path_format = options.path_format or \ - config_val(config, 'beets', 'path_format', DEFAULT_PATH_FORMAT) - lib = library.Library(os.path.expanduser(libpath), - directory, - path_format) + libpath = options.libpath or \ + config_val(config, 'beets', 'library', DEFAULT_LIBRARY) + directory = options.directory or \ + config_val(config, 'beets', 'directory', DEFAULT_DIRECTORY) + path_format = options.path_format or \ + config_val(config, 'beets', 'path_format', DEFAULT_PATH_FORMAT) + lib = library.Library(os.path.expanduser(libpath), + directory, + path_format) # Invoke the subcommand. try: diff --git a/beets/ui/commands.py b/beets/ui/commands.py index 7962479e5..51ab3dc79 100644 --- a/beets/ui/commands.py +++ b/beets/ui/commands.py @@ -403,69 +403,6 @@ remove_cmd.func = remove_func default_commands.append(remove_cmd) -# bpd: Run the built-in MPD-like music player. - -DEFAULT_BPD_HOST = '' -DEFAULT_BPD_PORT = '6600' -DEFAULT_BPD_PASSWORD = '' - -def start_bpd(lib, host, port, password, debug): - """Starts a BPD server.""" - log = logging.getLogger('beets.player.bpd') - if debug: - log.setLevel(logging.DEBUG) - else: - log.setLevel(logging.WARNING) - try: - bpd.Server(lib, host, port, password).run() - except bpd.NoGstreamerError: - print_('Gstreamer Python bindings not found.') - print_('Install "python-gst0.10", "py26-gst-python", or similar ' \ - 'package to use BPD.') - return - -bpd_cmd = ui.Subcommand('bpd', - help='run an MPD-compatible music player server') -bpd_cmd.parser.add_option('-d', '--debug', action='store_true', - help='dump all MPD traffic to stdout') -def bpd_func(lib, config, opts, args): - host = args.pop(0) if args else ui.config_val(config, 'bpd', 'host', - DEFAULT_BPD_HOST) - port = args.pop(0) if args else ui.config_val(config, 'bpd', 'port', - DEFAULT_BPD_PORT) - if args: - raise ui.UserError('too many arguments') - password = ui.config_val(config, 'bpd', 'password', DEFAULT_BPD_PASSWORD) - debug = opts.debug or False - start_bpd(lib, host, int(port), password, debug) -bpd_cmd.func = bpd_func -default_commands.append(bpd_cmd) - - -# dadd: Add to device. - -def device_add(lib, query, name): - """Add items matching query from lib to a device with the given - name. - """ - items = lib.items(query=query) - - from beets import device - pod = device.PodLibrary.by_name(name) - for item in items: - pod.add(item) - pod.save() - -dadd_cmd = ui.Subcommand('dadd', help='add files to a device') -def dadd_func(lib, config, opts, args): - if not args: - raise ui.UserError('no device name specified') - name = args.pop(0) - device_add(lib, ui.make_query(args), name) -dadd_cmd.func = dadd_func -default_commands.append(dadd_cmd) - - # stats: Show library/query statistics. def show_stats(lib, query): diff --git a/beets/player/bpd.py b/beetsplug/bpd/__init__.py similarity index 95% rename from beets/player/bpd.py rename to beetsplug/bpd/__init__.py index c67fec916..4b7c5a986 100755 --- a/beets/player/bpd.py +++ b/beetsplug/bpd/__init__.py @@ -20,13 +20,18 @@ use of the wide range of MPD clients. import eventlet import re from string import Template -import beets import traceback import logging import time +import beets +from beets.plugins import BeetsPlugin +import beets.ui + DEFAULT_PORT = 6600 +DEFAULT_HOST = '' +DEFAULT_PASSWORD = '' PROTOCOL_VERSION = '0.13.0' BUFSIZE = 1024 @@ -66,7 +71,7 @@ SAFE_COMMANDS = ( log = logging.getLogger('beets.player.bpd') -# Gstreamer import error (counterpart of identical class in gstplayer). +# Gstreamer import error. class NoGstreamerError(Exception): pass @@ -202,7 +207,8 @@ class BaseServer(object): This is a generic superclass and doesn't support many commands. """ - def __init__(self, host='', port=DEFAULT_PORT, password=''): + def __init__(self, host=DEFAULT_HOST, port=DEFAULT_PORT, + password=DEFAULT_PASSWORD): """Create a new server bound to address `host` and listening on port `port`. If `password` is given, it is required to do anything significant on the server. @@ -735,7 +741,7 @@ class Server(BaseServer): def __init__(self, library, host='', port=DEFAULT_PORT, password=''): try: - from beets.player import gstplayer + from beetsplug.bpd import gstplayer except ImportError, e: # This is a little hacky, but it's the best I know for now. if e.args[0].endswith(' gst'): @@ -1101,3 +1107,44 @@ class Server(BaseServer): super(Server, self).cmd_setvol(conn, vol) self.player.volume = float(vol)/100 + +# Beets plugin hooks. + +class BPDPlugin(BeetsPlugin): + """Provides the "beet bpd" command for running a music player + server. + """ + def start_bpd(self, lib, host, port, password, debug): + """Starts a BPD server.""" + if debug: + log.setLevel(logging.DEBUG) + else: + log.setLevel(logging.WARNING) + try: + Server(lib, host, port, password).run() + except NoGstreamerError: + beets.ui.print_('Gstreamer Python bindings not found.') + beets.ui.print_('Install "python-gst0.10", "py26-gst-python",' + 'or similar package to use BPD.') + + def commands(self): + cmd = beets.ui.Subcommand('bpd', + help='run an MPD-compatible music player server') + cmd.parser.add_option('-d', '--debug', action='store_true', + help='dump all MPD traffic to stdout') + + def func(lib, config, opts, args): + host = args.pop(0) if args else \ + beets.ui.config_val(config, 'bpd', 'host', DEFAULT_HOST) + port = args.pop(0) if args else \ + beets.ui.config_val(config, 'bpd', 'port', str(DEFAULT_PORT)) + if args: + raise beets.ui.UserError('too many arguments') + password = beets.ui.config_val(config, 'bpd', 'password', + DEFAULT_PASSWORD) + debug = opts.debug or False + self.start_bpd(lib, host, int(port), password, debug) + + cmd.func = func + return [cmd] + diff --git a/beets/player/gstplayer.py b/beetsplug/bpd/gstplayer.py similarity index 100% rename from beets/player/gstplayer.py rename to beetsplug/bpd/gstplayer.py diff --git a/beets/device.py b/beetsplug/device.py similarity index 83% rename from beets/device.py rename to beetsplug/device.py index e29296831..8860e0f45 100644 --- a/beets/device.py +++ b/beetsplug/device.py @@ -17,7 +17,10 @@ import sys import socket import locale import gpod + from beets.library import BaseLibrary, Item +from beets.plugins import BeetsPlugin +import beets.ui FIELD_MAP = { 'artist': 'artist', @@ -99,3 +102,22 @@ class PodLibrary(BaseLibrary): def remove(self, item): raise NotImplementedError + +# Plugin hook. + +class DevicePlugin(BeetsPlugin): + def commands(self): + cmd = beets.ui.Subcommand('dadd', help='add files to a device') + def func(lib, config, opts, args): + if not args: + raise beets.ui.UserError('no device name specified') + name = args.pop(0) + + items = lib.items(query=beets.ui.make_query(args)) + pod = PodLibrary.by_name(name) + for item in items: + pod.add(item) + pod.save() + cmd.func = func + return [cmd] +