mirror of
https://github.com/navidrome/navidrome.git
synced 2026-10-18 07:30:29 +00:00
An absent artwork state was revisited by an hourly job, by viewing the entity, and by the startup backfill on any artwork config change. On a large library the last one queued tens of thousands of external lookups at once and got the provider to rate-limit us for hours. Nothing revisits an absent state now. Retrying is explicit: `artwork reprocess` on the CLI, or the refresh button in the UI. The config fingerprint survives only as an advisory, warning at startup and naming the command that clears it. Since absent is terminal, `artwork status` splits it into two disjoint columns, and `--source failed` targets only the ones that gave up rather than being answered. Both read through the filter CountBySource and EnqueueBySource already share, so the reported number is the set the command acts on. Also fixes the last_failure default left by 20260819204637, which marked every pre-existing absent row as failed, and removes the code the deleted retry paths orphaned.
210 lines
5.2 KiB
Go
210 lines
5.2 KiB
Go
package persistence
|
|
|
|
import (
|
|
"context"
|
|
|
|
"github.com/deluan/rest"
|
|
"github.com/navidrome/navidrome/log"
|
|
"github.com/navidrome/navidrome/model"
|
|
"github.com/navidrome/navidrome/model/request"
|
|
. "github.com/onsi/ginkgo/v2"
|
|
. "github.com/onsi/gomega"
|
|
)
|
|
|
|
var _ = Describe("RadioRepository", func() {
|
|
var repo model.RadioRepository
|
|
|
|
Describe("Admin User", func() {
|
|
BeforeEach(func() {
|
|
ctx := log.NewContext(context.TODO())
|
|
ctx = request.WithUser(ctx, model.User{ID: "userid", UserName: "userid", IsAdmin: true})
|
|
repo = NewRadioRepository(ctx, GetDBXBuilder())
|
|
_ = repo.Put(&radioWithHomePage)
|
|
})
|
|
|
|
AfterEach(func() {
|
|
all, _ := repo.GetAll()
|
|
|
|
for _, radio := range all {
|
|
_ = repo.Delete(radio.ID)
|
|
}
|
|
|
|
for i := range testRadios {
|
|
err := repo.Put(new(testRadios[i]))
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
}
|
|
})
|
|
|
|
Describe("Count", func() {
|
|
It("returns the number of radios in the DB", func() {
|
|
Expect(repo.CountAll()).To(Equal(int64(2)))
|
|
})
|
|
})
|
|
|
|
Describe("Delete", func() {
|
|
It("deletes existing item", func() {
|
|
err := repo.Delete(radioWithHomePage.ID)
|
|
|
|
Expect(err).To(BeNil())
|
|
|
|
_, err = repo.Get(radioWithHomePage.ID)
|
|
Expect(err).To(MatchError(model.ErrNotFound))
|
|
})
|
|
})
|
|
|
|
Describe("Get", func() {
|
|
It("returns an existing item", func() {
|
|
res, err := repo.Get(radioWithHomePage.ID)
|
|
|
|
Expect(err).To(BeNil())
|
|
Expect(res.ID).To(Equal(radioWithHomePage.ID))
|
|
})
|
|
|
|
It("errors when missing", func() {
|
|
_, err := repo.Get("notanid")
|
|
|
|
Expect(err).To(MatchError(model.ErrNotFound))
|
|
})
|
|
})
|
|
|
|
Describe("GetAll", func() {
|
|
It("returns all items from the DB", func() {
|
|
all, err := repo.GetAll()
|
|
Expect(err).To(BeNil())
|
|
Expect(all[0].ID).To(Equal(radioWithoutHomePage.ID))
|
|
Expect(all[1].ID).To(Equal(radioWithHomePage.ID))
|
|
})
|
|
})
|
|
|
|
Describe("Put", func() {
|
|
It("successfully updates item", func() {
|
|
err := repo.Put(&model.Radio{
|
|
ID: radioWithHomePage.ID,
|
|
Name: "New Name",
|
|
StreamUrl: "https://example.com:4533/app",
|
|
})
|
|
|
|
Expect(err).To(BeNil())
|
|
|
|
item, err := repo.Get(radioWithHomePage.ID)
|
|
Expect(err).To(BeNil())
|
|
|
|
Expect(item.HomePageUrl).To(Equal(""))
|
|
})
|
|
|
|
It("successfully creates item", func() {
|
|
err := repo.Put(&model.Radio{
|
|
Name: "New radio",
|
|
StreamUrl: "https://example.com:4533/app",
|
|
})
|
|
|
|
Expect(err).To(BeNil())
|
|
Expect(repo.CountAll()).To(Equal(int64(3)))
|
|
|
|
all, err := repo.GetAll()
|
|
Expect(err).To(BeNil())
|
|
Expect(all[2].StreamUrl).To(Equal("https://example.com:4533/app"))
|
|
})
|
|
|
|
It("enqueues artwork resolution for the saved radio", func() {
|
|
err := repo.Put(&model.Radio{
|
|
Name: "Artwork radio",
|
|
StreamUrl: "https://example.com:4533/artwork",
|
|
})
|
|
Expect(err).To(BeNil())
|
|
|
|
all, err := repo.GetAll()
|
|
Expect(err).To(BeNil())
|
|
created := all[len(all)-1]
|
|
|
|
queueRepo := NewArtworkQueueRepository(context.Background(), GetDBXBuilder())
|
|
queued, err := queueRepo.DequeueBatch(1000)
|
|
Expect(err).To(BeNil())
|
|
Expect(queued).To(ContainElement(SatisfyAll(
|
|
HaveField("ItemKind", "ra"),
|
|
HaveField("ItemID", created.ID),
|
|
HaveField("Priority", model.ArtworkPriorityBump),
|
|
)))
|
|
})
|
|
})
|
|
|
|
Describe("Update", func() {
|
|
It("only writes the columns sent by the client", func() {
|
|
radio := radioWithHomePage
|
|
radio.UploadedImage = "cover.png"
|
|
Expect(repo.Put(&radio)).To(Succeed())
|
|
|
|
persistable := repo.(rest.Persistable)
|
|
Expect(persistable.Update(radio.ID, &model.Radio{Name: "Renamed"}, "name")).To(Succeed())
|
|
|
|
item, err := repo.Get(radio.ID)
|
|
Expect(err).To(BeNil())
|
|
Expect(item.Name).To(Equal("Renamed"))
|
|
Expect(item.UploadedImage).To(Equal("cover.png"))
|
|
Expect(item.StreamUrl).To(Equal(radio.StreamUrl))
|
|
Expect(item.HomePageUrl).To(Equal(radio.HomePageUrl))
|
|
})
|
|
})
|
|
})
|
|
|
|
Describe("Regular User", func() {
|
|
BeforeEach(func() {
|
|
ctx := log.NewContext(context.TODO())
|
|
ctx = request.WithUser(ctx, model.User{ID: "userid", UserName: "userid", IsAdmin: false})
|
|
repo = NewRadioRepository(ctx, GetDBXBuilder())
|
|
})
|
|
|
|
Describe("Count", func() {
|
|
It("returns the number of radios in the DB", func() {
|
|
Expect(repo.CountAll()).To(Equal(int64(2)))
|
|
})
|
|
})
|
|
|
|
Describe("Delete", func() {
|
|
It("fails to delete items", func() {
|
|
err := repo.Delete(radioWithHomePage.ID)
|
|
|
|
Expect(err).To(Equal(rest.ErrPermissionDenied))
|
|
})
|
|
})
|
|
|
|
Describe("Get", func() {
|
|
It("returns an existing item", func() {
|
|
res, err := repo.Get(radioWithHomePage.ID)
|
|
|
|
Expect(err).To(BeNil())
|
|
Expect(res.ID).To(Equal(radioWithHomePage.ID))
|
|
})
|
|
|
|
It("errors when missing", func() {
|
|
_, err := repo.Get("notanid")
|
|
|
|
Expect(err).To(MatchError(model.ErrNotFound))
|
|
})
|
|
})
|
|
|
|
Describe("GetAll", func() {
|
|
It("returns all items from the DB", func() {
|
|
all, err := repo.GetAll()
|
|
Expect(err).To(BeNil())
|
|
Expect(all[0].ID).To(Equal(radioWithoutHomePage.ID))
|
|
Expect(all[1].ID).To(Equal(radioWithHomePage.ID))
|
|
})
|
|
})
|
|
|
|
Describe("Put", func() {
|
|
It("fails to update item", func() {
|
|
err := repo.Put(&model.Radio{
|
|
ID: radioWithHomePage.ID,
|
|
Name: "New Name",
|
|
StreamUrl: "https://example.com:4533/app",
|
|
})
|
|
|
|
Expect(err).To(Equal(rest.ErrPermissionDenied))
|
|
})
|
|
})
|
|
})
|
|
})
|