Better error handling

This commit is contained in:
Deluan 2022-12-28 10:19:52 -05:00 committed by Deluan Quintão
parent 949331ed24
commit bc09de6640
8 changed files with 37 additions and 43 deletions

View file

@ -52,10 +52,13 @@ func (a *artwork) Get(ctx context.Context, id string, size int) (reader io.ReadC
}
r, err := a.cache.Get(ctx, artReader)
if err != nil && !errors.Is(err, context.Canceled) {
log.Error(ctx, "Error accessing image cache", "id", id, "size", size, err)
if err != nil {
if !errors.Is(err, context.Canceled) {
log.Error(ctx, "Error accessing image cache", "id", id, "size", size, err)
}
return nil, time.Time{}, err
}
return r, artReader.LastUpdated(), err
return r, artReader.LastUpdated(), nil
}
func (a *artwork) getArtworkReader(ctx context.Context, artID model.ArtworkID, size int) (artworkReader, error) {
@ -72,7 +75,7 @@ func (a *artwork) getArtworkReader(ctx context.Context, artID model.ArtworkID, s
case model.KindPlaylistArtwork:
artReader, err = newPlaylistArtworkReader(ctx, a, artID)
default:
artReader, err = newPlaceholderReader(ctx, artID)
artReader, err = newEmptyIDReader(ctx, artID)
}
}
return artReader, err

View file

@ -38,8 +38,7 @@ func (a *albumArtworkReader) LastUpdated() time.Time {
func (a *albumArtworkReader) Reader(ctx context.Context) (io.ReadCloser, string, error) {
var ff = fromCoverArtPriority(ctx, a.a.ffmpeg, conf.Server.CoverArtPriority, a.album)
ff = append(ff, fromPlaceholder())
r, source := extractImage(ctx, a.artID, ff...)
return r, source, nil
return selectImageReader(ctx, a.artID, ff...)
}
func fromCoverArtPriority(ctx context.Context, ffmpeg ffmpeg.FFmpeg, priority string, al model.Album) []sourceFunc {

View file

@ -7,29 +7,29 @@ import (
"time"
"github.com/navidrome/navidrome/conf"
"github.com/navidrome/navidrome/consts"
"github.com/navidrome/navidrome/model"
)
type placeholderReader struct {
type emptyIDReader struct {
artID model.ArtworkID
}
func newPlaceholderReader(_ context.Context, artID model.ArtworkID) (*placeholderReader, error) {
a := &placeholderReader{
func newEmptyIDReader(_ context.Context, artID model.ArtworkID) (*emptyIDReader, error) {
a := &emptyIDReader{
artID: artID,
}
return a, nil
}
func (a *placeholderReader) LastUpdated() time.Time {
return time.Now() // Basically make it non-cacheable
func (a *emptyIDReader) LastUpdated() time.Time {
return consts.ServerStart // Invalidate cached placeholder every server start
}
func (a *placeholderReader) Key() string {
return fmt.Sprintf("0.%d.0.%d", a.LastUpdated().UnixMilli(), conf.Server.CoverJpegQuality)
func (a *emptyIDReader) Key() string {
return fmt.Sprintf("placeholder.%d.0.%d", a.LastUpdated().UnixMilli(), conf.Server.CoverJpegQuality)
}
func (a *placeholderReader) Reader(ctx context.Context) (io.ReadCloser, string, error) {
r, source := extractImage(ctx, a.artID, fromPlaceholder())
return r, source, nil
func (a *emptyIDReader) Reader(ctx context.Context) (io.ReadCloser, string, error) {
return selectImageReader(ctx, a.artID, fromPlaceholder())
}

View file

@ -51,8 +51,7 @@ func (a *mediafileArtworkReader) Reader(ctx context.Context) (io.ReadCloser, str
}
}
ff = append(ff, fromAlbum(ctx, a.a, a.mediafile.AlbumCoverArtID()))
r, source := extractImage(ctx, a.artID, ff...)
return r, source, nil
return selectImageReader(ctx, a.artID, ff...)
}
func fromAlbum(ctx context.Context, a *artwork, id model.ArtworkID) sourceFunc {

View file

@ -49,8 +49,7 @@ func (a *playlistArtworkReader) Reader(ctx context.Context) (io.ReadCloser, stri
ff = append(ff, a.fromGeneratedTile(ctx, pl.Tracks))
}
ff = append(ff, fromPlaceholder())
r, source := extractImage(ctx, a.artID, ff...)
return r, source, nil
return selectImageReader(ctx, a.artID, ff...)
}
func (a *playlistArtworkReader) fromGeneratedTile(ctx context.Context, tracks model.PlaylistTracks) sourceFunc {
@ -129,7 +128,10 @@ func (a *playlistArtworkReader) createTiledImage(_ context.Context, tiles []imag
} else {
err = png.Encode(buf, tiles[0])
}
return io.NopCloser(buf), err
if err != nil {
return nil, err
}
return io.NopCloser(buf), nil
}
func rect(pos int) image.Rectangle {

View file

@ -54,7 +54,7 @@ func (a *resizedArtworkReader) Reader(ctx context.Context) (io.ReadCloser, strin
r := io.TeeReader(orig, buf)
defer orig.Close()
resized, origSize, err := resizeImageIntoReader(r, a.size)
resized, origSize, err := resizeImage(r, a.size)
log.Trace(ctx, "Resizing artwork", "artID", a.artID, "original", origSize, "resized", a.size)
if err != nil {
log.Warn(ctx, "Could not resize image. Will return image as is", "artID", a.artID, "size", a.size, err)
@ -74,7 +74,12 @@ func asImageReader(r io.Reader) (io.Reader, string, error) {
return br, http.DetectContentType(buf), nil
}
func resizeImage(r io.Reader, size int) (image.Image, int, error) {
func resizeImage(reader io.Reader, size int) (io.Reader, int, error) {
r, format, err := asImageReader(reader)
if err != nil {
return nil, 0, err
}
img, _, err := image.Decode(r)
if err != nil {
return nil, 0, err
@ -89,20 +94,6 @@ func resizeImage(r io.Reader, size int) (image.Image, int, error) {
m = imaging.Resize(img, 0, size, imaging.Lanczos)
}
return m, number.Max(bounds.Max.X, bounds.Max.Y), err
}
func resizeImageIntoReader(reader io.Reader, size int) (io.Reader, int, error) {
r, format, err := asImageReader(reader)
if err != nil {
return nil, 0, err
}
m, origSize, err := resizeImage(r, size)
if err != nil {
return nil, 0, err
}
buf := new(bytes.Buffer)
buf.Reset()
if format == "image/png" {
@ -110,5 +101,5 @@ func resizeImageIntoReader(reader io.Reader, size int) (io.Reader, int, error) {
} else {
err = jpeg.Encode(buf, m, &jpeg.Options{Quality: conf.Server.CoverJpegQuality})
}
return buf, origSize, err
return buf, number.Max(bounds.Max.X, bounds.Max.Y), err
}

View file

@ -19,20 +19,19 @@ import (
"github.com/navidrome/navidrome/resources"
)
func extractImage(ctx context.Context, artID model.ArtworkID, extractFuncs ...sourceFunc) (io.ReadCloser, string) {
func selectImageReader(ctx context.Context, artID model.ArtworkID, extractFuncs ...sourceFunc) (io.ReadCloser, string, error) {
for _, f := range extractFuncs {
if ctx.Err() != nil {
return nil, ""
return nil, "", ctx.Err()
}
r, path, err := f()
if r != nil {
log.Trace(ctx, "Found artwork", "artID", artID, "path", path, "source", f)
return r, path
return r, path, nil
}
log.Trace(ctx, "Tried to extract artwork", "artID", artID, "source", f, err)
}
log.Error(ctx, "extractImage should never reach this point!", "artID", artID, "path")
return nil, ""
return nil, "", fmt.Errorf("could not get a cover art for %s", artID)
}
type sourceFunc func() (r io.ReadCloser, path string, err error)

View file

@ -47,6 +47,7 @@ const getScanStatus = () => httpClient(url('getScanStatus'))
const getCoverArtUrl = (record, size) => {
const options = {
...(record.updatedAt && { _: record.updatedAt }),
...(size && { size }),
}