]> kaliko git repositories - mpd-sima.git/blob - sima/lib/simaecho.py
Propagate Artist type
[mpd-sima.git] / sima / lib / simaecho.py
1 # -*- coding: utf-8 -*-
2
3 # Copyright (c) 2014 Jack Kaliko <kaliko@azylum.org>
4 #
5 #   This program is free software: you can redistribute it and/or modify
6 #   it under the terms of the GNU General Public License as published by
7 #   the Free Software Foundation, either version 3 of the License, or
8 #   (at your option) any later version.
9 #
10 #   This program is distributed in the hope that it will be useful,
11 #   but WITHOUT ANY WARRANTY; without even the implied warranty of
12 #   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 #   GNU General Public License for more details.
14 #
15 #   You should have received a copy of the GNU General Public License
16 #   along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 #
18 #
19
20 """
21 Consume EchoNest web service
22 """
23
24 __version__ = '0.0.4'
25 __author__ = 'Jack Kaliko'
26
27
28
29 from sima import ECH
30 from sima.lib.meta import Artist
31 from sima.lib.track import Track
32 from sima.lib.http import HttpClient
33 from sima.utils.utils import WSError, WSNotFound
34 from sima.utils.utils import getws
35 if len(ECH.get('apikey')) == 23:  # simple hack allowing imp.reload
36     getws(ECH)
37
38
39 class SimaEch:
40     """EchoNest http client
41     """
42     root_url = 'http://{host}/api/{version}'.format(**ECH)
43     ratelimit = None
44     name = 'EchoNest'
45     cache = False
46     stats = {'etag':0,
47              'ccontrol':0,
48              'minrl':120,
49              'total':0}
50
51     def __init__(self):
52         self.http = HttpClient(cache=self.cache, stats=self.stats)
53
54     def _controls_answer(self, ans):
55         """Controls answer.
56         """
57         status = ans.get('response').get('status')
58         code = status.get('code')
59         if code is 0:
60             return True
61         if code is 5:
62             raise WSNotFound('Artist not found')
63         raise WSError(status.get('message'))
64
65     def _forge_payload(self, artist, top=False):
66         """Build payload
67         """
68         payload = {'api_key': ECH.get('apikey')}
69         if not isinstance(artist, Artist):
70             raise TypeError('"{0!r}" not an Artist object'.format(artist))
71         if artist.mbid:
72             payload.update(
73                     id='musicbrainz:artist:{0}'.format(artist.mbid))
74         else:
75             payload.update(name=artist.name)
76         payload.update(bucket='id:musicbrainz')
77         payload.update(results=100)
78         if top:
79             if artist.mbid:
80                 aid = payload.pop('id')
81                 payload.update(artist_id=aid)
82             else:
83                 name = payload.pop('name')
84                 payload.update(artist=name)
85             payload.update(results=100)
86             payload.update(sort='song_hotttnesss-desc')
87         # > hashing the URL into a cache key
88         # return a sorted list of 2-tuple to have consistent cache
89         return sorted(payload.items(), key=lambda param: param[0])
90
91     def get_similar(self, artist=None):
92         """Fetch similar artists
93         """
94         payload = self._forge_payload(artist)
95         # Construct URL
96         ressource = '{0}/artist/similar'.format(SimaEch.root_url)
97         ans = self.http(ressource, payload)
98         self._controls_answer(ans.json())
99         for art in ans.json().get('response').get('artists'):
100             mbid = None
101             if 'foreign_ids' in art:
102                 for frgnid in art.get('foreign_ids'):
103                     if frgnid.get('catalog') == 'musicbrainz':
104                         mbid = frgnid.get('foreign_id'
105                                 ).split(':')[2]
106             yield Artist(mbid=mbid, name=art.get('name'))
107
108     def get_toptrack(self, artist=None):
109         """Fetch artist top tracks
110         """
111         payload = self._forge_payload(artist, top=True)
112         # Construct URL
113         ressource = '{0}/song/search'.format(SimaEch.root_url)
114         ans = self.http(ressource, payload)
115         self._controls_answer(ans.json())
116         titles = list()
117         art = {
118                 'artist': artist.name,
119                 'musicbrainz_artistid': artist.mbid,
120                 }
121         for song in ans.json().get('response').get('songs'):
122             title = song.get('title')
123             if title not in titles:
124                 titles.append(title)
125                 yield Track(title=title, **art)
126
127
128 # VIM MODLINE
129 # vim: ai ts=4 sw=4 sts=4 expandtab