]> kaliko git repositories - mpd-sima.git/blobdiff - sima/lib/simaecho.py
Code convention cleanup (pylint)
[mpd-sima.git] / sima / lib / simaecho.py
index caf8b5bfbc12b9e21cbd8a3e193f952621581f82..cfae27c675530b086a322c61b08fe85cbae7b945 100644 (file)
 Consume EchoNest web service
 """
 
 Consume EchoNest web service
 """
 
-__version__ = '0.0.2'
+__version__ = '0.0.5'
 __author__ = 'Jack Kaliko'
 
 
 __author__ = 'Jack Kaliko'
 
 
-from datetime import datetime, timedelta
-
-from requests import Session, Request, Timeout, ConnectionError
 
 from sima import ECH
 from sima.lib.meta import Artist
 from sima.lib.track import Track
 
 from sima import ECH
 from sima.lib.meta import Artist
 from sima.lib.track import Track
-from sima.lib.http import CacheController
-from sima.utils.utils import WSError, WSNotFound, WSTimeout, WSHTTPError
-from sima.utils.utils import getws, Throttle
+from sima.lib.http import HttpClient
+from sima.utils.utils import WSError, WSNotFound
+from sima.utils.utils import getws
 if len(ECH.get('apikey')) == 23:  # simple hack allowing imp.reload
     getws(ECH)
 
 if len(ECH.get('apikey')) == 23:  # simple hack allowing imp.reload
     getws(ECH)
 
-# Some definitions
-WAIT_BETWEEN_REQUESTS = timedelta(0, 1)
-SOCKET_TIMEOUT = 4
+
+def get_mbid(obj, foreign='foreign_ids'):
+    if foreign in obj:
+        for frgnid in obj.get(foreign):
+            if frgnid.get('catalog') == 'musicbrainz':
+                return frgnid.get('foreign_id').split(':')[2]
+    return None
 
 
 class SimaEch:
     """EchoNest http client
     """
     root_url = 'http://{host}/api/{version}'.format(**ECH)
 
 
 class SimaEch:
     """EchoNest http client
     """
     root_url = 'http://{host}/api/{version}'.format(**ECH)
-    timestamp = datetime.utcnow()
-    ratelimit = None
     name = 'EchoNest'
     cache = False
     name = 'EchoNest'
     cache = False
+    stats = {'etag':0,
+             'ccontrol':0,
+             'minrl':120,
+             'total':0}
 
     def __init__(self):
 
     def __init__(self):
-        self._ressource = None
-        self.current_element = None
-        self.controller = CacheController(self.cache)
-
-    def _fetch(self, payload):
-        """Use cached elements or proceed http request"""
-        req = Request('GET', self._ressource, params=payload,
-                      ).prepare()
-        if self.cache:
-            cached_response = self.controller.cached_request(req.url, req.headers)
-            if cached_response:
-                return cached_response.json()
-
-        try:
-            return self._fetch_ws(req)
-        except Timeout:
-            raise WSTimeout('Failed to reach server within {0}s'.format(
-                               SOCKET_TIMEOUT))
-        except ConnectionError as err:
-            raise WSError(err)
-
-    @Throttle(WAIT_BETWEEN_REQUESTS)
-    def _fetch_ws(self, prepreq):
-        """fetch from web service"""
-        sess = Session()
-        resp = sess.send(prepreq, timeout=SOCKET_TIMEOUT)
-        self.__class__.ratelimit = resp.headers.get('x-ratelimit-remaining', None)
-        if resp.status_code is not 200:
-            raise WSHTTPError('{0.status_code}: {0.reason}'.format(resp))
-        ans = resp.json()
-        self._controls_answer(ans)
-        if self.cache:
-            self.controller.cache_response(resp.request, resp)
-        return ans
+        self.http = HttpClient(cache=self.cache, stats=self.stats)
 
     def _controls_answer(self, ans):
         """Controls answer.
 
     def _controls_answer(self, ans):
         """Controls answer.
@@ -106,8 +76,7 @@ class SimaEch:
         if not isinstance(artist, Artist):
             raise TypeError('"{0!r}" not an Artist object'.format(artist))
         if artist.mbid:
         if not isinstance(artist, Artist):
             raise TypeError('"{0!r}" not an Artist object'.format(artist))
         if artist.mbid:
-            payload.update(
-                    id='musicbrainz:artist:{0}'.format(artist.mbid))
+            payload.update(id='musicbrainz:artist:{0}'.format(artist.mbid))
         else:
             payload.update(name=artist.name)
         payload.update(bucket='id:musicbrainz')
         else:
             payload.update(name=artist.name)
         payload.update(bucket='id:musicbrainz')
@@ -121,23 +90,20 @@ class SimaEch:
                 payload.update(artist=name)
             payload.update(results=100)
             payload.update(sort='song_hotttnesss-desc')
                 payload.update(artist=name)
             payload.update(results=100)
             payload.update(sort='song_hotttnesss-desc')
-        return payload
+        # > hashing the URL into a cache key
+        # 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):
         """Fetch similar artists
         """
         payload = self._forge_payload(artist)
         # Construct URL
 
     def get_similar(self, artist=None):
         """Fetch similar artists
         """
         payload = self._forge_payload(artist)
         # Construct URL
-        self._ressource = '{0}/artist/similar'.format(SimaEch.root_url)
-        ans = self._fetch(payload)
-        for art in ans.get('response').get('artists'):
-            artist = {}
-            mbid = None
-            if 'foreign_ids' in art:
-                for frgnid in art.get('foreign_ids'):
-                    if frgnid.get('catalog') == 'musicbrainz':
-                        mbid = frgnid.get('foreign_id'
-                                          ).lstrip('musicbrainz:artist:')
+        ressource = '{0}/artist/similar'.format(SimaEch.root_url)
+        ans = self.http(ressource, payload)
+        self._controls_answer(ans.json())  # pylint: disable=no-member
+        for art in ans.json().get('response').get('artists'):  # pylint: disable=no-member
+            mbid = get_mbid(art)
             yield Artist(mbid=mbid, name=art.get('name'))
 
     def get_toptrack(self, artist=None):
             yield Artist(mbid=mbid, name=art.get('name'))
 
     def get_toptrack(self, artist=None):
@@ -145,18 +111,19 @@ class SimaEch:
         """
         payload = self._forge_payload(artist, top=True)
         # Construct URL
         """
         payload = self._forge_payload(artist, top=True)
         # Construct URL
-        self._ressource = '{0}/song/search'.format(SimaEch.root_url)
-        ans = self._fetch(payload)
+        ressource = '{0}/song/search'.format(SimaEch.root_url)
+        ans = self.http(ressource, payload)
+        self._controls_answer(ans.json())  # pylint: disable=no-member
         titles = list()
         titles = list()
-        artist = {
-                'artist': artist.name,
-                'musicbrainz_artistid': artist.mbid,
-                }
-        for song in ans.get('response').get('songs'):
+        art = {'artist': artist.name,
+               'musicbrainz_artistid': artist.mbid,}
+        for song in ans.json().get('response').get('songs'):  # pylint: disable=no-member
             title = song.get('title')
             title = song.get('title')
+            if not art.get('musicbrainz_artistid'):
+                art['musicbrainz_artistid'] = get_mbid(song, 'artist_foreign_ids')
             if title not in titles:
                 titles.append(title)
             if title not in titles:
                 titles.append(title)
-                yield Track(title=title, **artist)
+                yield Track(title=title, **art)
 
 
 # VIM MODLINE
 
 
 # VIM MODLINE