]> kaliko git repositories - mpd-sima.git/blobdiff - sima/lib/plugin.py
Some cleanup in log, get messages more uniform across plugins
[mpd-sima.git] / sima / lib / plugin.py
index 3839f8754505591550f632cee6a31ab27db1b59d..49cd7f155d9c0ee057e0353aef4e27cf4e28f10f 100644 (file)
@@ -1,5 +1,5 @@
 # -*- coding: utf-8 -*-
 # -*- coding: utf-8 -*-
-# Copyright (c) 2013-2015, 2020 kaliko <kaliko@azylum.org>
+# Copyright (c) 2013-2015, 2020-2021 kaliko <kaliko@azylum.org>
 #
 #  This file is part of sima
 #
 #
 #  This file is part of sima
 #
@@ -24,7 +24,7 @@ Plugin object to derive from
 import random
 
 from .track import Track
 import random
 
 from .track import Track
-from .meta import Album, Artist
+from .meta import Album, Artist, MetaContainer
 
 
 class Plugin:
 
 
 class Plugin:
@@ -46,13 +46,14 @@ class Plugin:
         if cls.__doc__:
             doc = cls.__doc__.strip(' \n').splitlines()[0]
         return {'name': cls.__name__,
         if cls.__doc__:
             doc = cls.__doc__.strip(' \n').splitlines()[0]
         return {'name': cls.__name__,
-                'doc': doc,}
+                'doc': doc}
 
     def __init__(self, daemon):
         self.log = daemon.log
 
     def __init__(self, daemon):
         self.log = daemon.log
-        self.__daemon = daemon
         self.player = daemon.player
         self.plugin_conf = None
         self.player = daemon.player
         self.plugin_conf = None
+        self.main_conf = daemon.config
+        self.sdb = daemon.sdb
         self.__get_config()
 
     def __str__(self):
         self.__get_config()
 
     def __str__(self):
@@ -61,7 +62,7 @@ class Plugin:
     def __get_config(self):
         """Get plugin's specific configuration from global applications's config
         """
     def __get_config(self):
         """Get plugin's specific configuration from global applications's config
         """
-        conf = self.__daemon.config
+        conf = self.main_conf
         for sec in conf.sections():  # Discovering plugin conf
             if sec == self.__class__.__name__.lower():
                 self.plugin_conf = conf[sec]
         for sec in conf.sections():  # Discovering plugin conf
             if sec == self.__class__.__name__.lower():
                 self.plugin_conf = conf[sec]
@@ -70,7 +71,7 @@ class Plugin:
         if not self.plugin_conf:
             self.plugin_conf = {'priority': '80'}
         #if self.plugin_conf:
         if not self.plugin_conf:
             self.plugin_conf = {'priority': '80'}
         #if self.plugin_conf:
-        #    self.log.debug('Got config for %s: %s', self, self.plugin_conf)
+        #   self.log.debug('Got config for %s: %s', self, self.plugin_conf)
 
     @property
     def priority(self):
 
     @property
     def priority(self):
@@ -81,71 +82,60 @@ class Plugin:
         Called when the daemon().run() is called and
         right after the player has connected successfully.
         """
         Called when the daemon().run() is called and
         right after the player has connected successfully.
         """
-        pass
 
     def callback_player(self):
         """
         Called on player changes, stopped, paused, skipped
         """
 
     def callback_player(self):
         """
         Called on player changes, stopped, paused, skipped
         """
-        pass
 
     def callback_player_database(self):
         """
         Called on player music library changes
         """
 
     def callback_player_database(self):
         """
         Called on player music library changes
         """
-        pass
 
     def callback_playlist(self):
         """
         Called on playlist changes
         Not returning data
         """
 
     def callback_playlist(self):
         """
         Called on playlist changes
         Not returning data
         """
-        pass
 
     def callback_next_song(self):
         """
         Could be use to scrobble, maintain an history…
         Not returning data,
         """
 
     def callback_next_song(self):
         """
         Could be use to scrobble, maintain an history…
         Not returning data,
         """
-        pass
 
     def callback_need_track(self):
         """
         Returns a list of Track objects to add
         """
 
     def callback_need_track(self):
         """
         Returns a list of Track objects to add
         """
-        pass
 
     def callback_need_track_fb(self):
         """
         Called when callback_need_track failled to find tracks to queue
         Returns a list of Track objects to add
         """
 
     def callback_need_track_fb(self):
         """
         Called when callback_need_track failled to find tracks to queue
         Returns a list of Track objects to add
         """
-        pass
 
     def shutdown(self):
         """Called on application shutdown"""
 
     def shutdown(self):
         """Called on application shutdown"""
-        pass
 
 
 
 
-class AdvancedLookUp:
+class AdvancedPlugin(Plugin):
     """Object to derive from for plugins
     Exposes advanced music library look up with use of play history
     """
 
     """Object to derive from for plugins
     Exposes advanced music library look up with use of play history
     """
 
-    def __init__(self, daemon):
-        self.log = daemon.log
-        self.daemon = daemon
-        self.player = daemon.player
-
     # Query History
     def get_history(self, artist=False):
     # Query History
     def get_history(self, artist=False):
-        """Constructs list of already played artists.
+        """Constructs Track list of already played artists.
+
+        :param Artist artist: Artist object to look history for
         """
         """
-        duration = self.daemon.config.getint('sima', 'history_duration')
+        duration = self.main_conf.getint('sima', 'history_duration')
         name = None
         if artist:
             name = artist.name
         name = None
         if artist:
             name = artist.name
-        from_db = self.daemon.sdb.get_history(duration=duration, artist=name)
+        from_db = self.sdb.get_history(duration=duration, artist=name)
         hist = [Track(artist=tr[0], album=tr[1], title=tr[2],
                       file=tr[3]) for tr in from_db]
         return hist
         hist = [Track(artist=tr[0], album=tr[1], title=tr[2],
                       file=tr[3]) for tr in from_db]
         return hist
@@ -162,60 +152,70 @@ class AdvancedLookUp:
 
     def get_reorg_artists_list(self, alist):
         """
 
     def get_reorg_artists_list(self, alist):
         """
-        Move around items in artists_list in order to play first not recently
-        played artists
+        Move around items in alist in order to have first not recently
+        played (or about to be played) artists.
 
 
-        :param list(str) alist:
+        :param {Artist} alist: Artist objects list/container
         """
         """
-        hist = list()
-        duration = self.daemon.config.getint('sima', 'history_duration')
-        for art in self.daemon.sdb.get_artists_history(alist, duration=duration):
+        queued_artist = MetaContainer([Artist(_.artist) for _ in
+                                       self.player.queue if _.artist])
+        not_queued_artist = alist - queued_artist
+        duration = self.main_conf.getint('sima', 'history_duration')
+        hist = []
+        for art in self.sdb.get_artists_history(alist, duration=duration):
             if art not in hist:
             if art not in hist:
-                hist.insert(0, art)
-        reorg = [art for art in alist if art not in hist]
+                if art not in queued_artist:
+                    hist.insert(0, art)
+                else:
+                    hist.append(art)
+        # Find not recently played (not in history) & not in queue
+        reorg = [art for art in not_queued_artist if art not in hist]
         reorg.extend(hist)
         return reorg
     # /Query History
 
     # Find not recently played/unplayed
     def album_candidate(self, artist, unplayed=True):
         reorg.extend(hist)
         return reorg
     # /Query History
 
     # Find not recently played/unplayed
     def album_candidate(self, artist, unplayed=True):
-        """
+        """Search an album for artist
+
         :param Artist artist: Artist to fetch an album for
         :param bool unplayed: Fetch only unplayed album
         """
         self.log.info('Searching an album for "%s"...' % artist)
         albums = self.player.search_albums(artist)
         if not albums:
         :param Artist artist: Artist to fetch an album for
         :param bool unplayed: Fetch only unplayed album
         """
         self.log.info('Searching an album for "%s"...' % artist)
         albums = self.player.search_albums(artist)
         if not albums:
-            return []
-        self.log.debug('Albums candidate: %s', albums)
+            return None
+        self.log.debug('Albums candidates: %s', albums)
         albums_hist = self.get_album_history(artist)
         albums_hist = self.get_album_history(artist)
-        self.log.debug('Albums history: %s', albums_hist)
+        self.log.trace('Albums history: %s', [a.name for a in albums_hist])
         albums_not_in_hist = [a for a in albums if a.name not in albums_hist]
         # Get to next artist if there are no unplayed albums
         if not albums_not_in_hist:
             self.log.info('No unplayed album found for "%s"' % artist)
             if unplayed:
         albums_not_in_hist = [a for a in albums if a.name not in albums_hist]
         # Get to next artist if there are no unplayed albums
         if not albums_not_in_hist:
             self.log.info('No unplayed album found for "%s"' % artist)
             if unplayed:
-                return []
+                return None
         random.shuffle(albums_not_in_hist)
         albums_not_in_hist.extend(albums_hist)
         random.shuffle(albums_not_in_hist)
         albums_not_in_hist.extend(albums_hist)
+        self.log.debug('Albums candidate: %s', albums_not_in_hist)
         album_to_queue = []
         for album in albums_not_in_hist:
             # Controls the album found is not already queued
             if album in {t.album for t in self.player.queue}:
                 self.log.debug('"%s" already queued, skipping!', album)
         album_to_queue = []
         for album in albums_not_in_hist:
             # Controls the album found is not already queued
             if album in {t.album for t in self.player.queue}:
                 self.log.debug('"%s" already queued, skipping!', album)
-                return []
+                continue
             # In random play mode use complete playlist to filter
             if self.player.playmode.get('random'):
                 if album in {t.album for t in self.player.playlist}:
                     self.log.debug('"%s" already in playlist, skipping!',
                                    album)
             # In random play mode use complete playlist to filter
             if self.player.playmode.get('random'):
                 if album in {t.album for t in self.player.playlist}:
                     self.log.debug('"%s" already in playlist, skipping!',
                                    album)
-                    return []
+                    continue
             album_to_queue = album
             album_to_queue = album
+            break
         if not album_to_queue:
             self.log.info('No album found for "%s"', artist)
         if not album_to_queue:
             self.log.info('No album found for "%s"', artist)
-            return []
-        self.log.info('%s album candidate: %s - %s', self.__class__.__name__,
-                      artist, album_to_queue)
+            return None
+        self.log.info('%s plugin chose album: %s - %s',
+                      self.__class__.__name__, artist, album_to_queue)
         return album_to_queue
 
     def filter_track(self, tracks, unplayed=False):
         return album_to_queue
 
     def filter_track(self, tracks, unplayed=False):
@@ -236,16 +236,16 @@ class AdvancedLookUp:
             if unplayed:
                 return None
         random.shuffle(not_in_hist)
             if unplayed:
                 return None
         random.shuffle(not_in_hist)
-        candidates = [_ for _ in not_in_hist if _ not in deny_list]
-        for trk in [_ for _ in not_in_hist if _ not in deny_list]:
-            # Should use albumartist heuristic as well
-        #     if self.plugin_conf.getboolean('single_album'):  # pylint: disable=no-member
-                if (trk.album == self.player.current.album or
-        #                 trk.album in [tr.album for tr in black_list]):
-                    self.log.debug('Found unplayed track ' +
-                                   'but from an album already queued: %s', trk)
-                    continue
-            candidates.append(trk)
+        candidates = []
+        for trk in [_ for _ in not_in_hist if _ not in deny_list]:
+            # Should use albumartist heuristic as well
+            if self.plugin_conf.getboolean('single_album', False):  # pylint: disable=no-member
+                if (trk.album == self.player.current.album or
+                        trk.album in [tr.album for tr in deny_list]):
+                    self.log.debug('Found unplayed track ' +
+                                   'but from an album already queued: %s', trk)
+                    continue
+            candidates.append(trk)
         if not candidates:
             return None
         return random.choice(candidates)
         if not candidates:
             return None
         return random.choice(candidates)