From 08182123b8165c8c8dc55d1fefc643f5c5c47035 Mon Sep 17 00:00:00 2001 From: Simon Garrelou Date: Sat, 10 Dec 2022 22:22:32 +0100 Subject: Add playlist support --- .gitignore | 1 + src/app.go | 52 ++++++++++++++++++++++----- src/footer.go | 8 +++-- src/keybinds.go | 44 +++++++++++++++++++++++ src/page_artists.go | 5 +-- src/page_playlists.go | 98 +++++++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 194 insertions(+), 14 deletions(-) create mode 100644 .gitignore create mode 100644 src/page_playlists.go diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a5122bd --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +launch.json \ No newline at end of file diff --git a/src/app.go b/src/app.go index f1995a4..ee1b342 100644 --- a/src/app.go +++ b/src/app.go @@ -20,13 +20,21 @@ type app struct { cfg *Config // Artists page - artistsTree *tview.TreeView - songsList *tview.List - currentSongs []*subsonic.Child + artistsLoaded bool + artistsTree *tview.TreeView + songsList *tview.List + currentSongs []*subsonic.Child // Play queue page playQueueList *tview.List + // Playlist page + playlistsLoaded bool + playlistsList *tview.List + playlistSongs *tview.List + allPlaylists []*subsonic.Playlist + currentPlaylist *subsonic.Playlist + // Subsonic variables sub *subsonic.Client playQueue *music.Queue @@ -47,6 +55,7 @@ func Run(cfg *Config) { a.pages.AddPage("config", a.configPage(), true, false) a.pages.AddPage("artists", a.artistsPage(), true, false) a.pages.AddPage("playqueue", a.queuePage(), true, false) + a.pages.AddPage("playlists", a.playlistsPage(), true, false) mainLayout := tview.NewFlex(). SetDirection(tview.FlexRow). @@ -59,12 +68,26 @@ func Run(cfg *Config) { } else { a.sub, _ = buildSubsonicClient(a.cfg) a.playQueue.SetClient(a.sub) - err := a.refreshArtists() - if err != nil { - a.alert("Could not refresh artists: %v", err) + + fmt.Printf("Loading artists...") + if err := a.refreshArtists(); err != nil { + fmt.Println("ERR") + a.alert("Loading artists: %v", err) } else { - a.switchToPage("artists") + fmt.Println("OK") + a.artistsLoaded = true + } + + fmt.Printf("Loading playlists...") + if err := a.refreshPlaylists(); err != nil { + fmt.Println("ERR") + a.alert("Loading playlists: %v", err) + } else { + fmt.Println("OK") + a.playlistsLoaded = true } + + a.switchToPage("artists") } // Keyboard shortcuts @@ -101,6 +124,12 @@ func Run(cfg *Config) { func (a *app) switchToPage(name string) { switch name { case "artists": + if !a.artistsLoaded { + if err := a.refreshArtists(); err != nil { + a.alert("Error: %v", err) + } + a.artistsLoaded = true + } a.pages.SwitchToPage("artists") a.headerSections.Highlight("artists") a.tv.SetFocus(a.artistsTree) @@ -111,9 +140,16 @@ func (a *app) switchToPage(name string) { a.tv.SetFocus(a.playQueueList) a.pages.SetBorder(true) case "playlists": + if !a.playlistsLoaded { + if err := a.refreshPlaylists(); err != nil { + a.alert("Error: %v", err) + } + a.playlistsLoaded = true + } a.pages.SwitchToPage("playlists") a.headerSections.Highlight("playlists") - a.pages.SetBorder(true) + a.tv.SetFocus(a.playlistsList) + a.pages.SetBorder(false) case "config": a.pages.SwitchToPage("config") a.headerSections.Highlight("config") diff --git a/src/footer.go b/src/footer.go index be275c3..ab6181d 100644 --- a/src/footer.go +++ b/src/footer.go @@ -11,8 +11,12 @@ func (a *app) updateFooter() { case "playqueue": a.footer.SetText("[blue]l:[yellow] Next song [blue]p:[yellow] Toggle pause [blue]d:[yellow] Remove [blue]j:[yellow] Move up [blue]k:[yellow] Move down") case "playlists": - a.footer.SetText("") + if a.tv.GetFocus() == a.playlistsList { + a.footer.SetText("[blue]l:[yellow] Next song [blue]p:[yellow] Toggle pause [blue]e:[yellow] Play playlist last [blue]n:[yellow] Play playlist next") + } else if a.tv.GetFocus() == a.playlistSongs { + a.footer.SetText("[blue]l:[yellow] Next song [blue]p:[yellow] Toggle pause [blue]e:[yellow] Play song last [blue]n:[yellow] Play song next") + } case "config": - a.footer.SetText("") + a.footer.SetText("[yellow]No shortcuts here") } } diff --git a/src/keybinds.go b/src/keybinds.go index ffdf64a..74f7953 100644 --- a/src/keybinds.go +++ b/src/keybinds.go @@ -120,6 +120,50 @@ func (a *app) setupMusicControlKeys(p *tview.Box) { } } + if a.tv.GetFocus() == a.playlistsList { + if event.Rune() == 'e' { + sel := a.playlistsList.GetCurrentItem() + pl, err := a.sub.GetPlaylist(a.allPlaylists[sel].ID) + if err != nil { + a.alert("Error: %v", err) + return nil + } + + for _, s := range pl.Entry { + a.playQueue.Append(s) + } + + a.updatePageQueue() + } else if event.Rune() == 'n' { + sel := a.playlistsList.GetCurrentItem() + pl, err := a.sub.GetPlaylist(a.allPlaylists[sel].ID) + if err != nil { + a.alert("Error: %v", err) + return nil + } + + for i := len(pl.Entry) - 1; i >= 0; i-- { + a.playQueue.Insert(1, pl.Entry[i]) + } + + a.updatePageQueue() + } + } + + if a.tv.GetFocus() == a.playlistSongs { + if event.Rune() == 'e' { + sel := a.playlistSongs.GetCurrentItem() + a.playQueue.Append(a.currentPlaylist.Entry[sel]) + + a.updatePageQueue() + } else if event.Rune() == 'n' { + sel := a.playlistSongs.GetCurrentItem() + a.playQueue.Insert(1, a.currentPlaylist.Entry[sel]) + + a.updatePageQueue() + } + } + return event }) } diff --git a/src/page_artists.go b/src/page_artists.go index 874a675..b90d785 100644 --- a/src/page_artists.go +++ b/src/page_artists.go @@ -3,7 +3,6 @@ package src import ( "fmt" - "github.com/delucks/go-subsonic" "github.com/gdamore/tcell/v2" "github.com/rivo/tview" ) @@ -115,10 +114,8 @@ func (a *app) loadAlbumInPanel(id string) error { } a.songsList.Clear() - a.currentSongs = make([]*subsonic.Child, 0) + a.currentSongs = album.Child for _, song := range album.Child { - a.currentSongs = append(a.currentSongs, song) - txt := fmt.Sprintf("%-2d - %s", song.Track, song.Title) a.songsList.AddItem(txt, "", 0, func() { diff --git a/src/page_playlists.go b/src/page_playlists.go new file mode 100644 index 0000000..303a9a7 --- /dev/null +++ b/src/page_playlists.go @@ -0,0 +1,98 @@ +package src + +import ( + "fmt" + + "github.com/gdamore/tcell/v2" + "github.com/rivo/tview" +) + +func (a *app) playlistsPage() tview.Primitive { + flex := tview.NewFlex().SetDirection(tview.FlexColumn) + + a.playlistsList = tview.NewList(). + SetMainTextColor(tcell.ColorRed). + SetHighlightFullLine(true). + ShowSecondaryText(false) + a.playlistsList.SetBorder(true).SetBorderAttributes(tcell.AttrDim) + + a.playlistSongs = tview.NewList(). + SetHighlightFullLine(true). + ShowSecondaryText(false) + a.playlistSongs.SetBorder(true).SetBorderAttributes(tcell.AttrDim) + + // Change the left-right keys to switch between the panels + a.playlistsList.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey { + if event.Key() == tcell.KeyLeft || event.Key() == tcell.KeyRight { + a.tv.SetFocus(a.playlistSongs) + a.updateFooter() + return nil + } + return event + }) + a.playlistSongs.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey { + if event.Key() == tcell.KeyLeft || event.Key() == tcell.KeyRight { + a.tv.SetFocus(a.playlistsList) + a.updateFooter() + return nil + } + return event + }) + + // Setup e & n keybinds + a.setupMusicControlKeys(flex.Box) + + flex.AddItem(a.playlistsList, 0, 1, false) + flex.AddItem(a.playlistSongs, 0, 1, false) + + return flex +} + +func (a *app) refreshPlaylists() error { + playlists, err := a.sub.GetPlaylists(nil) + if err != nil { + return err + } + + a.allPlaylists = playlists + + a.playlistsList.Clear() + for _, pl := range playlists { + id := pl.ID + a.playlistsList.AddItem(pl.Name, "", 0, func() { + a.loadPlaylist(id) + a.tv.SetFocus(a.playlistSongs) + a.updateFooter() + }) + } + + a.playlistsList.SetCurrentItem(0) + + return nil +} + +func (a *app) loadPlaylist(id string) error { + a.playlistSongs.Clear() + pl, err := a.sub.GetPlaylist(id) + if err != nil { + return err + } + + a.currentPlaylist = pl + + for _, s := range a.currentPlaylist.Entry { + a.playlistSongs.AddItem(fmt.Sprintf("%s - %s", s.Title, s.Artist), "", 0, func() { + sel := a.playlistSongs.GetCurrentItem() + a.playQueue.Clear() + for _, s := range a.currentPlaylist.Entry[sel:] { + a.playQueue.Append(s) + } + + if err := a.playQueue.Play(); err != nil { + a.alert("Error: %v", err) + } + }) + } + + return nil +} -- cgit v1.2.3