feat: add global smart playlist functionality

Signed-off-by: Deluan <deluan@navidrome.org>
This commit is contained in:
Deluan 2026-01-16 10:27:51 -05:00
commit 8861eebe21
7 changed files with 108 additions and 5 deletions

View file

@ -168,6 +168,10 @@ func (s *playlists) parseNSP(_ context.Context, pls *model.Playlist, reader io.R
if nsp.Comment != "" {
pls.Comment = nsp.Comment
}
pls.Global = nsp.Global
if nsp.Global {
pls.Public = true
}
return nil
}
@ -404,12 +408,18 @@ func (s *playlists) updatePlaylist(ctx context.Context, newPls *model.Playlist)
newPls.Name = pls.Name
newPls.Comment = pls.Comment
newPls.OwnerID = pls.OwnerID
newPls.Public = pls.Public
// Preserve Public from existing playlist, unless the new playlist is Global
if !newPls.Global {
newPls.Public = pls.Public
}
newPls.EvaluatedAt = &time.Time{}
} else {
log.Info(ctx, "Adding synced playlist", "playlist", newPls.Name, "path", newPls.Path, "owner", owner.UserName)
newPls.OwnerID = owner.ID
newPls.Public = conf.Server.DefaultPlaylistPublicVisibility
// Only apply default visibility if not a global playlist (which is always public)
if !newPls.Global {
newPls.Public = conf.Server.DefaultPlaylistPublicVisibility
}
}
return s.ds.Playlist(ctx).Put(newPls)
}
@ -473,6 +483,7 @@ type nspFile struct {
criteria.Criteria
Name string `json:"name"`
Comment string `json:"comment"`
Global bool `json:"global"`
}
func (i *nspFile) UnmarshalJSON(data []byte) error {
@ -483,5 +494,6 @@ func (i *nspFile) UnmarshalJSON(data []byte) error {
}
i.Name, _ = m["name"].(string)
i.Comment, _ = m["comment"].(string)
i.Global, _ = m["global"].(bool)
return json.Unmarshal(data, &i.Criteria)
}

View file

@ -107,11 +107,20 @@ var _ = Describe("Playlists", func() {
Expect(pls.Rules.Order).To(Equal("desc"))
Expect(pls.Rules.Limit).To(Equal(100))
Expect(pls.Rules.Expression).To(BeAssignableToTypeOf(criteria.All{}))
Expect(pls.Global).To(BeFalse())
Expect(pls.Public).To(BeFalse())
})
It("returns an error if the playlist is not well-formed", func() {
_, err := ps.ImportFile(ctx, folder, "invalid_json.nsp")
Expect(err.Error()).To(ContainSubstring("line 19, column 1: invalid character '\\n'"))
})
It("parses global attribute and sets playlist to public", func() {
pls, err := ps.ImportFile(ctx, folder, "global_smart_playlist.nsp")
Expect(err).ToNot(HaveOccurred())
Expect(pls.Name).To(Equal("Global Smart Playlist"))
Expect(pls.Global).To(BeTrue())
Expect(pls.Public).To(BeTrue())
})
})
Describe("Cross-library relative paths", func() {