diff --git a/README.md b/README.md index 053a88e..001dd55 100644 --- a/README.md +++ b/README.md @@ -107,6 +107,7 @@ $ gspt 1. `?` Search 1. `v` Toggle Visual Mode (Only works in some views) 1. `a` Add to Playlist (Only works in some views) +1. `q` Queue Songs or Contexts (Only works in some views) 1. `ctrl-p` Start playing the entry under the cursor in some views (PlaylistNavigator, Albums, etc.) 1. ` ` Toggle Playback (Space) 1. `o` Open the Current Track's Album diff --git a/config/key.go b/config/key.go index 4377684..069b02d 100644 --- a/config/key.go +++ b/config/key.go @@ -14,9 +14,11 @@ var ( "recently_played_view": { "normal": { {R: 'a'}: "add_to_playlist", + {R: 'q'}: "queue_entry", }, "visual": { {R: 'a'}: "add_to_playlist", + {R: 'q'}: "queue_entry", }, }, "search_view": { @@ -54,27 +56,33 @@ var ( "playlist_nav": { "normal": { {K: tcell.KeyCtrlP}: "play_entry", + {R: 'q'}: "queue_entry", }, }, "playlist_view": { "normal": { {R: 'a'}: "add_to_playlist", + {R: 'q'}: "queue_entry", }, "visual": { {R: 'a'}: "add_to_playlist", + {R: 'q'}: "queue_entry", }, }, "top_tracks_view": { "normal": { {K: tcell.KeyCtrlP}: "play_entry", + {R: 'q'}: "queue_entry", }, }, "liked_songs_view": { "normal": { {R: 'a'}: "add_to_playlist", + {R: 'q'}: "queue_entry", }, "visual": { {R: 'a'}: "add_to_playlist", + {R: 'q'}: "queue_entry", }, }, "artists_view": { @@ -96,9 +104,11 @@ var ( "album_view": { "normal": { {R: 'a'}: "add_to_playlist", + {R: 'q'}: "queue_entry", }, "visual": { {R: 'a'}: "add_to_playlist", + {R: 'q'}: "queue_entry", }, }, "nav_menu": {}, diff --git a/spt/add.go b/spt/add.go index 437a9d5..64a3039 100644 --- a/spt/add.go +++ b/spt/add.go @@ -8,15 +8,15 @@ import ( ) func AddTracksToPlaylist(playlistId spotify.ID, t ...spotify.ID) error { - _, err := Client.AddTracksToPlaylist(ctx(), playlistId, t...) + _, err := Client.AddTracksToPlaylist(ctx, playlistId, t...) return err } -func QueueTracks(ids ...spotify.SimpleTrack) error { +func QueueTracks(ids ...spotify.ID) error { count := 0 - _ctx := ctx() - for _, v := range ids { - if err := Client.QueueSong(_ctx, v.ID); err != nil { + _ctx := ctx + for _, id := range ids { + if err := Client.QueueSong(_ctx, id); err != nil { return errors.New(fmt.Sprintf("%s | Tracks Queued: %d", err.Error(), count)) } } @@ -32,7 +32,34 @@ func QueueAlbum(id spotify.ID) error { if err != nil { return err } - if err := QueueTracks(*album.Tracks...); err != nil { + + ids := []spotify.ID{} + for _, v := range *album.Tracks { + ids = append(ids, v.ID) + } + + if err := QueueTracks(ids...); err != nil { + return err + } + return nil +} + +func QueuePlaylist(id spotify.ID) error { + playlist, c := GetPlaylist(id) + if c == nil { + return (errors.New("hi!")) + } + err := <-c + if err != nil { + return err + } + + ids := []spotify.ID{} + for _, v := range *playlist.Tracks { + ids = append(ids, v.Track.ID) + } + + if err := QueueTracks(ids...); err != nil { return err } return nil diff --git a/spt/get.go b/spt/get.go index 9d42377..a9f8323 100644 --- a/spt/get.go +++ b/spt/get.go @@ -39,7 +39,7 @@ type Playable interface { } var ( - ctx = func() context.Context { return context.Background() } + ctx = context.Background() Client *spotify.Client playlistCache map[spotify.ID]*Playlist = make(map[spotify.ID]*Playlist) albumCache map[spotify.ID]*Album = make(map[spotify.ID]*Album) @@ -48,7 +48,7 @@ var ( func GetPlaylist(playlistId spotify.ID) (*Playlist, chan error) { c := make(chan error) - if fp, err := Client.GetPlaylist(ctx(), playlistId); err != nil { + if fp, err := Client.GetPlaylist(ctx, playlistId); err != nil { go func() { c <- err }() return nil, c } else { @@ -60,7 +60,7 @@ func GetPlaylist(playlistId spotify.ID) (*Playlist, chan error) { addTracks() go func() { for page := 1; ; page++ { - if perr := Client.NextPage(ctx(), &fp.Tracks); perr == spotify.ErrNoMorePages { + if perr := Client.NextPage(ctx, &fp.Tracks); perr == spotify.ErrNoMorePages { c <- nil break } else if perr != nil { @@ -86,7 +86,7 @@ func GetPlaylist(playlistId spotify.ID) (*Playlist, chan error) { func GetAlbum(albumID spotify.ID) (*Album, chan error) { c := make(chan error) if _, ok := albumCache[albumID]; !ok { - fa, err := Client.GetAlbum(ctx(), albumID) + fa, err := Client.GetAlbum(ctx, albumID) if err != nil { go func() { c <- err }() return nil, c @@ -98,7 +98,7 @@ func GetAlbum(albumID spotify.ID) (*Album, chan error) { addTracks() go func() { for page := 1; ; page++ { - if perr := Client.NextPage(ctx(), &fa.Tracks); perr == spotify.ErrNoMorePages { + if perr := Client.NextPage(ctx, &fa.Tracks); perr == spotify.ErrNoMorePages { c <- nil break } else if perr != nil { @@ -125,7 +125,7 @@ func CurrentUserSavedAlbums() (*SavedAlbums, chan error) { c := make(chan error) _a := make(SavedAlbums, 0) albums := &_a - if sp, err := Client.CurrentUsersAlbums(ctx()); err != nil { + if sp, err := Client.CurrentUsersAlbums(ctx); err != nil { go func() { c <- err }() return nil, c } else { @@ -135,7 +135,7 @@ func CurrentUserSavedAlbums() (*SavedAlbums, chan error) { addAlbums() go func() { for page := 1; ; page++ { - if perr := Client.NextPage(ctx(), sp); perr == spotify.ErrNoMorePages { + if perr := Client.NextPage(ctx, sp); perr == spotify.ErrNoMorePages { c <- nil break } else if perr != nil { @@ -153,7 +153,7 @@ func CurrentUserPlaylists() (*UserPlaylists, chan error) { c := make(chan error) _p := make(UserPlaylists, 0) playlists := &_p - if spp, err := Client.CurrentUsersPlaylists(ctx()); err != nil { + if spp, err := Client.CurrentUsersPlaylists(ctx); err != nil { go func() { c <- err }() return nil, c } else { @@ -163,7 +163,7 @@ func CurrentUserPlaylists() (*UserPlaylists, chan error) { addPlaylists() go func() { for page := 1; ; page++ { - if perr := Client.NextPage(ctx(), spp); perr == spotify.ErrNoMorePages { + if perr := Client.NextPage(ctx, spp); perr == spotify.ErrNoMorePages { c <- nil break } else if perr != nil { @@ -181,7 +181,7 @@ func CurrentUserSavedTracks() (*LikedSongs, chan error) { c := make(chan error) _p := make(LikedSongs, 0) playlists := &_p - if ls, err := Client.CurrentUsersTracks(ctx()); err != nil { + if ls, err := Client.CurrentUsersTracks(ctx); err != nil { go func() { c <- err }() return nil, c } else { @@ -191,7 +191,7 @@ func CurrentUserSavedTracks() (*LikedSongs, chan error) { addTracks() go func() { for page := 1; ; page++ { - if perr := Client.NextPage(ctx(), ls); perr == spotify.ErrNoMorePages { + if perr := Client.NextPage(ctx, ls); perr == spotify.ErrNoMorePages { c <- nil break } else if perr != nil { @@ -210,7 +210,7 @@ func CurrentUserFollowedArtists() (*FollowedArtists, chan error) { // TODO: Check if this is the proper implementation _a := make(FollowedArtists, 0) artists := &_a - if ar, err := Client.CurrentUsersFollowedArtists(ctx()); err != nil { + if ar, err := Client.CurrentUsersFollowedArtists(ctx); err != nil { go func() { c <- err }() return nil, c } else { @@ -225,7 +225,7 @@ func CurrentUserFollowedArtists() (*FollowedArtists, chan error) { if len(ar.Artists) == 0 { c <- nil } - if ar, err = Client.CurrentUsersFollowedArtists(ctx(), spotify.After(string(ap))); err != nil { + if ar, err = Client.CurrentUsersFollowedArtists(ctx, spotify.After(string(ap))); err != nil { if err == spotify.ErrNoMorePages { c <- nil break @@ -243,15 +243,15 @@ func CurrentUserFollowedArtists() (*FollowedArtists, chan error) { } func RecentlyPlayed() ([]spotify.RecentlyPlayedItem, error) { - return Client.PlayerRecentlyPlayedOpt(ctx(), &spotify.RecentlyPlayedOptions{Limit: 50}) + return Client.PlayerRecentlyPlayedOpt(ctx, &spotify.RecentlyPlayedOptions{Limit: 50}) } func GetPlayerState() (*spotify.PlayerState, error) { - return Client.PlayerState(ctx()) + return Client.PlayerState(ctx) } func GetTopTracks() ([]spotify.FullTrack, error) { - c, err := Client.CurrentUsersTopTracks(ctx(), spotify.Limit(topTracksLimit)) + c, err := Client.CurrentUsersTopTracks(ctx, spotify.Limit(topTracksLimit)) if c != nil { return c.Tracks, err } else { @@ -260,7 +260,7 @@ func GetTopTracks() ([]spotify.FullTrack, error) { } func GetTopArtists() ([]spotify.FullArtist, error) { - c, err := Client.CurrentUsersTopArtists(ctx(), spotify.Limit(topTracksLimit)) + c, err := Client.CurrentUsersTopArtists(ctx, spotify.Limit(topTracksLimit)) if c != nil { return c.Artists, err } else { @@ -269,15 +269,15 @@ func GetTopArtists() ([]spotify.FullArtist, error) { } func GetArtistTopTracks(artistID spotify.ID) ([]spotify.FullTrack, error) { - c, err := Client.CurrentUser(ctx()) + c, err := Client.CurrentUser(ctx) if err != nil { return []spotify.FullTrack{}, err } - return Client.GetArtistsTopTracks(ctx(), artistID, c.Country) + return Client.GetArtistsTopTracks(ctx, artistID, c.Country) } func GetArtistAlbums(artistID spotify.ID) ([]spotify.SimpleAlbum, error) { - c, err := Client.GetArtistAlbums(ctx(), artistID, albumtypes) + c, err := Client.GetArtistAlbums(ctx, artistID, albumtypes) if err != nil { return []spotify.SimpleAlbum{}, err } @@ -285,7 +285,7 @@ func GetArtistAlbums(artistID spotify.ID) ([]spotify.SimpleAlbum, error) { } func Search(s string) (*spotify.SearchResult, error) { - return Client.Search(ctx(), s, + return Client.Search(ctx, s, spotify.SearchTypePlaylist| spotify.SearchTypeAlbum| spotify.SearchTypeTrack| @@ -293,7 +293,7 @@ func Search(s string) (*spotify.SearchResult, error) { } func UserDevices() ([]spotify.PlayerDevice, error) { - return Client.PlayerDevices(ctx()) + return Client.PlayerDevices(ctx) } func TransferPlayback(deviceId spotify.ID) error { @@ -301,10 +301,10 @@ func TransferPlayback(deviceId spotify.ID) error { if err != nil { return errors.New("Unable to get Current Player State!") } - err = Client.PauseOpt(ctx(), &spotify.PlayOptions{DeviceID: &s.Device.ID}) - return Client.TransferPlayback(ctx(), deviceId, true) + err = Client.PauseOpt(ctx, &spotify.PlayOptions{DeviceID: &s.Device.ID}) + return Client.TransferPlayback(ctx, deviceId, true) } func GetFullPlaylist(id spotify.ID) (*spotify.FullPlaylist, error) { - return Client.GetPlaylist(ctx(), id) + return Client.GetPlaylist(ctx, id) } diff --git a/spt/play.go b/spt/play.go index 230a9a6..91a62d9 100644 --- a/spt/play.go +++ b/spt/play.go @@ -8,7 +8,7 @@ import ( ) func play(options *spotify.PlayOptions) error { - return Client.PlayOpt(ctx(), options) + return Client.PlayOpt(ctx, options) } func PlaySong(uri spotify.URI) error { @@ -38,16 +38,16 @@ func PlayContext(context spotify.URI) error { } func TogglePlayback() error { - p, err := Client.PlayerCurrentlyPlaying(ctx()) + p, err := Client.PlayerCurrentlyPlaying(ctx) if err != nil { return err } if p.Playing { - if err := Client.Pause(ctx()); err != nil { + if err := Client.Pause(ctx); err != nil { return err } } else { - if err := Client.Play(ctx()); err != nil { + if err := Client.Play(ctx); err != nil { return err } } @@ -63,11 +63,11 @@ func UriToID(uri spotify.URI) (spotify.ID, error) { } func Next() error { - return Client.Next(ctx()) + return Client.Next(ctx) } func Previous() error { - return Client.Previous(ctx()) + return Client.Previous(ctx) } func Shuffle() error { @@ -77,7 +77,7 @@ func Shuffle() error { return err } - return Client.Shuffle(ctx(), !s.ShuffleState) + return Client.Shuffle(ctx, !s.ShuffleState) } func Repeat() error { @@ -92,5 +92,5 @@ func Repeat() error { return err } - return Client.Repeat(ctx(), next[s.RepeatState]) + return Client.Repeat(ctx, next[s.RepeatState]) } diff --git a/ui/app.go b/ui/app.go index 51f19ae..190a61e 100644 --- a/ui/app.go +++ b/ui/app.go @@ -286,6 +286,7 @@ func NewApplication() *tview.Application { App.SetFocus(Main) return nil }, nil), + "queue_entry": NewAction(playlistNav.QueueEntry, nil), })) navMenu.SetActions(utils.MergeMaps(globalActions, map[string]*Action{ "open_entry": NewAction(navMenu.OpenEntry, @@ -296,24 +297,40 @@ func NewApplication() *tview.Application { playlistView.AddToPlaylist() return nil }, nil), + "queue_entry": NewAction(func(e *tcell.EventKey) *tcell.EventKey { + playlistView.QueueEntry() + return nil + }, nil), })) recentlyPlayedView.SetActions(utils.MergeMaps(globalActions, map[string]*Action{ "add_to_playlist": NewAction(func(e *tcell.EventKey) *tcell.EventKey { recentlyPlayedView.AddToPlaylist() return nil }, nil), + "queue_entry": NewAction(func(e *tcell.EventKey) *tcell.EventKey { + recentlyPlayedView.QueueEntry() + return nil + }, nil), })) topTracksView.SetActions(utils.MergeMaps(globalActions, map[string]*Action{ "play_entry": NewAction(func(e *tcell.EventKey) *tcell.EventKey { - topTracksView.PlaySelectedEntry() + topTracksView.PlayEntry() return nil }, progressBar), + "queue_entry": NewAction(func(e *tcell.EventKey) *tcell.EventKey { + topTracksView.QueueEntry() + return nil + }, nil), })) likedSongsView.SetActions(utils.MergeMaps(globalActions, map[string]*Action{ "add_to_playlist": NewAction(func(e *tcell.EventKey) *tcell.EventKey { likedSongsView.AddToPlaylist() return nil }, nil), + "queue_entry": NewAction(func(e *tcell.EventKey) *tcell.EventKey { + likedSongsView.QueueEntry() + return nil + }, nil), })) searchView.SetActions(utils.MergeMaps(globalActions, map[string]*Action{ "play_entry": NewAction(func(e *tcell.EventKey) *tcell.EventKey { @@ -339,29 +356,37 @@ func NewApplication() *tview.Application { return nil }, progressBar), "queue_entry": NewAction(func(e *tcell.EventKey) *tcell.EventKey { - albumsView.QueueSelectEntry() + albumsView.QueueEntry() return nil - }, progressBar), + }, nil), })) albumView.SetActions(utils.MergeMaps(globalActions, map[string]*Action{ "add_to_playlist": NewAction(func(e *tcell.EventKey) *tcell.EventKey { albumView.AddToPlaylist() return nil }, nil), + "queue_entry": NewAction(func(e *tcell.EventKey) *tcell.EventKey { + albumView.QueueEntry() + return nil + }, nil), })) // Visual Actions albumView.SetVisualActions(map[string]func(start, end int, e *tcell.EventKey) *tcell.EventKey{ "add_to_playlist": albumView.AddToPlaylistVisual, + "queue_entry": albumView.QueueSongsVisual, }) recentlyPlayedView.SetVisualActions(map[string]func(start, end int, e *tcell.EventKey) *tcell.EventKey{ "add_to_playlist": recentlyPlayedView.AddToPlaylistVisual, + "queue_entry": recentlyPlayedView.QueueSongsVisual, }) playlistView.SetVisualActions(map[string]func(start, end int, e *tcell.EventKey) *tcell.EventKey{ "add_to_playlist": playlistView.AddToPlaylistVisual, + "queue_entry": playlistView.QueueSongsVisual, }) likedSongsView.SetVisualActions(map[string]func(start, end int, e *tcell.EventKey) *tcell.EventKey{ "add_to_playlist": likedSongsView.AddToPlaylistVisual, + "queue_entry": likedSongsView.QueueSongsVisual, }) mappings := config.GenerateMappings() diff --git a/ui/nav.go b/ui/nav.go index 2efee3c..e8662e7 100644 --- a/ui/nav.go +++ b/ui/nav.go @@ -83,6 +83,21 @@ func (v *PlaylistNav) PlayEntry(e *tcell.EventKey) *tcell.EventKey { return nil } +func (v *PlaylistNav) QueueEntry(e *tcell.EventKey) *tcell.EventKey { + r, _ := v.Table.GetSelection() + playlist := (*v.Playlists)[r] + msg := SendNotificationWithChan("Queueing %s...", playlist.Name) + go func() { + if err := spt.QueuePlaylist(playlist.ID); err != nil { + msg <- err.Error() + return + } + msg <- playlist.Name + " Queued Succesfully!" + }() + + return nil +} + func (v *PlaylistNav) RefreshState() { p, ch := spt.CurrentUserPlaylists() go func() { diff --git a/ui/utils.go b/ui/utils.go index 3ba8415..44d9c22 100644 --- a/ui/utils.go +++ b/ui/utils.go @@ -71,6 +71,17 @@ func addToPlaylist(tracks []spotify.ID) { }) } +func queueSongs(tracks []spotify.ID) { + msg := SendNotificationWithChan(fmt.Sprintf("Queueing %d tracks...", len(tracks))) + go func() { + err := spt.QueueTracks(tracks...) + if err != nil { + msg <- err.Error() + } + msg <- fmt.Sprintf("Queued %d tracks!", len(tracks)) + }() +} + func fileName(a spotify.SimpleAlbum) string { return fmt.Sprintf(filepath.Join(cfg.CacheDir, "%s.jpg"), a.ID) } @@ -131,3 +142,10 @@ func artistName(s []spotify.SimpleArtist) string { func wrap(args ...interface{}) []interface{} { return args } + +func Map[K any, V any](a []K, f func(K) V) (res []V) { + for _, v := range a { + res = append(res, f(v)) + } + return +} diff --git a/ui/view_album.go b/ui/view_album.go index 2fd1cb4..a6dc2d4 100644 --- a/ui/view_album.go +++ b/ui/view_album.go @@ -1,6 +1,8 @@ package ui import ( + "fmt" + "github.com/aditya-K2/gspt/spt" "github.com/gdamore/tcell/v2" "github.com/zmb3/spotify/v2" @@ -33,14 +35,14 @@ func (a *AlbumView) Content() func() [][]Content { if a.currentAlbumID != nil { if a.currentFullAlbum == nil { - msg := SendNotificationWithChan("Loading %s....", a.currentAlbumName) + msg := SendNotificationWithChan("Fetching %s....", a.currentAlbumName) al, ch := spt.GetAlbum(*a.currentAlbumID) go func() { err := <-ch if err != nil { msg <- err.Error() } else { - msg <- "Album Loaded Succesfully!" + msg <- "Album Fetched Succesfully!" } }() a.currentFullAlbum = al @@ -64,13 +66,30 @@ func (a *AlbumView) AddToPlaylist() { addToPlaylist([]spotify.ID{track.ID}) } -func (a *AlbumView) AddToPlaylistVisual(start, end int, e *tcell.EventKey) *tcell.EventKey { - tracks := make([]spotify.ID, 0) - sTracks := (*(*a.currentFullAlbum).Tracks) - for k := start; k <= end; k++ { - tracks = append(tracks, sTracks[k].ID) +func (a *AlbumView) QueueEntry() { + r, _ := Main.GetSelection() + track := (*(*a.currentFullAlbum).Tracks)[r] + msg := fmt.Sprintf("%s queued succesfully!", track.Name) + if err := spt.QueueTracks(track.ID); err != nil { + msg = err.Error() } - addToPlaylist(tracks) + SendNotification(msg) +} + +func (a *AlbumView) AddToPlaylistVisual(start, end int, e *tcell.EventKey) *tcell.EventKey { + addToPlaylist(Map((*(*a.currentFullAlbum).Tracks)[start:end+1], + func(s spotify.SimpleTrack) spotify.ID { + return s.ID + })) + return nil +} + +func (a *AlbumView) QueueSongsVisual(start, end int, e *tcell.EventKey) *tcell.EventKey { + tracks := (*(*a.currentFullAlbum).Tracks)[start : end+1] + queueSongs(Map(tracks, + func(s spotify.SimpleTrack) spotify.ID { + return s.ID + })) return nil } diff --git a/ui/view_albums.go b/ui/view_albums.go index d85d2af..2221a53 100644 --- a/ui/view_albums.go +++ b/ui/view_albums.go @@ -21,7 +21,7 @@ func (a *AlbumsView) Content() func() [][]Content { return func() [][]Content { c := make([][]Content, 0) if a.savedAlbums == nil { - msg := SendNotificationWithChan("Loading Albums from your Library...") + msg := SendNotificationWithChan("Fetching Albums from your Library...") sa, ch := spt.CurrentUserSavedAlbums() go func() { err := <-ch @@ -59,16 +59,16 @@ func (a *AlbumsView) PlayEntry() { } } -func (a *AlbumsView) QueueSelectEntry() { +func (a *AlbumsView) QueueEntry() { r, _ := Main.GetSelection() alb := (*a.savedAlbums)[r] msg := SendNotificationWithChan("Queueing " + alb.Name + "...") go func() { if err := spt.QueueAlbum(alb.ID); err != nil { msg <- err.Error() - } else { - msg <- (alb.Name) + " queued succesfully!" + return } + msg <- (alb.Name) + " queued succesfully!" }() } diff --git a/ui/view_artist.go b/ui/view_artist.go index d8cb668..5d8a459 100644 --- a/ui/view_artist.go +++ b/ui/view_artist.go @@ -32,7 +32,7 @@ func (a *ArtistView) SetArtist(id *spotify.ID) { } func (a *ArtistView) RefreshState() { - msg := SendNotificationWithChan("Loading Artist!") + msg := SendNotificationWithChan("Fetching Artist....") topTracks, err := spt.GetArtistTopTracks(*a.artistID) if err != nil { msg <- ("Error retrieving Artist Top Tracks: " + err.Error()) @@ -45,7 +45,7 @@ func (a *ArtistView) RefreshState() { return } a.albums = albums - msg <- "Artist Loaded Succesfully!" + msg <- "Artist Fetched Succesfully!" } func (a *ArtistView) Content() func() [][]Content { @@ -71,29 +71,37 @@ func (a *ArtistView) Content() func() [][]Content { } } -func (a *ArtistView) PlayEntry() { - r, _ := Main.GetSelection() - if r > 0 { - if r < (len(a.albums) + 1) { - if err := spt.PlayContext(a.albums[r-1].URI); err != nil { - SendNotification(err.Error()) - } - } - } -} - -func (a *ArtistView) OpenEntry() { +func (a *ArtistView) handle(albumHandler func(int), trackHandler func(int)) { r, _ := Main.GetSelection() if r > 0 { if r < (len(a.albums)+1) && len(a.albums) > 0 { - albumView.SetAlbum(a.albums[r-1].Name, &a.albums[r-1].ID) - SetCurrentView(albumView) + albumHandler(r - 1) } else if r != len(a.albums)+1 && len(a.topTracks) > 0 { - if err := spt.PlaySong(a.topTracks[r-2-len(a.albums)].URI); err != nil { - SendNotification(err.Error()) - } + trackHandler(r - 2 - len(a.albums)) } } } +func (a *ArtistView) PlayEntry() { + a.handle(func(r int) { + if err := spt.PlayContext(a.albums[r].URI); err != nil { + SendNotification(err.Error()) + } + }, func(int) {}) +} + +func (a *ArtistView) OpenEntry() { + a.handle(func(r int) { + albumView.SetAlbum(a.albums[r].Name, &a.albums[r].ID) + SetCurrentView(albumView) + }, func(r int) { + if err := spt.PlaySong(a.topTracks[r].URI); err != nil { + SendNotification(err.Error()) + } + }) +} + +func (a *ArtistsView) QueueEntry() { +} + func (a *ArtistView) Name() string { return "AlbumsView" } diff --git a/ui/view_artists.go b/ui/view_artists.go index b25a7b0..237d556 100644 --- a/ui/view_artists.go +++ b/ui/view_artists.go @@ -21,7 +21,7 @@ func (a *ArtistsView) Content() func() [][]Content { return func() [][]Content { c := make([][]Content, 0) if a.followedArtists == nil { - msg := SendNotificationWithChan("Loading Artists from your Library...") + msg := SendNotificationWithChan("Fetching Artists from your Library...") fa, ch := spt.CurrentUserFollowedArtists() go func() { err := <-ch diff --git a/ui/view_liked.go b/ui/view_liked.go index ae35ccd..5af64d8 100644 --- a/ui/view_liked.go +++ b/ui/view_liked.go @@ -1,6 +1,8 @@ package ui import ( + "fmt" + "github.com/aditya-K2/gspt/spt" "github.com/gdamore/tcell/v2" "github.com/zmb3/spotify/v2" @@ -23,13 +25,13 @@ func (p *LikedSongsView) Content() func() [][]Content { return func() [][]Content { c := make([][]Content, 0) if p.likedSongs == nil { - msg := SendNotificationWithChan("Loading Liked Songs...") + msg := SendNotificationWithChan("Fetching Liked Songs...") p.refreshState(func(err error) { if err != nil { msg <- err.Error() return } - msg <- "Liked Songs Loaded Succesfully!" + msg <- "Liked Songs Fetched Succesfully!" }) } if p.likedSongs != nil { @@ -51,11 +53,19 @@ func (l *LikedSongsView) AddToPlaylist() { } func (l *LikedSongsView) AddToPlaylistVisual(start, end int, e *tcell.EventKey) *tcell.EventKey { - tracks := make([]spotify.ID, 0) - for k := start; k <= end; k++ { - tracks = append(tracks, (*l.likedSongs)[k].ID) - } - addToPlaylist(tracks) + addToPlaylist(Map((*l.likedSongs)[start:end+1], + func(s spotify.SavedTrack) spotify.ID { + return s.ID + })) + return nil +} + +func (l *LikedSongsView) QueueSongsVisual(start, end int, e *tcell.EventKey) *tcell.EventKey { + tracks := (*l.likedSongs)[start : end+1] + queueSongs(Map(tracks, + func(s spotify.SavedTrack) spotify.ID { + return s.ID + })) return nil } @@ -66,6 +76,16 @@ func (l *LikedSongsView) OpenEntry() { } } +func (l *LikedSongsView) QueueEntry() { + r, _ := Main.GetSelection() + track := (*l.likedSongs)[r] + msg := fmt.Sprintf("%s Queued Succesfully!", track.Name) + if err := spt.QueueTracks(track.ID); err != nil { + msg = err.Error() + } + SendNotification(msg) +} + func (l *LikedSongsView) Name() string { return "LikedSongsView" } func (p *LikedSongsView) refreshState(errHandler func(error)) { diff --git a/ui/view_playlist.go b/ui/view_playlist.go index a017531..c2b8f6d 100644 --- a/ui/view_playlist.go +++ b/ui/view_playlist.go @@ -1,6 +1,8 @@ package ui import ( + "fmt" + "github.com/aditya-K2/gspt/spt" "github.com/gdamore/tcell/v2" "github.com/zmb3/spotify/v2" @@ -31,14 +33,14 @@ func (p *PlaylistView) Content() func() [][]Content { c := make([][]Content, 0) if p.currentPlaylist != nil { if p.currentUserFullPlaylist == nil { - msg := SendNotificationWithChan("Loading %s....", p.currentPlaylist.Name) + msg := SendNotificationWithChan("Fetching %s....", p.currentPlaylist.Name) pf, ch := spt.GetPlaylist(p.currentPlaylist.ID) go func() { err := <-ch if err != nil { msg <- err.Error() } else { - msg <- "Playlist Loaded Succesfully!" + msg <- "Playlist Fetched Succesfully!" } }() p.currentUserFullPlaylist = pf @@ -63,12 +65,19 @@ func (p *PlaylistView) AddToPlaylist() { } func (p *PlaylistView) AddToPlaylistVisual(start, end int, e *tcell.EventKey) *tcell.EventKey { - tracks := make([]spotify.ID, 0) - sTracks := (*(*p.currentUserFullPlaylist).Tracks) - for k := start; k <= end; k++ { - tracks = append(tracks, sTracks[k].Track.ID) - } - addToPlaylist(tracks) + addToPlaylist(Map((*(*p.currentUserFullPlaylist).Tracks)[start:end+1], + func(s spotify.PlaylistTrack) spotify.ID { + return s.Track.ID + })) + return nil +} + +func (p *PlaylistView) QueueSongsVisual(start, end int, e *tcell.EventKey) *tcell.EventKey { + tracks := (*(*p.currentUserFullPlaylist).Tracks)[start : end+1] + queueSongs(Map(tracks, + func(s spotify.PlaylistTrack) spotify.ID { + return s.Track.ID + })) return nil } @@ -79,4 +88,14 @@ func (p *PlaylistView) OpenEntry() { } } +func (p *PlaylistView) QueueEntry() { + r, _ := Main.GetSelection() + track := (*(*p.currentUserFullPlaylist).Tracks)[r].Track + msg := fmt.Sprintf("%s Queued Succesfully!", track.Name) + if err := spt.QueueTracks(track.ID); err != nil { + msg = err.Error() + } + SendNotification(msg) +} + func (p *PlaylistView) Name() string { return "PlaylistView" } diff --git a/ui/view_recent.go b/ui/view_recent.go index 024a576..ab191ba 100644 --- a/ui/view_recent.go +++ b/ui/view_recent.go @@ -1,6 +1,8 @@ package ui import ( + "fmt" + "github.com/aditya-K2/gspt/spt" "github.com/aditya-K2/utils" "github.com/gdamore/tcell/v2" @@ -40,11 +42,19 @@ func (r *RecentlyPlayedView) AddToPlaylist() { } func (r *RecentlyPlayedView) AddToPlaylistVisual(start, end int, e *tcell.EventKey) *tcell.EventKey { - tracks := make([]spotify.ID, 0) - for k := start; k <= end; k++ { - tracks = append(tracks, r.recentlyPlayed[k].Track.ID) - } - addToPlaylist(tracks) + addToPlaylist(Map(r.recentlyPlayed[start:end+1], + func(r spotify.RecentlyPlayedItem) spotify.ID { + return r.Track.ID + })) + return nil +} + +func (r *RecentlyPlayedView) QueueSongsVisual(start, end int, e *tcell.EventKey) *tcell.EventKey { + tracks := r.recentlyPlayed[start : end+1] + queueSongs(Map(tracks, + func(s spotify.RecentlyPlayedItem) spotify.ID { + return s.Track.ID + })) return nil } @@ -73,3 +83,13 @@ func (re *RecentlyPlayedView) OpenEntry() { } } } + +func (re *RecentlyPlayedView) QueueEntry() { + r, _ := Main.GetSelection() + track := re.recentlyPlayed[r].Track + msg := fmt.Sprintf("%s Queued Succesfully!", track.Name) + if err := spt.QueueTracks(track.ID); err != nil { + msg = err.Error() + } + SendNotification(msg) +} diff --git a/ui/view_top.go b/ui/view_top.go index b0fe8b7..23a94ef 100644 --- a/ui/view_top.go +++ b/ui/view_top.go @@ -1,6 +1,8 @@ package ui import ( + "fmt" + "github.com/aditya-K2/gspt/spt" "github.com/zmb3/spotify/v2" ) @@ -57,30 +59,52 @@ func (a *TopTracksView) Content() func() [][]Content { } } -func (a *TopTracksView) PlaySelectedEntry() { +func (a *TopTracksView) handle(trackHandler, artistHandler func(r int)) { r, _ := Main.GetSelection() if r > 0 { if r < (len(a.topArtists) + 1) { - if err := spt.PlayContext(a.topArtists[r-1].URI); err != nil { - SendNotification(err.Error()) + if artistHandler != nil { + artistHandler(r - 1) + } + } else if r != len(a.topArtists)+1 { + if trackHandler != nil { + trackHandler(r - 2 - len(a.topArtists)) } } } +} + +func (a *TopTracksView) PlayEntry() { + a.handle(nil, func(r int) { + if err := spt.PlayContext(a.topArtists[r].URI); err != nil { + SendNotification(err.Error()) + } + }) } func (a *TopTracksView) OpenEntry() { - r, _ := Main.GetSelection() - if r > 0 { - if r < (len(a.topArtists) + 1) { - artistView.SetArtist(&(a.topArtists)[r-1].ID) - SetCurrentView(artistView) - } else if r != len(a.topArtists)+1 { - if err := spt.PlaySong(a.topTracks[r-2-len(a.topArtists)].URI); err != nil { - SendNotification(err.Error()) - } + artistHandler := func(r int) { + artistView.SetArtist(&(a.topArtists)[r].ID) + SetCurrentView(artistView) + } + trackHandler := func(r int) { + if err := spt.PlaySong(a.topTracks[r].URI); err != nil { + SendNotification(err.Error()) } } + a.handle(trackHandler, artistHandler) +} + +func (a *TopTracksView) QueueEntry() { + a.handle(func(r int) { + msg := fmt.Sprintf("%s Queued Succesfully!", a.topTracks[r].Name) + if err := spt.QueueTracks(a.topTracks[r].ID); err != nil { + msg = err.Error() + } + SendNotification(msg) + }, func(int) { SendNotification("Artists can not be queued!") }) + } func (a *TopTracksView) Name() string { return "TopTracksView" }