diff --git a/persistence/album_repository.go b/persistence/album_repository.go index 66632bdac..1ebb09751 100644 --- a/persistence/album_repository.go +++ b/persistence/album_repository.go @@ -259,14 +259,8 @@ func (r *albumRepository) GetAll(options ...model.QueryOptions) (model.Albums, e } func (r *albumRepository) hydrateArtwork(albums model.Albums) { - if len(albums) == 0 { - return - } - ids := slice.Map(albums, func(a model.Album) string { return a.ID }) - infos := hydrateItemImages(r.ctx, r.db, model.KindAlbumArtwork, ids) - for i := range albums { - applyItemImage(infos, albums[i].ID, &albums[i].ItemImage) - } + hydrateItems(r.ctx, r.db, model.KindAlbumArtwork, albums, + func(a *model.Album) (string, *model.ItemImage) { return a.ID, &a.ItemImage }) } // GetAllIDs returns the IDs of GetAll's row set, skipping its column projection and JSON decoding. diff --git a/persistence/artist_repository.go b/persistence/artist_repository.go index c5c3a2444..67d0df448 100644 --- a/persistence/artist_repository.go +++ b/persistence/artist_repository.go @@ -279,14 +279,8 @@ func (r *artistRepository) GetAllIDs(options ...model.QueryOptions) ([]string, e // hydrateArtwork fills each artist's ImageHash/ImageAbsent from one batched item_artwork lookup. func (r *artistRepository) hydrateArtwork(artists model.Artists) { - if len(artists) == 0 { - return - } - ids := slice.Map(artists, func(a model.Artist) string { return a.ID }) - infos := hydrateItemImages(r.ctx, r.db, model.KindArtistArtwork, ids) - for i := range artists { - applyItemImage(infos, artists[i].ID, &artists[i].ItemImage) - } + hydrateItems(r.ctx, r.db, model.KindArtistArtwork, artists, + func(a *model.Artist) (string, *model.ItemImage) { return a.ID, &a.ItemImage }) } func (r *artistRepository) GetCursor(options ...model.QueryOptions) (model.ArtistCursor, error) { diff --git a/persistence/artwork_hydration.go b/persistence/artwork_hydration.go index 0e8edce6e..fa9920f27 100644 --- a/persistence/artwork_hydration.go +++ b/persistence/artwork_hydration.go @@ -74,6 +74,21 @@ func applyItemImage(infos map[string]model.ItemArtworkInfo, id string, img *mode } } +// hydrateItems fills every item's embedded ItemImage from one batched lookup. ref yields an +// item's id and the ItemImage to fill, which is all that differs between the entity kinds. +func hydrateItems[T any](ctx context.Context, db dbx.Builder, kind model.Kind, items []T, + ref func(*T) (string, *model.ItemImage)) { + ids := make([]string, len(items)) + for i := range items { + ids[i], _ = ref(&items[i]) + } + infos := hydrateItemImages(ctx, db, kind, ids) + for i := range items { + id, img := ref(&items[i]) + applyItemImage(infos, id, img) + } +} + // hydrateMediaFileArtwork mirrors MediaFile.CoverArtID: an embedded-eligible file with resolved own // art uses it, else it falls back to the album's. func hydrateMediaFileArtwork(ctx context.Context, db dbx.Builder, mfs model.MediaFiles) { diff --git a/persistence/playlist_repository.go b/persistence/playlist_repository.go index 1ae1ce43e..081dab3fa 100644 --- a/persistence/playlist_repository.go +++ b/persistence/playlist_repository.go @@ -13,7 +13,6 @@ import ( "github.com/deluan/rest" "github.com/navidrome/navidrome/log" "github.com/navidrome/navidrome/model" - "github.com/navidrome/navidrome/utils/slice" "github.com/pocketbase/dbx" ) @@ -185,14 +184,8 @@ func (r *playlistRepository) findBy(sql Sqlizer) (*model.Playlist, error) { } func (r *playlistRepository) hydrateArtwork(playlists model.Playlists) { - if len(playlists) == 0 { - return - } - ids := slice.Map(playlists, func(p model.Playlist) string { return p.ID }) - infos := hydrateItemImages(r.ctx, r.db, model.KindPlaylistArtwork, ids) - for i := range playlists { - applyItemImage(infos, playlists[i].ID, &playlists[i].ItemImage) - } + hydrateItems(r.ctx, r.db, model.KindPlaylistArtwork, playlists, + func(p *model.Playlist) (string, *model.ItemImage) { return p.ID, &p.ItemImage }) } func (r *playlistRepository) GetAll(options ...model.QueryOptions) (model.Playlists, error) { diff --git a/persistence/radio_repository.go b/persistence/radio_repository.go index 01558e541..b73487e40 100644 --- a/persistence/radio_repository.go +++ b/persistence/radio_repository.go @@ -10,7 +10,6 @@ import ( "github.com/navidrome/navidrome/log" "github.com/navidrome/navidrome/model" "github.com/navidrome/navidrome/model/id" - "github.com/navidrome/navidrome/utils/slice" "github.com/pocketbase/dbx" ) @@ -76,14 +75,8 @@ func (r *radioRepository) GetAll(options ...model.QueryOptions) (model.Radios, e // hydrateArtwork fills each radio's ImageHash/ImageAbsent from one batched item_artwork lookup. func (r *radioRepository) hydrateArtwork(radios model.Radios) { - if len(radios) == 0 { - return - } - ids := slice.Map(radios, func(rd model.Radio) string { return rd.ID }) - infos := hydrateItemImages(r.ctx, r.db, model.KindRadioArtwork, ids) - for i := range radios { - applyItemImage(infos, radios[i].ID, &radios[i].ItemImage) - } + hydrateItems(r.ctx, r.db, model.KindRadioArtwork, radios, + func(rd *model.Radio) (string, *model.ItemImage) { return rd.ID, &rd.ItemImage }) } // GetAllIDs returns just the radio IDs. Used by bulk enumeration (artwork backfill).