use coverArt ID instead of album ID to fetch images

This commit is contained in:
Drew Weymouth
2023-03-20 18:14:02 -07:00
parent 9ad76397ff
commit 163d195032
7 changed files with 40 additions and 46 deletions
+4 -4
View File
@@ -126,7 +126,7 @@ func (r *baseIter) Next() *subsonic.AlbumID3 {
r.prefetchedPos = 1 r.prefetchedPos = 1
if r.l.PreCacheCoverFn != nil { if r.l.PreCacheCoverFn != nil {
for _, album := range albums { for _, album := range albums {
go r.l.PreCacheCoverFn(album.ID) go r.l.PreCacheCoverFn(album.CoverArt)
} }
} }
@@ -230,7 +230,7 @@ func (s *searchIter) addNewAlbums(al []*subsonic.AlbumID3) {
} }
s.prefetched = append(s.prefetched, album) s.prefetched = append(s.prefetched, album)
if s.l.PreCacheCoverFn != nil { if s.l.PreCacheCoverFn != nil {
go s.l.PreCacheCoverFn(album.ID) go s.l.PreCacheCoverFn(album.CoverArt)
} }
s.albumIDset[album.ID] = true s.albumIDset[album.ID] = true
} }
@@ -284,7 +284,7 @@ func (r *randomIter) Next() *subsonic.AlbumID3 {
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 { if r.l.PreCacheCoverFn != nil {
go r.l.PreCacheCoverFn(album.ID) go r.l.PreCacheCoverFn(album.CoverArt)
} }
r.albumIDSet[album.ID] = true r.albumIDSet[album.ID] = true
} }
@@ -305,7 +305,7 @@ func (r *randomIter) Next() *subsonic.AlbumID3 {
hitCount++ hitCount++
r.prefetched = append(r.prefetched, album) r.prefetched = append(r.prefetched, album)
if r.l.PreCacheCoverFn != nil { if r.l.PreCacheCoverFn != nil {
go r.l.PreCacheCoverFn(album.ID) go r.l.PreCacheCoverFn(album.CoverArt)
} }
r.albumIDSet[album.ID] = true r.albumIDSet[album.ID] = true
} }
+2 -2
View File
@@ -55,8 +55,8 @@ 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.bgrndCtx, a.ServerManager, configdir.LocalCache(AppName)) a.ImageManager = NewImageManager(a.bgrndCtx, a.ServerManager, configdir.LocalCache(AppName))
a.LibraryManager.PreCacheCoverFn = func(albumID string) { a.LibraryManager.PreCacheCoverFn = func(coverID string) {
_, _ = a.ImageManager.GetAlbumThumbnail(albumID) _, _ = a.ImageManager.GetAlbumThumbnail(coverID)
} }
return a, nil return a, nil
+25 -25
View File
@@ -45,39 +45,39 @@ func NewImageManager(ctx context.Context, s *ServerManager, baseCacheDir string)
return i return i
} }
func (i *ImageManager) GetAlbumThumbnailFromCache(albumID string) (image.Image, bool) { func (i *ImageManager) GetAlbumThumbnailFromCache(coverID string) (image.Image, bool) {
img, err := i.thumbnailCache.GetExtendTTL(albumID, i.thumbnailCache.DefaultTTL) img, err := i.thumbnailCache.GetExtendTTL(coverID, i.thumbnailCache.DefaultTTL)
if err == nil && img != nil { if err == nil && img != nil {
return img, true return img, true
} }
return nil, false return nil, false
} }
func (i *ImageManager) GetAlbumThumbnail(albumID string) (image.Image, error) { func (i *ImageManager) GetAlbumThumbnail(coverID string) (image.Image, error) {
if im, ok := i.GetAlbumThumbnailFromCache(albumID); ok { if im, ok := i.GetAlbumThumbnailFromCache(coverID); ok {
return im, nil return im, nil
} }
return i.fetchAndCacheCoverFromDiskOrServer(albumID, i.thumbnailCache.DefaultTTL) return i.fetchAndCacheCoverFromDiskOrServer(coverID, i.thumbnailCache.DefaultTTL)
} }
func (i *ImageManager) GetAlbumThumbnailWithTTL(albumID string, ttl time.Duration) (image.Image, error) { func (i *ImageManager) GetAlbumThumbnailWithTTL(coverID string, ttl time.Duration) (image.Image, error) {
// in-memory cache // in-memory cache
if img, err := i.thumbnailCache.GetWithNewTTL(albumID, ttl); err == nil { if img, err := i.thumbnailCache.GetWithNewTTL(coverID, ttl); err == nil {
return img, nil return img, nil
} }
return i.fetchAndCacheCoverFromDiskOrServer(albumID, ttl) return i.fetchAndCacheCoverFromDiskOrServer(coverID, ttl)
} }
func (i *ImageManager) GetFullSizeAlbumCover(albumID string) (image.Image, error) { func (i *ImageManager) GetFullSizeAlbumCover(coverID string) (image.Image, error) {
if i.cachedFullSizeCoverID == albumID { if i.cachedFullSizeCoverID == coverID {
return i.cachedFullSizeCover, nil return i.cachedFullSizeCover, nil
} }
im, err := i.s.Server.GetCoverArt(albumID, nil) im, err := i.s.Server.GetCoverArt(coverID, nil)
if err != nil { if err != nil {
return nil, err return nil, err
} }
i.cachedFullSizeCover = im i.cachedFullSizeCover = im
i.cachedFullSizeCoverID = albumID i.cachedFullSizeCoverID = coverID
return im, nil return im, nil
} }
@@ -126,43 +126,43 @@ func (i *ImageManager) fetchRemoteArtistImage(url string) (image.Image, error) {
return nil, err return nil, err
} }
func (i *ImageManager) fetchAndCacheCoverFromDiskOrServer(albumID string, ttl time.Duration) (image.Image, error) { func (i *ImageManager) fetchAndCacheCoverFromDiskOrServer(coverID string, ttl time.Duration) (image.Image, error) {
// on disc cache // on disc cache
path := i.filePathForCover(albumID) path := i.filePathForCover(coverID)
if i.ensureCoverCacheDir() != "" { if i.ensureCoverCacheDir() != "" {
if s, err := os.Stat(path); err == nil { if s, err := os.Stat(path); err == nil {
go i.checkRefreshLocalCover(s, albumID, ttl) go i.checkRefreshLocalCover(s, coverID, ttl)
if img, ok := i.loadLocalImage(path); ok { if img, ok := i.loadLocalImage(path); ok {
i.thumbnailCache.SetWithTTL(albumID, img, ttl) i.thumbnailCache.SetWithTTL(coverID, img, ttl)
return img, nil return img, nil
} }
} }
} }
return i.fetchAndCacheCoverFromServer(albumID, ttl) return i.fetchAndCacheCoverFromServer(coverID, ttl)
} }
func (i *ImageManager) fetchAndCacheCoverFromServer(albumID string, ttl time.Duration) (image.Image, error) { func (i *ImageManager) fetchAndCacheCoverFromServer(coverID string, ttl time.Duration) (image.Image, error) {
img, err := i.s.Server.GetCoverArt(albumID, map[string]string{"size": "300"}) img, err := i.s.Server.GetCoverArt(coverID, map[string]string{"size": "300"})
if err != nil { if err != nil {
return nil, err return nil, err
} }
if i.ensureCoverCacheDir() != "" { if i.ensureCoverCacheDir() != "" {
path := i.filePathForCover(albumID) path := i.filePathForCover(coverID)
_ = i.writeJpeg(img, path) _ = i.writeJpeg(img, path)
} }
i.thumbnailCache.SetWithTTL(albumID, img, ttl) i.thumbnailCache.SetWithTTL(coverID, img, ttl)
return img, nil return img, nil
} }
func (i *ImageManager) checkRefreshLocalCover(stat os.FileInfo, albumID string, ttl time.Duration) { func (i *ImageManager) checkRefreshLocalCover(stat os.FileInfo, coverID string, ttl time.Duration) {
if time.Since(stat.ModTime()) > CachedImageValidTime { if time.Since(stat.ModTime()) > CachedImageValidTime {
i.fetchAndCacheCoverFromServer(albumID, ttl) i.fetchAndCacheCoverFromServer(coverID, ttl)
} }
} }
func (i *ImageManager) filePathForCover(albumID string) string { func (i *ImageManager) filePathForCover(coverID string) string {
return filepath.Join(i.ensureCoverCacheDir(), fmt.Sprintf("%s.jpg", albumID)) return filepath.Join(i.ensureCoverCacheDir(), fmt.Sprintf("%s.jpg", coverID))
} }
func (i *ImageManager) filePathForArtistImage(id string) string { func (i *ImageManager) filePathForArtistImage(id string) string {
+1 -1
View File
@@ -9,7 +9,7 @@ type AlbumIterator interface {
} }
type LibraryManager struct { type LibraryManager struct {
PreCacheCoverFn func(string) PreCacheCoverFn func(coverID string)
s *ServerManager s *ServerManager
} }
+1 -1
View File
@@ -95,7 +95,7 @@ func (bp *BottomPanel) onSongChange(song *subsonic.Child, _ *subsonic.Child) {
// be in cache for the next song if it's from the same album, or // be in cache for the next song if it's from the same album, or
// if the user navigates to the album page for the track // if the user navigates to the album page for the track
imgTTLSec := song.Duration + 30 imgTTLSec := song.Duration + 30
im, _ = bp.ImageManager.GetAlbumThumbnailWithTTL(song.AlbumID, time.Duration(imgTTLSec)*time.Second) im, _ = bp.ImageManager.GetAlbumThumbnailWithTTL(song.CoverArt, time.Duration(imgTTLSec)*time.Second)
} }
bp.NowPlaying.Update(song.Title, song.Artist, song.Album, im) bp.NowPlaying.Update(song.Title, song.Artist, song.Album, im)
} }
+5 -11
View File
@@ -129,6 +129,7 @@ type AlbumPageHeader struct {
widget.BaseWidget widget.BaseWidget
albumID string albumID string
coverID string
artistID string artistID string
genre string genre string
@@ -151,11 +152,7 @@ func NewAlbumPageHeader(page *AlbumPage) *AlbumPageHeader {
a.cover = widgets.NewTappableImage(func() { go a.showPopUpCover() }) a.cover = widgets.NewTappableImage(func() { go a.showPopUpCover() })
a.cover.FillMode = canvas.ImageFillContain a.cover.FillMode = canvas.ImageFillContain
a.cover.SetMinSize(fyne.NewSize(225, 225)) a.cover.SetMinSize(fyne.NewSize(225, 225))
// due to cache warming we can probably immediately set the cover
// and not have to set it asynchronously in the Update function
if im, ok := page.im.GetAlbumThumbnailFromCache(page.albumID); ok {
a.cover.Image.Image = im
}
a.titleLabel = widget.NewRichTextWithText("") a.titleLabel = widget.NewRichTextWithText("")
a.titleLabel.Wrapping = fyne.TextTruncate a.titleLabel.Wrapping = fyne.TextTruncate
a.titleLabel.Segments[0].(*widget.TextSegment).Style = widget.RichTextStyle{ a.titleLabel.Segments[0].(*widget.TextSegment).Style = widget.RichTextStyle{
@@ -201,6 +198,7 @@ func (a *AlbumPageHeader) CreateRenderer() fyne.WidgetRenderer {
func (a *AlbumPageHeader) Update(album *subsonic.AlbumID3, im *backend.ImageManager) { func (a *AlbumPageHeader) Update(album *subsonic.AlbumID3, im *backend.ImageManager) {
a.albumID = album.ID a.albumID = album.ID
a.coverID = album.CoverArt
a.artistID = album.ArtistID a.artistID = album.ArtistID
a.titleLabel.Segments[0].(*widget.TextSegment).Text = album.Name a.titleLabel.Segments[0].(*widget.TextSegment).Text = album.Name
a.artistLabel.SetText(album.Artist) a.artistLabel.SetText(album.Artist)
@@ -210,12 +208,8 @@ func (a *AlbumPageHeader) Update(album *subsonic.AlbumID3, im *backend.ImageMana
a.toggleFavButton.IsFavorited = !album.Starred.IsZero() a.toggleFavButton.IsFavorited = !album.Starred.IsZero()
a.Refresh() a.Refresh()
// cover image was already loaded from cache in consructor
if a.albumID == album.ID && a.cover.Image.Image != nil {
return
}
go func() { go func() {
if cover, err := im.GetAlbumThumbnail(album.ID); err == nil { if cover, err := im.GetAlbumThumbnail(album.CoverArt); err == nil {
a.cover.Image.Image = cover a.cover.Image.Image = cover
a.cover.Refresh() a.cover.Refresh()
} else { } else {
@@ -233,7 +227,7 @@ func (a *AlbumPageHeader) toggleFavorited() {
} }
func (a *AlbumPageHeader) showPopUpCover() { func (a *AlbumPageHeader) showPopUpCover() {
cover, err := a.page.im.GetFullSizeAlbumCover(a.albumID) cover, err := a.page.im.GetFullSizeAlbumCover(a.coverID)
if err != nil { if err != nil {
log.Printf("error getting full size album cover: %s", err.Error()) log.Printf("error getting full size album cover: %s", err.Error())
return return
+2 -2
View File
@@ -154,7 +154,7 @@ func (ag *AlbumGrid) doUpdateAlbumCard(albumIdx int, ac *AlbumCard) {
ac.ImgLoadCancel() ac.ImgLoadCancel()
ac.ImgLoadCancel = nil ac.ImgLoadCancel = nil
} }
if img, ok := ag.imageFetcher.GetAlbumThumbnailFromCache(album.ID); ok { if img, ok := ag.imageFetcher.GetAlbumThumbnailFromCache(album.CoverArt); ok {
ac.Cover.SetImage(img) ac.Cover.SetImage(img)
} else { } else {
ac.Cover.SetImageResource(res.ResAlbumplaceholderPng) ac.Cover.SetImageResource(res.ResAlbumplaceholderPng)
@@ -162,7 +162,7 @@ func (ag *AlbumGrid) doUpdateAlbumCard(albumIdx int, ac *AlbumCard) {
ctx, cancel := context.WithCancel(context.Background()) ctx, cancel := context.WithCancel(context.Background())
ac.ImgLoadCancel = cancel ac.ImgLoadCancel = cancel
go func(ctx context.Context) { go func(ctx context.Context) {
i, err := ag.imageFetcher.GetAlbumThumbnail(album.ID) i, err := ag.imageFetcher.GetAlbumThumbnail(album.CoverArt)
select { select {
case <-ctx.Done(): case <-ctx.Done():
return return