]> kaliko git repositories - mpd-sima.git/blobdiff - sima/lib/simafm.py
Mainly use literal for list/dict and f-strings when possible
[mpd-sima.git] / sima / lib / simafm.py
index 236efe725cb9458dbf7f50531ffed66f0c92d156..5103aceac9455a9ac5d8a39e8fc10f5812151b3f 100644 (file)
@@ -1,6 +1,6 @@
 # -*- coding: utf-8 -*-
 
-# Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014 Jack Kaliko <kaliko@azylum.org>
+# Copyright (c) 2009-2014, 2021 kaliko <kaliko@azylum.org>
 #
 #   This program is free software: you can redistribute it and/or modify
 #   it under the terms of the GNU General Public License as published by
@@ -25,7 +25,6 @@ __version__ = '0.5.1'
 __author__ = 'Jack Kaliko'
 
 
-
 from sima import LFM
 from sima.lib.meta import Artist
 from sima.lib.track import Track
@@ -41,12 +40,15 @@ class SimaFM:
     """Last.fm http client
     """
     root_url = 'http://{host}/{version}/'.format(**LFM)
-    ratelimit = None
     name = 'Last.fm'
     cache = False
-    stats = {'etag':0,
-            'ccontrol':0,
-            'total':0}
+    """HTTP cache to use, in memory or persitent.
+
+    :param BaseCache cache: Set a cache, defaults to `False`.
+    """
+    stats = {'etag': 0,
+             'ccontrol': 0,
+             'total': 0}
 
     def __init__(self):
         self.http = HttpClient(cache=self.cache, stats=self.stats)
@@ -59,25 +61,25 @@ class SimaFM:
             code = ans.get('error')
             mess = ans.get('message')
             if code == 6:
-                raise WSNotFound('{0}: "{1}"'.format(mess, self.artist))
+                raise WSNotFound(f'{mess}: "{self.artist}"')
             raise WSError(mess)
         return True
 
     def _forge_payload(self, artist, method='similar', track=None):
         """Build payload
         """
-        payloads = dict({'similar': {'method':'artist.getsimilar',},
-                        'top': {'method':'artist.gettoptracks',},
-                        'track': {'method':'track.getsimilar',},
-                        'info': {'method':'artist.getinfo',},
-                        })
+        payloads = dict({'similar': {'method': 'artist.getsimilar',},
+                         'top': {'method': 'artist.gettoptracks',},
+                         'track': {'method': 'track.getsimilar',},
+                         'info': {'method': 'artist.getinfo',},
+                         })
         payload = payloads.get(method)
         payload.update(api_key=LFM.get('apikey'), format='json')
         if not isinstance(artist, Artist):
-            raise TypeError('"{0!r}" not an Artist object'.format(artist))
+            raise TypeError(f'"{artist!r}" not an Artist object')
         self.artist = artist
         if artist.mbid:
-            payload.update(mbid='{0}'.format(artist.mbid))
+            payload.update(mbid=f'{artist.mbid}')
         else:
             payload.update(artist=artist.name,
                            autocorrect=1)
@@ -88,36 +90,45 @@ class SimaFM:
         # return a sorted list of 2-tuple to have consistent cache
         return sorted(payload.items(), key=lambda param: param[0])
 
-    def get_similar(self, artist=None):
+    def get_similar(self, artist):
         """Fetch similar artists
+
+        :param sima.lib.meta.Artist artist: `Artist` to fetch similar artists from
+        :returns: generator of :class:`sima.lib.meta.Artist`
         """
         payload = self._forge_payload(artist)
         # Construct URL
         ans = self.http(self.root_url, payload)
-        self._controls_answer(ans.json())
-        # Artist might be found be return no 'artist' list…
+        try:
+            ans.json()
+        except ValueError as err:
+            # Corrupted/malformed cache? cf. gitlab issue #35
+            raise WSError('Malformed json, try purging the cache: %s') from err
+        self._controls_answer(ans.json())  # pylint: disable=no-member
+        # Artist might be found but return no 'artist' list…
         # cf. "Mulatu Astatqe" vs. "Mulatu Astatqé" with autocorrect=0
         # json format is broken IMHO, xml is more consistent IIRC
         # Here what we got:
         # >>> {"similarartists":{"#text":"\n","artist":"Mulatu Astatqe"}}
         # autocorrect=1 should fix it, checking anyway.
-        simarts = ans.json().get('similarartists').get('artist')
+        simarts = ans.json().get('similarartists').get('artist')  # pylint: disable=no-member
         if not isinstance(simarts, list):
             raise WSError('Artist found but no similarities returned')
-        for art in ans.json().get('similarartists').get('artist'):
+        for art in ans.json().get('similarartists').get('artist'):  # pylint: disable=no-member
             yield Artist(name=art.get('name'), mbid=art.get('mbid', None))
 
-    def get_toptrack(self, artist=None):
+    def get_toptrack(self, artist):
         """Fetch artist top tracks
+
+        :param sima.lib.meta.Artist artist: `Artist` to fetch top tracks from
+        :returns: generator of :class:`sima.lib.track.Track`
         """
         payload = self._forge_payload(artist, method='top')
         ans = self.http(self.root_url, payload)
-        self._controls_answer(ans.json())
-        tops = ans.json().get('toptracks').get('track')
-        art = {
-                'artist': artist.name,
-                'musicbrainz_artistid': artist.mbid,
-                }
+        self._controls_answer(ans.json())  # pylint: disable=no-member
+        tops = ans.json().get('toptracks').get('track')  # pylint: disable=no-member
+        art = {'artist': artist.name,
+               'musicbrainz_artistid': artist.mbid,}
         for song in tops:
             for key in ['artist', 'streamable', 'listeners',
                         'url', 'image', '@attr']:
@@ -125,7 +136,7 @@ class SimaFM:
                     song.pop(key)
             song.update(art)
             song.update(title=song.pop('name'))
-            song.update(time=song.pop('duration'))
+            song.update(time=song.pop('duration', 0))
             yield Track(**song)
 
 # VIM MODLINE