Load artwork from embedded

This commit is contained in:
Deluan
2022-12-19 15:34:21 -05:00
committed by Deluan Quintão
parent c36e77d41f
commit 7b87386089
8 changed files with 143 additions and 37 deletions
+68 -1
View File
@@ -1,12 +1,17 @@
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"
@@ -25,5 +30,67 @@ type artwork struct {
}
func (a *artwork) Get(ctx context.Context, id string, size int) (io.ReadCloser, error) {
return resources.FS().Open(consts.PlaceholderAlbumArt)
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
}
}
+60
View File
@@ -0,0 +1,60 @@
package core
import (
"context"
"github.com/navidrome/navidrome/consts"
"github.com/navidrome/navidrome/log"
"github.com/navidrome/navidrome/model"
"github.com/navidrome/navidrome/tests"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
)
var _ = FDescribe("Artwork", func() {
var aw *artwork
var ds model.DataStore
ctx := log.NewContext(context.TODO())
var alOnlyEmbed, alEmbedNotFound model.Album
BeforeEach(func() {
ds = &tests.MockDataStore{MockedTranscoding: &tests.MockTranscodingRepo{}}
alOnlyEmbed = model.Album{ID: "222", Name: "Only embed", EmbedArtPath: "tests/fixtures/test.mp3"}
alEmbedNotFound = model.Album{ID: "333", Name: "Embed not found", EmbedArtPath: "tests/fixtures/NON_EXISTENT.mp3"}
// {ID: "666", Name: "All options", EmbedArtPath: "tests/fixtures/test.mp3",
// ImageFiles: "tests/fixtures/cover.jpg:tests/fixtures/front.png"},
//})
aw = NewArtwork(ds).(*artwork)
})
When("cover art is not found", func() {
BeforeEach(func() {
ds.Album(ctx).(*tests.MockAlbumRepo).SetData(model.Albums{
alOnlyEmbed,
})
})
It("returns placeholder if album is not in the DB", func() {
_, path, err := aw.get(context.Background(), "al-999-0", 0)
Expect(err).ToNot(HaveOccurred())
Expect(path).To(Equal(consts.PlaceholderAlbumArt))
})
})
When("album has only embed images", func() {
BeforeEach(func() {
ds.Album(ctx).(*tests.MockAlbumRepo).SetData(model.Albums{
alOnlyEmbed,
alEmbedNotFound,
})
})
It("returns embed cover", func() {
_, path, err := aw.get(context.Background(), alOnlyEmbed.CoverArtID().String(), 0)
Expect(err).ToNot(HaveOccurred())
Expect(path).To(Equal("tests/fixtures/test.mp3"))
})
It("returns placeholder if embed path is not available", func() {
_, path, err := aw.get(context.Background(), alEmbedNotFound.CoverArtID().String(), 0)
Expect(err).ToNot(HaveOccurred())
Expect(path).To(Equal(consts.PlaceholderAlbumArt))
})
})
})
-29
View File
@@ -1,29 +0,0 @@
package core
import (
"context"
"github.com/navidrome/navidrome/log"
"github.com/navidrome/navidrome/model"
"github.com/navidrome/navidrome/tests"
. "github.com/onsi/ginkgo/v2"
)
var _ = Describe("Artwork", func() {
var ds model.DataStore
ctx := log.NewContext(context.TODO())
BeforeEach(func() {
ds = &tests.MockDataStore{MockedTranscoding: &tests.MockTranscodingRepo{}}
ds.Album(ctx).(*tests.MockAlbumRepo).SetData(model.Albums{
{ID: "222", EmbedArtPath: "tests/fixtures/test.mp3"},
{ID: "333"},
{ID: "444", EmbedArtPath: "tests/fixtures/cover.jpg"},
})
ds.MediaFile(ctx).(*tests.MockMediaFileRepo).SetData(model.MediaFiles{
{ID: "123", AlbumID: "222", Path: "tests/fixtures/test.mp3", HasCoverArt: true},
{ID: "456", AlbumID: "222", Path: "tests/fixtures/test.ogg", HasCoverArt: false},
})
})
})