137 lines
3.1 KiB
Go
137 lines
3.1 KiB
Go
|
package morningalarm
|
||
|
|
||
|
import (
|
||
|
"context"
|
||
|
"encoding/json"
|
||
|
"fmt"
|
||
|
"math/rand"
|
||
|
"net/http"
|
||
|
"os"
|
||
|
|
||
|
"github.com/gin-gonic/gin"
|
||
|
"github.com/zmb3/spotify/v2"
|
||
|
spotifyauth "github.com/zmb3/spotify/v2/auth"
|
||
|
"golang.org/x/oauth2"
|
||
|
)
|
||
|
|
||
|
const redirectURI = "/api/spotifycb"
|
||
|
|
||
|
func (ma *MorningAlarm) setupSpotify() error {
|
||
|
auth := spotifyauth.New(
|
||
|
spotifyauth.WithRedirectURL(ma.config.RedirectURL+redirectURI),
|
||
|
spotifyauth.WithClientID(ma.config.SpotifyClientID),
|
||
|
spotifyauth.WithClientSecret(ma.config.SpotifyClientSecret),
|
||
|
spotifyauth.WithScopes(
|
||
|
spotifyauth.ScopeUserReadPrivate,
|
||
|
spotifyauth.ScopeUserModifyPlaybackState,
|
||
|
spotifyauth.ScopeStreaming,
|
||
|
spotifyauth.ScopeUserReadPlaybackState,
|
||
|
),
|
||
|
)
|
||
|
|
||
|
loadedTokenJSON, err := os.ReadFile("spotifyToken.json")
|
||
|
|
||
|
if err == nil {
|
||
|
fmt.Println("Found access token in file")
|
||
|
|
||
|
var token oauth2.Token
|
||
|
err = json.Unmarshal(loadedTokenJSON, &token)
|
||
|
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
ma.sp = spotify.New(auth.Client(context.Background(), &token), spotify.WithRetry(true))
|
||
|
|
||
|
newToken, err := ma.sp.Token()
|
||
|
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
tokenJSON, err := json.Marshal(newToken)
|
||
|
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
os.WriteFile("spotifyToken.json", tokenJSON, os.ModePerm)
|
||
|
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
state := "abc123"
|
||
|
|
||
|
ma.ro.GET(redirectURI, func(c *gin.Context) {
|
||
|
token, err := auth.Token(c, state, c.Request)
|
||
|
|
||
|
if err != nil {
|
||
|
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||
|
return
|
||
|
}
|
||
|
|
||
|
tokenJSON, err := json.Marshal(token)
|
||
|
os.WriteFile("spotifyToken.json", tokenJSON, os.ModePerm)
|
||
|
|
||
|
ma.sp = spotify.New(auth.Client(c, token))
|
||
|
})
|
||
|
|
||
|
url := auth.AuthURL(state)
|
||
|
|
||
|
fmt.Println("Please log in to Spotify by visiting the following page in your browser:", url)
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
// playWakeUpMusic plays the playlist specified in the config at the specified device.
|
||
|
// Returns true if the playback was started successfully.
|
||
|
// Returns error if any error occurred.
|
||
|
// Can still return an error even if the playback was started successfully.
|
||
|
func (ma *MorningAlarm) playWakeUpMusic() (bool, error) {
|
||
|
playContextURI := spotify.URI("spotify:playlist:" + ma.config.PlaylistID)
|
||
|
deviceID := spotify.ID(ma.config.DeviceID)
|
||
|
|
||
|
playlist, err := ma.sp.GetPlaylistItems(context.Background(), spotify.ID(ma.config.PlaylistID))
|
||
|
|
||
|
if err != nil {
|
||
|
return true, err
|
||
|
}
|
||
|
|
||
|
randomTrackIndex := rand.Intn(playlist.Total)
|
||
|
|
||
|
err = ma.sp.PlayOpt(context.Background(), &spotify.PlayOptions{
|
||
|
PlaybackContext: &playContextURI,
|
||
|
DeviceID: &deviceID,
|
||
|
PlaybackOffset: &spotify.PlaybackOffset{Position: randomTrackIndex},
|
||
|
})
|
||
|
|
||
|
if err != nil {
|
||
|
return true, err
|
||
|
}
|
||
|
|
||
|
err = ma.sp.ShuffleOpt(context.Background(), true, &spotify.PlayOptions{
|
||
|
DeviceID: &deviceID,
|
||
|
})
|
||
|
|
||
|
return true, err
|
||
|
}
|
||
|
|
||
|
func (ma *MorningAlarm) getAvailableDevices() ([]Device, error) {
|
||
|
devices, err := ma.sp.PlayerDevices(context.Background())
|
||
|
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
var availableDevices []Device
|
||
|
for _, device := range devices {
|
||
|
if !device.Restricted {
|
||
|
availableDevices = append(availableDevices, Device{
|
||
|
ID: string(device.ID),
|
||
|
Name: device.Name,
|
||
|
})
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return availableDevices, nil
|
||
|
}
|