]> kaliko git repositories - mpd-sima.git/blobdiff - sima/plugins/internal/lastfm.py
Converging webservices plugins
[mpd-sima.git] / sima / plugins / internal / lastfm.py
index 1b9ae41798cd39c46efc940f16eb77d99340a2f6..9ca859f6a724629ba73be2d39c1e8b27a99e1e27 100644 (file)
@@ -7,15 +7,15 @@ Fetching similar artists from last.fm web services
 import random
 
 from collections import deque
-from itertools import dropwhile
 from hashlib import md5
 
 # third parties components
 
 # local import
 from ...lib.plugin import Plugin
-from ...lib.simafm import SimaFM, XmlFMHTTPError, XmlFMNotFound, XmlFMError
+from ...lib.simafm import SimaFM, WSError
 from ...lib.track import Track
+from ...lib.meta import Artist
 
 
 def cache(func):
@@ -23,7 +23,7 @@ def cache(func):
     def wrapper(*args, **kwargs):
         #pylint: disable=W0212,C0111
         cls = args[0]
-        similarities = [art + str(match) for art, match in args[1]]
+        similarities = [art for art, _ in args[1]]
         hashedlst = md5(''.join(similarities).encode('utf-8')).hexdigest()
         if hashedlst in cls._cache.get('asearch'):
             cls.log.debug('cached request')
@@ -37,36 +37,6 @@ def cache(func):
     return wrapper
 
 
-def blacklist(artist=False, album=False, track=False):
-    #pylint: disable=C0111,W0212
-    field = (artist, album, track)
-    def decorated(func):
-        def wrapper(*args, **kwargs):
-            cls = args[0]
-            boolgen = (bl for bl in field)
-            bl_fun = (cls._Plugin__daemon.sdb.get_bl_artist,
-                      cls._Plugin__daemon.sdb.get_bl_album,
-                      cls._Plugin__daemon.sdb.get_bl_track,)
-            #bl_getter = next(fn for fn, bl in zip(bl_fun, boolgen) if bl is True)
-            bl_getter = next(dropwhile(lambda _: not next(boolgen), bl_fun))
-            cls.log.debug('using {0} as bl filter'.format(bl_getter.__name__))
-            if artist:
-                results = func(*args, **kwargs)
-                for elem in results:
-                    if bl_getter(elem, add_not=True):
-                        cls.log.info('Blacklisted: {0}'.format(elem))
-                        results.remove(elem)
-                return results
-            if track:
-                for elem in args[1]:
-                    if bl_getter(elem, add_not=True):
-                        cls.log.info('Blacklisted: {0}'.format(elem))
-                        args[1].remove(elem)
-                return func(*args, **kwargs)
-        return wrapper
-    return decorated
-
-
 class Lastfm(Plugin):
     """last.fm similar artists
     """
@@ -91,10 +61,11 @@ class Lastfm(Plugin):
         """
         Both flushes and instanciates _cache
         """
+        name = self.__class__.__name__
         if isinstance(self._cache, dict):
-            self.log.info('Lastfm: Flushing cache!')
+            self.log.info('{0}: Flushing cache!'.format(name))
         else:
-            self.log.info('Lastfm: Initialising cache!')
+            self.log.info('{0}: Initialising cache!'.format(name))
         self._cache = {
                 'asearch': dict(),
                 'tsearch': dict(),
@@ -175,7 +146,6 @@ class Lastfm(Plugin):
                        ' / '.join(art_not_in_hist)))
         return art_not_in_hist
 
-    @blacklist(artist=True)
     @cache
     def get_artists_from_player(self, similarities):
         """
@@ -202,24 +172,24 @@ class Lastfm(Plugin):
         Retrieve similar artists on last.fm server.
         """
         if artist is None:
-            current = self.player.current
+            curr = self.player.current.__dict__
+            name = curr.get('artist')
+            mbid = curr.get('musicbrainz_artistid', None)
+            current = Artist(name=name, mbid=mbid)
         else:
             current = artist
         simafm = SimaFM()
         # initialize artists deque list to construct from DB
         as_art = deque()
-        as_artists = simafm.get_similar(artist=current.artist)
-        self.log.debug('Requesting last.fm for "{0.artist}"'.format(current))
+        as_artists = simafm.get_similar(artist=current)
+        self.log.debug('Requesting last.fm for "{0}"'.format(current))
         try:
-            [as_art.append((a, m)) for a, m in as_artists]
-        except XmlFMHTTPError as err:
-            self.log.warning('last.fm http error: %s' % err)
-        except XmlFMNotFound as err:
-            self.log.warning("last.fm: %s" % err)
-        except XmlFMError as err:
-            self.log.warning('last.fm module error: %s' % err)
+            # TODO: let's propagate Artist type
+            [as_art.append((str(a), m)) for a, m in as_artists]
+        except WSError as err:
+            self.log.warning('Last.fm: {0}'.format(err))
         if as_art:
-            self.log.debug('Fetched %d artist(s) from last.fm' % len(as_art))
+            self.log.debug('Fetched {0} artist(s)'.format(len(as_art)))
         return as_art
 
     def get_recursive_similar_artist(self):
@@ -262,18 +232,19 @@ class Lastfm(Plugin):
             return []
         similar = sorted(similar, key=lambda sim: sim[1], reverse=True)
         self.log.info('First five similar artist(s): {}...'.format(
-                      ' / '.join([a for a, m in similar[0:5]])))
+                      ' / '.join([a for a, _ in similar[0:5]])))
         self.log.info('Looking availability in music library')
         ret = self.get_artists_from_player(similar)
         ret_extra = None
         if len(self.history) >= 2:
-            ret_extra = self.get_recursive_similar_artist()
+            if self.plugin_conf.getint('depth') > 1:
+                ret_extra = self.get_recursive_similar_artist()
+        if ret_extra:
+            ret = list(set(ret) | set(ret_extra))
         if not ret:
             self.log.warning('Got nothing from music library.')
             self.log.warning('Try running in debug mode to guess why...')
             return []
-        if ret_extra:
-            ret = list(set(ret) | set(ret_extra))
         self.log.info('Got {} artists in library'.format(len(ret)))
         self.log.info(' / '.join(ret))
         # Move around similars items to get in unplayed|not recently played
@@ -297,7 +268,13 @@ class Lastfm(Plugin):
         for artist in artists:
             self.log.info('Looking for an album to add for "%s"...' % artist)
             albums = self.player.find_albums(artist)
+            # str conversion while Album type is not propagated
+            albums = [ str(album) for album in albums]
+            if albums:
+                self.log.debug('Albums candidate: {0:s}'.format(' / '.join(albums)))
+            else: continue
             # albums yet in history for this artist
+            albums = set(albums)
             albums_yet_in_hist = albums & self._get_album_history(artist=artist)
             albums_not_in_hist = list(albums - albums_yet_in_hist)
             # Get to next artist if there are no unplayed albums
@@ -308,10 +285,6 @@ class Lastfm(Plugin):
             random.shuffle(albums_not_in_hist)
             for album in albums_not_in_hist:
                 tracks = self.player.find_album(artist, album)
-                if tracks and self.sdb.get_bl_album(tracks[0], add_not=True):
-                    self.log.info('Blacklisted album: "%s"' % album)
-                    self.log.debug('using track: "%s"' % tracks[0])
-                    continue
                 # Look if one track of the album is already queued
                 # Good heuristic, at least enough to guess if the whole album is
                 # already queued.
@@ -348,7 +321,7 @@ class Lastfm(Plugin):
                             'history getting too large?')
             return None
         for track in self.to_add:
-            self.log.info('last.fm candidate: {0!s}'.format(track))
+            self.log.info('last.fm candidates: {0!s}'.format(track))
 
     def _album(self):
         """Get albums for album queue mode
@@ -365,7 +338,11 @@ class Lastfm(Plugin):
     def callback_need_track(self):
         self._cleanup_cache()
         if not self.player.current:
-            self.log.info('Not currently playing track, cannot queue')
+            self.log.info('No current track, cannot queue')
+            return None
+        if not self.player.current.artist:
+            self.log.warning('No artist set for the current track')
+            self.log.debug(repr(self.player.current))
             return None
         self.queue_mode()
         candidates = self.to_add