1
2
3 __author__ = "Abhinav Sarkar <abhinav@abhinavsarkar.net>"
4 __version__ = "0.2"
5 __license__ = "GNU Lesser General Public License"
6
7 from lastfm.base import LastfmBase
8 from lastfm.mixins import Cacheable, Shoutable
9 from lastfm.lazylist import lazylist
10 import lastfm.playlist
11 from lastfm.decorators import cached_property, top_property, authenticate
12
13 -class User(LastfmBase, Cacheable, Shoutable):
14 """A class representing an user."""
15 - def init(self,
16 api,
17 name = None,
18 real_name = None,
19 url = None,
20 image = None,
21 stats = None,
22 **kwargs):
38
39 @property
41 """name of the user"""
42 return self._name
43
44 @property
46 """real name of the user"""
47 return self._real_name
48
49 @property
51 """url of the user's page"""
52 return self._url
53
54 @property
56 """image of the user"""
57 return self._image
58
59 @property
61 """stats for the user"""
62 return self._stats
63
64 @property
65 @authenticate
67 """lang for the user"""
68 return self._language
69
70 @property
71 @authenticate
73 """country for the user"""
74 return self._country
75
76 @property
77 @authenticate
79 """age for the user"""
80 return self._age
81
82 @property
83 @authenticate
85 """stats for the user"""
86 return self._gender
87
88 @property
89 @authenticate
91 """is the user a subscriber"""
92 return self._subscriber
93
94 @property
102
103 @cached_property
112
115 params = self._default_params({'method': 'user.getPastEvents'})
116 if limit is not None:
117 params.update({'limit': limit})
118
119 @lazylist
120 def gen(lst):
121 data = self._api._fetch_data(params).find('events')
122 total_pages = int(data.attrib['totalPages'])
123
124 @lazylist
125 def gen2(lst, data):
126 for e in data.findall('event'):
127 yield Event.create_from_data(self._api, e)
128
129 for e in gen2(data):
130 yield e
131
132 for page in xrange(2, total_pages+1):
133 params.update({'page': page})
134 data = self._api._fetch_data(params).find('events')
135 for e in gen2(data):
136 yield e
137 return gen()
138
139 @cached_property
142
143 @authenticate
145 params = {'method': 'user.getRecommendedEvents'}
146 if limit is not None:
147 params.update({'limit': limit})
148
149 @lazylist
150 def gen(lst):
151 data = self._api._fetch_data(params, sign = True, session = True).find('events')
152 total_pages = int(data.attrib['totalPages'])
153
154 @lazylist
155 def gen2(lst, data):
156 for e in data.findall('event'):
157 yield Event.create_from_data(self._api, e)
158
159 for e in gen2(data):
160 yield e
161
162 for page in xrange(2, total_pages+1):
163 params.update({'page': page})
164 data = self._api._fetch_data(params, sign = True, session = True).find('events')
165 for e in gen2(data):
166 yield e
167 return gen()
168
169 @cached_property
172
175 params = self._default_params({'method': 'user.getFriends'})
176 if limit is not None:
177 params.update({'limit': limit})
178 data = self._api._fetch_data(params).find('friends')
179 return [
180 User(
181 self._api,
182 subject = self,
183 name = u.findtext('name'),
184 real_name = u.findtext('realname'),
185 image = dict([(i.get('size'), i.text) for i in u.findall('image')]),
186 url = u.findtext('url'),
187 )
188 for u in data.findall('user')
189 ]
190
191
192 @cached_property
194 """friends of the user"""
195 return self.get_friends()
196
198 params = self._default_params({'method': 'user.getNeighbours'})
199 if limit is not None:
200 params.update({'limit': limit})
201 data = self._api._fetch_data(params).find('neighbours')
202 return [
203 User(
204 self._api,
205 subject = self,
206 name = u.findtext('name'),
207 real_name = u.findtext('realname'),
208 image = {'medium': u.findtext('image')},
209 url = u.findtext('url'),
210 stats = Stats(
211 subject = u.findtext('name'),
212 match = u.findtext('match') and float(u.findtext('match')),
213 ),
214 )
215 for u in data.findall('user')
216 ]
217
218 @cached_property
222
223 @top_property("neighbours")
225 """nearest neightbour of the user"""
226 pass
227
228 @cached_property
230 """playlists of the user"""
231 params = self._default_params({'method': 'user.getPlaylists'})
232 data = self._api._fetch_data(params).find('playlists')
233 return [
234 User.Playlist(
235 self._api,
236 id = int(p.findtext('id')),
237 title = p.findtext('title'),
238 date = datetime(*(
239 time.strptime(
240 p.findtext('date').strip(),
241 '%Y-%m-%dT%H:%M:%S'
242 )[0:6])
243 ),
244 size = int(p.findtext('size')),
245 creator = self
246 )
247 for p in data.findall('playlist')
248 ]
249
250 @authenticate
252 params = {'method': 'playlist.create',
253 'title': title}
254 if description is not None:
255 params['description'] = description
256 self._api._post_data(params)
257 self._playlists = None
258
259 @cached_property
261 params = self._default_params({'method': 'user.getLovedTracks'})
262 data = self._api._fetch_data(params).find('lovedtracks')
263 return [
264 Track(
265 self._api,
266 subject = self,
267 name = t.findtext('name'),
268 artist = Artist(
269 self._api,
270 subject = self,
271 name = t.findtext('artist/name'),
272 mbid = t.findtext('artist/mbid'),
273 url = t.findtext('artist/url'),
274 ),
275 mbid = t.findtext('mbid'),
276 image = dict([(i.get('size'), i.text) for i in t.findall('image')]),
277 loved_on = datetime(*(
278 time.strptime(
279 t.findtext('date').strip(),
280 '%d %b %Y, %H:%M'
281 )[0:6])
282 )
283 )
284 for t in data.findall('track')
285 ]
286
288 params = self._default_params({'method': 'user.getRecentTracks'})
289 data = self._api._fetch_data(params, no_cache = True).find('recenttracks')
290 return [
291 Track(
292 self._api,
293 subject = self,
294 name = t.findtext('name'),
295 artist = Artist(
296 self._api,
297 subject = self,
298 name = t.findtext('artist'),
299 mbid = t.find('artist').attrib['mbid'],
300 ),
301 album = Album(
302 self._api,
303 subject = self,
304 name = t.findtext('album'),
305 artist = Artist(
306 self._api,
307 subject = self,
308 name = t.findtext('artist'),
309 mbid = t.find('artist').attrib['mbid'],
310 ),
311 mbid = t.find('album').attrib['mbid'],
312 ),
313 mbid = t.findtext('mbid'),
314 streamable = (t.findtext('streamable') == '1'),
315 url = t.findtext('url'),
316 image = dict([(i.get('size'), i.text) for i in t.findall('image')]),
317 played_on = datetime(*(
318 time.strptime(
319 t.findtext('date').strip(),
320 '%d %b %Y, %H:%M'
321 )[0:6])
322 )
323 )
324 for t in data.findall('track')
325 ]
326
327 @property
331
332 @top_property("recent_tracks")
334 """most recent track played by the user"""
335 pass
336
338 params = self._default_params({'method': 'user.getTopAlbums'})
339 if period is not None:
340 params.update({'period': period})
341 data = self._api._fetch_data(params).find('topalbums')
342
343 return [
344 Album(
345 self._api,
346 subject = self,
347 name = a.findtext('name'),
348 artist = Artist(
349 self._api,
350 subject = self,
351 name = a.findtext('artist/name'),
352 mbid = a.findtext('artist/mbid'),
353 url = a.findtext('artist/url'),
354 ),
355 mbid = a.findtext('mbid'),
356 url = a.findtext('url'),
357 image = dict([(i.get('size'), i.text) for i in a.findall('image')]),
358 stats = Stats(
359 subject = a.findtext('name'),
360 playcount = int(a.findtext('playcount')),
361 rank = int(a.attrib['rank'])
362 )
363 )
364 for a in data.findall('album')
365 ]
366
367 @cached_property
369 """overall top albums of the user"""
370 return self.get_top_albums()
371
372 @top_property("top_albums")
374 """overall top most album of the user"""
375 pass
376
378 params = self._default_params({'method': 'user.getTopArtists'})
379 if period is not None:
380 params.update({'period': period})
381 data = self._api._fetch_data(params).find('topartists')
382
383 return [
384 Artist(
385 self._api,
386 subject = self,
387 name = a.findtext('name'),
388 mbid = a.findtext('mbid'),
389 stats = Stats(
390 subject = a.findtext('name'),
391 rank = a.attrib['rank'].strip() and int(a.attrib['rank']) or None,
392 playcount = a.findtext('playcount') and int(a.findtext('playcount')) or None
393 ),
394 url = a.findtext('url'),
395 streamable = (a.findtext('streamable') == "1"),
396 image = dict([(i.get('size'), i.text) for i in a.findall('image')]),
397 )
398 for a in data.findall('artist')
399 ]
400
401 @cached_property
405
406 @top_property("top_artists")
408 """top artist of the user"""
409 pass
410
411 @cached_property
412 @authenticate
414 params = {'method': 'user.getRecommendedArtists'}
415
416 @lazylist
417 def gen(lst):
418 data = self._api._fetch_data(params, sign = True, session = True).find('recommendations')
419 total_pages = int(data.attrib['totalPages'])
420
421 @lazylist
422 def gen2(lst, data):
423 for a in data.findall('artist'):
424 yield Artist(
425 self._api,
426 name = a.findtext('name'),
427 mbid = a.findtext('mbid'),
428 url = a.findtext('url'),
429 streamable = (a.findtext('streamable') == "1"),
430 image = dict([(i.get('size'), i.text) for i in a.findall('image')]),
431 )
432
433 for a in gen2(data):
434 yield a
435
436 for page in xrange(2, total_pages+1):
437 params.update({'page': page})
438 data = self._api._fetch_data(params, sign = True, session = True).find('recommendations')
439 for a in gen2(data):
440 yield a
441 return gen()
442
444 params = self._default_params({'method': 'user.getTopTracks'})
445 if period is not None:
446 params.update({'period': period})
447 data = self._api._fetch_data(params).find('toptracks')
448 return [
449 Track(
450 self._api,
451 subject = self,
452 name = t.findtext('name'),
453 artist = Artist(
454 self._api,
455 subject = self,
456 name = t.findtext('artist/name'),
457 mbid = t.findtext('artist/mbid'),
458 url = t.findtext('artist/url'),
459 ),
460 mbid = t.findtext('mbid'),
461 stats = Stats(
462 subject = t.findtext('name'),
463 rank = t.attrib['rank'].strip() and int(t.attrib['rank']) or None,
464 playcount = t.findtext('playcount') and int(t.findtext('playcount')) or None
465 ),
466 streamable = (t.findtext('streamable') == '1'),
467 full_track = (t.find('streamable').attrib['fulltrack'] == '1'),
468 image = dict([(i.get('size'), i.text) for i in t.findall('image')]),
469 )
470 for t in data.findall('track')
471 ]
472
473 @cached_property
477
478 @top_property("top_tracks")
482
501
502 @cached_property
506
507 @top_property("top_tags")
509 """top tag of the user"""
510 pass
511
512 @cached_property
520
528
529 @cached_property
532
533 @cached_property
544 return gen()
545
553
554 @cached_property
557
558 @cached_property
569 return gen()
570
578
579 @cached_property
582
583 @cached_property
594 return gen()
595
601
602 @cached_property
605
606 @cached_property
617 return gen()
618
619 - def compare(self, other, limit = None):
626 @property
629
630 @staticmethod
640
641 @staticmethod
656
658 if not self.name:
659 raise InvalidParametersError("user has to be provided.")
660 params = {'user': self.name}
661 params.update(extra_params)
662 return params
663
664 @staticmethod
666 try:
667 return hash(kwds['name'])
668 except KeyError:
669 raise InvalidParametersError("name has to be provided for hashing")
670
673
676
679
681 return "<lastfm.User: %s>" % self.name
682
683 - class Playlist(lastfm.playlist.Playlist):
684 """A class representing a playlist belonging to the user."""
685 - def init(self, api, id, title, date, size, creator):
692
693 @property
696
697 @property
700
701 @property
704
705 @property
708
709 @property
712
713 @property
716
717 @authenticate
733
734 @staticmethod
736 try:
737 return hash(kwds['id'])
738 except KeyError:
739 raise InvalidParametersError("id has to be provided for hashing")
740
743
745 return "<lastfm.User.Playlist: %s>" % self.title
746
748 """A class representing the music library of the user."""
750 self._api = api
751 self._user = user
752
753 @property
756
759 params = self._default_params({'method': 'library.getAlbums'})
760 if limit is not None:
761 params.update({'limit': limit})
762
763 @lazylist
764 def gen(lst):
765 data = self._api._fetch_data(params).find('albums')
766 total_pages = int(data.attrib['totalPages'])
767
768 @lazylist
769 def gen2(lst, data):
770 for a in data.findall('album'):
771 yield Album(
772 self._api,
773 subject = self,
774 name = a.findtext('name'),
775 artist = Artist(
776 self._api,
777 subject = self,
778 name = a.findtext('artist/name'),
779 mbid = a.findtext('artist/mbid'),
780 url = a.findtext('artist/url'),
781 ),
782 mbid = a.findtext('mbid'),
783 url = a.findtext('url'),
784 image = dict([(i.get('size'), i.text) for i in a.findall('image')]),
785 stats = Stats(
786 subject = a.findtext('name'),
787 playcount = int(a.findtext('playcount')),
788 )
789 )
790
791
792 for a in gen2(data):
793 yield a
794
795 for page in xrange(2, total_pages+1):
796 params.update({'page': page})
797 try:
798 data = self._api._fetch_data(params).find('albums')
799 except LastfmError:
800 continue
801 for a in gen2(data):
802 yield a
803 return gen()
804
805 @cached_property
808
809 @authenticate
826
829 params = self._default_params({'method': 'library.getArtists'})
830 if limit is not None:
831 params.update({'limit': limit})
832
833 @lazylist
834 def gen(lst):
835 data = self._api._fetch_data(params).find('artists')
836 total_pages = int(data.attrib['totalPages'])
837
838 @lazylist
839 def gen2(lst, data):
840 for a in data.findall('artist'):
841 yield Artist(
842 self._api,
843 subject = self,
844 name = a.findtext('name'),
845 mbid = a.findtext('mbid'),
846 stats = Stats(
847 subject = a.findtext('name'),
848 playcount = a.findtext('playcount') and int(a.findtext('playcount')) or None,
849 tagcount = a.findtext('tagcount') and int(a.findtext('tagcount')) or None
850 ),
851 url = a.findtext('url'),
852 streamable = (a.findtext('streamable') == "1"),
853 image = dict([(i.get('size'), i.text) for i in a.findall('image')]),
854 )
855
856 for a in gen2(data):
857 yield a
858
859 for page in xrange(2, total_pages+1):
860 params.update({'page': page})
861 try:
862 data = self._api._fetch_data(params).find('artists')
863 except LastfmError:
864 continue
865 for a in gen2(data):
866 yield a
867 return gen()
868
869 @cached_property
872
873 @authenticate
875 params = {'method': 'library.addArtist'}
876 if isinstance(artist, Artist):
877 params['artist'] = artist.name
878 else:
879 params['artist'] = artist
880 self._api._post_data(params)
881 self._artists = None
882
885 params = self._default_params({'method': 'library.getTracks'})
886 if limit is not None:
887 params.update({'limit': limit})
888
889 @lazylist
890 def gen(lst):
891 data = self._api._fetch_data(params).find('tracks')
892 total_pages = int(data.attrib['totalPages'])
893
894 @lazylist
895 def gen2(lst, data):
896 for t in data.findall('track'):
897 yield Track(
898 self._api,
899 subject = self,
900 name = t.findtext('name'),
901 artist = Artist(
902 self._api,
903 subject = self,
904 name = t.findtext('artist/name'),
905 mbid = t.findtext('artist/mbid'),
906 url = t.findtext('artist/url'),
907 ),
908 mbid = t.findtext('mbid'),
909 stats = Stats(
910 subject = t.findtext('name'),
911 playcount = t.findtext('playcount') and int(t.findtext('playcount')) or None,
912 tagcount = t.findtext('tagcount') and int(t.findtext('tagcount')) or None
913 ),
914 streamable = (t.findtext('streamable') == '1'),
915 full_track = (t.find('streamable').attrib['fulltrack'] == '1'),
916 image = dict([(i.get('size'), i.text) for i in t.findall('image')]),
917 )
918
919 for t in gen2(data):
920 yield t
921
922 for page in xrange(2, total_pages+1):
923 params.update({'page': page})
924 data = None
925 try:
926 data = self._api._fetch_data(params).find('tracks')
927 except LastfmError:
928 continue
929 for t in gen2(data):
930 yield t
931 return gen()
932
933 @cached_property
936
937 @authenticate
953
960
961 @staticmethod
963 try:
964 return hash(kwds['user'])
965 except KeyError:
966 raise InvalidParametersError("user has to be provided for hashing")
967
970
972 return "<lastfm.User.Library: for user '%s'>" % self.user.name
973
974 from datetime import datetime
975 import time
976
977 from lastfm.api import Api
978 from lastfm.artist import Artist
979 from lastfm.album import Album
980 from lastfm.error import LastfmError, InvalidParametersError, AuthenticationFailedError
981 from lastfm.event import Event
982 from lastfm.geo import Country
983 from lastfm.stats import Stats
984 from lastfm.tag import Tag
985 from lastfm.tasteometer import Tasteometer
986 from lastfm.track import Track
987 from lastfm.weeklychart import WeeklyChart, WeeklyAlbumChart, WeeklyArtistChart, WeeklyTrackChart, WeeklyTagChart
988