From d9ef84067e10a2d3d5db5dd53c9808930325852f Mon Sep 17 00:00:00 2001 From: Tobias Gesellchen Date: Sun, 7 Jun 2026 14:20:01 +0200 Subject: [PATCH] feat(service): keep the chooser reachable via /?chooser (refs #451) With default_landing set to app or admin, "/" redirects straight there, which made the chooser (and through it the other surface) unreachable from the "home" link. Add a "?chooser" override: "/" always serves the chooser when that query is present, regardless of the configured default. Point the "home" brand links on the player, the admin console, and the chooser itself at /?chooser, so "home" always lands on the hub instead of bouncing back through the default redirect. The bare "/" still honours the default for direct hits and bookmarks. Co-Authored-By: Claude Opus 4.8 (1M context) --- pkg/service/handlers/handlers_landing_test.go | 19 +++++++++++++++ pkg/service/handlers/handlers_media.go | 23 +++++++++++-------- pkg/service/handlers/web/index.html | 2 +- pkg/service/handlers/web/landing.html | 2 +- pkg/service/soundtouchweb/static/js/app.js | 2 +- 5 files changed, 36 insertions(+), 12 deletions(-) diff --git a/pkg/service/handlers/handlers_landing_test.go b/pkg/service/handlers/handlers_landing_test.go index 0122033..d2a5aee 100644 --- a/pkg/service/handlers/handlers_landing_test.go +++ b/pkg/service/handlers/handlers_landing_test.go @@ -76,6 +76,25 @@ func TestHandleRootRedirects(t *testing.T) { } } +// TestHandleRootChooserOverride: "?chooser" forces the chooser even when a +// default redirect is configured, so the hub stays reachable. +func TestHandleRootChooserOverride(t *testing.T) { + for _, landing := range []string{"app", "admin"} { + server := newLandingServer(t, landing) + + rec := httptest.NewRecorder() + server.HandleRoot(rec, htmlGet("/?chooser")) + + if rec.Code != http.StatusOK { + t.Errorf("landing=%q with ?chooser: status = %d; want 200 (no redirect)", landing, rec.Code) + } + + if !strings.Contains(rec.Body.String(), `href="/admin"`) { + t.Errorf("landing=%q with ?chooser: body is not the chooser", landing) + } + } +} + // TestHandleRootJSONIgnoresLanding: API/speaker clients (non-HTML Accept) // always get the version JSON, never a landing redirect, regardless of // the configured default. diff --git a/pkg/service/handlers/handlers_media.go b/pkg/service/handlers/handlers_media.go index f8e81b9..05a4b19 100644 --- a/pkg/service/handlers/handlers_media.go +++ b/pkg/service/handlers/handlers_media.go @@ -117,15 +117,20 @@ func (s *Server) HandleRoot(w http.ResponseWriter, r *http.Request) { } // HTML branch: a browser hitting "/". Honour the configured default - // landing surface, otherwise serve the neutral chooser. The admin - // console itself now lives at /admin (served by HandleAdmin). - switch s.defaultLanding() { - case "app": - http.Redirect(w, r, "/app", http.StatusFound) - return - case "admin": - http.Redirect(w, r, "/admin", http.StatusFound) - return + // landing surface, otherwise serve the neutral chooser. A "?chooser" + // query forces the chooser even when a default redirect is set, so the + // hub (and through it the admin console) stays reachable: the "home" + // links on the player and admin point here. The admin console itself + // lives at /admin (served by HandleAdmin). + if !r.URL.Query().Has("chooser") { + switch s.defaultLanding() { + case "app": + http.Redirect(w, r, "/app", http.StatusFound) + return + case "admin": + http.Redirect(w, r, "/admin", http.StatusFound) + return + } } w.Header().Set("Content-Type", "text/html") diff --git a/pkg/service/handlers/web/index.html b/pkg/service/handlers/web/index.html index 0c1558f..7d2f2fa 100644 --- a/pkg/service/handlers/web/index.html +++ b/pkg/service/handlers/web/index.html @@ -9,7 +9,7 @@
- + AfterTouch diff --git a/pkg/service/handlers/web/landing.html b/pkg/service/handlers/web/landing.html index 6d7e710..c95173a 100644 --- a/pkg/service/handlers/web/landing.html +++ b/pkg/service/handlers/web/landing.html @@ -163,7 +163,7 @@
- + AfterTouch diff --git a/pkg/service/soundtouchweb/static/js/app.js b/pkg/service/soundtouchweb/static/js/app.js index baec39b..5007b7b 100644 --- a/pkg/service/soundtouchweb/static/js/app.js +++ b/pkg/service/soundtouchweb/static/js/app.js @@ -170,7 +170,7 @@ function App() { return html`