mirror of
https://github.com/navidrome/navidrome.git
synced 2025-06-06 18:33:10 +03:00
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:
parent
1bc68c20fc
commit
a1ba5c59b2
@ -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) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user