Returns default cover on any error (not found, encoding, or unknown)

Only returns error if it cannot read the default image
This commit is contained in:
Deluan 2020-04-05 17:53:55 -04:00 committed by Deluan Quintão
parent 1bc68c20fc
commit a1ba5c59b2

View File

@ -9,10 +9,10 @@ import (
"image/jpeg" "image/jpeg"
_ "image/png" _ "image/png"
"io" "io"
"net/http"
"os" "os"
"path/filepath" "path/filepath"
"strings" "strings"
"time"
"github.com/deluan/navidrome/conf" "github.com/deluan/navidrome/conf"
"github.com/deluan/navidrome/consts" "github.com/deluan/navidrome/consts"
@ -40,74 +40,82 @@ type cover struct {
cache fscache.Cache cache fscache.Cache
} }
func (c *cover) getCoverPath(ctx context.Context, id string) (string, error) { func (c *cover) getCoverPath(ctx context.Context, id string) (string, *time.Time, error) {
var found bool var found bool
var err error var err error
if found, err = c.ds.Album(ctx).Exists(id); err != nil { if found, err = c.ds.Album(ctx).Exists(id); err != nil {
return "", err return "", nil, err
} }
if found { if found {
al, err := c.ds.Album(ctx).Get(id) al, err := c.ds.Album(ctx).Get(id)
if err != nil { if err != nil {
return "", err return "", nil, err
} }
if al.CoverArtId == "" { if al.CoverArtId == "" {
return "", model.ErrNotFound return "", nil, model.ErrNotFound
} }
return al.CoverArtPath, nil id = al.CoverArtId
} }
mf, err := c.ds.MediaFile(ctx).Get(id) mf, err := c.ds.MediaFile(ctx).Get(id)
if err != nil { if err != nil {
return "", err return "", nil, err
} }
if mf.HasCoverArt { if mf.HasCoverArt {
return mf.Path, nil return mf.Path, &mf.UpdatedAt, nil
} }
return "", model.ErrNotFound return "", nil, model.ErrNotFound
} }
func (c *cover) Get(ctx context.Context, id string, size int, out io.Writer) error { func (c *cover) Get(ctx context.Context, id string, size int, out io.Writer) error {
id = strings.TrimPrefix(id, "al-") id = strings.TrimPrefix(id, "al-")
path, err := c.getCoverPath(ctx, id) path, _, err := c.getCoverPath(ctx, id)
if err != nil && err != model.ErrNotFound { if err != nil && err != model.ErrNotFound {
return err return err
} }
var reader io.Reader reader, err := c.getCover(ctx, path, size)
if err != model.ErrNotFound {
reader, err = readFromTag(path)
} else {
var f http.File
f, err = static.AssetFile().Open("default_cover.jpg")
if err == nil {
defer f.Close()
reader = f
}
}
if err != nil { if err != nil {
return model.ErrNotFound return err
}
if size > 0 {
return resizeImage(reader, size, out)
} }
_, err = io.Copy(out, reader) _, err = io.Copy(out, reader)
return err return err
} }
func resizeImage(reader io.Reader, size int, out io.Writer) error { func (c *cover) getCover(ctx context.Context, path string, size int) (reader io.Reader, err error) {
img, _, err := image.Decode(reader) defer func() {
if err != nil { if err != nil {
return err log.Warn(ctx, "Error extracting image", "path", path, "size", size, err)
reader, err = static.AssetFile().Open("navidrome-310x310.png")
}
}()
var data []byte
data, err = readFromTag(path)
if err == nil && size > 0 {
data, err = resizeImage(bytes.NewReader(data), size)
} }
m := imaging.Resize(img, size, size, imaging.Lanczos) // Confirm the image is valid. Costly, but necessary
return jpeg.Encode(out, m, &jpeg.Options{Quality: 75}) _, _, err = image.Decode(bytes.NewReader(data))
if err == nil {
reader = bytes.NewReader(data)
}
return
} }
func readFromTag(path string) (io.Reader, error) { func resizeImage(reader io.Reader, size int) ([]byte, error) {
img, _, err := image.Decode(reader)
if err != nil {
return nil, err
}
m := imaging.Resize(img, size, size, imaging.Lanczos)
buf := new(bytes.Buffer)
err = jpeg.Encode(buf, m, &jpeg.Options{Quality: 75})
return buf.Bytes(), err
}
func readFromTag(path string) ([]byte, error) {
f, err := os.Open(path) f, err := os.Open(path)
if err != nil { if err != nil {
return nil, err return nil, err
@ -121,9 +129,9 @@ func readFromTag(path string) (io.Reader, error) {
picture := m.Picture() picture := m.Picture()
if picture == nil { if picture == nil {
return nil, errors.New("error extracting art from file " + path) return nil, errors.New("file does not contain embedded art")
} }
return bytes.NewReader(picture.Data), nil return picture.Data, nil
} }
func NewImageCache() (ImageCache, error) { func NewImageCache() (ImageCache, error) {