add cache warming for album covers to album iterators

This commit is contained in:
Drew Weymouth
2023-01-07 16:24:18 -08:00
parent 5722c18d36
commit 584a160809
7 changed files with 55 additions and 21 deletions
+16
View File
@@ -14,6 +14,8 @@ type AlbumIterator interface {
} }
type LibraryManager struct { type LibraryManager struct {
PreCacheCoverFn func(string)
s *ServerManager s *ServerManager
albumDetailCache gcache.Cache albumDetailCache gcache.Cache
} }
@@ -153,6 +155,11 @@ func (r *baseIter) Next() *subsonic.AlbumID3 {
} }
r.prefetched = albums r.prefetched = albums
r.prefetchedPos = 1 r.prefetchedPos = 1
if r.l.PreCacheCoverFn != nil {
for _, album := range albums {
go r.l.PreCacheCoverFn(album.ID)
}
}
return r.prefetched[0] return r.prefetched[0]
} }
@@ -277,6 +284,9 @@ func (s *searchIter) addNewAlbums(al []*subsonic.AlbumID3) {
continue continue
} }
s.prefetched = append(s.prefetched, album) s.prefetched = append(s.prefetched, album)
if s.l.PreCacheCoverFn != nil {
go s.l.PreCacheCoverFn(album.ID)
}
s.albumIDset[album.ID] = true s.albumIDset[album.ID] = true
} }
} }
@@ -328,6 +338,9 @@ func (r *randomIter) Next() *subsonic.AlbumID3 {
for _, album := range albums { for _, album := range albums {
if _, ok := r.albumIDSet[album.ID]; !ok { if _, ok := r.albumIDSet[album.ID]; !ok {
r.prefetched = append(r.prefetched, album) r.prefetched = append(r.prefetched, album)
if r.l.PreCacheCoverFn != nil {
go r.l.PreCacheCoverFn(album.ID)
}
r.albumIDSet[album.ID] = true r.albumIDSet[album.ID] = true
} }
} }
@@ -346,6 +359,9 @@ func (r *randomIter) Next() *subsonic.AlbumID3 {
if _, ok := r.albumIDSet[album.ID]; !ok { if _, ok := r.albumIDSet[album.ID]; !ok {
hitCount++ hitCount++
r.prefetched = append(r.prefetched, album) r.prefetched = append(r.prefetched, album)
if r.l.PreCacheCoverFn != nil {
go r.l.PreCacheCoverFn(album.ID)
}
r.albumIDSet[album.ID] = true r.albumIDSet[album.ID] = true
} }
} }
+3
View File
@@ -51,6 +51,9 @@ func StartupApp() (*App, error) {
a.PlaybackManager = NewPlaybackManager(a.bgrndCtx, a.ServerManager, a.Player) a.PlaybackManager = NewPlaybackManager(a.bgrndCtx, a.ServerManager, a.Player)
a.LibraryManager = NewLibraryManager(a.ServerManager) a.LibraryManager = NewLibraryManager(a.ServerManager)
a.ImageManager = NewImageManager(a.ServerManager, configdir.LocalCache(AppName)) a.ImageManager = NewImageManager(a.ServerManager, configdir.LocalCache(AppName))
a.LibraryManager.PreCacheCoverFn = func(albumID string) {
_, _ = a.ImageManager.GetAlbumThumbnail(albumID)
}
return a, nil return a, nil
} }
+7
View File
@@ -32,6 +32,13 @@ func NewImageManager(s *ServerManager, baseCacheDir string) *ImageManager {
} }
} }
func (i *ImageManager) GetAlbumThumbnailFromCache(albumID string) (image.Image, bool) {
if img, err := i.thumbnailCache.Get(albumID); err == nil && img != nil {
return img.(image.Image), true
}
return nil, false
}
func (i *ImageManager) GetAlbumThumbnail(albumID string) (image.Image, error) { func (i *ImageManager) GetAlbumThumbnail(albumID string) (image.Image, error) {
// in-memory cache // in-memory cache
if i.thumbnailCache.Has(albumID) { if i.thumbnailCache.Has(albumID) {
+2 -2
View File
@@ -67,7 +67,7 @@ func NewAlbumsPage(title string, sortOrder string, lm *backend.LibraryManager, i
a.sortOrder.OnChanged = a.onSortOrderChanged a.sortOrder.OnChanged = a.onSortOrderChanged
sortVbox := container.NewVBox(layout.NewSpacer(), a.sortOrder, layout.NewSpacer()) sortVbox := container.NewVBox(layout.NewSpacer(), a.sortOrder, layout.NewSpacer())
iter := lm.AlbumsIter(backend.AlbumSortOrder(a.sortOrder.Selected)) iter := lm.AlbumsIter(backend.AlbumSortOrder(a.sortOrder.Selected))
a.grid = widgets.NewAlbumGrid(iter, im.GetAlbumThumbnail, false /*showYear*/) a.grid = widgets.NewAlbumGrid(iter, im, false /*showYear*/)
a.grid.OnPlayAlbum = a.onPlayAlbum a.grid.OnPlayAlbum = a.onPlayAlbum
a.grid.OnShowArtistPage = a.onShowArtistPage a.grid.OnShowArtistPage = a.onShowArtistPage
a.grid.OnShowAlbumPage = a.onShowAlbumPage a.grid.OnShowAlbumPage = a.onShowAlbumPage
@@ -116,7 +116,7 @@ func (a *AlbumsPage) Reload() {
func (a *AlbumsPage) doSearch(query string) { func (a *AlbumsPage) doSearch(query string) {
if a.searchGrid == nil { if a.searchGrid == nil {
a.searchGrid = widgets.NewAlbumGrid(a.lm.SearchIter(query), a.im.GetAlbumThumbnail, false /*showYear*/) a.searchGrid = widgets.NewAlbumGrid(a.lm.SearchIter(query), a.im, false /*showYear*/)
a.searchGrid.OnPlayAlbum = a.onPlayAlbum a.searchGrid.OnPlayAlbum = a.onPlayAlbum
a.searchGrid.OnShowAlbumPage = a.onShowAlbumPage a.searchGrid.OnShowAlbumPage = a.onShowAlbumPage
a.searchGrid.OnShowArtistPage = a.onShowArtistPage a.searchGrid.OnShowArtistPage = a.onShowArtistPage
+1 -1
View File
@@ -76,7 +76,7 @@ func (a *ArtistPage) loadAsync() {
} }
a.titleDisp.Segments[0].(*widget.TextSegment).Text = artist.Name a.titleDisp.Segments[0].(*widget.TextSegment).Text = artist.Name
a.titleDisp.Refresh() a.titleDisp.Refresh()
ag := widgets.NewFixedAlbumGrid(artist.Album, a.im.GetAlbumThumbnail, true /*showYear*/) ag := widgets.NewFixedAlbumGrid(artist.Album, a.im, true /*showYear*/)
ag.OnPlayAlbum = a.onPlayAlbum ag.OnPlayAlbum = a.onPlayAlbum
ag.OnShowAlbumPage = a.onShowAlbumPage ag.OnShowAlbumPage = a.onShowAlbumPage
a.container.Objects[0] = ag a.container.Objects[0] = ag
+2 -2
View File
@@ -45,7 +45,7 @@ func NewGenrePage(genre string, lm *backend.LibraryManager, im *backend.ImageMan
SizeName: theme.SizeNameHeadingText, SizeName: theme.SizeNameHeadingText,
} }
iter := g.lm.GenreIter(g.genre) iter := g.lm.GenreIter(g.genre)
g.grid = widgets.NewAlbumGrid(iter, g.im.GetAlbumThumbnail, false) g.grid = widgets.NewAlbumGrid(iter, g.im, false)
g.grid.OnPlayAlbum = g.onPlayAlbum g.grid.OnPlayAlbum = g.onPlayAlbum
g.grid.OnShowArtistPage = g.onShowArtistPage g.grid.OnShowArtistPage = g.onShowArtistPage
g.grid.OnShowAlbumPage = g.onShowAlbumPage g.grid.OnShowAlbumPage = g.onShowAlbumPage
@@ -115,7 +115,7 @@ func (g *GenrePage) doSearch(query string) {
return al.Genre == g.genre return al.Genre == g.genre
}) })
if g.searchGrid == nil { if g.searchGrid == nil {
g.searchGrid = widgets.NewAlbumGrid(iter, g.im.GetAlbumThumbnail, false /*showYear*/) g.searchGrid = widgets.NewAlbumGrid(iter, g.im, false /*showYear*/)
g.searchGrid.OnPlayAlbum = g.onPlayAlbum g.searchGrid.OnPlayAlbum = g.onPlayAlbum
g.searchGrid.OnShowAlbumPage = g.onShowAlbumPage g.searchGrid.OnShowAlbumPage = g.onShowAlbumPage
g.searchGrid.OnShowArtistPage = g.onShowArtistPage g.searchGrid.OnShowArtistPage = g.onShowArtistPage
+24 -16
View File
@@ -10,7 +10,10 @@ import (
"github.com/dweymouth/go-subsonic" "github.com/dweymouth/go-subsonic"
) )
type ImageFetcher func(string) (image.Image, error) type ImageFetcher interface {
GetAlbumThumbnailFromCache(string) (image.Image, bool)
GetAlbumThumbnail(string) (image.Image, error)
}
type AlbumIterator interface { type AlbumIterator interface {
NextN(int, func(*subsonic.AlbumID3)) NextN(int, func(*subsonic.AlbumID3))
@@ -121,22 +124,27 @@ func (ag *AlbumGrid) doUpdateAlbumCard(albumIdx int, ac *AlbumCard) {
ac.ImgLoadCancel() ac.ImgLoadCancel()
ac.ImgLoadCancel = nil ac.ImgLoadCancel = nil
} }
ctx, cancel := context.WithCancel(context.Background()) if img, ok := ag.imageFetcher.GetAlbumThumbnailFromCache(album.ID); ok {
go func(ctx context.Context) { ac.Cover.SetImage(img)
i, err := ag.imageFetcher(album.ID) ac.Cover.Refresh()
select { } else {
case <-ctx.Done(): ctx, cancel := context.WithCancel(context.Background())
return go func(ctx context.Context) {
default: i, err := ag.imageFetcher.GetAlbumThumbnail(album.ID)
if err == nil { select {
ac.Cover.SetImage(i) case <-ctx.Done():
ac.Cover.Refresh() return
} else { default:
log.Printf("error fetching image: %s", err.Error()) if err == nil {
ac.Cover.SetImage(i)
ac.Cover.Refresh()
} else {
log.Printf("error fetching image: %s", err.Error())
}
} }
} }(ctx)
}(ctx) ac.ImgLoadCancel = cancel
ac.ImgLoadCancel = cancel }
// TODO: remove magic number 10 // TODO: remove magic number 10
if !ag.done && !ag.fetching && albumIdx > len(ag.albums)-10 { if !ag.done && !ag.fetching && albumIdx > len(ag.albums)-10 {