From aacc46f7f527d26cf0cf7fed4f658c96246f7894 Mon Sep 17 00:00:00 2001 From: Deluan Date: Sun, 5 Jul 2026 15:07:43 -0400 Subject: [PATCH] feat(jellyfin): user views and current-user endpoints --- server/jellyfin/api.go | 6 ++++- server/jellyfin/users.go | 31 +++++++++++++++++++++++++ server/jellyfin/users_test.go | 43 +++++++++++++++++++++++++++++++++++ 3 files changed, 79 insertions(+), 1 deletion(-) create mode 100644 server/jellyfin/users.go create mode 100644 server/jellyfin/users_test.go diff --git a/server/jellyfin/api.go b/server/jellyfin/api.go index 5e9e2ecf9..1da4c5c21 100644 --- a/server/jellyfin/api.go +++ b/server/jellyfin/api.go @@ -48,10 +48,14 @@ func (api *Router) routes() http.Handler { r.Post("/System/Ping", api.ping) r.Get("/QuickConnect/Enabled", api.quickConnectEnabled) r.Post("/Users/AuthenticateByName", api.authenticateByName) + r.Get("/Users/Public", api.getPublicUsers) r.Group(func(r chi.Router) { r.Use(api.authenticate) - // authenticated endpoints are registered by later tasks + r.Get("/UserViews", api.getUserViews) + r.Get("/Users/{userId}/Views", api.getUserViews) + r.Get("/Users/Me", api.getCurrentUser) + r.Get("/Users/{userId}", api.getCurrentUser) }) return r diff --git a/server/jellyfin/users.go b/server/jellyfin/users.go new file mode 100644 index 000000000..e604c9c4a --- /dev/null +++ b/server/jellyfin/users.go @@ -0,0 +1,31 @@ +package jellyfin + +import ( + "net/http" + + "github.com/navidrome/navidrome/model/request" + "github.com/navidrome/navidrome/server/jellyfin/dto" +) + +const musicViewID = "music" + +func (api *Router) getUserViews(w http.ResponseWriter, r *http.Request) { + view := dto.BaseItemDto{ + Name: api.serverName(), + Id: musicViewID, + Type: "CollectionFolder", + CollectionType: "music", + IsFolder: true, + BackdropImageTags: []string{}, + } + api.ok(w, r, dto.QueryResult{Items: []dto.BaseItemDto{view}, TotalRecordCount: 1, StartIndex: 0}) +} + +func (api *Router) getCurrentUser(w http.ResponseWriter, r *http.Request) { + u, _ := request.UserFrom(r.Context()) + api.ok(w, r, userToDto(&u, api.serverName())) +} + +func (api *Router) getPublicUsers(w http.ResponseWriter, r *http.Request) { + api.ok(w, r, []dto.UserDto{}) // manual login only +} diff --git a/server/jellyfin/users_test.go b/server/jellyfin/users_test.go new file mode 100644 index 000000000..1252c7b86 --- /dev/null +++ b/server/jellyfin/users_test.go @@ -0,0 +1,43 @@ +package jellyfin + +import ( + "context" + "encoding/json" + "net/http" + "net/http/httptest" + + "github.com/navidrome/navidrome/model" + "github.com/navidrome/navidrome/model/request" + "github.com/navidrome/navidrome/server/jellyfin/dto" + "github.com/navidrome/navidrome/tests" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" +) + +var _ = Describe("Users", func() { + var api *Router + authed := func(r *http.Request) *http.Request { + ctx := request.WithUser(context.Background(), model.User{ID: "u1", UserName: "alice"}) + return r.WithContext(ctx) + } + BeforeEach(func() { api = &Router{ds: &tests.MockDataStore{}} }) + + It("returns a single music view", func() { + w := httptest.NewRecorder() + api.getUserViews(w, authed(httptest.NewRequest("GET", "/UserViews", nil))) + Expect(w.Code).To(Equal(http.StatusOK)) + var res dto.QueryResult + Expect(json.Unmarshal(w.Body.Bytes(), &res)).To(Succeed()) + Expect(res.Items).To(HaveLen(1)) + Expect(res.Items[0].CollectionType).To(Equal("music")) + Expect(res.Items[0].Type).To(Equal("CollectionFolder")) + }) + + It("returns the current user", func() { + w := httptest.NewRecorder() + api.getCurrentUser(w, authed(httptest.NewRequest("GET", "/Users/Me", nil))) + var u dto.UserDto + Expect(json.Unmarshal(w.Body.Bytes(), &u)).To(Succeed()) + Expect(u.Name).To(Equal("alice")) + }) +})