zmb3 / spotify Goto Github PK
View Code? Open in Web Editor NEWA Go wrapper for the Spotify Web API
License: Apache License 2.0
A Go wrapper for the Spotify Web API
License: Apache License 2.0
Spotify is requiring all calls to be authenticated later this month.
Deprecate the default client and associated wrappers, and update the readme and godoc comments that mention which calls require authorization.
GetArtistAlbums(id)
will call return c.GetArtistAlbumsOpt(artistID, nil, nil)
The third arg should not be supplied.
func (c *Client) GetArtistAlbumsOpt(artistID ID, options *Options, ts ...*AlbumType) (*SimpleAlbumPage, error) {
spotifyURL := fmt.Sprintf("%sartists/%s/albums", c.baseURL, artistID)
// add optional query string if options were specified
values := url.Values{}
if ts != nil {
types := make([]string, len(ts))
for i := range ts {
types[i] = ts[i].encode()
}
values.Set("include_groups", strings.Join(types, ","))
}
that for loops panics, since ts will not be nill, but will instead be [nil]
I am trying to use your extremely useful package for a report I am writing, However the report is run as a daily job and must connect using client credentials https://developer.spotify.com/web-api/authorization-guide/#client-credentials-flow. Currently you support Authorization flow. Just wondering if its possible to use Client Credentials with your package. Using the oauth2/clientcredentials package it seems straight forward to create an authorised client. But I cannot assign it to a spotify client. Any suggestions.
import (
"context"
"fmt"
"github.com/zmb3/spotify"
"golang.org/x/oauth2/clientcredentials"
)
func main() {
config := &clientcredentials.Config{
ClientID: "CLIENTID",
ClientSecret: "SECRET",
TokenURL: "https://accounts.spotify.com/api/token",
}
//Creates an authorized *http.client
AuthorizedClient := config.Client(context.Background())
// need to assign authorizedClient to spotify.client
Hi there and thanks for this great library, it saved us a lot of work :)
I do have one problem though - an access token expires after 1 hour, but can be refreshed using the refresh token:
Access tokens are deliberately set to expire after a short time, after which new tokens may be granted by supplying the refresh token originally obtained during the authorization code exchange.
Is there a way to do this using this library?
Thanks in advance!
Running the auth example of the library returns the following error:
2017/01/13 23:32:10 Post https://accounts.spotify.com/api/token: stream error: stream ID 1; REFUSED_STREAM
UPDATE:
If it is executed with GODEBUG=http2client=0
it seems to work. This is the output I get when I set GODEBUG=http2debug=2
:
2017/01/13 23:33:57 http2: Transport failed to get client conn for accounts.spotify.com:443: http2: no cached connection was available
2017/01/13 23:33:57 http2: Transport creating client conn 0xc4200901a0 to 194.132.196.226:443
2017/01/13 23:33:57 http2: Framer 0xc4202f5800: wrote SETTINGS len=18, settings: ENABLE_PUSH=0, INITIAL_WINDOW_SIZE=4194304, MAX_HEADER_LIST_SIZE=10485760
2017/01/13 23:33:57 http2: Framer 0xc4202f5800: wrote WINDOW_UPDATE len=4 (conn) incr=1073741824
2017/01/13 23:33:57 http2: Transport encoding header ":authority" = "accounts.spotify.com"
2017/01/13 23:33:57 http2: Transport encoding header ":method" = "POST"
2017/01/13 23:33:57 http2: Transport encoding header ":path" = "/api/token"
2017/01/13 23:33:57 http2: Transport encoding header ":scheme" = "https"
2017/01/13 23:33:57 http2: Transport encoding header "content-type" = "application/x-www-form-urlencoded"
2017/01/13 23:33:57 http2: Transport encoding header "authorization" = "Basic NDEzZGY5N2FlOTZmNDliODgxN2Q1MzIyNzg4YjI0YzI6NDM5Mzk3Zjg1OGM4NGE3ZWJmOTUzMzFmZjA2NjA3ZDY="
2017/01/13 23:33:57 http2: Transport encoding header "content-length" = "379"
2017/01/13 23:33:57 http2: Transport encoding header "accept-encoding" = "gzip"
2017/01/13 23:33:57 http2: Transport encoding header "user-agent" = "Go-http-client/2.0"
2017/01/13 23:33:57 http2: Framer 0xc4202f5800: wrote HEADERS flags=END_HEADERS stream=1 len=158
2017/01/13 23:33:57 http2: Framer 0xc4202f5800: wrote DATA stream=1 len=379 data="client_id=MY_ID&code=AQAGHoYEEByHqEm9ecc22P9zqQTegw5D89DIswksVSmMcNFTcje5neDqJlNRpmxRyBihut-LCd7pLZr9vw5ltoXM2hRtTcE8yPnOFHEpzfhHxrsNOV-NnW77HMQku1X291AXOI8434rpv8t-B-5RxB62jJ9BTtumniPvSqondV1nG-UfaEoYsYNsN3VS3P17K96TknTlE9NSgmzX" (123 bytes omitted)
2017/01/13 23:33:57 http2: Framer 0xc4202f5800: wrote DATA flags=END_STREAM stream=1 len=0 data=""
2017/01/13 23:33:57 http2: Framer 0xc4202f5800: read SETTINGS len=18, settings: MAX_CONCURRENT_STREAMS=128, INITIAL_WINDOW_SIZE=0, MAX_FRAME_SIZE=16777215
2017/01/13 23:33:57 http2: Transport received SETTINGS len=18, settings: MAX_CONCURRENT_STREAMS=128, INITIAL_WINDOW_SIZE=0, MAX_FRAME_SIZE=16777215
2017/01/13 23:33:57 http2: Framer 0xc4202f5800: wrote SETTINGS flags=ACK len=0
2017/01/13 23:33:57 http2: Framer 0xc4202f5800: read WINDOW_UPDATE len=4 (conn) incr=2147418112
2017/01/13 23:33:57 http2: Transport received WINDOW_UPDATE len=4 (conn) incr=2147418112
2017/01/13 23:33:57 http2: Framer 0xc4202f5800: read SETTINGS flags=ACK len=0
2017/01/13 23:33:57 http2: Transport received SETTINGS flags=ACK len=0
2017/01/13 23:33:57 http2: Framer 0xc4202f5800: read RST_STREAM stream=1 len=4 ErrCode=REFUSED_STREAM
2017/01/13 23:33:57 http2: Transport received RST_STREAM stream=1 len=4 ErrCode=REFUSED_STREAM
2017/01/13 23:33:57 RoundTrip failure: stream error: stream ID 1; REFUSED_STREAM
2017/01/13 23:33:57 Post https://accounts.spotify.com/api/token: stream error: stream ID 1; REFUSED_STREAM
exit status 1
Hello there!
First of great work and thanks for making this package! ๐ โค๏ธ
I am trying this package to control spotifyd, however, somehow spotify API always returns with HTTP 202: Accepted (body empty)
instead of HTTP 204: No Content
as soon as I make a call (selected spotifyd as connected device).
The commands get trough! And spotifyd does everything fine, but HTTP 202
is not expected in this package so it will aways return an error.
I know that there is an Autoretry mode, however spotify always returns 202 no matter what, so I end up in an endless loop...
My guess is that there is an issue on spotifyd's side. (Will create a ticket there as well)
However I think there should be an option to enable HTTP 202 is good enough
mode
What do you think?
BTW: willing to implement that feature!
Hi. I have recently tried to use TransferPlayback method without success. Whenever I run the code below, the change of track in the PlayOpt method works, but it does not switch playback device. I start Spotify on my phone and begin playing music. I run the code, and song switches, but it doesn't change playback device to my computer. Do I have to do something else or am I just missing something?
devices, err := client.PlayerDevices()
if err != nil {
log.Print("L72: ", err)
}
for _, device := range devices {
if device.Name == "VictorsMacbookAir" {
fmt.Println(device.ID)
err = client.TransferPlayback(device.ID, true)
if err != nil {
log.Print("L79: ", err)
}
w.Header().Set("Content-Type", "text/plain")
fmt.Fprintf(w, "Login completed, transfering playback to: %s", device.Name)
break
}
}
songs := []spotify.URI{"spotify:track:7BfiAzV3ASEK9egnfxN1v1"}
options := &spotify.PlayOptions{
URIs: songs,
}
err = client.PlayOpt(options)
if err != nil {
log.Print("L93: ", err)
}
Best regards,
Victor
client.PlayOpt(&spotify.PlayOptions{PlaybackContext: &spotify.URI("SOME_URI")})
always results in a crash. Am I stupid or is this a bug?
[signal SIGSEGV: segmentation violation code=0x1 addr=0x10 pc=0x644025]
goroutine 19 [running]:
github.com/zmb3/spotify.(*Client).PlayOpt(0x0, 0xc420498030, 0x0, 0x0)
/home/lumi/go/src/github.com/zmb3/spotify/player.go:286 +0x55
main.mgmt(0x0)
/home/lumi/Projects/spotiman/mgmt.go:50 +0xdd
created by main.main
/home/lumi/Projects/spotiman/main.go:39 +0x7a
https://github.com/zmb3/spotify/blob/master/spotify.go#L235
I'm having trouble understanding why pointers are required for options? Especially for arguments like Offset
and Limit
.
Hello
I'm having trouble using your package to access Spotify web API, looking to retrieve recently played items:
package main
import (
"context"
"fmt"
"log"
"github.com/zmb3/spotify"
"golang.org/x/oauth2/clientcredentials"
)
func main() {
config := &clientcredentials.Config{
ClientID: "...",
ClientSecret: "...",
TokenURL: spotify.TokenURL,
Scopes: []string{spotify.ScopeUserReadRecentlyPlayed},
}
token, err := config.Token(context.Background())
if err != nil {
log.Fatalf("unable to get token: %v", err)
}
client := spotify.Authenticator{}.NewClient(token)
recent, err := client.PlayerRecentlyPlayedOpt(&spotify.RecentlyPlayedOptions{Limit: 10})
if err != nil {
log.Fatalf("unable to get recently played items: %v", err)
}
for _, item := range recent {
fmt.Println(item)
}
}
When I execute this code the API call for recently played items fails: 2017/10/29 15:26:53 unable to get recently played items: Insufficient client scope
Did I miss something regarding the specification of scopes?
It seems like we're cutting ContentLength
-bytes out of the body, loading it into a Buffer
, and then passing that to the JSON-parser when we could just do what we did everywhere else and parse resp.Body
directly. No?
Current:
func (c *Client) NewReleasesOpt(opt *Options) (albums *SimpleAlbumPage, err error) {
spotifyURL := baseAddress + "browse/new-releases"
if opt != nil {
v := url.Values{}
if opt.Country != nil {
v.Set("country", *opt.Country)
}
if opt.Limit != nil {
v.Set("limit", strconv.Itoa(*opt.Limit))
}
if opt.Offset != nil {
v.Set("offset", strconv.Itoa(*opt.Offset))
}
if params := v.Encode(); params != "" {
spotifyURL += "?" + params
}
}
resp, err := c.http.Get(spotifyURL)
if err != nil {
return nil, err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return nil, decodeError(c, resp)
}
buf := bytes.NewBuffer(make([]byte, 0, resp.ContentLength+1))
_, err = buf.ReadFrom(resp.Body)
if err != nil {
return nil, err
}
body := buf.Bytes()
var objmap map[string]*json.RawMessage
err = json.Unmarshal(body, &objmap)
if err != nil {
return nil, err
}
var result SimpleAlbumPage
err = json.Unmarshal(*objmap["albums"], &result)
if err != nil {
return nil, err
}
return &result, nil
}
Proposed:
func (c *Client) NewReleasesOpt(opt *Options) (albums *SimpleAlbumPage, err error) {
spotifyURL := baseAddress + "browse/new-releases"
if opt != nil {
v := url.Values{}
if opt.Country != nil {
v.Set("country", *opt.Country)
}
if opt.Limit != nil {
v.Set("limit", strconv.Itoa(*opt.Limit))
}
if opt.Offset != nil {
v.Set("offset", strconv.Itoa(*opt.Offset))
}
if params := v.Encode(); params != "" {
spotifyURL += "?" + params
}
}
resp, err := c.http.Get(spotifyURL)
if err != nil {
return nil, err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return nil, decodeError(c, resp)
}
var objmap map[string]*json.RawMessage
err = json.NewDecoder(resp.Body).Decode(&objmap)
if err != nil {
return nil, err
}
var result SimpleAlbumPage
err = json.Unmarshal(*objmap["albums"], &result)
if err != nil {
return nil, err
}
return &result, nil
}
It seems to me that userID
should be a string
in ReorderPlaylistTracks
. It is expecting an ID
instead
I'm learning go, and also new to the spotify API, so I might be missing something else :).
I'll gladly create the PR if you want
Hi there!
I noticed that the function client.PlayerCurrentlyPlaying()
returns an error with the message EOF when no song is currently playing.
The error occurs when trying to decode an empty response body.
if result != nil {
if err := json.NewDecoder(resp.Body).Decode(result); err != nil {
return err
}
}
I would offer to submit a PR to fix this, but this is actually the first project I'm working on using go, so I'm not sure how to approach this issue.
Thanks!
Realize this is not so much an issue with this Spotify lib, but curious if anyone has got Spotify's OAUTH token to "refresh" using the Go Ouath2 library?
I have implemented a pair of helper functions to writeToken and readToken that caches a json blob containing the auth token to disk. I am doing this so that the user isn't forced to continually authorize access to Spotify. As it stands Spotify has a very short token expiry (1 hour) but they do provide a refresh token when authenticated. Documented here -> https://developer.spotify.com/web-api/authorization-guide/#authorization_code_flow
@zmb3 if you have attempted such an oauth flow using the refresh token, would you mind adding this to the example?
I'm not sure this is a true bug, more like the behaviour is unclear.
cur, err := client.PlayerCurrentlyPlaying()
If I execute this while nothing is playing, I get err != nil containing: "HTTP 204: No Content (body empty)"
Is this intended? I would expect cur.Playing to just be false.
app engine seems to need a custom context to work somewhy:
Post https://accounts.spotify.com/api/token: not an App Engine context
oauth2.NoContext is user for all Follow, NewClient and Unfollow methods.
Should those accept a golang.net/x/net/context as an argument ?
I may be missing it, but I can't seem to find a function to get the user's top tracks using this https://developer.spotify.com/web-api/get-users-top-artists-and-tracks/
From previous issues, it looks like the HTTP 204 error has already been dealt with when it comes to playback functions, but I'm currently getting it for Client.PlayerStateOpt().
Simply substituting Client.get() with Client.execute() in Client.PlayerStateOpt() won't work, as it will result in an EOF error when reading the Body on a 204.
Since HTTP 204 seems to be a standard part of Spotify's API, could we add a check to Client.get() before decoding the Body that returns nil if the status code is 204?
Alternatively, if you don't want to mess with the Client.get() code, returning an exported error type that includes the HTTP status code would be nice.
When I am executing my app I am receiving a Bad Gateway on a regular basis, but not on every run. The app is simply searching for tracks and manipulating playlists. Has anyone else seen this before? Retries are turned on within the API client.
I could be helpful for newbies and to help in adoption to have working examples to match https://github.com/zmb3/spotify#api-examples.
Also, similar to those found here:
https://github.com/op/go-libspotify/tree/master/examples
It seems that e.g. getPlaylist doesn't support the paging features of the Spotify API. As Spotify limits output per page to 100, this means that the wrapper will only retrieve the first 100 items of a playlist or album. The following pages are inaccessibly through the wrapper.
Sometimes, when there's no player registered (I suppose), the API returns an EOF. The token is correct and the error can be ignored.
if ftl, err := client.PlayerCurrentlyPlaying(); err != nil {
if err != io.EOF {
log.Fatal(err)
}
} else {
if !ftl.Playing {
log.Println("Currently not playing...")
return
}
// Do whatever
}
Hi, thanks for a great library wrapper!
I wonder about the TrackAttributes struct, wouldn't it be better/simpler to map a simple struct against the spotify API? at least export the fields so it can easily decode from json.
Now it is quite awkward to construct.
In my particular usecase I fetch some json trackattributes that I just want to send to the recommendation seed, and I dont see the point in looping and testing for every property. In the end its just json objects both ways.
Is there any way to do the authentication process completely inside go, without having to use an external browser for the login part? I could not find any working solution so far.
I'm a bit confused as to how I should store the Spotify access token in order to identify users through multiple page accesses (i.e. keep a long running "session" open, saving the user's authorization grant).
Is the token itself safe to store in a cookie? Should I create a session ID and store that in a cookie instead (and use a map
to associate it with a token)? Is there a better approach that I'm not aware of?
Is there a way to delete a playlist and I missed it in the docs?
Hey,
I see that most properties in this package have a JSON-tag to make the property lowercase when marshalling the structs, but it seems that FullArtist.Followers does not have it. Is there any reason for this?
The Spotify Web API also supports the option parameter show_dialog
for authentication. Right now the library does not support this parameter and it's something that I would like to use for a project. Is there any plans to add/support this?
I don't quite understand why this is giving an "unauthorized" error.
What am I missing? The credentials work fine for some other client.
package main
import (
"context"
"fmt"
"log"
"github.com/zmb3/spotify"
"golang.org/x/oauth2/clientcredentials"
)
func main() {
config := &clientcredentials.Config{
ClientID: os.Getenv("SPOTIFY_ID"),
ClientSecret: os.Getenv("SPOTIFY_SECRET"),
TokenURL: spotify.TokenURL,
}
token, err := config.Token(context.Background())
if err != nil {
log.Fatalf("couldn't get token: %v", err)
}
client := spotify.Authenticator{}.NewClient(token)
page, err := client.CurrentUsersPlaylists()
if err != nil {
log.Fatalf("couldn't get playlists: %v", err)
}
for _, playlist := range page.Playlists {
fmt.Println(" ", playlist.Name)
}
}
Hello,
I would like to know how I could play a specific music with your library.
Thanks.
I'd like to download songs in mp3 format.
I know stream ripping violates ToS, yet this is learning purpose, and it will be completely private code.
So, kindly, if you know how to do, plz tell me roughly...:)
After clicking the auth link....
2018/07/13 21:50:48 spotify: HTTP 204: No Content (body empty)
(exit code 1)
Happened yesterday and today, starting from something between 21:00 and 21:30 Central European Standard Time. Will keep trying to log in in order to find out when it starts working again.
I am working on something where I need all the playlists of a user. I am not sure if this should be part of this library or not. Anyways here is my code:
func (c *Client) CurrentUsersAllPlaylists() (*SimplePlaylistPage, error){
var allPlaylists *SimplePlaylistPage
var total int
limit := 50
offset := 0
opt := Options{
Limit: &limit,
Offset: &offset,
}
for {
playlists, err := c.CurrentUsersPlaylistsOpt(&opt)
if err != nil {
return nil, err
}
total = playlists.Total
if allPlaylists == nil {
allPlaylists = playlists
} else {
allPlaylists.Playlists = append(allPlaylists.Playlists, playlists.Playlists...)
}
offset = offset + limit
if total < offset {
break
}
}
return allPlaylists, nil
}
If you think this is a good idea to have this as part of spotify lib, then I would be happy to send a PR ๐
I might just be missing something, but why should TransferPlayback take a slice of deviceIDs rather than just a single ID to transfer playback to?
func (c *Client) TransferPlayback(deviceIDs []ID, play bool) error {
I am still trying to figure out what is causing it, but the TransferPlayback method is very finicky for me and seems to only work when I run it in between a song change or if I start the playback through the app and not the API.
Edit: It seems like I can transfer the playback between devices but the playback gets stuck on my desktop PC running Windows 10 and then I'm unable to transfer playback from this device. This might be just an issue with my desktop client... If so I can close this if the slice of deviceIDs is purposeful.
You have alot of functions but i cant find a function to play a specific songID?
Is there something i have not seen or is this not possible?
This line is buggy
https://github.com/zmb3/spotify/blob/master/user.go#L210
ids parameter value is missing. and the type is mandatory.
https://developer.spotify.com/web-api/follow-artists-users/
this works
spotifyURL := baseAddress + "me/following?type=artist&ids=" + strings.Join(toStringSlice(ids), ",")
I can submit a PR for this, but want to know what do you consider being the best way of tackling this.
Both Follow and UNfollow use the same modifyFollowers
and take ids as varaidic arguments.
Shoud them take type as an argument? I think so. Following multiple people of different types would probably fail. SHould it be documented?
Currently trying to list the tracks on my playlist but I can't seem to get more than 100 which is the maximum items per page returned by spotify, now how do I fetch the next page of tracks?
I think this could be added to the search example or add a new example that lists all tracks (I can make a pr for that if I can get it working).
My current code
// list songs from playlist
songs, err := client.GetPlaylistTracks(user.ID, playlistID)
if err != nil {
log.Fatal(err)
}
for _, item := range songs.Tracks {
fmt.Printf("%s: %s (%s)\n", item.Track.ID, item.Track.Name, item.Track.Artists[0].Name)
}
fmt.Printf("This playlist has: %d songs (listed %d)\n", songs.Total, len(songs.Tracks))
// This one outputs: `This playlist has: 144 songs (listed 100)`
#71, which adds the ReleaseDate
and ReleaseDatePrecision
fields to the SimpleAlbum
struct, was merged ages ago, but SimpleAlbum
doesn't have the ReleaseDateTime
method which is defined for the FullAlbum
struct.
Is it possible to move the ReleaseDateTime
method to the SimpleAlbum
instead?
I would gladly open a PR if interested.
Tangentially related: Is there a reason why - especially in case of the Album structs - multiple fields are defined both on the "simple" as well as on the "full" variant even though the simple one is embedded?
Hey,
I've tried using this wrapper for authentication. It seems to work fine except for the redirectURL and state which contain a hexadecimal representation of their special characters:
auth = spotify.NewAuthenticator("http://localhost:4200/create", spotify.ScopeUserModifyPlaybackState)
config := config.ReadConfig()
auth.SetAuthInfo(config.ClientId, config.ClientSecret)
code := rest_objects.AuthorizationCode{Uri: auth.AuthURL(time.Now().Format(time.RFC3339))}
println(code.Uri)
Which prints: https://accounts.spotify...redirect_uri=http%3A%2F%2Flocalhost%3A4200%2Fcreate&...&state=2018-04-30T14%3A04%3A39%2B02%3A00
I am currently replacing these substrings but is there a way to bypass this in the first place?
Hello!
Simply trying to retrieve the current playing song, feel like I am running into a wall with understanding the auth mechanisms here. Maybe it is that to get the currently playing song of my own account it is considered private data? and thus client credentials don't allow it?
package main
import (
"context"
"fmt"
"log"
"os"
"github.com/zmb3/spotify"
"golang.org/x/oauth2/clientcredentials"
)
func main() {
config := &clientcredentials.Config{
ClientID: os.Getenv("SPOTIFY_ID"),
ClientSecret: os.Getenv("SPOTIFY_SECRET"),
TokenURL: spotify.TokenURL,
Scopes: []string{spotify.ScopeUserReadCurrentlyPlaying},
}
token, err := config.Token(context.Background())
if err != nil {
log.Fatalf("unable to get token: %v", err)
}
client := spotify.Authenticator{}.NewClient(token)
song, err := client.PlayerCurrentlyPlaying()
if err != nil {
log.Fatalf("unable to get currently playing song: %v", err)
}
fmt.Println(song)
}
The error here is Invalid username
Any help would be appreciated.
Cheers!
Hi,
I'm playing with the player example but I have some issue sending request just after I logging or sending 2 commands
The error I got is sometimes
2017/10/07 12:18:21 oauth2: cannot fetch token: 400 Bad Request
Response: {"error":"invalid_grant","error_description":"Authorization code expired"}
or
2017/10/07 12:21:51 oauth2: cannot fetch token: 400 Bad Request Response: {"error":"invalid_grant","error_description":"Invalid authorization code"}
Is there an issue with oauth2 lib ?
Up until recently it worked fine, but now some calls return the following error:
spotify: HTTP 204: No Content (body empty)
Which is not really an error if you ask me ;)
Ive identified at least these functions to do this:
p.client.PlayOpt(&spotify.PlayOptions{
URIs: []spotify.URI{URI},
})
p.client.Repeat("off")
p.client.Shuffle(false)
But there might be more?
I have an application that consists of two components: a persistent server that takes care of authenticating with Spotify (it stores creds and refreshes them after authenticating once), and a CLI that gets existing creds from this auth server and uses that token to make Spotify API calls. This lets me control Spotify from the command line without re-authenticating frequently. Currently the CLI portion of the app is written in Ruby while the server is in Go. I'm translating the CLI to Go right now and was hoping to use this library. However, the implementation of the Client
struct here won't let me bypass this library's auth mechanism. I believe I could use this library if the Client.http
field was public โ I would create my own client with an http.RoundTripper
that simply adds the authorization field.
Any chance these fields could be exposed?
The day is here https://developer.spotify.com/community/news/2018/06/12/changes-to-playlist-uris/
This client is really hard to use now if you need to work with playlists without the user part. (eg spotify:playlist:37i9dQZF1DZ06evO3OC4Te
).
Can we make a communal effort to add handlers for Playlists operations only using the ID part?
Hello,
While trying to receive a token, to make subsequent requests, I get the following error :
2019/01/13 18:33:09 couldn't get token: Post https://accounts.spotify.com/api/token: x509: certificate signed by unknown authority
This of course implies that the certificate, that is offered, is signed by a (to my computer) unknown authority.
However, this did work sometime in November last year. So spotify changed something up I'm guessing.
Would you have an Idea how to get this working, besides authorizing the certificate?
The following code was used:
config := &clientcredentials.Config{
ClientID: os.Getenv("SPOTIFY_ID"),
ClientSecret: os.Getenv("SPOTIFY_SECRET"),
TokenURL: spotify.TokenURL,
}
token, err := config.Token(context.Background())
if err != nil {
log.Fatalf("couldn't get token: %v", err)
}
client := spotify.Authenticator{}.NewClient(token)
Code:
results, err := client.NewReleases()
if err != nil {
log.Fatal(err)
}
spew.Dump(results)
The result is an empty SimpleAlbumPage struct and there is no raised error:
(*spotify.SimpleAlbumPage)(0xc04222f320)({
basePage: (spotify.basePage) {
Endpoint: (string) "",
Limit: (int) 0,
Offset: (int) 0,
Total: (int) 0,
Next: (string) "",
Previous: (string) ""
},
Albums: ([]spotify.SimpleAlbum) <nil>
})
Other functions that need authentication work as expected with my client
.
Hello,
I'm actually using gin, and i can't access to the http.Request object
Is it possible to add a function where i can retrieve the token without using http.request
regards,
Is there a way to save the oauth credentials to the filesystem, so they can be used on a subsequent run?
I'm assigning a redirect-URI like:
redirectUrl := "http://urlecho.appspot.com/echo?debugMode=1"
auth := spotify.NewAuthenticator(redirectUrl, spotify.ScopeUserReadPrivate)
..but the produced authorization URL looks like:
https://accounts.spotify.com/authorize?client_id=CLIENTID&redirect_uri=http%3A%2F%2Furlecho.appspot.com%2Fecho&response_type=code&scope=user-read-private&state=arbitrary-state-data
When I add the argument to the URL directly, Spotify accepts it (though I have to make sure to white-list the whole thing, including the query portion) and then redirects to it. So, it is definitely supported.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.