Skip to content

Commit

Permalink
feat(playlists): add functions to create, edit, reorder and delete pl…
Browse files Browse the repository at this point in the history
…aylists and edit user library playlists (#709)

* feat(playlists): add functions to create, edit and delete playlists and add functions to add and remove playlists from user library

* feat(playlists): add reorder function

* chore(sourcery): add sourcery suggestions

* feat(playlist): multiple track arguments

* fix(playlist): fix my code that didnt work
  • Loading branch information
arctixdev committed May 8, 2023
1 parent ddc6341 commit 5257988
Show file tree
Hide file tree
Showing 11 changed files with 1,256 additions and 6 deletions.
47 changes: 41 additions & 6 deletions src/deezer/client.py
Expand Up @@ -118,12 +118,11 @@ def _process_json(
if "id" not in result and resource_id is not None:
result["id"] = resource_id

if "type" in result:
if result["type"] in self.objects_types:
object_class = self.objects_types[result["type"]]
else:
# in case any new types are introduced by the API
object_class = Resource
if "type" in result and result["type"] in self.objects_types:
object_class = self.objects_types[result["type"]]
elif "type" in result or not resource_type and "id" in result:
# in case any new types are introduced by the API
object_class = Resource
elif resource_type:
object_class = resource_type
else:
Expand Down Expand Up @@ -541,6 +540,42 @@ def remove_user_track(self, track_id: int) -> bool:
"""
return self.request("DELETE", "user/me/tracks", track_id=track_id)

def remove_user_playlist(self, playlist_id: int) -> bool:
"""
Remove a playlist from the user's library
:param playlist_id: the ID of the playlist to remove.
:return: boolean whether the operation succeeded.
"""
return self.request("DELETE", "user/me/playlists", playlist_id=playlist_id)

def add_user_playlist(self, playlist_id: int) -> bool:
"""
Add a playlist to the user's library
:param playlist_id: the ID of the playlist to add.
:return: boolean whether the operation succeeded.
"""
return self.request("POST", "user/me/playlists", playlist_id=playlist_id)

def create_playlist(self, playlist_name) -> int:
"""
Create a playlist on the user's account
:param playlist_name: the name of the playlist.
:return: ID of the new playlist.
"""
return self.request("POST", "user/me/playlists", title=playlist_name).id

def delete_playlist(self, playlist_id) -> bool:
"""
Delete a playlist from the user's account
:param playlist_id: the ID of the playlist to remove.
:return: boolean whether the operation succeeded.
"""
return self.request("DELETE", f"playlist/{playlist_id}")

def _search(
self,
path: str,
Expand Down
48 changes: 48 additions & 0 deletions src/deezer/resources/playlist.py
Expand Up @@ -56,3 +56,51 @@ def get_fans(self, **kwargs) -> PaginatedList[User]:
of :class:`User <deezer.User>` instances
"""
return self.get_paginated_list("fans", **kwargs)

def add_tracks(self, tracks: list, **kwargs) -> bool:
"""
Add tracks to a playlist.
:param tracks: A list of the track's or track id's to add to the playlist
:returns: a boolean that tells if the operation was successful
"""
tracks_ids = []
for track in tracks:
if isinstance(track, int):
tracks_ids.append(str(track))
else:
tracks_ids.append(str(track.id))
tracks_parsed = ",".join(tracks_ids)
return self.client.request(
"POST", f"playlist/{self.id}/tracks", songs=tracks_parsed, **kwargs
)

def delete_tracks(self, tracks: list, **kwargs) -> bool:
"""
Delete tracks from a playlist.
:param tracks: A list of the track's or track id's to delete to the playlist
:returns: a boolean that tells if the operation was successful
"""
tracks_ids = []
for track in tracks:
if isinstance(track, int):
tracks_ids.append(str(track))
else:
tracks_ids.append(str(track.id))
tracks_parsed = ",".join(tracks_ids)
return self.client.request(
"DELETE", f"playlist/{self.id}/tracks", songs=tracks_parsed, **kwargs
)

def reorder_tracks(self, order: list[int], **kwargs) -> bool:
"""
Reorder the tracks of a playlist.
:param order: A list of the track id's in the wished order
:returns: a boolean that tells if the operation was successful
"""
order_string = ",".join(map(str, order))
return self.client.request(
"POST", f"playlist/{self.id}/tracks", order=order_string, **kwargs
)
56 changes: 56 additions & 0 deletions tests/cassettes/TestClient.test_add_user_playlist.yaml
@@ -0,0 +1,56 @@
interactions:
- request:
body: null
headers:
Accept:
- '*/*'
Accept-Encoding:
- identity
Connection:
- keep-alive
Content-Length:
- '0'
User-Agent:
- python-requests/2.29.0
method: POST
uri: https://api.deezer.com/user/me/playlists?access_token=dummy&playlist_id=8749345882
response:
body:
string: 'true'
headers:
Access-Control-Allow-Credentials:
- 'true'
Access-Control-Allow-Headers:
- X-Requested-With, Content-Type, Authorization, Origin, Accept, Accept-Encoding
Access-Control-Allow-Methods:
- POST, GET, OPTIONS, DELETE, PUT
Access-Control-Expose-Headers:
- Location
Access-Control-Max-Age:
- '86400'
Cache-Control:
- no-store, no-cache, must-revalidate
Connection:
- keep-alive
Content-Length:
- '4'
Content-Type:
- application/json; charset=utf-8
Expires:
- Thu, 19 Nov 1981 08:52:00 GMT
Pragma:
- no-cache
Server:
- Apache
Strict-Transport-Security:
- max-age=31536000; includeSubDomains
X-Content-Type-Options:
- nosniff
X-Host:
- blm-web-76
x-org:
- FR
status:
code: 200
message: OK
version: 1
56 changes: 56 additions & 0 deletions tests/cassettes/TestClient.test_create_playlist.yaml
@@ -0,0 +1,56 @@
interactions:
- request:
body: null
headers:
Accept:
- '*/*'
Accept-Encoding:
- identity
Connection:
- keep-alive
Content-Length:
- '0'
User-Agent:
- python-requests/2.29.0
method: POST
uri: https://api.deezer.com/user/me/playlists?access_token=dummy&title=CoolPlaylist
response:
body:
string: '{"id":11336219744}'
headers:
Access-Control-Allow-Credentials:
- 'true'
Access-Control-Allow-Headers:
- X-Requested-With, Content-Type, Authorization, Origin, Accept, Accept-Encoding
Access-Control-Allow-Methods:
- POST, GET, OPTIONS, DELETE, PUT
Access-Control-Expose-Headers:
- Location
Access-Control-Max-Age:
- '86400'
Cache-Control:
- no-store, no-cache, must-revalidate
Connection:
- keep-alive
Content-Length:
- '18'
Content-Type:
- application/json; charset=utf-8
Expires:
- Thu, 19 Nov 1981 08:52:00 GMT
Pragma:
- no-cache
Server:
- Apache
Strict-Transport-Security:
- max-age=31536000; includeSubDomains
X-Content-Type-Options:
- nosniff
X-Host:
- blm-web-83
x-org:
- FR
status:
code: 200
message: OK
version: 1
56 changes: 56 additions & 0 deletions tests/cassettes/TestClient.test_delete_playlist.yaml
@@ -0,0 +1,56 @@
interactions:
- request:
body: null
headers:
Accept:
- '*/*'
Accept-Encoding:
- identity
Connection:
- keep-alive
Content-Length:
- '0'
User-Agent:
- python-requests/2.29.0
method: DELETE
uri: https://api.deezer.com/playlist/11336219744?access_token=dummy
response:
body:
string: 'true'
headers:
Access-Control-Allow-Credentials:
- 'true'
Access-Control-Allow-Headers:
- X-Requested-With, Content-Type, Authorization, Origin, Accept, Accept-Encoding
Access-Control-Allow-Methods:
- POST, GET, OPTIONS, DELETE, PUT
Access-Control-Expose-Headers:
- Location
Access-Control-Max-Age:
- '86400'
Cache-Control:
- no-store, no-cache, must-revalidate
Connection:
- keep-alive
Content-Length:
- '4'
Content-Type:
- application/json; charset=utf-8
Expires:
- Thu, 19 Nov 1981 08:52:00 GMT
Pragma:
- no-cache
Server:
- Apache
Strict-Transport-Security:
- max-age=31536000; includeSubDomains
X-Content-Type-Options:
- nosniff
X-Host:
- blm-web-38
x-org:
- FR
status:
code: 200
message: OK
version: 1
56 changes: 56 additions & 0 deletions tests/cassettes/TestClient.test_remove_user_playlist.yaml
@@ -0,0 +1,56 @@
interactions:
- request:
body: null
headers:
Accept:
- '*/*'
Accept-Encoding:
- identity
Connection:
- keep-alive
Content-Length:
- '0'
User-Agent:
- python-requests/2.29.0
method: DELETE
uri: https://api.deezer.com/user/me/playlists?access_token=dummy&playlist_id=8749345882
response:
body:
string: 'true'
headers:
Access-Control-Allow-Credentials:
- 'true'
Access-Control-Allow-Headers:
- X-Requested-With, Content-Type, Authorization, Origin, Accept, Accept-Encoding
Access-Control-Allow-Methods:
- POST, GET, OPTIONS, DELETE, PUT
Access-Control-Expose-Headers:
- Location
Access-Control-Max-Age:
- '86400'
Cache-Control:
- no-store, no-cache, must-revalidate
Connection:
- keep-alive
Content-Length:
- '4'
Content-Type:
- application/json; charset=utf-8
Expires:
- Thu, 19 Nov 1981 08:52:00 GMT
Pragma:
- no-cache
Server:
- Apache
Strict-Transport-Security:
- max-age=31536000; includeSubDomains
X-Content-Type-Options:
- nosniff
X-Host:
- blm-web-152
x-org:
- FR
status:
code: 200
message: OK
version: 1

0 comments on commit 5257988

Please sign in to comment.