Skip to content

Commit

Permalink
change: removes pro-active background loading of playlist data, makin…
Browse files Browse the repository at this point in the history
…g the playlist page act more like the other pages: loading subcontent on demand

change: playlist lists (such as in the "add song to playlist" function) can now be more accurate. They were being populated once at GUI initialization, and so would always miss newly added playlists.
  • Loading branch information
xxxserxxx committed Dec 30, 2024
1 parent efcb9c6 commit 8fcd7f9
Show file tree
Hide file tree
Showing 6 changed files with 57 additions and 145 deletions.
4 changes: 0 additions & 4 deletions gui.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,6 @@ type Ui struct {
mpvEvents chan mpvplayer.UiEvent
mprisPlayer *remote.MprisPlayer

playlists []subsonic.Playlist
connection *subsonic.Connection
player *mpvplayer.Player
logger *logger.Logger
Expand Down Expand Up @@ -91,7 +90,6 @@ func InitGui(artists []subsonic.Artist,
eventLoop: nil, // initialized by initEventLoops()
mpvEvents: make(chan mpvplayer.UiEvent, 5),

playlists: []subsonic.Playlist{},
connection: connection,
player: player,
logger: logger,
Expand Down Expand Up @@ -203,8 +201,6 @@ func InitGui(artists []subsonic.Artist,
SetFocus(rootFlex).
EnableMouse(true)

ui.playlistPage.UpdatePlaylists()

return ui
}

Expand Down
18 changes: 13 additions & 5 deletions page_browser.go
Original file line number Diff line number Diff line change
Expand Up @@ -170,10 +170,6 @@ func (ui *Ui) createBrowserPage(artists []subsonic.Artist) *BrowserPage {
}
})

// "add to playlist" modal
for _, playlist := range ui.playlists {
ui.addToPlaylistList.AddItem(tview.Escape(playlist.Name), "", 0, nil)
}
ui.addToPlaylistList.SetBorder(true).
SetTitle("Add to Playlist")

Expand All @@ -190,7 +186,7 @@ func (ui *Ui) createBrowserPage(artists []subsonic.Artist) *BrowserPage {
ui.app.SetFocus(browserPage.entityList)
return nil
} else if event.Key() == tcell.KeyEnter {
playlist := ui.playlists[ui.addToPlaylistList.GetCurrentItem()]
playlist := ui.playlistPage.playlists[ui.addToPlaylistList.GetCurrentItem()]
browserPage.handleAddEntityToPlaylist(&playlist)

ui.pages.HidePage(PageAddToPlaylist)
Expand All @@ -217,6 +213,7 @@ func (ui *Ui) createBrowserPage(artists []subsonic.Artist) *BrowserPage {
case 'A':
// only makes sense to add to a playlist if there are playlists
if ui.playlistPage.GetCount() > 0 {
browserPage.updatePlaylists()
ui.pages.ShowPage(PageAddToPlaylist)
ui.app.SetFocus(ui.addToPlaylistList)
} else {
Expand Down Expand Up @@ -630,3 +627,14 @@ func (b *BrowserPage) handleAddEntityToPlaylist(playlist *subsonic.Playlist) {
}
}, b.ui.playlistPage.UpdatePlaylists)
}

func (b *BrowserPage) updatePlaylists() {
ui := b.ui
ui.addToPlaylistList.Clear()
if ui.playlistPage.playlists != nil && len(ui.playlistPage.playlists) > 0 {
// "add to playlist" modal
for _, playlist := range ui.playlistPage.playlists {
ui.addToPlaylistList.AddItem(tview.Escape(playlist.Name), "", 0, nil)
}
}
}
141 changes: 32 additions & 109 deletions page_playlist.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,10 @@
package main

import (
"fmt"
"sync"
"time"

"github.com/gdamore/tcell/v2"
"github.com/rivo/tview"
"github.com/spezifisch/stmps/logger"
"github.com/spezifisch/stmps/subsonic"
"github.com/spf13/viper"
)

type PlaylistPage struct {
Expand All @@ -23,20 +18,18 @@ type PlaylistPage struct {
playlistList *tview.List
newPlaylistInput *tview.InputField
selectedPlaylist *tview.List
playlists []subsonic.Playlist

// external refs
ui *Ui
logger logger.LoggerInterface

updatingMutex sync.Locker
isUpdating bool
}

func (ui *Ui) createPlaylistPage() *PlaylistPage {
playlistPage := PlaylistPage{
ui: ui,
logger: ui.logger,
updatingMutex: &sync.Mutex{},
ui: ui,
logger: ui.logger,
playlists: make([]subsonic.Playlist, 0),
}

// left half: playlists
Expand All @@ -48,10 +41,7 @@ func (ui *Ui) createPlaylistPage() *PlaylistPage {
SetTitleAlign(tview.AlignLeft).
SetBorder(true)

// add the playlists
for _, playlist := range ui.playlists {
playlistPage.playlistList.AddItem(tview.Escape(playlist.Name), "", 0, nil)
}
playlistPage.UpdatePlaylists()

// right half: songs of selected playlist
playlistPage.selectedPlaylist = tview.NewList().
Expand Down Expand Up @@ -167,15 +157,15 @@ func (ui *Ui) createPlaylistPage() *PlaylistPage {
playlistPage.DeletePlaylistModal = makeModal(deletePlaylistFlex, 20, 3)

playlistPage.playlistList.SetChangedFunc(func(index int, _ string, _ string, _ rune) {
if index < 0 || index >= len(ui.playlists) {
if index < 0 || index >= len(playlistPage.playlists) {
return
}
playlistPage.handlePlaylistSelected(ui.playlists[index])
playlistPage.handlePlaylistSelected(playlistPage.playlists[index])
})

// open first playlist by default so we don't get stuck when there's only one playlist
if len(ui.playlists) > 0 {
playlistPage.handlePlaylistSelected(ui.playlists[0])
if len(playlistPage.playlists) > 0 {
playlistPage.handlePlaylistSelected(playlistPage.playlists[0])
}

return &playlistPage
Expand All @@ -190,94 +180,20 @@ func (p *PlaylistPage) GetCount() int {
}

func (p *PlaylistPage) UpdatePlaylists() {
// There's a potential race condition here and, albeit highly unlikely to ever get hit,
// we'll put in some protection
p.updatingMutex.Lock()
defer p.updatingMutex.Unlock()
if p.isUpdating {
playlists, err := p.ui.connection.GetPlaylists()
if err != nil {
p.logger.PrintError("GetPlaylists", err)
return
}
p.isUpdating = true
// TODO (B) Stop pro-actively deeply loading the playlists. This will remove all of the threading and spinner code.

var spinnerText []rune = []rune(viper.GetString("ui.spinner"))
if len(spinnerText) == 0 {
spinnerText = []rune("▉▊▋▌▍▎▏▎▍▌▋▊▉")
p.playlistList.Clear()
p.playlists = playlists.Playlists
for _, pl := range playlists.Playlists {
p.playlistList.AddItem(tview.Escape(pl.Name), "", 0, nil)
}
spinnerMax := len(spinnerText) - 1
playlistsButton := buttonOrder[PAGE_PLAYLISTS]
stop := make(chan bool)
go func() {
var idx int
timer := time.NewTicker(500 * time.Millisecond)
defer timer.Stop()
for {
select {
case <-timer.C:
p.ui.app.QueueUpdateDraw(func() {
var format string
if playlistsButton == p.ui.menuWidget.activeButton {
format = "%d: [::b][red]%c[white]%s[::-]"
} else {
format = "%d: [red]%c[white]%s"
}
label := fmt.Sprintf(format, PAGE_PLAYLISTS+1, spinnerText[idx], playlistsButton)
p.ui.menuWidget.buttons[playlistsButton].SetLabel(label)
idx++
if idx > spinnerMax {
idx = 0
}
})
case <-stop:
p.ui.app.QueueUpdateDraw(func() {
var format string
if playlistsButton == p.ui.menuWidget.activeButton {
format = "%d: [::b]%s[::-]"
} else {
format = "%d: %s"
}
label := fmt.Sprintf(format, PAGE_PLAYLISTS+1, playlistsButton)
p.ui.menuWidget.buttons[playlistsButton].SetLabel(label)
})
close(stop)
return
}
}
}()

go func() {
playlists, err := p.ui.connection.GetPlaylists()
if err != nil {
p.logger.PrintError("GetPlaylists", err)
p.isUpdating = false
stop <- true
return
}
if len(playlists.Playlists) == 0 {
p.logger.Printf("no error from GetPlaylists, but also no response!")
stop <- true
return
}
p.updatingMutex.Lock()
defer p.updatingMutex.Unlock()
p.ui.playlists = playlists.Playlists
p.ui.app.QueueUpdateDraw(func() {
p.playlistList.Clear()
p.ui.addToPlaylistList.Clear()

for _, playlist := range p.ui.playlists {
p.addPlaylist(playlist)
}

p.isUpdating = false
})
stop <- true
}()
}

func (p *PlaylistPage) addPlaylist(playlist subsonic.Playlist) {
p.playlistList.AddItem(tview.Escape(playlist.Name), "", 0, nil)
p.ui.addToPlaylistList.AddItem(tview.Escape(playlist.Name), "", 0, nil)
// Rather than getting the current selected, let's use the features of closures.
}

func (p *PlaylistPage) handleAddPlaylistSongToQueue() {
Expand All @@ -289,7 +205,7 @@ func (p *PlaylistPage) handleAddPlaylistSongToQueue() {
if entityIndex < 0 || entityIndex >= p.selectedPlaylist.GetItemCount() {
return
}
if playlistIndex >= len(p.ui.playlists) || entityIndex >= len(p.ui.playlists[playlistIndex].Entries) {
if playlistIndex >= len(p.playlists) || entityIndex >= len(p.playlists[playlistIndex].Entries) {
return
}

Expand All @@ -298,15 +214,15 @@ func (p *PlaylistPage) handleAddPlaylistSongToQueue() {
p.selectedPlaylist.SetCurrentItem(entityIndex + 1)
}

entity := p.ui.playlists[playlistIndex].Entries[entityIndex]
entity := p.playlists[playlistIndex].Entries[entityIndex]
p.ui.addSongToQueue(entity)

p.ui.queuePage.UpdateQueue()
}

func (p *PlaylistPage) handleAddPlaylistToQueue() {
currentIndex := p.playlistList.GetCurrentItem()
if currentIndex < 0 || currentIndex >= p.playlistList.GetItemCount() || currentIndex >= len(p.ui.playlists) {
if currentIndex < 0 || currentIndex >= p.playlistList.GetItemCount() || currentIndex >= len(p.playlists) {
return
}

Expand All @@ -315,7 +231,7 @@ func (p *PlaylistPage) handleAddPlaylistToQueue() {
p.playlistList.SetCurrentItem(currentIndex + 1)
}

playlist := p.ui.playlists[currentIndex]
playlist := p.playlists[currentIndex]
for _, entity := range playlist.Entries {
p.ui.addSongToQueue(entity)
}
Expand All @@ -324,6 +240,13 @@ func (p *PlaylistPage) handleAddPlaylistToQueue() {
}

func (p *PlaylistPage) handlePlaylistSelected(playlist subsonic.Playlist) {
var err error
playlist, err = p.ui.connection.GetPlaylist(string(playlist.Id))
if err != nil {
p.logger.PrintError("handlePlaylistSelected", err)
return
}

p.selectedPlaylist.Clear()
p.selectedPlaylist.SetSelectedFocusOnly(true)

Expand All @@ -341,25 +264,25 @@ func (p *PlaylistPage) newPlaylist(name string) {
return
}

p.ui.playlists = append(p.ui.playlists, playlist)
p.playlists = append(p.playlists, playlist)

p.playlistList.AddItem(tview.Escape(playlist.Name), "", 0, nil)
p.ui.addToPlaylistList.AddItem(tview.Escape(playlist.Name), "", 0, nil)
}

func (p *PlaylistPage) deletePlaylist(index int) {
if index < 0 || index >= len(p.ui.playlists) {
if index < 0 || index >= len(p.playlists) {
return
}

playlist := p.ui.playlists[index]
playlist := p.playlists[index]

if index == 0 {
p.playlistList.SetCurrentItem(1)
}

// Removes item with specified index
p.ui.playlists = append(p.ui.playlists[:index], p.ui.playlists[index+1:]...)
p.playlists = append(p.playlists[:index], p.playlists[index+1:]...)

p.playlistList.RemoveItem(index)
p.ui.addToPlaylistList.RemoveItem(index)
Expand Down
8 changes: 4 additions & 4 deletions page_queue.go
Original file line number Diff line number Diff line change
Expand Up @@ -452,7 +452,7 @@ func (q *QueuePage) saveQueue(playlistName string) {
}

var playlistId string
for _, p := range q.ui.playlists {
for _, p := range q.ui.playlistPage.playlists {
if p.Name == playlistName {
playlistId = string(p.Id)
break
Expand All @@ -473,15 +473,15 @@ func (q *QueuePage) saveQueue(playlistName string) {
q.logger.Print(message)
} else {
if playlistId != "" {
for i, pl := range q.ui.playlists {
for i, pl := range q.ui.playlistPage.playlists {
if string(pl.Id) == playlistId {
q.ui.playlists[i] = response
q.ui.playlistPage.playlists[i] = response
break
}
}
} else {
q.ui.playlistPage.addPlaylist(response)
q.ui.playlists = append(q.ui.playlists, response)
q.ui.playlistPage.playlists = append(q.ui.playlistPage.playlists, response)
}
q.ui.playlistPage.handlePlaylistSelected(response)
}
Expand Down
21 changes: 1 addition & 20 deletions subsonic/connection.go
Original file line number Diff line number Diff line change
Expand Up @@ -381,26 +381,7 @@ func (connection *Connection) GetPlaylists() (Playlists, error) {
if resp == nil {
return Playlists{}, fmt.Errorf("GetPlaylists nil response from server: %s", err)
}
playlists := resp.Playlists

for i := 0; i < len(playlists.Playlists); i++ {
playlist := playlists.Playlists[i]

if playlist.SongCount == 0 {
continue
}

pl, err := connection.GetPlaylist(string(playlist.Id))

if err != nil {
return Playlists{Playlists: make([]Playlist, 0)}, err
}

playlists.Playlists[i].Entries = pl.Entries

}

return playlists, nil
return resp.Playlists, nil
}

func (connection *Connection) GetPlaylist(id string) (Playlist, error) {
Expand Down
Loading

0 comments on commit 8fcd7f9

Please sign in to comment.