Files
navidrome/core/artwork.go
T
2022-12-28 15:31:56 -05:00

97 lines
2.1 KiB
Go

package core
import (
"bytes"
"context"
"errors"
_ "image/gif"
_ "image/png"
"io"
"os"
"github.com/dhowden/tag"
"github.com/navidrome/navidrome/consts"
"github.com/navidrome/navidrome/log"
"github.com/navidrome/navidrome/model"
"github.com/navidrome/navidrome/resources"
_ "golang.org/x/image/webp"
)
type Artwork interface {
Get(ctx context.Context, id string, size int) (io.ReadCloser, error)
}
func NewArtwork(ds model.DataStore) Artwork {
return &artwork{ds: ds}
}
type artwork struct {
ds model.DataStore
}
func (a *artwork) Get(ctx context.Context, id string, size int) (io.ReadCloser, error) {
r, _, err := a.get(ctx, id, size)
return r, err
}
func (a *artwork) get(ctx context.Context, id string, size int) (io.ReadCloser, string, error) {
artId, err := model.ParseArtworkID(id)
if err != nil {
return nil, "", errors.New("invalid ID")
}
id = artId.ID
al, err := a.ds.Album(ctx).Get(id)
if errors.Is(err, model.ErrNotFound) {
r, path := fromPlaceholder()()
return r, path, nil
}
if err != nil {
return nil, "", err
}
r, path := extractImage(ctx, artId,
fromTag(al.EmbedArtPath),
fromPlaceholder(),
)
return r, path, nil
}
func extractImage(ctx context.Context, artId model.ArtworkID, extractFuncs ...func() (io.ReadCloser, string)) (io.ReadCloser, string) {
for _, f := range extractFuncs {
r, path := f()
if r != nil {
log.Trace(ctx, "Found artwork", "artId", artId, "path", path)
return r, path
}
}
log.Error(ctx, "extractImage should never reach this point!", "artId", artId, "path")
return nil, ""
}
func fromTag(path string) func() (io.ReadCloser, string) {
return func() (io.ReadCloser, string) {
f, err := os.Open(path)
if err != nil {
return nil, ""
}
defer f.Close()
m, err := tag.ReadFrom(f)
if err != nil {
return nil, ""
}
picture := m.Picture()
if picture == nil {
return nil, ""
}
return io.NopCloser(bytes.NewReader(picture.Data)), path
}
}
func fromPlaceholder() func() (io.ReadCloser, string) {
return func() (io.ReadCloser, string) {
r, _ := resources.FS().Open(consts.PlaceholderAlbumArt)
return r, consts.PlaceholderAlbumArt
}
}