11from datetime import datetime
22from requests import Session
3- from typing import Any , Dict , Iterable , Optional , Tuple , Union
4- from deezergw .exceptions import NoRightOnMedia , NotFoundException , UnauthorizedException
3+ from typing import Any , Dict , Optional , Tuple , Union
4+ from deezergw .exceptions import AlreadyExistsError , NotFoundException , RequestSpecificError , UnauthorizedException , UnknownException
55from deezergw .globals import Qualities , QualityType
6- from deezergw .types import LoginDumpData , MediaData
6+ from deezergw .types import LoginDumpData , MediaData , PlaylistState , ArrayLike
77
88METHOD_GET_USER_DATA = "deezer.getUserData"
99METHOD_GET_USER_PROFILE = "deezer.pageProfile"
6363 "UpdatePlaylist" ,
6464 "mutation UpdatePlaylist($input: PlaylistUpdateMutationInput!) { updatePlaylist(input: $input) { playlist { id title description isPrivate isCollaborative picture { id } } } }" ,
6565)
66+ GRAPHQL_GET_PLAYLIST_STATE = ("PlaylistState" ,"query PlaylistState($playlistId: String!) { playlist(playlistId: $playlistId) { isPrivate isCollaborative } }" )
6667
6768
6869class DeezerAPI :
@@ -167,19 +168,14 @@ def _get_api(
167168 retries -= 1
168169 self ._refresh_token ()
169170 return self ._get_api (method , json_data , retries )
171+ elif "ERROR_DATA_EXISTS" in error_data :
172+ raise AlreadyExistsError (error_data ["ERROR_DATA_EXISTS" ])
170173 else :
171- # Catch any unknown error
172- print ("[!] An unknown error was received by DeezerGW. Please report it" )
173- print ("[ ] JSON-Data:" )
174- print (response .json ())
174+ # Any other error is up to the specific function to handle
175175
176- if retries <= 0 :
177- raise Exception ("Results are empty" )
178-
179- print (f"Retrying ({ retries } tries left) ..." )
180- retries -= 1
181- self ._refresh_token ()
182- return self ._get_api (method , json_data , retries = retries )
176+ error_type : str = tuple (error_data .keys ())[0 ]
177+ error_msg : str = error_data [error_type ]
178+ raise RequestSpecificError (error_type , error_msg )
183179
184180 return results
185181
@@ -206,7 +202,10 @@ def _request_graphql(
206202 print ("Refreshing JWT Token..." )
207203 self ._refresh_jwt_token ()
208204 return self ._request_graphql (query_pair , variables )
205+ elif response_json ["errors" ][0 ]["type" ] == "PlaylistMutationFailedException" :
206+ raise UnauthorizedException (response_json ["errors" ][0 ]["message" ])
209207 else :
208+ print (response_json )
210209 raise Exception ("GraphQL request failed. Unknown JSON Error" )
211210
212211 #check if theres data before trying to access it
@@ -264,6 +263,12 @@ def get_playlist_data(self, id: Union[str, int], start: int = 0):
264263
265264 return data
266265
266+ def get_playlist_state (self , id : Union [str , int ]) -> PlaylistState :
267+ variables = {"playlistId" : str (id )}
268+ response = self ._request_graphql (GRAPHQL_GET_PLAYLIST_STATE , variables )
269+
270+ return response ["playlist" ]
271+
267272 def create_playlist (self , title :str , description :Optional [str ] = None , is_private : bool = False , is_collaborative : bool = False ) -> str :
268273 """
269274 Create a new playlist. Returns the playlist ID. Playlist cannot be both private and collaborative.
@@ -347,13 +352,13 @@ def edit_playlist(self, playlist_id:str, title: Optional[str] = None, descriptio
347352 response = self ._request_graphql (GRAPHQL_EDIT_PLAYLIST , variables )
348353 return response ["updatePlaylist" ]["playlist" ]["id" ]
349354
350- def get_track_batch_data (self , ids : Iterable [str ]):
355+ def get_track_batch_data (self , ids : ArrayLike [str ]):
351356 json_data = {"sng_ids" : tuple (ids )}
352357 data = self ._get_api (METHOD_GET_BATCH_TRACK_DATA , json_data )
353358
354359 return data
355360
356- def add_tracks_to_playlist (self , playlist_id : str , song_ids : Iterable [str ],offset : int = - 1 ) -> None :
361+ def add_tracks_to_playlist (self , playlist_id : str , song_ids : ArrayLike [str ],offset : int = - 1 ) -> None :
357362 """
358363 Add songs to a playlist.
359364
@@ -365,6 +370,9 @@ def add_tracks_to_playlist(self, playlist_id: str, song_ids: Iterable[str],offse
365370 :type offset: int
366371 """
367372
373+ if len (song_ids ) == 0 :
374+ return
375+
368376 # Convert song IDs to [id, position] format
369377 songs = [[str (song_id ), i ] for i , song_id in enumerate (song_ids )]
370378
@@ -373,10 +381,16 @@ def add_tracks_to_playlist(self, playlist_id: str, song_ids: Iterable[str],offse
373381 "songs" : songs ,
374382 "offset" : offset ,
375383 }
376-
377- self ._get_api (METHOD_ADD_PLAYLIST_TRACK , json_data )
378384
379- def remove_tracks_from_playlist (self , playlist_id : str ,song_ids : Iterable [str ]) -> None :
385+ try :
386+ self ._get_api (METHOD_ADD_PLAYLIST_TRACK , json_data )
387+ except RequestSpecificError as e :
388+ if e .error_type == "REQUEST_ERROR" :
389+ raise UnauthorizedException (e .error_msg )
390+ else :
391+ raise e
392+
393+ def remove_tracks_from_playlist (self , playlist_id : str ,song_ids : ArrayLike [str ]) -> None :
380394 """
381395 Remove songs from a playlist.
382396
@@ -385,6 +399,9 @@ def remove_tracks_from_playlist(self, playlist_id: str,song_ids: Iterable[str])
385399 :param song_ids: A list of song IDs to remove from the playlist
386400 :type song_ids: ArrayLike[str]
387401 """
402+
403+ if len (song_ids ) == 0 :
404+ return
388405
389406 songs = [[int (song_id ), i ] for i , song_id in enumerate (song_ids )] #convert song IDs to [id, position] format (as integers)
390407
@@ -422,7 +439,7 @@ def get_media_data(
422439 infos = response .json ()["data" ][0 ]
423440
424441 if "errors" in infos :
425- raise NoRightOnMedia (infos ["errors" ][0 ]["message" ])
442+ raise UnauthorizedException (infos ["errors" ][0 ]["message" ])
426443
427444 return infos ["media" ][0 ]
428445
@@ -451,7 +468,7 @@ def get_favorited_track_ids(self):
451468
452469 return favorited_tracks
453470
454- def add_favorite_tracks (self , ids : Iterable [str ]):
471+ def add_favorite_tracks (self , ids : ArrayLike [str ]):
455472 now = datetime .now ()
456473
457474 json_data = {"IDS" : tuple (ids )}
@@ -460,7 +477,7 @@ def add_favorite_tracks(self, ids: Iterable[str]):
460477 for id in ids :
461478 self .favorited_ids [id ] = now
462479
463- def remove_favorite_tracks (self , ids : Iterable [str ]):
480+ def remove_favorite_tracks (self , ids : ArrayLike [str ]):
464481 json_data = {"IDS" : tuple (ids )}
465482 self ._get_api (METHOD_REMOVE_FAVORITE_TRACKS , json_data )
466483
0 commit comments