radio from playlist and saved tracks
This commit is contained in:
parent
d92095d8db
commit
5d98ae43fd
@ -89,11 +89,29 @@ func QueueSong(ctx *gctx.Context, client *spotify.Client, id spotify.ID) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func PlaySongInPlaylist(ctx *gctx.Context, client *spotify.Client, context *spotify.URI, offset int) error {
|
func PlaySongInPlaylist(ctx *gctx.Context, client *spotify.Client, context *spotify.URI, offset int) error {
|
||||||
err := client.PlayOpt(ctx, &spotify.PlayOptions{
|
e := client.PlayOpt(ctx, &spotify.PlayOptions{
|
||||||
PlaybackOffset: &spotify.PlaybackOffset{Position: offset},
|
PlaybackOffset: &spotify.PlaybackOffset{Position: offset},
|
||||||
PlaybackContext: context,
|
PlaybackContext: context,
|
||||||
})
|
})
|
||||||
return err
|
if e != nil {
|
||||||
|
if isNoActiveError(e) {
|
||||||
|
err := activateDevice(ctx, client)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = client.PlayOpt(ctx, &spotify.PlayOptions{
|
||||||
|
PlaybackOffset: &spotify.PlaybackOffset{Position: offset},
|
||||||
|
PlaybackContext: context,
|
||||||
|
})
|
||||||
|
err = client.Play(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func PlayLikedSongs(ctx *gctx.Context, client *spotify.Client, position int) error {
|
func PlayLikedSongs(ctx *gctx.Context, client *spotify.Client, position int) error {
|
||||||
@ -420,7 +438,6 @@ func Repeat(ctx *gctx.Context, client *spotify.Client) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("Failed to get current playstate")
|
return fmt.Errorf("Failed to get current playstate")
|
||||||
}
|
}
|
||||||
fmt.Println(state.RepeatState)
|
|
||||||
newState := "off"
|
newState := "off"
|
||||||
if state.RepeatState == "off" {
|
if state.RepeatState == "off" {
|
||||||
newState = "context"
|
newState = "context"
|
||||||
@ -496,15 +513,124 @@ func isNoActiveError(err error) bool {
|
|||||||
return strings.Contains(err.Error(), "No active device found")
|
return strings.Contains(err.Error(), "No active device found")
|
||||||
}
|
}
|
||||||
|
|
||||||
func activateDevice(ctx *gctx.Context, client *spotify.Client) error {
|
func RadioFromPlaylist(ctx *gctx.Context, client *spotify.Client, playlist spotify.SimplePlaylist) error {
|
||||||
to_play := true
|
rand.Seed(time.Now().Unix())
|
||||||
current, err := client.PlayerCurrentlyPlaying(ctx)
|
total := playlist.Tracks.Total
|
||||||
|
if total == 0 {
|
||||||
|
return fmt.Errorf("This playlist is empty")
|
||||||
|
}
|
||||||
|
pages := (total / 50)
|
||||||
|
randomPage := 0
|
||||||
|
if pages != 0 {
|
||||||
|
randomPage = rand.Intn(int(pages))
|
||||||
|
}
|
||||||
|
playlistPage, err := client.GetPlaylistItems(ctx, playlist.ID, spotify.Limit(50), spotify.Offset(randomPage*50))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if current.Item == nil || !current.Playing {
|
pageSongs := playlistPage.Items
|
||||||
to_play = false
|
rand.Shuffle(len(pageSongs), func(i, j int) { pageSongs[i], pageSongs[j] = pageSongs[j], pageSongs[i] })
|
||||||
|
seedCount := 5
|
||||||
|
if len(pageSongs) < seedCount {
|
||||||
|
seedCount = len(pageSongs)
|
||||||
}
|
}
|
||||||
|
seedIds := []spotify.ID{}
|
||||||
|
for idx, song := range pageSongs {
|
||||||
|
if idx >= seedCount {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
seedIds = append(seedIds, song.Track.Track.ID)
|
||||||
|
}
|
||||||
|
return RadioGivenList(ctx, client, seedIds[:seedCount])
|
||||||
|
}
|
||||||
|
|
||||||
|
func RadioFromSavedTracks(ctx *gctx.Context, client *spotify.Client) error {
|
||||||
|
rand.Seed(time.Now().Unix())
|
||||||
|
savedSongs, err := client.CurrentUsersTracks(ctx, spotify.Limit(50), spotify.Offset(0))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if savedSongs.Total == 0 {
|
||||||
|
return fmt.Errorf("You have no saved songs")
|
||||||
|
}
|
||||||
|
pages := (savedSongs.Total / 50)
|
||||||
|
randomPage := rand.Intn(int(pages))
|
||||||
|
trackPage, err := client.CurrentUsersTracks(ctx, spotify.Limit(50), spotify.Offset(randomPage*50))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
pageSongs := trackPage.Tracks
|
||||||
|
rand.Shuffle(len(pageSongs), func(i, j int) { pageSongs[i], pageSongs[j] = pageSongs[j], pageSongs[i] })
|
||||||
|
seedCount := 4
|
||||||
|
seedIds := []spotify.ID{}
|
||||||
|
for idx, song := range pageSongs {
|
||||||
|
if idx >= seedCount {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
seedIds = append(seedIds, song.ID)
|
||||||
|
}
|
||||||
|
seedIds = append(seedIds, savedSongs.Tracks[0].ID)
|
||||||
|
return RadioGivenList(ctx, client, seedIds)
|
||||||
|
}
|
||||||
|
|
||||||
|
func RadioGivenList(ctx *gctx.Context, client *spotify.Client, song_ids []spotify.ID) error {
|
||||||
|
seed := spotify.Seeds{
|
||||||
|
Tracks: song_ids,
|
||||||
|
}
|
||||||
|
recomendations, err := client.GetRecommendations(ctx, seed, &spotify.TrackAttributes{}, spotify.Limit(99))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
recomendationIds := []spotify.ID{}
|
||||||
|
for _, song := range recomendations.Tracks {
|
||||||
|
recomendationIds = append(recomendationIds, song.ID)
|
||||||
|
}
|
||||||
|
err = ClearRadio(ctx, client)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
radioPlaylist, err := GetRadioPlaylist(ctx, client)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
queue := []spotify.ID{song_ids[0]}
|
||||||
|
queue = append(queue, recomendationIds...)
|
||||||
|
_, err = client.AddTracksToPlaylist(ctx, radioPlaylist.ID, queue...)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
client.PlayOpt(ctx, &spotify.PlayOptions{
|
||||||
|
PlaybackContext: &radioPlaylist.URI,
|
||||||
|
PlaybackOffset: &spotify.PlaybackOffset{
|
||||||
|
Position: 0,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
err = client.Repeat(ctx, "context")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for i := 0; i < 4; i++ {
|
||||||
|
id := rand.Intn(len(recomendationIds)-2) + 1
|
||||||
|
seed := spotify.Seeds{
|
||||||
|
Tracks: []spotify.ID{recomendationIds[id]},
|
||||||
|
}
|
||||||
|
additional_recs, err := client.GetRecommendations(ctx, seed, &spotify.TrackAttributes{}, spotify.Limit(100))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
additionalRecsIds := []spotify.ID{}
|
||||||
|
for _, song := range additional_recs.Tracks {
|
||||||
|
additionalRecsIds = append(additionalRecsIds, song.ID)
|
||||||
|
}
|
||||||
|
_, err = client.AddTracksToPlaylist(ctx, radioPlaylist.ID, additionalRecsIds...)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func activateDevice(ctx *gctx.Context, client *spotify.Client) error {
|
||||||
configDir, _ := os.UserConfigDir()
|
configDir, _ := os.UserConfigDir()
|
||||||
if _, err := os.Stat(filepath.Join(configDir, "gospt/device.json")); err == nil {
|
if _, err := os.Stat(filepath.Join(configDir, "gospt/device.json")); err == nil {
|
||||||
deviceFile, err := os.Open(filepath.Join(configDir, "gospt/device.json"))
|
deviceFile, err := os.Open(filepath.Join(configDir, "gospt/device.json"))
|
||||||
@ -521,7 +647,7 @@ func activateDevice(ctx *gctx.Context, client *spotify.Client) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = client.TransferPlayback(ctx, device.ID, to_play)
|
err = client.TransferPlayback(ctx, device.ID, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,6 @@ package tui
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"gospt/internal/commands"
|
"gospt/internal/commands"
|
||||||
@ -59,7 +58,9 @@ func (m *mainModel) Tick() {
|
|||||||
select {
|
select {
|
||||||
case <-ticker.C:
|
case <-ticker.C:
|
||||||
playing, _ := m.client.PlayerCurrentlyPlaying(m.ctx)
|
playing, _ := m.client.PlayerCurrentlyPlaying(m.ctx)
|
||||||
currentlyPlaying = "Now playing " + playing.Item.Name + " by " + playing.Item.Artists[0].Name
|
if playing.Playing {
|
||||||
|
currentlyPlaying = "Now playing " + playing.Item.Name + " by " + playing.Item.Artists[0].Name
|
||||||
|
}
|
||||||
case <-quit:
|
case <-quit:
|
||||||
ticker.Stop()
|
ticker.Stop()
|
||||||
return
|
return
|
||||||
@ -72,16 +73,29 @@ func HandlePlay(ctx *gctx.Context, client *spotify.Client, uri *spotify.URI, pos
|
|||||||
var err error
|
var err error
|
||||||
err = commands.PlaySongInPlaylist(ctx, client, uri, pos)
|
err = commands.PlaySongInPlaylist(ctx, client, uri, pos)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println()
|
return
|
||||||
os.Exit(1)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func HandleRadio(ctx *gctx.Context, client *spotify.Client, id spotify.ID) {
|
func HandleRadio(ctx *gctx.Context, client *spotify.Client, id spotify.ID) {
|
||||||
err := commands.RadioGivenSong(ctx, client, id, 0)
|
err := commands.RadioGivenSong(ctx, client, id, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
return
|
||||||
os.Exit(1)
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func HandlePlaylistRadio(ctx *gctx.Context, client *spotify.Client, playlist spotify.SimplePlaylist) {
|
||||||
|
err := commands.RadioFromPlaylist(ctx, client, playlist)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func HandleLibraryRadio(ctx *gctx.Context, client *spotify.Client) {
|
||||||
|
err := commands.RadioFromSavedTracks(ctx, client)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err.Error())
|
||||||
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -156,7 +170,7 @@ func HandlePlayLikedSong(ctx *gctx.Context, client *spotify.Client, position int
|
|||||||
err := commands.PlayLikedSongs(ctx, client, position)
|
err := commands.PlayLikedSongs(ctx, client, position)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err.Error())
|
fmt.Println(err.Error())
|
||||||
os.Exit(1)
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -180,7 +194,7 @@ func (m mainModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|||||||
new_items, err := DeviceView(m.ctx, m.client)
|
new_items, err := DeviceView(m.ctx, m.client)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err.Error())
|
fmt.Println(err.Error())
|
||||||
os.Exit(1)
|
return m, tea.Quit
|
||||||
}
|
}
|
||||||
m.list.SetItems(new_items)
|
m.list.SetItems(new_items)
|
||||||
m.list.ResetSelected()
|
m.list.ResetSelected()
|
||||||
@ -215,7 +229,7 @@ func (m mainModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|||||||
new_items, err := PlaylistView(m.ctx, m.client, playlist)
|
new_items, err := PlaylistView(m.ctx, m.client, playlist)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err.Error())
|
fmt.Println(err.Error())
|
||||||
os.Exit(1)
|
return m, tea.Quit
|
||||||
}
|
}
|
||||||
m.list.SetItems(new_items)
|
m.list.SetItems(new_items)
|
||||||
m.list.ResetSelected()
|
m.list.ResetSelected()
|
||||||
@ -225,7 +239,7 @@ func (m mainModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|||||||
new_items, err := SavedTracksView(m.ctx, m.client)
|
new_items, err := SavedTracksView(m.ctx, m.client)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err.Error())
|
fmt.Println(err.Error())
|
||||||
os.Exit(1)
|
return m, tea.Quit
|
||||||
}
|
}
|
||||||
m.list.SetItems(new_items)
|
m.list.SetItems(new_items)
|
||||||
m.list.ResetSelected()
|
m.list.ResetSelected()
|
||||||
@ -256,9 +270,13 @@ func (m mainModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|||||||
case "main":
|
case "main":
|
||||||
switch m.list.SelectedItem().(mainItem).SpotifyItem.(type) {
|
switch m.list.SelectedItem().(mainItem).SpotifyItem.(type) {
|
||||||
case spotify.SimplePlaylist:
|
case spotify.SimplePlaylist:
|
||||||
m.list.NewStatusMessage("Not implemented yet")
|
currentlyPlaying = m.list.SelectedItem().FilterValue()
|
||||||
|
m.list.NewStatusMessage("Starting radio for " + currentlyPlaying)
|
||||||
|
go HandlePlaylistRadio(m.ctx, m.client, m.list.SelectedItem().(mainItem).SpotifyItem.(spotify.SimplePlaylist))
|
||||||
case *spotify.SavedTrackPage:
|
case *spotify.SavedTrackPage:
|
||||||
m.list.NewStatusMessage("Not implemented yet")
|
currentlyPlaying = m.list.SelectedItem().FilterValue()
|
||||||
|
m.list.NewStatusMessage("Starting radio for " + currentlyPlaying)
|
||||||
|
go HandleLibraryRadio(m.ctx, m.client)
|
||||||
}
|
}
|
||||||
case "playlist":
|
case "playlist":
|
||||||
currentlyPlaying = m.list.SelectedItem().FilterValue()
|
currentlyPlaying = m.list.SelectedItem().FilterValue()
|
||||||
@ -323,7 +341,7 @@ func DisplayMain(ctx *gctx.Context, client *spotify.Client) error {
|
|||||||
|
|
||||||
if _, err := p.Run(); err != nil {
|
if _, err := p.Run(); err != nil {
|
||||||
fmt.Println("Error running program:", err)
|
fmt.Println("Error running program:", err)
|
||||||
os.Exit(1)
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -446,6 +464,6 @@ func HandleSetDevice(ctx *gctx.Context, client *spotify.Client, player spotify.P
|
|||||||
err = commands.SetDevice(ctx, client, player)
|
err = commands.SetDevice(ctx, client, player)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err.Error())
|
fmt.Println(err.Error())
|
||||||
os.Exit(1)
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user