Skip to content

High-level helpers

Shortcuts available on both clients (sync returns values, async uses await). They return plain lists / dicts — no paging boilerplate.

client.find_track("Daft Punk", limit=5)
client.find_album("Discovery", limit=5)
client.find_artist("Daft Punk", limit=5)
client.find_playlist("workout", limit=5)
client.find_podcast("news", limit=5)
client.best_track_match("eminem")        # first hit or None
client.best_album_match("Discovery")
client.best_artist_match("Daft Punk")

client.top_tracks(limit=10)
client.top_albums(limit=10)
client.top_artists(limit=10)
client.top_playlists(limit=10)
client.top_podcasts(limit=10)
client.genre_top_tracks(132, limit=10)   # genre charts
client.genres(limit=50)
client.new_releases(limit=10)
client.editorial_selection(limit=10)

client.artist_top_tracks(27, limit=10)
client.artist_albums(27, limit=25)
client.artist_related(27, limit=10)
client.artist_radio_tracks(27, limit=25)
client.album_tracks(302127)
client.playlist_tracks(908622995, limit=10)
client.playlist_all_tracks(908622995)    # walks all pages
client.radio_tracks(38305, limit=25)
client.podcast_episodes(1523, limit=25)

client.full_track(3135556)               # {"track", "album", "artist"}
client.full_album(302127)                # {"album", "artist"}
client.track_preview_url(3135556)        # 30 s mp3 or None

# Needs an access token:
client.me()
client.my_playlists()
client.my_favorite_tracks()
client.my_favorite_albums()
client.my_favorite_artists()
client.my_flow()
client.create_playlist("My mix")
client.add_to_playlist(playlist_id, [3135556])

deezify.highlevel

High-level convenience methods shared by both clients.

Sync client: helpers run directly and return values. Async client: AsyncDeezerClient overrides every helper with an async variant (see client.py), so await client.find_track(...) works while the sync client.find_track(...) stays sync. This module holds the sync implementations plus the small pieces the async overrides reuse.

HighLevelMixin

Friendly shortcuts combining several low-level calls (sync).

Source code in deezify/highlevel.py
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
class HighLevelMixin:
    """Friendly shortcuts combining several low-level calls (sync)."""

    # -- search shortcuts ----------------------------------------------------
    def find_track(self, query: str, *, limit: int = 5) -> list:
        """Top ``limit`` tracks for ``query`` as a plain list."""
        return list(self.search.tracks(query, limit=limit))[:limit]

    def find_album(self, query: str, *, limit: int = 5) -> list:
        """Top ``limit`` albums for ``query`` as a plain list."""
        return list(self.search.albums(query, limit=limit))[:limit]

    def find_artist(self, query: str, *, limit: int = 5) -> list:
        """Top ``limit`` artists for ``query`` as a plain list."""
        return list(self.search.artists(query, limit=limit))[:limit]

    def find_playlist(self, query: str, *, limit: int = 5) -> list:
        """Top ``limit`` playlists for ``query`` as a plain list."""
        return list(self.search.playlists(query, limit=limit))[:limit]

    def find_podcast(self, query: str, *, limit: int = 5) -> list:
        """Top ``limit`` podcasts for ``query`` as a plain list."""
        return list(self.search.podcasts(query, limit=limit))[:limit]

    def best_track_match(self, query: str) -> dict | None:
        """First track result for ``query`` (``None`` when empty)."""
        items = self.find_track(query, limit=1)
        return items[0] if items else None

    def best_album_match(self, query: str) -> dict | None:
        """First album result for ``query`` (``None`` when empty)."""
        items = self.find_album(query, limit=1)
        return items[0] if items else None

    def best_artist_match(self, query: str) -> dict | None:
        """First artist result for ``query`` (``None`` when empty)."""
        items = self.find_artist(query, limit=1)
        return items[0] if items else None

    # -- artist shortcuts ------------------------------------------------------
    def artist_top_tracks(self, artist_id: int, *, limit: int = 10) -> list:
        """Top tracks of an artist as a plain list."""
        return list(self.artist.top(artist_id, limit=limit))[:limit]

    def artist_albums(self, artist_id: int, *, limit: int = 25) -> list:
        """Albums of an artist as a plain list."""
        return list(self.artist.albums(artist_id, limit=limit))[:limit]

    def artist_related(self, artist_id: int, *, limit: int = 10) -> list:
        """Related artists as a plain list."""
        return list(self.artist.related(artist_id, limit=limit))[:limit]

    def artist_radio_tracks(self, artist_id: int, *, limit: int = 25) -> list:
        """Artist radio tracks as a plain list."""
        return list(self.artist.radio(artist_id, limit=limit))[:limit]

    # -- album / playlist / radio shortcuts --------------------------------------
    def album_tracks(self, album_id: int) -> list:
        """Every track of an album (albums fit on one page)."""
        return list(self.album.tracks(album_id))

    def playlist_tracks(self, playlist_id: int, *, limit: int | None = None) -> list:
        """Tracks of a playlist as a plain list (``limit`` caps the result)."""
        items = list(self.playlist.tracks(playlist_id, limit=limit or 100))
        return items if limit is None else items[:limit]

    def playlist_all_tracks(self, playlist_id: int) -> list:
        """Every track of a playlist, walking all pages."""
        return list(self.playlist.tracks(playlist_id).iter_all_items())

    def radio_tracks(self, radio_id: int, *, limit: int = 25) -> list:
        """Tracks of a radio as a plain list."""
        return list(self.radio.tracks(radio_id, limit=limit))[:limit]

    def podcast_episodes(self, podcast_id: int, *, limit: int = 25) -> list:
        """Latest episodes of a podcast as a plain list."""
        return list(self.podcast.episodes(podcast_id, limit=limit))[:limit]

    # -- chart / editorial / genre shortcuts ---------------------------------------
    def top_tracks(self, *, limit: int = 10) -> list:
        """Global top tracks as a plain list."""
        return list(self.chart.tracks(limit=limit))[:limit]

    def top_albums(self, *, limit: int = 10) -> list:
        """Global top albums as a plain list."""
        return list(self.chart.albums(limit=limit))[:limit]

    def top_artists(self, *, limit: int = 10) -> list:
        """Global top artists as a plain list."""
        return list(self.chart.artists(limit=limit))[:limit]

    def top_playlists(self, *, limit: int = 10) -> list:
        """Global top playlists as a plain list."""
        return list(self.chart.playlists(limit=limit))[:limit]

    def top_podcasts(self, *, limit: int = 10) -> list:
        """Global top podcasts as a plain list."""
        return list(self.chart.podcasts(limit=limit))[:limit]

    def genre_top_tracks(self, genre_id: int, *, limit: int = 10) -> list:
        """Top tracks of a genre as a plain list."""
        return list(self.chart.tracks(genre_id, limit=limit))[:limit]

    def genres(self, *, limit: int = 50) -> list:
        """All genres as a plain list."""
        return list(self.genre.list(limit=limit))[:limit]

    def new_releases(self, *, limit: int = 10) -> list:
        """Editorial new releases as a plain list."""
        return list(self.editorial.releases(limit=limit))[:limit]

    def editorial_selection(self, *, limit: int = 10) -> list:
        """Weekly editorial album picks as a plain list."""
        return list(self.editorial.selection(limit=limit))[:limit]

    # -- track enrichment ------------------------------------------------------------
    def full_track(self, track_id: int) -> dict:
        """Track plus its full album and artist objects in one dict."""
        track = self.track.get(track_id)
        out: dict[str, Any] = {"track": track}
        album = (track.get("album") or {}) if isinstance(track, dict) else {}
        artist = (track.get("artist") or {}) if isinstance(track, dict) else {}
        if album.get("id"):
            try:
                out["album"] = self.album.get(album["id"])
            except Exception:
                out["album"] = album
        if artist.get("id"):
            try:
                out["artist"] = self.artist.get(artist["id"])
            except Exception:
                out["artist"] = artist
        return out

    def full_album(self, album_id: int) -> dict:
        """Album plus its artist object: ``{"album": ..., "artist": ...}``."""
        album = self.album.get(album_id)
        out: dict[str, Any] = {"album": album}
        artist = (album.get("artist") or {}) if isinstance(album, dict) else {}
        if artist.get("id"):
            try:
                out["artist"] = self.artist.get(artist["id"])
            except Exception:
                out["artist"] = artist
        return out

    def track_preview_url(self, track_id: int) -> str | None:
        """30-second preview MP3 URL of a track (``None`` when absent)."""
        track = self.track.get(track_id)
        return track.get("preview") if isinstance(track, dict) else None

    # -- user shortcuts (need access token) ----------------------------------------------
    def me(self) -> dict:
        """Authenticated user's profile (``GET /user/me``)."""
        return self.user.me()

    def my_playlists(self, *, limit: int = 25) -> list:
        """Authenticated user's playlists as a plain list."""
        return list(self.user.playlists("me", limit=limit))[:limit]

    def my_favorite_tracks(self, *, limit: int = 25) -> list:
        """Authenticated user's favorite tracks as a plain list."""
        return list(self.user.tracks("me", limit=limit))[:limit]

    def my_favorite_albums(self, *, limit: int = 25) -> list:
        """Authenticated user's favorite albums as a plain list."""
        return list(self.user.albums("me", limit=limit))[:limit]

    def my_favorite_artists(self, *, limit: int = 25) -> list:
        """Authenticated user's favorite artists as a plain list."""
        return list(self.user.artists("me", limit=limit))[:limit]

    def my_flow(self, *, limit: int = 25) -> list:
        """Authenticated user's Flow tracks as a plain list."""
        return list(self.user.flow("me", limit=limit))[:limit]

    def create_playlist(self, title: str, user_id: UserId = "me") -> dict:
        """Create a playlist for ``user_id`` (default: token owner)."""
        return self.user.create_playlist(user_id, title)

    def add_to_playlist(self, playlist_id: int, track_ids: list[int] | int) -> bool:
        """Append track(s) to a playlist."""
        return self.playlist.add_tracks(playlist_id, track_ids)

find_track(query, *, limit=5)

Top limit tracks for query as a plain list.

Source code in deezify/highlevel.py
23
24
25
def find_track(self, query: str, *, limit: int = 5) -> list:
    """Top ``limit`` tracks for ``query`` as a plain list."""
    return list(self.search.tracks(query, limit=limit))[:limit]

find_album(query, *, limit=5)

Top limit albums for query as a plain list.

Source code in deezify/highlevel.py
27
28
29
def find_album(self, query: str, *, limit: int = 5) -> list:
    """Top ``limit`` albums for ``query`` as a plain list."""
    return list(self.search.albums(query, limit=limit))[:limit]

find_artist(query, *, limit=5)

Top limit artists for query as a plain list.

Source code in deezify/highlevel.py
31
32
33
def find_artist(self, query: str, *, limit: int = 5) -> list:
    """Top ``limit`` artists for ``query`` as a plain list."""
    return list(self.search.artists(query, limit=limit))[:limit]

find_playlist(query, *, limit=5)

Top limit playlists for query as a plain list.

Source code in deezify/highlevel.py
35
36
37
def find_playlist(self, query: str, *, limit: int = 5) -> list:
    """Top ``limit`` playlists for ``query`` as a plain list."""
    return list(self.search.playlists(query, limit=limit))[:limit]

find_podcast(query, *, limit=5)

Top limit podcasts for query as a plain list.

Source code in deezify/highlevel.py
39
40
41
def find_podcast(self, query: str, *, limit: int = 5) -> list:
    """Top ``limit`` podcasts for ``query`` as a plain list."""
    return list(self.search.podcasts(query, limit=limit))[:limit]

best_track_match(query)

First track result for query (None when empty).

Source code in deezify/highlevel.py
43
44
45
46
def best_track_match(self, query: str) -> dict | None:
    """First track result for ``query`` (``None`` when empty)."""
    items = self.find_track(query, limit=1)
    return items[0] if items else None

best_album_match(query)

First album result for query (None when empty).

Source code in deezify/highlevel.py
48
49
50
51
def best_album_match(self, query: str) -> dict | None:
    """First album result for ``query`` (``None`` when empty)."""
    items = self.find_album(query, limit=1)
    return items[0] if items else None

best_artist_match(query)

First artist result for query (None when empty).

Source code in deezify/highlevel.py
53
54
55
56
def best_artist_match(self, query: str) -> dict | None:
    """First artist result for ``query`` (``None`` when empty)."""
    items = self.find_artist(query, limit=1)
    return items[0] if items else None

artist_top_tracks(artist_id, *, limit=10)

Top tracks of an artist as a plain list.

Source code in deezify/highlevel.py
59
60
61
def artist_top_tracks(self, artist_id: int, *, limit: int = 10) -> list:
    """Top tracks of an artist as a plain list."""
    return list(self.artist.top(artist_id, limit=limit))[:limit]

artist_albums(artist_id, *, limit=25)

Albums of an artist as a plain list.

Source code in deezify/highlevel.py
63
64
65
def artist_albums(self, artist_id: int, *, limit: int = 25) -> list:
    """Albums of an artist as a plain list."""
    return list(self.artist.albums(artist_id, limit=limit))[:limit]

Related artists as a plain list.

Source code in deezify/highlevel.py
67
68
69
def artist_related(self, artist_id: int, *, limit: int = 10) -> list:
    """Related artists as a plain list."""
    return list(self.artist.related(artist_id, limit=limit))[:limit]

artist_radio_tracks(artist_id, *, limit=25)

Artist radio tracks as a plain list.

Source code in deezify/highlevel.py
71
72
73
def artist_radio_tracks(self, artist_id: int, *, limit: int = 25) -> list:
    """Artist radio tracks as a plain list."""
    return list(self.artist.radio(artist_id, limit=limit))[:limit]

album_tracks(album_id)

Every track of an album (albums fit on one page).

Source code in deezify/highlevel.py
76
77
78
def album_tracks(self, album_id: int) -> list:
    """Every track of an album (albums fit on one page)."""
    return list(self.album.tracks(album_id))

playlist_tracks(playlist_id, *, limit=None)

Tracks of a playlist as a plain list (limit caps the result).

Source code in deezify/highlevel.py
80
81
82
83
def playlist_tracks(self, playlist_id: int, *, limit: int | None = None) -> list:
    """Tracks of a playlist as a plain list (``limit`` caps the result)."""
    items = list(self.playlist.tracks(playlist_id, limit=limit or 100))
    return items if limit is None else items[:limit]

playlist_all_tracks(playlist_id)

Every track of a playlist, walking all pages.

Source code in deezify/highlevel.py
85
86
87
def playlist_all_tracks(self, playlist_id: int) -> list:
    """Every track of a playlist, walking all pages."""
    return list(self.playlist.tracks(playlist_id).iter_all_items())

radio_tracks(radio_id, *, limit=25)

Tracks of a radio as a plain list.

Source code in deezify/highlevel.py
89
90
91
def radio_tracks(self, radio_id: int, *, limit: int = 25) -> list:
    """Tracks of a radio as a plain list."""
    return list(self.radio.tracks(radio_id, limit=limit))[:limit]

podcast_episodes(podcast_id, *, limit=25)

Latest episodes of a podcast as a plain list.

Source code in deezify/highlevel.py
93
94
95
def podcast_episodes(self, podcast_id: int, *, limit: int = 25) -> list:
    """Latest episodes of a podcast as a plain list."""
    return list(self.podcast.episodes(podcast_id, limit=limit))[:limit]

top_tracks(*, limit=10)

Global top tracks as a plain list.

Source code in deezify/highlevel.py
 98
 99
100
def top_tracks(self, *, limit: int = 10) -> list:
    """Global top tracks as a plain list."""
    return list(self.chart.tracks(limit=limit))[:limit]

top_albums(*, limit=10)

Global top albums as a plain list.

Source code in deezify/highlevel.py
102
103
104
def top_albums(self, *, limit: int = 10) -> list:
    """Global top albums as a plain list."""
    return list(self.chart.albums(limit=limit))[:limit]

top_artists(*, limit=10)

Global top artists as a plain list.

Source code in deezify/highlevel.py
106
107
108
def top_artists(self, *, limit: int = 10) -> list:
    """Global top artists as a plain list."""
    return list(self.chart.artists(limit=limit))[:limit]

top_playlists(*, limit=10)

Global top playlists as a plain list.

Source code in deezify/highlevel.py
110
111
112
def top_playlists(self, *, limit: int = 10) -> list:
    """Global top playlists as a plain list."""
    return list(self.chart.playlists(limit=limit))[:limit]

top_podcasts(*, limit=10)

Global top podcasts as a plain list.

Source code in deezify/highlevel.py
114
115
116
def top_podcasts(self, *, limit: int = 10) -> list:
    """Global top podcasts as a plain list."""
    return list(self.chart.podcasts(limit=limit))[:limit]

genre_top_tracks(genre_id, *, limit=10)

Top tracks of a genre as a plain list.

Source code in deezify/highlevel.py
118
119
120
def genre_top_tracks(self, genre_id: int, *, limit: int = 10) -> list:
    """Top tracks of a genre as a plain list."""
    return list(self.chart.tracks(genre_id, limit=limit))[:limit]

genres(*, limit=50)

All genres as a plain list.

Source code in deezify/highlevel.py
122
123
124
def genres(self, *, limit: int = 50) -> list:
    """All genres as a plain list."""
    return list(self.genre.list(limit=limit))[:limit]

new_releases(*, limit=10)

Editorial new releases as a plain list.

Source code in deezify/highlevel.py
126
127
128
def new_releases(self, *, limit: int = 10) -> list:
    """Editorial new releases as a plain list."""
    return list(self.editorial.releases(limit=limit))[:limit]

editorial_selection(*, limit=10)

Weekly editorial album picks as a plain list.

Source code in deezify/highlevel.py
130
131
132
def editorial_selection(self, *, limit: int = 10) -> list:
    """Weekly editorial album picks as a plain list."""
    return list(self.editorial.selection(limit=limit))[:limit]

full_track(track_id)

Track plus its full album and artist objects in one dict.

Source code in deezify/highlevel.py
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
def full_track(self, track_id: int) -> dict:
    """Track plus its full album and artist objects in one dict."""
    track = self.track.get(track_id)
    out: dict[str, Any] = {"track": track}
    album = (track.get("album") or {}) if isinstance(track, dict) else {}
    artist = (track.get("artist") or {}) if isinstance(track, dict) else {}
    if album.get("id"):
        try:
            out["album"] = self.album.get(album["id"])
        except Exception:
            out["album"] = album
    if artist.get("id"):
        try:
            out["artist"] = self.artist.get(artist["id"])
        except Exception:
            out["artist"] = artist
    return out

full_album(album_id)

Album plus its artist object: {"album": ..., "artist": ...}.

Source code in deezify/highlevel.py
153
154
155
156
157
158
159
160
161
162
163
def full_album(self, album_id: int) -> dict:
    """Album plus its artist object: ``{"album": ..., "artist": ...}``."""
    album = self.album.get(album_id)
    out: dict[str, Any] = {"album": album}
    artist = (album.get("artist") or {}) if isinstance(album, dict) else {}
    if artist.get("id"):
        try:
            out["artist"] = self.artist.get(artist["id"])
        except Exception:
            out["artist"] = artist
    return out

track_preview_url(track_id)

30-second preview MP3 URL of a track (None when absent).

Source code in deezify/highlevel.py
165
166
167
168
def track_preview_url(self, track_id: int) -> str | None:
    """30-second preview MP3 URL of a track (``None`` when absent)."""
    track = self.track.get(track_id)
    return track.get("preview") if isinstance(track, dict) else None

me()

Authenticated user's profile (GET /user/me).

Source code in deezify/highlevel.py
171
172
173
def me(self) -> dict:
    """Authenticated user's profile (``GET /user/me``)."""
    return self.user.me()

my_playlists(*, limit=25)

Authenticated user's playlists as a plain list.

Source code in deezify/highlevel.py
175
176
177
def my_playlists(self, *, limit: int = 25) -> list:
    """Authenticated user's playlists as a plain list."""
    return list(self.user.playlists("me", limit=limit))[:limit]

my_favorite_tracks(*, limit=25)

Authenticated user's favorite tracks as a plain list.

Source code in deezify/highlevel.py
179
180
181
def my_favorite_tracks(self, *, limit: int = 25) -> list:
    """Authenticated user's favorite tracks as a plain list."""
    return list(self.user.tracks("me", limit=limit))[:limit]

my_favorite_albums(*, limit=25)

Authenticated user's favorite albums as a plain list.

Source code in deezify/highlevel.py
183
184
185
def my_favorite_albums(self, *, limit: int = 25) -> list:
    """Authenticated user's favorite albums as a plain list."""
    return list(self.user.albums("me", limit=limit))[:limit]

my_favorite_artists(*, limit=25)

Authenticated user's favorite artists as a plain list.

Source code in deezify/highlevel.py
187
188
189
def my_favorite_artists(self, *, limit: int = 25) -> list:
    """Authenticated user's favorite artists as a plain list."""
    return list(self.user.artists("me", limit=limit))[:limit]

my_flow(*, limit=25)

Authenticated user's Flow tracks as a plain list.

Source code in deezify/highlevel.py
191
192
193
def my_flow(self, *, limit: int = 25) -> list:
    """Authenticated user's Flow tracks as a plain list."""
    return list(self.user.flow("me", limit=limit))[:limit]

create_playlist(title, user_id='me')

Create a playlist for user_id (default: token owner).

Source code in deezify/highlevel.py
195
196
197
def create_playlist(self, title: str, user_id: UserId = "me") -> dict:
    """Create a playlist for ``user_id`` (default: token owner)."""
    return self.user.create_playlist(user_id, title)

add_to_playlist(playlist_id, track_ids)

Append track(s) to a playlist.

Source code in deezify/highlevel.py
199
200
201
def add_to_playlist(self, playlist_id: int, track_ids: list[int] | int) -> bool:
    """Append track(s) to a playlist."""
    return self.playlist.add_tracks(playlist_id, track_ids)