refactor(provider): return reporting failures instead of discarding them

PlaybackReporter and ProgressReporter now return an error. The UI logs it at
the three fire-and-forget call sites, so jellyfin, emby, and navidrome gain
the observability audiobookshelf had — they were dropping their client errors
silently. Player state is read on the UI goroutine and passed into the
closures, so the reports stay race-free.
This commit is contained in:
coryshaw1
2026-08-17 21:06:10 -04:00
parent 9355138673
commit 70dcc75035
9 changed files with 87 additions and 39 deletions
+6 -3
View File
@@ -148,12 +148,15 @@ type progressProv struct {
func (p *progressProv) CanReportPlayback(playlist.Track) bool { return true }
func (p *progressProv) ReportNowPlaying(playlist.Track, time.Duration, bool) {}
func (p *progressProv) ReportNowPlaying(playlist.Track, time.Duration, bool) error { return nil }
func (p *progressProv) ReportScrobble(playlist.Track, time.Duration, time.Duration, bool) {}
func (p *progressProv) ReportScrobble(playlist.Track, time.Duration, time.Duration, bool) error {
return nil
}
func (p *progressProv) ReportProgress(_ playlist.Track, position time.Duration) {
func (p *progressProv) ReportProgress(_ playlist.Track, position time.Duration) error {
p.reports <- position
return nil
}
func TestTickProgressReportThrottles(t *testing.T) {
+18 -3
View File
@@ -4,6 +4,7 @@ import (
"strings"
"time"
"github.com/bjarneo/cliamp/applog"
"github.com/bjarneo/cliamp/internal/playback"
"github.com/bjarneo/cliamp/luaplugin"
"github.com/bjarneo/cliamp/playlist"
@@ -115,7 +116,12 @@ func (m *Model) nowPlaying(track playlist.Track) {
return
}
canSeek := m.player.Seekable()
go reporter.ReportNowPlaying(track, m.player.Position(), canSeek)
position := m.player.Position()
go func() {
if err := reporter.ReportNowPlaying(track, position, canSeek); err != nil {
applog.Warn("now-playing report failed for %q: %v", track.Title, err)
}
}()
}
// maybeScrobble fires a playback-complete report for the given track if all
@@ -163,7 +169,11 @@ func (m *Model) maybeScrobble(track playlist.Track, elapsed, duration time.Durat
return // less than 50% played
}
canSeek := m.player.Seekable()
go reporter.ReportScrobble(track, elapsed, duration, canSeek)
go func() {
if err := reporter.ReportScrobble(track, elapsed, duration, canSeek); err != nil {
applog.Warn("scrobble failed for %q: %v", track.Title, err)
}
}()
}
// findPlaybackReporter returns the first registered provider that can report
@@ -213,5 +223,10 @@ func (m *Model) tickProgressReport(now time.Time) {
return
}
m.lastProgressReport = now
go reporter.ReportProgress(track, m.player.Position())
position := m.player.Position()
go func() {
if err := reporter.ReportProgress(track, position); err != nil {
applog.Warn("progress report failed for %q: %v", track.Title, err)
}
}()
}