api.py 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320
  1. import eventlet
  2. requests = eventlet.import_patched('requests')
  3. class SearchOrder():
  4. """Possible values for order parameter in search"""
  5. RANKING = "RANKING"
  6. TRACK_ASC = "TRACK_ASC"
  7. TRACK_DESC = "TRACK_DESC"
  8. ARTIST_ASC = "ARTIST_ASC"
  9. ARTIST_DESC = "ARTIST_DESC"
  10. ALBUM_ASC = "ALBUM_ASC"
  11. ALBUM_DESC = "ALBUM_DESC"
  12. RATING_ASC = "RATING_ASC"
  13. RATING_DESC = "RATING_DESC"
  14. DURATION_ASC = "DURATION_ASC"
  15. DURATION_DESC = "DURATION_DESC"
  16. class API:
  17. def __init__(self, session, headers):
  18. self.http_headers = headers
  19. self.session = session
  20. def api_call(self, method, args=None):
  21. if args is None:
  22. args = {}
  23. try:
  24. result = self.session.get(
  25. "https://api.deezer.com/" + method,
  26. params=args,
  27. headers=self.http_headers,
  28. timeout=30
  29. )
  30. result_json = result.json()
  31. except:
  32. eventlet.sleep(2)
  33. return self.api_call(method, args)
  34. if 'error' in result_json.keys():
  35. if 'code' in result_json['error']:
  36. if result_json['error']['code'] in [4, 700]:
  37. eventlet.sleep(5)
  38. return self.api_call(method, args)
  39. if result_json['error']['code'] == 100: raise ItemsLimitExceededException(f"ItemsLimitExceededException: {method}")
  40. if result_json['error']['code'] == 200: raise PermissionException(f"PermissionException: {method}")
  41. if result_json['error']['code'] == 300: raise InvalidTokenException(f"InvalidTokenException: {method}")
  42. if result_json['error']['code'] == 500: raise WrongParameterException(f"ParameterException: {method}")
  43. if result_json['error']['code'] == 501: raise MissingParameterException(f"MissingParameterException: {method}")
  44. if result_json['error']['code'] == 600: raise InvalidQueryException(f"InvalidQueryException: {method}")
  45. if result_json['error']['code'] == 800: raise DataException(f"DataException: {method}")
  46. if result_json['error']['code'] == 901: raise IndividualAccountChangedNotAllowedException(f"IndividualAccountChangedNotAllowedException: {method}")
  47. raise APIError(json.dumps(result_json['error']))
  48. return result_json
  49. def get_album(self, album_id):
  50. return self.api_call(f'album/{str(album_id)}')
  51. def get_album_by_UPC(self, upc):
  52. return self.get_album(f'upc:{upc}')
  53. def get_album_comments(self, album_id, index=0, limit=10):
  54. return self.api_call(f'album/{str(album_id)}/comments', {'index': index, 'limit': limit})
  55. def get_album_fans(self, album_id, index=0, limit=100):
  56. return self.api_call(f'album/{str(album_id)}/fans', {'index': index, 'limit': limit})
  57. def get_album_tracks(self, album_id, index=0, limit=-1):
  58. return self.api_call(f'album/{str(album_id)}/tracks', {'index': index, 'limit': limit})
  59. def get_artist(self, artist_id):
  60. return self.api_call(f'artist/{str(artist_id)}')
  61. def get_artist_top(self, artist_id, index=0, limit=10):
  62. return self.api_call(f'artist/{str(artist_id)}/top', {'index': index, 'limit': limit})
  63. def get_artist_albums(self, artist_id, index=0, limit=-1):
  64. return self.api_call(f'artist/{str(artist_id)}/albums', {'index': index, 'limit': limit})
  65. def get_artist_comments(self, artist_id, index=0, limit=10):
  66. return self.api_call(f'artist/{str(artist_id)}/comments', {'index': index, 'limit': limit})
  67. def get_artist_fans(self, artist_id, index=0, limit=100):
  68. return self.api_call(f'artist/{str(artist_id)}/fans', {'index': index, 'limit': limit})
  69. def get_artist_related(self, artist_id, index=0, limit=20):
  70. return self.api_call(f'artist/{str(artist_id)}/related', {'index': index, 'limit': limit})
  71. def get_artist_radio(self, artist_id, index=0, limit=25):
  72. return self.api_call(f'artist/{str(artist_id)}/radio', {'index': index, 'limit': limit})
  73. def get_artist_playlists(self, artist_id, index=0, limit=-1):
  74. return self.api_call(f'artist/{str(artist_id)}/playlists', {'index': index, 'limit': limit})
  75. def get_chart(self, genre_id=0, index=0, limit=10):
  76. return self.api_call(f'chart/{str(genre_id)}', {'index': index, 'limit': limit})
  77. def get_chart_tracks(self, genre_id=0, index=0, limit=10):
  78. return self.api_call(f'chart/{str(genre_id)}/tracks', {'index': index, 'limit': limit})
  79. def get_chart_albums(self, genre_id=0, index=0, limit=10):
  80. return self.api_call(f'chart/{str(genre_id)}/albums', {'index': index, 'limit': limit})
  81. def get_chart_artists(self, genre_id=0, index=0, limit=10):
  82. return self.api_call(f'chart/{str(genre_id)}/artists', {'index': index, 'limit': limit})
  83. def get_chart_playlists(self, genre_id=0, index=0, limit=10):
  84. return self.api_call(f'chart/{str(genre_id)}/playlists', {'index': index, 'limit': limit})
  85. def get_chart_podcasts(self, genre_id=0, index=0, limit=10):
  86. return self.api_call(f'chart/{str(genre_id)}/podcasts', {'index': index, 'limit': limit})
  87. def get_comment(self, comment_id):
  88. return self.api_call(f'comment/{str(comment_id)}')
  89. def get_editorials(self, index=0, limit=10):
  90. return self.api_call('editorial', {'index': index, 'limit': limit})
  91. def get_editorial(self, genre_id=0):
  92. return self.api_call(f'editorial/{str(genre_id)}')
  93. def get_editorial_selection(self, genre_id=0, index=0, limit=10):
  94. return self.api_call(f'editorial/{str(genre_id)}/selection', {'index': index, 'limit': limit})
  95. def get_editorial_charts(self, genre_id=0, index=0, limit=10):
  96. return self.api_call(f'editorial/{str(genre_id)}/charts', {'index': index, 'limit': limit})
  97. def get_editorial_releases(self, genre_id=0, index=0, limit=10):
  98. return self.api_call(f'editorial/{str(genre_id)}/releases', {'index': index, 'limit': limit})
  99. def get_genres(self, index=0, limit=10):
  100. return self.api_call('genre', {'index': index, 'limit': limit})
  101. def get_genre(self, genre_id=0):
  102. return self.api_call(f'genre/{str(genre_id)}')
  103. def get_genre_artists(self, genre_id=0, index=0, limit=10):
  104. return self.api_call(f'genre/{str(genre_id)}/artists', {'index': index, 'limit': limit})
  105. def get_genre_radios(self, genre_id=0, index=0, limit=10):
  106. return self.api_call(f'genre/{str(genre_id)}/radios', {'index': index, 'limit': limit})
  107. def get_infos(self):
  108. return self.api_call('infos')
  109. def get_options(self):
  110. return self.api_call('options')
  111. def get_playlist(self, playlist_id):
  112. return self.api_call(f'playlist/{str(playlist_id)}')
  113. def get_playlist_comments(self, album_id, index=0, limit=10):
  114. return self.api_call(f'playlist/{str(album_id)}/comments', {'index': index, 'limit': limit})
  115. def get_playlist_fans(self, album_id, index=0, limit=100):
  116. return self.api_call(f'playlist/{str(album_id)}/fans', {'index': index, 'limit': limit})
  117. def get_playlist_tracks(self, album_id, index=0, limit=-1):
  118. return self.api_call(f'playlist/{str(album_id)}/tracks', {'index': index, 'limit': limit})
  119. def get_playlist_radio(self, album_id, index=0, limit=100):
  120. return self.api_call(f'playlist/{str(album_id)}/radio', {'index': index, 'limit': limit})
  121. def get_radios(self, index=0, limit=10):
  122. return self.api_call('radio', {'index': index, 'limit': limit})
  123. def get_radios_genres(self, index=0, limit=25):
  124. return self.api_call('radio/genres', {'index': index, 'limit': limit})
  125. def get_radios_top(self, index=0, limit=50):
  126. return self.api_call('radio/top', {'index': index, 'limit': limit})
  127. def get_radios_lists(self, index=0, limit=25):
  128. return self.api_call('radio/lists', {'index': index, 'limit': limit})
  129. def get_radio(self, radio_id):
  130. return self.api_call(f'radio/{str(radio_id)}')
  131. def get_radio_tracks(self, radio_id, index=0, limit=40):
  132. return self.api_call(f'radio/{str(radio_id)}/tracks', {'index': index, 'limit': limit})
  133. def _generate_search_advanced_query(self, artist="", album="", track="", label="", dur_min=0, dur_max=0, bpm_min=0, bpm_max=0):
  134. query = ""
  135. if artist: query += f'artist:"{artist}" '
  136. if album: query += f'album:"{album}" '
  137. if track: query += f'track:"{track}" '
  138. if label: query += f'label:"{label}" '
  139. if dur_min: query += f'dur_min:"{str(dur_min)}" '
  140. if dur_max: query += f'dur_max:"{str(dur_max)}" '
  141. if bpm_min: query += f'bpm_min:"{str(bpm_min)}" '
  142. if bpm_max: query += f'bpm_max:"{str(bpm_max)}" '
  143. return query.strip()
  144. def _generate_search_args(self, query, strict=False, order=None, index=0, limit=25):
  145. args = {'q': query, 'index': index, 'limit': limit}
  146. if strict: args['strict'] = 'on'
  147. if order: args['order'] = order
  148. return args
  149. def search(self, query, strict=False, order=None, index=0, limit=25):
  150. args = self._generate_search_args(query, strict, order, index, limit)
  151. return self.api_call('search', args)
  152. def advanced_search(self, artist="", album="", track="", label="", dur_min=0, dur_max=0, bpm_min=0, bpm_max=0, strict=False, order=None, index=0, limit=25):
  153. query = self._generate_search_advanced_query(artist, album, track, label, dur_min, dur_max, bpm_min, bpm_max)
  154. return self.search(query, strict, order, index, limit)
  155. def search_album(self, query, strict=False, order=None, index=0, limit=25):
  156. args = self._generate_search_args(query, strict, order, index, limit)
  157. return self.api_call('search/album', args)
  158. def search_artist(self, query, strict=False, order=None, index=0, limit=25):
  159. args = self._generate_search_args(query, strict, order, index, limit)
  160. return self.api_call('search/artist', args)
  161. def search_playlist(self, query, strict=False, order=None, index=0, limit=25):
  162. args = self._generate_search_args(query, strict, order, index, limit)
  163. return self.api_call('search/playlist', args)
  164. def search_radio(self, query, strict=False, order=None, index=0, limit=25):
  165. args = self._generate_search_args(query, strict, order, index, limit)
  166. return self.api_call('search/radio', args)
  167. def search_track(self, query, strict=False, order=None, index=0, limit=25):
  168. args = self._generate_search_args(query, strict, order, index, limit)
  169. return self.api_call('search/track', args)
  170. def search_user(self, query, strict=False, order=None, index=0, limit=25):
  171. args = self._generate_search_args(query, strict, order, index, limit)
  172. return self.api_call('search/user', args)
  173. def get_track(self, song_id):
  174. return self.api_call(f'track/{str(song_id)}')
  175. def get_track_by_ISRC(self, isrc):
  176. return self.get_track(f'isrc:{isrc}')
  177. def get_user(self, user_id):
  178. return self.api_call(f'user/{str(user_id)}')
  179. def get_user_albums(self, user_id, index=0, limit=25):
  180. return self.api_call(f'user/{str(user_id)}/albums', {'index': index, 'limit': limit})
  181. def get_user_artists(self, user_id, index=0, limit=25):
  182. return self.api_call(f'user/{str(user_id)}/artists', {'index': index, 'limit': limit})
  183. def get_user_artists(self, user_id, index=0, limit=25):
  184. return self.api_call(f'user/{str(user_id)}/artists', {'index': index, 'limit': limit})
  185. def get_user_flow(self, user_id, index=0, limit=25):
  186. return self.api_call(f'user/{str(user_id)}/flow', {'index': index, 'limit': limit})
  187. def get_user_following(self, user_id, index=0, limit=25):
  188. return self.api_call(f'user/{str(user_id)}/followings', {'index': index, 'limit': limit})
  189. def get_user_followers(self, user_id, index=0, limit=25):
  190. return self.api_call(f'user/{str(user_id)}/followers', {'index': index, 'limit': limit})
  191. def get_user_playlists(self, user_id, index=0, limit=25):
  192. return self.api_call(f'user/{str(user_id)}/playlists', {'index': index, 'limit': limit})
  193. def get_user_radios(self, user_id, index=0, limit=25):
  194. return self.api_call(f'user/{str(user_id)}/radios', {'index': index, 'limit': limit})
  195. def get_user_tracks(self, user_id, index=0, limit=25):
  196. return self.api_call(f'user/{str(user_id)}/tracks', {'index': index, 'limit': limit})
  197. # Extra calls
  198. def get_countries_charts(self):
  199. temp = self.get_user_playlists('637006841', limit=-1)['data']
  200. result = sorted(temp, key=lambda k: k['title']) # Sort all playlists
  201. if not result[0]['title'].startswith('Top'): result = result[1:] # Remove loved tracks playlist
  202. return result
  203. def get_track_id_from_metadata(self, artist, track, album):
  204. artist = artist.replace("–", "-").replace("’", "'")
  205. track = track.replace("–", "-").replace("’", "'")
  206. album = album.replace("–", "-").replace("’", "'")
  207. resp = self.advanced_search(artist=artist, track=track, album=album, limit=1)
  208. if len(resp['data']) > 0: return resp['data'][0]['id']
  209. resp = self.advanced_search(artist=artist, track=track, limit=1)
  210. if len(resp['data']) > 0: return resp['data'][0]['id']
  211. # Try removing version
  212. if "(" in track and ")" in track and track.find("(") < track.find(")"):
  213. resp = self.advanced_search(artist=artist, track=track[:track.find("(")], limit=1)
  214. if len(resp['data']) > 0: return resp['data'][0]['id']
  215. elif " - " in track:
  216. resp = self.advanced_search(artist=artist, track=track[:track.find(" - ")], limit=1)
  217. if len(resp['data']) > 0: return resp['data'][0]['id']
  218. return 0
  219. class APIError(Exception):
  220. """Base class for Deezer exceptions"""
  221. pass
  222. class ItemsLimitExceededException(APIError):
  223. pass
  224. class PermissionException(APIError):
  225. pass
  226. class InvalidTokenException(APIError):
  227. pass
  228. class WrongParameterException(APIError):
  229. pass
  230. class MissingParameterException(APIError):
  231. pass
  232. class InvalidQueryException(APIError):
  233. pass
  234. class DataException(APIError):
  235. pass
  236. class IndividualAccountChangedNotAllowedException(APIError):
  237. pass