//go:build !windows package plugins import ( "github.com/navidrome/navidrome/core/sonic" "github.com/navidrome/navidrome/model" "github.com/navidrome/navidrome/plugins/capabilities" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" ) var _ = Describe("SonicSimilarityPlugin", Ordered, func() { var ( manager *Manager provider sonic.Provider ) BeforeAll(func() { manager, _ = createTestManagerWithPlugins(nil, "test-sonic-similarity"+PackageExtension) var ok bool provider, ok = manager.LoadSonicSimilarity("test-sonic-similarity") Expect(ok).To(BeTrue()) }) Describe("PluginNames", func() { It("reports the sonic similarity capability", func() { names := manager.PluginNames(string(CapabilitySonicSimilarity)) Expect(names).To(ContainElement("test-sonic-similarity")) }) }) Describe("GetSonicSimilarTracks", func() { It("returns similar tracks from the plugin", func() { mf := &model.MediaFile{ ID: "track-1", Title: "Yesterday", Artist: "The Beatles", } results, err := provider.GetSonicSimilarTracks(GinkgoT().Context(), mf, 3) Expect(err).ToNot(HaveOccurred()) Expect(results).To(HaveLen(3)) Expect(results[0].Song.Name).To(Equal("Similar to Yesterday #1")) Expect(results[0].Song.Artists).To(HaveLen(1)) Expect(results[0].Song.Artists[0].Name).To(Equal("The Beatles")) Expect(results[0].Similarity).To(Equal(1.0)) Expect(results[1].Similarity).To(Equal(0.9)) Expect(results[2].Similarity).To(Equal(0.8)) }) }) Describe("FindSonicPath", func() { It("returns a path between two tracks from the plugin", func() { startMf := &model.MediaFile{ ID: "track-1", Title: "Yesterday", Artist: "The Beatles", } endMf := &model.MediaFile{ ID: "track-2", Title: "Tomorrow Never Knows", Artist: "The Beatles", } results, err := provider.FindSonicPath(GinkgoT().Context(), startMf, endMf, 3) Expect(err).ToNot(HaveOccurred()) Expect(results).To(HaveLen(3)) Expect(results[0].Song.Name).To(Equal("Path Yesterday to Tomorrow Never Knows #1")) Expect(results[0].Song.Artists).To(HaveLen(1)) Expect(results[0].Song.Artists[0].Name).To(Equal("The Beatles")) Expect(results[0].Similarity).To(Equal(1.0)) Expect(results[1].Similarity).To(Equal(0.95)) Expect(results[2].Similarity).To(Equal(0.9)) }) }) }) var _ = Describe("SonicSimilarityPlugin error handling", Ordered, func() { var ( errorManager *Manager errorProvider sonic.Provider ) BeforeAll(func() { errorManager, _ = createTestManagerWithPlugins(map[string]map[string]string{ "test-sonic-similarity": { "error": "simulated plugin error", }, }, "test-sonic-similarity"+PackageExtension) var ok bool errorProvider, ok = errorManager.LoadSonicSimilarity("test-sonic-similarity") Expect(ok).To(BeTrue()) }) It("returns error from GetSonicSimilarTracks", func() { mf := &model.MediaFile{ID: "track-1", Title: "Test"} _, err := errorProvider.GetSonicSimilarTracks(GinkgoT().Context(), mf, 3) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("simulated plugin error")) }) It("returns error from FindSonicPath", func() { startMf := &model.MediaFile{ID: "track-1", Title: "Start"} endMf := &model.MediaFile{ID: "track-2", Title: "End"} _, err := errorProvider.FindSonicPath(GinkgoT().Context(), startMf, endMf, 3) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("simulated plugin error")) }) }) var _ = Describe("mediaFileToSongRef multi-artist", func() { It("fills Artists (with IDs) from role=artist participants", func() { mf := &model.MediaFile{ID: "x", Title: "Collab", Participants: model.Participants{ model.RoleArtist: model.ParticipantList{ {Artist: model.Artist{ID: "ar-drake", Name: "Drake", MbzArtistID: "m-drake"}}, {Artist: model.Artist{ID: "ar-future", Name: "Future", MbzArtistID: "m-future"}}, }, }} ref := mediaFileToSongRef(mf) Expect(ref.Artists).To(Equal([]capabilities.ArtistRef{ {ID: "ar-drake", Name: "Drake", MBID: "m-drake", Role: "artist"}, {ID: "ar-future", Name: "Future", MBID: "m-future", Role: "artist"}, })) }) It("leaves Artists nil when the track has no role=artist participants", func() { mf := &model.MediaFile{ID: "x", Title: "Solo", Artist: "Drake"} ref := mediaFileToSongRef(mf) Expect(ref.Artists).To(BeNil()) }) })