Package lastfm :: Module user

[hide private]
[frames] | no frames]

# Source Code for Module lastfm.user

      1  #!/usr/bin/env python
      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):
     23          if not isinstance(api, Api):
     24              raise InvalidParametersError("api reference must be supplied as an argument")
     25          Shoutable.init(self, api)
     26          self._api = api
     27          self._name = name
     28          self._real_name = real_name
     29          self._url = url
     30          self._image = image
     31          self._stats = stats and Stats(
     32                               subject = self,
     33                               match = stats.match,
     34                               weight = stats.weight,
     35                               playcount = stats.playcount
     36                              )
     37          self._library = User.Library(api, self)
     38
     39      @property
     40 -    def name(self):
     41          """name of the user"""
     42          return self._name
     43
     44      @property
     45 -    def real_name(self):
     46          """real name of the user"""
     47          return self._real_name
     48
     49      @property
     50 -    def url(self):
     51          """url of the user's page"""
     52          return self._url
     53
     54      @property
     55 -    def image(self):
     56          """image of the user"""
     57          return self._image
     58
     59      @property
     60 -    def stats(self):
     61          """stats for the user"""
     62          return self._stats
     63
     64      @property
     65      @authenticate
     66 -    def language(self):
     67          """lang for the user"""
     68          return self._language
     69
     70      @property
     71      @authenticate
     72 -    def country(self):
     73          """country for the user"""
     74          return self._country
     75
     76      @property
     77      @authenticate
     78 -    def age(self):
     79          """age for the user"""
     80          return self._age
     81
     82      @property
     83      @authenticate
     84 -    def gender(self):
     85          """stats for the user"""
     86          return self._gender
     87
     88      @property
     89      @authenticate
     90 -    def subscriber(self):
     91          """is the user a subscriber"""
     92          return self._subscriber
     93
     94      @property
     95 -    def authenticated(self):
     96          """is the user authenticated"""
     97          try:
     98              auth_user = self._api.get_authenticated_user()
     99              return auth_user == self
    100          except AuthenticationFailedError:
    101              return False
    102
    103      @cached_property
    104 -    def events(self):
    105          params = self._default_params({'method': 'user.getEvents'})
    106          data = self._api._fetch_data(params).find('events')
    107
    108          return [
    109                  Event.create_from_data(self._api, e)
    110                  for e in data.findall('event')
    111                  ]
    112
    113 -    def get_past_events(self,
    114                        limit = None):
    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
    140 -    def past_events(self):
    141          return self.get_past_events()
    142
    143      @authenticate
    144 -    def get_recommended_events(self, limit = None):
    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
    170 -    def recommended_events(self):
    171          return self.get_recommended_events()
    172
    173 -    def get_friends(self,
    174                     limit = None):
    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
    193 -    def friends(self):
    194          """friends of the user"""
    195          return self.get_friends()
    196
    197 -    def get_neighbours(self, limit = None):
    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
    219 -    def neighbours(self):
    220          """neighbours of the user"""
    221          return self.get_neighbours()
    222
    223      @top_property("neighbours")
    224 -    def nearest_neighbour(self):
    225          """nearest neightbour of the user"""
    226          pass
    227
    228      @cached_property
    229 -    def playlists(self):
    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
    251 -    def create_playlist(self, title, description = None):
    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
    260 -    def loved_tracks(self):
    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
    287 -    def get_recent_tracks(self, limit = None):
    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
    328 -    def recent_tracks(self):
    329          """recent tracks played by the user"""
    330          return self.get_recent_tracks()
    331
    332      @top_property("recent_tracks")
    333 -    def most_recent_track(self):
    334          """most recent track played by the user"""
    335          pass
    336
    337 -    def get_top_albums(self, period = None):
    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
    368 -    def top_albums(self):
    369          """overall top albums of the user"""
    370          return self.get_top_albums()
    371
    372      @top_property("top_albums")
    373 -    def top_album(self):
    374          """overall top most album of the user"""
    375          pass
    376
    377 -    def get_top_artists(self, period = None):
    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
    402 -    def top_artists(self):
    403          """top artists of the user"""
    404          return self.get_top_artists()
    405
    406      @top_property("top_artists")
    407 -    def top_artist(self):
    408          """top artist of the user"""
    409          pass
    410
    411      @cached_property
    412      @authenticate
    413 -    def recommended_artists(self):
    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
    443 -    def get_top_tracks(self, period = None):
    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
    474 -    def top_tracks(self):
    475          """top tracks of the user"""
    476          return self.get_top_tracks()
    477
    478      @top_property("top_tracks")
    479 -    def top_track(self):
    480          """top track of the user"""
    481          return (len(self.top_tracks) and self.top_tracks[0] or None)
    482
    483 -    def get_top_tags(self, limit = None):
    484          params = self._default_params({'method': 'user.getTopTags'})
    485          if limit is not None:
    486              params.update({'limit': limit})
    487          data = self._api._fetch_data(params).find('toptags')
    488          return [
    489                  Tag(
    490                      self._api,
    491                      subject = self,
    492                      name = t.findtext('name'),
    493                      url = t.findtext('url'),
    494                      stats = Stats(
    495                                    subject = t.findtext('name'),
    496                                    count = int(t.findtext('count'))
    497                                    )
    498                      )
    499                  for t in data.findall('tag')
    500                  ]
    501
    502      @cached_property
    503 -    def top_tags(self):
    504          """top tags of the user"""
    505          return self.get_top_tags()
    506
    507      @top_property("top_tags")
    508 -    def top_tag(self):
    509          """top tag of the user"""
    510          pass
    511
    512      @cached_property
    513 -    def weekly_chart_list(self):
    514          params = self._default_params({'method': 'user.getWeeklyChartList'})
    515          data = self._api._fetch_data(params).find('weeklychartlist')
    516          return [
    517                  WeeklyChart.create_from_data(self._api, self, c)
    518                  for c in data.findall('chart')
    519                  ]
    520
    521 -    def get_weekly_album_chart(self,
    522                               start = None,
    523                               end = None):
    524          params = self._default_params({'method': 'user.getWeeklyAlbumChart'})
    525          params = WeeklyChart._check_weekly_chart_params(params, start, end)
    526          data = self._api._fetch_data(params).find('weeklyalbumchart')
    527          return WeeklyAlbumChart.create_from_data(self._api, self, data)
    528
    529      @cached_property
    530 -    def recent_weekly_album_chart(self):
    531          return self.get_weekly_album_chart()
    532
    533      @cached_property
    534 -    def weekly_album_chart_list(self):
    535          wcl = list(self.weekly_chart_list)
    536          wcl.reverse()
    537          @lazylist
    538          def gen(lst):
    539              for wc in wcl:
    540                  try:
    541                      yield self.get_weekly_album_chart(wc.start, wc.end)
    542                  except LastfmError:
    543                      pass
    544          return gen()
    545
    546 -    def get_weekly_artist_chart(self,
    547                               start = None,
    548                               end = None):
    549          params = self._default_params({'method': 'user.getWeeklyArtistChart'})
    550          params = WeeklyChart._check_weekly_chart_params(params, start, end)
    551          data = self._api._fetch_data(params).find('weeklyartistchart')
    552          return WeeklyArtistChart.create_from_data(self._api, self, data)
    553
    554      @cached_property
    555 -    def recent_weekly_artist_chart(self):
    556          return self.get_weekly_artist_chart()
    557
    558      @cached_property
    559 -    def weekly_artist_chart_list(self):
    560          wcl = list(self.weekly_chart_list)
    561          wcl.reverse()
    562          @lazylist
    563          def gen(lst):
    564              for wc in wcl:
    565                  try:
    566                      yield self.get_weekly_artist_chart(wc.start, wc.end)
    567                  except LastfmError:
    568                      pass
    569          return gen()
    570
    571 -    def get_weekly_track_chart(self,
    572                               start = None,
    573                               end = None):
    574          params = self._default_params({'method': 'user.getWeeklyTrackChart'})
    575          params = WeeklyChart._check_weekly_chart_params(params, start, end)
    576          data = self._api._fetch_data(params).find('weeklytrackchart')
    577          return WeeklyTrackChart.create_from_data(self._api, self, data)
    578
    579      @cached_property
    580 -    def recent_weekly_track_chart(self):
    581          return self.get_weekly_track_chart()
    582
    583      @cached_property
    584 -    def weekly_track_chart_list(self):
    585          wcl = list(self.weekly_chart_list)
    586          wcl.reverse()
    587          @lazylist
    588          def gen(lst):
    589              for wc in wcl:
    590                  try:
    591                      yield self.get_weekly_track_chart(wc.start, wc.end)
    592                  except LastfmError:
    593                      pass
    594          return gen()
    595
    596 -    def get_weekly_tag_chart(self,
    597                               start = None,
    598                               end = None):
    599          WeeklyChart._check_weekly_chart_params({}, start, end)
    600          return WeeklyTagChart.create_from_data(self._api, self, start, end)
    601
    602      @cached_property
    603 -    def recent_weekly_tag_chart(self):
    604          return self.get_weekly_tag_chart()
    605
    606      @cached_property
    607 -    def weekly_tag_chart_list(self):
    608          wcl = list(self.weekly_chart_list)
    609          wcl.reverse()
    610          @lazylist
    611          def gen(lst):
    612              for wc in wcl:
    613                  try:
    614                      yield self.get_weekly_tag_chart(wc.start, wc.end)
    615                  except LastfmError:
    616                      pass
    617          return gen()
    618
    619 -    def compare(self, other, limit = None):
    620          if isinstance(other, User):
    621              other = other.name
    622          return Tasteometer.compare(self._api,
    623                                     'user', 'user',
    624                                     self.name, other,
    625                                     limit)
    626      @property
    627 -    def library(self):
    628          return self._library
    629
    630      @staticmethod
    631 -    def get_info(api, name):
    632          user = User(api, name = name)
    633          friends = user.friends
    634          if len(friends) == 0:
    635              return user
    636          else:
    637              f = friends[0]
    638              user = [a for a in f.friends if a.name == user.name][0]
    639              return user
    640
    641      @staticmethod
    642 -    def get_authenticated_user(api):
    643          data = api._fetch_data({'method': 'user.getInfo'}, sign = True, session = True).find('user')
    644          user = User(
    645                  api,
    646                  name = data.findtext('name'),
    647                  url = data.findtext('url'),
    648              )
    649          user._language = data.findtext('lang')
    650          user._country = Country(api, name = Country.ISO_CODES[data.findtext('country')])
    651          user._age = int(data.findtext('age'))
    652          user._gender = data.findtext('gender')
    653          user._subscriber = (data.findtext('subscriber') == "1")
    654          user._stats = Stats(subject = user, playcount = data.findtext('playcount'))
    655          return user
    656
    657 -    def _default_params(self, extra_params = {}):
    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
    665 -    def _hash_func(*args, **kwds):
    666          try:
    667              return hash(kwds['name'])
    668          except KeyError:
    669              raise InvalidParametersError("name has to be provided for hashing")
    670
    671 -    def __hash__(self):
    672          return self.__class__._hash_func(name = self.name)
    673
    674 -    def __eq__(self, other):
    675          return self.name == other.name
    676
    677 -    def __lt__(self, other):
    678          return self.name < other.name
    679
    680 -    def __repr__(self):
    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):
    686              super(User.Playlist, self).init(api, "lastfm://playlist/%s" % id)
    687              self._id = id
    688              self._title = title
    689              self._date = date
    690              self._size = size
    691              self._creator = creator
    692
    693          @property
    694 -        def id(self):
    695              return self._id
    696
    697          @property
    698 -        def title(self):
    699              return self._title
    700
    701          @property
    702 -        def date(self):
    703              return self._date
    704
    705          @property
    706 -        def size(self):
    707              return self._size
    708
    709          @property
    710 -        def creator(self):
    711              return self._creator
    712
    713          @property
    714 -        def user(self):
    715              return self._creator
    716
    717          @authenticate
    718 -        def add_track(self, track, artist = None):
    719              params = {'method': 'playlist.addTrack', 'playlistID': self.id}
    720              if isinstance(track, Track):
    721                  params['artist'] = track.artist.name
    722                  params['track'] = track.name
    723              else:
    724                  if artist is None:
    725                      track = self._api.search_track(track)[0]
    726                      params['artist'] = track.artist.name
    727                      params['track'] = track.name
    728                  else:
    729                      params['artist'] = isinstance(artist, Artist) and artist.name or artist
    730                      params['track'] = track
    731              self._api._post_data(params)
    732              self._data = None
    733
    734          @staticmethod
    735 -        def _hash_func(*args, **kwds):
    736              try:
    737                  return hash(kwds['id'])
    738              except KeyError:
    739                  raise InvalidParametersError("id has to be provided for hashing")
    740
    741 -        def __hash__(self):
    742              return self.__class__._hash_func(id = self.id)
    743
    744 -        def __repr__(self):
    745              return "<lastfm.User.Playlist: %s>" % self.title
    746
    747 -    class Library(object):
    748          """A class representing the music library of the user."""
    749 -        def __init__(self, api, user):
    750              self._api = api
    751              self._user = user
    752
    753          @property
    754 -        def user(self):
    755              return self._user
    756
    757 -        def get_albums(self,
    758                        limit = None):
    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
    806 -        def albums(self):
    807              return self.get_albums()
    808
    809          @authenticate
    810 -        def add_album(self, album, artist = None):
    811              params = {'method': 'library.addAlbum'}
    812              if isinstance(album, Album):
    813                  params['artist'] = album.artist.name
    814                  params['album'] = album.name
    815              else:
    816                  if artist is None:
    817                      album = self._api.search_album(album)[0]
    818                      params['artist'] = album.artist.name
    819                      params['album'] = album.name
    820                  else:
    821                      params['artist'] = isinstance(artist, Artist) and artist.name or artist
    822                      params['album'] = album
    823
    824              self._api._post_data(params)
    825              self._albums = None
    826
    827 -        def get_artists(self,
    828                         limit = None):
    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
    870 -        def artists(self):
    871              return self.get_artists()
    872
    873          @authenticate
    874 -        def add_artist(self, artist):
    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
    883 -        def get_tracks(self,
    884                        limit = None):
    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
    934 -        def tracks(self):
    935              return self.get_tracks()
    936
    937          @authenticate
    938 -        def add_track(self, track, artist = None):
    939              params = {'method': 'library.addTrack'}
    940              if isinstance(track, Track):
    941                  params['artist'] = track.artist.name
    942                  params['track'] = track.name
    943              else:
    944                  if artist is None:
    945                      track = self._api.search_track(track)[0]
    946                      params['artist'] = track.artist.name
    947                      params['track'] = track.name
    948                  else:
    949                      params['artist'] = isinstance(artist, Artist) and artist.name or artist
    950                      params['track'] = track
    951              self._api._post_data(params)
    952              self._tracks = None
    953
    954 -        def _default_params(self, extra_params = {}):
    955              if not self.user.name:
    956                  raise InvalidParametersError("user has to be provided.")
    957              params = {'user': self.user.name}
    958              params.update(extra_params)
    959              return params
    960
    961          @staticmethod
    962 -        def _hash_func(*args, **kwds):
    963              try:
    964                  return hash(kwds['user'])
    965              except KeyError:
    966                  raise InvalidParametersError("user has to be provided for hashing")
    967
    968 -        def __hash__(self):
    969              return self.__class__._hash_func(user = self.user)
    970
    971 -        def __repr__(self):
    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