Skip to content

Commit fc5e056

Browse files
authored
Removing saved albums (#352)
1 parent 91e625b commit fc5e056

File tree

2 files changed

+68
-3
lines changed

2 files changed

+68
-3
lines changed

src/spotifyaio/spotify.py

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
from typing import TYPE_CHECKING, Any, Awaitable, Callable, Self
99

1010
from aiohttp import ClientSession
11-
from aiohttp.hdrs import METH_GET, METH_POST, METH_PUT
11+
from aiohttp.hdrs import METH_DELETE, METH_GET, METH_POST, METH_PUT
1212
from yarl import URL
1313

1414
from spotifyaio.exceptions import SpotifyConnectionError
@@ -144,6 +144,15 @@ async def _put(
144144
"""Handle a PUT request to Spotify."""
145145
return await self._request(METH_PUT, uri, data=data, params=params)
146146

147+
async def _delete(
148+
self,
149+
uri: str,
150+
data: dict[str, Any] | None = None,
151+
params: dict[str, Any] | None = None,
152+
) -> str:
153+
"""Handle a DELETE request to Spotify."""
154+
return await self._request(METH_DELETE, uri, data=data, params=params)
155+
147156
async def get_album(self, album_id: str) -> Album:
148157
"""Get album."""
149158
identifier = get_identifier(album_id)
@@ -188,7 +197,17 @@ async def save_albums(self, album_ids: list[str]) -> None:
188197
}
189198
await self._put("v1/me/albums", params=params)
190199

191-
# Remove an album
200+
async def remove_saved_albums(self, album_ids: list[str]) -> None:
201+
"""Remove saved albums."""
202+
if not album_ids:
203+
return
204+
if len(album_ids) > 50:
205+
msg = "Maximum of 50 albums can be removed at once"
206+
raise ValueError(msg)
207+
params: dict[str, Any] = {
208+
"ids": ",".join([get_identifier(i) for i in album_ids])
209+
}
210+
await self._delete("v1/me/albums", params=params)
192211

193212
# Check if one or more albums is already saved
194213

tests/test_spotify.py

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
from typing import TYPE_CHECKING, Any
77

88
import aiohttp
9-
from aiohttp.hdrs import METH_GET, METH_POST, METH_PUT
9+
from aiohttp.hdrs import METH_DELETE, METH_GET, METH_POST, METH_PUT
1010
from aioresponses import CallbackResult, aioresponses
1111
import pytest
1212
from yarl import URL
@@ -214,6 +214,52 @@ async def test_save_too_many_albums(
214214
responses.assert_not_called() # type: ignore[no-untyped-call]
215215

216216

217+
async def test_removing_saved_albums(
218+
responses: aioresponses,
219+
authenticated_client: SpotifyClient,
220+
) -> None:
221+
"""Test deleting saved albums."""
222+
responses.delete(
223+
f"{SPOTIFY_URL}/v1/me/albums?ids=3IqzqH6ShrRtie9Yd2ODyG%252C1A2GTWGtFfWp7KSQTwWOyo%252C2noRn2Aes5aoNVsU6iWTh",
224+
status=200,
225+
)
226+
await authenticated_client.remove_saved_albums(
227+
[
228+
"spotify:album:3IqzqH6ShrRtie9Yd2ODyG",
229+
"1A2GTWGtFfWp7KSQTwWOyo",
230+
"2noRn2Aes5aoNVsU6iWTh",
231+
]
232+
)
233+
responses.assert_called_once_with(
234+
f"{SPOTIFY_URL}/v1/me/albums",
235+
METH_DELETE,
236+
headers=HEADERS,
237+
params={
238+
"ids": "3IqzqH6ShrRtie9Yd2ODyG,1A2GTWGtFfWp7KSQTwWOyo,2noRn2Aes5aoNVsU6iWTh"
239+
},
240+
json=None,
241+
)
242+
243+
244+
async def test_removing_no_saved_albums(
245+
responses: aioresponses,
246+
authenticated_client: SpotifyClient,
247+
) -> None:
248+
"""Test removing no saved albums."""
249+
await authenticated_client.remove_saved_albums([])
250+
responses.assert_not_called() # type: ignore[no-untyped-call]
251+
252+
253+
async def test_removing_too_many_saved_albums(
254+
responses: aioresponses,
255+
authenticated_client: SpotifyClient,
256+
) -> None:
257+
"""Test removing too many saved albums."""
258+
with pytest.raises(ValueError, match="Maximum of 50 albums can be removed at once"):
259+
await authenticated_client.remove_saved_albums(["abc"] * 51)
260+
responses.assert_not_called() # type: ignore[no-untyped-call]
261+
262+
217263
@pytest.mark.parametrize(
218264
"playback_fixture",
219265
[

0 commit comments

Comments
 (0)