Skip to content

Commit 66ab61a

Browse files
authored
Add support for fetching top artists and tracks (#311)
1 parent 1e5bcfb commit 66ab61a

7 files changed

Lines changed: 10948 additions & 3 deletions

File tree

.pre-commit-config.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ repos:
7373
exclude: ^poetry\.lock$
7474
entry: poetry run codespell
7575
args:
76-
- --ignore-words-list=doen,te
76+
- --ignore-words-list=doen,te,ons
7777
- id: detect-private-key
7878
name: 🕵️ Detect Private Keys
7979
language: system

src/spotifyaio/models.py

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,18 @@
1212
from mashumaro.types import Discriminator, SerializationStrategy
1313

1414

15+
class LowercaseAlbumTypeSerializationStrategy(SerializationStrategy):
16+
"""Serialization strategy for objects encapsulated in items."""
17+
18+
def serialize(self, value: AlbumType) -> str:
19+
"""Serialize optional string."""
20+
return value
21+
22+
def deserialize(self, value: str) -> AlbumType:
23+
"""Deserialize optional string."""
24+
return AlbumType(value.lower())
25+
26+
1527
class DeviceType(StrEnum):
1628
"""Device type."""
1729

@@ -73,6 +85,7 @@ class AlbumType(StrEnum):
7385
"""Album type."""
7486

7587
ALBUM = "album"
88+
EP = "ep"
7689
SINGLE = "single"
7790
COMPILATION = "compilation"
7891

@@ -119,7 +132,11 @@ def deserialize(self, value: dict[str, Any]) -> list[Any]:
119132
class SimplifiedAlbum(DataClassORJSONMixin):
120133
"""Album model."""
121134

122-
album_type: AlbumType
135+
album_type: AlbumType = field(
136+
metadata=field_options(
137+
serialization_strategy=LowercaseAlbumTypeSerializationStrategy()
138+
)
139+
)
123140
total_tracks: int
124141
album_id: str = field(metadata=field_options(alias="id"))
125142
images: list[Image]
@@ -219,6 +236,20 @@ class Artist(SimplifiedArtist):
219236
"""Artist model."""
220237

221238

239+
@dataclass
240+
class TopArtistsResponse(DataClassORJSONMixin):
241+
"""Top artists response model."""
242+
243+
items: list[Artist]
244+
245+
246+
@dataclass
247+
class TopTracksResponse(DataClassORJSONMixin):
248+
"""Top tracks response model."""
249+
250+
items: list[Track]
251+
252+
222253
@dataclass
223254
class SimplifiedTrack(DataClassORJSONMixin):
224255
"""SimplifiedTrack model."""

src/spotifyaio/spotify.py

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
import asyncio
66
from dataclasses import dataclass
77
from importlib import metadata
8-
from typing import Any, Awaitable, Callable, Self
8+
from typing import TYPE_CHECKING, Any, Awaitable, Callable, Self
99

1010
from aiohttp import ClientSession
1111
from aiohttp.hdrs import METH_GET, METH_POST, METH_PUT
@@ -37,9 +37,14 @@
3737
SavedTrackResponse,
3838
Show,
3939
SimplifiedArtist,
40+
TopArtistsResponse,
41+
TopTracksResponse,
4042
UserProfile,
4143
)
4244

45+
if TYPE_CHECKING:
46+
from spotifyaio import Artist, Track
47+
4348

4449
@dataclass
4550
class SpotifyClient:
@@ -306,6 +311,18 @@ async def get_category_playlists(self, category_id: str) -> list[BasePlaylist]:
306311
)
307312
return CategoryPlaylistResponse.from_json(response).playlists.items
308313

314+
async def get_top_artists(self) -> list[Artist]:
315+
"""Get top artists."""
316+
params: dict[str, Any] = {"limit": 48}
317+
response = await self._get("v1/me/top/artists", params=params)
318+
return TopArtistsResponse.from_json(response).items
319+
320+
async def get_top_tracks(self) -> list[Track]:
321+
"""Get top tracks."""
322+
params: dict[str, Any] = {"limit": 48}
323+
response = await self._get("v1/me/top/tracks", params=params)
324+
return TopTracksResponse.from_json(response).items
325+
309326
async def get_episode(self, episode_id: str) -> Episode:
310327
"""Get episode."""
311328
identifier = episode_id.split(":")[-1]

0 commit comments

Comments
 (0)