Optimize playlist cover generation

This commit is contained in:
Deluan
2023-01-13 21:33:49 -05:00
committed by Deluan Quintão
parent c46a2a5f5f
commit 16c869ec86
5 changed files with 42 additions and 28 deletions
+18 -19
View File
@@ -8,13 +8,12 @@ import (
"image/draw"
"image/png"
"io"
"math/rand"
"time"
"github.com/disintegration/imaging"
"github.com/navidrome/navidrome/log"
"github.com/navidrome/navidrome/model"
"github.com/navidrome/navidrome/utils/slice"
"golang.org/x/exp/slices"
)
type playlistArtworkReader struct {
@@ -44,18 +43,16 @@ func (a *playlistArtworkReader) LastUpdated() time.Time {
}
func (a *playlistArtworkReader) Reader(ctx context.Context) (io.ReadCloser, string, error) {
var ff []sourceFunc
pl, err := a.a.ds.Playlist(ctx).GetWithTracks(a.pl.ID, false)
if err == nil {
ff = append(ff, a.fromGeneratedTile(ctx, pl.Tracks))
ff := []sourceFunc{
a.fromGeneratedTile(ctx),
fromAlbumPlaceholder(),
}
ff = append(ff, fromAlbumPlaceholder())
return selectImageReader(ctx, a.artID, ff...)
}
func (a *playlistArtworkReader) fromGeneratedTile(ctx context.Context, tracks model.PlaylistTracks) sourceFunc {
func (a *playlistArtworkReader) fromGeneratedTile(ctx context.Context) sourceFunc {
return func() (io.ReadCloser, string, error) {
tiles, err := a.loadTiles(ctx, tracks)
tiles, err := a.loadTiles(ctx)
if err != nil {
return nil, "", err
}
@@ -64,19 +61,21 @@ func (a *playlistArtworkReader) fromGeneratedTile(ctx context.Context, tracks mo
}
}
func compactIDs(tracks model.PlaylistTracks) []model.ArtworkID {
slices.SortFunc(tracks, func(a, b model.PlaylistTrack) bool { return a.AlbumID < b.AlbumID })
tracks = slices.CompactFunc(tracks, func(a, b model.PlaylistTrack) bool { return a.AlbumID == b.AlbumID })
ids := slice.Map(tracks, func(e model.PlaylistTrack) model.ArtworkID {
return e.AlbumCoverArtID()
func toArtworkIDs(albumIDs []string) []model.ArtworkID {
return slice.Map(albumIDs, func(id string) model.ArtworkID {
al := model.Album{ID: id}
return al.CoverArtID()
})
rand.Seed(time.Now().UnixNano())
rand.Shuffle(len(ids), func(i, j int) { ids[i], ids[j] = ids[j], ids[i] })
return ids
}
func (a *playlistArtworkReader) loadTiles(ctx context.Context, t model.PlaylistTracks) ([]image.Image, error) {
ids := compactIDs(t)
func (a *playlistArtworkReader) loadTiles(ctx context.Context) ([]image.Image, error) {
tracksRepo := a.a.ds.Playlist(ctx).Tracks(a.pl.ID, false)
albumIds, err := tracksRepo.GetAlbumIDs(model.QueryOptions{Max: 4, Sort: "random()"})
if err != nil {
log.Error(ctx, "Error getting album IDs for playlist", "id", a.pl.ID, "name", a.pl.Name, err)
return nil, err
}
ids := toArtworkIDs(albumIds)
var tiles []image.Image
for len(tiles) < 4 {
+2 -2
View File
@@ -205,7 +205,7 @@ func (s *playlists) Update(ctx context.Context, playlistID string,
pls.AddTracks(idsToAdd)
} else {
if len(idsToAdd) > 0 {
_, err = repo.Tracks(playlistID).Add(idsToAdd)
_, err = repo.Tracks(playlistID, true).Add(idsToAdd)
if err != nil {
return err
}
@@ -232,7 +232,7 @@ func (s *playlists) Update(ctx context.Context, playlistID string,
}
// Special case: The playlist is now empty
if len(idxToRemove) > 0 && len(pls.Tracks) == 0 {
if err = repo.Tracks(playlistID).DeleteAll(); err != nil {
if err = repo.Tracks(playlistID, true).DeleteAll(); err != nil {
return err
}
}