1
2 """Module for calling Artist related last.fm web services API methods"""
3
4 __author__ = "Abhinav Sarkar <abhinav@abhinavsarkar.net>"
5 __version__ = "0.2"
6 __license__ = "GNU Lesser General Public License"
7
8 from lastfm.base import LastfmBase
9 from lastfm.mixins import Cacheable, Searchable, Sharable, Shoutable, Taggable
10 from lastfm.lazylist import lazylist
11 from lastfm.decorators import cached_property, top_property
12
13 -class Artist(LastfmBase, Cacheable, Sharable, Shoutable, Searchable, Taggable):
14 """A class representing an artist."""
15 - def init(self,
16 api,
17 name = None,
18 mbid = None,
19 url = None,
20 image = None,
21 streamable = None,
22 stats = None,
23 similar = None,
24 top_tags = None,
25 bio = None,
26 subject = None):
27 """
28 Create an Artist object by providing all the data related to it.
29
30 @param api: an instance of L{Api}
31 @type api: L{Api}
32 @param name: the artist name
33 @type name: L{str}
34 @param mbid: MBID of the artist
35 @type mbid: L{str}
36 @param url: URL of the artist on last.fm
37 @type url: L{str}
38 @param image: the images of the artist in various sizes
39 @type image: L{dict}
40 @param streamable: flag indicating if the artist is streamable from last.fm
41 @type streamable: L{bool}
42 @param stats: the artist statistics
43 @type stats: L{Stats}
44 @param similar: artists similar to the provided artist
45 @type similar: L{list} of L{Artist}
46 @param top_tags: top tags for the artist
47 @type top_tags: L{list} of L{Tag}
48 @param bio: biography of the artist
49 @type bio: L{Wiki}
50 @param subject: the subject to which this instance belongs to
51 @type subject: L{User} OR L{Artist} OR L{Tag} OR L{Track} OR L{WeeklyChart}
52
53 @raise InvalidParametersError: If an instance of L{Api} is not provided as the first
54 parameter then an Exception is raised.
55 """
56 if not isinstance(api, Api):
57 raise InvalidParametersError("api reference must be supplied as an argument")
58 Sharable.init(self, api)
59 Shoutable.init(self, api)
60 Taggable.init(self, api)
61
62 self._api = api
63 self._name = name
64 self._mbid = mbid
65 self._url = url
66 self._image = image
67 self._streamable = streamable
68 self._stats = stats and Stats(
69 subject = self,
70 listeners = stats.listeners,
71 playcount = stats.playcount,
72 weight = stats.weight,
73 match = stats.match,
74 rank = stats.rank
75 )
76 self._similar = similar
77 self._top_tags = top_tags
78 self._bio = bio and Wiki(
79 subject = self,
80 published = bio.published,
81 summary = bio.summary,
82 content = bio.content
83 )
84 self._subject = subject
85
86 @property
88 """
89 name of the artist
90 @rtype: L{str}
91 """
92 return self._name
93
94 @property
96 """
97 MBID of the artist
98 @rtype: L{str}
99 """
100 if self._mbid is None:
101 self._fill_info()
102 return self._mbid
103
104 @property
106 """
107 url of the artist's page
108 @rtype: L{str}
109 """
110 if self._url is None:
111 self._fill_info()
112 return self._url
113
114 @property
116 """
117 images of the artist
118 @rtype: L{dict}
119 """
120 if self._image is None:
121 self._fill_info()
122 return self._image
123
124 @property
126 """
127 is the artist streamable on last.fm
128 @rtype: L{bool}
129 """
130 if self._streamable is None:
131 self._fill_info()
132 return self._streamable
133
134 @property
136 """
137 stats for the artist
138 @rtype: L{Stats}
139 """
140 if self._stats is None:
141 self._fill_info()
142 return self._stats
143
145 """
146 Get the artists similar to this artist.
147
148 @param limit: the number of artists returned (optional)
149 @type limit: L{int}
150
151 @return: artists similar to this artist
152 @rtype: L{list} of L{Artist}
153 """
154 params = self._default_params({'method': 'artist.getSimilar'})
155 if limit is not None:
156 params.update({'limit': limit})
157 data = self._api._fetch_data(params).find('similarartists')
158 self._similar = [
159 Artist(
160 self._api,
161 subject = self,
162 name = a.findtext('name'),
163 mbid = a.findtext('mbid'),
164 stats = Stats(
165 subject = a.findtext('name'),
166 match = float(a.findtext('match')),
167 ),
168 url = 'http://' + a.findtext('url'),
169 image = {'large': a.findtext('image')}
170 )
171 for a in data.findall('artist')
172 ]
173 return self._similar[:]
174
175 @property
177 """
178 artists similar to this artist
179 @rtype: L{list} of L{Artist}
180 """
181 if self._similar is None or len(self._similar) < 6:
182 return self.get_similar()
183 return self._similar[:]
184
185 @top_property("similar")
187 """
188 artist most similar to this artist
189 @rtype: L{Artist}
190 """
191 pass
192
193 @property
212
213 @top_property("top_tags")
215 """
216 top tag for the artist
217 @rtype: L{Tag}
218 """
219 pass
220
221 @property
223 """
224 biography of the artist
225 @rtype: L{Wiki}
226 """
227 if self._bio is None:
228 self._fill_info()
229 return self._bio
230
231 @cached_property
233 """
234 events for the artist
235 @rtype: L{lazylist} of L{Event}
236 """
237 params = self._default_params({'method': 'artist.getEvents'})
238 data = self._api._fetch_data(params).find('events')
239
240 return [
241 Event.create_from_data(self._api, e)
242 for e in data.findall('event')
243 ]
244
245 @cached_property
247 """
248 top albums of the artist
249 @rtype: L{list} of L{Album}
250 """
251 params = self._default_params({'method': 'artist.getTopAlbums'})
252 data = self._api._fetch_data(params).find('topalbums')
253
254 return [
255 Album(
256 self._api,
257 subject = self,
258 name = a.findtext('name'),
259 artist = self,
260 mbid = a.findtext('mbid'),
261 url = a.findtext('url'),
262 image = dict([(i.get('size'), i.text) for i in a.findall('image')]),
263 stats = Stats(
264 subject = a.findtext('name'),
265 playcount = int(a.findtext('playcount')),
266 rank = int(a.attrib['rank'])
267 )
268 )
269 for a in data.findall('album')
270 ]
271
272 @top_property("top_albums")
274 """
275 top album of the artist
276 @rtype: L{Album}
277 """
278 pass
279
280 @cached_property
282 """
283 top fans of the artist
284 @rtype: L{list} of L{User}
285 """
286 params = self._default_params({'method': 'artist.getTopFans'})
287 data = self._api._fetch_data(params).find('topfans')
288 return [
289 User(
290 self._api,
291 subject = self,
292 name = u.findtext('name'),
293 url = u.findtext('url'),
294 image = dict([(i.get('size'), i.text) for i in u.findall('image')]),
295 stats = Stats(
296 subject = u.findtext('name'),
297 weight = int(u.findtext('weight'))
298 )
299 )
300 for u in data.findall('user')
301 ]
302
303 @top_property("top_fans")
305 """
306 top fan of the artist
307 @rtype: L{User}"""
308 pass
309
310 @cached_property
312 """
313 top tracks of the artist
314 @rtype: L{list} of L{Track}
315 """
316 params = self._default_params({'method': 'artist.getTopTracks'})
317 data = self._api._fetch_data(params).find('toptracks')
318 return [
319 Track(
320 self._api,
321 subject = self,
322 name = t.findtext('name'),
323 artist = self,
324 mbid = t.findtext('mbid'),
325 stats = Stats(
326 subject = t.findtext('name'),
327 playcount = int(t.findtext('playcount')),
328 rank = int(t.attrib['rank'])
329 ),
330 streamable = (t.findtext('streamable') == '1'),
331 full_track = (t.find('streamable').attrib['fulltrack'] == '1'),
332 image = dict([(i.get('size'), i.text) for i in t.findall('image')]),
333 )
334 for t in data.findall('track')
335 ]
336
337 @top_property("top_tracks")
339 """
340 topmost track of the artist
341 @rtype: L{Track}
342 """
343 pass
344
345 @staticmethod
346 - def get_info(api, artist = None, mbid = None):
347 """
348 Get the data for the artist.
349
350 @param api: an instance of L{Api}
351 @type api: L{Api}
352 @param artist: the name of the artist
353 @type artist: L{str}
354 @param mbid: MBID of the artist
355 @type mbid: L{str}
356
357 @return: an Artist object corresponding the provided artist name
358 @rtype: L{Artist}
359
360 @raise lastfm.InvalidParametersError: Either artist or mbid parameter has to
361 be provided. Otherwise exception is raised.
362
363 @note: Use the L{Api.get_artist} method instead of using this method directly.
364 """
365 data = Artist._fetch_data(api, artist, mbid)
366
367 a = Artist(api, name = data.findtext('name'))
368 a._fill_info()
369 return a
370
372 if not self.name:
373 raise InvalidParametersError("artist has to be provided.")
374 params = {'artist': self.name}
375 params.update(extra_params)
376 return params
377
378 @staticmethod
379 - def _fetch_data(api,
380 artist = None,
381 mbid = None):
390
392 data = Artist._fetch_data(self._api, self.name)
393 self._name = data.findtext('name')
394 self._mbid = data.findtext('mbid')
395 self._url = data.findtext('url')
396 self._image = dict([(i.get('size'), i.text) for i in data.findall('image')])
397 self._streamable = (data.findtext('streamable') == 1)
398 if not self._stats:
399 self._stats = Stats(
400 subject = self,
401 listeners = int(data.findtext('stats/listeners')),
402 playcount = int(data.findtext('stats/playcount'))
403 )
404 self._similar = [
405 Artist(
406 self._api,
407 subject = self,
408 name = a.findtext('name'),
409 url = a.findtext('url'),
410 image = dict([(i.get('size'), i.text) for i in a.findall('image')])
411 )
412 for a in data.findall('similar/artist')
413 ]
414 self._top_tags = [
415 Tag(
416 self._api,
417 subject = self,
418 name = t.findtext('name'),
419 url = t.findtext('url')
420 )
421 for t in data.findall('tags/tag')
422 ]
423 self._bio = Wiki(
424 self,
425 published = data.findtext('bio/published').strip() and
426 datetime(*(time.strptime(
427 data.findtext('bio/published').strip(),
428 '%a, %d %b %Y %H:%M:%S +0000'
429 )[0:6])),
430 summary = data.findtext('bio/summary'),
431 content = data.findtext('bio/content')
432 )
433
434 @staticmethod
444 @staticmethod
446 try:
447 return hash(kwds['name'].lower())
448 except KeyError:
449 try:
450 return hash(args[1].lower())
451 except IndexError:
452 raise InvalidParametersError("name has to be provided for hashing")
453
456
463
466
468 return "<lastfm.Artist: %s>" % self._name
469
470 from datetime import datetime
471 import time
472
473 from lastfm.album import Album
474 from lastfm.api import Api
475 from lastfm.error import InvalidParametersError
476 from lastfm.event import Event
477 from lastfm.stats import Stats
478 from lastfm.tag import Tag
479 from lastfm.track import Track
480 from lastfm.user import User
481 from lastfm.wiki import Wiki
482