implemented new methods and check for authenticated method calls.

master
Abhinav Sarkar 2008-12-31 20:09:06 +00:00
parent 2565dbb9a1
commit 55680ba9c8
10 changed files with 525 additions and 52 deletions

View File

@ -96,9 +96,7 @@ class Album(LastfmBase, Cacheable, Searchable, Taggable):
@property @property
def streamable(self): def streamable(self):
"""is the artist streamable""" """is the album streamable"""
if self._streamable is None:
self._fill_info()
return self._streamable return self._streamable
@LastfmBase.cached_property @LastfmBase.cached_property

View File

@ -245,14 +245,14 @@ class Api(object):
return urllib.urlencode([(k, self._encode(parameters[k])) for k in keys if parameters[k] is not None]) return urllib.urlencode([(k, self._encode(parameters[k])) for k in keys if parameters[k] is not None])
def _read_url_data(self, opener, url, data = None): def _read_url_data(self, opener, url, data = None):
now = datetime.now() now = datetime.now()
delta = now - self._last_fetch_time delta = now - self._last_fetch_time
delta = delta.seconds + float(delta.microseconds)/1000000 delta = delta.seconds + float(delta.microseconds)/1000000
if delta < Api.FETCH_INTERVAL: if delta < Api.FETCH_INTERVAL:
time.sleep(Api.FETCH_INTERVAL - delta) time.sleep(Api.FETCH_INTERVAL - delta)
url_data = opener.open(url, data).read() url_data = opener.open(url, data).read()
self._last_fetch_time = datetime.now() self._last_fetch_time = datetime.now()
return url_data return url_data
def _fetch_url(self, def _fetch_url(self,
url, url,
@ -307,6 +307,7 @@ class Api(object):
sign = False, sign = False,
session = False, session = False,
no_cache = False): no_cache = False):
params = params.copy()
params['api_key'] = self.api_key params['api_key'] = self.api_key
if session: if session:
@ -325,9 +326,9 @@ class Api(object):
url, url,
parameters): parameters):
url = self._build_url(url) url = self._build_url(url)
if self._debug:
print url
data = self._encode_parameters(parameters) data = self._encode_parameters(parameters)
if self._debug:
print data
opener = self._get_opener(url) opener = self._get_opener(url)
url_data = self._read_url_data(opener, url, data) url_data = self._read_url_data(opener, url, data)
return url_data return url_data
@ -350,6 +351,7 @@ class Api(object):
keys.sort() keys.sort()
sig = unicode() sig = unicode()
for name in keys: for name in keys:
if name == 'api_sig': continue
sig += ("%s%s" % (name, params[name])) sig += ("%s%s" % (name, params[name]))
sig += self.secret sig += self.secret
hashed_sig = md5.new(sig).hexdigest() hashed_sig = md5.new(sig).hexdigest()

View File

@ -37,6 +37,7 @@ class Artist(LastfmBase, Cacheable, Sharable, Shoutable, Searchable, Taggable):
subject = self, subject = self,
listeners = stats.listeners, listeners = stats.listeners,
playcount = stats.playcount, playcount = stats.playcount,
weight = stats.weight,
match = stats.match, match = stats.match,
rank = stats.rank rank = stats.rank
) )

View File

@ -33,6 +33,24 @@ class LastfmBase(object):
return cache_attribute return cache_attribute
return property(fget = wrapper, doc = func.__doc__) return property(fget = wrapper, doc = func.__doc__)
@staticmethod
def autheticate(func):
def wrapper(self, *args, **kwargs):
from lastfm.user import User
user = None
if isinstance(self, User):
user = self.name
if self.autheticated:
return func(self, *args, **kwargs)
elif hasattr(self, 'user'):
user = self.user.name
if self.user.autheticated:
return func(self, *args, **kwargs)
raise AuthenticationFailedError(
"user '%s' does not have permissions to access the service" % user)
return wrapper
def __gt__(self, other): def __gt__(self, other):
return not (self.__lt__(other) or self.__eq(other)) return not (self.__lt__(other) or self.__eq(other))
@ -47,4 +65,4 @@ class LastfmBase(object):
return not self.__gt__(other) return not self.__gt__(other)
import copy import copy
from lastfm.error import LastfmError from lastfm.error import LastfmError, AuthenticationFailedError

View File

@ -57,6 +57,9 @@ class ServiceOfflineError(LastfmError):#11
class SubscribersOnlyError(LastfmError):#12 class SubscribersOnlyError(LastfmError):#12
pass pass
class InvalidMethodSignatureError(LastfmError):#13
pass
class TokenNotAuthorizedError(LastfmError):#14 class TokenNotAuthorizedError(LastfmError):#14
pass pass
@ -76,6 +79,7 @@ error_map = {
10: InvalidApiKeyError, 10: InvalidApiKeyError,
11: ServiceOfflineError, 11: ServiceOfflineError,
12: SubscribersOnlyError, 12: SubscribersOnlyError,
13: InvalidMethodSignatureError,
14: TokenNotAuthorizedError, 14: TokenNotAuthorizedError,
15: TokenExpiredError 15: TokenExpiredError
} }

View File

@ -257,6 +257,253 @@ class Location(LastfmBase, Cacheable):
class Country(LastfmBase, Cacheable): class Country(LastfmBase, Cacheable):
"""A class representing a country.""" """A class representing a country."""
ISO_CODES = {
'AD': 'Andorra',
'AE': 'United Arab Emirates',
'AF': 'Afghanistan',
'AG': 'Antigua and Barbuda',
'AI': 'Anguilla',
'AL': 'Albania',
'AM': 'Armenia',
'AN': 'Netherlands Antilles',
'AO': 'Angola',
'AQ': 'Antarctica',
'AR': 'Argentina',
'AS': 'American Samoa',
'AT': 'Austria',
'AU': 'Australia',
'AW': 'Aruba',
'AX': 'land Islands',
'AZ': 'Azerbaijan',
'BA': 'Bosnia and Herzegovina',
'BB': 'Barbados',
'BD': 'Bangladesh',
'BE': 'Belgium',
'BF': 'Burkina Faso',
'BG': 'Bulgaria',
'BH': 'Bahrain',
'BI': 'Burundi',
'BJ': 'Benin',
'BL': 'Saint Barthlemy',
'BM': 'Bermuda',
'BN': 'Brunei Darussalam',
'BO': 'Bolivia',
'BR': 'Brazil',
'BS': 'Bahamas',
'BT': 'Bhutan',
'BV': 'Bouvet Island',
'BW': 'Botswana',
'BY': 'Belarus',
'BZ': 'Belize',
'CA': 'Canada',
'CC': 'Cocos (Keeling) Islands',
'CD': 'Congo, The Democratic Republic of the',
'CF': 'Central African Republic',
'CG': 'Congo',
'CH': 'Switzerland',
'CI': "Cte d'Ivoire",
'CK': 'Cook Islands',
'CL': 'Chile',
'CM': 'Cameroon',
'CN': 'China',
'CO': 'Colombia',
'CR': 'Costa Rica',
'CU': 'Cuba',
'CV': 'Cape Verde',
'CX': 'Christmas Island',
'CY': 'Cyprus',
'CZ': 'Czech Republic',
'DE': 'Germany',
'DJ': 'Djibouti',
'DK': 'Denmark',
'DM': 'Dominica',
'DO': 'Dominican Republic',
'DZ': 'Algeria',
'EC': 'Ecuador',
'EE': 'Estonia',
'EG': 'Egypt',
'EH': 'Western Sahara',
'ER': 'Eritrea',
'ES': 'Spain',
'ET': 'Ethiopia',
'FI': 'Finland',
'FJ': 'Fiji',
'FK': 'Falkland Islands (Malvinas)',
'FM': 'Micronesia, Federated States of',
'FO': 'Faroe Islands',
'FR': 'France',
'GA': 'Gabon',
'GB': 'United Kingdom',
'GD': 'Grenada',
'GE': 'Georgia',
'GF': 'French Guiana',
'GG': 'Guernsey',
'GH': 'Ghana',
'GI': 'Gibraltar',
'GL': 'Greenland',
'GM': 'Gambia',
'GN': 'Guinea',
'GP': 'Guadeloupe',
'GQ': 'Equatorial Guinea',
'GR': 'Greece',
'GS': 'South Georgia and the South Sandwich Islands',
'GT': 'Guatemala',
'GU': 'Guam',
'GW': 'Guinea-Bissau',
'GY': 'Guyana',
'HK': 'Hong Kong',
'HM': 'Heard Island and McDonald Islands',
'HN': 'Honduras',
'HR': 'Croatia',
'HT': 'Haiti',
'HU': 'Hungary',
'ID': 'Indonesia',
'IE': 'Ireland',
'IL': 'Israel',
'IM': 'Isle of Man',
'IN': 'India',
'IO': 'British Indian Ocean Territory',
'IQ': 'Iraq',
'IR': 'Iran, Islamic Republic of',
'IS': 'Iceland',
'IT': 'Italy',
'JE': 'Jersey',
'JM': 'Jamaica',
'JO': 'Jordan',
'JP': 'Japan',
'KE': 'Kenya',
'KG': 'Kyrgyzstan',
'KH': 'Cambodia',
'KI': 'Kiribati',
'KM': 'Comoros',
'KN': 'Saint Kitts and Nevis',
'KP': "Korea, Democratic People's Republic of",
'KR': 'Korea, Republic of',
'KW': 'Kuwait',
'KY': 'Cayman Islands',
'KZ': 'Kazakhstan',
'LA': "Lao People's Democratic Republic",
'LB': 'Lebanon',
'LC': 'Saint Lucia',
'LI': 'Liechtenstein',
'LK': 'Sri Lanka',
'LR': 'Liberia',
'LS': 'Lesotho',
'LT': 'Lithuania',
'LU': 'Luxembourg',
'LV': 'Latvia',
'LY': 'Libyan Arab Jamahiriya',
'MA': 'Morocco',
'MC': 'Monaco',
'MD': 'Moldova',
'ME': 'Montenegro',
'MF': 'Saint Martin',
'MG': 'Madagascar',
'MH': 'Marshall Islands',
'MK': 'Macedonia, The Former Yugoslav Republic of',
'ML': 'Mali',
'MM': 'Myanmar',
'MN': 'Mongolia',
'MO': 'Macao',
'MP': 'Northern Mariana Islands',
'MQ': 'Martinique',
'MR': 'Mauritania',
'MS': 'Montserrat',
'MT': 'Malta',
'MU': 'Mauritius',
'MV': 'Maldives',
'MW': 'Malawi',
'MX': 'Mexico',
'MY': 'Malaysia',
'MZ': 'Mozambique',
'NA': 'Namibia',
'NC': 'New Caledonia',
'NE': 'Niger',
'NF': 'Norfolk Island',
'NG': 'Nigeria',
'NI': 'Nicaragua',
'NL': 'Netherlands',
'NO': 'Norway',
'NP': 'Nepal',
'NR': 'Nauru',
'NU': 'Niue',
'NZ': 'New Zealand',
'OM': 'Oman',
'PA': 'Panama',
'PE': 'Peru',
'PF': 'French Polynesia',
'PG': 'Papua New Guinea',
'PH': 'Philippines',
'PK': 'Pakistan',
'PL': 'Poland',
'PM': 'Saint Pierre and Miquelon',
'PN': 'Pitcairn',
'PR': 'Puerto Rico',
'PS': 'Palestinian Territory, Occupied',
'PT': 'Portugal',
'PW': 'Palau',
'PY': 'Paraguay',
'QA': 'Qatar',
'RE': 'Runion',
'RO': 'Romania',
'RS': 'Serbia',
'RU': 'Russian Federation',
'RW': 'Rwanda',
'SA': 'Saudi Arabia',
'SB': 'Solomon Islands',
'SC': 'Seychelles',
'SD': 'Sudan',
'SE': 'Sweden',
'SG': 'Singapore',
'SH': 'Saint Helena',
'SI': 'Slovenia',
'SJ': 'Svalbard and Jan Mayen',
'SK': 'Slovakia',
'SL': 'Sierra Leone',
'SM': 'San Marino',
'SN': 'Senegal',
'SO': 'Somalia',
'SR': 'Suriname',
'ST': 'Sao Tome and Principe',
'SV': 'El Salvador',
'SY': 'Syrian Arab Republic',
'SZ': 'Swaziland',
'TC': 'Turks and Caicos Islands',
'TD': 'Chad',
'TF': 'French Southern Territories',
'TG': 'Togo',
'TH': 'Thailand',
'TJ': 'Tajikistan',
'TK': 'Tokelau',
'TL': 'Timor-Leste',
'TM': 'Turkmenistan',
'TN': 'Tunisia',
'TO': 'Tonga',
'TR': 'Turkey',
'TT': 'Trinidad and Tobago',
'TV': 'Tuvalu',
'TW': 'Taiwan, Province of China',
'TZ': 'Tanzania, United Republic of',
'UA': 'Ukraine',
'UG': 'Uganda',
'UM': 'United States Minor Outlying Islands',
'US': 'United States',
'UY': 'Uruguay',
'UZ': 'Uzbekistan',
'VA': 'Holy See (Vatican City State)',
'VC': 'Saint Vincent and the Grenadines',
'VE': 'Venezuela',
'VG': 'Virgin Islands, British',
'VI': 'Virgin Islands, U.S.',
'VN': 'Viet Nam',
'VU': 'Vanuatu',
'WF': 'Wallis and Futuna',
'WS': 'Samoa',
'YE': 'Yemen',
'YT': 'Mayotte',
'ZA': 'South Africa',
'ZM': 'Zambia',
'ZW': 'Zimbabwe'}
def init(self, def init(self,
api, api,
name = None): name = None):

View File

@ -97,6 +97,36 @@ class Group(LastfmBase, Cacheable):
yield self.get_weekly_track_chart(wc.start, wc.end) yield self.get_weekly_track_chart(wc.start, wc.end)
return gen() return gen()
@LastfmBase.cached_property
def members(self):
params = self._default_params({'method': 'group.getMembers'})
@lazylist
def gen(lst):
data = self._api._fetch_data(params).find('members')
total_pages = int(data.attrib['totalPages'])
@lazylist
def gen2(lst, data):
for u in data.findall('user'):
yield User(
self._api,
name = u.findtext('name'),
real_name = u.findtext('realname'),
image = dict([(i.get('size'), i.text) for i in u.findall('image')]),
url = u.findtext('url')
)
for u in gen2(data):
yield u
for page in xrange(1, total_pages+1):
params.update({'page': page})
data = self._api._fetch_data(params).find('members')
for u in gen2(data):
yield u
return gen()
def _default_params(self, extra_params = {}): def _default_params(self, extra_params = {}):
if not self.name: if not self.name:
raise InvalidParametersError("group has to be provided.") raise InvalidParametersError("group has to be provided.")
@ -125,4 +155,5 @@ class Group(LastfmBase, Cacheable):
from lastfm.api import Api from lastfm.api import Api
from lastfm.error import InvalidParametersError from lastfm.error import InvalidParametersError
from lastfm.user import User
from lastfm.weeklychart import WeeklyChart, WeeklyAlbumChart, WeeklyArtistChart, WeeklyTrackChart from lastfm.weeklychart import WeeklyChart, WeeklyAlbumChart, WeeklyArtistChart, WeeklyTrackChart

View File

@ -169,6 +169,43 @@ class Tag(LastfmBase, Cacheable, Searchable):
return Playlist.fetch(self._api, return Playlist.fetch(self._api,
"lastfm://playlist/tag/%s/freetracks" % self.name) "lastfm://playlist/tag/%s/freetracks" % self.name)
@LastfmBase.cached_property
def weekly_chart_list(self):
params = self._default_params({'method': 'tag.getWeeklyChartList'})
data = self._api._fetch_data(params).find('weeklychartlist')
return [
WeeklyChart.create_from_data(self._api, self, c)
for c in data.findall('chart')
]
def get_weekly_artist_chart(self,
start = None,
end = None,
limit = None):
params = self._default_params({'method': 'tag.getWeeklyArtistChart'})
if limit is not None:
params['limit'] = limit
params = WeeklyArtistChart._check_weekly_chart_params(params, start, end)
data = self._api._fetch_data(params).find('weeklyartistchart')
return WeeklyArtistChart.create_from_data(self._api, self, data)
@LastfmBase.cached_property
def recent_weekly_artist_chart(self):
return self.get_weekly_artist_chart()
@LastfmBase.cached_property
def weekly_artist_chart_list(self):
wcl = list(self.weekly_chart_list)
wcl.reverse()
@lazylist
def gen(lst):
for wc in wcl:
try:
yield self.get_weekly_artist_chart(wc.start, wc.end)
except LastfmError:
pass
return gen()
@staticmethod @staticmethod
def get_top_tags(api): def get_top_tags(api):
params = {'method': 'tag.getTopTags'} params = {'method': 'tag.getTopTags'}
@ -227,7 +264,8 @@ class Tag(LastfmBase, Cacheable, Searchable):
from lastfm.album import Album from lastfm.album import Album
from lastfm.api import Api from lastfm.api import Api
from lastfm.artist import Artist from lastfm.artist import Artist
from lastfm.error import InvalidParametersError from lastfm.error import LastfmError, InvalidParametersError
from lastfm.playlist import Playlist from lastfm.playlist import Playlist
from lastfm.stats import Stats from lastfm.stats import Stats
from lastfm.track import Track from lastfm.track import Track
from lastfm.weeklychart import WeeklyChart, WeeklyArtistChart

View File

@ -14,19 +14,16 @@ class User(LastfmBase, Cacheable, Shoutable):
def init(self, def init(self,
api, api,
name = None, name = None,
real_name = None,
url = None, url = None,
image = None, image = None,
stats = None, stats = None):
language = None,
country = None,
age = None,
gender = None,
subscriber = None):
if not isinstance(api, Api): if not isinstance(api, Api):
raise InvalidParametersError("api reference must be supplied as an argument") raise InvalidParametersError("api reference must be supplied as an argument")
Shoutable.init(self, api) Shoutable.init(self, api)
self._api = api self._api = api
self._name = name self._name = name
self._real_name = real_name
self._url = url self._url = url
self._image = image self._image = image
self._stats = stats and Stats( self._stats = stats and Stats(
@ -36,17 +33,17 @@ class User(LastfmBase, Cacheable, Shoutable):
playcount = stats.playcount playcount = stats.playcount
) )
self._library = User.Library(api, self) self._library = User.Library(api, self)
self._language = language
self._country = country
self._age = age
self._gender = gender
self._subscriber = subscriber
@property @property
def name(self): def name(self):
"""name of the user""" """name of the user"""
return self._name return self._name
@property
def real_name(self):
"""real name of the user"""
return self._real_name
@property @property
def url(self): def url(self):
"""url of the user's page""" """url of the user's page"""
@ -63,29 +60,39 @@ class User(LastfmBase, Cacheable, Shoutable):
return self._stats return self._stats
@property @property
@LastfmBase.autheticate
def language(self): def language(self):
"""lang for the user""" """lang for the user"""
return self._language return self._language
@property @property
@LastfmBase.autheticate
def country(self): def country(self):
"""country for the user""" """country for the user"""
return self._country return self._country
@property @property
@LastfmBase.autheticate
def age(self): def age(self):
"""age for the user""" """age for the user"""
return self._age return self._age
@property @property
@LastfmBase.autheticate
def gender(self): def gender(self):
"""stats for the user""" """stats for the user"""
return self._gender return self._gender
@property @property
@LastfmBase.autheticate
def subscriber(self): def subscriber(self):
"""is the user a subscriber""" """is the user a subscriber"""
return self._subscriber return self._subscriber
@property
def autheticated(self):
"""is the user autheticated"""
return self._api.get_authenticated_user() == self
@LastfmBase.cached_property @LastfmBase.cached_property
def events(self): def events(self):
@ -126,7 +133,37 @@ class User(LastfmBase, Cacheable, Shoutable):
@LastfmBase.cached_property @LastfmBase.cached_property
def past_events(self): def past_events(self):
return self.get_past_events() return self.get_past_events()
@LastfmBase.autheticate
def get_recommended_events(self, limit = None):
params = {'method': 'user.getRecommendedEvents'}
if limit is not None:
params.update({'limit': limit})
@lazylist
def gen(lst):
data = self._api._fetch_data(params, sign = True, session = True).find('events')
total_pages = int(data.attrib['totalPages'])
@lazylist
def gen2(lst, data):
for e in data.findall('event'):
yield Event.create_from_data(self._api, e)
for e in gen2(data):
yield e
for page in xrange(2, total_pages+1):
params.update({'page': page})
data = self._api._fetch_data(params, sign = True, session = True).find('events')
for e in gen2(data):
yield e
return gen()
@LastfmBase.cached_property
def recommended_events(self):
return self.get_recommended_events()
def get_friends(self, def get_friends(self,
limit = None): limit = None):
params = self._default_params({'method': 'user.getFriends'}) params = self._default_params({'method': 'user.getFriends'})
@ -202,6 +239,15 @@ class User(LastfmBase, Cacheable, Shoutable):
for p in data.findall('playlist') for p in data.findall('playlist')
] ]
@LastfmBase.autheticate
def create_playlist(self, title, description = None):
params = {'method': 'playlist.create',
'title': title}
if description is not None:
params['description'] = description
self._api._post_data(params)
self._playlists = None
@LastfmBase.cached_property @LastfmBase.cached_property
def loved_tracks(self): def loved_tracks(self):
params = self._default_params({'method': 'user.getLovedTracks'}) params = self._default_params({'method': 'user.getLovedTracks'})
@ -353,7 +399,39 @@ class User(LastfmBase, Cacheable, Shoutable):
def top_artist(self): def top_artist(self):
"""top artist of the user""" """top artist of the user"""
pass pass
@LastfmBase.cached_property
@LastfmBase.autheticate
def recommended_artists(self):
params = {'method': 'user.getRecommendedArtists'}
@lazylist
def gen(lst):
data = self._api._fetch_data(params, sign = True, session = True).find('recommendations')
total_pages = 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'),
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, total_pages+1):
params.update({'page': page})
data = self._api._fetch_data(params, sign = True, session = True).find('recommendations')
for a in gen2(data):
yield a
return gen()
def get_top_tracks(self, period = None): def get_top_tracks(self, period = None):
params = self._default_params({'method': 'user.getTopTracks'}) params = self._default_params({'method': 'user.getTopTracks'})
if period is not None: if period is not None:
@ -516,24 +594,23 @@ class User(LastfmBase, Cacheable, Shoutable):
def library(self): def library(self):
return self._library return self._library
@staticmethod @staticmethod
def get_authenticated_user(api): def get_authenticated_user(api):
data = api._fetch_data({'method': 'user.getInfo'}, sign = True, session = True).find('user') data = api._fetch_data({'method': 'user.getInfo'}, sign = True, session = True).find('user')
return User( user = User(
api, api,
name = data.findtext('name'), name = data.findtext('name'),
url = data.findtext('url'), url = data.findtext('url'),
language = data.findtext('lang'),
country = Country(api, name = data.findtext('country')),
age = int(data.findtext('age')),
gender = data.findtext('gender'),
subscriber = (data.findtext('subscriber') == '1'),
stats = Stats(
subject = data.findtext('name'),
playcount = data.findtext('playcount')
)
) )
user._language = data.findtext('lang')
user._country = Country(api, name = Country.ISO_CODES[data.findtext('country')])
user._age = int(data.findtext('age'))
user._gender = data.findtext('gender')
user._subscriber = (data.findtext('subscriber') == "1")
user._stats = Stats(subject = user, playcount = data.findtext('playcount'))
return user
def _default_params(self, extra_params = {}): def _default_params(self, extra_params = {}):
if not self.name: if not self.name:
raise InvalidParametersError("user has to be provided.") raise InvalidParametersError("user has to be provided.")
@ -589,15 +666,27 @@ class User(LastfmBase, Cacheable, Shoutable):
@property @property
def creator(self): def creator(self):
return self._creator return self._creator
@property
def user(self):
return self._creator
def add_track(self, track): @LastfmBase.autheticate
def add_track(self, track, artist = None):
params = {'method': 'playlist.addTrack', 'playlistID': self.id} params = {'method': 'playlist.addTrack', 'playlistID': self.id}
if not isinstance(track, Track): if isinstance(track, Track):
track = self._api.search_track(track)[0] params['artist'] = track.artist.name
params['track'] = track.name
params['artist'] = track.artist.name else:
params['track'] = track.name if artist is None:
track = self._api.search_track(track)[0]
params['artist'] = track.artist.name
params['track'] = track.name
else:
params['artist'] = isinstance(artist, Artist) and artist.name or artist
params['track'] = track
self._api._post_data(params) self._api._post_data(params)
self._data = None
@staticmethod @staticmethod
def _hash_func(*args, **kwds): def _hash_func(*args, **kwds):
@ -673,7 +762,25 @@ class User(LastfmBase, Cacheable, Shoutable):
@LastfmBase.cached_property @LastfmBase.cached_property
def albums(self): def albums(self):
return self.get_albums() return self.get_albums()
@LastfmBase.autheticate
def add_album(self, album, artist = None):
params = {'method': 'library.addAlbum'}
if isinstance(album, Album):
params['artist'] = album.artist.name
params['album'] = album.name
else:
if artist is None:
album = self._api.search_album(album)[0]
params['artist'] = album.artist.name
params['album'] = album.name
else:
params['artist'] = isinstance(artist, Artist) and artist.name or artist
params['album'] = album
self._api._post_data(params)
self._albums = None
def get_artists(self, def get_artists(self,
limit = None): limit = None):
params = self._default_params({'method': 'library.getArtists'}) params = self._default_params({'method': 'library.getArtists'})
@ -720,6 +827,16 @@ class User(LastfmBase, Cacheable, Shoutable):
def artists(self): def artists(self):
return self.get_artists() return self.get_artists()
@LastfmBase.autheticate
def add_artist(self, artist):
params = {'method': 'library.addArtist'}
if isinstance(artist, Artist):
params['artist'] = artist.name
else:
params['artist'] = artist
self._api._post_data(params)
self._artists = None
def get_tracks(self, def get_tracks(self,
limit = None): limit = None):
params = self._default_params({'method': 'library.getTracks'}) params = self._default_params({'method': 'library.getTracks'})
@ -774,6 +891,23 @@ class User(LastfmBase, Cacheable, Shoutable):
def tracks(self): def tracks(self):
return self.get_tracks() return self.get_tracks()
@LastfmBase.autheticate
def add_track(self, track, artist = None):
params = {'method': 'library.addTrack'}
if isinstance(track, Track):
params['artist'] = track.artist.name
params['track'] = track.name
else:
if artist is None:
track = self._api.search_track(track)[0]
params['artist'] = track.artist.name
params['track'] = track.name
else:
params['artist'] = isinstance(artist, Artist) and artist.name or artist
params['track'] = track
self._api._post_data(params)
self._tracks = None
def _default_params(self, extra_params = {}): def _default_params(self, extra_params = {}):
if not self.user.name: if not self.user.name:
raise InvalidParametersError("user has to be provided.") raise InvalidParametersError("user has to be provided.")

View File

@ -170,19 +170,19 @@ class WeeklyArtistChart(WeeklyChart):
start = datetime.utcfromtimestamp(int(data.attrib['from'])), start = datetime.utcfromtimestamp(int(data.attrib['from'])),
end = datetime.utcfromtimestamp(int(data.attrib['to'])), end = datetime.utcfromtimestamp(int(data.attrib['to'])),
) )
count_attribute = data.find('artist').findtext('playcount') and 'playcount' or 'weight'
def get_count_attribute(artist):
return {count_attribute: int(eval(artist.findtext(count_attribute)))}
def get_count_attribute_sum(artists):
return {count_attribute: reduce(lambda x,y:(x + int(eval(y.findtext(count_attribute)))), artists, 0)}
return WeeklyArtistChart( return WeeklyArtistChart(
subject = subject, subject = subject,
start = datetime.utcfromtimestamp(int(data.attrib['from'])), start = datetime.utcfromtimestamp(int(data.attrib['from'])),
end = datetime.utcfromtimestamp(int(data.attrib['to'])), end = datetime.utcfromtimestamp(int(data.attrib['to'])),
stats = Stats( stats = Stats(
subject = subject, subject = subject,
playcount = reduce( **get_count_attribute_sum(data.findall('artist'))
lambda x,y:(
x + int(y.findtext('playcount'))
),
data.findall('artist'),
0
)
), ),
artists = [ artists = [
Artist( Artist(
@ -193,7 +193,7 @@ class WeeklyArtistChart(WeeklyChart):
stats = Stats( stats = Stats(
subject = a.findtext('name'), subject = a.findtext('name'),
rank = int(a.attrib['rank']), rank = int(a.attrib['rank']),
playcount = int(a.findtext('playcount')), **get_count_attribute(a)
), ),
url = a.findtext('url'), url = a.findtext('url'),
) )