deezer-python 7.2.0__py3-none-any.whl → 7.3.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,56 @@
1
+ from __future__ import annotations
2
+
3
+ import datetime as dt
4
+ from typing import TYPE_CHECKING
5
+
6
+ from deezer.dates import parse_date
7
+
8
+ from .artist import AsyncArtist
9
+ from .resource import AsyncResource
10
+
11
+ if TYPE_CHECKING:
12
+ from .album import AsyncAlbum
13
+
14
+
15
+ class AsyncTrack(AsyncResource):
16
+ """Async track resource."""
17
+
18
+ id: int
19
+ readable: bool
20
+ title: str
21
+ title_short: str
22
+ title_version: str
23
+ unseen: bool
24
+ isrc: str
25
+ link: str
26
+ share: str
27
+ duration: int
28
+ track_position: int
29
+ disk_number: int
30
+ rank: int
31
+ release_date: dt.date
32
+ explicit_lyrics: bool
33
+ explicit_content_lyrics: int
34
+ explicit_content_cover: int
35
+ preview: str
36
+ bpm: float
37
+ gain: float
38
+ available_countries: list[str]
39
+ alternative: AsyncTrack
40
+ contributors: list[AsyncArtist]
41
+ md5_image: str
42
+ artist: AsyncArtist
43
+ album: AsyncAlbum
44
+
45
+ _parse_release_date = staticmethod(parse_date)
46
+
47
+ def _parse_contributors(self, raw_value):
48
+ return [AsyncArtist(client=self.client, json=val) for val in raw_value]
49
+
50
+ async def get_artist(self) -> AsyncArtist:
51
+ """Get the artist of the Track."""
52
+ return await self.client.request("GET", f"artist/{self.artist.id}")
53
+
54
+ async def get_album(self) -> AsyncAlbum:
55
+ """Get the album of the Track."""
56
+ return await self.client.request("GET", f"album/{self.album.id}")
@@ -0,0 +1,110 @@
1
+ from __future__ import annotations
2
+
3
+ import datetime as dt
4
+ from typing import TYPE_CHECKING
5
+
6
+ from deezer.dates import parse_date
7
+ from deezer.utils import get_id
8
+
9
+ from .resource import AsyncResource
10
+
11
+ if TYPE_CHECKING:
12
+ from deezer.asyncio.pagination import AsyncPaginatedList
13
+
14
+
15
+ class AsyncUser(AsyncResource):
16
+ """Async user resource."""
17
+
18
+ id: int
19
+ name: str
20
+ lastname: str | None
21
+ firstname: str | None
22
+ email: str | None
23
+ status: int | None
24
+ birthday: dt.date | None
25
+ inscription_date: dt.date
26
+ gender: str | None
27
+ link: str
28
+ picture: str
29
+ picture_small: str
30
+ picture_medium: str
31
+ picture_big: str
32
+ picture_xl: str
33
+ country: str
34
+ lang: str | None
35
+ is_kid: bool | None
36
+ explicit_content_level: str | None
37
+ explicit_content_levels_available: list[str] | None
38
+ tracklist: str
39
+
40
+ _parse_birthday = staticmethod(parse_date)
41
+ _parse_inscription_date = staticmethod(parse_date)
42
+
43
+ async def get_albums(self, **kwargs) -> AsyncPaginatedList:
44
+ """Get user's favorite albums."""
45
+ return await self.get_paginated_list("albums", **kwargs)
46
+
47
+ async def add_album(self, album) -> bool:
48
+ """Add an album to user's favorite albums."""
49
+ return await self.post_relation("albums", params={"album_id": get_id(album)})
50
+
51
+ async def remove_album(self, album) -> bool:
52
+ """Remove an album from user's favorite albums."""
53
+ return await self.delete_relation("albums", params={"album_id": get_id(album)})
54
+
55
+ async def get_tracks(self, **kwargs) -> AsyncPaginatedList:
56
+ """Get user's favorite tracks."""
57
+ return await self.get_paginated_list("tracks", **kwargs)
58
+
59
+ async def add_track(self, track) -> bool:
60
+ """Add a track to user's favorite tracks."""
61
+ return await self.post_relation("tracks", params={"track_id": get_id(track)})
62
+
63
+ async def remove_track(self, track) -> bool:
64
+ """Remove a track from user's favorite tracks."""
65
+ return await self.delete_relation("tracks", params={"track_id": get_id(track)})
66
+
67
+ async def get_artists(self, **kwargs) -> AsyncPaginatedList:
68
+ """Get user's favorite artists."""
69
+ return await self.get_paginated_list("artists", **kwargs)
70
+
71
+ async def add_artist(self, artist) -> bool:
72
+ """Add an artist to user's favorite artists."""
73
+ return await self.post_relation("artists", params={"artist_id": get_id(artist)})
74
+
75
+ async def remove_artist(self, artist) -> bool:
76
+ """Remove an artist from user's favorite artists."""
77
+ return await self.delete_relation("artists", params={"artist_id": get_id(artist)})
78
+
79
+ async def get_followers(self, **kwargs) -> AsyncPaginatedList:
80
+ """Get user's followers."""
81
+ return await self.get_paginated_list("followers", **kwargs)
82
+
83
+ async def get_followings(self, **kwargs) -> AsyncPaginatedList:
84
+ """Get user's followings."""
85
+ return await self.get_paginated_list("followings", **kwargs)
86
+
87
+ async def follow(self, user) -> bool:
88
+ """Follow a user."""
89
+ return await self.post_relation("followings", params={"user_id": get_id(user)})
90
+
91
+ async def unfollow(self, user) -> bool:
92
+ """Unfollow a user."""
93
+ return await self.delete_relation("followings", params={"user_id": get_id(user)})
94
+
95
+ async def get_playlists(self, **kwargs) -> AsyncPaginatedList:
96
+ """Get user's public playlists."""
97
+ return await self.get_paginated_list("playlists", **kwargs)
98
+
99
+ async def add_playlist(self, playlist) -> bool:
100
+ """Add a playlist to user's public playlists."""
101
+ return await self.post_relation("playlists", params={"playlist_id": get_id(playlist)})
102
+
103
+ async def remove_playlist(self, playlist) -> bool:
104
+ """Remove a playlist from user's public playlists."""
105
+ return await self.delete_relation("playlists", params={"playlist_id": get_id(playlist)})
106
+
107
+ async def create_playlist(self, title: str) -> int:
108
+ """Create a playlist."""
109
+ result = await self.post_relation("playlists", params={"title": title})
110
+ return result.id
deezer/auth.py CHANGED
@@ -16,7 +16,7 @@ class DeezerQueryAuth(httpx.Auth):
16
16
  def __init__(self, access_token: str):
17
17
  self.access_token = access_token
18
18
 
19
- def auth_flow(self, request: httpx.Request) -> typing.Generator[httpx.Request, None, None]:
19
+ def auth_flow(self, request: httpx.Request) -> typing.Generator[httpx.Request, httpx.Response, None]:
20
20
  """
21
21
  Add authentication query parameter to the request.
22
22
 
deezer/client.py CHANGED
@@ -1,15 +1,13 @@
1
1
  from __future__ import annotations
2
2
 
3
- from typing import Any, ClassVar
4
-
5
3
  import httpx
6
4
  from httpx._types import HeaderTypes
7
5
 
6
+ from deezer._mixin import DeezerMixin
8
7
  from deezer.auth import DeezerQueryAuth
9
8
  from deezer.exceptions import (
10
9
  DeezerErrorResponse,
11
10
  DeezerHTTPError,
12
- DeezerUnknownResource,
13
11
  )
14
12
  from deezer.pagination import PaginatedList
15
13
  from deezer.resources import (
@@ -28,7 +26,7 @@ from deezer.resources import (
28
26
  )
29
27
 
30
28
 
31
- class Client(httpx.Client):
29
+ class Client(DeezerMixin, httpx.Client):
32
30
  """
33
31
  A client to retrieve some basic infos about Deezer resources.
34
32
 
@@ -51,22 +49,6 @@ class Client(httpx.Client):
51
49
  :param headers: a dictionary of headers to be used.
52
50
  """
53
51
 
54
- objects_types: ClassVar[dict[str, type[Resource] | None]] = {
55
- "album": Album,
56
- "artist": Artist,
57
- "chart": Chart,
58
- "editorial": Editorial,
59
- "episode": Episode,
60
- # 'folder': None, # need identification
61
- "genre": Genre,
62
- "playlist": Playlist,
63
- "podcast": Podcast,
64
- "radio": Radio,
65
- "search": None,
66
- "track": Track,
67
- "user": User,
68
- }
69
-
70
52
  def __init__(
71
53
  self,
72
54
  access_token: str | None = None,
@@ -82,57 +64,7 @@ class Client(httpx.Client):
82
64
  headers=headers,
83
65
  )
84
66
 
85
- def _process_json(
86
- self,
87
- item: dict[str, Any],
88
- parent: Resource | None = None,
89
- resource_type: type[Resource] | None = None,
90
- resource_id: int | None = None,
91
- paginate_list=False,
92
- ):
93
- """
94
- Recursively convert dictionary to :class:`~deezer.Resource` object.
95
-
96
- :param item: the JSON response as dict.
97
- :param parent: A reference to the parent resource, to avoid fetching again.
98
- :param resource_type: The resource class to use as top level.
99
- :param resource_id: The resource id to use as top level.
100
- :param paginate_list: Whether to wrap list into a pagination object.
101
- :returns: instance of :class:`~deezer.Resource`
102
- """
103
- if "data" in item:
104
- parsed_data = [self._process_json(i, parent, paginate_list=False) for i in item["data"]]
105
- if not paginate_list:
106
- return parsed_data
107
- item["data"] = parsed_data
108
- return item
109
-
110
- result = {}
111
- for key, value in item.items():
112
- if isinstance(value, dict) and ("type" in value or "data" in value):
113
- value = self._process_json(value, parent)
114
- result[key] = value
115
- if parent is not None:
116
- result[parent.type] = parent
117
-
118
- if "id" not in result and resource_id is not None:
119
- result["id"] = resource_id
120
-
121
- if "type" in result and result["type"] in self.objects_types:
122
- object_class = self.objects_types[result["type"]]
123
- elif "type" in result or (not resource_type and "id" in result):
124
- # in case any new types are introduced by the API
125
- object_class = Resource
126
- elif resource_type:
127
- object_class = resource_type
128
- elif item.get("results") is True:
129
- return True
130
- else:
131
- raise DeezerUnknownResource(f"Unable to find resource type for {result!r}")
132
- assert object_class is not None # noqa S101
133
- return object_class(self, result)
134
-
135
- def request(
67
+ def request( # ty: ignore[invalid-method-override]
136
68
  self,
137
69
  method: str,
138
70
  path: str,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: deezer-python
3
- Version: 7.2.0
3
+ Version: 7.3.0
4
4
  Summary: A friendly wrapper library for the Deezer API
5
5
  Author-email: Bruno Alla <alla.brunoo@gmail.com>
6
6
  License-Expression: MIT
@@ -0,0 +1,42 @@
1
+ deezer/__init__.py,sha256=ydHiQL-4BdOfDFdLMQEbFMOxsn5WIncR2RKs4kjr6e8,556
2
+ deezer/_mixin.py,sha256=Q5B96yjP2_jnlMp0VSmK038CH72bvd57YTGeU8xbLAo,2822
3
+ deezer/auth.py,sha256=dtOC3_0tjtCPP8_5nFpsqDYDIsxfMlNW_0A2itQ9p5s,701
4
+ deezer/client.py,sha256=SDKEeMG4NvzKOOxI5jtO7GueibmYCdhDXnUjOkS6w-8,22343
5
+ deezer/dates.py,sha256=raTeUAAOkajl0TTzM2cupzieTY0amzTeZCaaT3gp_iU,648
6
+ deezer/exceptions.py,sha256=fDLZ63QllqaTwX83cJm1czwEz39ysAcKPB4ie_rAhYI,2004
7
+ deezer/pagination.py,sha256=iufsEnRqjXvtwWDLMnhf_Adptw1dvb8pk3dRsjTHnu8,4108
8
+ deezer/utils.py,sha256=uXCAnEZR0ulro9lz3YHlwsMgjC1_6_twqDVzGgCuuhM,610
9
+ deezer/asyncio/__init__.py,sha256=V42lzmLFsk5K3FpRyTFuz2n_BGpentYQ4ve5MojwzdI,634
10
+ deezer/asyncio/client.py,sha256=C-TWu20XuOlbSqvhsKyP78eEewp3qOi4GmnsrLnuGBM,16299
11
+ deezer/asyncio/pagination.py,sha256=TGKpx9VpRrrnC0ZA62jCZ81H9JZgfAVdqdhrg3AxgcQ,4943
12
+ deezer/asyncio/resources/__init__.py,sha256=46roTlKPH6DpSRYWApuA54XNVMFuHFNgnNEEBHk2-P0,669
13
+ deezer/asyncio/resources/album.py,sha256=0tJWBrk8jYJ3GQUlYvyCRlGx0HlsdmNEEf7jqQqHN_M,1620
14
+ deezer/asyncio/resources/artist.py,sha256=MyebbObCP-HyJPqv5bas1m_nNfZjfsEp4GBxgVHoF_A,1433
15
+ deezer/asyncio/resources/chart.py,sha256=hPWDSRPgOZC7Fx04TyVnsKkTkruS0L0_ifI6AjiLZtg,1169
16
+ deezer/asyncio/resources/editorial.py,sha256=knyGIku3tPMQTo7csusBFXiqBQAHpZXcOP96vMUb-mg,977
17
+ deezer/asyncio/resources/episode.py,sha256=icYxes7Aq4GAuoxw9R2dBz3Cz5F869pDezfgKjB7XHQ,1063
18
+ deezer/asyncio/resources/genre.py,sha256=Zwli7xR1Wz6P0hSgC12lHVc_X698YRHA-mBCpN4WGB8,870
19
+ deezer/asyncio/resources/playlist.py,sha256=YAX0Gur2TExjM0uipwVqcU6ldXCaqz2ZrkLKqwvDwlI,2042
20
+ deezer/asyncio/resources/podcast.py,sha256=dlkcMcUlEvOGrmuzk16s8f1KGO8g9APO2cpbFKbF0hI,651
21
+ deezer/asyncio/resources/radio.py,sha256=srNkXBvkf0kz0BHSLjQMV-vpEuAaGghgNl3mx5vhSPA,484
22
+ deezer/asyncio/resources/resource.py,sha256=pz0g-mJwqg7Z_meSWgKF3Q73YK4GPUPcR8o2kzs8rIQ,3343
23
+ deezer/asyncio/resources/track.py,sha256=QShZGIoVUIIqibyvKub9jZd7ThrfxXMYIYQ31NNBodk,1382
24
+ deezer/asyncio/resources/user.py,sha256=0zfzMePsx9vHdStefHVNdCUSqz5MmZJ8g86tDrEAk2o,4095
25
+ deezer/resources/__init__.py,sha256=WLHWGhV5rLyzZe9IjAtVWUsLvNJDWoldgE2JIADC0L4,549
26
+ deezer/resources/album.py,sha256=83PXZNSSkxY7qVVgyvgyHceaV4IMoQxfqcbTR5v-l38,1734
27
+ deezer/resources/artist.py,sha256=bWt4QmKK6Ywzc5JoekcSHpV7uysy_wM61bjKJMkZnBo,2239
28
+ deezer/resources/chart.py,sha256=l4l5M7bYcW1-lFKZl874CGWi-gjOVBcskJ-zL5DMcXE,2193
29
+ deezer/resources/editorial.py,sha256=eD2W9BctUSdUMo3VTMHEFkzGIRkvolLLz20ZD_pWclw,1373
30
+ deezer/resources/episode.py,sha256=1dOBQeNQeKofO_HaMFCg-rKYaPxyqgIm2eMTw0RA-vk,1722
31
+ deezer/resources/genre.py,sha256=CDWyNyFT3fXQM7jPkz3UtGr8gNtVn9430h11Jl0ZwAc,1355
32
+ deezer/resources/playlist.py,sha256=lC06LGRTpJKWxsDJHnreaWFUhYuX_ssb44sAlQZYIKU,3242
33
+ deezer/resources/podcast.py,sha256=FwfOe-m4xI1iRwauZpMjKzXKfLDryDz9Y5cVVzP8wVo,915
34
+ deezer/resources/radio.py,sha256=moOdlSJABqCcluInvgbHSwIzSIhDvBQaVyDGdgeVr_0,805
35
+ deezer/resources/resource.py,sha256=4ma_lH6S0ZljBQ24MNdOxotGJFL3rGThLSnea-RSweg,5259
36
+ deezer/resources/track.py,sha256=e3DPTsYWq5yNCjMRQhGTrFQHfQUe3xn0mEVYbpL3O_0,1546
37
+ deezer/resources/user.py,sha256=kCgMUEbKt1QJzzBEpYxPNM3IbojMlm1fYYTSgqa4Sug,6899
38
+ deezer_python-7.3.0.dist-info/licenses/LICENSE.txt,sha256=lGqKEubFaPBoiJVRoHOxg1LYlte1e5kLoq6zWUSRQzQ,1054
39
+ deezer_python-7.3.0.dist-info/METADATA,sha256=WAE62eDS85oKzo5OAUcMFIcon8b7nAPy2oAA2yLO8Bw,14059
40
+ deezer_python-7.3.0.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
41
+ deezer_python-7.3.0.dist-info/top_level.txt,sha256=yEWpBI2w2sX3SpyAi-ZGzg-lpP8apYE6uEgvnnb7S44,7
42
+ deezer_python-7.3.0.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (80.9.0)
2
+ Generator: setuptools (82.0.1)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -1,25 +0,0 @@
1
- deezer/__init__.py,sha256=aSzufMLPkXLHs04TaE7KpzQmcVfE9qRqG66U77RioUw,556
2
- deezer/auth.py,sha256=mKnPDiNBJKEq7Qo0CDu2kW_agviGpTdCbj_duFpYWco,691
3
- deezer/client.py,sha256=SmHZtjvd6F6okjoCF5tnkaoIDD_RzqztfbIeP6dyI3E,24782
4
- deezer/dates.py,sha256=raTeUAAOkajl0TTzM2cupzieTY0amzTeZCaaT3gp_iU,648
5
- deezer/exceptions.py,sha256=fDLZ63QllqaTwX83cJm1czwEz39ysAcKPB4ie_rAhYI,2004
6
- deezer/pagination.py,sha256=iufsEnRqjXvtwWDLMnhf_Adptw1dvb8pk3dRsjTHnu8,4108
7
- deezer/utils.py,sha256=uXCAnEZR0ulro9lz3YHlwsMgjC1_6_twqDVzGgCuuhM,610
8
- deezer/resources/__init__.py,sha256=WLHWGhV5rLyzZe9IjAtVWUsLvNJDWoldgE2JIADC0L4,549
9
- deezer/resources/album.py,sha256=83PXZNSSkxY7qVVgyvgyHceaV4IMoQxfqcbTR5v-l38,1734
10
- deezer/resources/artist.py,sha256=bWt4QmKK6Ywzc5JoekcSHpV7uysy_wM61bjKJMkZnBo,2239
11
- deezer/resources/chart.py,sha256=l4l5M7bYcW1-lFKZl874CGWi-gjOVBcskJ-zL5DMcXE,2193
12
- deezer/resources/editorial.py,sha256=eD2W9BctUSdUMo3VTMHEFkzGIRkvolLLz20ZD_pWclw,1373
13
- deezer/resources/episode.py,sha256=1dOBQeNQeKofO_HaMFCg-rKYaPxyqgIm2eMTw0RA-vk,1722
14
- deezer/resources/genre.py,sha256=CDWyNyFT3fXQM7jPkz3UtGr8gNtVn9430h11Jl0ZwAc,1355
15
- deezer/resources/playlist.py,sha256=lC06LGRTpJKWxsDJHnreaWFUhYuX_ssb44sAlQZYIKU,3242
16
- deezer/resources/podcast.py,sha256=FwfOe-m4xI1iRwauZpMjKzXKfLDryDz9Y5cVVzP8wVo,915
17
- deezer/resources/radio.py,sha256=moOdlSJABqCcluInvgbHSwIzSIhDvBQaVyDGdgeVr_0,805
18
- deezer/resources/resource.py,sha256=4ma_lH6S0ZljBQ24MNdOxotGJFL3rGThLSnea-RSweg,5259
19
- deezer/resources/track.py,sha256=e3DPTsYWq5yNCjMRQhGTrFQHfQUe3xn0mEVYbpL3O_0,1546
20
- deezer/resources/user.py,sha256=kCgMUEbKt1QJzzBEpYxPNM3IbojMlm1fYYTSgqa4Sug,6899
21
- deezer_python-7.2.0.dist-info/licenses/LICENSE.txt,sha256=lGqKEubFaPBoiJVRoHOxg1LYlte1e5kLoq6zWUSRQzQ,1054
22
- deezer_python-7.2.0.dist-info/METADATA,sha256=REeREdrSYkRozH2GQfcfwCjjBjkHHjPEmvE3cKnOGGc,14059
23
- deezer_python-7.2.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
24
- deezer_python-7.2.0.dist-info/top_level.txt,sha256=yEWpBI2w2sX3SpyAi-ZGzg-lpP8apYE6uEgvnnb7S44,7
25
- deezer_python-7.2.0.dist-info/RECORD,,