Fix/playlist pagination - #55
Open
Danieloni1 wants to merge 11 commits into
Open
Conversation
Runtime scope string was narrower than the declared SCOPES list, silently stripping user-top-read, user-read-recently-played, user-read-playback-position, app-remote-control, streaming, and user-library-modify. Also adds user-modify-playback-state to the list itself (was missing, required for start/pause/skip/previous). Derive the runtime scope from SCOPES so the two cannot drift again. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
pyproject.toml already pins spotipy==2.26.0 (upstream 8ee9844); lockfile was still resolving 2.24.0. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Playback.action now accepts 'previous' and dispatches to Client.previous_track() (already wraps spotipy.previous_track). Closes the one-way navigation gap where callers could only skip forward. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
✨ M1: Previous-track action + OAuth scope fix
Moves all ToolModel pydantic classes (Playback, Search, Queue, GetInfo, Playlist) plus new ones (History, TasteProfile, SmartPlay) to src/spotify_mcp/tool_models.py to keep server.py under the 500-line project guideline once M2-M4 dispatcher cases land. Adds utils.ensure_auth for read-only methods that need a fresh token but not an assigned device (search, recently-played, top items). Swaps search() from @Validate to @ensure_auth: search never touches a device, so requiring one was spurious and broke SmartPlay callers with no active device. Drops the now-unused device kwarg. Adds owner_id to parse_playlist (non-breaking) so SmartPlay can detect editorial playlists via owner.id == 'spotify'. Also prunes a batch of unused imports from server.py. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Wraps current_user_recently_played with limit clamping (Spotify caps
at 50) and mutually-exclusive after/before cursors. Returns a compact
list of {track, played_at, context_uri, context_type} per item so the
caller can recover the source playlist/album of each play.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Exposes three actions: - profile: top artists + top tracks + genre histogram. - tracks: top tracks only. - artists: top artists only. Taste profile is cached per time_range for 30 days; callers bypass the cache with refresh=True. The cache stores internal keys (_top_artist_ids, _cached_at) that M4 SmartPlay consumes; those keys are stripped before the public JSON response. Adds parse_top_artist (keeps genres + popularity) and genre_histogram helpers in utils. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
NL query -> Spotify search (track+album+playlist) -> score by name-overlap, editorial-curation, prefer-bias, and taste-bonus (match against cached top artists) -> auto-play top pick. Graceful degrade: - Taste fetch failure: rank without taste signal; taste_available=false. - Auto-play failure (no device, etc): auto_played=false with auto_play_error populated, no crash. - Empty query / invalid prefer: structured error string. Ranking isolated in ranking.py (pure functions, no spotipy import). Artist IDs are injected into candidate dicts in-memory from the raw search response so existing parsers (parse_track, parse_album) stay unchanged and no internal keys leak into Search/GetInfo output. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Documents fork-added features alongside existing tools with example prompts for each: - Playback `previous` action (new). - SpotifyHistory (M2). - SpotifyTasteProfile (M3). - SpotifySmartPlay (M4, flagship). OAuth re-auth note added for users migrating from upstream (scope list expanded). Install snippets swapped to this fork's git URL. Original upstream README preserved verbatim at README.original.md with a snapshot banner pointing back to the active README. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
✨ M2/M3/M4: History, TasteProfile, SmartPlay tools
sp.playlist() caps at 100 items; large playlists (e.g. 260+ track Dump) silently truncated. Paginate via sp.playlist_items() until exhausted. parse_tracks now also preserves added_at when present. - get_info playlist branch: extend tracks past first page - get_playlist_tracks: loop with optional cap, limit=None = all - parse_tracks: keep added_at on parsed dict Co-Authored-By: Claude Opus 4.7 <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.
No description provided.