mirror of
https://git.sr.ht/~phw/scotty
synced 2025-04-18 19:19:28 +02:00
Spotify: Implemented API request and tests for user tracks
This commit is contained in:
parent
d0739aad0f
commit
ed9debc127
4 changed files with 623 additions and 9 deletions
|
@ -68,13 +68,27 @@ func (c Client) recentlyPlayed(after *time.Time, before *time.Time, limit int) (
|
||||||
request.SetQueryParam("after", strconv.FormatInt(after.Unix(), 10))
|
request.SetQueryParam("after", strconv.FormatInt(after.Unix(), 10))
|
||||||
} else if before != nil {
|
} else if before != nil {
|
||||||
request.SetQueryParam("before", strconv.FormatInt(before.Unix(), 10))
|
request.SetQueryParam("before", strconv.FormatInt(before.Unix(), 10))
|
||||||
|
|
||||||
}
|
}
|
||||||
response, err := request.Get(path)
|
response, err := request.Get(path)
|
||||||
|
|
||||||
if response.StatusCode() != 200 {
|
if response.StatusCode() != 200 {
|
||||||
err = errors.New(response.String())
|
err = errors.New(response.String())
|
||||||
return
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c Client) UserTracks(offset int, limit int) (result TracksResult, err error) {
|
||||||
|
const path = "/me/tracks"
|
||||||
|
response, err := c.HttpClient.R().
|
||||||
|
SetQueryParams(map[string]string{
|
||||||
|
"offset": strconv.Itoa(offset),
|
||||||
|
"limit": strconv.Itoa(limit),
|
||||||
|
}).
|
||||||
|
SetResult(&result).
|
||||||
|
Get(path)
|
||||||
|
|
||||||
|
if response.StatusCode() != 200 {
|
||||||
|
err = errors.New(response.String())
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,9 +22,13 @@ THE SOFTWARE.
|
||||||
package spotify_test
|
package spotify_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"net/http"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/jarcoal/httpmock"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
"go.uploadedlobster.com/scotty/backends/spotify"
|
"go.uploadedlobster.com/scotty/backends/spotify"
|
||||||
"golang.org/x/oauth2"
|
"golang.org/x/oauth2"
|
||||||
)
|
)
|
||||||
|
@ -35,3 +39,53 @@ func TestNewClient(t *testing.T) {
|
||||||
client := spotify.NewClient(conf, token)
|
client := spotify.NewClient(conf, token)
|
||||||
assert.IsType(t, spotify.Client{}, client)
|
assert.IsType(t, spotify.Client{}, client)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestRecentlyPlayedAfter(t *testing.T) {
|
||||||
|
defer httpmock.DeactivateAndReset()
|
||||||
|
|
||||||
|
client := spotify.NewClient(oauth2.Config{}, nil)
|
||||||
|
setupHttpMock(t, client.HttpClient.GetClient(),
|
||||||
|
"https://api.spotify.com/v1/me/player/recently-played",
|
||||||
|
"testdata/recently-played.json")
|
||||||
|
|
||||||
|
result, err := client.RecentlyPlayedAfter(time.Now(), 3)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
assert := assert.New(t)
|
||||||
|
assert.Equal(3, result.Limit)
|
||||||
|
require.Len(t, result.Items, 3)
|
||||||
|
listen1 := result.Items[0]
|
||||||
|
assert.Equal("2023-11-21T15:00:07.229Z", listen1.PlayedAt)
|
||||||
|
assert.Equal("Evidence", listen1.Track.Name)
|
||||||
|
assert.Equal("Viva Emptiness", listen1.Track.Album.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetUserTracks(t *testing.T) {
|
||||||
|
defer httpmock.DeactivateAndReset()
|
||||||
|
|
||||||
|
client := spotify.NewClient(oauth2.Config{}, nil)
|
||||||
|
setupHttpMock(t, client.HttpClient.GetClient(),
|
||||||
|
"https://api.spotify.com/v1/me/tracks",
|
||||||
|
"testdata/user-tracks.json")
|
||||||
|
|
||||||
|
result, err := client.UserTracks(0, 2)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
assert := assert.New(t)
|
||||||
|
assert.Equal(1243, result.Total)
|
||||||
|
require.Len(t, result.Items, 2)
|
||||||
|
track1 := result.Items[0]
|
||||||
|
assert.Equal("2022-02-13T21:46:08Z", track1.AddedAt)
|
||||||
|
assert.Equal("Death to the Holy", track1.Track.Name)
|
||||||
|
assert.Equal("Zeal & Ardor", track1.Track.Album.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
func setupHttpMock(t *testing.T, client *http.Client, url string, testDataPath string) {
|
||||||
|
httpmock.ActivateNonDefault(client)
|
||||||
|
|
||||||
|
responder, err := httpmock.NewJsonResponder(200, httpmock.File(testDataPath))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
httpmock.RegisterResponder("GET", url, responder)
|
||||||
|
}
|
||||||
|
|
|
@ -29,6 +29,12 @@ type TracksResult struct {
|
||||||
Previous string `json:"previous"`
|
Previous string `json:"previous"`
|
||||||
Offset int `json:"offset"`
|
Offset int `json:"offset"`
|
||||||
Total int `json:"total"`
|
Total int `json:"total"`
|
||||||
|
Items []SavedTrack `json:"items"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type SavedTrack struct {
|
||||||
|
AddedAt string `json:"added_at"`
|
||||||
|
Track Track `json:"track"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type RecentlyPlayedResult struct {
|
type RecentlyPlayedResult struct {
|
||||||
|
@ -45,8 +51,8 @@ type Cursors struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type Listen struct {
|
type Listen struct {
|
||||||
Track Track `json:"track"`
|
|
||||||
PlayedAt string `json:"played_at"`
|
PlayedAt string `json:"played_at"`
|
||||||
|
Track Track `json:"track"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Track struct {
|
type Track struct {
|
||||||
|
|
540
backends/spotify/testdata/user-tracks.json
vendored
Normal file
540
backends/spotify/testdata/user-tracks.json
vendored
Normal file
|
@ -0,0 +1,540 @@
|
||||||
|
{
|
||||||
|
"href": "https://api.spotify.com/v1/me/tracks?offset=143&limit=2&locale=de,en-US;q=0.7,en;q=0.3",
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"added_at": "2022-02-13T21:46:08Z",
|
||||||
|
"track": {
|
||||||
|
"album": {
|
||||||
|
"album_type": "album",
|
||||||
|
"artists": [
|
||||||
|
{
|
||||||
|
"external_urls": {
|
||||||
|
"spotify": "https://open.spotify.com/artist/6yCjbLFZ9qAnWfsy9ujm5Y"
|
||||||
|
},
|
||||||
|
"href": "https://api.spotify.com/v1/artists/6yCjbLFZ9qAnWfsy9ujm5Y",
|
||||||
|
"id": "6yCjbLFZ9qAnWfsy9ujm5Y",
|
||||||
|
"name": "Zeal & Ardor",
|
||||||
|
"type": "artist",
|
||||||
|
"uri": "spotify:artist:6yCjbLFZ9qAnWfsy9ujm5Y"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"available_markets": [],
|
||||||
|
"external_urls": {
|
||||||
|
"spotify": "https://open.spotify.com/album/34u4cq27YP6837IcmzTTgX"
|
||||||
|
},
|
||||||
|
"href": "https://api.spotify.com/v1/albums/34u4cq27YP6837IcmzTTgX",
|
||||||
|
"id": "34u4cq27YP6837IcmzTTgX",
|
||||||
|
"images": [
|
||||||
|
{
|
||||||
|
"height": 640,
|
||||||
|
"url": "https://i.scdn.co/image/ab67616d0000b2731fedf861c139b6d8bebdc840",
|
||||||
|
"width": 640
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"height": 300,
|
||||||
|
"url": "https://i.scdn.co/image/ab67616d00001e021fedf861c139b6d8bebdc840",
|
||||||
|
"width": 300
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"height": 64,
|
||||||
|
"url": "https://i.scdn.co/image/ab67616d000048511fedf861c139b6d8bebdc840",
|
||||||
|
"width": 64
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "Zeal & Ardor",
|
||||||
|
"release_date": "2022-02-11",
|
||||||
|
"release_date_precision": "day",
|
||||||
|
"total_tracks": 14,
|
||||||
|
"type": "album",
|
||||||
|
"uri": "spotify:album:34u4cq27YP6837IcmzTTgX"
|
||||||
|
},
|
||||||
|
"artists": [
|
||||||
|
{
|
||||||
|
"external_urls": {
|
||||||
|
"spotify": "https://open.spotify.com/artist/6yCjbLFZ9qAnWfsy9ujm5Y"
|
||||||
|
},
|
||||||
|
"href": "https://api.spotify.com/v1/artists/6yCjbLFZ9qAnWfsy9ujm5Y",
|
||||||
|
"id": "6yCjbLFZ9qAnWfsy9ujm5Y",
|
||||||
|
"name": "Zeal & Ardor",
|
||||||
|
"type": "artist",
|
||||||
|
"uri": "spotify:artist:6yCjbLFZ9qAnWfsy9ujm5Y"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"available_markets": [],
|
||||||
|
"disc_number": 1,
|
||||||
|
"duration_ms": 187680,
|
||||||
|
"explicit": false,
|
||||||
|
"external_ids": {
|
||||||
|
"isrc": "CH8092101707"
|
||||||
|
},
|
||||||
|
"external_urls": {
|
||||||
|
"spotify": "https://open.spotify.com/track/07K2e1PXNra3Zd5SGCsLuZ"
|
||||||
|
},
|
||||||
|
"href": "https://api.spotify.com/v1/tracks/07K2e1PXNra3Zd5SGCsLuZ",
|
||||||
|
"id": "07K2e1PXNra3Zd5SGCsLuZ",
|
||||||
|
"is_local": false,
|
||||||
|
"name": "Death to the Holy",
|
||||||
|
"popularity": 0,
|
||||||
|
"preview_url": null,
|
||||||
|
"track_number": 3,
|
||||||
|
"type": "track",
|
||||||
|
"uri": "spotify:track:07K2e1PXNra3Zd5SGCsLuZ"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"added_at": "2022-02-13T21:34:31Z",
|
||||||
|
"track": {
|
||||||
|
"album": {
|
||||||
|
"album_type": "single",
|
||||||
|
"artists": [
|
||||||
|
{
|
||||||
|
"external_urls": {
|
||||||
|
"spotify": "https://open.spotify.com/artist/7FsZ5HKdtDFJ1xmK6NICBO"
|
||||||
|
},
|
||||||
|
"href": "https://api.spotify.com/v1/artists/7FsZ5HKdtDFJ1xmK6NICBO",
|
||||||
|
"id": "7FsZ5HKdtDFJ1xmK6NICBO",
|
||||||
|
"name": "Wucan",
|
||||||
|
"type": "artist",
|
||||||
|
"uri": "spotify:artist:7FsZ5HKdtDFJ1xmK6NICBO"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"available_markets": [
|
||||||
|
"AR",
|
||||||
|
"AU",
|
||||||
|
"AT",
|
||||||
|
"BE",
|
||||||
|
"BO",
|
||||||
|
"BR",
|
||||||
|
"BG",
|
||||||
|
"CA",
|
||||||
|
"CL",
|
||||||
|
"CO",
|
||||||
|
"CR",
|
||||||
|
"CY",
|
||||||
|
"CZ",
|
||||||
|
"DK",
|
||||||
|
"DO",
|
||||||
|
"DE",
|
||||||
|
"EC",
|
||||||
|
"EE",
|
||||||
|
"SV",
|
||||||
|
"FI",
|
||||||
|
"FR",
|
||||||
|
"GR",
|
||||||
|
"GT",
|
||||||
|
"HN",
|
||||||
|
"HK",
|
||||||
|
"HU",
|
||||||
|
"IS",
|
||||||
|
"IE",
|
||||||
|
"IT",
|
||||||
|
"LV",
|
||||||
|
"LT",
|
||||||
|
"LU",
|
||||||
|
"MY",
|
||||||
|
"MT",
|
||||||
|
"MX",
|
||||||
|
"NL",
|
||||||
|
"NZ",
|
||||||
|
"NI",
|
||||||
|
"NO",
|
||||||
|
"PA",
|
||||||
|
"PY",
|
||||||
|
"PE",
|
||||||
|
"PH",
|
||||||
|
"PL",
|
||||||
|
"PT",
|
||||||
|
"SG",
|
||||||
|
"SK",
|
||||||
|
"ES",
|
||||||
|
"SE",
|
||||||
|
"CH",
|
||||||
|
"TW",
|
||||||
|
"TR",
|
||||||
|
"UY",
|
||||||
|
"US",
|
||||||
|
"GB",
|
||||||
|
"AD",
|
||||||
|
"LI",
|
||||||
|
"MC",
|
||||||
|
"ID",
|
||||||
|
"JP",
|
||||||
|
"TH",
|
||||||
|
"VN",
|
||||||
|
"RO",
|
||||||
|
"IL",
|
||||||
|
"ZA",
|
||||||
|
"SA",
|
||||||
|
"AE",
|
||||||
|
"BH",
|
||||||
|
"QA",
|
||||||
|
"OM",
|
||||||
|
"KW",
|
||||||
|
"EG",
|
||||||
|
"MA",
|
||||||
|
"DZ",
|
||||||
|
"TN",
|
||||||
|
"LB",
|
||||||
|
"JO",
|
||||||
|
"PS",
|
||||||
|
"IN",
|
||||||
|
"BY",
|
||||||
|
"KZ",
|
||||||
|
"MD",
|
||||||
|
"UA",
|
||||||
|
"AL",
|
||||||
|
"BA",
|
||||||
|
"HR",
|
||||||
|
"ME",
|
||||||
|
"MK",
|
||||||
|
"RS",
|
||||||
|
"SI",
|
||||||
|
"KR",
|
||||||
|
"BD",
|
||||||
|
"PK",
|
||||||
|
"LK",
|
||||||
|
"GH",
|
||||||
|
"KE",
|
||||||
|
"NG",
|
||||||
|
"TZ",
|
||||||
|
"UG",
|
||||||
|
"AG",
|
||||||
|
"AM",
|
||||||
|
"BS",
|
||||||
|
"BB",
|
||||||
|
"BZ",
|
||||||
|
"BT",
|
||||||
|
"BW",
|
||||||
|
"BF",
|
||||||
|
"CV",
|
||||||
|
"CW",
|
||||||
|
"DM",
|
||||||
|
"FJ",
|
||||||
|
"GM",
|
||||||
|
"GE",
|
||||||
|
"GD",
|
||||||
|
"GW",
|
||||||
|
"GY",
|
||||||
|
"HT",
|
||||||
|
"JM",
|
||||||
|
"KI",
|
||||||
|
"LS",
|
||||||
|
"LR",
|
||||||
|
"MW",
|
||||||
|
"MV",
|
||||||
|
"ML",
|
||||||
|
"MH",
|
||||||
|
"FM",
|
||||||
|
"NA",
|
||||||
|
"NR",
|
||||||
|
"NE",
|
||||||
|
"PW",
|
||||||
|
"PG",
|
||||||
|
"WS",
|
||||||
|
"SM",
|
||||||
|
"ST",
|
||||||
|
"SN",
|
||||||
|
"SC",
|
||||||
|
"SL",
|
||||||
|
"SB",
|
||||||
|
"KN",
|
||||||
|
"LC",
|
||||||
|
"VC",
|
||||||
|
"SR",
|
||||||
|
"TL",
|
||||||
|
"TO",
|
||||||
|
"TT",
|
||||||
|
"TV",
|
||||||
|
"VU",
|
||||||
|
"AZ",
|
||||||
|
"BN",
|
||||||
|
"BI",
|
||||||
|
"KH",
|
||||||
|
"CM",
|
||||||
|
"TD",
|
||||||
|
"KM",
|
||||||
|
"GQ",
|
||||||
|
"SZ",
|
||||||
|
"GA",
|
||||||
|
"GN",
|
||||||
|
"KG",
|
||||||
|
"LA",
|
||||||
|
"MO",
|
||||||
|
"MR",
|
||||||
|
"MN",
|
||||||
|
"NP",
|
||||||
|
"RW",
|
||||||
|
"TG",
|
||||||
|
"UZ",
|
||||||
|
"ZW",
|
||||||
|
"BJ",
|
||||||
|
"MG",
|
||||||
|
"MU",
|
||||||
|
"MZ",
|
||||||
|
"AO",
|
||||||
|
"CI",
|
||||||
|
"DJ",
|
||||||
|
"ZM",
|
||||||
|
"CD",
|
||||||
|
"CG",
|
||||||
|
"IQ",
|
||||||
|
"LY",
|
||||||
|
"TJ",
|
||||||
|
"VE",
|
||||||
|
"ET",
|
||||||
|
"XK"
|
||||||
|
],
|
||||||
|
"external_urls": {
|
||||||
|
"spotify": "https://open.spotify.com/album/11XibdriTL2mncbfoWLwv7"
|
||||||
|
},
|
||||||
|
"href": "https://api.spotify.com/v1/albums/11XibdriTL2mncbfoWLwv7",
|
||||||
|
"id": "11XibdriTL2mncbfoWLwv7",
|
||||||
|
"images": [
|
||||||
|
{
|
||||||
|
"height": 640,
|
||||||
|
"url": "https://i.scdn.co/image/ab67616d0000b2734f84c9e19c3a309cd123c6e5",
|
||||||
|
"width": 640
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"height": 300,
|
||||||
|
"url": "https://i.scdn.co/image/ab67616d00001e024f84c9e19c3a309cd123c6e5",
|
||||||
|
"width": 300
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"height": 64,
|
||||||
|
"url": "https://i.scdn.co/image/ab67616d000048514f84c9e19c3a309cd123c6e5",
|
||||||
|
"width": 64
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "Night to Fall",
|
||||||
|
"release_date": "2018-10-22",
|
||||||
|
"release_date_precision": "day",
|
||||||
|
"total_tracks": 1,
|
||||||
|
"type": "album",
|
||||||
|
"uri": "spotify:album:11XibdriTL2mncbfoWLwv7"
|
||||||
|
},
|
||||||
|
"artists": [
|
||||||
|
{
|
||||||
|
"external_urls": {
|
||||||
|
"spotify": "https://open.spotify.com/artist/7FsZ5HKdtDFJ1xmK6NICBO"
|
||||||
|
},
|
||||||
|
"href": "https://api.spotify.com/v1/artists/7FsZ5HKdtDFJ1xmK6NICBO",
|
||||||
|
"id": "7FsZ5HKdtDFJ1xmK6NICBO",
|
||||||
|
"name": "Wucan",
|
||||||
|
"type": "artist",
|
||||||
|
"uri": "spotify:artist:7FsZ5HKdtDFJ1xmK6NICBO"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"available_markets": [
|
||||||
|
"AR",
|
||||||
|
"AU",
|
||||||
|
"AT",
|
||||||
|
"BE",
|
||||||
|
"BO",
|
||||||
|
"BR",
|
||||||
|
"BG",
|
||||||
|
"CA",
|
||||||
|
"CL",
|
||||||
|
"CO",
|
||||||
|
"CR",
|
||||||
|
"CY",
|
||||||
|
"CZ",
|
||||||
|
"DK",
|
||||||
|
"DO",
|
||||||
|
"DE",
|
||||||
|
"EC",
|
||||||
|
"EE",
|
||||||
|
"SV",
|
||||||
|
"FI",
|
||||||
|
"FR",
|
||||||
|
"GR",
|
||||||
|
"GT",
|
||||||
|
"HN",
|
||||||
|
"HK",
|
||||||
|
"HU",
|
||||||
|
"IS",
|
||||||
|
"IE",
|
||||||
|
"IT",
|
||||||
|
"LV",
|
||||||
|
"LT",
|
||||||
|
"LU",
|
||||||
|
"MY",
|
||||||
|
"MT",
|
||||||
|
"MX",
|
||||||
|
"NL",
|
||||||
|
"NZ",
|
||||||
|
"NI",
|
||||||
|
"NO",
|
||||||
|
"PA",
|
||||||
|
"PY",
|
||||||
|
"PE",
|
||||||
|
"PH",
|
||||||
|
"PL",
|
||||||
|
"PT",
|
||||||
|
"SG",
|
||||||
|
"SK",
|
||||||
|
"ES",
|
||||||
|
"SE",
|
||||||
|
"CH",
|
||||||
|
"TW",
|
||||||
|
"TR",
|
||||||
|
"UY",
|
||||||
|
"US",
|
||||||
|
"GB",
|
||||||
|
"AD",
|
||||||
|
"LI",
|
||||||
|
"MC",
|
||||||
|
"ID",
|
||||||
|
"JP",
|
||||||
|
"TH",
|
||||||
|
"VN",
|
||||||
|
"RO",
|
||||||
|
"IL",
|
||||||
|
"ZA",
|
||||||
|
"SA",
|
||||||
|
"AE",
|
||||||
|
"BH",
|
||||||
|
"QA",
|
||||||
|
"OM",
|
||||||
|
"KW",
|
||||||
|
"EG",
|
||||||
|
"MA",
|
||||||
|
"DZ",
|
||||||
|
"TN",
|
||||||
|
"LB",
|
||||||
|
"JO",
|
||||||
|
"PS",
|
||||||
|
"IN",
|
||||||
|
"BY",
|
||||||
|
"KZ",
|
||||||
|
"MD",
|
||||||
|
"UA",
|
||||||
|
"AL",
|
||||||
|
"BA",
|
||||||
|
"HR",
|
||||||
|
"ME",
|
||||||
|
"MK",
|
||||||
|
"RS",
|
||||||
|
"SI",
|
||||||
|
"KR",
|
||||||
|
"BD",
|
||||||
|
"PK",
|
||||||
|
"LK",
|
||||||
|
"GH",
|
||||||
|
"KE",
|
||||||
|
"NG",
|
||||||
|
"TZ",
|
||||||
|
"UG",
|
||||||
|
"AG",
|
||||||
|
"AM",
|
||||||
|
"BS",
|
||||||
|
"BB",
|
||||||
|
"BZ",
|
||||||
|
"BT",
|
||||||
|
"BW",
|
||||||
|
"BF",
|
||||||
|
"CV",
|
||||||
|
"CW",
|
||||||
|
"DM",
|
||||||
|
"FJ",
|
||||||
|
"GM",
|
||||||
|
"GE",
|
||||||
|
"GD",
|
||||||
|
"GW",
|
||||||
|
"GY",
|
||||||
|
"HT",
|
||||||
|
"JM",
|
||||||
|
"KI",
|
||||||
|
"LS",
|
||||||
|
"LR",
|
||||||
|
"MW",
|
||||||
|
"MV",
|
||||||
|
"ML",
|
||||||
|
"MH",
|
||||||
|
"FM",
|
||||||
|
"NA",
|
||||||
|
"NR",
|
||||||
|
"NE",
|
||||||
|
"PW",
|
||||||
|
"PG",
|
||||||
|
"WS",
|
||||||
|
"SM",
|
||||||
|
"ST",
|
||||||
|
"SN",
|
||||||
|
"SC",
|
||||||
|
"SL",
|
||||||
|
"SB",
|
||||||
|
"KN",
|
||||||
|
"LC",
|
||||||
|
"VC",
|
||||||
|
"SR",
|
||||||
|
"TL",
|
||||||
|
"TO",
|
||||||
|
"TT",
|
||||||
|
"TV",
|
||||||
|
"VU",
|
||||||
|
"AZ",
|
||||||
|
"BN",
|
||||||
|
"BI",
|
||||||
|
"KH",
|
||||||
|
"CM",
|
||||||
|
"TD",
|
||||||
|
"KM",
|
||||||
|
"GQ",
|
||||||
|
"SZ",
|
||||||
|
"GA",
|
||||||
|
"GN",
|
||||||
|
"KG",
|
||||||
|
"LA",
|
||||||
|
"MO",
|
||||||
|
"MR",
|
||||||
|
"MN",
|
||||||
|
"NP",
|
||||||
|
"RW",
|
||||||
|
"TG",
|
||||||
|
"UZ",
|
||||||
|
"ZW",
|
||||||
|
"BJ",
|
||||||
|
"MG",
|
||||||
|
"MU",
|
||||||
|
"MZ",
|
||||||
|
"AO",
|
||||||
|
"CI",
|
||||||
|
"DJ",
|
||||||
|
"ZM",
|
||||||
|
"CD",
|
||||||
|
"CG",
|
||||||
|
"IQ",
|
||||||
|
"LY",
|
||||||
|
"TJ",
|
||||||
|
"VE",
|
||||||
|
"ET",
|
||||||
|
"XK"
|
||||||
|
],
|
||||||
|
"disc_number": 1,
|
||||||
|
"duration_ms": 248372,
|
||||||
|
"explicit": false,
|
||||||
|
"external_ids": {
|
||||||
|
"isrc": "DEMV91805509"
|
||||||
|
},
|
||||||
|
"external_urls": {
|
||||||
|
"spotify": "https://open.spotify.com/track/30YxzMczS77DCXIWiXSzSK"
|
||||||
|
},
|
||||||
|
"href": "https://api.spotify.com/v1/tracks/30YxzMczS77DCXIWiXSzSK",
|
||||||
|
"id": "30YxzMczS77DCXIWiXSzSK",
|
||||||
|
"is_local": false,
|
||||||
|
"name": "Night to Fall",
|
||||||
|
"popularity": 29,
|
||||||
|
"preview_url": "https://p.scdn.co/mp3-preview/9d3edae25510e9f78194a04625a0773ee1f0db65?cid=5433a04d90a946f2a0e5175b1383604a",
|
||||||
|
"track_number": 1,
|
||||||
|
"type": "track",
|
||||||
|
"uri": "spotify:track:30YxzMczS77DCXIWiXSzSK"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"limit": 2,
|
||||||
|
"next": "https://api.spotify.com/v1/me/tracks?offset=145&limit=2&locale=de,en-US;q=0.7,en;q=0.3",
|
||||||
|
"offset": 143,
|
||||||
|
"previous": "https://api.spotify.com/v1/me/tracks?offset=141&limit=2&locale=de,en-US;q=0.7,en;q=0.3",
|
||||||
|
"total": 1243
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue