1 # -*- coding: utf-8 -*-
3 # Copyright (c) 2014 Jack Kaliko <kaliko@azylum.org>
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.
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.
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/>.
21 Consume EchoNest web service
25 __author__ = 'Jack Kaliko'
30 from datetime import datetime, timedelta
31 from time import sleep
33 from requests import get, Timeout, ConnectionError
36 from sima.lib.meta import Artist
37 from sima.utils.utils import getws
38 if len(ECH.get('apikey')) == 23:
42 WAIT_BETWEEN_REQUESTS = timedelta(0, 1)
46 class EchoError(Exception):
49 class EchoNotFound(EchoError):
52 class EchoTimeout(EchoError):
55 class EchoHTTPError(EchoError):
59 def __init__(self, wait):
61 self.last_called = datetime.now()
63 def __call__(self, func):
64 def wrapper(*args, **kwargs):
65 while self.last_called + self.wait > datetime.now():
67 result = func(*args, **kwargs)
68 self.last_called = datetime.now()
74 def __init__(self, elem, last=None):
76 self.requestdate = last
78 self.requestdate = datetime.utcnow()
81 return self.requestdate
90 root_url = 'http://{host}/api/{version}'.format(**ECH)
92 timestamp = datetime.utcnow()
94 def __init__(self, cache=True):
96 self._ressource = None
97 self.current_element = None
101 def _fetch(self, payload):
102 """Use cached elements or proceed http request"""
103 url = Request('GET', self._ressource, params=payload,).prepare().url
104 if url in SimaEch.cache:
105 self.current_element = SimaEch.cache.get(url).elem
108 self._fetch_lfm(payload)
110 raise EchoTimeout('Failed to reach server within {0}s'.format(
112 except ConnectionError as err:
115 @Throttle(WAIT_BETWEEN_REQUESTS)
116 def _fetch_lfm(self, payload):
117 """fetch from web service"""
118 req = get(self._ressource, params=payload,
119 timeout=SOCKET_TIMEOUT)
120 if 'x-ratelimit-remaining' in req.headers:
121 logging.debug('x-ratelimit-remaining {x-ratelimit-remaining}'.format(**req.headers))
122 if req.status_code is not 200:
123 raise EchoHTTPError(req.status_code)
124 self.current_element = req.json()
125 self._controls_answer()
127 SimaEch.cache.update({req.url:
128 Cache(self.current_element)})
130 def _controls_answer(self):
131 """Controls last.fm answer.
133 status = self.current_element.get('response').get('status')
134 code = status.get('code')
138 raise EchoNotFound('Artist not found: "{0}"'.format(self.artist))
139 raise EchoError(status.get('message'))
141 def _forge_payload(self, artist):
144 payload = {'api_key': ECH.get('apikey')}
145 if not isinstance(artist, Artist):
146 raise TypeError('"{0!r}" not an Artist object'.format(artist))
150 id='musicbrainz:artist:{0}'.format(artist.mbid))
152 payload.update(name=artist.name)
153 payload.update(bucket='id:musicbrainz')
154 payload.update(results=30)
157 def purge_cache(self, age=4):
158 now = datetime.utcnow()
159 if now.hour == SimaEch.timestamp.hour:
161 SimaEch.timestamp = datetime.utcnow()
162 cache = SimaEch.cache
163 delta = timedelta(hours=age)
164 for url in list(cache.keys()):
165 timestamp = cache.get(url).created()
166 if now - timestamp > delta:
169 def get_similar(self, artist=None):
172 payload = self._forge_payload(artist)
174 self._ressource = '{0}/artist/similar'.format(SimaEch.root_url)
176 for art in self.current_element.get('response').get('artists'):
179 if 'foreign_ids' in art:
180 for frgnid in art.get('foreign_ids'):
181 if frgnid.get('catalog') == 'musicbrainz':
182 mbid = frgnid.get('foreign_id').lstrip('musicbrainz:artist:')
183 yield Artist(mbid=mbid, name=art.get('name'))
187 # vim: ai ts=4 sw=4 sts=4 expandtab