Skip to content

Commit 9a6dc27

Browse files
authored
Merge pull request #193 from zmb3/get-playlist-items-fix-local-tracks
Fix local tracks in GetPlaylistItems
2 parents c886435 + 13d000d commit 9a6dc27

File tree

4 files changed

+49
-17
lines changed

4 files changed

+49
-17
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,4 @@
1515
# vendor/
1616

1717
.idea/
18+
.vscode/

README.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,3 +90,14 @@ Examples of the API can be found in the [examples](examples) directory.
9090
You may find tools such as [Spotify's Web API Console](https://developer.spotify.com/web-api/console/)
9191
or [Rapid API](https://rapidapi.com/package/SpotifyPublicAPI/functions?utm_source=SpotifyGitHub&utm_medium=button&utm_content=Vendor_GitHub)
9292
valuable for experimenting with the API.
93+
94+
### Missing data in responses
95+
96+
It's extremely common that when there is no market information available in your
97+
request, that the Spotify API will simply return null for details about a track
98+
or episode.
99+
100+
This typically occurs when you are just using an application's auth token, and
101+
aren't impersonating a user via oauth. As when you are using a token associated
102+
with a user, the user's market seems to be extracted from their profile and
103+
used when producing the response.

examples/paging/page.go

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,12 @@ package main
22

33
import (
44
"context"
5+
"log"
6+
"os"
7+
58
"github.com/zmb3/spotify/v2"
69
spotifyauth "github.com/zmb3/spotify/v2/auth"
710
"golang.org/x/oauth2/clientcredentials"
8-
"log"
9-
"os"
1011
)
1112

1213
func main() {
@@ -24,14 +25,24 @@ func main() {
2425
httpClient := spotifyauth.New().Client(ctx, token)
2526
client := spotify.New(httpClient)
2627

27-
tracks, err := client.GetPlaylistTracks(ctx, "57qttz6pK881sjxj2TAEEo")
28+
// Public playlist owned by noah.stride:
29+
// "Long playlist for testing pagination"
30+
playlistID := "1ckDytqUi4BUYzs6HIhcAN"
31+
if id := os.Getenv("SPOTIFY_PLAYLIST"); id != "" {
32+
playlistID = id
33+
}
34+
35+
tracks, err := client.GetPlaylistItems(
36+
ctx,
37+
spotify.ID(playlistID),
38+
)
2839
if err != nil {
2940
log.Fatal(err)
3041
}
3142

3243
log.Printf("Playlist has %d total tracks", tracks.Total)
3344
for page := 1; ; page++ {
34-
log.Printf(" Page %d has %d tracks", page, len(tracks.Tracks))
45+
log.Printf(" Page %d has %d tracks", page, len(tracks.Items))
3546
err = client.NextPage(ctx, tracks)
3647
if err == spotify.ErrNoMorePages {
3748
break

playlist.go

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -209,36 +209,45 @@ type PlaylistItem struct {
209209
Track PlaylistItemTrack `json:"track"`
210210
}
211211

212-
// PlaylistItemTrack is a union type for both tracks and episodes.
212+
// PlaylistItemTrack is a union type for both tracks and episodes. If both
213+
// values are null, it's likely that the piece of content is not available in
214+
// the configured market.
213215
type PlaylistItemTrack struct {
214216
Track *FullTrack
215217
Episode *EpisodePage
216218
}
217219

218220
// UnmarshalJSON customises the unmarshalling based on the type flags set.
219221
func (t *PlaylistItemTrack) UnmarshalJSON(b []byte) error {
220-
is := struct {
221-
Episode bool `json:"episode"`
222-
Track bool `json:"track"`
222+
// Spotify API will return `track: null`` where the content is not available
223+
// in the specified market. We should respect this and just pass the null
224+
// up...
225+
if bytes.Equal(b, []byte("null")) {
226+
return nil
227+
}
228+
229+
itemType := struct {
230+
Type string `json:"type"`
223231
}{}
224232

225-
err := json.Unmarshal(b, &is)
233+
err := json.Unmarshal(b, &itemType)
226234
if err != nil {
227235
return err
228236
}
229237

230-
if is.Episode {
238+
switch itemType.Type {
239+
case "episode":
231240
err := json.Unmarshal(b, &t.Episode)
232241
if err != nil {
233242
return err
234243
}
235-
}
236-
237-
if is.Track {
244+
case "track":
238245
err := json.Unmarshal(b, &t.Track)
239246
if err != nil {
240247
return err
241248
}
249+
default:
250+
return fmt.Errorf("unrecognized item type: %s", itemType.Type)
242251
}
243252

244253
return nil
@@ -470,17 +479,17 @@ func (c *Client) RemoveTracksFromPlaylistOpt(
470479
ctx context.Context,
471480
playlistID ID,
472481
tracks []TrackToRemove,
473-
snapshotID string) (newSnapshotID string, err error) {
474-
482+
snapshotID string,
483+
) (newSnapshotID string, err error) {
475484
return c.removeTracksFromPlaylist(ctx, playlistID, tracks, snapshotID)
476485
}
477486

478487
func (c *Client) removeTracksFromPlaylist(
479488
ctx context.Context,
480489
playlistID ID,
481490
tracks interface{},
482-
snapshotID string) (newSnapshotID string, err error) {
483-
491+
snapshotID string,
492+
) (newSnapshotID string, err error) {
484493
m := make(map[string]interface{})
485494
m["tracks"] = tracks
486495
if snapshotID != "" {

0 commit comments

Comments
 (0)