mirror of
https://git.sr.ht/~phw/scotty
synced 2025-04-16 10:09: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))
|
||||
} else if before != nil {
|
||||
request.SetQueryParam("before", strconv.FormatInt(before.Unix(), 10))
|
||||
|
||||
}
|
||||
response, err := request.Get(path)
|
||||
|
||||
if response.StatusCode() != 200 {
|
||||
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
|
||||
}
|
||||
|
|
|
@ -22,9 +22,13 @@ THE SOFTWARE.
|
|||
package spotify_test
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/jarcoal/httpmock"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"go.uploadedlobster.com/scotty/backends/spotify"
|
||||
"golang.org/x/oauth2"
|
||||
)
|
||||
|
@ -35,3 +39,53 @@ func TestNewClient(t *testing.T) {
|
|||
client := spotify.NewClient(conf, token)
|
||||
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)
|
||||
}
|
||||
|
|
|
@ -23,12 +23,18 @@ THE SOFTWARE.
|
|||
package spotify
|
||||
|
||||
type TracksResult struct {
|
||||
Href string `json:"href"`
|
||||
Limit int `json:"limit"`
|
||||
Next string `json:"next"`
|
||||
Previous string `json:"previous"`
|
||||
Offset int `json:"offset"`
|
||||
Total int `json:"total"`
|
||||
Href string `json:"href"`
|
||||
Limit int `json:"limit"`
|
||||
Next string `json:"next"`
|
||||
Previous string `json:"previous"`
|
||||
Offset int `json:"offset"`
|
||||
Total int `json:"total"`
|
||||
Items []SavedTrack `json:"items"`
|
||||
}
|
||||
|
||||
type SavedTrack struct {
|
||||
AddedAt string `json:"added_at"`
|
||||
Track Track `json:"track"`
|
||||
}
|
||||
|
||||
type RecentlyPlayedResult struct {
|
||||
|
@ -45,8 +51,8 @@ type Cursors struct {
|
|||
}
|
||||
|
||||
type Listen struct {
|
||||
Track Track `json:"track"`
|
||||
PlayedAt string `json:"played_at"`
|
||||
Track Track `json:"track"`
|
||||
}
|
||||
|
||||
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