add setting to disable waveform seekbar
This commit is contained in:
+6
-4
@@ -110,8 +110,9 @@ type NowPlayingPageConfig struct {
|
||||
}
|
||||
|
||||
type PlaybackConfig struct {
|
||||
Autoplay bool
|
||||
RepeatMode string
|
||||
Autoplay bool
|
||||
RepeatMode string
|
||||
UseWaveformSeekbar bool
|
||||
}
|
||||
|
||||
type LocalPlaybackConfig struct {
|
||||
@@ -239,8 +240,9 @@ func DefaultConfig(appVersionTag string) *Config {
|
||||
TracklistColumns: []string{"Album", "Time", "Plays"},
|
||||
},
|
||||
Playback: PlaybackConfig{
|
||||
Autoplay: false,
|
||||
RepeatMode: "None",
|
||||
Autoplay: false,
|
||||
RepeatMode: "None",
|
||||
UseWaveformSeekbar: true,
|
||||
},
|
||||
LocalPlayback: LocalPlaybackConfig{
|
||||
// "auto" is the name to pass to MPV for autoselecting the output device
|
||||
|
||||
@@ -84,6 +84,7 @@ type playbackEngine struct {
|
||||
|
||||
// to pass to onSongChange listeners; clear once listeners have been called
|
||||
lastScrobbled *mediaprovider.Track
|
||||
playbackCfg *PlaybackConfig
|
||||
scrobbleCfg *ScrobbleConfig
|
||||
transcodeCfg *TranscodingConfig
|
||||
replayGainCfg ReplayGainConfig
|
||||
@@ -118,6 +119,7 @@ func NewPlaybackEngine(
|
||||
sm: s,
|
||||
audiocache: c,
|
||||
player: p,
|
||||
playbackCfg: playbackCfg,
|
||||
scrobbleCfg: scrobbleCfg,
|
||||
transcodeCfg: transcodeCfg,
|
||||
nowPlayingIdx: -1,
|
||||
@@ -820,7 +822,11 @@ func (pm *playbackEngine) invokeNoArgCallbacks(cbs []func()) {
|
||||
func (p *playbackEngine) startPollTimePos() {
|
||||
ctx, cancel := context.WithCancel(p.ctx)
|
||||
p.cancelPollPos = cancel
|
||||
pollingTick := time.NewTicker(125 * time.Millisecond)
|
||||
pollFrequency := 250 * time.Millisecond
|
||||
if p.playbackCfg.UseWaveformSeekbar {
|
||||
pollFrequency = 100 * time.Millisecond
|
||||
}
|
||||
pollingTick := time.NewTicker(pollFrequency)
|
||||
|
||||
go func() {
|
||||
for {
|
||||
|
||||
+82
-73
@@ -37,7 +37,10 @@ type PlaybackManager struct {
|
||||
|
||||
autoplay bool
|
||||
|
||||
lastPlayTime float64
|
||||
lastPlayTime float64
|
||||
lastPlayingID string
|
||||
wfmUpdateImageCancel context.CancelFunc
|
||||
wfmImageJobs [3]*WaveformImageJob
|
||||
}
|
||||
|
||||
type RemotePlaybackDevice struct {
|
||||
@@ -75,6 +78,22 @@ func NewPlaybackManager(
|
||||
return pm
|
||||
}
|
||||
|
||||
func (p *PlaybackManager) findWfmImageJob(id string) (*WaveformImageJob, bool) {
|
||||
for _, j := range p.wfmImageJobs {
|
||||
if j != nil && j.ItemID == id {
|
||||
return j, true
|
||||
}
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
|
||||
func (p *PlaybackManager) addWfmImageJob(job *WaveformImageJob) {
|
||||
p.wfmImageJobs[0].Cancel()
|
||||
p.wfmImageJobs[0] = p.wfmImageJobs[1]
|
||||
p.wfmImageJobs[1] = p.wfmImageJobs[2]
|
||||
p.wfmImageJobs[2] = job
|
||||
}
|
||||
|
||||
func (p *PlaybackManager) addOnTrackChangeHook() {
|
||||
// See https://github.com/dweymouth/supersonic/issues/483
|
||||
// On Windows, MPV sometimes fails to start playback when switching to a track
|
||||
@@ -84,87 +103,21 @@ func (p *PlaybackManager) addOnTrackChangeHook() {
|
||||
p.lastPlayTime = curTime
|
||||
})
|
||||
|
||||
var waveformJobs [3]*WaveformImageJob
|
||||
findJob := func(id string) (*WaveformImageJob, bool) {
|
||||
for _, j := range waveformJobs {
|
||||
if j != nil && j.ItemID == id {
|
||||
return j, true
|
||||
p.engine.onBeforeSongChange = append(p.engine.onBeforeSongChange, func(item mediaprovider.MediaItem) {
|
||||
if p.engine.playbackCfg.UseWaveformSeekbar {
|
||||
if p.wfmGen != nil && item != nil && item.Metadata().Type == mediaprovider.MediaItemTypeTrack {
|
||||
// start generating waveform image for next-up track
|
||||
p.addWfmImageJob(p.wfmGen.StartWaveformGeneration(item.(*mediaprovider.Track)))
|
||||
}
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
addJob := func(job *WaveformImageJob) {
|
||||
waveformJobs[0].Cancel()
|
||||
waveformJobs[0] = waveformJobs[1]
|
||||
waveformJobs[1] = waveformJobs[2]
|
||||
waveformJobs[2] = job
|
||||
}
|
||||
|
||||
p.engine.onBeforeSongChange = append(p.engine.onBeforeSongChange, func(item mediaprovider.MediaItem) {
|
||||
if p.wfmGen != nil && item != nil && item.Metadata().Type == mediaprovider.MediaItemTypeTrack {
|
||||
// start generating waveform image for next-up track
|
||||
addJob(p.wfmGen.StartWaveformGeneration(item.(*mediaprovider.Track)))
|
||||
}
|
||||
})
|
||||
|
||||
lastPlayingID := ""
|
||||
var wfmImageUpdateCancel context.CancelFunc
|
||||
|
||||
p.OnSongChange(func(item mediaprovider.MediaItem, _ *mediaprovider.Track) {
|
||||
// Autoplay if enabled and we are on the last track
|
||||
if p.autoplay && p.NowPlayingIndex() == len(p.engine.playQueue)-1 {
|
||||
p.enqueueAutoplayTracks()
|
||||
}
|
||||
if wfmImageUpdateCancel != nil {
|
||||
wfmImageUpdateCancel()
|
||||
}
|
||||
|
||||
updateUnfinishedJob := func(job *WaveformImageJob) {
|
||||
ctx, c := context.WithCancel(p.cache.rootCtx)
|
||||
wfmImageUpdateCancel = c
|
||||
go func(ctx context.Context, job *WaveformImageJob) {
|
||||
for {
|
||||
time.Sleep(333 * time.Millisecond)
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
default:
|
||||
img := job.Get()
|
||||
for _, cb := range p.onWaveformImgUpdate {
|
||||
cb(img)
|
||||
}
|
||||
if job.Done() {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}(ctx, job)
|
||||
}
|
||||
|
||||
if item != nil {
|
||||
// cancel possible waveform generation job for previous track
|
||||
if old, ok := findJob(lastPlayingID); ok {
|
||||
old.Cancel()
|
||||
}
|
||||
lastPlayingID = item.Metadata().ID
|
||||
|
||||
var job *WaveformImageJob
|
||||
if j, ok := findJob(item.Metadata().ID); ok {
|
||||
job = j
|
||||
} else if tr, ok := item.(*mediaprovider.Track); ok {
|
||||
job = p.wfmGen.StartWaveformGeneration(tr)
|
||||
addJob(job)
|
||||
}
|
||||
if job != nil {
|
||||
img := job.Get()
|
||||
for _, cb := range p.onWaveformImgUpdate {
|
||||
cb(img)
|
||||
}
|
||||
if !job.done && job != nil {
|
||||
updateUnfinishedJob(job)
|
||||
}
|
||||
}
|
||||
}
|
||||
p.handleWaveformImageSongChange(item)
|
||||
|
||||
if runtime.GOOS != "windows" {
|
||||
return
|
||||
@@ -183,6 +136,62 @@ func (p *PlaybackManager) addOnTrackChangeHook() {
|
||||
})
|
||||
}
|
||||
|
||||
func (p *PlaybackManager) handleWaveformImageSongChange(item mediaprovider.MediaItem) {
|
||||
if p.wfmUpdateImageCancel != nil {
|
||||
p.wfmUpdateImageCancel()
|
||||
}
|
||||
if !p.engine.playbackCfg.UseWaveformSeekbar {
|
||||
return
|
||||
}
|
||||
|
||||
updateUnfinishedJob := func(job *WaveformImageJob) {
|
||||
ctx, c := context.WithCancel(p.cache.rootCtx)
|
||||
p.wfmUpdateImageCancel = c
|
||||
go func(ctx context.Context, job *WaveformImageJob) {
|
||||
for {
|
||||
time.Sleep(333 * time.Millisecond)
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
default:
|
||||
img := job.Get()
|
||||
for _, cb := range p.onWaveformImgUpdate {
|
||||
cb(img)
|
||||
}
|
||||
if job.Done() {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}(ctx, job)
|
||||
}
|
||||
|
||||
if item != nil {
|
||||
// cancel possible waveform generation job for previous track
|
||||
if old, ok := p.findWfmImageJob(p.lastPlayingID); ok {
|
||||
old.Cancel()
|
||||
}
|
||||
p.lastPlayingID = item.Metadata().ID
|
||||
|
||||
var job *WaveformImageJob
|
||||
if j, ok := p.findWfmImageJob(item.Metadata().ID); ok {
|
||||
job = j
|
||||
} else if tr, ok := item.(*mediaprovider.Track); ok {
|
||||
job = p.wfmGen.StartWaveformGeneration(tr)
|
||||
p.addWfmImageJob(job)
|
||||
}
|
||||
if job != nil {
|
||||
img := job.Get()
|
||||
for _, cb := range p.onWaveformImgUpdate {
|
||||
cb(img)
|
||||
}
|
||||
if !job.done && job != nil {
|
||||
updateUnfinishedJob(job)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (p *PlaybackManager) ScanRemotePlayers(ctx context.Context, fastScan bool) {
|
||||
if fastScan {
|
||||
p.scanRemotePlayers(ctx, 1 /*waitSec*/)
|
||||
|
||||
Reference in New Issue
Block a user