refactor: extract lyric fetching logic to LyricsManager

This commit is contained in:
Drew Weymouth
2025-11-01 09:58:30 -07:00
parent 35b27432a5
commit 711d564509
3 changed files with 13 additions and 34 deletions
+4 -2
View File
@@ -44,6 +44,7 @@ var (
type App struct { type App struct {
Config *Config Config *Config
ServerManager *ServerManager ServerManager *ServerManager
LyricsManager *LyricsManager
ImageManager *ImageManager ImageManager *ImageManager
AudioCache *AudioCache AudioCache *AudioCache
PlaybackManager *PlaybackManager PlaybackManager *PlaybackManager
@@ -52,7 +53,6 @@ type App struct {
MPRISHandler *MPRISHandler MPRISHandler *MPRISHandler
WinSMTC *windows.SMTC WinSMTC *windows.SMTC
ipcServer ipc.IPCServer ipcServer ipc.IPCServer
LrcLibFetcher *LrcLibFetcher
// UI callbacks to be set in main // UI callbacks to be set in main
OnReactivate func() OnReactivate func()
@@ -158,10 +158,12 @@ func StartupApp(appName, displayAppName, appVersion, appVersionTag, latestReleas
a.ServerManager.SetPrefetchAlbumCoverCallback(func(coverID string) { a.ServerManager.SetPrefetchAlbumCoverCallback(func(coverID string) {
_, _ = a.ImageManager.GetCoverThumbnail(coverID) _, _ = a.ImageManager.GetCoverThumbnail(coverID)
}) })
var fetch *LrcLibFetcher
if a.Config.Application.EnableLrcLib { if a.Config.Application.EnableLrcLib {
timeout := time.Duration(a.Config.Application.RequestTimeoutSeconds) * time.Second timeout := time.Duration(a.Config.Application.RequestTimeoutSeconds) * time.Second
a.LrcLibFetcher = NewLrcLibFetcher(a.cacheDir, a.Config.Application.CustomLrcLibUrl, timeout) fetch = NewLrcLibFetcher(a.cacheDir, a.Config.Application.CustomLrcLibUrl, timeout)
} }
a.LyricsManager = NewLyricsManager(a.ServerManager, fetch)
// Periodically scan for remote players // Periodically scan for remote players
go a.PlaybackManager.ScanRemotePlayers(a.bgrndCtx, true /*fastScan*/) go a.PlaybackManager.ScanRemotePlayers(a.bgrndCtx, true /*fastScan*/)
+8 -31
View File
@@ -61,7 +61,6 @@ type NowPlayingPage struct {
container *fyne.Container container *fyne.Container
// cancel funcs for background fetch tasks // cancel funcs for background fetch tasks
lyricFetchCancel context.CancelFunc
imageLoadCancel context.CancelFunc imageLoadCancel context.CancelFunc
relatedFetchCancel context.CancelFunc relatedFetchCancel context.CancelFunc
} }
@@ -72,11 +71,11 @@ type nowPlayingPageState struct {
pool *util.WidgetPool pool *util.WidgetPool
sm *backend.ServerManager sm *backend.ServerManager
pm *backend.PlaybackManager pm *backend.PlaybackManager
lm *backend.LyricsManager
im *backend.ImageManager im *backend.ImageManager
mp mediaprovider.MediaProvider mp mediaprovider.MediaProvider
canRate bool canRate bool
canShare bool canShare bool
lrcFetch *backend.LrcLibFetcher
} }
func NewNowPlayingPage( func NewNowPlayingPage(
@@ -84,15 +83,15 @@ func NewNowPlayingPage(
contr *controller.Controller, contr *controller.Controller,
pool *util.WidgetPool, pool *util.WidgetPool,
sm *backend.ServerManager, sm *backend.ServerManager,
lm *backend.LyricsManager,
im *backend.ImageManager, im *backend.ImageManager,
pm *backend.PlaybackManager, pm *backend.PlaybackManager,
mp mediaprovider.MediaProvider, mp mediaprovider.MediaProvider,
canRate bool, canRate bool,
canShare bool, canShare bool,
lrcLibFetcher *backend.LrcLibFetcher,
) *NowPlayingPage { ) *NowPlayingPage {
state := nowPlayingPageState{ state := nowPlayingPageState{
conf: conf, contr: contr, pool: pool, sm: sm, im: im, pm: pm, mp: mp, canRate: canRate, canShare: canShare, lrcFetch: lrcLibFetcher, conf: conf, contr: contr, pool: pool, sm: sm, lm: lm, im: im, pm: pm, mp: mp, canRate: canRate, canShare: canShare,
} }
if page, ok := pool.Obtain(util.WidgetTypeNowPlayingPage).(*NowPlayingPage); ok && page != nil { if page, ok := pool.Obtain(util.WidgetTypeNowPlayingPage).(*NowPlayingPage); ok && page != nil {
page.nowPlayingPageState = state page.nowPlayingPageState = state
@@ -336,10 +335,6 @@ func (a *NowPlayingPage) onImageLoaded(img image.Image, err error) {
} }
func (a *NowPlayingPage) updateLyrics() { func (a *NowPlayingPage) updateLyrics() {
if a.lyricFetchCancel != nil {
a.lyricFetchCancel()
}
if a.nowPlayingID == a.curLyricsID { if a.nowPlayingID == a.curLyricsID {
if a.nowPlayingID != "" { if a.nowPlayingID != "" {
// just need to sync the current time // just need to sync the current time
@@ -354,8 +349,6 @@ func (a *NowPlayingPage) updateLyrics() {
return return
} }
a.curLyricsID = a.nowPlayingID a.curLyricsID = a.nowPlayingID
ctx, cancel := context.WithCancel(context.Background())
a.lyricFetchCancel = cancel
a.lyricsLoading.Start() a.lyricsLoading.Start()
// set the widget to an empty (not nil) lyric during fetch // set the widget to an empty (not nil) lyric during fetch
// to keep it from showing "Lyrics not available" // to keep it from showing "Lyrics not available"
@@ -365,27 +358,11 @@ func (a *NowPlayingPage) updateLyrics() {
Lines: []mediaprovider.LyricLine{{Text: ""}}, Lines: []mediaprovider.LyricLine{{Text: ""}},
}) })
tr, _ := a.nowPlaying.(*mediaprovider.Track) tr, _ := a.nowPlaying.(*mediaprovider.Track)
go a.fetchLyrics(ctx, tr)
}
func (a *NowPlayingPage) fetchLyrics(ctx context.Context, song *mediaprovider.Track) { a.lm.FetchLyricsAsync(tr, func(id string, lyrics *mediaprovider.Lyrics) {
var lyrics *mediaprovider.Lyrics if id != a.nowPlayingID {
var err error
if lp, ok := a.sm.Server.(mediaprovider.LyricsProvider); ok {
if lyrics, err = lp.GetLyrics(song); err != nil {
log.Printf("Error fetching lyrics: %v", err)
}
}
if lyrics == nil && a.lrcFetch != nil {
lyrics, err = a.lrcFetch.FetchLrcLibLyrics(song.Title, song.ArtistNames[0], song.Album, int(song.Duration.Seconds()))
if err != nil {
log.Println(err.Error())
}
}
select {
case <-ctx.Done():
return return
default: }
fyne.Do(func() { fyne.Do(func() {
a.lyricsLoading.Stop() a.lyricsLoading.Stop()
a.lyricsViewer.EnableTapToSeek() a.lyricsViewer.EnableTapToSeek()
@@ -395,7 +372,7 @@ func (a *NowPlayingPage) fetchLyrics(ctx context.Context, song *mediaprovider.Tr
a.lyricsViewer.OnSeeked(a.lastPlayPos) a.lyricsViewer.OnSeeked(a.lastPlayPos)
} }
}) })
} })
} }
func (a *NowPlayingPage) updateRelatedList() { func (a *NowPlayingPage) updateRelatedList() {
@@ -464,7 +441,7 @@ func (a *NowPlayingPage) Reload() {
} }
func (s *nowPlayingPageState) Restore() Page { func (s *nowPlayingPageState) Restore() Page {
return NewNowPlayingPage(s.conf, s.contr, s.pool, s.sm, s.im, s.pm, s.mp, s.canRate, s.canShare, s.lrcFetch) return NewNowPlayingPage(s.conf, s.contr, s.pool, s.sm, s.lm, s.im, s.pm, s.mp, s.canRate, s.canShare)
} }
var _ CanShowPlayTime = (*NowPlayingPage)(nil) var _ CanShowPlayTime = (*NowPlayingPage)(nil)
+1 -1
View File
@@ -48,7 +48,7 @@ func (r Router) CreatePage(rte controller.Route) Page {
case controller.Genres: case controller.Genres:
return NewGenresPage(r.Controller, r.App.ServerManager.Server) return NewGenresPage(r.Controller, r.App.ServerManager.Server)
case controller.NowPlaying: case controller.NowPlaying:
return NewNowPlayingPage(&r.App.Config.NowPlayingConfig, r.Controller, r.widgetPool, r.App.ServerManager, r.App.ImageManager, r.App.PlaybackManager, r.App.ServerManager.Server, canRate, canShare, r.App.LrcLibFetcher) return NewNowPlayingPage(&r.App.Config.NowPlayingConfig, r.Controller, r.widgetPool, r.App.ServerManager, r.App.LyricsManager, r.App.ImageManager, r.App.PlaybackManager, r.App.ServerManager.Server, canRate, canShare)
case controller.Playlist: case controller.Playlist:
return NewPlaylistPage(rte.Arg, &r.App.Config.PlaylistPage, r.widgetPool, r.Controller, r.App.ServerManager, r.App.PlaybackManager, r.App.ImageManager) return NewPlaylistPage(rte.Arg, &r.App.Config.PlaylistPage, r.widgetPool, r.Controller, r.App.ServerManager, r.App.PlaybackManager, r.App.ImageManager)
case controller.Playlists: case controller.Playlists: