aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon Garrelou <simon.garrelou@gmail.com>2022-12-10 22:22:32 +0100
committerSimon Garrelou <simon.garrelou@gmail.com>2022-12-10 22:22:32 +0100
commit08182123b8165c8c8dc55d1fefc643f5c5c47035 (patch)
tree631891c25d5f294820e5b49a9bf467b7688d98c1
parent96e0b7c9c2b058b479079fa41f10cf3513e95359 (diff)
downloadtermsonic-08182123b8165c8c8dc55d1fefc643f5c5c47035.tar.gz
termsonic-08182123b8165c8c8dc55d1fefc643f5c5c47035.zip
Add playlist support
-rw-r--r--.gitignore1
-rw-r--r--src/app.go52
-rw-r--r--src/footer.go8
-rw-r--r--src/keybinds.go44
-rw-r--r--src/page_artists.go5
-rw-r--r--src/page_playlists.go98
6 files changed, 194 insertions, 14 deletions
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 {
20 cfg *Config 20 cfg *Config
21 21
22 // Artists page 22 // Artists page
23 artistsTree *tview.TreeView 23 artistsLoaded bool
24 songsList *tview.List 24 artistsTree *tview.TreeView
25 currentSongs []*subsonic.Child 25 songsList *tview.List
26 currentSongs []*subsonic.Child
26 27
27 // Play queue page 28 // Play queue page
28 playQueueList *tview.List 29 playQueueList *tview.List
29 30
31 // Playlist page
32 playlistsLoaded bool
33 playlistsList *tview.List
34 playlistSongs *tview.List
35 allPlaylists []*subsonic.Playlist
36 currentPlaylist *subsonic.Playlist
37
30 // Subsonic variables 38 // Subsonic variables
31 sub *subsonic.Client 39 sub *subsonic.Client
32 playQueue *music.Queue 40 playQueue *music.Queue
@@ -47,6 +55,7 @@ func Run(cfg *Config) {
47 a.pages.AddPage("config", a.configPage(), true, false) 55 a.pages.AddPage("config", a.configPage(), true, false)
48 a.pages.AddPage("artists", a.artistsPage(), true, false) 56 a.pages.AddPage("artists", a.artistsPage(), true, false)
49 a.pages.AddPage("playqueue", a.queuePage(), true, false) 57 a.pages.AddPage("playqueue", a.queuePage(), true, false)
58 a.pages.AddPage("playlists", a.playlistsPage(), true, false)
50 59
51 mainLayout := tview.NewFlex(). 60 mainLayout := tview.NewFlex().
52 SetDirection(tview.FlexRow). 61 SetDirection(tview.FlexRow).
@@ -59,12 +68,26 @@ func Run(cfg *Config) {
59 } else { 68 } else {
60 a.sub, _ = buildSubsonicClient(a.cfg) 69 a.sub, _ = buildSubsonicClient(a.cfg)
61 a.playQueue.SetClient(a.sub) 70 a.playQueue.SetClient(a.sub)
62 err := a.refreshArtists() 71
63 if err != nil { 72 fmt.Printf("Loading artists...")
64 a.alert("Could not refresh artists: %v", err) 73 if err := a.refreshArtists(); err != nil {
74 fmt.Println("ERR")
75 a.alert("Loading artists: %v", err)
65 } else { 76 } else {
66 a.switchToPage("artists") 77 fmt.Println("OK")
78 a.artistsLoaded = true
79 }
80
81 fmt.Printf("Loading playlists...")
82 if err := a.refreshPlaylists(); err != nil {
83 fmt.Println("ERR")
84 a.alert("Loading playlists: %v", err)
85 } else {
86 fmt.Println("OK")
87 a.playlistsLoaded = true
67 } 88 }
89
90 a.switchToPage("artists")
68 } 91 }
69 92
70 // Keyboard shortcuts 93 // Keyboard shortcuts
@@ -101,6 +124,12 @@ func Run(cfg *Config) {
101func (a *app) switchToPage(name string) { 124func (a *app) switchToPage(name string) {
102 switch name { 125 switch name {
103 case "artists": 126 case "artists":
127 if !a.artistsLoaded {
128 if err := a.refreshArtists(); err != nil {
129 a.alert("Error: %v", err)
130 }
131 a.artistsLoaded = true
132 }
104 a.pages.SwitchToPage("artists") 133 a.pages.SwitchToPage("artists")
105 a.headerSections.Highlight("artists") 134 a.headerSections.Highlight("artists")
106 a.tv.SetFocus(a.artistsTree) 135 a.tv.SetFocus(a.artistsTree)
@@ -111,9 +140,16 @@ func (a *app) switchToPage(name string) {
111 a.tv.SetFocus(a.playQueueList) 140 a.tv.SetFocus(a.playQueueList)
112 a.pages.SetBorder(true) 141 a.pages.SetBorder(true)
113 case "playlists": 142 case "playlists":
143 if !a.playlistsLoaded {
144 if err := a.refreshPlaylists(); err != nil {
145 a.alert("Error: %v", err)
146 }
147 a.playlistsLoaded = true
148 }
114 a.pages.SwitchToPage("playlists") 149 a.pages.SwitchToPage("playlists")
115 a.headerSections.Highlight("playlists") 150 a.headerSections.Highlight("playlists")
116 a.pages.SetBorder(true) 151 a.tv.SetFocus(a.playlistsList)
152 a.pages.SetBorder(false)
117 case "config": 153 case "config":
118 a.pages.SwitchToPage("config") 154 a.pages.SwitchToPage("config")
119 a.headerSections.Highlight("config") 155 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() {
11 case "playqueue": 11 case "playqueue":
12 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") 12 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")
13 case "playlists": 13 case "playlists":
14 a.footer.SetText("") 14 if a.tv.GetFocus() == a.playlistsList {
15 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")
16 } else if a.tv.GetFocus() == a.playlistSongs {
17 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")
18 }
15 case "config": 19 case "config":
16 a.footer.SetText("") 20 a.footer.SetText("[yellow]No shortcuts here")
17 } 21 }
18} 22}
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) {
120 } 120 }
121 } 121 }
122 122
123 if a.tv.GetFocus() == a.playlistsList {
124 if event.Rune() == 'e' {
125 sel := a.playlistsList.GetCurrentItem()
126 pl, err := a.sub.GetPlaylist(a.allPlaylists[sel].ID)
127 if err != nil {
128 a.alert("Error: %v", err)
129 return nil
130 }
131
132 for _, s := range pl.Entry {
133 a.playQueue.Append(s)
134 }
135
136 a.updatePageQueue()
137 } else if event.Rune() == 'n' {
138 sel := a.playlistsList.GetCurrentItem()
139 pl, err := a.sub.GetPlaylist(a.allPlaylists[sel].ID)
140 if err != nil {
141 a.alert("Error: %v", err)
142 return nil
143 }
144
145 for i := len(pl.Entry) - 1; i >= 0; i-- {
146 a.playQueue.Insert(1, pl.Entry[i])
147 }
148
149 a.updatePageQueue()
150 }
151 }
152
153 if a.tv.GetFocus() == a.playlistSongs {
154 if event.Rune() == 'e' {
155 sel := a.playlistSongs.GetCurrentItem()
156 a.playQueue.Append(a.currentPlaylist.Entry[sel])
157
158 a.updatePageQueue()
159 } else if event.Rune() == 'n' {
160 sel := a.playlistSongs.GetCurrentItem()
161 a.playQueue.Insert(1, a.currentPlaylist.Entry[sel])
162
163 a.updatePageQueue()
164 }
165 }
166
123 return event 167 return event
124 }) 168 })
125} 169}
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
3import ( 3import (
4 "fmt" 4 "fmt"
5 5
6 "github.com/delucks/go-subsonic"
7 "github.com/gdamore/tcell/v2" 6 "github.com/gdamore/tcell/v2"
8 "github.com/rivo/tview" 7 "github.com/rivo/tview"
9) 8)
@@ -115,10 +114,8 @@ func (a *app) loadAlbumInPanel(id string) error {
115 } 114 }
116 115
117 a.songsList.Clear() 116 a.songsList.Clear()
118 a.currentSongs = make([]*subsonic.Child, 0) 117 a.currentSongs = album.Child
119 for _, song := range album.Child { 118 for _, song := range album.Child {
120 a.currentSongs = append(a.currentSongs, song)
121
122 txt := fmt.Sprintf("%-2d - %s", song.Track, song.Title) 119 txt := fmt.Sprintf("%-2d - %s", song.Track, song.Title)
123 120
124 a.songsList.AddItem(txt, "", 0, func() { 121 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 @@
1package src
2
3import (
4 "fmt"
5
6 "github.com/gdamore/tcell/v2"
7 "github.com/rivo/tview"
8)
9
10func (a *app) playlistsPage() tview.Primitive {
11 flex := tview.NewFlex().SetDirection(tview.FlexColumn)
12
13 a.playlistsList = tview.NewList().
14 SetMainTextColor(tcell.ColorRed).
15 SetHighlightFullLine(true).
16 ShowSecondaryText(false)
17 a.playlistsList.SetBorder(true).SetBorderAttributes(tcell.AttrDim)
18
19 a.playlistSongs = tview.NewList().
20 SetHighlightFullLine(true).
21 ShowSecondaryText(false)
22 a.playlistSongs.SetBorder(true).SetBorderAttributes(tcell.AttrDim)
23
24 // Change the left-right keys to switch between the panels
25 a.playlistsList.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey {
26 if event.Key() == tcell.KeyLeft || event.Key() == tcell.KeyRight {
27 a.tv.SetFocus(a.playlistSongs)
28 a.updateFooter()
29 return nil
30 }
31 return event
32 })
33 a.playlistSongs.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey {
34 if event.Key() == tcell.KeyLeft || event.Key() == tcell.KeyRight {
35 a.tv.SetFocus(a.playlistsList)
36 a.updateFooter()
37 return nil
38 }
39 return event
40 })
41
42 // Setup e & n keybinds
43 a.setupMusicControlKeys(flex.Box)
44
45 flex.AddItem(a.playlistsList, 0, 1, false)
46 flex.AddItem(a.playlistSongs, 0, 1, false)
47
48 return flex
49}
50
51func (a *app) refreshPlaylists() error {
52 playlists, err := a.sub.GetPlaylists(nil)
53 if err != nil {
54 return err
55 }
56
57 a.allPlaylists = playlists
58
59 a.playlistsList.Clear()
60 for _, pl := range playlists {
61 id := pl.ID
62 a.playlistsList.AddItem(pl.Name, "", 0, func() {
63 a.loadPlaylist(id)
64 a.tv.SetFocus(a.playlistSongs)
65 a.updateFooter()
66 })
67 }
68
69 a.playlistsList.SetCurrentItem(0)
70
71 return nil
72}
73
74func (a *app) loadPlaylist(id string) error {
75 a.playlistSongs.Clear()
76 pl, err := a.sub.GetPlaylist(id)
77 if err != nil {
78 return err
79 }
80
81 a.currentPlaylist = pl
82
83 for _, s := range a.currentPlaylist.Entry {
84 a.playlistSongs.AddItem(fmt.Sprintf("%s - %s", s.Title, s.Artist), "", 0, func() {
85 sel := a.playlistSongs.GetCurrentItem()
86 a.playQueue.Clear()
87 for _, s := range a.currentPlaylist.Entry[sel:] {
88 a.playQueue.Append(s)
89 }
90
91 if err := a.playQueue.Play(); err != nil {
92 a.alert("Error: %v", err)
93 }
94 })
95 }
96
97 return nil
98}