fix: read playlist entries from the "item" key, honor limit by rows - #18
Open
tedeuxx wants to merge 2 commits into
Open
fix: read playlist entries from the "item" key, honor limit by rows#18tedeuxx wants to merge 2 commits into
tedeuxx wants to merge 2 commits into
Conversation
Skip playlist entries with no resolvable track ID (local files and unavailable/removed tracks come back with "id": None), which previously raised an unhandled pydantic ValidationError and failed the whole tool call. Fetch the pagination total via playlist_items(limit=1, fields="total") instead of playlist(fields="tracks.total") - lighter request and the authoritative total for the cursor being paginated. Closes jamiew#16 Closes jamiew#17 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
The Web API returns playlist-items rows with the entry under "item"; the parser only looked at "track", which no longer exists on those rows. Every entry resolved to None, so the previous skip-on-missing-id guard dropped 100% of tracks. Two symptoms, one cause: - get_playlist_tracks(<100-track playlist>) returned total=100, returned=0 - get_playlist_tracks(<1263-track playlist>, limit=5) timed out at 60s, because `remaining` was decremented by *parsed* tracks (always 0) instead of rows fetched, so a small limit paged through the entire playlist Fixes: - extract_playlist_entry() accepts "item" or the legacy "track" key - limit/offset now count playlist positions: consume len(rows) per batch - local/unavailable entries are returned marked (id=None, is_local=True) instead of silently disappearing; null entries keep their slot as an "Unavailable" placeholder so positions stay aligned - Track.id is now optional and Track gains is_local Verified live: 1263-track playlist with limit=5 returns in 0.56s (was a 60s timeout); 100-track playlist returns 100/100 (was 0). Refs jamiew#16 Refs jamiew#17 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
Author
|
Pushed a follow-up commit that fixes the actual root cause — the original patch traded a crash for a silent drop, and the drop turned into unbounded pagination. The Web API returns playlist-items rows with the entry under
Verified live: 1263-track playlist with |
jonico
added a commit
to jonico/spotify-mcp
that referenced
this pull request
Aug 25, 2026
get_playlist_info and playlist_resource both report total_tracks: null, even
for a 65-track playlist. They ask for it via
playlist(fields="...,tracks.total"), and a restricted app does not get that
field back -- requesting it alone yields a bare `{}`.
A one-item page of the items endpoint still reports the true total, so read it
from there when the playlist object withholds it. A reported count is trusted
as-is, so the extra request only happens when the field is actually missing,
and both call sites share one helper so they cannot drift.
Scoped deliberately to the two metadata paths. jamiew#18 already fixes the same
stripped field for get_playlist_tracks' pagination total (jamiew#17), so that call
site is left untouched here to avoid competing with it. get_user_playlists is
also left alone: filling counts there would mean one request per playlist on a
list endpoint.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
get_playlist_tracksreturns zero tracks on every playlist, and times out on large ones even with a smalllimit.Root cause
The Web API returns playlist-items rows with the entry under
item; thetrackkey is gone from those rows entirely. Confirmed live — row keys are['added_at', 'added_by', 'is_local', 'item', 'primary_color', 'video_thumbnail'].item.get("track")therefore resolved toNonefor every row, and the skip-on-missing-id guard dropped 100% of tracks. Two symptoms, one cause:total=100, returned=0limit=5timed out at 60s:remainingwas decremented by parsed tracks (always 0) rather than rows fetched, so a small limit paged through the entire playlist (~253 requests)Changes
extract_playlist_entry()acceptsitemor the legacytrackkey, with anisinstance(dict)check — the inner entry object has its own booleantrackfieldlimit/offsetcount playlist positions:remaining -= len(rows), not parsed tracks. An unparseable page can no longer holdremainingat its starting value and page forever.id=None,is_local=True) instead of silently disappearing; a null entry keeps its slot as an"Unavailable"placeholder so positions stay aligned for reorder/remove-by-indexTrack.idis now optional andTrackgainsis_localplaylist_items(limit=1, fields="total")instead ofplaylist(fields="tracks.total")— lighter request, and the authoritative total for the cursor being paginated (Use playlist_items(limit=1, fields="total") instead of playlist(fields="tracks.total") for the total count #17)current_user_saved_tracksstill uses thetrackkey and is unaffected; no other call site reads playlist-items rows.Verification
Live, against two real playlists:
limit=5limit=5, offset=10limit=Nonereturned=0limit=250(3 pages)124 tests pass, mypy clean. New coverage: entries under the
itemkey, null entries returned as placeholders, local tracks marked rather than dropped, and a regression test that a fully unparseable page issues exactly one request instead of scanning the playlist.Closes #16
Closes #17