diff --git a/backend/playbackmanager.go b/backend/playbackmanager.go index c105631..f693bec 100644 --- a/backend/playbackmanager.go +++ b/backend/playbackmanager.go @@ -6,6 +6,7 @@ import ( "strconv" "supersonic/backend/util" "supersonic/player" + "supersonic/sharedutil" "time" "github.com/dweymouth/go-subsonic/subsonic" @@ -141,7 +142,11 @@ func (p *PlaybackManager) LoadTracks(tracks []*subsonic.Child, appendToQueue, sh return err } p.player.AppendFile(url.String()) - p.playQueue = append(p.playQueue, tracks[i]) + // ensure a deep copy of the track info so that we can maintain our own state + // (tracking play count increases, favorite, and rating) without messing up + // other views' track models + tr := *tracks[i] + p.playQueue = append(p.playQueue, &tr) } return nil } @@ -176,10 +181,24 @@ func (p *PlaybackManager) PlayTrackAt(idx int) error { func (p *PlaybackManager) GetPlayQueue() []*subsonic.Child { pq := make([]*subsonic.Child, len(p.playQueue)) - copy(pq, p.playQueue) + for i, tr := range p.playQueue { + copy := *tr + pq[i] = © + } return pq } +// Any time the user changes the favorite status of a track elsewhere in the app, +// this should be called to ensure the in-memory track model is updated. +func (p *PlaybackManager) OnTrackFavoriteStatusChanged(id string, fav bool) { + tr := sharedutil.FindTrackByID(id, p.playQueue) + if fav { + tr.Starred = time.Now() + } else { + tr.Starred = time.Time{} + } +} + // trackIdxs must be sorted func (p *PlaybackManager) RemoveTracksFromQueue(trackIdxs []int) { newQueue := make([]*subsonic.Child, 0, len(p.playQueue)-len(trackIdxs)) @@ -228,6 +247,7 @@ func (p *PlaybackManager) checkScrobble(playDur time.Duration) { song := p.playQueue[p.nowPlayingIdx] if playDur.Seconds()/p.curTrackTime > ScrobbleThreshold { log.Printf("Scrobbling %q", song.Title) + song.PlayCount += 1 p.lastScrobbled = song p.sm.Server.Scrobble(song.ID, map[string]string{"time": strconv.FormatInt(time.Now().Unix()*1000, 10)}) } diff --git a/sharedutil/sharedutil.go b/sharedutil/sharedutil.go new file mode 100644 index 0000000..158aaa4 --- /dev/null +++ b/sharedutil/sharedutil.go @@ -0,0 +1,19 @@ +package sharedutil + +import "github.com/dweymouth/go-subsonic/subsonic" + +func FindTrackByID(id string, tracks []*subsonic.Child) *subsonic.Child { + for _, tr := range tracks { + if id == tr.ID { + return tr + } + } + return nil +} + +func TrackIDOrEmptyStr(track *subsonic.Child) string { + if track == nil { + return "" + } + return track.ID +} diff --git a/ui/browsing/albumpage.go b/ui/browsing/albumpage.go index df0152f..76d44ab 100644 --- a/ui/browsing/albumpage.go +++ b/ui/browsing/albumpage.go @@ -5,6 +5,7 @@ import ( "log" "supersonic/backend" "supersonic/res" + "supersonic/sharedutil" "supersonic/ui/controller" "supersonic/ui/layouts" "supersonic/ui/util" @@ -100,7 +101,7 @@ func (a *AlbumPage) OnSongChange(song *subsonic.Child, lastScrobbledIfAny *subso a.nowPlayingID = song.ID } a.tracklist.SetNowPlaying(a.nowPlayingID) - a.tracklist.IncrementPlayCount(lastScrobbledIfAny) + a.tracklist.IncrementPlayCount(sharedutil.TrackIDOrEmptyStr(lastScrobbledIfAny)) } func (a *AlbumPage) Reload() { diff --git a/ui/browsing/nowplayingpage.go b/ui/browsing/nowplayingpage.go index 827b334..a66131c 100644 --- a/ui/browsing/nowplayingpage.go +++ b/ui/browsing/nowplayingpage.go @@ -2,6 +2,7 @@ package browsing import ( "supersonic/backend" + "supersonic/sharedutil" "supersonic/ui/controller" "supersonic/ui/layouts" "supersonic/ui/widgets" @@ -44,8 +45,9 @@ func NewNowPlayingPage( a.tracklist.SetVisibleColumns(conf.TracklistColumns) a.tracklist.AutoNumber = true a.tracklist.DisablePlaybackMenu = true + contr.ConnectTracklistActions(a.tracklist) + // override the default OnPlayTrackAt handler b/c we don't need to re-load the tracks into the queue a.tracklist.OnPlayTrackAt = a.onPlayTrackAt - a.tracklist.OnAddToPlaylist = a.contr.DoAddTracksToPlaylistWorkflow a.tracklist.AuxiliaryMenuItems = []*fyne.MenuItem{ fyne.NewMenuItem("Remove from queue", a.onRemoveSelectedFromQueue), } @@ -86,7 +88,7 @@ func (a *NowPlayingPage) OnSongChange(song *subsonic.Child, lastScrobbledIfAny * a.nowPlayingID = song.ID } a.tracklist.SetNowPlaying(a.nowPlayingID) - a.tracklist.IncrementPlayCount(lastScrobbledIfAny) + a.tracklist.IncrementPlayCount(sharedutil.TrackIDOrEmptyStr(lastScrobbledIfAny)) } func (a *NowPlayingPage) Reload() { diff --git a/ui/browsing/playlistpage.go b/ui/browsing/playlistpage.go index f1daef5..bfd3cc3 100644 --- a/ui/browsing/playlistpage.go +++ b/ui/browsing/playlistpage.go @@ -5,6 +5,7 @@ import ( "log" "supersonic/backend" "supersonic/res" + "supersonic/sharedutil" "supersonic/ui/controller" "supersonic/ui/layouts" "supersonic/ui/util" @@ -87,7 +88,7 @@ func (a *PlaylistPage) OnSongChange(song *subsonic.Child, lastScrobbledIfAny *su a.nowPlayingID = song.ID } a.tracklist.SetNowPlaying(a.nowPlayingID) - a.tracklist.IncrementPlayCount(lastScrobbledIfAny) + a.tracklist.IncrementPlayCount(sharedutil.TrackIDOrEmptyStr(lastScrobbledIfAny)) } func (a *PlaylistPage) Reload() { diff --git a/ui/controller/controller.go b/ui/controller/controller.go index 270dee0..be192bc 100644 --- a/ui/controller/controller.go +++ b/ui/controller/controller.go @@ -62,6 +62,9 @@ func (m Controller) ConnectTracklistActions(tracklist *widgets.Tracklist) { } else { go s.Unstar(subsonic.StarParameters{SongIDs: trackIDs}) } + for _, id := range trackIDs { + m.App.PlaybackManager.OnTrackFavoriteStatusChanged(id, fav) + } } } diff --git a/ui/widgets/tracklist.go b/ui/widgets/tracklist.go index cb05c0a..8041e50 100644 --- a/ui/widgets/tracklist.go +++ b/ui/widgets/tracklist.go @@ -5,6 +5,7 @@ import ( "runtime" "strconv" "supersonic/res" + "supersonic/sharedutil" "supersonic/ui/layouts" "supersonic/ui/os" "supersonic/ui/util" @@ -150,16 +151,10 @@ func (t *Tracklist) SetNowPlaying(trackID string) { t.Refresh() } -func (t *Tracklist) IncrementPlayCount(track *subsonic.Child) { - if track == nil { - return - } - for _, tr := range t.Tracks { - if tr.ID == track.ID { - tr.PlayCount += 1 - t.Refresh() - return - } +func (t *Tracklist) IncrementPlayCount(trackID string) { + if tr := sharedutil.FindTrackByID(trackID, t.Tracks); tr != nil { + tr.PlayCount += 1 + t.Refresh() } } @@ -245,6 +240,14 @@ func (t *Tracklist) onShowContextMenu(e *fyne.PointEvent, trackIdx int) { } func (t *Tracklist) onSetFavorite(trackID string, fav bool) { + // update our own track model + tr := sharedutil.FindTrackByID(trackID, t.Tracks) + if fav { + tr.Starred = time.Now() + } else { + tr.Starred = time.Time{} + } + // notify listener if t.OnSetFavorite != nil { t.OnSetFavorite([]string{trackID}, fav) }