From 4d6d0cffc18af7d345be5e636ac96767f13ac62a Mon Sep 17 00:00:00 2001 From: Noah Stride Date: Sun, 26 Jun 2022 21:10:52 +0100 Subject: [PATCH 1/3] Fix local tracks in GetPlaylistItems --- playlist.go | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/playlist.go b/playlist.go index 7d80e32..6228232 100644 --- a/playlist.go +++ b/playlist.go @@ -217,28 +217,28 @@ type PlaylistItemTrack struct { // UnmarshalJSON customises the unmarshalling based on the type flags set. func (t *PlaylistItemTrack) UnmarshalJSON(b []byte) error { - is := struct { - Episode bool `json:"episode"` - Track bool `json:"track"` + itemType := struct { + Type string `json:"type"` }{} - err := json.Unmarshal(b, &is) + err := json.Unmarshal(b, &itemType) if err != nil { return err } - if is.Episode { + switch itemType.Type { + case "episode": err := json.Unmarshal(b, &t.Episode) if err != nil { return err } - } - - if is.Track { + case "track": err := json.Unmarshal(b, &t.Track) if err != nil { return err } + default: + return fmt.Errorf("unrecognized item type: %s", itemType.Type) } return nil @@ -470,8 +470,8 @@ func (c *Client) RemoveTracksFromPlaylistOpt( ctx context.Context, playlistID ID, tracks []TrackToRemove, - snapshotID string) (newSnapshotID string, err error) { - + snapshotID string, +) (newSnapshotID string, err error) { return c.removeTracksFromPlaylist(ctx, playlistID, tracks, snapshotID) } @@ -479,8 +479,8 @@ func (c *Client) removeTracksFromPlaylist( ctx context.Context, playlistID ID, tracks interface{}, - snapshotID string) (newSnapshotID string, err error) { - + snapshotID string, +) (newSnapshotID string, err error) { m := make(map[string]interface{}) m["tracks"] = tracks if snapshotID != "" { From f235e6dfa9bf9598a99b317f01fafb379c0e110d Mon Sep 17 00:00:00 2001 From: Noah Stride Date: Sun, 26 Jun 2022 22:01:22 +0100 Subject: [PATCH 2/3] Add fix for missing market --- .gitignore | 1 + examples/paging/page.go | 19 +++++++++++++++---- playlist.go | 11 ++++++++++- 3 files changed, 26 insertions(+), 5 deletions(-) diff --git a/.gitignore b/.gitignore index ee770a6..e8dd7a2 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,4 @@ # vendor/ .idea/ +.vscode/ diff --git a/examples/paging/page.go b/examples/paging/page.go index 2bc93a2..d4dce44 100644 --- a/examples/paging/page.go +++ b/examples/paging/page.go @@ -2,11 +2,12 @@ package main import ( "context" + "log" + "os" + "github.com/zmb3/spotify/v2" spotifyauth "github.com/zmb3/spotify/v2/auth" "golang.org/x/oauth2/clientcredentials" - "log" - "os" ) func main() { @@ -24,14 +25,24 @@ func main() { httpClient := spotifyauth.New().Client(ctx, token) client := spotify.New(httpClient) - tracks, err := client.GetPlaylistTracks(ctx, "57qttz6pK881sjxj2TAEEo") + // Public playlist owned by noah.stride: + // "Long playlist for testing pagination" + playlistID := "1ckDytqUi4BUYzs6HIhcAN" + if id := os.Getenv("SPOTIFY_PLAYLIST"); id != "" { + playlistID = id + } + + tracks, err := client.GetPlaylistItems( + ctx, + spotify.ID(playlistID), + ) if err != nil { log.Fatal(err) } log.Printf("Playlist has %d total tracks", tracks.Total) for page := 1; ; page++ { - log.Printf(" Page %d has %d tracks", page, len(tracks.Tracks)) + log.Printf(" Page %d has %d tracks", page, len(tracks.Items)) err = client.NextPage(ctx, tracks) if err == spotify.ErrNoMorePages { break diff --git a/playlist.go b/playlist.go index 6228232..b0e4ffd 100644 --- a/playlist.go +++ b/playlist.go @@ -209,7 +209,9 @@ type PlaylistItem struct { Track PlaylistItemTrack `json:"track"` } -// PlaylistItemTrack is a union type for both tracks and episodes. +// PlaylistItemTrack is a union type for both tracks and episodes. If both +// values are null, it's likely that the piece of content is not available in +// the configured market. type PlaylistItemTrack struct { Track *FullTrack Episode *EpisodePage @@ -217,6 +219,13 @@ type PlaylistItemTrack struct { // UnmarshalJSON customises the unmarshalling based on the type flags set. func (t *PlaylistItemTrack) UnmarshalJSON(b []byte) error { + // Spotify API will return `track: null`` where the content is not available + // in the specified market. We should respect this and just pass the null + // up... + if bytes.Equal(b, []byte("null")) { + return nil + } + itemType := struct { Type string `json:"type"` }{} From 13d000d197ab5a91ee57e614e596a99550293fdb Mon Sep 17 00:00:00 2001 From: Noah Stride Date: Sun, 26 Jun 2022 22:05:54 +0100 Subject: [PATCH 3/3] add additional troubleshooting info on markets --- README.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/README.md b/README.md index 1f2474b..92bf794 100644 --- a/README.md +++ b/README.md @@ -90,3 +90,14 @@ Examples of the API can be found in the [examples](examples) directory. You may find tools such as [Spotify's Web API Console](https://developer.spotify.com/web-api/console/) or [Rapid API](https://rapidapi.com/package/SpotifyPublicAPI/functions?utm_source=SpotifyGitHub&utm_medium=button&utm_content=Vendor_GitHub) valuable for experimenting with the API. + +### Missing data in responses + +It's extremely common that when there is no market information available in your +request, that the Spotify API will simply return null for details about a track +or episode. + +This typically occurs when you are just using an application's auth token, and +aren't impersonating a user via oauth. As when you are using a token associated +with a user, the user's market seems to be extracted from their profile and +used when producing the response.