2021-02-11 18:04:05 +00:00
|
|
|
|
import requests
|
|
|
|
|
from time import sleep
|
2020-11-12 15:55:24 +00:00
|
|
|
|
|
2021-03-05 12:49:33 +00:00
|
|
|
|
import json
|
2021-08-02 18:42:47 +00:00
|
|
|
|
from deezer.errors import ItemsLimitExceededException, PermissionException, InvalidTokenException, \
|
|
|
|
|
WrongParameterException, MissingParameterException, InvalidQueryException, DataException, \
|
|
|
|
|
IndividualAccountChangedNotAllowedException, APIError
|
2021-03-05 12:49:33 +00:00
|
|
|
|
|
2020-11-12 15:55:24 +00:00
|
|
|
|
class SearchOrder():
|
|
|
|
|
"""Possible values for order parameter in search"""
|
|
|
|
|
RANKING = "RANKING"
|
|
|
|
|
TRACK_ASC = "TRACK_ASC"
|
|
|
|
|
TRACK_DESC = "TRACK_DESC"
|
|
|
|
|
ARTIST_ASC = "ARTIST_ASC"
|
|
|
|
|
ARTIST_DESC = "ARTIST_DESC"
|
|
|
|
|
ALBUM_ASC = "ALBUM_ASC"
|
|
|
|
|
ALBUM_DESC = "ALBUM_DESC"
|
|
|
|
|
RATING_ASC = "RATING_ASC"
|
|
|
|
|
RATING_DESC = "RATING_DESC"
|
|
|
|
|
DURATION_ASC = "DURATION_ASC"
|
|
|
|
|
DURATION_DESC = "DURATION_DESC"
|
|
|
|
|
|
|
|
|
|
class API:
|
|
|
|
|
def __init__(self, session, headers):
|
|
|
|
|
self.http_headers = headers
|
|
|
|
|
self.session = session
|
2021-01-08 17:07:13 +00:00
|
|
|
|
self.access_token = None
|
2020-11-12 15:55:24 +00:00
|
|
|
|
|
|
|
|
|
def api_call(self, method, args=None):
|
|
|
|
|
if args is None:
|
|
|
|
|
args = {}
|
2021-01-08 17:07:13 +00:00
|
|
|
|
if self.access_token: args['access_token'] = self.access_token
|
2020-11-12 15:55:24 +00:00
|
|
|
|
try:
|
2021-03-12 14:02:11 +00:00
|
|
|
|
result_json = self.session.get(
|
2020-11-12 15:55:24 +00:00
|
|
|
|
"https://api.deezer.com/" + method,
|
|
|
|
|
params=args,
|
|
|
|
|
headers=self.http_headers,
|
|
|
|
|
timeout=30
|
2021-03-12 14:02:11 +00:00
|
|
|
|
).json()
|
2020-11-12 15:55:24 +00:00
|
|
|
|
except:
|
2021-02-11 18:04:05 +00:00
|
|
|
|
sleep(2)
|
2020-11-12 15:55:24 +00:00
|
|
|
|
return self.api_call(method, args)
|
|
|
|
|
if 'error' in result_json.keys():
|
|
|
|
|
if 'code' in result_json['error']:
|
|
|
|
|
if result_json['error']['code'] in [4, 700]:
|
2021-02-11 18:04:05 +00:00
|
|
|
|
sleep(5)
|
2020-11-12 15:55:24 +00:00
|
|
|
|
return self.api_call(method, args)
|
2021-03-12 14:02:11 +00:00
|
|
|
|
if result_json['error']['code'] == 100: raise ItemsLimitExceededException(f"ItemsLimitExceededException: {method} {result_json['error']['message'] if 'message' in result_json['error'] else ''}")
|
|
|
|
|
if result_json['error']['code'] == 200: raise PermissionException(f"PermissionException: {method} {result_json['error']['message'] if 'message' in result_json['error'] else ''}")
|
|
|
|
|
if result_json['error']['code'] == 300: raise InvalidTokenException(f"InvalidTokenException: {method} {result_json['error']['message'] if 'message' in result_json['error'] else ''}")
|
|
|
|
|
if result_json['error']['code'] == 500: raise WrongParameterException(f"ParameterException: {method} {result_json['error']['message'] if 'message' in result_json['error'] else ''}")
|
|
|
|
|
if result_json['error']['code'] == 501: raise MissingParameterException(f"MissingParameterException: {method} {result_json['error']['message'] if 'message' in result_json['error'] else ''}")
|
|
|
|
|
if result_json['error']['code'] == 600: raise InvalidQueryException(f"InvalidQueryException: {method} {result_json['error']['message'] if 'message' in result_json['error'] else ''}")
|
|
|
|
|
if result_json['error']['code'] == 800: raise DataException(f"DataException: {method} {result_json['error']['message'] if 'message' in result_json['error'] else ''}")
|
|
|
|
|
if result_json['error']['code'] == 901: raise IndividualAccountChangedNotAllowedException(f"IndividualAccountChangedNotAllowedException: {method} {result_json['error']['message'] if 'message' in result_json['error'] else ''}")
|
2020-11-12 15:55:24 +00:00
|
|
|
|
raise APIError(json.dumps(result_json['error']))
|
|
|
|
|
return result_json
|
|
|
|
|
|
|
|
|
|
def get_album(self, album_id):
|
|
|
|
|
return self.api_call(f'album/{str(album_id)}')
|
|
|
|
|
|
2020-11-19 17:56:40 +00:00
|
|
|
|
def get_album_by_UPC(self, upc):
|
2020-11-12 15:55:24 +00:00
|
|
|
|
return self.get_album(f'upc:{upc}')
|
|
|
|
|
|
|
|
|
|
def get_album_comments(self, album_id, index=0, limit=10):
|
|
|
|
|
return self.api_call(f'album/{str(album_id)}/comments', {'index': index, 'limit': limit})
|
|
|
|
|
|
|
|
|
|
def get_album_fans(self, album_id, index=0, limit=100):
|
|
|
|
|
return self.api_call(f'album/{str(album_id)}/fans', {'index': index, 'limit': limit})
|
|
|
|
|
|
|
|
|
|
def get_album_tracks(self, album_id, index=0, limit=-1):
|
|
|
|
|
return self.api_call(f'album/{str(album_id)}/tracks', {'index': index, 'limit': limit})
|
|
|
|
|
|
|
|
|
|
def get_artist(self, artist_id):
|
|
|
|
|
return self.api_call(f'artist/{str(artist_id)}')
|
|
|
|
|
|
|
|
|
|
def get_artist_top(self, artist_id, index=0, limit=10):
|
|
|
|
|
return self.api_call(f'artist/{str(artist_id)}/top', {'index': index, 'limit': limit})
|
|
|
|
|
|
|
|
|
|
def get_artist_albums(self, artist_id, index=0, limit=-1):
|
|
|
|
|
return self.api_call(f'artist/{str(artist_id)}/albums', {'index': index, 'limit': limit})
|
|
|
|
|
|
|
|
|
|
def get_artist_comments(self, artist_id, index=0, limit=10):
|
|
|
|
|
return self.api_call(f'artist/{str(artist_id)}/comments', {'index': index, 'limit': limit})
|
|
|
|
|
|
|
|
|
|
def get_artist_fans(self, artist_id, index=0, limit=100):
|
|
|
|
|
return self.api_call(f'artist/{str(artist_id)}/fans', {'index': index, 'limit': limit})
|
|
|
|
|
|
|
|
|
|
def get_artist_related(self, artist_id, index=0, limit=20):
|
|
|
|
|
return self.api_call(f'artist/{str(artist_id)}/related', {'index': index, 'limit': limit})
|
|
|
|
|
|
|
|
|
|
def get_artist_radio(self, artist_id, index=0, limit=25):
|
|
|
|
|
return self.api_call(f'artist/{str(artist_id)}/radio', {'index': index, 'limit': limit})
|
|
|
|
|
|
|
|
|
|
def get_artist_playlists(self, artist_id, index=0, limit=-1):
|
|
|
|
|
return self.api_call(f'artist/{str(artist_id)}/playlists', {'index': index, 'limit': limit})
|
|
|
|
|
|
|
|
|
|
def get_chart(self, genre_id=0, index=0, limit=10):
|
|
|
|
|
return self.api_call(f'chart/{str(genre_id)}', {'index': index, 'limit': limit})
|
|
|
|
|
|
|
|
|
|
def get_chart_tracks(self, genre_id=0, index=0, limit=10):
|
|
|
|
|
return self.api_call(f'chart/{str(genre_id)}/tracks', {'index': index, 'limit': limit})
|
|
|
|
|
|
|
|
|
|
def get_chart_albums(self, genre_id=0, index=0, limit=10):
|
|
|
|
|
return self.api_call(f'chart/{str(genre_id)}/albums', {'index': index, 'limit': limit})
|
|
|
|
|
|
|
|
|
|
def get_chart_artists(self, genre_id=0, index=0, limit=10):
|
|
|
|
|
return self.api_call(f'chart/{str(genre_id)}/artists', {'index': index, 'limit': limit})
|
|
|
|
|
|
|
|
|
|
def get_chart_playlists(self, genre_id=0, index=0, limit=10):
|
|
|
|
|
return self.api_call(f'chart/{str(genre_id)}/playlists', {'index': index, 'limit': limit})
|
|
|
|
|
|
|
|
|
|
def get_chart_podcasts(self, genre_id=0, index=0, limit=10):
|
|
|
|
|
return self.api_call(f'chart/{str(genre_id)}/podcasts', {'index': index, 'limit': limit})
|
|
|
|
|
|
|
|
|
|
def get_comment(self, comment_id):
|
|
|
|
|
return self.api_call(f'comment/{str(comment_id)}')
|
|
|
|
|
|
|
|
|
|
def get_editorials(self, index=0, limit=10):
|
|
|
|
|
return self.api_call('editorial', {'index': index, 'limit': limit})
|
|
|
|
|
|
|
|
|
|
def get_editorial(self, genre_id=0):
|
|
|
|
|
return self.api_call(f'editorial/{str(genre_id)}')
|
|
|
|
|
|
|
|
|
|
def get_editorial_selection(self, genre_id=0, index=0, limit=10):
|
|
|
|
|
return self.api_call(f'editorial/{str(genre_id)}/selection', {'index': index, 'limit': limit})
|
|
|
|
|
|
|
|
|
|
def get_editorial_charts(self, genre_id=0, index=0, limit=10):
|
|
|
|
|
return self.api_call(f'editorial/{str(genre_id)}/charts', {'index': index, 'limit': limit})
|
|
|
|
|
|
|
|
|
|
def get_editorial_releases(self, genre_id=0, index=0, limit=10):
|
|
|
|
|
return self.api_call(f'editorial/{str(genre_id)}/releases', {'index': index, 'limit': limit})
|
|
|
|
|
|
|
|
|
|
def get_genres(self, index=0, limit=10):
|
|
|
|
|
return self.api_call('genre', {'index': index, 'limit': limit})
|
|
|
|
|
|
|
|
|
|
def get_genre(self, genre_id=0):
|
|
|
|
|
return self.api_call(f'genre/{str(genre_id)}')
|
|
|
|
|
|
|
|
|
|
def get_genre_artists(self, genre_id=0, index=0, limit=10):
|
|
|
|
|
return self.api_call(f'genre/{str(genre_id)}/artists', {'index': index, 'limit': limit})
|
|
|
|
|
|
|
|
|
|
def get_genre_radios(self, genre_id=0, index=0, limit=10):
|
|
|
|
|
return self.api_call(f'genre/{str(genre_id)}/radios', {'index': index, 'limit': limit})
|
|
|
|
|
|
|
|
|
|
def get_infos(self):
|
|
|
|
|
return self.api_call('infos')
|
|
|
|
|
|
|
|
|
|
def get_options(self):
|
|
|
|
|
return self.api_call('options')
|
|
|
|
|
|
|
|
|
|
def get_playlist(self, playlist_id):
|
|
|
|
|
return self.api_call(f'playlist/{str(playlist_id)}')
|
|
|
|
|
|
|
|
|
|
def get_playlist_comments(self, album_id, index=0, limit=10):
|
|
|
|
|
return self.api_call(f'playlist/{str(album_id)}/comments', {'index': index, 'limit': limit})
|
|
|
|
|
|
|
|
|
|
def get_playlist_fans(self, album_id, index=0, limit=100):
|
|
|
|
|
return self.api_call(f'playlist/{str(album_id)}/fans', {'index': index, 'limit': limit})
|
|
|
|
|
|
|
|
|
|
def get_playlist_tracks(self, album_id, index=0, limit=-1):
|
|
|
|
|
return self.api_call(f'playlist/{str(album_id)}/tracks', {'index': index, 'limit': limit})
|
|
|
|
|
|
|
|
|
|
def get_playlist_radio(self, album_id, index=0, limit=100):
|
|
|
|
|
return self.api_call(f'playlist/{str(album_id)}/radio', {'index': index, 'limit': limit})
|
|
|
|
|
|
|
|
|
|
def get_radios(self, index=0, limit=10):
|
|
|
|
|
return self.api_call('radio', {'index': index, 'limit': limit})
|
|
|
|
|
|
|
|
|
|
def get_radios_genres(self, index=0, limit=25):
|
|
|
|
|
return self.api_call('radio/genres', {'index': index, 'limit': limit})
|
|
|
|
|
|
|
|
|
|
def get_radios_top(self, index=0, limit=50):
|
|
|
|
|
return self.api_call('radio/top', {'index': index, 'limit': limit})
|
|
|
|
|
|
|
|
|
|
def get_radios_lists(self, index=0, limit=25):
|
|
|
|
|
return self.api_call('radio/lists', {'index': index, 'limit': limit})
|
|
|
|
|
|
|
|
|
|
def get_radio(self, radio_id):
|
|
|
|
|
return self.api_call(f'radio/{str(radio_id)}')
|
|
|
|
|
|
|
|
|
|
def get_radio_tracks(self, radio_id, index=0, limit=40):
|
|
|
|
|
return self.api_call(f'radio/{str(radio_id)}/tracks', {'index': index, 'limit': limit})
|
|
|
|
|
|
|
|
|
|
def _generate_search_advanced_query(self, artist="", album="", track="", label="", dur_min=0, dur_max=0, bpm_min=0, bpm_max=0):
|
|
|
|
|
query = ""
|
|
|
|
|
if artist: query += f'artist:"{artist}" '
|
|
|
|
|
if album: query += f'album:"{album}" '
|
|
|
|
|
if track: query += f'track:"{track}" '
|
|
|
|
|
if label: query += f'label:"{label}" '
|
|
|
|
|
if dur_min: query += f'dur_min:"{str(dur_min)}" '
|
|
|
|
|
if dur_max: query += f'dur_max:"{str(dur_max)}" '
|
|
|
|
|
if bpm_min: query += f'bpm_min:"{str(bpm_min)}" '
|
|
|
|
|
if bpm_max: query += f'bpm_max:"{str(bpm_max)}" '
|
|
|
|
|
return query.strip()
|
|
|
|
|
|
|
|
|
|
def _generate_search_args(self, query, strict=False, order=None, index=0, limit=25):
|
|
|
|
|
args = {'q': query, 'index': index, 'limit': limit}
|
|
|
|
|
if strict: args['strict'] = 'on'
|
|
|
|
|
if order: args['order'] = order
|
|
|
|
|
return args
|
|
|
|
|
|
|
|
|
|
def search(self, query, strict=False, order=None, index=0, limit=25):
|
|
|
|
|
args = self._generate_search_args(query, strict, order, index, limit)
|
|
|
|
|
return self.api_call('search', args)
|
|
|
|
|
|
|
|
|
|
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):
|
|
|
|
|
query = self._generate_search_advanced_query(artist, album, track, label, dur_min, dur_max, bpm_min, bpm_max)
|
|
|
|
|
return self.search(query, strict, order, index, limit)
|
|
|
|
|
|
|
|
|
|
def search_album(self, query, strict=False, order=None, index=0, limit=25):
|
|
|
|
|
args = self._generate_search_args(query, strict, order, index, limit)
|
|
|
|
|
return self.api_call('search/album', args)
|
|
|
|
|
|
|
|
|
|
def search_artist(self, query, strict=False, order=None, index=0, limit=25):
|
|
|
|
|
args = self._generate_search_args(query, strict, order, index, limit)
|
|
|
|
|
return self.api_call('search/artist', args)
|
|
|
|
|
|
|
|
|
|
def search_playlist(self, query, strict=False, order=None, index=0, limit=25):
|
|
|
|
|
args = self._generate_search_args(query, strict, order, index, limit)
|
|
|
|
|
return self.api_call('search/playlist', args)
|
|
|
|
|
|
|
|
|
|
def search_radio(self, query, strict=False, order=None, index=0, limit=25):
|
|
|
|
|
args = self._generate_search_args(query, strict, order, index, limit)
|
2020-11-19 20:11:54 +00:00
|
|
|
|
return self.api_call('search/radio', args)
|
2020-11-12 15:55:24 +00:00
|
|
|
|
|
|
|
|
|
def search_track(self, query, strict=False, order=None, index=0, limit=25):
|
|
|
|
|
args = self._generate_search_args(query, strict, order, index, limit)
|
2020-11-19 20:11:54 +00:00
|
|
|
|
return self.api_call('search/track', args)
|
2020-11-12 15:55:24 +00:00
|
|
|
|
|
|
|
|
|
def search_user(self, query, strict=False, order=None, index=0, limit=25):
|
|
|
|
|
args = self._generate_search_args(query, strict, order, index, limit)
|
2020-11-19 20:11:54 +00:00
|
|
|
|
return self.api_call('search/user', args)
|
2020-11-12 15:55:24 +00:00
|
|
|
|
|
|
|
|
|
def get_track(self, song_id):
|
|
|
|
|
return self.api_call(f'track/{str(song_id)}')
|
|
|
|
|
|
|
|
|
|
def get_track_by_ISRC(self, isrc):
|
|
|
|
|
return self.get_track(f'isrc:{isrc}')
|
|
|
|
|
|
|
|
|
|
def get_user(self, user_id):
|
|
|
|
|
return self.api_call(f'user/{str(user_id)}')
|
|
|
|
|
|
|
|
|
|
def get_user_albums(self, user_id, index=0, limit=25):
|
|
|
|
|
return self.api_call(f'user/{str(user_id)}/albums', {'index': index, 'limit': limit})
|
|
|
|
|
|
|
|
|
|
def get_user_artists(self, user_id, index=0, limit=25):
|
|
|
|
|
return self.api_call(f'user/{str(user_id)}/artists', {'index': index, 'limit': limit})
|
|
|
|
|
|
|
|
|
|
def get_user_flow(self, user_id, index=0, limit=25):
|
|
|
|
|
return self.api_call(f'user/{str(user_id)}/flow', {'index': index, 'limit': limit})
|
|
|
|
|
|
|
|
|
|
def get_user_following(self, user_id, index=0, limit=25):
|
|
|
|
|
return self.api_call(f'user/{str(user_id)}/followings', {'index': index, 'limit': limit})
|
|
|
|
|
|
|
|
|
|
def get_user_followers(self, user_id, index=0, limit=25):
|
|
|
|
|
return self.api_call(f'user/{str(user_id)}/followers', {'index': index, 'limit': limit})
|
|
|
|
|
|
|
|
|
|
def get_user_playlists(self, user_id, index=0, limit=25):
|
|
|
|
|
return self.api_call(f'user/{str(user_id)}/playlists', {'index': index, 'limit': limit})
|
|
|
|
|
|
|
|
|
|
def get_user_radios(self, user_id, index=0, limit=25):
|
|
|
|
|
return self.api_call(f'user/{str(user_id)}/radios', {'index': index, 'limit': limit})
|
|
|
|
|
|
|
|
|
|
def get_user_tracks(self, user_id, index=0, limit=25):
|
|
|
|
|
return self.api_call(f'user/{str(user_id)}/tracks', {'index': index, 'limit': limit})
|
|
|
|
|
|
2020-11-19 17:56:40 +00:00
|
|
|
|
# Extra calls
|
|
|
|
|
|
|
|
|
|
def get_countries_charts(self):
|
2020-11-19 19:42:41 +00:00
|
|
|
|
temp = self.get_user_playlists('637006841', limit=-1)['data']
|
2020-11-19 17:56:40 +00:00
|
|
|
|
result = sorted(temp, key=lambda k: k['title']) # Sort all playlists
|
|
|
|
|
if not result[0]['title'].startswith('Top'): result = result[1:] # Remove loved tracks playlist
|
|
|
|
|
return result
|
|
|
|
|
|
|
|
|
|
def get_track_id_from_metadata(self, artist, track, album):
|
|
|
|
|
artist = artist.replace("–", "-").replace("’", "'")
|
|
|
|
|
track = track.replace("–", "-").replace("’", "'")
|
|
|
|
|
album = album.replace("–", "-").replace("’", "'")
|
|
|
|
|
|
|
|
|
|
resp = self.advanced_search(artist=artist, track=track, album=album, limit=1)
|
|
|
|
|
if len(resp['data']) > 0: return resp['data'][0]['id']
|
|
|
|
|
|
|
|
|
|
resp = self.advanced_search(artist=artist, track=track, limit=1)
|
|
|
|
|
if len(resp['data']) > 0: return resp['data'][0]['id']
|
|
|
|
|
|
|
|
|
|
# Try removing version
|
|
|
|
|
if "(" in track and ")" in track and track.find("(") < track.find(")"):
|
|
|
|
|
resp = self.advanced_search(artist=artist, track=track[:track.find("(")], limit=1)
|
|
|
|
|
if len(resp['data']) > 0: return resp['data'][0]['id']
|
|
|
|
|
elif " - " in track:
|
|
|
|
|
resp = self.advanced_search(artist=artist, track=track[:track.find(" - ")], limit=1)
|
|
|
|
|
if len(resp['data']) > 0: return resp['data'][0]['id']
|
2021-03-12 14:02:11 +00:00
|
|
|
|
return "0"
|