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