gpodder/src/gpodder/registry.py

104 lines
3.9 KiB
Python

#
# gpodder.registry - Central hub for exchanging plugin resolvers (2014-03-09)
# Copyright (c) 2014, Thomas Perl <m@thp.io>
#
# Permission to use, copy, modify, and/or distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
# AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
# OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
# PERFORMANCE OF THIS SOFTWARE.
#
import logging
logger = logging.getLogger(__name__)
class Resolver(object):
def __init__(self, name, description):
self._name = name
self._description = description
self._resolvers = []
def resolve(self, item, default, *args):
for resolver in self._resolvers:
result = resolver(item, *args)
if result is not None:
logger.info('{} resolved by {}: {} -> {}'.format(self._name, self._info(resolver),
default, result))
return result
return default
def each(self, *args):
for resolver in self._resolvers:
result = resolver(*args)
if result is not None:
yield result
def call_each(self, *args):
list(self.each(*args))
def select(self, selector=None):
for resolver in self._resolvers:
if selector is None or selector(resolver):
yield resolver
def register(self, func):
logger.debug('Registering {} resolver: {}'.format(self._name, func))
self._resolvers.append(func)
return func
def unregister(self, func):
logger.debug('Unregistering {} resolver: {}'.format(self._name, func))
self._resolvers.remove(func)
def register_instance(self, klass):
logger.debug('Registering {} resolver instance: {}'.format(self._name, klass))
self._resolvers.append(klass())
return klass
def unregister_instance(self, klass):
logger.debug('Unregistering {} resolver instance: {}'.format(self._name, klass))
self._resolvers = [r for r in self._resolvers if not isinstance(r, klass)]
def _info(self, resolver):
return '%s from %s' % (resolver.__name__ if hasattr(resolver, '__name__')
else resolver.__class__.__name__, resolver.__module__)
def _dump(self, indent=''):
print('== {} ({}) =='.format(self._name, self._description))
print('\n'.join('%s- %s' % (indent, self._info(resolver)) for resolver in self._resolvers))
print()
RESOLVER_NAMES = {
# 'cover_art': 'Resolve the real cover art URL of an episode',
'download_url': 'Resolve the real download URL of an episode',
# 'episode_basename': 'Resolve a good, unique download filename for an episode',
# 'podcast_title': 'Resolve a good title for a podcast',
# 'content_type': 'Resolve the content type (audio, video) of an episode',
'feed_handler': 'Handle fetching of a feed',
# 'fallback_feed_handler': 'Handle parsing of a feed (catch-all)',
# 'url_shortcut': 'Expand shortcuts when adding a new URL',
# 'after_download': 'Function to call with episodes after download finishes',
# 'directory': 'Podcast directory and search provider',
'custom_downloader': 'custom download method. See download.CustomDownloader',
}
LOCALS = locals()
for name, description in RESOLVER_NAMES.items():
LOCALS[name] = Resolver(name, description)
def dump(module_dict=LOCALS):
for name in sorted(RESOLVER_NAMES):
module_dict[name]._dump(' ')