#!/usr/bin/env python __author__ = "Abhinav Sarkar " __version__ = "0.2" __license__ = "GNU Lesser General Public License" __package__ = "lastfm" from lastfm.base import LastfmBase from lastfm.mixins import Cacheable, Searchable, Sharable, Taggable from lastfm.lazylist import lazylist from lastfm.decorators import cached_property, top_property class Track(LastfmBase, Cacheable, Sharable, Searchable, Taggable): """A class representing a track.""" def init(self, api, name = None, mbid = None, url = None, duration = None, streamable = None, full_track = None, artist = None, album = None, position = None, image = None, stats = None, played_on = None, loved_on = None, wiki = None, subject = None): if not isinstance(api, Api): raise InvalidParametersError("api reference must be supplied as an argument") Taggable.init(self, api) Sharable.init(self, api) self._api = api self._id = id self._name = name self._mbid = mbid self._url = url self._duration = duration self._streamable = streamable self._full_track = full_track self._artist = artist self._album = album self._position = position self._image = image self._stats = stats and Stats( subject = self, match = stats.match, playcount = stats.playcount, rank = stats.rank, listeners = stats.listeners, ) self._played_on = played_on self._loved_on = loved_on self._wiki = wiki and Wiki( subject = self, published = wiki.published, summary = wiki.summary, content = wiki.content ) self._subject = subject @property def id(self): """id of the track""" return self._id @property def name(self): """name of the track""" return self._name @property def mbid(self): """mbid of the track""" return self._mbid @property def url(self): """url of the tracks's page""" return self._url @property def duration(self): """duration of the tracks's page""" return self._duration @property def streamable(self): """is the track streamable""" if self._streamable is None: self._fill_info() return self._streamable @property def full_track(self): """is the full track streamable""" if self._full_track is None: self._fill_info() return self._full_track @property def artist(self): """artist of the track""" return self._artist @property def album(self): """artist of the track""" if self._album is None: self._fill_info() return self._album @property def position(self): """position of the track""" if self._position is None: self._fill_info() return self._position @property def image(self): """image of the track's album cover""" return self._image @property def stats(self): """stats of the track""" return self._stats @property def played_on(self): """datetime the track was last played""" return self._played_on @property def loved_on(self): """datetime the track was marked 'loved'""" return self._loved_on @property def wiki(self): """wiki of the track""" if self._wiki == "na": return None if self._wiki is None: self._fill_info() return self._wiki @cached_property def similar(self): """tracks similar to this track""" params = Track._check_params( {'method': 'track.getSimilar'}, self.artist.name, self.name, self.mbid ) data = self._api._fetch_data(params).find('similartracks') 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'), match = float(t.findtext('match')) ), streamable = (t.findtext('streamable') == '1'), full_track = (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') ] @top_property("similar") def most_similar(self): """track most similar to this track""" pass @cached_property def top_fans(self): """top fans of the track""" params = Track._check_params( {'method': 'track.getTopFans'}, self.artist.name, self.name, self.mbid ) data = self._api._fetch_data(params).find('topfans') return [ User( self._api, subject = self, name = u.findtext('name'), url = u.findtext('url'), image = dict([(i.get('size'), i.text) for i in u.findall('image')]), stats = Stats( subject = u.findtext('name'), weight = int(u.findtext('weight')) ) ) for u in data.findall('user') ] @top_property("top_fans") def top_fan(self): """topmost fan of the track""" pass @cached_property def top_tags(self): """top tags for the track""" params = Track._check_params( {'method': 'track.getTopTags'}, self.artist.name, self.name, self.mbid ) data = self._api._fetch_data(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') ] @top_property("top_tags") def top_tag(self): """topmost tag for the track""" pass def love(self): params = self._default_params({'method': 'track.love'}) self._api._post_data(params) def ban(self): params = self._default_params({'method': 'track.ban'}) self._api._post_data(params) @staticmethod def get_info(api, artist = None, track = None, mbid = None): data = Track._fetch_data(api, artist, track, mbid) t = Track( api, name = data.findtext('name'), artist = Artist( api, name = data.findtext('artist/name'), ), ) t._fill_info() return t def _default_params(self, extra_params = {}): if not (self.artist and self.name): raise InvalidParametersError("artist and track have to be provided.") params = {'artist': self.artist.name, 'track': self.name} params.update(extra_params) return params @staticmethod def _search_yield_func(api, track): return Track( api, name = track.findtext('name'), artist = Artist( api, name=track.findtext('artist') ), url = track.findtext('url'), stats = Stats( subject=track.findtext('name'), listeners=int(track.findtext('listeners')) ), streamable = (track.findtext('streamable') == '1'), full_track = (track.find('streamable').attrib['fulltrack'] == '1'), image = dict([(i.get('size'), i.text) for i in track.findall('image')]), ) @staticmethod def _fetch_data(api, artist = None, track = None, mbid = None): params = Track._check_params({'method': 'track.getInfo'}, artist, track, mbid) return api._fetch_data(params).find('track') def _fill_info(self): data = Track._fetch_data(self._api, self.artist.name, self.name) self._id = int(data.findtext('id')) self._mbid = data.findtext('mbid') self._url = data.findtext('url') self._duration = int(data.findtext('duration')) self._streamable = (data.findtext('streamable') == '1') self._full_track = (data.find('streamable').attrib['fulltrack'] == '1') self._image = dict([(i.get('size'), i.text) for i in data.findall('image')]) self._stats = Stats( subject = self, listeners = int(data.findtext('listeners')), playcount = int(data.findtext('playcount')), ) self._artist = Artist( self._api, name = data.findtext('artist/name'), mbid = data.findtext('artist/mbid'), url = data.findtext('artist/url') ) if data.find('album') is not None: self._album = Album( self._api, artist = self._artist, name = data.findtext('album/title'), mbid = data.findtext('album/mbid'), url = data.findtext('album/url'), image = dict([(i.get('size'), i.text) for i in data.findall('album/image')]) ) self._position = data.find('album').attrib['position'].strip() \ and int(data.find('album').attrib['position']) if data.find('wiki') is not None: self._wiki = Wiki( self, published = datetime(*(time.strptime( data.findtext('wiki/published').strip(), '%a, %d %b %Y %H:%M:%S +0000' )[0:6])), summary = data.findtext('wiki/summary'), content = data.findtext('wiki/content') ) else: self._wiki = 'na' @staticmethod def _check_params(params, artist = None, track = None, mbid = None): if not ((artist and track) or mbid): raise InvalidParametersError("either (artist and track) or mbid has to be given as argument.") if artist and track: params.update({'artist': artist, 'track': track}) elif mbid: params.update({'mbid': mbid}) return params @staticmethod def _hash_func(*args, **kwds): try: return hash("%s%s" % (kwds['name'], hash(kwds['artist']))) except KeyError: raise InvalidParametersError("name and artist have to be provided for hashing") def __hash__(self): return self.__class__._hash_func(name = self.name, artist = self.artist) def __eq__(self, other): if self.mbid and other.mbid: return self.mbid == other.mbid if self.url and other.url: return self.url == other.url if (self.name and self.artist) and (other.name and other.artist): return (self.name == other.name) and (self.artist == other.artist) return super(Track, self).__eq__(other) def __lt__(self, other): return self.name < other.name def __repr__(self): return "" % (self.name, self.artist.name) import time from datetime import datetime from lastfm.api import Api from lastfm.artist import Artist from lastfm.album import Album from lastfm.error import InvalidParametersError from lastfm.stats import Stats from lastfm.tag import Tag from lastfm.user import User from lastfm.wiki import Wiki