Skip to content

Commit

Permalink
fix get_playlist continuations (#736)
Browse files Browse the repository at this point in the history
* fix get_playlist continuations

* fix impl
  • Loading branch information
sigma67 authored Feb 2, 2025
1 parent 535f153 commit 334798f
Show file tree
Hide file tree
Showing 4 changed files with 35 additions and 14 deletions.
3 changes: 2 additions & 1 deletion tests/mixins/test_playlists.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,8 @@ def test_get_playlist_foreign(self, yt_oauth, playlist_id, tracks_len, related_l
playlist = yt_oauth.get_playlist(playlist_id, limit=None, related=True)
assert len(playlist["duration"]) > 5
assert playlist["trackCount"] > tracks_len
assert len(playlist["tracks"]) > tracks_len
# serialize each track to detect duplicates
assert len(set(json.dumps(track) for track in playlist["tracks"])) > tracks_len
assert len(playlist["related"]) == related_len
assert "suggestions" not in playlist
assert playlist["owned"] is False
Expand Down
27 changes: 27 additions & 0 deletions ytmusicapi/continuations.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,32 @@
from typing import Any, Optional

from ytmusicapi.navigation import nav

CONTINUATION_TOKEN = ["continuationItemRenderer", "continuationEndpoint", "continuationCommand", "token"]
CONTINUATION_ITEMS = ["onResponseReceivedActions", 0, "appendContinuationItemsAction", "continuationItems"]


def get_continuation_token(results: list[dict[str, Any]]) -> Optional[str]:
return nav(results[-1], CONTINUATION_TOKEN, True)


def get_continuations_2025(results, limit, request_func, parse_func):
items = []
continuation_token = get_continuation_token(results["contents"])
while continuation_token and (limit is None or len(items) < limit):
response = request_func({"continuation": continuation_token})
continuation_items = nav(response, CONTINUATION_ITEMS, True)
if not continuation_items:
break

contents = parse_func(continuation_items)
if len(contents) == 0:
break
items.extend(contents)
continuation_token = get_continuation_token(continuation_items)

return items


def get_continuations(
results, continuation_type, limit, request_func, parse_func, ctoken_path="", reloadable=False
Expand Down
12 changes: 5 additions & 7 deletions ytmusicapi/mixins/playlists.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,8 +110,9 @@ def get_playlist(
request_func = lambda additionalParams: self._send_request(endpoint, body, additionalParams)
response = request_func("")

request_func_continuations = lambda body: self._send_request(endpoint, body)
if playlistId.startswith("OLA") or playlistId.startswith("VLOLA"):
return parse_audio_playlist(response, limit, request_func)
return parse_audio_playlist(response, limit, request_func_continuations)

header_data = nav(response, [*TWO_COLUMN_RENDERER, *TAB_CONTENT, *SECTION_LIST_ITEM])
section_list = nav(response, [*TWO_COLUMN_RENDERER, "secondaryContents", *SECTION])
Expand Down Expand Up @@ -182,12 +183,9 @@ def get_playlist(
playlist["tracks"] = parse_playlist_items(content_data["contents"])

parse_func = lambda contents: parse_playlist_items(contents)
if "continuations" in content_data:
playlist["tracks"].extend(
get_continuations(
content_data, "musicPlaylistShelfContinuation", limit, request_func, parse_func
)
)
playlist["tracks"].extend(
get_continuations_2025(content_data, limit, request_func_continuations, parse_func)
)

playlist["duration_seconds"] = sum_total_duration(playlist)
return playlist
Expand Down
7 changes: 1 addition & 6 deletions ytmusicapi/parsers/playlists.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,12 +89,7 @@ def parse_audio_playlist(response: dict, limit: Optional[int], request_func) ->
playlist["tracks"] = parse_playlist_items(content_data["contents"])

parse_func = lambda contents: parse_playlist_items(contents)
if "continuations" in content_data:
playlist["tracks"].extend(
get_continuations(
content_data, "musicPlaylistShelfContinuation", limit, request_func, parse_func
)
)
playlist["tracks"].extend(get_continuations_2025(content_data, limit, request_func, parse_func))

playlist["title"] = playlist["tracks"][0]["album"]["name"]

Expand Down

0 comments on commit 334798f

Please sign in to comment.