From da2bb672f004c0f285214dd6f8f1a329205083aa Mon Sep 17 00:00:00 2001 From: bvandeusen Date: Sun, 19 Apr 2026 17:38:44 +0000 Subject: [PATCH] feat(subsonic): mount /rest router with /ping and /getLicense Exposes each handler at /rest/name and /rest/name.view, GET+POST, for client convention compatibility. --- internal/subsonic/subsonic.go | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 internal/subsonic/subsonic.go diff --git a/internal/subsonic/subsonic.go b/internal/subsonic/subsonic.go new file mode 100644 index 00000000..2eff4057 --- /dev/null +++ b/internal/subsonic/subsonic.go @@ -0,0 +1,34 @@ +// Package subsonic implements a Subsonic-compatible REST API surface under +// /rest. It exists for third-party Subsonic clients (Symfonium, Substreamer, +// DSub, Tempo, play:Sub, …). Minstrel's own clients use the native /api/* +// surface, which has modern auth; /rest/* retains Subsonic's legacy auth for +// compatibility only. See docs/auth.md for the security posture. +package subsonic + +import ( + "log/slog" + "net/http" + + "github.com/go-chi/chi/v5" + "github.com/jackc/pgx/v5/pgxpool" +) + +// Mount attaches Subsonic handlers at /rest on r. Endpoints are exposed at +// both /rest/foo and /rest/foo.view because client conventions vary. Both +// GET and POST are accepted; Subsonic's auth params live in the query string +// either way. +func Mount(r chi.Router, pool *pgxpool.Pool, logger *slog.Logger, cfg Config) { + r.Route("/rest", func(sub chi.Router) { + sub.Use(Middleware(pool, cfg)) + register(sub, "/ping", handlePing) + register(sub, "/getLicense", handleGetLicense) + _ = logger + }) +} + +func register(r chi.Router, path string, h func(http.ResponseWriter, *http.Request)) { + r.Get(path, h) + r.Post(path, h) + r.Get(path+".view", h) + r.Post(path+".view", h) +}