Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions tests/test_user.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,14 @@ def test_get_user_playlists(session):
assert playlist_ids | favourite_ids == both_ids


def test_get_user_playlists_paginated(session):
expected_count = session.user.favorites.get_playlists_count()
all_playlists = session.user.favorites.playlists_paginated()
assert len(all_playlists) == expected_count
unique_ids = set(x.id for x in all_playlists)
assert len(unique_ids) == expected_count


def test_get_playlist_folders(session):
folder = session.user.create_folder(title="testfolder")
assert folder
Expand Down
76 changes: 47 additions & 29 deletions tidalapi/user.py
Original file line number Diff line number Diff line change
Expand Up @@ -671,31 +671,50 @@ def playlists_paginated(
order: Optional[PlaylistOrder] = None,
order_direction: Optional[OrderDirection] = None,
) -> List["Playlist"]:
"""Get the users favorite playlists, using pagination.
"""Get the users favorite playlists, using cursor-based pagination.

The v2 my-collection/playlists/folders endpoint uses cursor-based
pagination. Each response includes a ``cursor`` field that must be
passed to the next request to retrieve the following page.

:param order: Optional; A :class:`PlaylistOrder` describing the ordering type when returning the user favorite playlists. eg.: "NAME, "DATE"
:param order_direction: Optional; A :class:`OrderDirection` describing the ordering direction when sorting by `order`. eg.: "ASC", "DESC"
:return: A :class:`list` :class:`~tidalapi.playlist.Playlist` objects containing the favorite playlists.
"""
count = self.session.user.favorites.get_playlists_count()
return get_items(
self.session.user.favorites.playlists, count, order, order_direction
)
playlists: List["Playlist"] = []
cursor: Optional[str] = None

while True:
items = self.playlists(
cursor=cursor,
order=order,
order_direction=order_direction,
)
playlists.extend(items)
cursor = self._last_playlists_cursor
if not cursor or not items:
break

return playlists

def playlists(
self,
limit: int = 50,
offset: int = 0,
order: Optional[PlaylistOrder] = None,
order_direction: Optional[OrderDirection] = None,
cursor: Optional[str] = None,
) -> List["Playlist"]:
"""Get the users favorite playlists (v2 endpoint), relative to the root folder
"""Get the users favorite playlists (v2 endpoint), relative to the root folder.
This function is limited to 50 by TIDAL, requiring pagination.

:param limit: The number of playlists you want returned (Note: Cannot exceed 50)
:param offset: The index of the first playlist to fetch
:param offset: The index of the first playlist to fetch. Note: this parameter is
ignored by the TIDAL API for this endpoint. Use ``cursor`` for pagination.
:param order: Optional; A :class:`PlaylistOrder` describing the ordering type when returning the user favorite playlists. eg.: "NAME, "DATE"
:param order_direction: Optional; A :class:`OrderDirection` describing the ordering direction when sorting by `order`. eg.: "ASC", "DESC"
:param cursor: Cursor for fetching the next page of results. Obtained from
:attr:`_last_playlists_cursor` after a previous call to this method.
:return: A :class:`list` :class:`~tidalapi.playlist.Playlist` objects containing the favorite playlists.
"""
params = {
Expand All @@ -704,6 +723,8 @@ def playlists(
"limit": limit,
"includeOnly": "PLAYLIST", # Include only PLAYLIST types, FOLDER will be ignored
}
if cursor:
params["cursor"] = cursor
if order:
params["order"] = order.value
else:
Expand All @@ -714,17 +735,13 @@ def playlists(
params["orderDirection"] = OrderDirection.Descending.value

endpoint = "my-collection/playlists/folders"
return cast(
List["Playlist"],
self.session.request.map_request(
url=urljoin(
self.session.config.api_v2_location,
endpoint,
),
params=params,
parse=self.session.parse_playlist,
),
url = urljoin(self.session.config.api_v2_location, endpoint)
json_obj = self.session.request.request("GET", url, params).json()
items = self.session.request.map_json(
json_obj, parse=self.session.parse_playlist
)
self._last_playlists_cursor = json_obj.get("cursor")
return cast(List["Playlist"], items)

def playlist_folders(
self,
Expand All @@ -733,14 +750,19 @@ def playlist_folders(
order: Optional[PlaylistOrder] = None,
order_direction: Optional[OrderDirection] = None,
parent_folder_id: str = "root",
cursor: Optional[str] = None,
) -> List["Folder"]:
"""Get a list of folders created by the user.

:param limit: The number of playlists you want returned (Note: Cannot exceed 50)
:param offset: The index of the first playlist folder to fetch
:param offset: The index of the first playlist folder to fetch. Note: this
parameter is ignored by the TIDAL API for this endpoint. Use ``cursor``
for pagination.
:param order: Optional; A :class:`PlaylistOrder` describing the ordering type when returning the user favorite playlists. eg.: "NAME, "DATE"
:param order_direction: Optional; A :class:`OrderDirection` describing the ordering direction when sorting by `order`. eg.: "ASC", "DESC"
:param parent_folder_id: Parent folder ID. Default: 'root' playlist folder
:param cursor: Cursor for fetching the next page of results. Obtained from
:attr:`_last_folders_cursor` after a previous call to this method.
:return: Returns a list of :class:`~tidalapi.playlist.Folder` objects containing the Folders.
"""
params = {
Expand All @@ -750,23 +772,19 @@ def playlist_folders(
"order": "NAME",
"includeOnly": "FOLDER",
}
if cursor:
params["cursor"] = cursor
if order:
params["order"] = order.value
if order_direction:
params["orderDirection"] = order_direction.value

endpoint = "my-collection/playlists/folders"
return cast(
List["Folder"],
self.session.request.map_request(
url=urljoin(
self.session.config.api_v2_location,
endpoint,
),
params=params,
parse=self.session.parse_folder,
),
)
url = urljoin(self.session.config.api_v2_location, endpoint)
json_obj = self.session.request.request("GET", url, params).json()
items = self.session.request.map_json(json_obj, parse=self.session.parse_folder)
self._last_folders_cursor = json_obj.get("cursor")
return cast(List["Folder"], items)

def get_playlists_count(self) -> int:
"""Get the total number of playlists in the user's root collection.
Expand Down