]> kaliko git repositories - mpd-sima.git/commitdiff
Add priority to plugins
authorkaliko <kaliko@azylum.org>
Thu, 5 Feb 2015 14:50:45 +0000 (15:50 +0100)
committerkaliko <kaliko@azylum.org>
Thu, 5 Feb 2015 14:50:45 +0000 (15:50 +0100)
data/man/mpd_sima.cfg.5.xml
doc/Changelog
doc/examples/all_settings.cfg
sima/client.py
sima/core.py
sima/launch.py
sima/lib/plugin.py
sima/plugins/internal/random.py [moved from sima/plugins/internal/randomfallback.py with 90% similarity]
sima/utils/config.py
tests/test_plugin.py [new file with mode: 0644]

index ef483a17fbbc7a8b3a1ac541dfae85695e66b147..b6bd1237a9e2f1291a109fd9f435da11b5e04ce2 100644 (file)
@@ -222,13 +222,13 @@ man(1), man(7), http://www.tldp.org/HOWTO/Man-Page/
                 "AwesomePlugin" declared here gets its configuration from the
                 corresponding section "[awesomeplugin]".<sbr />internal plugins
                 will look for a section named after the lower-cased name of the
-                pluglin, ie.  RandomFallBack → randomfallback.
+                plugin, ie.  Random → random.
             </para>
             <variablelist>
                 <varlistentry> <!-- sima.internal -->
-                    <term><option>internal=</option><replaceable>Crop, RandomFallBack, Lastfm</replaceable></term>
+                    <term><option>internal=</option><replaceable>Crop, Random, Lastfm</replaceable></term>
                     <listitem>
-                        <para><option>Crop</option> and <option>RandomFallback</option>
+                        <para><option>Crop</option> and <option>Random</option>
                             are utilities plugins while <option>Lastfm</option> is the
                             actual queue plugin.<sbr /> Another queue plugin is available as
                             a "techno preview", it relies on EchoNest web services, replace
@@ -259,13 +259,13 @@ man(1), man(7), http://www.tldp.org/HOWTO/Man-Page/
                     </listitem>
                 </varlistentry>
         </refsect2>
-        <refsect2 id="randomfallback">
-            <title>RandomFallback section</title>
-            <para>RandomFallback plugin's configuration:</para>
-                <varlistentry> <!-- randomfallback -->
-                    <term><option>[randomfallback]</option></term>
+        <refsect2 id="random">
+            <title>Random section</title>
+            <para>Random plugin's configuration:</para>
+                <varlistentry> <!-- random -->
+                    <term><option>[random]</option></term>
                 </varlistentry>
-                <varlistentry> <!-- randomfallback.flavour -->
+                <varlistentry> <!-- random.flavour -->
                     <term><option>flavour=</option><replaceable>sensible</replaceable></term>
                     <listitem>
                         <para>When no similar tracks are found, falling back to
index f9466e1c068d101ffb3789e6d21c26927b3e58be..bbdbf1789bfab296abc11f5030b9ecc1093d1338 100644 (file)
@@ -1,9 +1,10 @@
 MPD_sima v0.14.0
 
+ * Add priority feature for plugins
+ * More robust MPD client
  * Fixed top track mode
  * Fixed default conf file name (back to mpd_sima.cfg)
  * Cleanup code (removed users similarities)
- * More robust MPD client
 
 -- kaliko jack <kaliko@azylum.org> UNRELEASED
 
index 01c910062d5e188c5cbd793822786f78d2ea1d7f..4778e1aea2cfca30609f818b48d8ede41bb471f7 100644 (file)
@@ -65,7 +65,7 @@ verbosity = info
 #                contrib = Scrobble, AwesomePlugin,
 #                          ExperimentalTest, AnotherTest
 # default:
-#          internal = "Crop, Lastfm, RandomFallBack"
+#          internal = "Crop, Lastfm, Random"
 #          contrib =
 # description: Plugins list declaration.
 #     Optional plugin's configuration lays in its own section.
@@ -73,11 +73,11 @@ verbosity = info
 #     gets its configuration from the corresponding section:
 #     "[awesomeplugin]"
 #     internal plugins will look for a section named after the lower-cased name
-#     of the pluglin, ie. RandomFallBack → randomfallback.
+#     of the pluglin, ie. Random → random.
 #
 #     Two plugins sources are available, internal and contrib
 #
-internal = Crop, Lastfm, RandomFallBack
+internal = Crop, Lastfm, Random
 #contrib =
 
 ## HISTORY_DURATION
@@ -118,12 +118,11 @@ musicbrainzid = True
 #  Leave commented to keep all tracks
 #consume = 10
 
-[randomfallback]
+[random]
 ## FLAVOUR
 # type: string
 # default: sensible
-# description: When no similar tracks are found, falling back to random
-#     queuing. Different mode, aka random flavour, are available.
+# description: Random queuing, different mode, aka random flavour, are available.
 #     random flavour :
 #       * pure:     complete random choice among all tracks available in the
 #                   player media library
@@ -132,7 +131,7 @@ musicbrainzid = True
 #                   chose among the same genre as current track (using genre
 #                   tag). If no genre tag is available "sensible" flavour
 #                   is used  instead
-#flavour=sensible
+flavour=sensible
 
 ## TRACK_TO_ADD
 # type: integer
index f64277e8f1bd21b2325d62a654dbe74362a73d08..926e2952acc5a9c177d8b622f01bb4d620935217 100644 (file)
@@ -336,7 +336,7 @@ class PlayerClient(Player):
 
     @property
     def artists(self):
-        return self._cache.get('artists')
+        return self._cache.get('artists') | self._cache.get('nombid_artists')
 
     @property
     def state(self):
index 3532c88e951e1f06e13c563debcc64909f5ed84f..264d97e144e108f45a3794c955c70f232a3156da 100644 (file)
@@ -1,5 +1,5 @@
 # -*- coding: utf-8 -*-
-# Copyright (c) 2009, 2010, 2011, 2013, 2014 Jack Kaliko <kaliko@azylum.org>
+# Copyright (c) 2009, 2010, 2011, 2013, 2014, 2015 Jack Kaliko <kaliko@azylum.org>
 #
 #  This file is part of sima
 #
@@ -43,7 +43,8 @@ class Sima(Daemon):
         self.sdb = SimaDB(db_path=conf.get('sima', 'db_file'))
         PlayerClient.database = self.sdb
         self.log = getLogger('sima')
-        self.plugins = list()
+        self._plugins = list()
+        self._core_plugins = list()
         self.player = self.__get_player()  # Player client
         self.short_history = deque(maxlen=60)
 
@@ -55,19 +56,38 @@ class Sima(Daemon):
         return PlayerClient(host, port, pswd)
 
     def add_history(self):
-        """Handle local short history"""
+        """Handle local, in memory, short history"""
         self.short_history.appendleft(self.player.current)
 
     def register_plugin(self, plugin_class):
         """Registers plugin in Sima instance..."""
-        self.plugins.append(plugin_class(self))
+        plgn = plugin_class(self)
+        prio = int(plgn.priority)
+        self._plugins.append((prio, plgn))
+
+    def register_core_plugin(self, plugin_class):
+        """Registers core plugins"""
+        plgn = plugin_class(self)
+        prio = int(plgn.priority)
+        self._core_plugins.append((prio, plgn))
 
     def foreach_plugin(self, method, *args, **kwds):
         """Plugin's callbacks dispatcher"""
+        for plugin in self.core_plugins:
+            getattr(plugin, method)(*args, **kwds)
         for plugin in self.plugins:
             #self.log.debug('dispatching {0} to {1}'.format(method, plugin))
             getattr(plugin, method)(*args, **kwds)
 
+    @property
+    def core_plugins(self):
+        return [plugin[1] for plugin in
+                sorted(self._core_plugins, key=lambda pl: pl[0], reverse=True)]
+
+    @property
+    def plugins(self):
+        return [plugin[1] for plugin in sorted(self._plugins, key=lambda pl: pl[0], reverse=True)]
+
     def need_tracks(self):
         """Is the player in need for tracks"""
         if not self.enabled:
@@ -84,15 +104,12 @@ class Sima(Daemon):
     def queue(self):
         to_add = list()
         for plugin in self.plugins:
-            pl_callback = getattr(plugin, 'callback_need_track')()
-            if pl_callback:
-                to_add.extend(pl_callback)
-        if not to_add:
-            self.log.warning('Queue plugins returned nothing!')
-            for plugin in self.plugins:
-                pl_callback = getattr(plugin, 'callback_need_track_fb')()
-                if pl_callback:
-                    to_add.extend(pl_callback)
+            self.log.info('running {}'.format(plugin))
+            pl_candidates = getattr(plugin, 'callback_need_track')()
+            if pl_candidates:
+                to_add.extend(pl_candidates)
+            if to_add:
+                break
         for track in to_add:
             self.player.add(track)
 
index 1ff6c94c4b94a2d91a102fd06256d74075f39105..c2dad9e823df571361414e6a2e3bd7b9c490266c 100644 (file)
@@ -1,5 +1,5 @@
 # -*- coding: utf-8 -*-
-# Copyright (c) 2013, 2014 Jack Kaliko <kaliko@azylum.org>
+# Copyright (c) 2013, 2014, 2015 Jack Kaliko <kaliko@azylum.org>
 #
 #  This file is part of sima
 #
@@ -54,6 +54,7 @@ def load_plugins(sima, source):
     if not sima.config.get('sima', source):
         return
     logger = logging.getLogger('sima')
+    # TODO: Sanity check for "sima.config.get('sima', source)" ?
     for plugin in sima.config.get('sima', source).split(','):
         plugin = plugin.strip(' \n')
         module = 'sima.plugins.{0}.{1}'.format(source, plugin.lower())
@@ -71,7 +72,7 @@ def load_plugins(sima, source):
             sima.shutdown()
             sys.exit(1)
         logger.info('Loading {0} plugin: {name} ({doc})'.format(
-                             source, **plugin_obj.info()))
+            source, **plugin_obj.info()))
         sima.register_plugin(plugin_obj)
 
 
@@ -107,14 +108,15 @@ def start(sopt, restart=False):
     core_plugins = [History, MpdOptions, Uniq]
     for cplgn in core_plugins:
         logger.debug('Register core {name} ({doc})'.format(**cplgn.info()))
-        sima.register_plugin(cplgn)
+        sima.register_core_plugin(cplgn)
+    logger.debug('core loaded, prioriy: {}'.format(' > '.join(map(str, sima.core_plugins))))
 
     #  Loading internal plugins
     load_plugins(sima, 'internal')
 
     #  Loading contrib plugins
     load_plugins(sima, 'contrib')
-
+    logger.info('plugins loaded, prioriy: {}'.format(' > '.join(map(str, sima.plugins))))
     #  Set use of MusicBrainzIdentifier
     if not config.getboolean('sima', 'musicbrainzid'):
         logger.info('Disabling MusicBrainzIdentifier')
index bb80a272642d5852b2518775da16bc32ff14ebfc..559e59ffc50a4a6c4510cc5ddc5f10f26ac07f9c 100644 (file)
@@ -21,6 +21,7 @@
 Plugin object to derive from
 """
 
+
 class Plugin:
     """
     First non-empty line of the docstring is used as description
@@ -57,13 +58,21 @@ class Plugin:
         """Get plugin's specific configuration from global applications's config
         """
         conf = self.__daemon.config
-        for sec in conf.sections():
+        for sec in conf.sections():  # Discovering plugin conf
             if sec == self.__class__.__name__.lower():
                 self.plugin_conf = conf[sec]
+                if 'priority' not in self.plugin_conf:
+                    self.plugin_conf['priority'] = '80'
+        if not self.plugin_conf:
+            self.plugin_conf = {'priority': '80'}
         #if self.plugin_conf:
         #    self.log.debug('Got config for {0}: {1}'.format(self,
         #                                                    self.plugin_conf))
 
+    @property
+    def priority(self):
+        return self.plugin_conf.get('priority')
+
     def start(self):
         """
         Called when the daemon().run() is called and
similarity index 90%
rename from sima/plugins/internal/randomfallback.py
rename to sima/plugins/internal/random.py
index ee0be20b78822ed645a92bf754a93aab0d91646a..f446b82f3953f5bba7faf39e2b0bfe8caec72c69 100644 (file)
@@ -1,5 +1,5 @@
 # -*- coding: utf-8 -*-
-# Copyright (c) 2013, 2014 Jack Kaliko <kaliko@azylum.org>
+# Copyright (c) 2013, 2014, 2015 Jack Kaliko <kaliko@azylum.org>
 #
 #  This file is part of sima
 #
@@ -18,7 +18,7 @@
 #
 #
 """
-Fetching similar artists from last.fm web services
+Add random title
 """
 
 # standard library import
@@ -31,8 +31,8 @@ from ...lib.plugin import Plugin
 from ...lib.meta import Artist
 
 
-class RandomFallBack(Plugin):
-    """Add random track as fallback
+class Random(Plugin):
+    """Add random track
     TODO: refactor, this plugin does not look good to me.
           callback_need_track_fb/get_trk articulation is not elegant at all
     """
@@ -57,7 +57,7 @@ class RandomFallBack(Plugin):
         artists = [tr[-1] for tr in tracks_from_db]
         return set(artists)
 
-    def callback_need_track_fb(self):
+    def callback_need_track(self):
         trks = list()
         target = self.plugin_conf.getint('track_to_add')
         limit = 0
@@ -92,7 +92,7 @@ class RandomFallBack(Plugin):
         trks = self.player.find_track(Artist(art))
         if trks:
             trk = random.choice(trks)
-            self.log.info('random fallback ({}): {}'.format(self.mode, trk))
+            self.log.info('Random candidate ({}): {}'.format(self.mode, trk))
         return trk
 
 
index 0e775ecc54d5c1294daebdc643b1250fe3037d0f..d3bcbe293a1c529f10cf7fd3af04ea910cfa6eeb 100644 (file)
@@ -72,6 +72,7 @@ DEFAULT_CONF = {
             'track_to_add': 1,
             'album_to_add': 1,
             'depth': 1,
+            'priority': 100,
             },
         'lastfm': {
             'queue_mode': "track", #TODO control values
@@ -81,11 +82,13 @@ DEFAULT_CONF = {
             'album_to_add': 1,
             'depth': 1,
             'cache': True,
+            'priority': 100,
             },
-        'randomfallback': {
+        'random': {
             'flavour': "sensible", # in pure, sensible
             'track_to_add': 1,
-            }
+            'priority': 50,
+            },
         }
 #
 
diff --git a/tests/test_plugin.py b/tests/test_plugin.py
new file mode 100644 (file)
index 0000000..5c3a384
--- /dev/null
@@ -0,0 +1,49 @@
+# -*- coding: utf-8 -*-
+
+import unittest
+import configparser
+
+from unittest.mock import Mock
+
+import sima.lib.plugin
+
+class SomePlugin(sima.lib.plugin.Plugin):
+
+    def __init__(self, daemon):
+        sima.lib.plugin.Plugin.__init__(self, daemon)
+
+
+class TestFileAccessControl(unittest.TestCase):
+
+    def setUp(self):
+        pass
+
+    def tearDown(self):
+        pass
+
+    def test_plugin_conf_discovery(self):
+        config = configparser.ConfigParser()
+        default = {'priority': '42', 'option': 'value'}
+        config.read_dict({'someplugin': default})
+        daemon = Mock(config=config)
+        plugin = SomePlugin(daemon)
+        self.assertEqual(dict(plugin.plugin_conf), default)
+
+    def test_plugin_default_priority(self):
+        config = configparser.ConfigParser()
+        default = {'option': 'value'}
+        config.read_dict({'someplugin': default})
+        daemon = Mock(config=config)
+        plugin = SomePlugin(daemon)
+        self.assertEqual(plugin.plugin_conf.get('priority'), '80')
+        self.assertEqual(plugin.plugin_conf.get('option'), default.get('option'))
+
+        config = configparser.ConfigParser()
+        config.read_dict({})
+        daemon = Mock(config=config)
+        plugin = SomePlugin(daemon)
+        self.assertEqual(plugin.plugin_conf.get('priority'), '80')
+
+
+# VIM MODLINE
+# vim: ai ts=4 sw=4 sts=4 expandtab