python-lastfm/src/user.py

720 lines
28 KiB
Python

#!/usr/bin/env python
__author__ = "Abhinav Sarkar <abhinav@abhinavsarkar.net>"
__version__ = "0.1"
__license__ = "GNU Lesser General Public License"
from base import LastfmBase
from lazylist import lazylist
import playlist
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 LastfmInvalidParametersError("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,
subject = self,
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,
subject = self,
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
@LastfmBase.cachedProperty
def playlists(self):
"""playlists of the user"""
params = {'method': 'user.getPlaylists', 'user': self.name}
data = self.__api._fetchData(params).find('playlists')
return [
User.Playlist(
self.__api,
id = int(p.findtext('id')),
title = p.findtext('title'),
date = datetime(*(
time.strptime(
p.findtext('date').strip(),
'%Y-%m-%dT%H:%M:%S'
)[0:6])
),
size = int(p.findtext('size')),
creator = self
)
for p in data.findall('playlist')
]
@LastfmBase.cachedProperty
def lovedTracks(self):
params = {'method': 'user.getlovedtracks', 'user': self.name}
data = self.__api._fetchData(params).find('lovedtracks')
return [
Track(
self.__api,
subject = self,
name = t.findtext('name'),
artist = Artist(
self.__api,
subject = self,
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,
subject = self,
name = t.findtext('name'),
artist = Artist(
self.__api,
subject = self,
name = t.findtext('artist'),
mbid = t.find('artist').attrib['mbid'],
),
album = Album(
self.__api,
subject = self,
name = t.findtext('album'),
artist = Artist(
self.__api,
subject = self,
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,
subject = self,
name = a.findtext('name'),
artist = Artist(
self.__api,
subject = self,
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,
subject = self,
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,
subject = self,
name = t.findtext('name'),
artist = Artist(
self.__api,
subject = self,
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,
subject = self,
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()
def compare(self, other, limit = None):
return Tasteometer.compare(self.__api,
'user', 'user',
self.name, other.name,
limit)
@property
def library(self):
return self.__lirary
@staticmethod
def hashFunc(*args, **kwds):
try:
return hash(kwds['name'])
except KeyError:
raise LastfmInvalidParametersError("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 "<lastfm.User: %s>" % self.name
class Playlist(playlist.Playlist):
"""A class representing a playlist belonging to the user."""
def init(self, api, id, title, date, size, creator):
super(User.Playlist, self).init(api, "lastfm://playlist/%s" % id)
self.__id = id
self.__title = title
self.__date = date
self.__size = size
self.__creator = creator
@property
def id(self):
return self.__id
@property
def title(self):
return self.__title
@property
def date(self):
return self.__date
@property
def size(self):
return self.__size
@property
def creator(self):
return self.__creator
@staticmethod
def hashFunc(*args, **kwds):
try:
return hash(kwds['id'])
except KeyError:
raise LastfmInvalidParametersError("id has to be provided for hashing")
def __hash__(self):
return self.__class__.hashFunc(id = self.id)
def __repr__(self):
return "<lastfm.User.Playlist: %s>" % self.title
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,
subject = self,
name = a.findtext('name'),
artist = Artist(
self.__api,
subject = self,
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,
subject = self,
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,
subject = self,
name = t.findtext('name'),
artist = Artist(
self.__api,
subject = self,
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()
@staticmethod
def hashFunc(*args, **kwds):
try:
return hash(kwds['user'])
except KeyError:
raise LastfmInvalidParametersError("user has to be provided for hashing")
def __hash__(self):
return self.__class__.hashFunc(user = self.user)
def __repr__(self):
return "<lastfm.User.Library: for user '%s'>" % 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, LastfmInvalidParametersError
from event import Event
from stats import Stats
from tag import Tag
from tasteometer import Tasteometer
from track import Track
from weeklychart import WeeklyChart, WeeklyAlbumChart, WeeklyArtistChart, WeeklyTrackChart