ensure play queue track state is updated on favorite/unfavorite and scrobbles
This commit is contained in:
@@ -6,6 +6,7 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
"supersonic/backend/util"
|
"supersonic/backend/util"
|
||||||
"supersonic/player"
|
"supersonic/player"
|
||||||
|
"supersonic/sharedutil"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/dweymouth/go-subsonic/subsonic"
|
"github.com/dweymouth/go-subsonic/subsonic"
|
||||||
@@ -141,7 +142,11 @@ func (p *PlaybackManager) LoadTracks(tracks []*subsonic.Child, appendToQueue, sh
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
p.player.AppendFile(url.String())
|
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
|
return nil
|
||||||
}
|
}
|
||||||
@@ -176,10 +181,24 @@ func (p *PlaybackManager) PlayTrackAt(idx int) error {
|
|||||||
|
|
||||||
func (p *PlaybackManager) GetPlayQueue() []*subsonic.Child {
|
func (p *PlaybackManager) GetPlayQueue() []*subsonic.Child {
|
||||||
pq := make([]*subsonic.Child, len(p.playQueue))
|
pq := make([]*subsonic.Child, len(p.playQueue))
|
||||||
copy(pq, p.playQueue)
|
for i, tr := range p.playQueue {
|
||||||
|
copy := *tr
|
||||||
|
pq[i] = ©
|
||||||
|
}
|
||||||
return pq
|
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
|
// trackIdxs must be sorted
|
||||||
func (p *PlaybackManager) RemoveTracksFromQueue(trackIdxs []int) {
|
func (p *PlaybackManager) RemoveTracksFromQueue(trackIdxs []int) {
|
||||||
newQueue := make([]*subsonic.Child, 0, len(p.playQueue)-len(trackIdxs))
|
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]
|
song := p.playQueue[p.nowPlayingIdx]
|
||||||
if playDur.Seconds()/p.curTrackTime > ScrobbleThreshold {
|
if playDur.Seconds()/p.curTrackTime > ScrobbleThreshold {
|
||||||
log.Printf("Scrobbling %q", song.Title)
|
log.Printf("Scrobbling %q", song.Title)
|
||||||
|
song.PlayCount += 1
|
||||||
p.lastScrobbled = song
|
p.lastScrobbled = song
|
||||||
p.sm.Server.Scrobble(song.ID, map[string]string{"time": strconv.FormatInt(time.Now().Unix()*1000, 10)})
|
p.sm.Server.Scrobble(song.ID, map[string]string{"time": strconv.FormatInt(time.Now().Unix()*1000, 10)})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
}
|
||||||
@@ -5,6 +5,7 @@ import (
|
|||||||
"log"
|
"log"
|
||||||
"supersonic/backend"
|
"supersonic/backend"
|
||||||
"supersonic/res"
|
"supersonic/res"
|
||||||
|
"supersonic/sharedutil"
|
||||||
"supersonic/ui/controller"
|
"supersonic/ui/controller"
|
||||||
"supersonic/ui/layouts"
|
"supersonic/ui/layouts"
|
||||||
"supersonic/ui/util"
|
"supersonic/ui/util"
|
||||||
@@ -100,7 +101,7 @@ func (a *AlbumPage) OnSongChange(song *subsonic.Child, lastScrobbledIfAny *subso
|
|||||||
a.nowPlayingID = song.ID
|
a.nowPlayingID = song.ID
|
||||||
}
|
}
|
||||||
a.tracklist.SetNowPlaying(a.nowPlayingID)
|
a.tracklist.SetNowPlaying(a.nowPlayingID)
|
||||||
a.tracklist.IncrementPlayCount(lastScrobbledIfAny)
|
a.tracklist.IncrementPlayCount(sharedutil.TrackIDOrEmptyStr(lastScrobbledIfAny))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *AlbumPage) Reload() {
|
func (a *AlbumPage) Reload() {
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package browsing
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"supersonic/backend"
|
"supersonic/backend"
|
||||||
|
"supersonic/sharedutil"
|
||||||
"supersonic/ui/controller"
|
"supersonic/ui/controller"
|
||||||
"supersonic/ui/layouts"
|
"supersonic/ui/layouts"
|
||||||
"supersonic/ui/widgets"
|
"supersonic/ui/widgets"
|
||||||
@@ -44,8 +45,9 @@ func NewNowPlayingPage(
|
|||||||
a.tracklist.SetVisibleColumns(conf.TracklistColumns)
|
a.tracklist.SetVisibleColumns(conf.TracklistColumns)
|
||||||
a.tracklist.AutoNumber = true
|
a.tracklist.AutoNumber = true
|
||||||
a.tracklist.DisablePlaybackMenu = 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.OnPlayTrackAt = a.onPlayTrackAt
|
||||||
a.tracklist.OnAddToPlaylist = a.contr.DoAddTracksToPlaylistWorkflow
|
|
||||||
a.tracklist.AuxiliaryMenuItems = []*fyne.MenuItem{
|
a.tracklist.AuxiliaryMenuItems = []*fyne.MenuItem{
|
||||||
fyne.NewMenuItem("Remove from queue", a.onRemoveSelectedFromQueue),
|
fyne.NewMenuItem("Remove from queue", a.onRemoveSelectedFromQueue),
|
||||||
}
|
}
|
||||||
@@ -86,7 +88,7 @@ func (a *NowPlayingPage) OnSongChange(song *subsonic.Child, lastScrobbledIfAny *
|
|||||||
a.nowPlayingID = song.ID
|
a.nowPlayingID = song.ID
|
||||||
}
|
}
|
||||||
a.tracklist.SetNowPlaying(a.nowPlayingID)
|
a.tracklist.SetNowPlaying(a.nowPlayingID)
|
||||||
a.tracklist.IncrementPlayCount(lastScrobbledIfAny)
|
a.tracklist.IncrementPlayCount(sharedutil.TrackIDOrEmptyStr(lastScrobbledIfAny))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *NowPlayingPage) Reload() {
|
func (a *NowPlayingPage) Reload() {
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import (
|
|||||||
"log"
|
"log"
|
||||||
"supersonic/backend"
|
"supersonic/backend"
|
||||||
"supersonic/res"
|
"supersonic/res"
|
||||||
|
"supersonic/sharedutil"
|
||||||
"supersonic/ui/controller"
|
"supersonic/ui/controller"
|
||||||
"supersonic/ui/layouts"
|
"supersonic/ui/layouts"
|
||||||
"supersonic/ui/util"
|
"supersonic/ui/util"
|
||||||
@@ -87,7 +88,7 @@ func (a *PlaylistPage) OnSongChange(song *subsonic.Child, lastScrobbledIfAny *su
|
|||||||
a.nowPlayingID = song.ID
|
a.nowPlayingID = song.ID
|
||||||
}
|
}
|
||||||
a.tracklist.SetNowPlaying(a.nowPlayingID)
|
a.tracklist.SetNowPlaying(a.nowPlayingID)
|
||||||
a.tracklist.IncrementPlayCount(lastScrobbledIfAny)
|
a.tracklist.IncrementPlayCount(sharedutil.TrackIDOrEmptyStr(lastScrobbledIfAny))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *PlaylistPage) Reload() {
|
func (a *PlaylistPage) Reload() {
|
||||||
|
|||||||
@@ -62,6 +62,9 @@ func (m Controller) ConnectTracklistActions(tracklist *widgets.Tracklist) {
|
|||||||
} else {
|
} else {
|
||||||
go s.Unstar(subsonic.StarParameters{SongIDs: trackIDs})
|
go s.Unstar(subsonic.StarParameters{SongIDs: trackIDs})
|
||||||
}
|
}
|
||||||
|
for _, id := range trackIDs {
|
||||||
|
m.App.PlaybackManager.OnTrackFavoriteStatusChanged(id, fav)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+13
-10
@@ -5,6 +5,7 @@ import (
|
|||||||
"runtime"
|
"runtime"
|
||||||
"strconv"
|
"strconv"
|
||||||
"supersonic/res"
|
"supersonic/res"
|
||||||
|
"supersonic/sharedutil"
|
||||||
"supersonic/ui/layouts"
|
"supersonic/ui/layouts"
|
||||||
"supersonic/ui/os"
|
"supersonic/ui/os"
|
||||||
"supersonic/ui/util"
|
"supersonic/ui/util"
|
||||||
@@ -150,16 +151,10 @@ func (t *Tracklist) SetNowPlaying(trackID string) {
|
|||||||
t.Refresh()
|
t.Refresh()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Tracklist) IncrementPlayCount(track *subsonic.Child) {
|
func (t *Tracklist) IncrementPlayCount(trackID string) {
|
||||||
if track == nil {
|
if tr := sharedutil.FindTrackByID(trackID, t.Tracks); tr != nil {
|
||||||
return
|
tr.PlayCount += 1
|
||||||
}
|
t.Refresh()
|
||||||
for _, tr := range t.Tracks {
|
|
||||||
if tr.ID == track.ID {
|
|
||||||
tr.PlayCount += 1
|
|
||||||
t.Refresh()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -245,6 +240,14 @@ func (t *Tracklist) onShowContextMenu(e *fyne.PointEvent, trackIdx int) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (t *Tracklist) onSetFavorite(trackID string, fav bool) {
|
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 {
|
if t.OnSetFavorite != nil {
|
||||||
t.OnSetFavorite([]string{trackID}, fav)
|
t.OnSetFavorite([]string{trackID}, fav)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user