diff --git a/src/album.py b/src/album.py index fb6dcf4..38ae064 100644 --- a/src/album.py +++ b/src/album.py @@ -17,8 +17,7 @@ class Album(LastfmBase): url = None, releaseDate = None, image = None, - listeners = None, - playcount = None, + stats = None, topTags = None): if not isinstance(api, Api): raise LastfmError("api reference must be supplied as an argument") @@ -30,8 +29,13 @@ class Album(LastfmBase): self.__url = url self.__releaseDate = releaseDate self.__image = image - self.__listeners = listeners - self.__playcount = playcount + self.__stats = stats and Stats( + subject = self, + listeners = stats.listeners, + playcount = stats.playcount, + match = stats.match, + rank = stats.rank + ) self.__topTags = topTags def getName(self): @@ -55,11 +59,8 @@ class Album(LastfmBase): def getImage(self): return self.__image - def getListeners(self): - return self.__listeners - - def getPlaycount(self): - return self.__playcount + def getStats(self): + return self.__stats def getTopTags(self): if self.__topTags is None: @@ -93,9 +94,7 @@ class Album(LastfmBase): image = property(getImage, None, None, "Image's Docstring") - listeners = property(getListeners, None, None, "Listeners's Docstring") - - playcount = property(getPlaycount, None, None, "Playcount's Docstring") + stats = property(getStats, None, None, "Stats's Docstring") topTags = property(getTopTags, None, None, "TopTags's Docstring") topTag = property(lambda self: self.topTags and len(self.topTags) and self.topTags[0], @@ -128,8 +127,11 @@ class Album(LastfmBase): releaseDate = data.findtext('releasedate') and data.findtext('releasedate').strip() and datetime(*(time.strptime(data.findtext('releasedate').strip(), '%d %b %Y, 00:00')[0:6])), image = dict([(i.get('size'), i.text) for i in data.findall('image')]), - listeners = int(data.findtext('listeners')), - playcount = int(data.findtext('playcount')), + stats = Stats( + subject = data.findtext('name'), + listeners = int(data.findtext('listeners')), + playcount = int(data.findtext('playcount')), + ), topTags = [ Tag( api, @@ -173,4 +175,5 @@ import time from api import Api from error import LastfmError from tag import Tag -from artist import Artist \ No newline at end of file +from artist import Artist +from stats import Stats \ No newline at end of file diff --git a/src/api.py b/src/api.py index c32aeed..6dd7b56 100644 --- a/src/api.py +++ b/src/api.py @@ -152,8 +152,8 @@ class Api(object): def getGroup(self, name): return Group(self, name = name) - def fetchPlaylist(self, playlistUrl): - return Playlist(self, playlistUrl = playlistUrl) + def fetchPlaylist(self, url): + return Playlist.fetch(self, url) def getTag(self, name): return Tag(self, name = name) diff --git a/src/artist.py b/src/artist.py index a570268..3715933 100644 --- a/src/artist.py +++ b/src/artist.py @@ -13,7 +13,6 @@ class Artist(LastfmBase): name = None, mbid = None, url = None, - match = None, image = None, streamable = None, stats = None, @@ -26,13 +25,14 @@ class Artist(LastfmBase): self.__name = name self.__mbid = mbid self.__url = url - self.__match = match self.__image = image self.__streamable = streamable self.__stats = stats and Stats( - artist = self, + subject = self, listeners = stats.listeners, - plays = stats.plays + playcount = stats.playcount, + match = stats.match, + rank = stats.rank ) self.__similar = similar self.__topTags = topTags @@ -52,9 +52,6 @@ class Artist(LastfmBase): def getUrl(self): return self.__url - def getMatch(self): - return self.__match - def getImage(self): return self.__image @@ -77,7 +74,10 @@ class Artist(LastfmBase): self.__api, name = a.findtext('name'), mbid = a.findtext('mbid'), - match = float(a.findtext('match')), + stats = Stats( + artist = a.findtext('name'), + match = float(a.findtext('match')), + ), url = 'http://' + a.findtext('url'), image = {'large': a.findtext('image')} ) @@ -111,8 +111,6 @@ class Artist(LastfmBase): url = property(getUrl, None, None, "Url's Docstring") - match = property(getMatch, None, None, "Match's Docstring") - image = property(getImage, None, None, "Image's Docstring") streamable = property(getStreamable, None, None, "Streamable's Docstring") @@ -139,7 +137,7 @@ class Artist(LastfmBase): id = int(e.findtext('id')), title = e.findtext('title'), artists = [Artist(self.__api, name = a.text) for a in e.findall('artists/artist')], - headliner = e.findtext('artists/headliner'), + headliner = Artist(self.__api, name = e.findtext('artists/headliner')), venue = Venue( name = e.findtext('venue/name'), location = Location( @@ -188,7 +186,11 @@ class Artist(LastfmBase): mbid = a.findtext('mbid'), url = a.findtext('url'), image = dict([(i.get('size'), i.text) for i in a.findall('image')]), - playcount = int(a.findtext('playcount')), + stats = Stats( + subject = a.findtext('name'), + playcount = int(a.findtext('playcount')), + rank = int(a.attrib['rank']) + ) ) for a in data.findall('album') ] @@ -206,7 +208,10 @@ class Artist(LastfmBase): name = u.findtext('name'), url = u.findtext('url'), image = dict([(i.get('size'), i.text) for i in u.findall('image')]), - weight = int(u.findtext('weight')) + stats = Stats( + subject = u.findtext('name'), + weight = int(u.findtext('weight')) + ) ) for u in data.findall('user') ] @@ -224,7 +229,11 @@ class Artist(LastfmBase): name = t.findtext('name'), artist = self, mbid = t.findtext('mbid'), - playcount = int(t.findtext('playcount')), + stats = Stats( + subject = t.findtext('name'), + playcount = int(t.findtext('playcount')), + rank = int(t.attrib['rank']) + ), 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')]), @@ -263,7 +272,7 @@ class Artist(LastfmBase): image = dict([(i.get('size'), i.text) for i in a.findall('image')]), streamable = (a.findtext('streamable') == '1'), stats = Stats( - artist = a.findtext('name'), + subject = a.findtext('name'), listeners = int(a.findtext('listeners')), ), ) @@ -293,9 +302,9 @@ class Artist(LastfmBase): image = dict([(i.get('size'), i.text) for i in data.findall('image')]), streamable = (data.findtext('streamable') == 1), stats = Stats( - artist, + subject = artist, listeners = int(data.findtext('stats/listeners')), - plays = int(data.findtext('stats/plays')) + playcount = int(data.findtext('stats/plays')) ), similar = [ Artist( @@ -352,34 +361,6 @@ class Artist(LastfmBase): def __repr__(self): return "" % self.__name -class Stats(object): - """A class representing the stats of an artist.""" - def __init__(self, - artist, - listeners = None, - plays = None): - self.__artist = artist - self.__listeners = listeners - self.__plays = plays - - def getArtist(self): - return self.__artist - - def getListeners(self): - return self.__listeners - - def getPlays(self): - return self.__plays - - listeners = property(getListeners, None, None, "Listeners's Docstring") - - plays = property(getPlays, None, None, "Plays's Docstring") - - artist = property(getArtist, None, None, "Artist's Docstring") - - def __repr__(self): - return "" % self.__artist.name - class Bio(object): """A class representing the biography of an artist.""" def __init__(self, @@ -426,4 +407,5 @@ from geo import Country, Location, Venue from tag import Tag from track import Track from user import User -from search import SearchResult \ No newline at end of file +from search import SearchResult +from stats import Stats \ No newline at end of file diff --git a/src/event.py b/src/event.py index 39278df..7a8376e 100644 --- a/src/event.py +++ b/src/event.py @@ -20,8 +20,7 @@ class Event(LastfmBase): description = None, image = None, url = None, - attendance = None, - reviews = None, + stats = None, tag = None): if not isinstance(api, Api): raise LastfmError("api reference must be supplied as an argument") @@ -36,8 +35,11 @@ class Event(LastfmBase): self.__description = description self.__image = image self.__url = url - self.__attendance = attendance - self.__reviews = reviews + self.__stats = stats and Stats( + subject = self, + attendance = self.attendance, + reviews = self.reviews + ) self.__tag = tag def getId(self): @@ -70,11 +72,8 @@ class Event(LastfmBase): def getUrl(self): return self.__url - def getAttendance(self): - return self.__attendance - - def getReviews(self): - return self.__reviews + def getStats(self): + return self.__stats def getTag(self): return self.__tag @@ -99,10 +98,8 @@ class Event(LastfmBase): url = property(getUrl, None, None, "Url's Docstring") - attendance = property(getAttendance, None, None, "Attendance's Docstring") - - reviews = property(getReviews, None, None, "Reviews's Docstring") - + stats = property(getStats, None, None, "Match's Docstring") + tag = property(getTag, None, None, "Tag's Docstring") @staticmethod @@ -115,7 +112,7 @@ class Event(LastfmBase): id = int(data.findtext('id')), title = data.findtext('title'), artists = [Artist(api, name = a.text) for a in data.findall('artists/artist')], - headliner = data.findtext('artists/headliner'), + headliner = Artist(api, name = data.findtext('artists/headliner')), venue = Venue( name = data.findtext('venue/name'), location = Location( @@ -146,8 +143,11 @@ class Event(LastfmBase): description = data.findtext('description'), image = dict([(i.get('size'), i.text) for i in data.findall('image')]), url = data.findtext('url'), - attendance = int(data.findtext('attendance')), - reviews = int(data.findtext('reviews')), + stats = Stats( + subject = int(data.findtext('id')), + attendance = int(data.findtext('attendance')), + reviews = int(data.findtext('reviews')), + ), tag = data.findtext('tag') ) @@ -176,4 +176,5 @@ import time from api import Api from error import LastfmError from artist import Artist -from geo import Venue, Location, Country \ No newline at end of file +from geo import Venue, Location, Country +from stats import Stats \ No newline at end of file diff --git a/src/geo.py b/src/geo.py index 3c5a08e..8939def 100644 --- a/src/geo.py +++ b/src/geo.py @@ -9,16 +9,108 @@ from base import LastfmBase class Geo(object): """A class representing an geographic location.""" @staticmethod - def getEvents(api, location, distance, page): - pass + def getEvents(api, + location, + distance = None, + page = None): + params = {'method': 'geo.getevents', 'location': location} + data = api.fetchData(params).find('events') + + return SearchResult( + type = 'event', + searchTerms = data.attrib['location'], + startPage = int(data.attrib['page']), + totalResults = int(data.attrib['total']), + itemsPerPage = int(math.ceil(float(data.attrib['total']))/float(data.attrib['totalpages'])), + matches = [ + Event( + api, + id = int(e.findtext('id')), + title = e.findtext('title'), + artists = [Artist(api, name = a.text) for a in e.findall('artists/artist')], + headliner = Artist(api, name = e.findtext('artists/headliner')), + venue = Venue( + name = e.findtext('venue/name'), + location = Location( + api, + city = e.findtext('venue/location/city'), + country = Country( + api, + name = e.findtext('venue/location/country') + ), + street = e.findtext('venue/location/street'), + postalCode = e.findtext('venue/location/postalcode'), + latitude = float(e.findtext( + 'venue/location/{%s}point/{%s}lat' % ((Location.xmlns,)*2) + )), + longitude = float(e.findtext( + 'venue/location/{%s}point/{%s}long' % ((Location.xmlns,)*2) + )), + timezone = e.findtext('venue/location/timezone') + ), + url = e.findtext('venue/url') + ), + startDate = e.findtext('startDate') and + datetime(*(time.strptime(e.findtext('startDate').strip(), '%a, %d %b %Y')[0:6])) or + None, + startTime = e.findtext('startTime') and + datetime(*(time.strptime(e.findtext('startTime').strip(), '%H:%M')[0:6])) or + None, + description = e.findtext('description'), + image = dict([(i.get('size'), i.text) for i in e.findall('image')]), + url = e.findtext('url') + ) + for e in data.findall('event') + ] + ) @staticmethod def getTopArtists(api, country): - pass + params = {'method': 'geo.gettopartists', 'country': country} + data = api.fetchData(params).find('topartists') + return [ + Artist( + api, + name = a.findtext('name'), + mbid = a.findtext('mbid'), + stats = Stats( + subject = a.findtext('name'), + rank = int(a.attrib['rank']), + playcount = int(a.findtext('playcount')) + ), + url = 'http://' + a.findtext('url'), + image = {'large': a.findtext('image')} + ) + for a in data.findall('artist') + ] @staticmethod def getTopTracks(api, country): - pass + params = {'method': 'geo.gettoptracks', 'country': country} + data = api.fetchData(params).find('toptracks') + return [ + Track( + api, + name = t.findtext('name'), + mbid = t.findtext('mbid'), + artist = Artist( + api, + name = t.findtext('artist/name'), + mbid = t.findtext('artist/mbid'), + url = t.findtext('artist/url') + ), + stats = Stats( + subject = t.findtext('name'), + rank = int(t.attrib['rank']), + playcount = int(t.findtext('playcount')) + ), + streamable = (t.findtext('streamable') == '1'), + fullTrack = (t.find('streamable').attrib['fulltrack'] == '1'), + url = 'http://' + t.findtext('url'), + image = {'large': t.findtext('image')} + ) + for t in data.findall('track') + ] class Venue(LastfmBase): """A class representing a venue of an event""" @@ -133,7 +225,7 @@ class Location(LastfmBase): def getEvents(self, distance = None, page = None): - return Geo.getEvents(self.__api, self.name, distance, page) + return Geo.getEvents(self.__api, self.name, distance, page).matches events = property(getEvents, None, None, "Event's Docstring") @@ -218,9 +310,16 @@ class Country(LastfmBase): return self.name < other.name def __repr__(self): - return "" % self.name +import math +from datetime import datetime +import time + from api import Api from error import LastfmError from artist import Artist -from track import Track \ No newline at end of file +from track import Track +from event import Event +from search import SearchResult +from stats import Stats \ No newline at end of file diff --git a/src/playlist.py b/src/playlist.py index 2edbb2f..9ea8754 100644 --- a/src/playlist.py +++ b/src/playlist.py @@ -6,39 +6,44 @@ __license__ = "GNU Lesser General Public License" from base import LastfmBase -class Playlist(LastfmBase, str): +class Playlist(LastfmBase): """A class representing an XPSF playlist.""" - def init(self, xpsfData, playlistUrl): - self = xpsfData - self.__playlistUrl = playlistUrl + def init(self, xpsfData, url): + self.__data = xpsfData + self.__url = url - def getPlaylistUrl(self): - return self.__playlistUrl + def getData(self): + return self.__data + + def getUrl(self): + return self.__url + + data = property(getData, None, None, "docstring") - playlistUrl = property(getPlaylistUrl, None, None, "PlaylistUrl's Docstring") + url = property(getUrl, None, None, "url's Docstring") @staticmethod - def fetch(api, playlistUrl): - params = {'method': 'playlist.fetch'} - return Playlist(api.fetchData(params, parse = False), playlistUrl) + def fetch(api, url): + params = {'method': 'playlist.fetch', 'playlistURL': url} + return Playlist(api.fetchData(params, parse = False), url = url) @staticmethod def hashFunc(*args, **kwds): try: - return hash(kwds['playlistUrl']) + return hash(kwds['url']) except KeyError: - raise LastfmError("playlistUrl has to be provided for hashing") + raise LastfmError("url has to be provided for hashing") def __hash__(self): - return self.__class__.hashFunc(playlistUrl = self.playlistUrl) + return self.__class__.hashFunc(url = self.url) def __eq__(self, other): - return self.playlistUrl == other.playlistUrl + return self.url == other.url def __lt__(self, other): - return self.playlistUrl < other.playlistUrl + return self.url < other.url def __repr__(self): - return "" % self.playlistUrl + return "" % self.url from error import LastfmError \ No newline at end of file diff --git a/src/search.py b/src/search.py index 625f791..47c28ca 100644 --- a/src/search.py +++ b/src/search.py @@ -65,15 +65,15 @@ class SearchResult(LastfmBase): @staticmethod def hashFunc(*args, **kwds): try: - return hash("%s%s%s" % (kwds['searchTerms'], kwds['type'], kwds['startIndex'])) + return hash("%s%s%s" % (kwds['searchTerms'], kwds['type'], kwds['startPage'])) except KeyError: - raise LastfmError("name and artist have to be provided for hashing") + raise LastfmError("searchTerms, type and startPage have to be provided for hashing") def __hash__(self): return self.__class__.hashFunc( searchTerms = self.searchTerms, type = self.type, - startIndex = self.startIndex + startPage = self.startPage ) def __eq__(self, other): diff --git a/src/stats.py b/src/stats.py new file mode 100644 index 0000000..ba662f9 --- /dev/null +++ b/src/stats.py @@ -0,0 +1,69 @@ +#!/usr/bin/env python + +__author__ = "Abhinav Sarkar" +__version__ = "0.1" +__license__ = "GNU Lesser General Public License" + +class Stats(object): + """A class representing the stats of an artist.""" + def __init__(self, + subject, + listeners = None, + playcount = None, + match = None, + rank = None, + weight = None, + attendance = None, + reviews = None,): + self.__subject = subject + self.__listeners = listeners + self.__playcount = playcount + self.__match = match + self.__rank = rank + self.__weight = weight + self.__attendance = attendance + self.__reviews = reviews + + def getSubject(self): + return self.__subject + + def getRank(self): + return self.__rank + + def getListeners(self): + return self.__listeners + + def getPlaycount(self): + return self.__playcount + + def getMatch(self): + return self.__match + + def getWeight(self): + return self.__weight + + def getAttendance(self): + return self.__attendance + + def getReviews(self): + return self.__reviews + + listeners = property(getListeners, None, None, "Listeners's Docstring") + + playcount = property(getPlaycount, None, None, "Plays's Docstring") + + match = property(getMatch, None, None, "Match's Docstring") + + rank = property(getRank, None, None, "Artist's Docstring") + + subject = property(getSubject, None, None, "subject's Docstring") + + weight = property(getWeight, None, None, "Weight's Docstring") + + attendance = property(getAttendance, None, None, "Attendance's Docstring") + + reviews = property(getReviews, None, None, "Reviews's Docstring") + + def __repr__(self): + return "" % self.__subject.name + \ No newline at end of file diff --git a/src/track.py b/src/track.py index d7b3bcc..eb6de26 100644 --- a/src/track.py +++ b/src/track.py @@ -16,8 +16,7 @@ class Track(LastfmBase): streamable = None, artist = None, image = None, - match = None, - playcount = None, + stats = None, fullTrack = None): if not isinstance(api, Api): raise LastfmError("api reference must be supplied as an argument") @@ -28,8 +27,12 @@ class Track(LastfmBase): self.__streamable = streamable self.__artist = artist self.__image = image - self.__match = match - self.__playcount = playcount + self.__stats = stats and Stats( + subject = self, + match = stats.match, + playcount = stats.playcount, + rank = stats.rank + ) self.__fullTrack = fullTrack def getName(self): @@ -50,11 +53,8 @@ class Track(LastfmBase): def getImage(self): return self.__image - def getMatch(self): - return self.__match - - def getPlaycount(self): - return self.__playcount + def getStats(self): + return self.__stats def getFullTrack(self): return self.__fullTrack @@ -71,9 +71,7 @@ class Track(LastfmBase): image = property(getImage, None, None, "Image's Docstring") - match = property(getMatch, None, None, "Match's Docstring") - - playcount = property(getPlaycount, None, None, "Match's Docstring") + stats = property(getStats, None, None, "Match's Docstring") fullTrack = property(getFullTrack, None, None, "Match's Docstring") @@ -159,4 +157,5 @@ class Track(LastfmBase): from api import Api from error import LastfmError from user import User -from tag import Tag \ No newline at end of file +from tag import Tag +from stats import Stats \ No newline at end of file diff --git a/src/user.py b/src/user.py index 590ad3d..d68617e 100644 --- a/src/user.py +++ b/src/user.py @@ -13,14 +13,18 @@ class User(LastfmBase): name = None, url = None, image = None, - weight = 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.__weight = weight + self.__stats = stats and Stats( + subject = self, + match = stats.match, + weight = stats.weight + ) def getName(self): return self.__name @@ -31,8 +35,8 @@ class User(LastfmBase): def getImage(self): return self.__image - def getWeight(self): - return self.__weight + def getStats(self): + return self.__stats name = property(getName, None, None, "Name's Docstring") @@ -40,7 +44,7 @@ class User(LastfmBase): image = property(getImage, None, None, "Image's Docstring") - weight = property(getWeight, None, None, "Weight's Docstring") + stats = property(getStats, None, None, "Weight's Docstring") def getEvents(self): pass @@ -141,4 +145,5 @@ class User(LastfmBase): return "" % self.name from api import Api -from error import LastfmError \ No newline at end of file +from error import LastfmError +from stats import Stats \ No newline at end of file