annotate Yading/7digital-python/lib/py7digital.py @ 13:844d341cf643 tip

Back up before ISMIR
author Yading Song <yading.song@eecs.qmul.ac.uk>
date Thu, 31 Oct 2013 13:17:06 +0000
parents 8c29444cb5fd
children
rev   line source
yading@7 1 #!/usr/bin/env python
yading@7 2 """A python interface to 7Digital web service (non-premium services)"""
yading@7 3 import os
yading@7 4 import urllib2, urllib
yading@7 5 import re
yading@7 6 import urlparse
yading@7 7 from xml.dom import minidom
yading@7 8 try:
yading@7 9 from hashlib import md5
yading@7 10 except ImportError:
yading@7 11 from md5 import md5
yading@7 12
yading@7 13 __name__ = 'py7digital'
yading@7 14 __doc__ = 'A python interface to 7Digital web service'
yading@7 15 __author__ = 'Oscar Celma, Pau Capella'
yading@7 16 __version__ = '0.0.1'
yading@7 17 __license__ = 'GPL'
yading@7 18 __maintainer__ = 'Oscar Celma'
yading@7 19 __email__ = 'ocelma@bmat.com'
yading@7 20 __status__ = 'Beta'
yading@7 21
yading@7 22 API_VERSION = '1.2'
yading@7 23 HOST_NAME = 'api.7digital.com/' + API_VERSION
yading@7 24 OAUTHKEY = '' #TODO Put your oauth key here
yading@7 25 COUNTRY = '' # ISO Country
yading@7 26
yading@7 27 __cache_dir = './cache' # Set cache directory
yading@7 28 __cache_enabled = False # Enable cache? if set to True, make sure that __cache_dir exists! (e.g. $ mkdir ./cache)
yading@7 29
yading@7 30 class ServiceException(Exception):
yading@7 31 """Exception related to the web service."""
yading@7 32
yading@7 33 def __init__(self, type, message):
yading@7 34 self._type = type
yading@7 35 self._message = message
yading@7 36
yading@7 37 def __str__(self):
yading@7 38 return self._type + ': ' + self._message
yading@7 39
yading@7 40 def get_message(self):
yading@7 41 return self._message
yading@7 42
yading@7 43 def get_type(self):
yading@7 44 return self._type
yading@7 45
yading@7 46 class _Request(object):
yading@7 47 """Representing an abstract web service operation."""
yading@7 48
yading@7 49 def __init__(self, method_name, params):
yading@7 50 self.params = params
yading@7 51 self.method = method_name
yading@7 52
yading@7 53 def _download_response(self):
yading@7 54 """Returns a response"""
yading@7 55 data = []
yading@7 56 for name in self.params.keys():
yading@7 57 data.append('='.join((name, urllib.quote_plus(self.params[name].replace('&amp;', '&').encode('utf8')))))
yading@7 58 data = '&'.join(data)
yading@7 59
yading@7 60 url = HOST_NAME
yading@7 61 parsed_url = urlparse.urlparse(url)
yading@7 62 if not parsed_url.scheme:
yading@7 63 url = "http://" + url
yading@7 64 url += self.method + '?oauth_consumer_key=' + OAUTHKEY + '&'
yading@7 65 if COUNTRY:
yading@7 66 url += 'country=' + COUNTRY + '&'
yading@7 67 url += data
yading@7 68 #print url
yading@7 69
yading@7 70 request = urllib2.Request(url)
yading@7 71 response = urllib2.urlopen(request)
yading@7 72 return response.read()
yading@7 73
yading@7 74 def execute(self, cacheable=False):
yading@7 75 try:
yading@7 76 if is_caching_enabled() and cacheable:
yading@7 77 response = self._get_cached_response()
yading@7 78 else:
yading@7 79 response = self._download_response()
yading@7 80 return minidom.parseString(response)
yading@7 81 except urllib2.HTTPError, e:
yading@7 82 raise self._get_error(e.fp.read())
yading@7 83
yading@7 84 def _get_cache_key(self):
yading@7 85 """Cache key"""
yading@7 86 keys = self.params.keys()[:]
yading@7 87 keys.sort()
yading@7 88 string = self.method
yading@7 89 for name in keys:
yading@7 90 string += name
yading@7 91 string += self.params[name]
yading@7 92 return get_md5(string)
yading@7 93
yading@7 94 def _is_cached(self):
yading@7 95 """Returns True if the request is available in the cache."""
yading@7 96 return os.path.exists(os.path.join(_get_cache_dir(), self._get_cache_key()))
yading@7 97
yading@7 98 def _get_cached_response(self):
yading@7 99 """Returns a file object of the cached response."""
yading@7 100 if not self._is_cached():
yading@7 101 response = self._download_response()
yading@7 102 response_file = open(os.path.join(_get_cache_dir(), self._get_cache_key()), "w")
yading@7 103 response_file.write(response)
yading@7 104 response_file.close()
yading@7 105 return open(os.path.join(_get_cache_dir(), self._get_cache_key()), "r").read()
yading@7 106
yading@7 107 def _get_error(self, text):
yading@7 108 return ServiceException('Error', text)
yading@7 109 raise
yading@7 110
yading@7 111
yading@7 112 class _BaseObject(object):
yading@7 113 """An abstract webservices object."""
yading@7 114
yading@7 115 def __init__(self, method):
yading@7 116 self._method = method
yading@7 117 self._xml = None
yading@7 118
yading@7 119 def _request(self, method_name , cacheable = False, params = None):
yading@7 120 if not params:
yading@7 121 params = self._get_params()
yading@7 122 return _Request(method_name, params).execute(cacheable)
yading@7 123
yading@7 124 def _get_params(self):
yading@7 125 return dict()
yading@7 126
yading@7 127
yading@7 128 class Artist(_BaseObject):
yading@7 129 """ A 7digital artist """
yading@7 130
yading@7 131 def __init__(self, id):
yading@7 132 _BaseObject.__init__(self, '/artist/')
yading@7 133
yading@7 134 self.name = None
yading@7 135 self.id = id
yading@7 136 self._url = None
yading@7 137 self._image = None
yading@7 138 self._albums = None
yading@7 139 self._top_tracks = None
yading@7 140 self._tags = None
yading@7 141 self._recommended_albums = None
yading@7 142
yading@7 143 def __repr__(self):
yading@7 144 return self.get_name().encode('utf8')
yading@7 145
yading@7 146 def __eq__(self, other):
yading@7 147 return self.get_id() == other.get_id()
yading@7 148
yading@7 149 def __ne__(self, other):
yading@7 150 return self.get_id() != other.get_id()
yading@7 151
yading@7 152 def get_id(self):
yading@7 153 """ Returns the 7digital artist id """
yading@7 154 return self.id
yading@7 155
yading@7 156 def get_name(self):
yading@7 157 """ Returns the name of the artist """
yading@7 158 if self.name is None:
yading@7 159 self.name = ''
yading@7 160 try:
yading@7 161 if not self._xml : self._xml = self._request(self._method, + 'details', True, {'artistid': self.id})
yading@7 162 self.name = _extract(self._xml, 'artist', 1) or ''
yading@7 163 except:
yading@7 164 return self.name
yading@7 165 return self.name
yading@7 166
yading@7 167 def set_name(self, name) :
yading@7 168 self.name = name
yading@7 169
yading@7 170 def get_image(self):
yading@7 171 """ Returns the image url of an artist """
yading@7 172 if self._image is None :
yading@7 173 if not self._xml : self._xml = self._request(self._method + 'details', True, {'artistid': self.id})
yading@7 174 self._image = _extract(self._xml, 'image')
yading@7 175 return self._image
yading@7 176
yading@7 177 def set_image(self, image) :
yading@7 178 self._image = image
yading@7 179
yading@7 180 def get_url(self):
yading@7 181 """ Returns the url of an artist """
yading@7 182 if self._url is None :
yading@7 183 if not self._xml : self._xml = self._request(self._method + 'details', True, {'artistid': self.id})
yading@7 184 self._url = _extract(self._xml, 'url')
yading@7 185 return self._url
yading@7 186
yading@7 187 def set_url(self, url) :
yading@7 188 self._url = url
yading@7 189
yading@7 190 def get_tags(self, pageSize=10):
yading@7 191 """ Returns the tags of an artist """
yading@7 192 if self._tags is None:
yading@7 193 self._tags = []
yading@7 194 xml = self._request(self._method + 'tags', True, {'artistid': self.id})
yading@7 195 for node in xml.getElementsByTagName('tag') :
yading@7 196 self._tags.append(_get_tag(node))
yading@7 197 if self._tags:
yading@7 198 self._tags.sort()
yading@7 199 return self._tags[:pageSize]
yading@7 200
yading@7 201 def get_albums(self, pageSize=10):
yading@7 202 """ Returns the albums of an artist """
yading@7 203 if self._albums is not None: return self._albums
yading@7 204
yading@7 205 results = []
yading@7 206 xml = self._request(self._method + 'releases', True, {'artistid': self.id, 'pageSize': str(pageSize)})
yading@7 207 for node in xml.getElementsByTagName('release'):
yading@7 208 album = _get_album(node, self)
yading@7 209 results.append(album)
yading@7 210 self._albums = results
yading@7 211 return self._albums
yading@7 212
yading@7 213 def get_recommended_albums(self, pageSize=10):
yading@7 214 """ Returns a list of recommended albums based on the seed artist """
yading@7 215 if self._recommended_albums is not None: return self._recommended_albums
yading@7 216
yading@7 217 results = []
yading@7 218 xml = self._request('/release/recommend', True, {'artistid': self.id, 'pageSize': str(pageSize)}) # TODO if country is set gives different results
yading@7 219 for node in xml.getElementsByTagName('release'):
yading@7 220 results.append(_get_album(node, _get_artist(node.getElementsByTagName('artist')[0])))
yading@7 221 self._recommended_albums = results
yading@7 222 return self._recommended_albums
yading@7 223
yading@7 224 def get_top_tracks(self, pageSize=10):
yading@7 225 """ Returns the top tracks of an artist """
yading@7 226 if self._top_tracks is not None: return self._top_tracks
yading@7 227
yading@7 228 results = []
yading@7 229 xml = self._request(self._method + 'toptracks', True, {'artistid': self.id, 'pageSize': str(pageSize)})
yading@7 230 for node in xml.getElementsByTagName('track'):
yading@7 231 results.append(_get_track(node, None, self))
yading@7 232 self._top_tracks = results
yading@7 233 return self._top_tracks
yading@7 234
yading@7 235 class Album(_BaseObject):
yading@7 236 """ A 7digital album """
yading@7 237 def __init__(self, id=HOST_NAME):
yading@7 238 _BaseObject.__init__(self, '/release/')
yading@7 239 self.id = id
yading@7 240 self.artist = None
yading@7 241 self.title = None
yading@7 242
yading@7 243 self._url = None
yading@7 244 self._type = None
yading@7 245 self._barcode = None
yading@7 246 self._year = None
yading@7 247 self._image = None
yading@7 248 self._label = None
yading@7 249 self._tags = None
yading@7 250 self._tracks = None
yading@7 251 self._similar = None
yading@7 252 self._release_date = None
yading@7 253 self._added_date = None
yading@7 254
yading@7 255 def __repr__(self):
yading@7 256 if self.get_artist():
yading@7 257 return self.get_artist().get_name().encode('utf8') + ' - ' + self.get_title().encode('utf8')
yading@7 258 return self.get_title().encode('utf8')
yading@7 259
yading@7 260 def __eq__(self, other):
yading@7 261 return self.get_id() == other.get_id()
yading@7 262
yading@7 263 def __ne__(self, other):
yading@7 264 return self.get_id() != other.get_id()
yading@7 265
yading@7 266 def get_id(self):
yading@7 267 """ Returns the 7digital album id """
yading@7 268 return self.id
yading@7 269
yading@7 270 def get_title(self):
yading@7 271 """ Returns the name of the album """
yading@7 272 if self.title is None:
yading@7 273 if not self._xml : self._xml = self._request(self._method + 'details', True, {'releaseid': self.id})
yading@7 274 self.title = _extract(self._xml, 'release', 1)
yading@7 275 return self.title
yading@7 276
yading@7 277 def set_title(self, title):
yading@7 278 if title is None:
yading@7 279 title = ''
yading@7 280 self.title = title
yading@7 281
yading@7 282 def get_type(self):
yading@7 283 """ Returns the type (CD, DVD, etc.) of the album """
yading@7 284 if self._type is None:
yading@7 285 if not self._xml : self._xml = self._request(self._method + 'details', True, {'releaseid': self.id})
yading@7 286 self._type = _extract(self._xml, 'type')
yading@7 287 return self._type
yading@7 288
yading@7 289 def set_type(self, type):
yading@7 290 self._type = type
yading@7 291
yading@7 292 def get_year(self):
yading@7 293 """ Returns the year of the album """
yading@7 294 if self._year is None:
yading@7 295 if not self._xml : self._xml = self._request(self._method + 'details', True, {'releaseid': self.id})
yading@7 296 self._year = _extract(self._xml, 'year')
yading@7 297 return self._year
yading@7 298
yading@7 299 def set_year(self, year):
yading@7 300 self._year = year
yading@7 301
yading@7 302 def get_barcode(self):
yading@7 303 """ Returns the barcode of the album """
yading@7 304 if self._barcode is None:
yading@7 305 if not self._xml : self._xml = self._request(self._method + 'details', True, {'releaseid': self.id})
yading@7 306 self.barcode = _extract(self._xml, 'barcode')
yading@7 307 return self._barcode
yading@7 308
yading@7 309 def set_barcode(self, barcode):
yading@7 310 self._barcode = barcode
yading@7 311
yading@7 312 def get_url(self):
yading@7 313 """ Returns the url of the album """
yading@7 314 if self._url is None :
yading@7 315 if not self._xml : self._xml = self._request(self._method + 'details', True, {'releaseid': self.id})
yading@7 316 self._url = _extract(self._xml, 'url')
yading@7 317 return self._url
yading@7 318
yading@7 319 def set_url(self, url) :
yading@7 320 self._url = url
yading@7 321
yading@7 322 def get_label(self):
yading@7 323 """ Returns the label of the album """
yading@7 324 if self._label is None:
yading@7 325 if not self._xml : self._xml = self._request(self._method + 'details', True, {'releaseid': self.id})
yading@7 326 self.set_label(_get_label(self._xml.getElementsByTagName('label')))
yading@7 327 return self._label
yading@7 328
yading@7 329 def set_label(self, label):
yading@7 330 self._label = label
yading@7 331
yading@7 332 def get_release_date(self):
yading@7 333 """ Returns the release date of the album """
yading@7 334 if self._release_date is None :
yading@7 335 if not self._xml : self._xml = self._request(self._method + 'details', True, {'releaseid': self.id})
yading@7 336 self._release_date = _extract(self._xml, 'releaseDate')
yading@7 337 return self._release_date
yading@7 338
yading@7 339 def set_release_date(self, release_date):
yading@7 340 self._release_date = release_date
yading@7 341
yading@7 342 def get_added_date(self):
yading@7 343 """ Returns the added date of the album """
yading@7 344 if self._added_date is None :
yading@7 345 if not self._xml : self._xml = self._request(self._method + 'details', True, {'releaseid': self.id})
yading@7 346 self._added_date = _extract(self._xml, 'addedDate')
yading@7 347 return self._added_date
yading@7 348
yading@7 349 def set_added_date(self, added_date):
yading@7 350 self._added_date = added_date
yading@7 351
yading@7 352 def get_artist(self):
yading@7 353 """ Returns the Artist of the album """
yading@7 354 if not self.artist:
yading@7 355 self.set_artist(_get_artist(self._xml.getElementsByTagName('artist')))
yading@7 356 return self.artist
yading@7 357
yading@7 358 def set_artist(self, artist):
yading@7 359 """ Sets the Artist object of the track """
yading@7 360 self.artist = artist
yading@7 361
yading@7 362 def get_image(self):
yading@7 363 """ Returns album image url """
yading@7 364 if self._image is None:
yading@7 365 if not self._xml : self._xml = self._request(self._method + 'details', True, {'releaseid': self.id})
yading@7 366 self._image = _extract(self._xml, 'release_small_image')
yading@7 367 return self._image
yading@7 368
yading@7 369 def set_image(self, image):
yading@7 370 if image is None: image = ''
yading@7 371 self._image = image
yading@7 372
yading@7 373 def get_tags(self, pageSize=10):
yading@7 374 """ Returns the tags of the album """
yading@7 375 if self._tags is None:
yading@7 376 self._tags = []
yading@7 377 xml = self._request(self._method + 'tags', True, {'releaseid': self.id})
yading@7 378 for node in xml.getElementsByTagName('tag') :
yading@7 379 self._tags.append(_get_tag(node))
yading@7 380 if self._tags:
yading@7 381 self._tags.sort()
yading@7 382 return self._tags[:pageSize]
yading@7 383
yading@7 384 def get_tracks(self, pageSize=10):
yading@7 385 """ Returns the tracks of the album """
yading@7 386 if self._tracks is not None: return self._tracks
yading@7 387
yading@7 388 results = []
yading@7 389 xml = self._request(self._method + 'tracks', True, {'releaseid': self.id, 'pageSize': str(pageSize)})
yading@7 390 for node in xml.getElementsByTagName('track'):
yading@7 391 if self.artist is None:
yading@7 392 self.set_artist(_get_artist(node.getElementsByTagName('artist')))
yading@7 393 track = _get_track(node, self, self.get_artist())
yading@7 394 results.append(track)
yading@7 395 self._tracks = results
yading@7 396 return self._tracks
yading@7 397
yading@7 398 def get_similar(self, pageSize=10):
yading@7 399 """ Returns a list similar albums """
yading@7 400 if self._similar is not None: return self._similar
yading@7 401
yading@7 402 results = []
yading@7 403 xml = self._request(self._method + 'recommend', True, {'releaseid': self.id, 'pageSize': str(pageSize)})
yading@7 404 for node in xml.getElementsByTagName('release'):
yading@7 405 album = _get_album(node, _get_artist(node.getElementsByTagName('artist')[0]))
yading@7 406 if self == album:
yading@7 407 continue #Same album!
yading@7 408 results.append(album)
yading@7 409 self._similar = results
yading@7 410 return self._similar
yading@7 411
yading@7 412
yading@7 413 class Track(_BaseObject):
yading@7 414 """ A Bmat track. """
yading@7 415 def __init__(self, id, artist=None):
yading@7 416 _BaseObject.__init__(self, '/track/')
yading@7 417
yading@7 418 if isinstance(artist, Artist):
yading@7 419 self.artist = artist
yading@7 420 else:
yading@7 421 self.artist = None
yading@7 422 self.id = id
yading@7 423 self.title = None
yading@7 424 self.artist = None
yading@7 425 self.album = None
yading@7 426
yading@7 427 self._isrc = None
yading@7 428 self._url = None
yading@7 429 self._preview = 'http://api.7digital.com/1.2/track/preview?trackid=' + self.id
yading@7 430 self._image = None
yading@7 431 self._tags = None
yading@7 432 self._duration = None
yading@7 433 self._version = None
yading@7 434 self._explicit = None
yading@7 435 self._position = None
yading@7 436
yading@7 437 def __repr__(self):
yading@7 438 return self.get_artist().get_name().encode('utf8') + ' - ' + self.get_title().encode('utf8')
yading@7 439
yading@7 440 def __eq__(self, other):
yading@7 441 return self.get_id() == other.get_id()
yading@7 442
yading@7 443 def __ne__(self, other):
yading@7 444 return self.get_id() != other.get_id()
yading@7 445
yading@7 446 def get_id(self):
yading@7 447 """ Returns the track id """
yading@7 448 return self.id
yading@7 449
yading@7 450 def get_title(self):
yading@7 451 """ Returns the track title """
yading@7 452 if self.title is None:
yading@7 453 if not self._xml : self._xml = self._request(self._method + 'details', True, {'trackid': self.id})
yading@7 454 self.title = _extract(self._xml, 'track', 1)
yading@7 455 return self.title
yading@7 456
yading@7 457 def set_title(self, title):
yading@7 458 self.title = title
yading@7 459
yading@7 460 def get_isrc(self):
yading@7 461 """ Returns the ISRC of the track """
yading@7 462 if self._isrc is None:
yading@7 463 if not self._xml : self._xml = self._request(self._method + 'details', True, {'trackid': self.id})
yading@7 464 self._isrc = _extract(self._xml, 'isrc')
yading@7 465 return self._isrc
yading@7 466
yading@7 467 def set_isrc(self, isrc):
yading@7 468 self._isrc = isrc
yading@7 469
yading@7 470 def get_url(self):
yading@7 471 """ Returns the url of the track """
yading@7 472 if self._url is None :
yading@7 473 if not self._xml : self._xml = self._request(self._method + 'details', True, {'trackid': self.id})
yading@7 474 self._url = _extract(self._xml, 'url')
yading@7 475 return self._url
yading@7 476
yading@7 477 def set_url(self, url):
yading@7 478 self._url = url
yading@7 479
yading@7 480 def get_audio(self):
yading@7 481 return self.get_preview()
yading@7 482
yading@7 483 def get_preview(self):
yading@7 484 """ Returns the url of the track """
yading@7 485 if self._preview is None :
yading@7 486 if not self._xml : self._xml = self._request(self._method + 'preview', True, {'trackid': self.id})
yading@7 487 self._preview = _extract(self._xml, 'url')
yading@7 488 return self._preview
yading@7 489
yading@7 490 def get_duration(self):
yading@7 491 """ Returns the duration of the track """
yading@7 492 if self._duration is None :
yading@7 493 if not self._xml : self._xml = self._request(self._method + 'details', True, {'trackid': self.id})
yading@7 494 self._duration = _extract(self._xml, 'duration')
yading@7 495 return self._duration
yading@7 496
yading@7 497 def set_duration(self, duration):
yading@7 498 self._duration = duration
yading@7 499
yading@7 500 def get_position(self):
yading@7 501 """ Returns the track number in the release """
yading@7 502 if self._position is None :
yading@7 503 if not self._xml : self._xml = self._request(self._method + 'details', True, {'trackid': self.id})
yading@7 504 self._position = _extract(self._xml, 'trackNumber')
yading@7 505 return self._position
yading@7 506
yading@7 507 def set_position(self, track_number):
yading@7 508 self._position = track_number
yading@7 509
yading@7 510 def get_explicit(self):
yading@7 511 """ Returns whether the track contains explicit content """
yading@7 512 if self._explicit is None :
yading@7 513 if not self._xml : self._xml = self._request(self._method + 'details', True, {'trackid': self.id})
yading@7 514 self._explicit = _extract(self._xml, 'explicitContent')
yading@7 515 return self._explicit
yading@7 516
yading@7 517 def set_explicit(self, explicit):
yading@7 518 self._explicit = explicit
yading@7 519
yading@7 520 def get_version(self):
yading@7 521 """ Returns the version of the track """
yading@7 522 if self._version is None :
yading@7 523 if not self._xml : self._xml = self._request(self._method + 'details', True, {'trackid': self.id})
yading@7 524 self._version = _extract(self._xml, 'version')
yading@7 525 return self._version
yading@7 526
yading@7 527 def set_version(self, version):
yading@7 528 self._version = version
yading@7 529
yading@7 530 def get_artist(self):
yading@7 531 """ Returns the Artist of the track """
yading@7 532 if not self.artist:
yading@7 533 self.set_artist(_get_artist(self._xml.getElementsByTagName('artist')))
yading@7 534 return self.artist
yading@7 535
yading@7 536 def set_artist(self, artist):
yading@7 537 """ Sets the Artist object of the track """
yading@7 538 self.artist = artist
yading@7 539
yading@7 540 def get_album(self):
yading@7 541 """ Returns the associated Album object """
yading@7 542 if not self.album:
yading@7 543 self.set_album(_get_album(self._xml.getElementsByTagName('release')))
yading@7 544 return self.album
yading@7 545
yading@7 546 def set_album(self, album):
yading@7 547 """ Sets the Album object of the track """
yading@7 548 self.album = album
yading@7 549
yading@7 550
yading@7 551 class Tag(_BaseObject):
yading@7 552 """ A Tag """
yading@7 553 def __init__(self, id):
yading@7 554 _BaseObject.__init__(self, '/tag/')
yading@7 555
yading@7 556 self.id = id
yading@7 557 self.name = None
yading@7 558 self._url = None
yading@7 559
yading@7 560 def __repr__(self):
yading@7 561 return self.get_name().encode('utf8')
yading@7 562
yading@7 563 def __eq__(self, other):
yading@7 564 return self.get_id() == other.get_id()
yading@7 565
yading@7 566 def __ne__(self, other):
yading@7 567 return self.get_id() != other.get_id()
yading@7 568
yading@7 569 def get_id(self):
yading@7 570 """ Returns the tag id """
yading@7 571 return self.id
yading@7 572
yading@7 573 def get_name(self):
yading@7 574 """ Returns the tag name """
yading@7 575 if self.name is None:
yading@7 576 if not self._xml : self._xml = self._request(self._method + 'details', True, {'tagid': self.id})
yading@7 577 self.name = _extract(self._xml, 'name')
yading@7 578 return self.name
yading@7 579
yading@7 580 def set_name(self, name):
yading@7 581 self.name = name
yading@7 582
yading@7 583 def get_url(self):
yading@7 584 """ Returns the url of the tag"""
yading@7 585 if self._url is None:
yading@7 586 if not self._xml : self._xml = self._request(self._method + 'details', True, {'tagid': self.id})
yading@7 587 self._url = _extract(self._xml, 'url')
yading@7 588 return self._url
yading@7 589
yading@7 590 def set_url(self, url):
yading@7 591 self._url = url
yading@7 592
yading@7 593 class Label(_BaseObject):
yading@7 594 """ A Label """
yading@7 595 def __init__(self, id):
yading@7 596 _BaseObject.__init__(self, '')
yading@7 597
yading@7 598 self.id = id
yading@7 599 self.name = None
yading@7 600
yading@7 601 def __repr__(self):
yading@7 602 return self.get_name().encode('utf8')
yading@7 603
yading@7 604 def __eq__(self, other):
yading@7 605 return self.get_id() == other.get_id()
yading@7 606
yading@7 607 def __ne__(self, other):
yading@7 608 return self.get_id() != other.get_id()
yading@7 609
yading@7 610 def get_id(self):
yading@7 611 """ Returns the label id """
yading@7 612 return self.id
yading@7 613
yading@7 614 def get_name(self):
yading@7 615 """ Returns the label name """
yading@7 616 return self.name
yading@7 617
yading@7 618 def set_name(self, name):
yading@7 619 self.name = name
yading@7 620
yading@7 621
yading@7 622 class _Search(_BaseObject):
yading@7 623 """ An abstract class for search """
yading@7 624
yading@7 625 def __init__(self, method, search_terms, xml_tag):
yading@7 626 _BaseObject.__init__(self, method)
yading@7 627
yading@7 628 self._search_terms = search_terms
yading@7 629 self._xml_tag = xml_tag
yading@7 630
yading@7 631 self._results_per_page = 10
yading@7 632 if self._search_terms.has_key('pageSize'):
yading@7 633 self._results_per_page = str(self._search_terms['pageSize'])
yading@7 634 else:
yading@7 635 self._search_terms['pageSize'] = str(self._results_per_page)
yading@7 636 self._last_page_index = 0
yading@7 637 self._hits = None
yading@7 638
yading@7 639 def get_total_result_count(self):
yading@7 640 if self._hits is not None:
yading@7 641 return self._hits
yading@7 642 params = self._get_params()
yading@7 643 params['pageSize'] = '1'
yading@7 644 xml = self._request(self._method, True, params)
yading@7 645 hits = int(_extract(xml, 'totalItems'))
yading@7 646 self._hits = hits
yading@7 647 return self._hits
yading@7 648
yading@7 649 def _get_params(self):
yading@7 650 params = {}
yading@7 651 for key in self._search_terms.keys():
yading@7 652 params[key] = self._search_terms[key]
yading@7 653 return params
yading@7 654
yading@7 655 def _retrieve_page(self, page_index):
yading@7 656 """ Returns the xml nodes to process """
yading@7 657 params = self._get_params()
yading@7 658
yading@7 659 if page_index != 0:
yading@7 660 #offset = self._results_per_page * page_index
yading@7 661 params["page"] = str(page_index)
yading@7 662
yading@7 663 doc = self._request(self._method, True, params)
yading@7 664 return doc.getElementsByTagName(self._xml_tag)[0]
yading@7 665
yading@7 666 def _retrieve_next_page(self):
yading@7 667 self._last_page_index += 1
yading@7 668 return self._retrieve_page(self._last_page_index)
yading@7 669
yading@7 670 def has_results(self):
yading@7 671 return self.get_total_result_count() > (self._results_per_page * self._last_page_index)
yading@7 672
yading@7 673 def get_next_page(self):
yading@7 674 master_node = self._retrieve_next_page()
yading@7 675 return self._get_results(master_node)
yading@7 676
yading@7 677 def get_page(self, page=0):
yading@7 678 if page < 0: page = 0
yading@7 679 if page > 0: page = page-1
yading@7 680
yading@7 681 master_node = self._retrieve_page(page)
yading@7 682 return self._get_results(master_node)
yading@7 683
yading@7 684
yading@7 685 class ArtistSearch(_Search):
yading@7 686 """ Search artists """
yading@7 687
yading@7 688 def __init__(self, query):
yading@7 689 _Search.__init__(self, '/artist/search', {'q': query}, 'searchResults')
yading@7 690
yading@7 691 def _get_results(self, master_node):
yading@7 692 results = []
yading@7 693 for node in master_node.getElementsByTagName('artist'):
yading@7 694 artist = _get_artist(node)
yading@7 695 results.append(artist)
yading@7 696 return results
yading@7 697
yading@7 698
yading@7 699 class ArtistBrowse(_Search):
yading@7 700 """ Browse artists """
yading@7 701
yading@7 702 def __init__(self, letter):
yading@7 703 _Search.__init__(self, '/artist/browse', {'letter': letter}, 'artists')
yading@7 704
yading@7 705 def _get_results(self, master_node):
yading@7 706 results = []
yading@7 707 for node in master_node.getElementsByTagName('artist'):
yading@7 708 artist = _get_artist(node)
yading@7 709 results.append(artist)
yading@7 710 return results
yading@7 711
yading@7 712 class ArtistDetail(_Search):
yading@7 713 def __init__(self, artist_id):
yading@7 714 _Search.__init__(self, '/artist/details', {'artistid': artist_id}, 'artist')
yading@7 715
yading@7 716 def _get_results(self, master_node):
yading@7 717 results = []
yading@7 718 node = master_node
yading@7 719
yading@7 720 artist = _get_artist(node)
yading@7 721
yading@7 722 results.append(artist)
yading@7 723 return results
yading@7 724
yading@7 725 class AlbumSearch(_Search):
yading@7 726 """ Search albums """
yading@7 727
yading@7 728 def __init__(self, query):
yading@7 729 _Search.__init__(self, '/release/search', {'q': query}, 'searchResults')
yading@7 730
yading@7 731 def _get_results(self, master_node):
yading@7 732 results = []
yading@7 733 for node in master_node.getElementsByTagName('release'):
yading@7 734 artist = _get_artist(node.getElementsByTagName('artist')[0])
yading@7 735 album = _get_album(node, artist)
yading@7 736 results.append(album)
yading@7 737 return results
yading@7 738
yading@7 739 class AlbumCharts(_Search):
yading@7 740 """ Chart albums """
yading@7 741
yading@7 742 def __init__(self, period, todate):
yading@7 743 _Search.__init__(self, '/release/chart', {'period': period, 'todate': todate}, 'chart')
yading@7 744
yading@7 745 def _get_results(self, master_node):
yading@7 746 results = []
yading@7 747 for node in master_node.getElementsByTagName('release'):
yading@7 748 artist = _get_artist(node.getElementsByTagName('artist')[0])
yading@7 749 album = _get_album(node, artist)
yading@7 750 results.append(album)
yading@7 751 return results
yading@7 752
yading@7 753 class AlbumReleases(_Search):
yading@7 754 """ Release albums by date """
yading@7 755
yading@7 756 def __init__(self, fromdate, todate):
yading@7 757 _Search.__init__(self, '/release/bydate', {'fromDate': fromdate, 'toDate': todate}, 'releases')
yading@7 758
yading@7 759 def _get_results(self, master_node):
yading@7 760 results = []
yading@7 761 for node in master_node.getElementsByTagName('release'):
yading@7 762 artist = _get_artist(node.getElementsByTagName('artist')[0])
yading@7 763 album = _get_album(node, artist)
yading@7 764 results.append(album)
yading@7 765 return results
yading@7 766
yading@7 767 class TrackSearch(_Search):
yading@7 768 """ Search for tracks """
yading@7 769
yading@7 770 def __init__(self, query):
yading@7 771 _Search.__init__(self, '/track/search', {'q': query}, 'searchResults')
yading@7 772
yading@7 773 def _get_results(self, master_node):
yading@7 774 results = []
yading@7 775 for node in master_node.getElementsByTagName('track'):
yading@7 776 artist = _get_artist(node.getElementsByTagName('artist')[0])
yading@7 777 album = _get_album(node.getElementsByTagName('release')[0], artist)
yading@7 778 track = _get_track(node, album, artist)
yading@7 779 results.append(track)
yading@7 780 return results
yading@7 781
yading@7 782 def get_artist_detail(artistId):
yading@7 783 return ArtistDetail(artistId)
yading@7 784
yading@7 785 def search_artist(query):
yading@7 786 """Search artists by query. Returns an ArtistSearch object.
yading@7 787 Use get_next_page() to retrieve sequences of results."""
yading@7 788 return ArtistSearch(query)
yading@7 789
yading@7 790 def browse_artists(letter):
yading@7 791 """Browse artists by letter [a..z]. Returns an ArtistBrowse object.
yading@7 792 Use get_next_page() to retrieve sequences of results."""
yading@7 793 return ArtistBrowse(letter)
yading@7 794
yading@7 795 def search_album(query):
yading@7 796 """Search albums by query. Returns the albumSearch object.
yading@7 797 Use get_next_page() to retrieve sequences of results."""
yading@7 798 return AlbumSearch(query)
yading@7 799
yading@7 800 def album_charts(period, todate):
yading@7 801 """Get chart albums in a given period of time """
yading@7 802 return AlbumCharts(period, todate)
yading@7 803
yading@7 804 def album_releases(fromdate, todate):
yading@7 805 """Get releases in a given period of time"""
yading@7 806 return AlbumReleases(fromdate, todate)
yading@7 807
yading@7 808 def search_track(query):
yading@7 809 """Search tracks by query. Returns a TrackSearch object.
yading@7 810 Use get_next_page() to retrieve sequences of results."""
yading@7 811 return TrackSearch(query)
yading@7 812
yading@7 813
yading@7 814 # XML
yading@7 815 def _extract(node, name, index = 0):
yading@7 816 """Extracts a value from the xml string"""
yading@7 817 try:
yading@7 818 nodes = node.getElementsByTagName(name)
yading@7 819
yading@7 820 if len(nodes):
yading@7 821 if nodes[index].firstChild:
yading@7 822 return nodes[index].firstChild.data.strip()
yading@7 823 else:
yading@7 824 return None
yading@7 825 except:
yading@7 826 return None
yading@7 827
yading@7 828 def _extract_all(node, name, pageSize_count = None):
yading@7 829 """Extracts all the values from the xml string. It returns a list."""
yading@7 830 results = []
yading@7 831 for i in range(0, len(node.getElementsByTagName(name))):
yading@7 832 if len(results) == pageSize_count:
yading@7 833 break
yading@7 834 results.append(_extract(node, name, i))
yading@7 835 return results
yading@7 836
yading@7 837 def _get_artist(xml):
yading@7 838 artist_id = xml.getAttribute('id')
yading@7 839 artist = Artist(artist_id)
yading@7 840 artist.set_name(_extract(xml, 'name'))
yading@7 841 return artist
yading@7 842
yading@7 843 def _get_album(xml, artist):
yading@7 844 album_id = xml.getAttribute('id')
yading@7 845 album = Album(album_id)
yading@7 846 album.set_artist(artist)
yading@7 847 album.set_title(_extract(xml, 'title'))
yading@7 848 album.set_type(_extract(xml, 'type'))
yading@7 849 album.set_image(_extract(xml, 'image'))
yading@7 850 album.set_year(_extract(xml, 'year'))
yading@7 851 album.set_barcode(_extract(xml, 'barcode'))
yading@7 852 album.set_url(_extract(xml, 'url'))
yading@7 853 album.set_release_date(_extract(xml, 'releaseDate'))
yading@7 854 album.set_added_date(_extract(xml, 'addedDate'))
yading@7 855 #TODO price, formats, artist appears_as
yading@7 856 try :
yading@7 857 album.set_label(_get_label(xml.getElementsByTagName('label')[0])) #In some cases that are albums with no label (record company) attached! :-(
yading@7 858 except:
yading@7 859 pass
yading@7 860 return album
yading@7 861
yading@7 862 def _get_track(xml, album, artist):
yading@7 863 track_id = xml.getAttribute('id')
yading@7 864 track = Track(track_id)
yading@7 865 track.set_title(_extract(xml, 'title'))
yading@7 866 track.set_url(_extract(xml, 'url'))
yading@7 867 track.set_isrc(_extract(xml, 'isrc'))
yading@7 868 track.set_duration(_extract(xml, 'duration'))
yading@7 869 track.set_position(_extract(xml, 'trackNumber'))
yading@7 870 track.set_explicit(_extract(xml, 'explicitContent'))
yading@7 871 track.set_version(_extract(xml, 'version'))
yading@7 872 track.set_album(album)
yading@7 873 track.set_artist(artist)
yading@7 874 #TODO price, formats
yading@7 875 return track
yading@7 876
yading@7 877 def _get_tag(xml):
yading@7 878 tag = Tag(_extract(xml, 'text'))
yading@7 879 tag.set_name(tag.get_id())
yading@7 880 return tag
yading@7 881
yading@7 882 def _get_label(xml):
yading@7 883 label = ''
yading@7 884 try:
yading@7 885 label = Label(xml.getAttribute('id'))
yading@7 886 label.set_name(_extract(xml, 'name'))
yading@7 887 except:
yading@7 888 pass
yading@7 889 return label
yading@7 890
yading@7 891 # CACHE
yading@7 892 def enable_caching(cache_dir = None):
yading@7 893 global __cache_dir
yading@7 894 global __cache_enabled
yading@7 895
yading@7 896 if cache_dir == None:
yading@7 897 import tempfile
yading@7 898 __cache_dir = tempfile.mkdtemp()
yading@7 899 else:
yading@7 900 if not os.path.exists(cache_dir):
yading@7 901 os.mkdir(cache_dir)
yading@7 902 __cache_dir = cache_dir
yading@7 903 __cache_enabled = True
yading@7 904
yading@7 905 def disable_caching():
yading@7 906 global __cache_enabled
yading@7 907 __cache_enabled = False
yading@7 908
yading@7 909 def is_caching_enabled():
yading@7 910 """Returns True if caching is enabled."""
yading@7 911 global __cache_enabled
yading@7 912 return __cache_enabled
yading@7 913
yading@7 914 def _get_cache_dir():
yading@7 915 """Returns the directory in which cache files are saved."""
yading@7 916 global __cache_dir
yading@7 917 global __cache_enabled
yading@7 918 return __cache_dir
yading@7 919
yading@7 920 def get_md5(text):
yading@7 921 """Returns the md5 hash of a string."""
yading@7 922 hash = md5()
yading@7 923 hash.update(text.encode('utf8'))
yading@7 924 return hash.hexdigest()
yading@7 925