From 27a1676c3bb075b41e259a0ad992b888124d927b Mon Sep 17 00:00:00 2001 From: Abhinav Sarkar Date: Tue, 2 Sep 2008 14:19:03 +0000 Subject: [PATCH] implemented playlist related methods in album, tag and user modules. updated some methods to the latest API docs. The read-only part of API is complete. --- src/album.py | 5 ++++ src/api.py | 8 ++---- src/geo.py | 62 ++++++++++++++++++++++++++-------------- src/playlist.py | 32 +++++++++++++++------ src/tag.py | 6 ++++ src/tasteometer.py | 2 +- src/user.py | 71 ++++++++++++++++++++++++++++++++++++++++++++-- 7 files changed, 148 insertions(+), 38 deletions(-) diff --git a/src/album.py b/src/album.py index f2ae37b..f18f2ea 100644 --- a/src/album.py +++ b/src/album.py @@ -114,6 +114,10 @@ class Album(LastfmBase): """top tag for the album""" pass + @LastfmBase.cachedProperty + def playlist(self): + return Playlist.fetch(self.__api, "lastfm://playlist/album/%s" % self.id) + @staticmethod def _fetchData(api, artist = None, @@ -203,5 +207,6 @@ import time from api import Api from artist import Artist from error import LastfmInvalidParametersError +from playlist import Playlist from stats import Stats from tag import Tag \ No newline at end of file diff --git a/src/api.py b/src/api.py index 6894c7c..22754ec 100644 --- a/src/api.py +++ b/src/api.py @@ -13,7 +13,7 @@ class Api(object): SEARCH_XMLNS = "http://a9.com/-/spec/opensearch/1.1/" def __init__(self, - apiKey = '23caa86333d2cb2055fa82129802780a', + apiKey, input_encoding=None, request_headers=None, no_cache = False, @@ -264,7 +264,6 @@ class Api(object): def _fetchData(self, params, - parse = True, no_cache = False): params.update({'api_key': self.__apiKey}) xml = self._fetchUrl(Api.API_ROOT_URL, params, no_cache = self._no_cache or no_cache) @@ -280,10 +279,7 @@ class Api(object): raise errorMap[code](message, code) else: raise LastfmError(message, code) - if parse: - return data - else: - return xml + return data def __repr__(self): return "" % self.__apiKey diff --git a/src/geo.py b/src/geo.py index 072145c..7c54fd2 100644 --- a/src/geo.py +++ b/src/geo.py @@ -12,10 +12,15 @@ class Geo(object): @staticmethod def getEvents(api, location, + latitude = None, + longitude = None, distance = None): params = {'method': 'geo.getevents', 'location': location} if distance is not None: params.update({'distance': distance}) + + if latitude is not None and longitude is not None: + params.update({'latitude': latitude, 'longitude': longitude}) @lazylist def gen(lst): @@ -58,8 +63,11 @@ class Geo(object): ] @staticmethod - def getTopTracks(api, country): + def getTopTracks(api, country, location = None): params = {'method': 'geo.gettoptracks', 'country': country} + if location is not None: + params.update({'location': location}) + data = api._fetchData(params).find('toptracks') return [ Track( @@ -135,7 +143,6 @@ class Location(LastfmBase): def init(self, api, - name = None, city = None, country = None, street = None, @@ -146,7 +153,6 @@ class Location(LastfmBase): if not isinstance(api, Api): raise LastfmInvalidParametersError("api reference must be supplied as an argument") self.__api = api - self.__name = name self.__city = city self.__country = country self.__street = street @@ -155,11 +161,6 @@ class Location(LastfmBase): self.__longitude = longitude self.__timezone = timezone - @property - def name(self): - """name of the location""" - return self.__name - @property def city(self): """city in which the location is situated""" @@ -194,10 +195,26 @@ class Location(LastfmBase): def timezone(self): """timezone in which the location is situated""" return self.__timezone - + + @LastfmBase.cachedProperty + def topTracks(self): + """top tracks of the location""" + if self.country is None or self.city is None: + raise LastfmInvalidParametersError("country and city of this location are required for calling this method") + return Geo.getTopTracks(self.__api, self.country.name, self.city) + + @LastfmBase.topProperty("topTracks") + def topTrack(self): + """top track of the location""" + pass + def getEvents(self, distance = None): - return Geo.getEvents(self.__api, self.name, distance) + return Geo.getEvents(self.__api, + self.city, + self.latitude, + self.longitude, + distance) @LastfmBase.cachedProperty def events(self): @@ -210,9 +227,9 @@ class Location(LastfmBase): return hash("latlong%s%s" % (kwds['latitude'], kwds['longitude'])) except KeyError: try: - return hash("name%s" % kwds['name']) + return hash("name%s" % kwds['city']) except KeyError: - raise LastfmInvalidParametersError("either latitude and longitude or name has to be provided for hashing") + raise LastfmInvalidParametersError("either latitude and longitude or city has to be provided for hashing") def __hash__(self): if not self.name: @@ -220,7 +237,7 @@ class Location(LastfmBase): latitude = self.latitude, longitude = self.longitude) else: - return self.__class__.hashFunc(name = self.name) + return self.__class__.hashFunc(name = self.city) def __eq__(self, other): return self.latitude == other.latitude and self.longitude == other.longitude @@ -232,10 +249,10 @@ class Location(LastfmBase): return self.city < other.city def __repr__(self): - if self.name is None: + if self.city is None: return "" % (self.latitude, self.longitude) else: - return "" % self.name + return "" % self.city class Country(LastfmBase): """A class representing a country.""" @@ -262,21 +279,24 @@ class Country(LastfmBase): """top artist of the country""" pass + def getTopTracks(self, location = None): + return Geo.getTopTracks(self.__api, self.name, location) + @LastfmBase.cachedProperty def topTracks(self): """top tracks of the country""" - return Geo.getTopTracks(self.__api, self.name) + return self.getTopTracks() - @LastfmBase.cachedProperty - def events(self): - """events taking place at/around the location""" - return Geo.getEvents(self.__api, self.name) - @LastfmBase.topProperty("topTracks") def topTrack(self): """top track of the country""" pass + @LastfmBase.cachedProperty + def events(self): + """events taking place at/around the location""" + return Geo.getEvents(self.__api, self.name) + @staticmethod def hashFunc(*args, **kwds): try: diff --git a/src/playlist.py b/src/playlist.py index 810f704..3768e05 100644 --- a/src/playlist.py +++ b/src/playlist.py @@ -8,14 +8,18 @@ from base import LastfmBase class Playlist(LastfmBase): """A class representing an XPSF playlist.""" - def init(self, xpsfData, url): - self.__data = xpsfData + def init(self, api, url): + self.__api = api + self.__data = None self.__url = url - @property + @LastfmBase.cachedProperty def data(self): """playlist's data""" - return self.__data + params = {'method': 'playlist.fetch', 'playlistURL': self.__url} + tmp = StringIO.StringIO() + ElementTree.ElementTree(self.__api._fetchData(params)[0]).write(tmp) + return tmp.getvalue() @property def url(self): @@ -24,8 +28,7 @@ class Playlist(LastfmBase): @staticmethod def fetch(api, url): - params = {'method': 'playlist.fetch', 'playlistURL': url} - return Playlist(api._fetchData(params, parse = False), url = url) + return Playlist(api, url = url) @staticmethod def hashFunc(*args, **kwds): @@ -45,5 +48,18 @@ class Playlist(LastfmBase): def __repr__(self): return "" % self.url - -from error import LastfmInvalidParametersError \ No newline at end of file + +import StringIO +import sys +from error import LastfmInvalidParametersError + +if sys.version.startswith('2.5'): + import xml.etree.cElementTree as ElementTree +else: + try: + import cElementTree as ElementTree + except ImportError: + try: + import ElementTree + except ImportError: + raise LastfmError("Install ElementTree package for using python-lastfm") \ No newline at end of file diff --git a/src/tag.py b/src/tag.py index 4299201..a8436b5 100644 --- a/src/tag.py +++ b/src/tag.py @@ -163,6 +163,11 @@ class Tag(LastfmBase): """top track for the tag""" pass + @LastfmBase.cachedProperty + def playlist(self): + return Playlist.fetch(self.__api, + "lastfm://playlist/tag/%s/freetracks" % self.name) + @staticmethod def getTopTags(api): params = {'method': 'tag.getTopTags'} @@ -240,5 +245,6 @@ from album import Album from api import Api from artist import Artist from error import LastfmInvalidParametersError +from playlist import Playlist from stats import Stats from track import Track \ No newline at end of file diff --git a/src/tasteometer.py b/src/tasteometer.py index c6e9b2f..8847853 100644 --- a/src/tasteometer.py +++ b/src/tasteometer.py @@ -61,6 +61,6 @@ class Tasteometer(object): def __repr__(self): - return "" + return "" % (self.score*100) from artist import Artist \ No newline at end of file diff --git a/src/user.py b/src/user.py index fae61e6..c02b6e9 100644 --- a/src/user.py +++ b/src/user.py @@ -6,6 +6,7 @@ __license__ = "GNU Lesser General Public License" from base import LastfmBase from lazylist import lazylist +import playlist class User(LastfmBase): """A class representing an user.""" @@ -141,10 +142,27 @@ class User(LastfmBase): """nearest neightbour of the user""" pass - @property + @LastfmBase.cachedProperty def playlists(self): """playlists of the user""" - pass + 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): @@ -451,6 +469,11 @@ class User(LastfmBase): 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 @@ -474,6 +497,49 @@ class User(LastfmBase): def __repr__(self): return "" % 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 "" % self.title + class Library(object): """A class representing the music library of the user.""" def __init__(self, api, user): @@ -649,5 +715,6 @@ 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 \ No newline at end of file