#!/usr/bin/env python __author__ = "Abhinav Sarkar " __version__ = "0.1" __license__ = "GNU Lesser General Public License" from base import LastfmBase from lazylist import lazylist class User(LastfmBase): """A class representing an user.""" def init(self, api, name = None, url = None, image = None, stats = None): if not isinstance(api, Api): raise LastfmError("api reference must be supplied as an argument") self.__api = api self.__name = name self.__url = url self.__image = image self.__stats = stats and Stats( subject = self, match = stats.match, weight = stats.weight ) self.__lirary = User.Library(api, self) @property def name(self): """name of the user""" return self.__name @property def url(self): """url of the user's page""" return self.__url @property def image(self): """image of the user""" return self.__image @property def stats(self): """stats for the user""" return self.__stats @LastfmBase.cachedProperty def events(self): params = {'method': 'user.getevents', 'user': self.name} data = self.__api._fetchData(params).find('events') return [ Event.createFromData(self.__api, e) for e in data.findall('event') ] def getPastEvents(self, limit = None): params = {'method': 'user.getpastevents', 'user': self.name} if limit is not None: params.update({'limit': limit}) @lazylist def gen(lst): data = self.__api._fetchData(params).find('events') totalPages = int(data.attrib['totalPages']) @lazylist def gen2(lst, data): for e in data.findall('event'): yield Event.createFromData(self.__api, e) for e in gen2(data): yield e for page in xrange(2, totalPages+1): params.update({'page': page}) data = self.__api._fetchData(params).find('events') for e in gen2(data): yield e return gen() @LastfmBase.cachedProperty def pastEvents(self): return self.getPastEvents() def getFriends(self, limit = None): params = {'method': 'user.getfriends', 'user': self.name} if limit is not None: params.update({'limit': limit}) data = self.__api._fetchData(params).find('friends') return [ User( self.__api, name = u.findtext('name'), image = dict([(i.get('size'), i.text) for i in u.findall('image')]), url = u.findtext('url'), ) for u in data.findall('user') ] @LastfmBase.cachedProperty def friends(self): """friends of the user""" return self.getFriends() def getNeighbours(self, limit = None): params = {'method': 'user.getneighbours', 'user': self.name} if limit is not None: params.update({'limit': limit}) data = self.__api._fetchData(params).find('neighbours') return [ User( self.__api, name = u.findtext('name'), image = {'medium': u.findtext('image')}, url = u.findtext('url'), stats = Stats( subject = u.findtext('name'), match = float(u.findtext('match')), ), ) for u in data.findall('user') ] @LastfmBase.cachedProperty def neighbours(self): """neighbours of the user""" return self.getNeighbours() @LastfmBase.topProperty("neighbours") def nearestNeighbour(self): """nearest neightbour of the user""" pass @property def playlists(self): """playlists of the user""" pass @LastfmBase.cachedProperty def lovedTracks(self): params = {'method': 'user.getlovedtracks', 'user': self.name} data = self.__api._fetchData(params).find('lovedtracks') return [ Track( self.__api, name = t.findtext('name'), artist = Artist( self.__api, name = t.findtext('artist/name'), mbid = t.findtext('artist/mbid'), url = t.findtext('artist/url'), ), mbid = t.findtext('mbid'), image = dict([(i.get('size'), i.text) for i in t.findall('image')]), lovedOn = datetime(*( time.strptime( t.findtext('date').strip(), '%d %b %Y, %H:%M' )[0:6]) ) ) for t in data.findall('track') ] def getRecentTracks(self, limit = None): params = {'method': 'user.getrecenttracks', 'user': self.name} data = self.__api._fetchData(params, no_cache = True).find('recenttracks') return [ Track( self.__api, name = t.findtext('name'), artist = Artist( self.__api, name = t.findtext('artist'), mbid = t.find('artist').attrib['mbid'], ), album = Album( self.__api, name = t.findtext('album'), artist = Artist( self.__api, name = t.findtext('artist'), mbid = t.find('artist').attrib['mbid'], ), mbid = t.find('album').attrib['mbid'], ), mbid = t.findtext('mbid'), streamable = (t.findtext('streamable') == '1'), url = t.findtext('url'), image = dict([(i.get('size'), i.text) for i in t.findall('image')]), playedOn = datetime(*( time.strptime( t.findtext('date').strip(), '%d %b %Y, %H:%M' )[0:6]) ) ) for t in data.findall('track') ] @property def recentTracks(self): """recent tracks played by the user""" return self.getRecentTracks() @LastfmBase.topProperty("recentTracks") def mostRecentTrack(self): """most recent track played by the user""" pass def getTopAlbums(self, period = None): params = {'method': 'user.gettopalbums', 'user': self.name} if period is not None: params.update({'period': period}) data = self.__api._fetchData(params).find('topalbums') return [ Album( self.__api, name = a.findtext('name'), artist = Artist( self.__api, name = a.findtext('artist/name'), mbid = a.findtext('artist/mbid'), url = a.findtext('artist/url'), ), mbid = a.findtext('mbid'), url = a.findtext('url'), image = dict([(i.get('size'), i.text) for i in a.findall('image')]), stats = Stats( subject = a.findtext('name'), playcount = int(a.findtext('playcount')), rank = int(a.attrib['rank']) ) ) for a in data.findall('album') ] @LastfmBase.cachedProperty def topAlbums(self): """overall top albums of the user""" return self.getTopAlbums() @LastfmBase.topProperty("topAlbums") def topAlbum(self): """overall top most album of the user""" pass def getTopArtists(self, period = None): params = {'method': 'user.gettopartists', 'user': self.name} if period is not None: params.update({'period': period}) data = self.__api._fetchData(params).find('topartists') return [ Artist( self.__api, name = a.findtext('name'), mbid = a.findtext('mbid'), stats = Stats( subject = a.findtext('name'), rank = a.attrib['rank'].strip() and int(a.attrib['rank']) or None, playcount = a.findtext('playcount') and int(a.findtext('playcount')) or None ), url = a.findtext('url'), streamable = (a.findtext('streamable') == "1"), image = dict([(i.get('size'), i.text) for i in a.findall('image')]), ) for a in data.findall('artist') ] @LastfmBase.cachedProperty def topArtists(self): """top artists of the user""" return self.getTopArtists() @LastfmBase.topProperty("topArtists") def topArtist(self): """top artist of the user""" pass def getTopTracks(self, period = None): params = {'method': 'user.gettoptracks', 'user': self.name} if period is not None: params.update({'period': period}) data = self.__api._fetchData(params).find('toptracks') return [ Track( self.__api, name = t.findtext('name'), artist = Artist( self.__api, name = t.findtext('artist/name'), mbid = t.findtext('artist/mbid'), url = t.findtext('artist/url'), ), mbid = t.findtext('mbid'), stats = Stats( subject = t.findtext('name'), rank = t.attrib['rank'].strip() and int(t.attrib['rank']) or None, playcount = t.findtext('playcount') and int(t.findtext('playcount')) or None ), streamable = (t.findtext('streamable') == '1'), fullTrack = (t.find('streamable').attrib['fulltrack'] == '1'), image = dict([(i.get('size'), i.text) for i in t.findall('image')]), ) for t in data.findall('track') ] @LastfmBase.cachedProperty def topTracks(self): """top tracks of the user""" return self.getTopTracks() @LastfmBase.topProperty("topTracks") def topTrack(self): """top track of the user""" return (len(self.topTracks) and self.topTracks[0] or None) def getTopTags(self, limit = None): params = {'method': 'user.gettoptags', 'user': self.name} if limit is not None: params.update({'limit': limit}) data = self.__api._fetchData(params).find('toptags') return [ Tag( self.__api, name = t.findtext('name'), url = t.findtext('url'), stats = Stats( subject = t.findtext('name'), count = int(t.findtext('count')) ) ) for t in data.findall('tag') ] @LastfmBase.cachedProperty def topTags(self): """top tags of the user""" return self.getTopTags() @LastfmBase.topProperty("topTags") def topTag(self): """top tag of the user""" pass @LastfmBase.cachedProperty def weeklyChartList(self): params = {'method': 'user.getweeklychartlist', 'user': self.name} data = self.__api._fetchData(params).find('weeklychartlist') return [ WeeklyChart.createFromData(self.__api, self, c) for c in data.findall('chart') ] def getWeeklyAlbumChart(self, start = None, end = None): params = {'method': 'user.getweeklyalbumchart', 'user': self.name} params = WeeklyChart._checkWeeklyChartParams(params, start, end) data = self.__api._fetchData(params).find('weeklyalbumchart') return WeeklyAlbumChart.createFromData(self.__api, self, data) @LastfmBase.cachedProperty def recentWeeklyAlbumChart(self): return self.getWeeklyAlbumChart() @LastfmBase.cachedProperty def weeklyAlbumChartList(self): wcl = list(self.weeklyChartList) wcl.reverse() @lazylist def gen(lst): for wc in wcl: try: yield self.getWeeklyAlbumChart(wc.start, wc.end) except LastfmError: pass return gen() def getWeeklyArtistChart(self, start = None, end = None): params = {'method': 'user.getweeklyartistchart', 'user': self.name} params = WeeklyChart._checkWeeklyChartParams(params, start, end) data = self.__api._fetchData(params).find('weeklyartistchart') return WeeklyArtistChart.createFromData(self.__api, self, data) @LastfmBase.cachedProperty def recentWeeklyArtistChart(self): return self.getWeeklyArtistChart() @LastfmBase.cachedProperty def weeklyArtistChartList(self): wcl = list(self.weeklyChartList) wcl.reverse() @lazylist def gen(lst): for wc in wcl: try: yield self.getWeeklyArtistChart(wc.start, wc.end) except LastfmError: pass return gen() def getWeeklyTrackChart(self, start = None, end = None): params = {'method': 'user.getweeklytrackchart', 'user': self.name} params = WeeklyChart._checkWeeklyChartParams(params, start, end) data = self.__api._fetchData(params).find('weeklytrackchart') return WeeklyTrackChart.createFromData(self.__api, self, data) @LastfmBase.cachedProperty def recentWeeklyTrackChart(self): return self.getWeeklyTrackChart() @LastfmBase.cachedProperty def weeklyTrackChartList(self): wcl = list(self.weeklyChartList) wcl.reverse() @lazylist def gen(lst): for wc in wcl: try: yield self.getWeeklyTrackChart(wc.start, wc.end) except LastfmError: pass return gen() @property def library(self): return self.__lirary @staticmethod def hashFunc(*args, **kwds): try: return hash(kwds['name']) except KeyError: raise LastfmError("name has to be provided for hashing") def __hash__(self): return self.__class__.hashFunc(name = self.name) def __eq__(self, other): return self.name == other.name def __lt__(self, other): return self.name < other.name def __repr__(self): return "" % self.name class Library(object): """A class representing the music library of the user.""" def __init__(self, api, user): self.__api = api self.__user = user @property def user(self): return self.__user def getAlbums(self, limit = None): params = {'method': 'library.getalbums', 'user': self.user.name} if limit is not None: params.update({'limit': limit}) @lazylist def gen(lst): data = self.__api._fetchData(params).find('albums') totalPages = int(data.attrib['totalPages']) @lazylist def gen2(lst, data): for a in data.findall('album'): yield Album( self.__api, name = a.findtext('name'), artist = Artist( self.__api, name = a.findtext('artist/name'), mbid = a.findtext('artist/mbid'), url = a.findtext('artist/url'), ), mbid = a.findtext('mbid'), url = a.findtext('url'), image = dict([(i.get('size'), i.text) for i in a.findall('image')]), stats = Stats( subject = a.findtext('name'), playcount = int(a.findtext('playcount')), ) ) for a in gen2(data): yield a for page in xrange(2, totalPages+1): params.update({'page': page}) data = self.__api._fetchData(params).find('albums') for a in gen2(data): yield a return gen() @LastfmBase.cachedProperty def albums(self): return self.getAlbums() def getArtists(self, limit = None): params = {'method': 'library.getartists', 'user': self.user.name} if limit is not None: params.update({'limit': limit}) @lazylist def gen(lst): data = self.__api._fetchData(params).find('artists') totalPages = int(data.attrib['totalPages']) @lazylist def gen2(lst, data): for a in data.findall('artist'): yield Artist( self.__api, name = a.findtext('name'), mbid = a.findtext('mbid'), stats = Stats( subject = a.findtext('name'), playcount = a.findtext('playcount') and int(a.findtext('playcount')) or None, tagcount = a.findtext('tagcount') and int(a.findtext('tagcount')) or None ), url = a.findtext('url'), streamable = (a.findtext('streamable') == "1"), image = dict([(i.get('size'), i.text) for i in a.findall('image')]), ) for a in gen2(data): yield a for page in xrange(2, totalPages+1): params.update({'page': page}) data = self.__api._fetchData(params).find('artists') for a in gen2(data): yield a return gen() @LastfmBase.cachedProperty def artists(self): return self.getArtists() def getTracks(self, limit = None): params = {'method': 'library.gettracks', 'user': self.user.name} if limit is not None: params.update({'limit': limit}) @lazylist def gen(lst): data = self.__api._fetchData(params).find('tracks') totalPages = int(data.attrib['totalPages']) @lazylist def gen2(lst, data): for t in data.findall('track'): yield Track( self.__api, name = t.findtext('name'), artist = Artist( self.__api, name = t.findtext('artist/name'), mbid = t.findtext('artist/mbid'), url = t.findtext('artist/url'), ), mbid = t.findtext('mbid'), stats = Stats( subject = t.findtext('name'), playcount = t.findtext('playcount') and int(t.findtext('playcount')) or None, tagcount = t.findtext('tagcount') and int(t.findtext('tagcount')) or None ), streamable = (t.findtext('streamable') == '1'), fullTrack = (t.find('streamable').attrib['fulltrack'] == '1'), image = dict([(i.get('size'), i.text) for i in t.findall('image')]), ) for t in gen2(data): yield t for page in xrange(2, totalPages+1): params.update({'page': page}) data = self.__api._fetchData(params).find('tracks') for t in gen2(data): yield t return gen() @LastfmBase.cachedProperty def tracks(self): return self.getTracks() def __repr__(self): return "" % self.user.name from datetime import datetime import time from api import Api from artist import Artist from album import Album from error import LastfmError from event import Event from stats import Stats from tag import Tag from track import Track from weeklychart import WeeklyChart, WeeklyAlbumChart, WeeklyArtistChart, WeeklyTrackChart #TODO #write exceptions #argument type checking #extra methods in weeklycharts #setup.py #cross check with website #registry issue