Skip to content

Commit

Permalink
Merge pull request #170 from lemorage/update/spotify-2.4.0
Browse files Browse the repository at this point in the history
  • Loading branch information
dvdmuckle authored Oct 23, 2023
2 parents 94852cc + 618b38f commit c017d42
Show file tree
Hide file tree
Showing 14 changed files with 214 additions and 154 deletions.
62 changes: 44 additions & 18 deletions cmd/helper/authHelp.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
Expand All @@ -16,6 +16,7 @@ limitations under the License.
package helper

import (
"context"
"encoding/json"
"fmt"
"io/ioutil"
Expand All @@ -28,22 +29,38 @@ import (

"github.com/spf13/cobra"
"github.com/zalando/go-keyring"
"github.com/zmb3/spotify"
"github.com/zmb3/spotify/v2"
"github.com/zmb3/spotify/v2/auth"
"golang.org/x/oauth2"
)

const redirectURI = "http://localhost:8888/callback"

var (
authenticator = spotify.NewAuthenticator(redirectURI, spotify.ScopeStreaming, spotify.ScopeUserModifyPlaybackState, spotify.ScopeUserReadPlaybackState, spotify.ScopePlaylistModifyPrivate, spotify.ScopePlaylistModifyPublic)
ch = make(chan *spotify.Client)
clientID string
secret string
state = "ringdingthing"
authenticator *spotifyauth.Authenticator
ch = make(chan *spotify.Client)
clientID string
secret string
state = "ringdingthing"
)

func initAuthenticator(clientID string, secret string) {
authenticator = spotifyauth.New(
spotifyauth.WithRedirectURL(redirectURI),
spotifyauth.WithClientID(clientID),
spotifyauth.WithClientSecret(secret),
spotifyauth.WithScopes(
spotifyauth.ScopeStreaming,
spotifyauth.ScopeUserModifyPlaybackState,
spotifyauth.ScopeUserReadPlaybackState,
spotifyauth.ScopePlaylistModifyPrivate,
spotifyauth.ScopePlaylistModifyPublic,
),
)
}

func completeAuth(w http.ResponseWriter, r *http.Request) {
tok, err := authenticator.Token(state, r)
tok, err := authenticator.Token(r.Context(), state, r)
if err != nil {
http.Error(w, "Couldn't get token", http.StatusForbidden)
LogErrorAndExit(err)
Expand All @@ -53,15 +70,16 @@ func completeAuth(w http.ResponseWriter, r *http.Request) {
LogErrorAndExit(fmt.Sprintf("State mismatch: %s != %s\n", st, state))
}
// use the token to get an authenticated client
client := authenticator.NewClient(tok)
client := spotify.New(authenticator.Client(r.Context(), tok))
fmt.Fprintf(w, "Login Completed!")
ch <- &client
ch <- client
}

//Auth authenticates with Spotify and refreshes the token
// Auth authenticates with Spotify and refreshes the token
func Auth(cmd *cobra.Command, cfgFile string, conf *Config) {
clientID = conf.ClientID
secret = conf.Secret
initAuthenticator(clientID, secret)
curUser, err := user.Current()
if err != nil {
LogErrorAndExit(err)
Expand Down Expand Up @@ -91,15 +109,18 @@ func Auth(cmd *cobra.Command, cfgFile string, conf *Config) {
}
} else {
fmt.Println("Getting token...")
authenticator.SetAuthInfo(clientID, secret)
http.HandleFunc("/callback", completeAuth)
go http.ListenAndServe(":8888", nil)
url := authenticator.AuthURL(state)
fmt.Println("Please log in to Spotify by clicking the following link, or copying it to a web browser:", url)
//wait for auth to finish
client := <-ch
if client == nil {
fmt.Println("Client is not initialized")
os.Exit(1)
}

user, err := client.CurrentUser()
user, err := client.CurrentUser(context.Background())
if err != nil {
LogErrorAndExit(err)
}
Expand All @@ -119,13 +140,13 @@ func Auth(cmd *cobra.Command, cfgFile string, conf *Config) {
}
}

//RefreshToken refreshes the auth token from Spotify
// RefreshToken refreshes the auth token from Spotify
func RefreshToken(client string, secret string, refreshToken string) *oauth2.Token {
var token *oauth2.Token = &oauth2.Token{}

if refreshToken != "" {
const grantType string = "refresh_token"
const tokenURL string = spotify.TokenURL
const tokenURL string = spotifyauth.TokenURL
const contentType string = "application/x-www-form-urlencoded"
form := url.Values{}
form.Add("grant_type", grantType)
Expand Down Expand Up @@ -153,8 +174,8 @@ func RefreshToken(client string, secret string, refreshToken string) *oauth2.Tok
return nil
}

//SetClient sets the Client field of Config struct to a valid Spotify client
//The Token field in the Config struct must be set
// SetClient sets the Client field of Config struct to a valid Spotify client
// The Token field in the Config struct must be set
func SetClient(conf *Config) {
curUser, err := user.Current()
if err != nil {
Expand Down Expand Up @@ -187,5 +208,10 @@ func SetClient(conf *Config) {
LogErrorAndExit("Error saving token to keyring", err)
}
}
conf.Client = spotify.NewAuthenticator(redirectURI).NewClient(&conf.Token)
httpClient := spotifyauth.New().Client(context.Background(), &conf.Token)
conf.Client = spotify.New(httpClient)
if conf.Client == nil {
fmt.Println("Client is not initialized")
os.Exit(1)
}
}
14 changes: 8 additions & 6 deletions cmd/helper/playback.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
Expand All @@ -16,23 +16,25 @@ limitations under the License.
package helper

import (
"github.com/zmb3/spotify"
"context"

"github.com/zmb3/spotify/v2"
)

//Pause wraps the spotify.Client.Pause() method for easy error checking
// Pause wraps the spotify.Client.Pause() method for easy error checking
func Pause(conf *Config) {
var opts spotify.PlayOptions
opts.DeviceID = &conf.DeviceID
if err := conf.Client.PauseOpt(&opts); err != nil {
if err := conf.Client.PauseOpt(context.Background(), &opts); err != nil {
LogErrorAndExit(err)
}
}

//Play wraps the spotify.Client.Play() method for easy error checking
// Play wraps the spotify.Client.Play() method for easy error checking
func Play(conf *Config) {
var opts spotify.PlayOptions
opts.DeviceID = &conf.DeviceID
if err := conf.Client.PlayOpt(&opts); err != nil {
if err := conf.Client.PlayOpt(context.Background(), &opts); err != nil {
LogErrorAndExit(err)
}
}
8 changes: 4 additions & 4 deletions cmd/helper/structs.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
Expand All @@ -16,15 +16,15 @@ limitations under the License.
package helper

import (
"github.com/zmb3/spotify"
"github.com/zmb3/spotify/v2"
"golang.org/x/oauth2"
)

//Config stores constantly accessed variables in memory
// Config stores constantly accessed variables in memory
type Config struct {
ClientID string
Secret string
Token oauth2.Token
Client spotify.Client
Client *spotify.Client
DeviceID spotify.ID
}
8 changes: 5 additions & 3 deletions cmd/next.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
Expand All @@ -16,9 +16,11 @@ limitations under the License.
package cmd

import (
"context"

"github.com/dvdmuckle/spc/cmd/helper"
"github.com/spf13/cobra"
"github.com/zmb3/spotify"
"github.com/zmb3/spotify/v2"
)

// nextCmd represents the next command
Expand All @@ -28,7 +30,7 @@ var nextCmd = &cobra.Command{
Long: `Skips the track currently playing. Will use the currently configured device.`,
Run: func(cmd *cobra.Command, args []string) {
helper.SetClient(&conf)
conf.Client.NextOpt(&spotify.PlayOptions{DeviceID: &conf.DeviceID})
conf.Client.NextOpt(context.Background(), &spotify.PlayOptions{DeviceID: &conf.DeviceID})
},
Aliases: []string{"skip"},
}
Expand Down
13 changes: 9 additions & 4 deletions cmd/previous.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
Expand All @@ -16,9 +16,11 @@ limitations under the License.
package cmd

import (
"context"

"github.com/dvdmuckle/spc/cmd/helper"
"github.com/spf13/cobra"
"github.com/zmb3/spotify"
"github.com/zmb3/spotify/v2"
)

// previousCmd represents the previous command
Expand All @@ -30,13 +32,16 @@ var previousCmd = &cobra.Command{
var opts spotify.PlayOptions
helper.SetClient(&conf)
opts.DeviceID = &conf.DeviceID

ctx := context.Background()

//We want to go to the last song playing, but
//spotify.Previous() will rewind the current song
//unless the current song is close to the beginning
//of playback, so we seek to zero here before calling
//spotify.Previous()
conf.Client.SeekOpt(0, &opts)
conf.Client.PreviousOpt(&opts)
conf.Client.SeekOpt(ctx, 0, &opts)
conf.Client.PreviousOpt(ctx, &opts)
},
Aliases: []string{"prev"},
}
Expand Down
4 changes: 2 additions & 2 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
Expand All @@ -23,7 +23,7 @@ import (
"strings"

"github.com/dvdmuckle/spc/cmd/helper"
"github.com/zmb3/spotify"
"github.com/zmb3/spotify/v2"

"github.com/spf13/cobra"

Expand Down
26 changes: 18 additions & 8 deletions cmd/saveWeekly.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
Expand All @@ -16,12 +16,14 @@ limitations under the License.
package cmd

import (
"context"
"fmt"
"os"
"time"

"github.com/dvdmuckle/spc/cmd/helper"
"github.com/spf13/cobra"
"github.com/zmb3/spotify"
"github.com/zmb3/spotify/v2"
)

// saveWeeklyCmd represents the saveWeekly command
Expand All @@ -39,19 +41,22 @@ only save the current playlist`,
playlistName = "Discover Weekly " + getPlaylistDate()
}
isPublic, _ := cmd.Flags().GetBool("public")
currentUser, err := conf.Client.CurrentUser()
isCollaborative, _ := cmd.Flags().GetBool("collaborative")

ctx := context.Background()
currentUser, err := conf.Client.CurrentUser(ctx)
if err != nil {
helper.LogErrorAndExit(err)
}
if deduplicatePlaylist(playlistName, currentUser.User.ID) {
fmt.Println("Discover Weekly already saved")
return
}
newPlaylist, err := conf.Client.CreatePlaylistForUser(currentUser.User.ID, playlistName, playlistDescription, isPublic)
newPlaylist, err := conf.Client.CreatePlaylistForUser(ctx, currentUser.User.ID, playlistName, playlistDescription, isPublic, isCollaborative)
if err != nil {
helper.LogErrorAndExit(err)
}
searchResult, err := conf.Client.Search("Discover Weekly", spotify.SearchTypePlaylist)
searchResult, err := conf.Client.Search(ctx, "Discover Weekly", spotify.SearchTypePlaylist)
if err != nil {
helper.LogErrorAndExit(err)
}
Expand All @@ -63,7 +68,7 @@ only save the current playlist`,
}
}
discoverPlaylistTracks := func() spotify.PlaylistTrackPage {
playlistTracks, err := conf.Client.GetPlaylistTracks(discoverPlaylist)
playlistTracks, err := conf.Client.GetPlaylistTracks(ctx, discoverPlaylist)
if err != nil {
helper.LogErrorAndExit(err)
}
Expand All @@ -73,7 +78,7 @@ only save the current playlist`,
for _, track := range discoverPlaylistTracks().Tracks {
discoverPlaylistTrackIDs = append(discoverPlaylistTrackIDs, track.Track.ID)
}
conf.Client.AddTracksToPlaylist(newPlaylist.ID, discoverPlaylistTrackIDs...)
conf.Client.AddTracksToPlaylist(ctx, newPlaylist.ID, discoverPlaylistTrackIDs...)
fmt.Printf("Discover Weekly saved as %s\n", playlistName)
},
}
Expand All @@ -86,7 +91,11 @@ func getPlaylistDate() string {
return fmt.Sprintf("%d/%d/%d", date.Month(), date.Day(), date.Year())
}
func deduplicatePlaylist(playlistName string, user string) bool {
searchResults, err := conf.Client.Search(playlistName, spotify.SearchTypePlaylist)
if conf.Client == nil {
fmt.Println("Client is not initialized")
os.Exit(1)
}
searchResults, err := conf.Client.Search(context.Background(), playlistName, spotify.SearchTypePlaylist)
if err != nil {
helper.LogErrorAndExit(err)
}
Expand All @@ -102,4 +111,5 @@ func init() {
rootCmd.AddCommand(saveWeeklyCmd)
saveWeeklyCmd.Flags().StringP("name", "n", "", "Custom name for the save playlist")
saveWeeklyCmd.Flags().BoolP("public", "p", false, "Whether to make the new playlist public")
saveWeeklyCmd.Flags().BoolP("collaborative", "c", false, "Set the playlist as collaborative")
}
Loading

0 comments on commit c017d42

Please sign in to comment.