diff --git a/mopidy/__main__.py b/mopidy/__main__.py index a2174899..f571e0ff 100644 --- a/mopidy/__main__.py +++ b/mopidy/__main__.py @@ -84,7 +84,6 @@ def main(): enabled_extensions.append(extension) log_extension_info(installed_extensions, enabled_extensions) - ext.register_gstreamer_elements(enabled_extensions) # Config and deps commands are simply special cased for now. if args.command == config_cmd: @@ -108,16 +107,13 @@ def main(): args.extension.ext_name) return 1 - registry = {'backends': [], 'frontends': [], 'local:library': []} for extension in enabled_extensions: - registry['backends'].extend(extension.get_backend_classes()) - registry['frontends'].extend(extension.get_frontend_classes()) - registry['local:library'].extend(extension.get_library_updaters()) + extension.setup() # Anything that wants to exit after this point must use # mopidy.utils.process.exit_process as actors can have been started. try: - return args.command.run(args, proxied_config, registry) + return args.command.run(args, proxied_config) except NotImplementedError: print root_cmd.format_help() return 1 diff --git a/mopidy/backends/local/commands.py b/mopidy/backends/local/commands.py index de84760b..8a951929 100644 --- a/mopidy/backends/local/commands.py +++ b/mopidy/backends/local/commands.py @@ -4,7 +4,7 @@ import logging import os import time -from mopidy import commands, exceptions +from mopidy import commands, exceptions, ext from mopidy.audio import scan from mopidy.utils import path @@ -22,14 +22,15 @@ class LocalCommand(commands.Command): class ScanCommand(commands.Command): help = "Scan local media files and populate the local library." - def run(self, args, config, registry): + def run(self, args, config): media_dir = config['local']['media_dir'] scan_timeout = config['local']['scan_timeout'] + excluded_file_extensions = config['local']['excluded_file_extensions'] excluded_file_extensions = set( - ext.lower() for ext in config['local']['excluded_file_extensions']) + file_ext.lower() for file_ext in excluded_file_extensions) # TODO: select updater / library to use by name - updaters = registry['local:library'] + updaters = ext.registry['local:library'] if not updaters: logger.error('No usable library updaters found.') return 1 diff --git a/mopidy/commands.py b/mopidy/commands.py index 35175e07..372550a0 100644 --- a/mopidy/commands.py +++ b/mopidy/commands.py @@ -9,7 +9,7 @@ import sys import glib import gobject -from mopidy import config as config_lib +from mopidy import config as config_lib, ext from mopidy.audio import Audio from mopidy.core import Core from mopidy.utils import deps, process, versioning @@ -257,22 +257,26 @@ class RootCommand(Command): type=config_override_type, metavar='OPTIONS', help='`section/key=value` values to override config options') - def run(self, args, config, registry): + def run(self, args, config): loop = gobject.MainLoop() + + backend_classes = ext.registry['backend'] + frontend_classes = ext.registry['frontend'] + try: audio = self.start_audio(config) - backends = self.start_backends(config, registry, audio) + backends = self.start_backends(config, backend_classes, audio) core = self.start_core(audio, backends) - self.start_frontends(config, registry, core) + self.start_frontends(config, frontend_classes, core) loop.run() except KeyboardInterrupt: logger.info('Interrupted. Exiting...') return finally: loop.quit() - self.stop_frontends(registry) + self.stop_frontends(frontend_classes) self.stop_core() - self.stop_backends(registry) + self.stop_backends(backend_classes) self.stop_audio() process.stop_remaining_actors() @@ -280,9 +284,7 @@ class RootCommand(Command): logger.info('Starting Mopidy audio') return Audio.start(config=config).proxy() - def start_backends(self, config, registry, audio): - backend_classes = registry['backends'] - + def start_backends(self, config, backend_classes, audio): logger.info( 'Starting Mopidy backends: %s', ', '.join(b.__name__ for b in backend_classes) or 'none') @@ -298,9 +300,7 @@ class RootCommand(Command): logger.info('Starting Mopidy core') return Core.start(audio=audio, backends=backends).proxy() - def start_frontends(self, config, registry, core): - frontend_classes = registry['frontends'] - + def start_frontends(self, config, frontend_classes, core): logger.info( 'Starting Mopidy frontends: %s', ', '.join(f.__name__ for f in frontend_classes) or 'none') @@ -308,18 +308,18 @@ class RootCommand(Command): for frontend_class in frontend_classes: frontend_class.start(config=config, core=core) - def stop_frontends(self, registry): + def stop_frontends(self, frontend_classes): logger.info('Stopping Mopidy frontends') - for frontend_class in registry['frontends']: + for frontend_class in frontend_classes: process.stop_actors_by_class(frontend_class) def stop_core(self): logger.info('Stopping Mopidy core') process.stop_actors_by_class(Core) - def stop_backends(self, registry): + def stop_backends(self, backend_classes): logger.info('Stopping Mopidy backends') - for backend_class in registry['backends']: + for backend_class in backend_classes: process.stop_actors_by_class(backend_class) def stop_audio(self): diff --git a/mopidy/ext.py b/mopidy/ext.py index feadc99f..d1c81dc5 100644 --- a/mopidy/ext.py +++ b/mopidy/ext.py @@ -1,5 +1,6 @@ from __future__ import unicode_literals +import collections import logging import pkg_resources @@ -61,6 +62,18 @@ class Extension(object): """ pass + def setup(self): + for backend_class in self.get_backend_classes(): + registry.add('backend', backend_class) + + for frontend_class in self.get_frontend_classes(): + registry.add('frontend', frontend_class) + + for library_updater in self.get_library_updaters(): + registry.add('local:library', library_updater) + + self.register_gstreamer_elements() + def get_frontend_classes(self): """List of frontend actor classes @@ -112,6 +125,29 @@ class Extension(object): pass +class _Registry(collections.Mapping): + def __init__(self): + self._registry = collections.defaultdict(list) + + def add(self, name, cls): + self._registry[name].append(cls) + + def __getitem__(self, name): + return self._registry[name] + + def __iter__(self): + return iter(self._registry) + + def __len__(self): + return len(self._registry) + + +# TODO: document the registry +# TODO: consider if we should avoid having this as a global and pass an +# instance from __main__ around instead? +registry = _Registry() + + def load_extensions(): """Find all installed extensions. @@ -166,15 +202,3 @@ def validate_extension(extension): return False return True - - -def register_gstreamer_elements(enabled_extensions): - """Registers custom GStreamer elements from extensions. - - :param enabled_extensions: list of enabled extensions - """ - - for extension in enabled_extensions: - logger.debug( - 'Registering GStreamer elements for: %s', extension.ext_name) - extension.register_gstreamer_elements()