From 6d0b5f2c78be4fe6a2685ee84e2015e49b607b51 Mon Sep 17 00:00:00 2001 From: Tobias Gesellchen Date: Sat, 4 Apr 2026 23:42:12 +0200 Subject: [PATCH] Add /bmx/registry/v1/servicesAvailability --- cmd/soundtouch-service/main.go | 1 + .../testdata/router_routes.txt | 1 + pkg/service/handlers/handlers_bmx.go | 6 ++ ...handlers_bmx_registry_availability_test.go | 73 +++++++++++++++++++ pkg/service/handlers/handlers_media.go | 3 + pkg/service/handlers/main_test.go | 1 + .../static/bmx_services_availability.json | 14 ++++ 7 files changed, 99 insertions(+) create mode 100644 pkg/service/handlers/handlers_bmx_registry_availability_test.go create mode 100644 pkg/service/handlers/static/bmx_services_availability.json diff --git a/cmd/soundtouch-service/main.go b/cmd/soundtouch-service/main.go index 2cfab7d..b9bb10f 100644 --- a/cmd/soundtouch-service/main.go +++ b/cmd/soundtouch-service/main.go @@ -714,6 +714,7 @@ func setupRouter(server *handlers.Server) *chi.Mux { r.Route("/bmx", func(r chi.Router) { r.Get("/registry/v1/services", server.HandleBMXRegistry) + r.Get("/registry/v1/servicesAvailability", server.HandleBMXServicesAvailability) r.Route("/tunein", func(r chi.Router) { r.Get("/v1/playback/station/{stationID}", server.HandleTuneInPlayback) diff --git a/cmd/soundtouch-service/testdata/router_routes.txt b/cmd/soundtouch-service/testdata/router_routes.txt index 9c57360..137c3aa 100644 --- a/cmd/soundtouch-service/testdata/router_routes.txt +++ b/cmd/soundtouch-service/testdata/router_routes.txt @@ -16,6 +16,7 @@ GET /accounts/{account}/devices/{device}/presets handlers.( GET /accounts/{account}/devices/{device}/recents handlers.(*Server).HandleMargeRecents-fm GET /accounts/{account}/full handlers.(*Server).HandleMargeAccountFull-fm GET /bmx/registry/v1/services handlers.(*Server).HandleBMXRegistry-fm +GET /bmx/registry/v1/servicesAvailability handlers.(*Server).HandleBMXServicesAvailability-fm GET /bmx/tunein/v1/playback/episode/{podcastID} handlers.(*Server).HandleTuneInPlaybackPodcast-fm GET /bmx/tunein/v1/playback/episodes/{podcastID} handlers.(*Server).HandleTuneInPodcastInfo-fm GET /bmx/tunein/v1/playback/station/{stationID} handlers.(*Server).HandleTuneInPlayback-fm diff --git a/pkg/service/handlers/handlers_bmx.go b/pkg/service/handlers/handlers_bmx.go index bc9524d..2d0ee67 100644 --- a/pkg/service/handlers/handlers_bmx.go +++ b/pkg/service/handlers/handlers_bmx.go @@ -33,6 +33,12 @@ func (s *Server) HandleBMXRegistry(w http.ResponseWriter, _ *http.Request) { _, _ = w.Write([]byte(content)) } +// HandleBMXServicesAvailability returns the BMX services availability. +func (s *Server) HandleBMXServicesAvailability(w http.ResponseWriter, _ *http.Request) { + w.Header().Set("Content-Type", "application/json") + _, _ = w.Write(bmxServicesAvailabilityJSON) +} + func (s *Server) writeBMXUnauthorized(w http.ResponseWriter) { w.Header().Set("Content-Type", "text/html; charset=utf-8") w.WriteHeader(http.StatusUnauthorized) diff --git a/pkg/service/handlers/handlers_bmx_registry_availability_test.go b/pkg/service/handlers/handlers_bmx_registry_availability_test.go new file mode 100644 index 0000000..7dbbc8a --- /dev/null +++ b/pkg/service/handlers/handlers_bmx_registry_availability_test.go @@ -0,0 +1,73 @@ +package handlers + +import ( + "encoding/json" + "net/http" + "net/http/httptest" + "testing" +) + +func TestHandleBMXServicesAvailability(t *testing.T) { + r, _ := setupRouter("http://localhost:8001", nil) + + req := httptest.NewRequest("GET", "/bmx/registry/v1/servicesAvailability", nil) + w := httptest.NewRecorder() + + r.ServeHTTP(w, req) + + if w.Code != http.StatusOK { + t.Errorf("Expected status 200, got %d", w.Code) + } + + contentType := w.Header().Get("Content-Type") + if contentType != "application/json" { + t.Errorf("Expected Content-Type application/json, got %s", contentType) + } + + var resp map[string]interface{} + if err := json.Unmarshal(w.Body.Bytes(), &resp); err != nil { + t.Fatalf("Failed to unmarshal response: %v", err) + } + + services, ok := resp["services"].([]interface{}) + if !ok { + t.Fatal("Response missing 'services' field") + } + + if len(services) != 2 { + t.Errorf("Expected 2 services, got %d", len(services)) + } + + foundTuneIn := false + foundSiriusXM := false + + for _, s := range services { + service := s.(map[string]interface{}) + name := service["service"].(string) + switch name { + case "TUNEIN": + foundTuneIn = true + if service["canAdd"] != true { + t.Errorf("TUNEIN: expected canAdd true, got %v", service["canAdd"]) + } + if service["canRemove"] != false { + t.Errorf("TUNEIN: expected canRemove false, got %v", service["canRemove"]) + } + case "SIRIUSXM_EVEREST": + foundSiriusXM = true + if service["canAdd"] != false { + t.Errorf("SIRIUSXM_EVEREST: expected canAdd false, got %v", service["canAdd"]) + } + if service["canRemove"] != true { + t.Errorf("SIRIUSXM_EVEREST: expected canRemove true, got %v", service["canRemove"]) + } + } + } + + if !foundTuneIn { + t.Error("TUNEIN not found in servicesAvailability") + } + if !foundSiriusXM { + t.Error("SIRIUSXM_EVEREST not found in servicesAvailability") + } +} diff --git a/pkg/service/handlers/handlers_media.go b/pkg/service/handlers/handlers_media.go index 2d819af..629abf8 100644 --- a/pkg/service/handlers/handlers_media.go +++ b/pkg/service/handlers/handlers_media.go @@ -20,6 +20,9 @@ var mediaFS embed.FS //go:embed static/bmx_services.json var bmxServicesJSON []byte +//go:embed static/bmx_services_availability.json +var bmxServicesAvailabilityJSON []byte + // Upstream source available at https://worldwide.bose.com/updates/soundtouch?serialnumber=_serial_ // which results in a redirect to https://downloads.bose.com/ced/soundtouch/mr4_22097fe2/index.xml // diff --git a/pkg/service/handlers/main_test.go b/pkg/service/handlers/main_test.go index e9e3154..f2ffa7d 100644 --- a/pkg/service/handlers/main_test.go +++ b/pkg/service/handlers/main_test.go @@ -23,6 +23,7 @@ func setupRouter(targetURL string, ds *datastore.DataStore) (*chi.Mux, *Server) // Setup BMX for tests r.Route("/bmx", func(r chi.Router) { r.Get("/registry/v1/services", server.HandleBMXRegistry) + r.Get("/registry/v1/servicesAvailability", server.HandleBMXServicesAvailability) r.Get("/tunein/v1/playback/station/{stationID}", server.HandleTuneInPlayback) r.Get("/tunein/v1/playback/episodes/{podcastID}", server.HandleTuneInPodcastInfo) r.Get("/tunein/v1/playback/episode/{podcastID}", server.HandleTuneInPlaybackPodcast) diff --git a/pkg/service/handlers/static/bmx_services_availability.json b/pkg/service/handlers/static/bmx_services_availability.json new file mode 100644 index 0000000..df411d0 --- /dev/null +++ b/pkg/service/handlers/static/bmx_services_availability.json @@ -0,0 +1,14 @@ +{ + "services": [ + { + "canAdd": true, + "canRemove": false, + "service": "TUNEIN" + }, + { + "canAdd": false, + "canRemove": true, + "service": "SIRIUSXM_EVEREST" + } + ] +}