From e99c04888c6a548fdb63dbb0e6fd92aed0ff5d57 Mon Sep 17 00:00:00 2001 From: Tobias Gesellchen Date: Sat, 2 May 2026 21:22:36 +0200 Subject: [PATCH] feat: implement missing endpoints and serve static resources from downloads/media hosts (#199) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Endpoints: - POST /streaming/music/musicprovider/{id}/trial/is_eligible (reuses is_eligible handler) - POST /bmx/tunein/v1/favorite/{stationID} with datastore persistence (SaveTuneInFavorite) - DELETE /bmx/tunein/v1/favorite/{stationID} (DeleteTuneInFavorite) - POST /bmx/core02/svc-bmx-adapter-orion/prod/orion/token (anonymous Orion token) - GET /bmx-icons/* serving embedded static/media assets (media.bose.io) - GET /ced/* serving embedded firmware index, release notes, and 10 app-help XMLs (downloads.bose.com) Add media.bose.io and downloads.bose.com to DNS redirect lists (setup.go both domain slices, dns.go shouldIntercept list, main.go getDomains map). Document implemented endpoints in tests/interactions_20260502_missing_external.md; mark rows 0246–0247 as self/☑ in the interactions table. Co-authored-by: Claude Sonnet 4.6 --- cmd/soundtouch-service/main.go | 7 + .../testdata/router_routes.txt | 6 + docs/SUMMARY.md | 1 + docs/reference/DEVICE-PAIRING-FLOW.md | 521 ++++++++++++++++++ pkg/discovery/dns.go | 1 + pkg/service/datastore/datastore.go | 30 + pkg/service/handlers/handlers_bmx.go | 49 ++ pkg/service/handlers/handlers_media.go | 21 + pkg/service/handlers/handlers_setup_test.go | 2 +- .../ced/soundtouch/mr4_22097fe2/index.xml | 312 +++++++++++ .../mr4_22097fe2/relnotes/releasenotes_en.xml | 101 ++++ .../en/bose_account_create_1.xml | 2 + .../en/gabbo_ios_settings.xml | 2 + .../en/gabbo_recovery_lisa.xml | 2 + .../en/gabbo_recovery_nelson.xml | 2 + .../en/gabbo_recovery_select_system.xml | 14 + .../en/gabbo_recovery_smt.xml | 2 + .../soundtouch_app_help/en/name_device.xml | 2 + .../en/prompt_other_devices.xml | 2 + .../soundtouch_app_help/en/setup_done.xml | 2 + .../en/wifi_or_ethernet_ask.xml | 2 + .../bmx-icons/tunein/top-menu/bubble.png | Bin 0 -> 2288 bytes .../bmx-icons/tunein/top-menu/location.png | Bin 0 -> 4354 bytes .../bmx-icons/tunein/top-menu/microphone.png | Bin 0 -> 4735 bytes .../media/bmx-icons/tunein/top-menu/news.png | Bin 0 -> 2651 bytes .../media/bmx-icons/tunein/top-menu/note.png | Bin 0 -> 4672 bytes .../bmx-icons/tunein/top-menu/podcasts.png | Bin 0 -> 4263 bytes pkg/service/setup/setup.go | 4 + pkg/service/setup/setup_test.go | 6 +- tests/interactions_20260328-103522-477978.md | 496 ++++++++--------- .../interactions_20260502_missing_external.md | 48 ++ 31 files changed, 1386 insertions(+), 251 deletions(-) create mode 100644 docs/reference/DEVICE-PAIRING-FLOW.md create mode 100644 pkg/service/handlers/static/ced/soundtouch/mr4_22097fe2/index.xml create mode 100644 pkg/service/handlers/static/ced/soundtouch/mr4_22097fe2/relnotes/releasenotes_en.xml create mode 100644 pkg/service/handlers/static/ced/soundtouch/soundtouch_app_help/en/bose_account_create_1.xml create mode 100644 pkg/service/handlers/static/ced/soundtouch/soundtouch_app_help/en/gabbo_ios_settings.xml create mode 100644 pkg/service/handlers/static/ced/soundtouch/soundtouch_app_help/en/gabbo_recovery_lisa.xml create mode 100644 pkg/service/handlers/static/ced/soundtouch/soundtouch_app_help/en/gabbo_recovery_nelson.xml create mode 100644 pkg/service/handlers/static/ced/soundtouch/soundtouch_app_help/en/gabbo_recovery_select_system.xml create mode 100644 pkg/service/handlers/static/ced/soundtouch/soundtouch_app_help/en/gabbo_recovery_smt.xml create mode 100644 pkg/service/handlers/static/ced/soundtouch/soundtouch_app_help/en/name_device.xml create mode 100644 pkg/service/handlers/static/ced/soundtouch/soundtouch_app_help/en/prompt_other_devices.xml create mode 100644 pkg/service/handlers/static/ced/soundtouch/soundtouch_app_help/en/setup_done.xml create mode 100644 pkg/service/handlers/static/ced/soundtouch/soundtouch_app_help/en/wifi_or_ethernet_ask.xml create mode 100644 pkg/service/handlers/static/media/bmx-icons/tunein/top-menu/bubble.png create mode 100644 pkg/service/handlers/static/media/bmx-icons/tunein/top-menu/location.png create mode 100644 pkg/service/handlers/static/media/bmx-icons/tunein/top-menu/microphone.png create mode 100644 pkg/service/handlers/static/media/bmx-icons/tunein/top-menu/news.png create mode 100644 pkg/service/handlers/static/media/bmx-icons/tunein/top-menu/note.png create mode 100644 pkg/service/handlers/static/media/bmx-icons/tunein/top-menu/podcasts.png create mode 100644 tests/interactions_20260502_missing_external.md diff --git a/cmd/soundtouch-service/main.go b/cmd/soundtouch-service/main.go index 9609058..d45e093 100644 --- a/cmd/soundtouch-service/main.go +++ b/cmd/soundtouch-service/main.go @@ -668,6 +668,7 @@ func getDomains(serverURL, httpsServerURL, hostname string) []string { "bose.io": true, "bose-prod.apigee.net": true, "bose-test.apigee.net": true, + "downloads.bose.com": true, // Local service domains setup.TestDomain: true, hostname: true, @@ -847,6 +848,8 @@ func setupRouter(server *handlers.Server) *chi.Mux { }) r.Get("/media/*", server.HandleMedia()) + r.Get("/bmx-icons/*", server.HandleBmxIcons()) + r.Get("/ced/*", server.HandleCedStatic()) r.Get("/web/*", server.HandleWeb()) r.Get("/docs/*", server.HandleDocs) @@ -863,9 +866,12 @@ func setupRouter(server *handlers.Server) *chi.Mux { r.Get("/v1/navigate", server.HandleTuneInNavigate) r.Get("/v1/navigate/*", server.HandleTuneInNavigate) r.Get("/v1/search", server.HandleTuneInSearch) + r.Post("/v1/favorite/{stationID}", server.HandleTuneInFavorite) + r.Delete("/v1/favorite/{stationID}", server.HandleTuneInDeleteFavorite) }) r.Post("/orion/v1/playback/station/{data}", server.HandleOrionPlayback) + r.Post("/core02/svc-bmx-adapter-orion/prod/orion/token", server.HandleOrionToken) }) r.Get("/custom/v1/playback/{encodedURL}", server.HandleCustomPlayback) @@ -932,6 +938,7 @@ func setupRouter(server *handlers.Server) *chi.Mux { r.Route("/music", func(r chi.Router) { r.Route("/musicprovider/{providerID}", func(r chi.Router) { r.Post("/is_eligible", server.HandleMusicProviderIsEligible) + r.Post("/trial/is_eligible", server.HandleMusicProviderIsEligible) }) }) diff --git a/cmd/soundtouch-service/testdata/router_routes.txt b/cmd/soundtouch-service/testdata/router_routes.txt index fe544c7..1f8b116 100644 --- a/cmd/soundtouch-service/testdata/router_routes.txt +++ b/cmd/soundtouch-service/testdata/router_routes.txt @@ -1,6 +1,7 @@ CONNECT /oauth/* handlers.(*Server).HandleBoseProxy-fm DELETE /accounts/{account}/devices/{device} handlers.(*Server).HandleMargeRemoveDevice-fm DELETE /accounts/{account}/group/{groupId} handlers.(*Server).HandleMargeDeleteGroup-fm +DELETE /bmx/tunein/v1/favorite/{stationID} handlers.(*Server).HandleTuneInDeleteFavorite-fm DELETE /oauth/* handlers.(*Server).HandleBoseProxy-fm DELETE /setup/devices/{deviceId} handlers.(*Server).HandleRemoveDevice-fm DELETE /setup/dns-discoveries handlers.(*Server).HandleClearDNSDiscoveries-fm @@ -19,6 +20,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 /accounts/{account}/sources handlers.(*Server).HandleMargeAccountSources-fm +GET /bmx-icons/* handlers.(*Server).HandleBmxIcons GET /bmx/registry/v1/services handlers.(*Server).HandleBMXRegistry-fm GET /bmx/registry/v1/servicesAvailability handlers.(*Server).HandleBMXServicesAvailability-fm GET /bmx/tunein/v1/navigate handlers.(*Server).HandleTuneInNavigate-fm @@ -27,6 +29,7 @@ GET /bmx/tunein/v1/playback/episode/{podcastID} handlers.( GET /bmx/tunein/v1/playback/episodes/{podcastID} handlers.(*Server).HandleTuneInPodcastInfo-fm GET /bmx/tunein/v1/playback/station/{stationID} handlers.(*Server).HandleTuneInPlayback-fm GET /bmx/tunein/v1/search handlers.(*Server).HandleTuneInSearch-fm +GET /ced/* handlers.(*Server).HandleCedStatic GET /custom/v1/playback/{encodedURL} handlers.(*Server).HandleCustomPlayback-fm GET /customer/account/{account} handlers.(*Server).HandleMargeAccountProfile-fm GET /docs/* handlers.(*Server).HandleDocs-fm @@ -91,7 +94,9 @@ POST /accounts/{account}/devices/{device}/presets/{presetNumber} handlers.( POST /accounts/{account}/devices/{device}/recents handlers.(*Server).HandleMargeAddRecent-fm POST /accounts/{account}/group handlers.(*Server).HandleMargeAddGroup-fm POST /accounts/{account}/group/{groupId} handlers.(*Server).HandleMargeModifyGroup-fm +POST /bmx/core02/svc-bmx-adapter-orion/prod/orion/token handlers.(*Server).HandleOrionToken-fm POST /bmx/orion/v1/playback/station/{data} handlers.(*Server).HandleOrionPlayback-fm +POST /bmx/tunein/v1/favorite/{stationID} handlers.(*Server).HandleTuneInFavorite-fm POST /bmx/tunein/v1/report handlers.(*Server).HandleTuneInReport-fm POST /bmx/tunein/v1/token handlers.(*Server).HandleTuneInToken-fm POST /customer/account/{account} handlers.(*Server).HandleMargeUpdateAccountProfile-fm @@ -136,6 +141,7 @@ POST /streaming/account/{account}/group/{groupId} handlers.( POST /streaming/account/{account}/source handlers.(*Server).HandleMargeAddSource-fm POST /streaming/device_setting/account/{account}/device/{device}/device_settings handlers.(*Server).HandleMargeUpdateDeviceSettings-fm POST /streaming/music/musicprovider/{providerID}/is_eligible handlers.(*Server).HandleMusicProviderIsEligible-fm +POST /streaming/music/musicprovider/{providerID}/trial/is_eligible handlers.(*Server).HandleMusicProviderIsEligible-fm POST /streaming/stats/error handlers.(*Server).HandleErrorStats-fm POST /streaming/stats/usage handlers.(*Server).HandleUsageStats-fm POST /streaming/support/customersupport handlers.(*Server).HandleMargeCustomerSupport-fm diff --git a/docs/SUMMARY.md b/docs/SUMMARY.md index b5788a8..b65bab8 100644 --- a/docs/SUMMARY.md +++ b/docs/SUMMARY.md @@ -39,6 +39,7 @@ * [System Endpoints](reference/SYSTEM-ENDPOINTS.md) * [Speaker Endpoint](reference/SPEAKER-ENDPOINT.md) * [WebSocket Events](reference/WEBSOCKET-EVENTS.md) +* [Device Pairing Flow](reference/DEVICE-PAIRING-FLOW.md) * [Discovery](reference/DISCOVERY.md) * [Zone Management](reference/ZONE-MANAGEMENT.md) * [Preset Management](reference/PRESET-MANAGEMENT.md) diff --git a/docs/reference/DEVICE-PAIRING-FLOW.md b/docs/reference/DEVICE-PAIRING-FLOW.md new file mode 100644 index 0000000..d0940dc --- /dev/null +++ b/docs/reference/DEVICE-PAIRING-FLOW.md @@ -0,0 +1,521 @@ +# SoundTouch Device WebSocket API — Pairing & Operation Flow + +Reference document derived from mitmproxy captures of the Bose SoundTouch Android app +(`bose-pairing-20260502-155542`, `bose-pairing-20260502-165549`). + +> **Why this matters:** With Bose cloud services shutting down on 2026-05-06, the original +> app may stop working for pairing and playback control. This document captures the exact +> WebSocket message sequences needed to replicate those flows independently. + +--- + +## Connection + +All interactions use the SoundTouch WebSocket API on the speaker's local IP, port **8090** +(the same port as the REST API). Connect with the `Gabbo` sub-protocol: + +``` +GET ws://192.168.x.y:8090/ +Upgrade: websocket +Sec-WebSocket-Protocol: Gabbo +``` + +Upon connection the server immediately sends an identification banner: + +```xml + +``` + +--- + +## Message Envelope + +All subsequent messages (except `selectLastWiFiSource`, see below) use this envelope: + +**Client → Server request:** +```xml + +
+ + + + +
+ + + +
+``` + +**Server → Client response:** +```xml + + +
+ + + +
+ + + +
+``` + +**Server → Client push (unsolicited):** +```xml + + ... + +``` + +`requestID` is a monotonically increasing integer per connection (client-side sequence). +`{device_id}` is the speaker's MAC address with colons removed (e.g. `08DF1F0BA325`). + +--- + +## Phase 1 — Discovery: Is the Speaker Already Paired? + +```xml + +
+ +
+ + + + SoundTouch 10 + SoundTouch 10 + 9569497 + https://streaming.bose.com + ... + +``` + +- **Empty `margeAccountUUID`** → device is unpaired, proceed to Phase 2 +- **Populated `margeAccountUUID`** → already paired with that account ID + +--- + +## Phase 2 — Pairing a New Speaker + +### 2.1 Setup State Machine + +The pairing flow uses a setup state machine on the device. States must be sent in order. + +```xml + +
+ +
+ + +
+ +
+ + + + + + + + + +
+ +
3
+ + +
+ +
+ + +
+ +
+ + +
+ +
My SoundTouch 10
+``` + +### 2.2 Account Pairing — The Critical Step + +```xml + +
+ +
+ + {accountId} + Bearer {token} + +
+ + + + ... + {accountId} + ... + +``` + +The server also pushes several `sourcesUpdated` events after successful pairing. + +**`{accountId}`** — the numeric Bose account ID (e.g. `9569497`), obtainable from +`GET /streaming/account/login` on soundtouch-service. + +**`{token}`** — a Bearer token issued by Bose authentication (or soundtouch-service). +The full token from the captures: +``` +Bearer NtJDRbNtY3hDhm5K8FC2JprRhRQNH3QdZjG6aR4ASwYQg4rvZMY6dPLc3Bm6zvWNciWzCpMWZ/dbITRQoVdClOdssgDO+Nlh4ZJWp2w3tZiGzB8Flho0c+ipXnT/0Yg5 +``` +(session-specific; obtain a fresh one from the service's account login flow) + +### 2.3 Finish Setup and Telemetry + +```xml + +
+ +
+ + +
+ +
+ + +/pushCustomerSupportInfoToMarge +``` + +--- + +## Phase 3 — Unpairing + +```xml + +
+ + + + +
+ + + +``` + +--- + +## Phase 4 — App Initialization (Bulk State Fetch) + +When the app connects to an already-paired device it sends these in rapid parallel sequence: + +``` +info (GET) — device metadata, check pairing +sources (GET) — available input sources +presets (GET) — saved presets 1–6 +swUpdateQuery (POST) — check if update is in progress +capabilities (GET) — hardware capabilities, network config +bassCapabilities (GET) — bass range and defaults +now_playing (GET) — current playback state +volume (GET) — current volume +getZone (GET) — multi-room zone membership +clockDisplay (POST) — set clock timezone/format +``` + +Then a second wave: + +``` +swUpdateCheck (POST) — check for new firmware +systemtimeout (GET) — power-saving timeout +rebroadcastlatencymode (GET) — zone latency mode +getGroup (GET) — stereo-pair group +language (GET, sourceItem source="settings") — UI language +bass (GET) — current bass level +serviceAvailability (GET, sourceItem source="add_service" or "settings") +webserver/pingRequest (GET) — keepalive +pushCustomerSupportInfoToMarge (GET) — telemetry +netStats (GET, sourceItem source="settings") — network statistics +introspect (POST, sourceItem source="AIRPLAY") — AirPlay2 capabilities +``` + +`clockDisplay` example with timezone: +```xml + + + +``` + +`serviceAvailability` response lists availability of all service types (PANDORA, AIRPLAY, +AMAZON, DEEZER, SPOTIFY, TUNEIN, SIRIUSXM_EVEREST, BLUETOOTH, etc.) with `isAvailable` +and optional `reason` attributes. + +--- + +## Playback Control + +### Start Playback via `playbackRequest` (preferred — bypasses source checks) + +```xml +
+ +
+ + + 1LIVE + + +
+ + + + + +``` + +For a TuneIn podcast episode, use `type="tracklisturl"` and +`location="/v1/playback/episodes/{id}?encoded_name={base64}"`. + +### Select Content via `select` (triggers preset/recents UI highlight) + +```xml +
+ +
+ + 1LIVE + +
+``` + +Note: `select` with a TUNEIN item that the device can't resolve directly may return +`error value="1005" name="UNKNOWN_SOURCE_ERROR"`. Use `playbackRequest` instead for +reliable playback. + +### Special: Select Last Wi-Fi Source + +A plain-text (non-XML) client message: +``` +selectLastWiFiSource +``` + +Server responds with plain text: +``` +/selectLastWiFiSource +``` + +### Key Presses + +```xml + +
+ +
{KEY}
+ + +
+ +
{KEY}
+``` + +Key names observed: `POWER`, `STOP`, `PAUSE`, `ADD_FAVORITE` + +`sender="Gabbo"` is the app identifier string used by all Bose mobile apps. + +### Volume + +```xml + +
+ +
30
+ + + + + 3030false + + +``` + +### Bass + +```xml + +
+ +
+ + +
+ +
-2
+ + +``` + +--- + +## Browse & Navigate + +```xml + +
+ +
+ + + + 4 + + + 1LIVE + + ... + + +``` + +Use `type="update"` on `` for subsequent refresh calls on the same menu. + +--- + +## Settings + +### System Timeout (Power-Saving) + +```xml + +
+ +
+ + +
+ +
false
+``` + +### Clock Display + +```xml +
+ +
+ + + +
+``` + +--- + +## Keepalive + +The app sends a ping roughly every 30 seconds: + +```xml + +
+ +
+ + + +``` + +--- + +## Server Push Events (Unsolicited) + +The server wraps push events in ``: + +| Event element | Trigger | +|----------------------------------|-----------------------------------------------------------------------------------------------------| +| `nowPlayingUpdated` | Source/track changed, playback state changed | +| `nowSelectionUpdated` | Preset slot highlighted (UI selection changed) | +| `recentsUpdated` | Recents list changed | +| `presetsUpdated` | Preset saved or modified | +| `volumeUpdated` | Volume changed (any source) | +| `bassUpdated` | Bass level changed | +| `connectionStateUpdated` | Wi-Fi signal strength changed (`EXCELLENT_SIGNAL`, `GOOD_SIGNAL`, `MARGINAL_SIGNAL`, `POOR_SIGNAL`) | +| `soundTouchConfigurationUpdated` | Setup state changed (e.g. `SOUNDTOUCH_CONFIGURING`) | +| `infoUpdated` | Device info changed (e.g. after un-pairing) | +| `sourcesUpdated` | Available sources list changed | + +Separate push (not inside ``): +```xml + +``` +Sent after any physical or app-initiated user action. + +--- + +## Notification (Client → Device Push) + +Used by the app to notify the device of data that has changed on the service side +(e.g. after syncing presets from cloud). Header uses `propagate="false"`: + +```xml + +
+ +
+ + + +
+ + +/notification +``` + +--- + +## Complete Pairing Sequence (Minimal) + +To pair a freshly factory-reset speaker to a Bose account (soundtouch-service must be +running and authenticated): + +``` +1. Connect WebSocket to ws://{speakerIP}:8090/ +2. Receive: +3. GET info → confirm margeAccountUUID is empty +4. POST setup SETUP_START +5. POST setup SETUP_IDENTIFY_DEVICE_ENTER (timeout=300000) + (user physically presses button on speaker to confirm identity) +6. POST language 3 +7. POST setup SETUP_ENTER +8. POST setup SETUP_IDENTIFY_DEVICE_LEAVE +9. POST name {desired name} +10. POST setMargeAccount + {accountId} + Bearer {token} + + → device responds with info, margeAccountUUID is now set +11. POST setup SETUP_LEAVE +12. GET pushCustomerSupportInfoToMarge (telemetry, safe to skip) +``` + +--- + +## Source References + +- `bose-pairing-20260502-155542` — Session 1: initial pairing of SoundTouch 10 to account 9569497 +- `bose-pairing-20260502-165549` — Session 2: re-pairing and full operation (TuneIn, Spotify, presets) +- Raw WebSocket files: `scripts/android/mitm/{session}/mirror/{n}-websocket/*.txt` +- Companion HTTP upgrade files: `scripts/android/mitm/{session}/mirror/{n}-*.http` diff --git a/pkg/discovery/dns.go b/pkg/discovery/dns.go index 5404dd2..49c979e 100644 --- a/pkg/discovery/dns.go +++ b/pkg/discovery/dns.go @@ -171,6 +171,7 @@ func (d *DNSDiscovery) shouldIntercept(hostname string) bool { "music.api.bose.com", "bosecm.com", "bose.io", + "downloads.bose.com", } for _, service := range interceptList { diff --git a/pkg/service/datastore/datastore.go b/pkg/service/datastore/datastore.go index 0d4f29b..e55bf5c 100644 --- a/pkg/service/datastore/datastore.go +++ b/pkg/service/datastore/datastore.go @@ -2038,3 +2038,33 @@ func (ds *DataStore) DeleteGroup(account, groupID string) error { return err } + +// SaveTuneInFavorite records a TuneIn station as favorited by creating a marker file. +// File presence indicates the station is a favorite; no content is stored. +func (ds *DataStore) SaveTuneInFavorite(stationID string) error { + if ds == nil || ds.DataDir == "" || stationID == "" { + return nil + } + + dir := ds.safeJoin("tunein", "favorites") + if err := os.MkdirAll(dir, 0755); err != nil { + return err + } + + return os.WriteFile(ds.safeJoin("tunein", "favorites", stationID), nil, 0644) +} + +// DeleteTuneInFavorite removes a previously saved TuneIn favorite marker file. +// Returns nil if the station was not favorited. +func (ds *DataStore) DeleteTuneInFavorite(stationID string) error { + if ds == nil || ds.DataDir == "" || stationID == "" { + return nil + } + + err := os.Remove(ds.safeJoin("tunein", "favorites", stationID)) + if os.IsNotExist(err) { + return nil + } + + return err +} diff --git a/pkg/service/handlers/handlers_bmx.go b/pkg/service/handlers/handlers_bmx.go index da52836..90e864c 100644 --- a/pkg/service/handlers/handlers_bmx.go +++ b/pkg/service/handlers/handlers_bmx.go @@ -4,12 +4,14 @@ package handlers import ( "encoding/base64" "encoding/json" + "log" "net/http" "net/url" "strconv" "strings" "github.com/gesellix/bose-soundtouch/pkg/service/bmx" + "github.com/gesellix/bose-soundtouch/pkg/service/datastore" "github.com/go-chi/chi/v5" ) @@ -148,6 +150,29 @@ func (s *Server) HandleTuneInToken(w http.ResponseWriter, r *http.Request) { } } +// HandleOrionToken returns an anonymous Orion access token. +// The token is a base64-encoded JSON serial, matching the pattern used by the real Bose BMX Orion service. +func (s *Server) HandleOrionToken(w http.ResponseWriter, _ *http.Request) { + token := datastore.GenerateSerialSecret("orion") + + resp := map[string]interface{}{ + "_embedded": map[string]interface{}{ + "bmx_account": map[string]string{ + "displayName": "", + "username": "", + }, + }, + "access_token": token, + "refresh_token": token, + } + + w.Header().Set("Content-Type", "application/json") + + if err := json.NewEncoder(w).Encode(resp); err != nil { + http.Error(w, "Failed to encode response", http.StatusInternalServerError) + } +} + // HandleOrionPlayback returns Orion playback information. func (s *Server) HandleOrionPlayback(w http.ResponseWriter, r *http.Request) { if r.Header.Get("Authorization") == "" { @@ -341,3 +366,27 @@ func (s *Server) HandleTuneInSearch(w http.ResponseWriter, r *http.Request) { http.Error(w, "Failed to encode response", http.StatusInternalServerError) } } + +// HandleTuneInFavorite handles POST /bmx/tunein/v1/favorite/{stationID}. +func (s *Server) HandleTuneInFavorite(w http.ResponseWriter, r *http.Request) { + stationID := chi.URLParam(r, "stationID") + if err := s.ds.SaveTuneInFavorite(stationID); err != nil { + log.Printf("Failed to persist TuneIn favorite %s: %v", stationID, err) + } + + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusAccepted) + _, _ = w.Write([]byte("{}")) +} + +// HandleTuneInDeleteFavorite handles DELETE /bmx/tunein/v1/favorite/{stationID}. +func (s *Server) HandleTuneInDeleteFavorite(w http.ResponseWriter, r *http.Request) { + stationID := chi.URLParam(r, "stationID") + if err := s.ds.DeleteTuneInFavorite(stationID); err != nil { + log.Printf("Failed to delete TuneIn favorite %s: %v", stationID, err) + } + + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusAccepted) + _, _ = w.Write([]byte("{}")) +} diff --git a/pkg/service/handlers/handlers_media.go b/pkg/service/handlers/handlers_media.go index 629abf8..1377834 100644 --- a/pkg/service/handlers/handlers_media.go +++ b/pkg/service/handlers/handlers_media.go @@ -17,6 +17,9 @@ var webFS embed.FS //go:embed static/media/* var mediaFS embed.FS +//go:embed static/ced +var cedFS embed.FS + //go:embed static/bmx_services.json var bmxServicesJSON []byte @@ -59,3 +62,21 @@ func (s *Server) HandleMedia() http.HandlerFunc { http.StripPrefix("/media", http.FileServer(http.FS(subFS))).ServeHTTP(w, r) } } + +// HandleBmxIcons returns a handler for serving BMX icon assets (media.bose.io /bmx-icons/*). +func (s *Server) HandleBmxIcons() http.HandlerFunc { + subFS, _ := fs.Sub(mediaFS, "static/media") + + return func(w http.ResponseWriter, r *http.Request) { + http.FileServer(http.FS(subFS)).ServeHTTP(w, r) + } +} + +// HandleCedStatic returns a handler for serving downloads.bose.com CED static files. +func (s *Server) HandleCedStatic() http.HandlerFunc { + subFS, _ := fs.Sub(cedFS, "static/ced") + + return func(w http.ResponseWriter, r *http.Request) { + http.StripPrefix("/ced", http.FileServer(http.FS(subFS))).ServeHTTP(w, r) + } +} diff --git a/pkg/service/handlers/handlers_setup_test.go b/pkg/service/handlers/handlers_setup_test.go index 251b1fa..b7cc1d0 100644 --- a/pkg/service/handlers/handlers_setup_test.go +++ b/pkg/service/handlers/handlers_setup_test.go @@ -417,7 +417,7 @@ func (m *mockSSH) Run(command string) (string, error) { m.runCount++ if m.runCount > 1 { // Return updated hosts for verification - return "127.0.0.1 localhost\n192.168.1.100\tstreaming.bose.com\n192.168.1.100\tupdates.bose.com\n192.168.1.100\tstats.bose.com\n192.168.1.100\tbmx.bose.com\n192.168.1.100\tcontent.api.bose.io\n192.168.1.100\tevents.api.bosecm.com\n192.168.1.100\tbose-prod.apigee.net\n192.168.1.100\tworldwide.bose.com", nil + return "127.0.0.1 localhost\n192.168.1.100\tstreaming.bose.com\n192.168.1.100\tupdates.bose.com\n192.168.1.100\tstats.bose.com\n192.168.1.100\tbmx.bose.com\n192.168.1.100\tcontent.api.bose.io\n192.168.1.100\tevents.api.bosecm.com\n192.168.1.100\tbose-prod.apigee.net\n192.168.1.100\tworldwide.bose.com\n192.168.1.100\tmedia.bose.io\n192.168.1.100\tdownloads.bose.com", nil } return "127.0.0.1 localhost", nil } diff --git a/pkg/service/handlers/static/ced/soundtouch/mr4_22097fe2/index.xml b/pkg/service/handlers/static/ced/soundtouch/mr4_22097fe2/index.xml new file mode 100644 index 0000000..151a14d --- /dev/null +++ b/pkg/service/handlers/static/ced/soundtouch/mr4_22097fe2/index.xml @@ -0,0 +1,312 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/pkg/service/handlers/static/ced/soundtouch/mr4_22097fe2/relnotes/releasenotes_en.xml b/pkg/service/handlers/static/ced/soundtouch/mr4_22097fe2/relnotes/releasenotes_en.xml new file mode 100644 index 0000000..4c74e0d --- /dev/null +++ b/pkg/service/handlers/static/ced/soundtouch/mr4_22097fe2/relnotes/releasenotes_en.xml @@ -0,0 +1,101 @@ + + + + Fixed bugs and did some general cleaning up under the hood + + + Fixed bugs and did some general cleaning up under the hood + + + Airplay2 support arrives for SoundTouch Wireless Link adapter! + Added improvements to the setup experience + General bug fixes and improvements + + + As usual, this release includes bug fixes and performance improvements + + + Added lots of under the hood changes to improve the app experience on iOS13 + Fixed an issue with Wi-Fi setup on certain Android devices + Additional bug fixes and performance improvements + + + We've added RadioPlayer to our family of music services! Enjoy thousands of regional stations and on demand programs right at your fingertips. Available in select regions + You can now disable the automatic power save mode in the app for your SoundTouch 10, SoundTouch 20 and SoundTouch 30 + Additional bug fixes & enhancements + + + Save more music — you can now save Favorites along with your 6 presets + We improved Spotify search so you can get grooving faster + It's now easier to access Recently Played + Little tweaks here and there to make the app better for you + + + Say hello to TuneIn (and goodbye to Internet Radio) + Easily browse through your favorite artists in Spotify + We made it easier to create an account and reset your password + General improvements made with our special app-tuning forks + + + Security related updates to improve application configuration and operation + Many other bug fixes and enhancements + + + By updating, you agree to our new Privacy Policy and Terms of Use available at https://worldwide.bose.com/privacypolicy and https://worldwide.bose.com/termsofuse + Security related updates to improve application configuration and operation + We tuned the app to include some major performance and stability improvements + + + Enhanced broadcasting performance of AUX/wired input to other SoundTouch speakers + Search enabled in Amazon Music + Many other bug fixes and enhancements + + + SoundTouch.com/privacy]]> + Broadcasting of AUX/wired input to other SoundTouch speakers + Volume and grouping enhancements + New "Just for You" section + Many other bug fixes and enhancements + + + As usual, this release includes bug fixes and performance improvements + + + We made your SoundTouch® experience better, with a completely redesigned app that's easier to use and nicer to look at + Stereo pairing for SoundTouch® 10 speakers + QQ Music QPlay streaming support (China only) + Now you can control your speaker from your Apple Watch® – just open the Watch app and add SoundTouch® + There’s a new SoundTouch® widget available for iOS – add it in the Today View so you can control your speaker even while your device is locked + We made speaker selection and volume control more reliable + The app now shows Pandora’s new logo + Plus, we fixed some bugs and made things more stable + + + Updated music library experience with faster navigation, easier search, and more album art + Improved Android Wear support + Bug fixes + + + Added Amazon Prime Music (US Only) + Android Wear notifications support + Android lock-screen controls + SiriusXM® Business Account support + Over 30 bug fixes + + + Support for additional music services (where available) + Search for a track, album, or artist in your stored music library + Adjust the bass performance of your SoundTouch® system + Additional bug fixes and performance improvements + + + Enables wireless setup of SoundTouch® products + Faster connection to speakers on your network + + + Enhanced detection of speakers on your network + + + Improved system discovery + + diff --git a/pkg/service/handlers/static/ced/soundtouch/soundtouch_app_help/en/bose_account_create_1.xml b/pkg/service/handlers/static/ced/soundtouch/soundtouch_app_help/en/bose_account_create_1.xml new file mode 100644 index 0000000..209e2bb --- /dev/null +++ b/pkg/service/handlers/static/ced/soundtouch/soundtouch_app_help/en/bose_account_create_1.xml @@ -0,0 +1,2 @@ + + Why do I need to create an account?A SoundTouch® account is required to keep track of your speakers, presets and music service. In addition, an account helps us better support your speaker and troubleshoot problems.

If you are setting up multiple SoundTouch® speakers, we strongly recommend that you set them up on the same SoundTouch® account. Also, any time you install the SoundTouch® app on another mobile device or computer, you are required to sign in using your SoundTouch® account info.

]]>
Why do I have to provide my email address?Each SoundTouch® account is uniquely identified by an email address. Notifications of software and service updates are sent to this address. When you provide your email address, you can choose (or decline) to receive emails from Bose® about new products, events and other announcements. Please read our privacy policy to learn more about how we use your email address by selecting Settings > About > LEGAL.

If you prefer not to provide your email address, you can set up your speaker anonymously by providing a single-purpose or even non-working email address. In this case, your speaker will continue to receive system software updates, but you will not receive email notifications explaining the new features when these updates are available.

]]>
Is there a minimum character or format requirement for the password?Your password must be at least six characters in length. The password field is case sensitive.

]]>
Why should I provide my name and address?We use your name and address to improve your customer service experience should you need assistance. Please read our privacy policy to understand other ways we may use your name and address by selecting Settings > About > LEGAL.

]]>
\ No newline at end of file diff --git a/pkg/service/handlers/static/ced/soundtouch/soundtouch_app_help/en/gabbo_ios_settings.xml b/pkg/service/handlers/static/ced/soundtouch/soundtouch_app_help/en/gabbo_ios_settings.xml new file mode 100644 index 0000000..604eb81 --- /dev/null +++ b/pkg/service/handlers/static/ced/soundtouch/soundtouch_app_help/en/gabbo_ios_settings.xml @@ -0,0 +1,2 @@ + + How do I change my network?Change your network from the Settings menu on your mobile device.

  1. On your mobile device, tap the Home button.

  2. Tap Settings > Wi-Fi.

    Note: By default, the Settings menu is on the Home screen.

  3. Select the Wi-Fi® network starting with Bose.

  4. Tap the Home button.

  5. Tap the SoundTouch® icon to return to the SoundTouch® app.

]]>
Why do I need to connect to the "Bose" Wi-Fi® network?Connecting to the "Bose" Wi-Fi® network enables your speaker to be set up on your home Wi-Fi® network. Connecting to this network is temporary. After you set up the speaker, you reconnect to your home network.

]]>
I can't find the "Bose" Wi-Fi® network.Make sure that you're looking for the Wi-Fi® network starting with Bose. It may take up to 30 seconds for the network to appear on the list.

If the network does not appear after 30 seconds, select I Don't See This Network to put the system into setup mode and continue with setup.

]]>
How do I return to the app from my mobile device's Settings menu?
  • On your mobile device, tap the Home button.

    On the Home screen, tap the SoundTouch® icon.

  • ]]>
    diff --git a/pkg/service/handlers/static/ced/soundtouch/soundtouch_app_help/en/gabbo_recovery_lisa.xml b/pkg/service/handlers/static/ced/soundtouch/soundtouch_app_help/en/gabbo_recovery_lisa.xml new file mode 100644 index 0000000..6608941 --- /dev/null +++ b/pkg/service/handlers/static/ced/soundtouch/soundtouch_app_help/en/gabbo_recovery_lisa.xml @@ -0,0 +1,2 @@ + + The Wi-Fi® indicator isn't glowing amber. What do I do now?If the Wi-Fi® indicator is not glowing solid amber, your system is not in setup mode.

    1. Power on your system.

    2. Press and hold the Control button on the back of the SoundTouch® wireless adapter for 1-8 seconds.

      Note: If the Wi-Fi® indicator does not glow solid amber, press and hold the Control button again, making sure to release the button before 8 seconds elapses.

    ]]>
    Where is the Control button?The Control button is on the SoundTouch® wireless adapter's connector panel.

    ]]>
    Where is the Wi-Fi® indicator?The Wi-Fi® indicator is on the SoundTouch® wireless adapter's connector panel.

    ]]>
    diff --git a/pkg/service/handlers/static/ced/soundtouch/soundtouch_app_help/en/gabbo_recovery_nelson.xml b/pkg/service/handlers/static/ced/soundtouch/soundtouch_app_help/en/gabbo_recovery_nelson.xml new file mode 100644 index 0000000..440b599 --- /dev/null +++ b/pkg/service/handlers/static/ced/soundtouch/soundtouch_app_help/en/gabbo_recovery_nelson.xml @@ -0,0 +1,2 @@ + + The Wi-Fi® indicator isn't glowing amber. What do I do now?If the Wi-Fi® indicator is not glowing solid amber, your system is not in setup mode.

    1. Power on your system.

    2. Press and hold the Control button on the back of the SoundTouch® pedestal for 1-8 seconds.

      The Wi-Fi® indicator glows solid amber.

      The message SETUP SEE INSTRUCTIONS appears on the display.

      Your system is now in setup mode.

    Note: If the Wi-Fi® indicator does not glow solid amber and the message does not appear on the display, press and hold the Control button again, making sure to release the button before 8 seconds elapses.

    ]]>
    Where is the Control button?The Control button is on the SoundTouch® pedestal’s connector panel.

    ]]>
    Where is the Wi-Fi® indicator?The Wi-Fi® indicator is on the SoundTouch® pedestal’s connector panel.

    ]]>
    diff --git a/pkg/service/handlers/static/ced/soundtouch/soundtouch_app_help/en/gabbo_recovery_select_system.xml b/pkg/service/handlers/static/ced/soundtouch/soundtouch_app_help/en/gabbo_recovery_select_system.xml new file mode 100644 index 0000000..7a1528f --- /dev/null +++ b/pkg/service/handlers/static/ced/soundtouch/soundtouch_app_help/en/gabbo_recovery_select_system.xml @@ -0,0 +1,14 @@ + + + +What is the name of my speaker? + +Check the carton or the owner's guide that shipped with your speaker. You may also find the name of the speaker on a label on the back or bottom of the speaker.

    ]]> +
    + +What is the "Bose" Wi-Fi® network? + +Your speaker has its own built-in Wi-Fi network that you use to set up your speaker. You will temporarily connect to this network on the device you are using, set the speaker up on your network and then reconnect to your home Wi-Fi network.

    ]]> +
    +
    +
    \ No newline at end of file diff --git a/pkg/service/handlers/static/ced/soundtouch/soundtouch_app_help/en/gabbo_recovery_smt.xml b/pkg/service/handlers/static/ced/soundtouch/soundtouch_app_help/en/gabbo_recovery_smt.xml new file mode 100644 index 0000000..f25e668 --- /dev/null +++ b/pkg/service/handlers/static/ced/soundtouch/soundtouch_app_help/en/gabbo_recovery_smt.xml @@ -0,0 +1,2 @@ + + The Wi-Fi® indicator isn't glowing amber. What do I do now?If the Wi-Fi® indicator is not glowing solid amber, your speaker is not in setup mode.

    1. Power on your speaker.

    2. On the button pad, press and hold the 2 and Volume - buttons until the countdown reaches 1 and a message similar to "Setup" appears on the display.

      The Wi-Fi® indicator glows solid amber.

      Your system is now in Setup mode.

    ]]>
    Where is the Wi-Fi® indicator?The Wi-Fi® indicator is on the front of the speaker.

    ]]>
    diff --git a/pkg/service/handlers/static/ced/soundtouch/soundtouch_app_help/en/name_device.xml b/pkg/service/handlers/static/ced/soundtouch/soundtouch_app_help/en/name_device.xml new file mode 100644 index 0000000..45f578a --- /dev/null +++ b/pkg/service/handlers/static/ced/soundtouch/soundtouch_app_help/en/name_device.xml @@ -0,0 +1,2 @@ + + Why should I name my speaker?Naming the speaker makes it easy to recognize in the app when you have multiple speakers. You can use a name that identifies the space where the speaker is placed, for example, such as Living Room.

    ]]>
    Can I rename this speaker later?Yes, you can rename the speaker from the Settings menu. Select Settings > Speaker Settings, then select your speaker.

    ]]>
    diff --git a/pkg/service/handlers/static/ced/soundtouch/soundtouch_app_help/en/prompt_other_devices.xml b/pkg/service/handlers/static/ced/soundtouch/soundtouch_app_help/en/prompt_other_devices.xml new file mode 100644 index 0000000..eaed18c --- /dev/null +++ b/pkg/service/handlers/static/ced/soundtouch/soundtouch_app_help/en/prompt_other_devices.xml @@ -0,0 +1,2 @@ + + Can I set up another speaker later?Yes. Select Settings > Add or Reconnect Speaker.

    ]]>
    How many speakers can I add to my network?You can add as many speakers to your network as determined by the capacity of your home Wi-Fi® network.

    ]]>
    diff --git a/pkg/service/handlers/static/ced/soundtouch/soundtouch_app_help/en/setup_done.xml b/pkg/service/handlers/static/ced/soundtouch/soundtouch_app_help/en/setup_done.xml new file mode 100644 index 0000000..71fdb9d --- /dev/null +++ b/pkg/service/handlers/static/ced/soundtouch/soundtouch_app_help/en/setup_done.xml @@ -0,0 +1,2 @@ + + diff --git a/pkg/service/handlers/static/ced/soundtouch/soundtouch_app_help/en/wifi_or_ethernet_ask.xml b/pkg/service/handlers/static/ced/soundtouch/soundtouch_app_help/en/wifi_or_ethernet_ask.xml new file mode 100644 index 0000000..963dd18 --- /dev/null +++ b/pkg/service/handlers/static/ced/soundtouch/soundtouch_app_help/en/wifi_or_ethernet_ask.xml @@ -0,0 +1,2 @@ + + How should I connect my speaker to my network?You can connect your speaker to your network using a Wi-Fi® or Ethernet connection. If you select Ethernet, make sure the Ethernet cable from your router can reach your speaker.

    Note: If you are setting up a SoundTouch® 10 speaker, SoundTouch® Wireless Link or SoundTouch® Portable Wi-Fi® music system, you must select WI-FI.

    ]]>
    Will there be a difference in performance between a wired and a wireless setup?Performance varies depending on the number of devices on your network and how the devices are connected. A wireless connection provides more flexibility when placing your system. A wired connection is better when your wireless router's signal is weak or can't be received.

    ]]>
    diff --git a/pkg/service/handlers/static/media/bmx-icons/tunein/top-menu/bubble.png b/pkg/service/handlers/static/media/bmx-icons/tunein/top-menu/bubble.png new file mode 100644 index 0000000000000000000000000000000000000000..d17764b07b44b7e65e6d1da4e346059246fed7d0 GIT binary patch literal 2288 zcmc(h`9Bj51IN)~$}#3hC?<;uX>upWWX?$BNRGuO(%i=uxiazaOp** zlg%UcQhxwI>ze7Zuv8?SKXEzB!U8NXLg?NPW?jql^b)WZXy3@3)H^4TGvwUDvciD^ z=~D-UfH{)(weptd6iOL|5(t#?R#Y52O5);-@Dx-VLM*IU+wPBEr-LA8sa~SsEN6T+ zYg0Dze394X@yu1bD~}!MnzSSwdSN>&`fr@mV#d@_(E7w=re?x43oGdVq6;Q3lH_G} ze->jgl#cE_)4yvX<8$?rlC}oG-y_>a(Cu9AUYhp8Cz8)gKBpK9TDm!yM0ME0QLcI} z6Rk3%;P1`sC^N=!+vMoMhhcp(VSThNXuBqO!^k(Un<9siCVm|CFvzDJ3^5=6+a(GC zTU5Imxz_O;9!|1W)TA%q@nyp$Mv-UM7$O;u~4(t|AHP;a@?hfrwz{ zO&TYkN2@t!W0ZEJ2;NwBe0RnowH1;R$%EaD^AL7S8e%yo}Q!t#rynl{8 zZ11SMjP}`{PP>lZ*at*9jfs?3HiRT1Hy4Z6*p4fAQ(P`wHaO#XFtWV5phDqiB-823 zXDUvgMLW~PV_^!RSW)o8N+-6f4dXZ)OTrgprb1$o31X64rZr6O2oG|J&>gbs9)L`D zUs>JPxNC;?`PMWl$Y$JAoQ<;u;2I$OB(goeb+zS-rYu|SL$lk{Bb71(zFqTdyp5YF z1i-Axe3X%)AjFqeK4XdpVZmXI-+Sd&U$xv!kb-abH&+_inOe^b^ zbEEKEiYSJ}_8UDS%Q>6uXM&fU@&DbTbQwKf$My+q<8k}`;O=5)`N2fkLiq^F zpZjLkUsZ$t@qV-)4jH8b1U}u)$(vyniNT?5mR@$*O6ZST!g_ zlK&_F?E1(oOPrP&)b@4>uxfWeJF(9A&on2)gEsMWeW+@)@h-W1;H9mnt1x?c7rn`9 z?Wx?PEJwrRx4rE7@2xssp1QzIf3mr^298Gb3($tOOzUE_boF)nh(6CE@)JLCq4G-=+i6{ z&9Thg-@m;5mc1B;WI|dNBPz0dK|f_AjzXC{zLJ07q4{*j1BE@sY5#)ny@BSA-fT;H z|9a$rl;E@$@P?RbUway2r4l=*5)Ma;Om$RBnIVLOlxG{EW2i0IZK?dbj@D|*chlaz zDT~4{I|vk}?7-QJO9gJL_^)V%0@)CS**gruOTpD21r|(d zs++Ef)oMe#RqW&3DBEh6b3I8(%e;*4uROxLBfuzeMc208<^W$+q5RSupE+Y^7l)l{ z;S%MTdWPfFVfRRdVweyUeTnMvqpTtz@0;J4=ae(A|F8-@0TwhZ>M=+$hI^e2m{p#-EQ6b30>Me6j~ zk!Mf(->J8;cLgduk=Xk@X5gc-Vr<~x`2nZ^y%hZ&fhTp z{%54|8k*1`>0LcmWqRsUjv^+wi(`h-&bnInKzTs*@SBzd#3&?>))#s)GG&R2|kwR8~qw=f7Bbz0|ifT9NKnll|l&0V%kw6u3momdeMk)GD=7@aOr|i7LH! z1@4mZPPhQ)FPu9ubWT1&a$#%muAN2J)b$mOk_V?K1`|F6B6i;Q5h_r$7ENTbhue7A z(B<*wSJJVahX5SvJ-rB?kBon-29`CJy0sA?CqG{$ccXyG)r){({e*Hk*qgFHr+`(k z&}7rh)NRI$5&Y6$zuSMYrau;@@+QG8wF%35>Q)DHymQY_IS&GD9`L$9S=`eg$YgQ7 z;;J(638SR$1UTO04qrrlKL1=Y7hlb&P%AM>FhHZxga&Q4}MF>GA%k~%Da g|BWO#*nYE)_b<6!JNxOzp9{lcWMGac({qme2lvzjO#lD@ literal 0 HcmV?d00001 diff --git a/pkg/service/handlers/static/media/bmx-icons/tunein/top-menu/location.png b/pkg/service/handlers/static/media/bmx-icons/tunein/top-menu/location.png new file mode 100644 index 0000000000000000000000000000000000000000..5197555bfa4acead7498e1519ce58c65b603adcd GIT binary patch literal 4354 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 N(o)ldy;HFd{|^Kl+}QvC literal 0 HcmV?d00001 diff --git a/pkg/service/handlers/static/media/bmx-icons/tunein/top-menu/news.png b/pkg/service/handlers/static/media/bmx-icons/tunein/top-menu/news.png new file mode 100644 index 0000000000000000000000000000000000000000..8c52195c0a9345246d2338c22a786a2079dd5a7e GIT binary patch literal 2651 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 S!{DDKM5d!*0IyQFef2+jfvoEQ literal 0 HcmV?d00001 diff --git a/pkg/service/handlers/static/media/bmx-icons/tunein/top-menu/podcasts.png b/pkg/service/handlers/static/media/bmx-icons/tunein/top-menu/podcasts.png new file mode 100644 index 0000000000000000000000000000000000000000..a83425c9d789620f8e3d1e3db509a57f34a0755c GIT binary patch literal 4263 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 B>wEwJ literal 0 HcmV?d00001 diff --git a/pkg/service/setup/setup.go b/pkg/service/setup/setup.go index e47c32e..9282c6e 100644 --- a/pkg/service/setup/setup.go +++ b/pkg/service/setup/setup.go @@ -278,6 +278,8 @@ func (m *Manager) GetMigrationSummary(deviceIP, targetURL, proxyURL string, opti "bose-prod.apigee.net", "worldwide.bose.com", "music.api.bose.com", + "media.bose.io", + "downloads.bose.com", } var hostsLines []string @@ -1061,6 +1063,8 @@ func (m *Manager) migrateViaHosts(deviceIP, targetURL string) (string, error) { "events.api.bosecm.com", "bose-prod.apigee.net", "worldwide.bose.com", + "media.bose.io", + "downloads.bose.com", } hostsContent, err := client.Run("cat /etc/hosts") diff --git a/pkg/service/setup/setup_test.go b/pkg/service/setup/setup_test.go index b92f752..35ce630 100644 --- a/pkg/service/setup/setup_test.go +++ b/pkg/service/setup/setup_test.go @@ -54,7 +54,7 @@ func TestMigrateViaHosts(t *testing.T) { if command == "cat /etc/hosts" { // Handle both initial read and verification read if len(runCalls) > 2 { // Rough heuristic: verification happens after upload - return "192.168.1.100\tstreaming.bose.com\n192.168.1.100\tupdates.bose.com\n192.168.1.100\tstats.bose.com\n192.168.1.100\tbmx.bose.com\n192.168.1.100\tcontent.api.bose.io\n192.168.1.100\tevents.api.bosecm.com\n192.168.1.100\tbose-prod.apigee.net\n192.168.1.100\tworldwide.bose.com", nil + return "192.168.1.100\tstreaming.bose.com\n192.168.1.100\tupdates.bose.com\n192.168.1.100\tstats.bose.com\n192.168.1.100\tbmx.bose.com\n192.168.1.100\tcontent.api.bose.io\n192.168.1.100\tevents.api.bosecm.com\n192.168.1.100\tbose-prod.apigee.net\n192.168.1.100\tworldwide.bose.com\n192.168.1.100\tmedia.bose.io\n192.168.1.100\tdownloads.bose.com", nil } return "127.0.0.1 localhost", nil } @@ -132,7 +132,7 @@ func TestMigrateViaHosts_UpdateExisting(t *testing.T) { runCount++ if command == "cat /etc/hosts" { if runCount > 1 { - return "127.0.0.1 localhost\n192.168.1.100\tstreaming.bose.com\n192.168.1.100\tupdates.bose.com\n192.168.1.100\tstats.bose.com\n192.168.1.100\tbmx.bose.com\n192.168.1.100\tcontent.api.bose.io\n192.168.1.100\tevents.api.bosecm.com\n192.168.1.100\tbose-prod.apigee.net\n192.168.1.100\tworldwide.bose.com", nil + return "127.0.0.1 localhost\n192.168.1.100\tstreaming.bose.com\n192.168.1.100\tupdates.bose.com\n192.168.1.100\tstats.bose.com\n192.168.1.100\tbmx.bose.com\n192.168.1.100\tcontent.api.bose.io\n192.168.1.100\tevents.api.bosecm.com\n192.168.1.100\tbose-prod.apigee.net\n192.168.1.100\tworldwide.bose.com\n192.168.1.100\tmedia.bose.io\n192.168.1.100\tdownloads.bose.com", nil } return "127.0.0.1 localhost\n1.2.3.4\tstreaming.bose.com\n1.2.3.4\tupdates.bose.com", nil } @@ -648,7 +648,7 @@ func TestMigrateViaHosts_SkipCAIfTrusted(t *testing.T) { if command == "cat /etc/hosts" { // Handle both initial read and verification read if len(runCalls) > 2 { // Rough heuristic: verification happens after upload - return "192.168.1.100\tstreaming.bose.com\n192.168.1.100\tupdates.bose.com\n192.168.1.100\tstats.bose.com\n192.168.1.100\tbmx.bose.com\n192.168.1.100\tcontent.api.bose.io\n192.168.1.100\tevents.api.bosecm.com\n192.168.1.100\tbose-prod.apigee.net\n192.168.1.100\tworldwide.bose.com", nil + return "192.168.1.100\tstreaming.bose.com\n192.168.1.100\tupdates.bose.com\n192.168.1.100\tstats.bose.com\n192.168.1.100\tbmx.bose.com\n192.168.1.100\tcontent.api.bose.io\n192.168.1.100\tevents.api.bosecm.com\n192.168.1.100\tbose-prod.apigee.net\n192.168.1.100\tworldwide.bose.com\n192.168.1.100\tmedia.bose.io\n192.168.1.100\tdownloads.bose.com", nil } return "127.0.0.1 localhost", nil } diff --git a/tests/interactions_20260328-103522-477978.md b/tests/interactions_20260328-103522-477978.md index bcaf49a..417b59a 100644 --- a/tests/interactions_20260328-103522-477978.md +++ b/tests/interactions_20260328-103522-477978.md @@ -1,249 +1,251 @@ Interactions for `20260328-103522-477978/`: -| sequence number | category | ignore/done | request | response status | filename | -|-----------------|----------|-------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------|--------------------------------------------------------------------------------------------------------| -| 0001 | self | ☑ | GET / | 200 OK | ./self/root/0001-20260328-103539.205-GET.http | -| 0002 | self | ☑ | GET /mgmt/spotify/accounts | 200 OK | ./self/mgmt/spotify/accounts/0002-20260328-103539.483-GET.http | -| 0003 | self | ☑ | GET /mgmt/spotify/accounts | 200 OK | ./self/mgmt/spotify/accounts/0003-20260328-103539.514-GET.http | -| 0004 | self | ☑ | GET /mgmt/spotify/accounts | 200 OK | ./self/mgmt/spotify/accounts/0004-20260328-103539.539-GET.http | -| 0005 | self | ☑ | GET /mgmt/spotify/accounts | 200 OK | ./self/mgmt/spotify/accounts/0005-20260328-103539.554-GET.http | -| 0006 | self | ☑ | GET /mgmt/spotify/accounts | 200 OK | ./self/mgmt/spotify/accounts/0006-20260328-103551.537-GET.http | -| 0007 | self | ☑ | GET /mgmt/spotify/accounts | 200 OK | ./self/mgmt/spotify/accounts/0007-20260328-103551.551-GET.http | -| 0008 | self | ☑ | GET /bmx/registry/v1/services | 200 OK | ./self/bmx/registry/v1/services/0008-20260328-103731.202-GET.http | -| 0009 | self | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./self/v1/scmudc/{device_id}/0009-20260328-103731.221-POST.http | -| 0010 | self | ☑ | POST /streaming/support/power_on | 200 OK | ./self/streaming/support/power_on/0010-20260328-103731.226-POST.http | -| 0011 | mirror | ☑ | POST /streaming/support/power_on | 200 OK | ./mirror/streaming/support/power_on/0011-20260328-103731.407-POST.http | -| 0012 | self | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./self/v1/scmudc/{device_id}/0012-20260328-103731.625-POST.http | -| 0013 | mirror | ☑ | GET /bmx/registry/v1/services | 200 OK | ./mirror/bmx/registry/v1/services/0013-20260328-103731.641-GET.http | -| 0014 | mirror | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./mirror/v1/scmudc/{device_id}/0014-20260328-103731.652-POST.http | -| 0015 | self | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./self/v1/scmudc/{device_id}/0015-20260328-103731.725-POST.http | -| 0016 | self | ☑ | GET / | 200 OK | ./self/root/0016-20260328-103731.804-GET.http | -| 0017 | self | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./self/v1/scmudc/{device_id}/0017-20260328-103731.806-POST.http | -| 0018 | mirror | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./mirror/v1/scmudc/{device_id}/0018-20260328-103732.053-POST.http | -| 0019 | mirror | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./mirror/v1/scmudc/{device_id}/0019-20260328-103732.173-POST.http | -| 0020 | mirror | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./mirror/v1/scmudc/{device_id}/0020-20260328-103732.229-POST.http | -| 0021 | self | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./self/v1/scmudc/{device_id}/0021-20260328-103733.180-POST.http | -| 0022 | self | ☑ | GET /streaming/sourceproviders | 200 OK | ./self/streaming/sourceproviders/0022-20260328-103733.439-GET.http | -| 0023 | mirror | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./mirror/v1/scmudc/{device_id}/0023-20260328-103733.587-POST.http | -| 0024 | self | | GET /streaming/account/{{accountId}}/full | 200 OK | ./self/streaming/account/{accountId}/full/0024-20260328-103733.945-GET.http | -| 0025 | mirror | | GET /streaming/account/{{accountId}}/full | 200 OK | ./mirror/streaming/account/{accountId}/full/0025-20260328-103734.751-GET.http | -| 0026 | self | ☑ | GET /streaming/account/{{accountId}}/provider_settings | 200 OK | ./self/streaming/account/{accountId}/provider_settings/0026-20260328-103735.894-GET.http | -| 0027 | self | ☑ | GET /streaming/account/{{accountId}}/device/{{device_id}}/group/ | 200 OK | ./self/streaming/account/{accountId}/device/{device_id}/group/0027-20260328-103735.914-GET.http | -| 0028 | self | ☑ | GET /streaming/device/{{device_id}}/streaming_token | 200 OK | ./self/streaming/device/{device_id}/streaming_token/0028-20260328-103735.931-GET.http | -| 0029 | self | ☑ | GET /streaming/account/{{accountId}}/provider_settings | 200 OK | ./self/streaming/account/{accountId}/provider_settings/0029-20260328-103735.954-GET.http | -| 0030 | mirror | ☑ | GET /streaming/account/{{accountId}}/provider_settings | 200 OK | ./mirror/streaming/account/{accountId}/provider_settings/0030-20260328-103736.065-GET.http | -| 0031 | mirror | ☑ | GET /streaming/account/{{accountId}}/device/{{device_id}}/group/ | 200 OK | ./mirror/streaming/account/{accountId}/device/{device_id}/group/0031-20260328-103736.093-GET.http | -| 0032 | mirror | ☑ | GET /streaming/account/{{accountId}}/provider_settings | 200 OK | ./mirror/streaming/account/{accountId}/provider_settings/0032-20260328-103736.130-GET.http | -| 0033 | self | ☑ | POST /oauth/device/{{device_id}}/music/musicprovider/15/token/cs3 | 200 OK | ./self/oauth/device/{device_id}/music/musicprovider/15/token/cs3/0033-20260328-103737.874-POST.http | -| 0034 | self | ☑ | GET /streaming/account/{{accountId}}/device/{{device_id}}/presets | 200 OK | ./self/streaming/account/{accountId}/device/{device_id}/presets/0034-20260328-103905.297-GET.http | -| 0035 | self | ☑ | GET /streaming/software/update/account/{{accountId}} | 200 OK | ./self/streaming/software/update/account/{accountId}/0035-20260328-103905.306-GET.http | -| 0036 | mirror | ☑ | GET /streaming/account/{{accountId}}/device/{{device_id}}/presets | 200 OK | ./mirror/streaming/account/{accountId}/device/{device_id}/presets/0036-20260328-103905.479-GET.http | -| 0037 | mirror | ☑ | GET /streaming/software/update/account/{{accountId}} | 200 OK | ./mirror/streaming/software/update/account/{accountId}/0037-20260328-103905.669-GET.http | -| 0038 | self | ☑ | GET /updates/soundtouch?serialnumber=_serial_ | 200 OK | ./self/updates/soundtouch/0038-20260328-103905.929-GET.http | -| 0039 | self | ☑ | GET /streaming/software/update/account/{{accountId}} | 200 OK | ./self/streaming/software/update/account/{accountId}/0039-20260328-104218.080-GET.http | -| 0040 | mirror | ☑ | GET /streaming/software/update/account/{{accountId}} | 200 OK | ./mirror/streaming/software/update/account/{accountId}/0040-20260328-104218.267-GET.http | -| 0041 | self | ☑ | GET /updates/soundtouch?serialnumber=_serial_ | 200 OK | ./self/updates/soundtouch/0041-20260328-104218.524-GET.http | -| 0042 | self | ☑ | GET /streaming/software/update/account/{{accountId}} | 200 OK | ./self/streaming/software/update/account/{accountId}/0042-20260328-104325.629-GET.http | -| 0043 | mirror | ☑ | GET /streaming/software/update/account/{{accountId}} | 200 OK | ./mirror/streaming/software/update/account/{accountId}/0043-20260328-104325.814-GET.http | -| 0044 | self | ☑ | GET /updates/soundtouch?serialnumber=_serial_ | 200 OK | ./self/updates/soundtouch/0044-20260328-104326.087-GET.http | -| 0045 | upstream | ☑ | DELETE https://streaming.bose.com/streaming/account/{{accountId}}/device/{{device_id}} | 400 Bad Request | ./upstream/streaming/account/{accountId}/device/{device_id}/0045-20260328-104348.987-DELETE.http | -| 0046 | self | ☑ | DELETE /streaming/account/{{accountId}}/device/{{device_id}} | 400 Bad Request | ./self/streaming/account/{accountId}/device/{device_id}/0046-20260328-104348.988-DELETE.http | -| 0047 | mirror | ☑ | DELETE /streaming/account/{{accountId}}/device/{{device_id}} | 200 OK | ./mirror/streaming/account/{accountId}/device/{device_id}/0047-20260328-104348.989-DELETE.http | -| 0048 | self | ☑ | POST /streaming/support/power_on | 200 OK | ./self/streaming/support/power_on/0048-20260328-104523.826-POST.http | -| 0049 | self | ☑ | GET /bmx/registry/v1/services | 200 OK | ./self/bmx/registry/v1/services/0049-20260328-104523.828-GET.http | -| 0050 | mirror | ☑ | POST /streaming/support/power_on | 400 Bad Request | ./mirror/streaming/support/power_on/0050-20260328-104524.002-POST.http | -| 0051 | mirror | ☑ | GET /bmx/registry/v1/services | 200 OK | ./mirror/bmx/registry/v1/services/0051-20260328-104524.277-GET.http | -| 0052 | mirror | ☑ | POST /streaming/account/{{accountId}}/device/ | 500 Internal Server Error | ./mirror/streaming/account/{accountId}/device/0052-20260328-105134.442-POST.http | -| 0053 | upstream | ☑ | POST https://streaming.bose.com/streaming/account/{{accountId}}/device/ | 201 Created | ./upstream/streaming/account/{accountId}/device/0053-20260328-105134.482-POST.http | -| 0054 | self | ☑ | POST /streaming/account/{{accountId}}/device/ | 201 Created | ./self/streaming/account/{accountId}/device/0054-20260328-105134.483-POST.http | -| 0055 | self | ☑ | GET /streaming/sourceproviders | 200 OK | ./self/streaming/sourceproviders/0055-20260328-105134.757-GET.http | -| 0056 | self | | GET /streaming/account/{{accountId}}/full | 200 OK | ./self/streaming/account/{accountId}/full/0056-20260328-105135.102-GET.http | -| 0057 | mirror | | GET /streaming/account/{{accountId}}/full | 200 OK | ./mirror/streaming/account/{accountId}/full/0057-20260328-105135.727-GET.http | -| 0058 | self | ☑ | GET /streaming/account/{{accountId}}/provider_settings | 200 OK | ./self/streaming/account/{accountId}/provider_settings/0058-20260328-105138.259-GET.http | -| 0059 | self | ☑ | GET /streaming/account/{{accountId}}/device/{{device_id}}/group/ | 200 OK | ./self/streaming/account/{accountId}/device/{device_id}/group/0059-20260328-105138.265-GET.http | -| 0060 | self | ☑ | POST /streaming/support/customersupport | 200 OK | ./self/streaming/support/customersupport/0060-20260328-105138.304-POST.http | -| 0061 | self | ☑ | GET /streaming/account/{{accountId}}/provider_settings | 200 OK | ./self/streaming/account/{accountId}/provider_settings/0061-20260328-105138.369-GET.http | -| 0062 | mirror | ☑ | GET /streaming/account/{{accountId}}/provider_settings | 200 OK | ./mirror/streaming/account/{accountId}/provider_settings/0062-20260328-105138.442-GET.http | -| 0063 | mirror | ☑ | GET /streaming/account/{{accountId}}/device/{{device_id}}/group/ | 200 OK | ./mirror/streaming/account/{accountId}/device/{device_id}/group/0063-20260328-105138.464-GET.http | -| 0064 | mirror | ☑ | POST /streaming/support/customersupport | 200 OK | ./mirror/streaming/support/customersupport/0064-20260328-105138.499-POST.http | -| 0065 | mirror | ☑ | GET /streaming/account/{{accountId}}/provider_settings | 200 OK | ./mirror/streaming/account/{accountId}/provider_settings/0065-20260328-105138.554-GET.http | -| 0066 | upstream | ☑ | GET https://events.api.bosecm.com/v1/blacklist/{{device_id}} | 405 Method Not Allowed | ./upstream/v1/blacklist/{device_id}/0066-20260328-105138.587-GET.http | -| 0067 | self | ☑ | GET /v1/blacklist/{{device_id}} | 405 Method Not Allowed | ./self/v1/blacklist/{device_id}/0067-20260328-105138.588-GET.http | -| 0068 | self | ☑ | GET /streaming/device/{{device_id}}/streaming_token | 200 OK | ./self/streaming/device/{device_id}/streaming_token/0068-20260328-105138.703-GET.http | -| 0069 | self | ☑ | GET / | 200 OK | ./self/root/0069-20260328-105138.868-GET.http | -| 0070 | self | ☑ | GET /streaming/software/update/account/{{accountId}} | 200 OK | ./self/streaming/software/update/account/{accountId}/0070-20260328-105139.565-GET.http | -| 0071 | self | ☑ | GET /streaming/sourceproviders | 200 OK | ./self/streaming/sourceproviders/0071-20260328-105139.581-GET.http | -| 0072 | self | ☑ | GET /streaming/account/{{accountId}}/provider_settings | 200 OK | ./self/streaming/account/{accountId}/provider_settings/0072-20260328-105139.612-GET.http | -| 0073 | mirror | ☑ | GET /streaming/software/update/account/{{accountId}} | 200 OK | ./mirror/streaming/software/update/account/{accountId}/0073-20260328-105139.857-GET.http | -| 0074 | mirror | ☑ | GET /streaming/account/{{accountId}}/provider_settings | 200 OK | ./mirror/streaming/account/{accountId}/provider_settings/0074-20260328-105139.861-GET.http | -| 0075 | self | | GET /streaming/account/{{accountId}}/full | 200 OK | ./self/streaming/account/{accountId}/full/0075-20260328-105140.030-GET.http | -| 0076 | mirror | | GET /streaming/account/{{accountId}}/full | 200 OK | ./mirror/streaming/account/{accountId}/full/0076-20260328-105140.172-GET.http | -| 0077 | self | ☑ | GET /updates/soundtouch?serialnumber=_serial_ | 200 OK | ./self/updates/soundtouch/0077-20260328-105140.196-GET.http | -| 0078 | upstream | ☑ | GET https://events.api.bosecm.com/v1/blacklist/{{device_id}} | 405 Method Not Allowed | ./upstream/v1/blacklist/{device_id}/0078-20260328-105146.094-GET.http | -| 0079 | self | ☑ | GET /v1/blacklist/{{device_id}} | 405 Method Not Allowed | ./self/v1/blacklist/{device_id}/0079-20260328-105146.094-GET.http | -| 0080 | self | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./self/v1/scmudc/{device_id}/0080-20260328-105146.457-POST.http | -| 0081 | mirror | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./mirror/v1/scmudc/{device_id}/0081-20260328-105146.867-POST.http | -| 0082 | self | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./self/v1/scmudc/{device_id}/0082-20260328-105148.464-POST.http | -| 0083 | mirror | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./mirror/v1/scmudc/{device_id}/0083-20260328-105148.876-POST.http | -| 0084 | self | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./self/v1/scmudc/{device_id}/0084-20260328-105549.637-POST.http | -| 0085 | self | ☑ | GET /bmx/registry/v1/services | 200 OK | ./self/bmx/registry/v1/services/0085-20260328-105549.645-GET.http | -| 0086 | self | ☑ | POST /streaming/support/power_on | 200 OK | ./self/streaming/support/power_on/0086-20260328-105549.665-POST.http | -| 0087 | mirror | ☑ | POST /streaming/support/power_on | 200 OK | ./mirror/streaming/support/power_on/0087-20260328-105549.864-POST.http | -| 0088 | mirror | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./mirror/v1/scmudc/{device_id}/0088-20260328-105550.089-POST.http | -| 0089 | mirror | ☑ | GET /bmx/registry/v1/services | 200 OK | ./mirror/bmx/registry/v1/services/0089-20260328-105550.097-GET.http | -| 0090 | self | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./self/v1/scmudc/{device_id}/0090-20260328-105551.010-POST.http | -| 0091 | self | ☑ | GET / | 200 OK | ./self/root/0091-20260328-105551.041-GET.http | -| 0092 | self | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./self/v1/scmudc/{device_id}/0092-20260328-105551.096-POST.http | -| 0093 | self | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./self/v1/scmudc/{device_id}/0093-20260328-105551.181-POST.http | -| 0094 | mirror | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./mirror/v1/scmudc/{device_id}/0094-20260328-105551.431-POST.http | -| 0095 | mirror | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./mirror/v1/scmudc/{device_id}/0095-20260328-105551.503-POST.http | -| 0096 | mirror | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./mirror/v1/scmudc/{device_id}/0096-20260328-105551.592-POST.http | -| 0097 | self | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./self/v1/scmudc/{device_id}/0097-20260328-105552.101-POST.http | -| 0098 | self | ☑ | GET /streaming/sourceproviders | 200 OK | ./self/streaming/sourceproviders/0098-20260328-105552.239-GET.http | -| 0099 | mirror | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./mirror/v1/scmudc/{device_id}/0099-20260328-105552.510-POST.http | -| 0100 | self | | GET /streaming/account/{{accountId}}/full | 200 OK | ./self/streaming/account/{accountId}/full/0100-20260328-105552.656-GET.http | -| 0101 | mirror | | GET /streaming/account/{{accountId}}/full | 200 OK | ./mirror/streaming/account/{accountId}/full/0101-20260328-105552.796-GET.http | -| 0102 | self | ☑ | GET /streaming/account/{{accountId}}/provider_settings | 200 OK | ./self/streaming/account/{accountId}/provider_settings/0102-20260328-105554.172-GET.http | -| 0103 | self | ☑ | GET /streaming/device/{{device_id}}/streaming_token | 200 OK | ./self/streaming/device/{device_id}/streaming_token/0103-20260328-105554.207-GET.http | -| 0104 | self | ☑ | GET /streaming/account/{{accountId}}/device/{{device_id}}/group/ | 200 OK | ./self/streaming/account/{accountId}/device/{device_id}/group/0104-20260328-105554.210-GET.http | -| 0105 | self | ☑ | GET /streaming/account/{{accountId}}/provider_settings | 200 OK | ./self/streaming/account/{accountId}/provider_settings/0105-20260328-105554.216-GET.http | -| 0106 | mirror | ☑ | GET /streaming/account/{{accountId}}/provider_settings | 200 OK | ./mirror/streaming/account/{accountId}/provider_settings/0106-20260328-105554.347-GET.http | -| 0107 | mirror | ☑ | GET /streaming/account/{{accountId}}/provider_settings | 200 OK | ./mirror/streaming/account/{accountId}/provider_settings/0107-20260328-105554.395-GET.http | -| 0108 | mirror | ☑ | GET /streaming/account/{{accountId}}/device/{{device_id}}/group/ | 200 OK | ./mirror/streaming/account/{accountId}/device/{device_id}/group/0108-20260328-105554.406-GET.http | -| 0109 | self | ☑ | POST /oauth/device/{{device_id}}/music/musicprovider/15/token/cs3 | 200 OK | ./self/oauth/device/{device_id}/music/musicprovider/15/token/cs3/0109-20260328-105556.138-POST.http | -| 0110 | self | ☑ | GET /streaming/software/update/account/{{accountId}} | 200 OK | ./self/streaming/software/update/account/{accountId}/0110-20260328-105606.529-GET.http | -| 0111 | mirror | ☑ | GET /streaming/software/update/account/{{accountId}} | 200 OK | ./mirror/streaming/software/update/account/{accountId}/0111-20260328-105606.699-GET.http | -| 0112 | self | ☑ | GET /updates/soundtouch?serialnumber=_serial_ | 200 OK | ./self/updates/soundtouch/0112-20260328-105606.961-GET.http | -| 0113 | self | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./self/v1/scmudc/{device_id}/0113-20260328-105612.425-POST.http | -| 0114 | self | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./self/v1/scmudc/{device_id}/0114-20260328-105612.493-POST.http | -| 0115 | self | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./self/v1/scmudc/{device_id}/0115-20260328-105612.582-POST.http | -| 0116 | mirror | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./mirror/v1/scmudc/{device_id}/0116-20260328-105612.851-POST.http | -| 0117 | mirror | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./mirror/v1/scmudc/{device_id}/0117-20260328-105612.906-POST.http | -| 0118 | mirror | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./mirror/v1/scmudc/{device_id}/0118-20260328-105613.000-POST.http | -| 0119 | self | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./self/v1/scmudc/{device_id}/0119-20260328-105614.239-POST.http | -| 0120 | mirror | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./mirror/v1/scmudc/{device_id}/0120-20260328-105614.649-POST.http | -| 0121 | self | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./self/v1/scmudc/{device_id}/0121-20260328-111412.273-POST.http | -| 0122 | mirror | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./mirror/v1/scmudc/{device_id}/0122-20260328-111412.689-POST.http | -| 0123 | self | ☑ | GET /streaming/account/{{accountId}}/device/{{device_id}}/group/ | 200 OK | ./self/streaming/account/{accountId}/device/{device_id}/group/0123-20260328-170446.020-GET.http | -| 0124 | mirror | ☑ | GET /streaming/account/{{accountId}}/device/{{device_id}}/group/ | 200 OK | ./mirror/streaming/account/{accountId}/device/{device_id}/group/0124-20260328-170446.206-GET.http | -| 0125 | self | ☑ | GET /streaming/account/{{accountId}}/device/{{device_id}}/group/ | 200 OK | ./self/streaming/account/{accountId}/device/{device_id}/group/0125-20260328-202258.172-GET.http | -| 0126 | mirror | ☑ | GET /streaming/account/{{accountId}}/device/{{device_id}}/group/ | 200 OK | ./mirror/streaming/account/{accountId}/device/{device_id}/group/0126-20260328-202258.374-GET.http | -| 0127 | self | ☑ | GET /streaming/account/{{accountId}}/device/{{device_id}}/group/ | 200 OK | ./self/streaming/account/{accountId}/device/{device_id}/group/0127-20260328-202300.656-GET.http | -| 0128 | mirror | ☑ | GET /streaming/account/{{accountId}}/device/{{device_id}}/group/ | 200 OK | ./mirror/streaming/account/{accountId}/device/{device_id}/group/0128-20260328-202300.841-GET.http | -| 0129 | self | ☑ | GET /streaming/account/{{accountId}}/device/{{device_id}}/group/ | 200 OK | ./self/streaming/account/{accountId}/device/{device_id}/group/0129-20260328-205953.361-GET.http | -| 0130 | mirror | ☑ | GET /streaming/account/{{accountId}}/device/{{device_id}}/group/ | 200 OK | ./mirror/streaming/account/{accountId}/device/{device_id}/group/0130-20260328-205953.560-GET.http | -| 0131 | self | ☑ | GET /streaming/account/{{accountId}}/device/{{device_id}}/group/ | 200 OK | ./self/streaming/account/{accountId}/device/{device_id}/group/0131-20260328-210005.518-GET.http | -| 0132 | mirror | ☑ | GET /streaming/account/{{accountId}}/device/{{device_id}}/group/ | 200 OK | ./mirror/streaming/account/{accountId}/device/{device_id}/group/0132-20260328-210005.707-GET.http | -| 0133 | self | ☑ | GET /streaming/account/{{accountId}}/device/{{device_id}}/group/ | 200 OK | ./self/streaming/account/{accountId}/device/{device_id}/group/0133-20260329-094502.893-GET.http | -| 0134 | mirror | ☑ | GET /streaming/account/{{accountId}}/device/{{device_id}}/group/ | 200 OK | ./mirror/streaming/account/{accountId}/device/{device_id}/group/0134-20260329-094503.109-GET.http | -| 0135 | self | ☑ | GET /streaming/account/{{accountId}}/device/{{device_id}}/group/ | 200 OK | ./self/streaming/account/{accountId}/device/{device_id}/group/0135-20260329-094510.575-GET.http | -| 0136 | mirror | ☑ | GET /streaming/account/{{accountId}}/device/{{device_id}}/group/ | 200 OK | ./mirror/streaming/account/{accountId}/device/{device_id}/group/0136-20260329-094510.907-GET.http | -| 0137 | self | ☑ | GET /streaming/account/{{accountId}}/device/{{device_id}}/group/ | 200 OK | ./self/streaming/account/{accountId}/device/{device_id}/group/0137-20260329-102911.229-GET.http | -| 0138 | mirror | ☑ | GET /streaming/account/{{accountId}}/device/{{device_id}}/group/ | 200 OK | ./mirror/streaming/account/{accountId}/device/{device_id}/group/0138-20260329-102911.443-GET.http | -| 0139 | self | ☑ | GET /streaming/account/{{accountId}}/device/{{device_id}}/group/ | 200 OK | ./self/streaming/account/{accountId}/device/{device_id}/group/0139-20260329-102923.636-GET.http | -| 0140 | mirror | ☑ | GET /streaming/account/{{accountId}}/device/{{device_id}}/group/ | 200 OK | ./mirror/streaming/account/{accountId}/device/{device_id}/group/0140-20260329-102923.807-GET.http | -| 0141 | self | ☑ | GET /streaming/account/{{accountId}}/device/{{device_id}}/group/ | 200 OK | ./self/streaming/account/{accountId}/device/{device_id}/group/0141-20260329-155214.420-GET.http | -| 0142 | mirror | ☑ | GET /streaming/account/{{accountId}}/device/{{device_id}}/group/ | 200 OK | ./mirror/streaming/account/{accountId}/device/{device_id}/group/0142-20260329-155216.805-GET.http | -| 0143 | self | ☑ | GET /streaming/account/{{accountId}}/device/{{device_id}}/group/ | 200 OK | ./self/streaming/account/{accountId}/device/{device_id}/group/0143-20260329-155221.905-GET.http | -| 0144 | mirror | ☑ | GET /streaming/account/{{accountId}}/device/{{device_id}}/group/ | 200 OK | ./mirror/streaming/account/{accountId}/device/{device_id}/group/0144-20260329-155222.082-GET.http | -| 0145 | mirror | ☑ | GET /streaming/account/{{accountId}}/device/{{device_id}}/recents | 200 OK | ./mirror/streaming/account/{accountId}/device/{device_id}/recents/0145-20260329-185442.017-GET.http | -| 0146 | upstream | ☑ | GET https://streaming.bose.com/streaming/account/{{accountId}}/device/{{device_id}}/recents | 200 OK | ./upstream/streaming/account/{accountId}/device/{device_id}/recents/0146-20260329-185442.128-GET.http | -| 0147 | self | ☑ | GET /streaming/account/{{accountId}}/device/{{device_id}}/recents | 200 OK | ./self/streaming/account/{accountId}/device/{device_id}/recents/0147-20260329-185442.130-GET.http | -| 0148 | self | ☑ | GET /streaming/account/{{accountId}}/device/{{device_id}}/group/ | 200 OK | ./self/streaming/account/{accountId}/device/{device_id}/group/0148-20260329-193915.264-GET.http | -| 0149 | mirror | ☑ | GET /streaming/account/{{accountId}}/device/{{device_id}}/group/ | 200 OK | ./mirror/streaming/account/{accountId}/device/{device_id}/group/0149-20260329-193915.468-GET.http | -| 0150 | self | ☑ | GET /streaming/account/{{accountId}}/device/{{device_id}}/group/ | 200 OK | ./self/streaming/account/{accountId}/device/{device_id}/group/0150-20260329-215246.808-GET.http | -| 0151 | mirror | ☑ | GET /streaming/account/{{accountId}}/device/{{device_id}}/group/ | 200 OK | ./mirror/streaming/account/{accountId}/device/{device_id}/group/0151-20260329-215247.001-GET.http | -| 0152 | self | ☑ | GET / | 200 OK | ./self/root/0152-20260329-233126.264-GET.http | -| 0153 | self | ☑ | GET /mgmt/spotify/accounts | 200 OK | ./self/mgmt/spotify/accounts/0153-20260329-233126.506-GET.http | -| 0154 | self | ☑ | GET /mgmt/spotify/accounts | 200 OK | ./self/mgmt/spotify/accounts/0154-20260329-233126.515-GET.http | -| 0155 | self | ☑ | GET /mgmt/spotify/accounts | 200 OK | ./self/mgmt/spotify/accounts/0155-20260329-233126.531-GET.http | -| 0156 | self | ☑ | GET /mgmt/spotify/accounts | 200 OK | ./self/mgmt/spotify/accounts/0156-20260329-233126.542-GET.http | -| 0157 | self | ☑ | GET / | 200 OK | ./self/root/0157-20260329-233128.611-GET.http | -| 0158 | self | ☑ | GET / | 200 OK | ./self/root/0158-20260329-233128.790-GET.http | -| 0159 | self | ☑ | GET /mgmt/spotify/accounts | 200 OK | ./self/mgmt/spotify/accounts/0159-20260329-233129.065-GET.http | -| 0160 | self | ☑ | GET /mgmt/spotify/accounts | 200 OK | ./self/mgmt/spotify/accounts/0160-20260329-233129.089-GET.http | -| 0161 | self | ☑ | GET /mgmt/spotify/accounts | 200 OK | ./self/mgmt/spotify/accounts/0161-20260329-233129.099-GET.http | -| 0162 | self | ☑ | GET /mgmt/spotify/accounts | 200 OK | ./self/mgmt/spotify/accounts/0162-20260329-233129.105-GET.http | -| 0163 | self | ☑ | GET /mgmt/spotify/accounts | 200 OK | ./self/mgmt/spotify/accounts/0163-20260329-233137.103-GET.http | -| 0164 | self | ☑ | GET /mgmt/spotify/accounts | 200 OK | ./self/mgmt/spotify/accounts/0164-20260329-233137.130-GET.http | -| 0165 | self | ☑ | GET /mgmt/accounts | 200 OK | ./self/mgmt/accounts/0165-20260329-233206.623-GET.http | -| 0166 | self | ☑ | GET /mgmt/accounts/{{accountId}} | 200 OK | ./self/mgmt/accounts/{accountId}/0166-20260329-233206.693-GET.http | -| 0167 | self | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./self/v1/scmudc/{device_id}/0167-20260329-233249.970-POST.http | -| 0168 | mirror | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./mirror/v1/scmudc/{device_id}/0168-20260329-233250.408-POST.http | -| 0169 | self | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./self/v1/scmudc/{device_id}/0169-20260329-233257.652-POST.http | -| 0170 | self | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./self/v1/scmudc/{device_id}/0170-20260329-233257.674-POST.http | -| 0171 | mirror | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./mirror/v1/scmudc/{device_id}/0171-20260329-233258.075-POST.http | -| 0172 | mirror | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./mirror/v1/scmudc/{device_id}/0172-20260329-233258.097-POST.http | -| 0173 | mirror | ☑ | GET /bmx/tunein/v1/playback/station/s166521 | 401 Unauthorized | ./mirror/bmx/tunein/v1/playback/station/s166521/0173-20260329-233258.121-GET.http | -| 0174 | self | ☑ | GET /bmx/tunein/v1/playback/station/s166521 | 200 OK | ./self/bmx/tunein/v1/playback/station/s166521/0174-20260329-233258.171-GET.http | -| 0175 | self | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./self/v1/scmudc/{device_id}/0175-20260329-233258.625-POST.http | -| 0176 | upstream | ☑ | POST https://content.api.bose.io/bmx/tunein/v1/token | 200 OK | ./upstream/bmx/tunein/v1/token/0176-20260329-233259.006-POST.http | -| 0177 | self | ☑ | POST /bmx/tunein/v1/token | 200 OK | ./self/bmx/tunein/v1/token/0177-20260329-233259.008-POST.http | -| 0178 | mirror | ☑ | POST /bmx/tunein/v1/token | 200 OK | ./mirror/bmx/tunein/v1/token/0178-20260329-233259.013-POST.http | -| 0179 | mirror | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./mirror/v1/scmudc/{device_id}/0179-20260329-233259.046-POST.http | -| 0180 | self | ☑ | GET /bmx/tunein/v1/playback/station/s166521 | 200 OK | ./self/bmx/tunein/v1/playback/station/s166521/0180-20260329-233259.719-GET.http | -| 0181 | mirror | ☑ | GET /bmx/tunein/v1/playback/station/s166521 | 200 OK | ./mirror/bmx/tunein/v1/playback/station/s166521/0181-20260329-233300.084-GET.http | -| 0182 | self | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./self/v1/scmudc/{device_id}/0182-20260329-233302.393-POST.http | -| 0183 | self | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./self/v1/scmudc/{device_id}/0183-20260329-233302.636-POST.http | -| 0184 | self | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./self/v1/scmudc/{device_id}/0184-20260329-233302.655-POST.http | -| 0185 | self | ☑ | POST /streaming/account/{{accountId}}/device/{{device_id}}/recent | 201 Created | ./self/streaming/account/{accountId}/device/{device_id}/recent/0185-20260329-233302.671-POST.http | -| 0186 | mirror | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./mirror/v1/scmudc/{device_id}/0186-20260329-233302.906-POST.http | -| 0187 | mirror | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./mirror/v1/scmudc/{device_id}/0187-20260329-233303.115-POST.http | -| 0188 | mirror | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./mirror/v1/scmudc/{device_id}/0188-20260329-233303.118-POST.http | -| 0189 | mirror | ☑ | POST /streaming/account/{{accountId}}/device/{{device_id}}/recent | 201 Created | ./mirror/streaming/account/{accountId}/device/{device_id}/recent/0189-20260329-233303.759-POST.http | -| 0190 | self | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./self/v1/scmudc/{device_id}/0190-20260329-233304.143-POST.http | -| 0191 | self | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./self/v1/scmudc/{device_id}/0191-20260329-233304.269-POST.http | -| 0192 | mirror | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./mirror/v1/scmudc/{device_id}/0192-20260329-233304.554-POST.http | -| 0193 | mirror | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./mirror/v1/scmudc/{device_id}/0193-20260329-233304.685-POST.http | -| 0194 | self | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./self/v1/scmudc/{device_id}/0194-20260329-233305.629-POST.http | -| 0195 | mirror | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./mirror/v1/scmudc/{device_id}/0195-20260329-233306.040-POST.http | -| 0196 | mirror | ☑ | POST /bmx/tunein/v1/report?stream_id=e536753726&guide_id=s166521&listen_id=1774819980&stream_type=liveRadio | 200 OK | ./mirror/bmx/tunein/v1/report/0196-20260329-233306.072-POST.http | -| 0197 | upstream | ☑ | POST https://content.api.bose.io/bmx/tunein/v1/report?stream_id=e536753726&guide_id=s166521&listen_id=1774819980&stream_type=liveRadio | 200 OK | ./upstream/bmx/tunein/v1/report/0197-20260329-233306.182-POST.http | -| 0198 | self | ☑ | POST /bmx/tunein/v1/report?stream_id=e536753726&guide_id=s166521&listen_id=1774819980&stream_type=liveRadio | 200 OK | ./self/bmx/tunein/v1/report/0198-20260329-233306.184-POST.http | -| 0199 | self | ☑ | GET /streaming/software/update/account/{{accountId}} | 200 OK | ./self/streaming/software/update/account/{accountId}/0199-20260329-233317.196-GET.http | -| 0200 | self | ☑ | GET /streaming/account/{{accountId}}/device/{{device_id}}/presets | 200 OK | ./self/streaming/account/{accountId}/device/{device_id}/presets/0200-20260329-233317.206-GET.http | -| 0201 | mirror | ☑ | GET /streaming/account/{{accountId}}/device/{{device_id}}/presets | 200 OK | ./mirror/streaming/account/{accountId}/device/{device_id}/presets/0201-20260329-233317.394-GET.http | -| 0202 | mirror | ☑ | GET /streaming/software/update/account/{{accountId}} | 200 OK | ./mirror/streaming/software/update/account/{accountId}/0202-20260329-233317.409-GET.http | -| 0203 | self | ☑ | GET /updates/soundtouch?serialnumber=_serial_ | 200 OK | ./self/updates/soundtouch/0203-20260329-233317.838-GET.http | -| 0204 | self | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./self/v1/scmudc/{device_id}/0204-20260329-233330.871-POST.http | -| 0205 | mirror | ☑ | PUT /streaming/account/{{accountId}}/device/{{device_id}}/preset/6 | 200 OK | ./mirror/streaming/account/{accountId}/device/{device_id}/preset/6/0205-20260329-233331.093-PUT.http | -| 0206 | upstream | ☑ | PUT https://streaming.bose.com/streaming/account/{{accountId}}/device/{{device_id}}/preset/6 | 500 Internal Server Error | ./upstream/streaming/account/{accountId}/device/{device_id}/preset/6/0206-20260329-233331.096-PUT.http | -| 0207 | self | ☑ | PUT /streaming/account/{{accountId}}/device/{{device_id}}/preset/6 | 500 Internal Server Error | ./self/streaming/account/{accountId}/device/{device_id}/preset/6/0207-20260329-233331.096-PUT.http | -| 0208 | mirror | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./mirror/v1/scmudc/{device_id}/0208-20260329-233331.323-POST.http | -| 0209 | self | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./self/v1/scmudc/{device_id}/0209-20260329-233331.938-POST.http | -| 0210 | self | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./self/v1/scmudc/{device_id}/0210-20260329-233331.982-POST.http | -| 0211 | mirror | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./mirror/v1/scmudc/{device_id}/0211-20260329-233332.366-POST.http | -| 0212 | mirror | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./mirror/v1/scmudc/{device_id}/0212-20260329-233332.396-POST.http | -| 0213 | self | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./self/v1/scmudc/{device_id}/0213-20260329-233344.994-POST.http | -| 0214 | self | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./self/v1/scmudc/{device_id}/0214-20260329-233345.001-POST.http | -| 0215 | mirror | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./mirror/v1/scmudc/{device_id}/0215-20260329-233345.427-POST.http | -| 0216 | mirror | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./mirror/v1/scmudc/{device_id}/0216-20260329-233345.430-POST.http | -| 0217 | mirror | ☑ | POST /bmx/tunein/v1/report?stream_id=e536753726&guide_id=s166521&listen_id=1774819980&last_titt=0&duration_balance=0&stream_type=liveRadio | 200 OK | ./mirror/bmx/tunein/v1/report/0217-20260329-233345.547-POST.http | -| 0218 | upstream | ☑ | POST https://content.api.bose.io/bmx/tunein/v1/report?stream_id=e536753726&guide_id=s166521&listen_id=1774819980&last_titt=0&duration_balance=0&stream_type=liveRadio | 200 OK | ./upstream/bmx/tunein/v1/report/0218-20260329-233345.651-POST.http | -| 0219 | self | ☑ | POST /bmx/tunein/v1/report?stream_id=e536753726&guide_id=s166521&listen_id=1774819980&last_titt=0&duration_balance=0&stream_type=liveRadio | 200 OK | ./self/bmx/tunein/v1/report/0219-20260329-233345.651-POST.http | -| 0220 | self | ☑ | GET /bmx/registry/v1/services | 200 OK | ./self/bmx/registry/v1/services/0220-20260329-233504.445-GET.http | -| 0221 | self | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./self/v1/scmudc/{device_id}/0221-20260329-233504.467-POST.http | -| 0222 | self | ☑ | POST /streaming/support/power_on | 200 OK | ./self/streaming/support/power_on/0222-20260329-233504.475-POST.http | -| 0223 | mirror | ☑ | POST /streaming/support/power_on | 200 OK | ./mirror/streaming/support/power_on/0223-20260329-233504.668-POST.http | -| 0224 | mirror | ☑ | GET /bmx/registry/v1/services | 200 OK | ./mirror/bmx/registry/v1/services/0224-20260329-233504.879-GET.http | -| 0225 | mirror | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./mirror/v1/scmudc/{device_id}/0225-20260329-233504.891-POST.http | -| 0226 | self | ☑ | GET / | 200 OK | ./self/root/0226-20260329-233505.214-GET.http | -| 0227 | self | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./self/v1/scmudc/{device_id}/0227-20260329-233505.548-POST.http | -| 0228 | self | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./self/v1/scmudc/{device_id}/0228-20260329-233505.560-POST.http | -| 0229 | self | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./self/v1/scmudc/{device_id}/0229-20260329-233505.735-POST.http | -| 0230 | mirror | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./mirror/v1/scmudc/{device_id}/0230-20260329-233505.980-POST.http | -| 0231 | mirror | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./mirror/v1/scmudc/{device_id}/0231-20260329-233505.994-POST.http | -| 0232 | mirror | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./mirror/v1/scmudc/{device_id}/0232-20260329-233506.158-POST.http | -| 0233 | self | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./self/v1/scmudc/{device_id}/0233-20260329-233506.707-POST.http | -| 0234 | self | ☑ | GET /streaming/sourceproviders | 200 OK | ./self/streaming/sourceproviders/0234-20260329-233506.769-GET.http | -| 0235 | self | | GET /streaming/account/{{accountId}}/full | 200 OK | ./self/streaming/account/{accountId}/full/0235-20260329-233507.099-GET.http | -| 0236 | mirror | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./mirror/v1/scmudc/{device_id}/0236-20260329-233507.137-POST.http | -| 0237 | mirror | | GET /streaming/account/{{accountId}}/full | 200 OK | ./mirror/streaming/account/{accountId}/full/0237-20260329-233507.277-GET.http | -| 0238 | self | ☑ | GET /streaming/account/{{accountId}}/device/{{device_id}}/group/ | 200 OK | ./self/streaming/account/{accountId}/device/{device_id}/group/0238-20260329-233508.639-GET.http | -| 0239 | self | ☑ | GET /streaming/device/{{device_id}}/streaming_token | 200 OK | ./self/streaming/device/{device_id}/streaming_token/0239-20260329-233508.642-GET.http | -| 0240 | self | ☑ | GET /streaming/account/{{accountId}}/provider_settings | 200 OK | ./self/streaming/account/{accountId}/provider_settings/0240-20260329-233508.755-GET.http | -| 0241 | mirror | ☑ | GET /streaming/account/{{accountId}}/device/{{device_id}}/group/ | 200 OK | ./mirror/streaming/account/{accountId}/device/{device_id}/group/0241-20260329-233508.809-GET.http | -| 0242 | self | ☑ | GET /streaming/account/{{accountId}}/provider_settings | 200 OK | ./self/streaming/account/{accountId}/provider_settings/0242-20260329-233508.866-GET.http | -| 0243 | mirror | ☑ | GET /streaming/account/{{accountId}}/provider_settings | 200 OK | ./mirror/streaming/account/{accountId}/provider_settings/0243-20260329-233508.968-GET.http | -| 0244 | mirror | ☑ | GET /streaming/account/{{accountId}}/provider_settings | 200 OK | ./mirror/streaming/account/{accountId}/provider_settings/0244-20260329-233509.041-GET.http | -| 0245 | self | ☑ | POST /oauth/device/{{device_id}}/music/musicprovider/15/token/cs3 | 200 OK | ./self/oauth/device/{device_id}/music/musicprovider/15/token/cs3/0245-20260329-233510.807-POST.http | +| sequence number | category | ignore/done | request | response status | filename | +|-----------------|----------|-------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| 0001 | self | ☑ | GET / | 200 OK | ./self/root/0001-20260328-103539.205-GET.http | +| 0002 | self | ☑ | GET /mgmt/spotify/accounts | 200 OK | ./self/mgmt/spotify/accounts/0002-20260328-103539.483-GET.http | +| 0003 | self | ☑ | GET /mgmt/spotify/accounts | 200 OK | ./self/mgmt/spotify/accounts/0003-20260328-103539.514-GET.http | +| 0004 | self | ☑ | GET /mgmt/spotify/accounts | 200 OK | ./self/mgmt/spotify/accounts/0004-20260328-103539.539-GET.http | +| 0005 | self | ☑ | GET /mgmt/spotify/accounts | 200 OK | ./self/mgmt/spotify/accounts/0005-20260328-103539.554-GET.http | +| 0006 | self | ☑ | GET /mgmt/spotify/accounts | 200 OK | ./self/mgmt/spotify/accounts/0006-20260328-103551.537-GET.http | +| 0007 | self | ☑ | GET /mgmt/spotify/accounts | 200 OK | ./self/mgmt/spotify/accounts/0007-20260328-103551.551-GET.http | +| 0008 | self | ☑ | GET /bmx/registry/v1/services | 200 OK | ./self/bmx/registry/v1/services/0008-20260328-103731.202-GET.http | +| 0009 | self | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./self/v1/scmudc/{device_id}/0009-20260328-103731.221-POST.http | +| 0010 | self | ☑ | POST /streaming/support/power_on | 200 OK | ./self/streaming/support/power_on/0010-20260328-103731.226-POST.http | +| 0011 | mirror | ☑ | POST /streaming/support/power_on | 200 OK | ./mirror/streaming/support/power_on/0011-20260328-103731.407-POST.http | +| 0012 | self | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./self/v1/scmudc/{device_id}/0012-20260328-103731.625-POST.http | +| 0013 | mirror | ☑ | GET /bmx/registry/v1/services | 200 OK | ./mirror/bmx/registry/v1/services/0013-20260328-103731.641-GET.http | +| 0014 | mirror | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./mirror/v1/scmudc/{device_id}/0014-20260328-103731.652-POST.http | +| 0015 | self | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./self/v1/scmudc/{device_id}/0015-20260328-103731.725-POST.http | +| 0016 | self | ☑ | GET / | 200 OK | ./self/root/0016-20260328-103731.804-GET.http | +| 0017 | self | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./self/v1/scmudc/{device_id}/0017-20260328-103731.806-POST.http | +| 0018 | mirror | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./mirror/v1/scmudc/{device_id}/0018-20260328-103732.053-POST.http | +| 0019 | mirror | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./mirror/v1/scmudc/{device_id}/0019-20260328-103732.173-POST.http | +| 0020 | mirror | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./mirror/v1/scmudc/{device_id}/0020-20260328-103732.229-POST.http | +| 0021 | self | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./self/v1/scmudc/{device_id}/0021-20260328-103733.180-POST.http | +| 0022 | self | ☑ | GET /streaming/sourceproviders | 200 OK | ./self/streaming/sourceproviders/0022-20260328-103733.439-GET.http | +| 0023 | mirror | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./mirror/v1/scmudc/{device_id}/0023-20260328-103733.587-POST.http | +| 0024 | self | | GET /streaming/account/{{accountId}}/full | 200 OK | ./self/streaming/account/{accountId}/full/0024-20260328-103733.945-GET.http | +| 0025 | mirror | | GET /streaming/account/{{accountId}}/full | 200 OK | ./mirror/streaming/account/{accountId}/full/0025-20260328-103734.751-GET.http | +| 0026 | self | ☑ | GET /streaming/account/{{accountId}}/provider_settings | 200 OK | ./self/streaming/account/{accountId}/provider_settings/0026-20260328-103735.894-GET.http | +| 0027 | self | ☑ | GET /streaming/account/{{accountId}}/device/{{device_id}}/group/ | 200 OK | ./self/streaming/account/{accountId}/device/{device_id}/group/0027-20260328-103735.914-GET.http | +| 0028 | self | ☑ | GET /streaming/device/{{device_id}}/streaming_token | 200 OK | ./self/streaming/device/{device_id}/streaming_token/0028-20260328-103735.931-GET.http | +| 0029 | self | ☑ | GET /streaming/account/{{accountId}}/provider_settings | 200 OK | ./self/streaming/account/{accountId}/provider_settings/0029-20260328-103735.954-GET.http | +| 0030 | mirror | ☑ | GET /streaming/account/{{accountId}}/provider_settings | 200 OK | ./mirror/streaming/account/{accountId}/provider_settings/0030-20260328-103736.065-GET.http | +| 0031 | mirror | ☑ | GET /streaming/account/{{accountId}}/device/{{device_id}}/group/ | 200 OK | ./mirror/streaming/account/{accountId}/device/{device_id}/group/0031-20260328-103736.093-GET.http | +| 0032 | mirror | ☑ | GET /streaming/account/{{accountId}}/provider_settings | 200 OK | ./mirror/streaming/account/{accountId}/provider_settings/0032-20260328-103736.130-GET.http | +| 0033 | self | ☑ | POST /oauth/device/{{device_id}}/music/musicprovider/15/token/cs3 | 200 OK | ./self/oauth/device/{device_id}/music/musicprovider/15/token/cs3/0033-20260328-103737.874-POST.http | +| 0034 | self | ☑ | GET /streaming/account/{{accountId}}/device/{{device_id}}/presets | 200 OK | ./self/streaming/account/{accountId}/device/{device_id}/presets/0034-20260328-103905.297-GET.http | +| 0035 | self | ☑ | GET /streaming/software/update/account/{{accountId}} | 200 OK | ./self/streaming/software/update/account/{accountId}/0035-20260328-103905.306-GET.http | +| 0036 | mirror | ☑ | GET /streaming/account/{{accountId}}/device/{{device_id}}/presets | 200 OK | ./mirror/streaming/account/{accountId}/device/{device_id}/presets/0036-20260328-103905.479-GET.http | +| 0037 | mirror | ☑ | GET /streaming/software/update/account/{{accountId}} | 200 OK | ./mirror/streaming/software/update/account/{accountId}/0037-20260328-103905.669-GET.http | +| 0038 | self | ☑ | GET /updates/soundtouch?serialnumber=_serial_ | 200 OK | ./self/updates/soundtouch/0038-20260328-103905.929-GET.http | +| 0039 | self | ☑ | GET /streaming/software/update/account/{{accountId}} | 200 OK | ./self/streaming/software/update/account/{accountId}/0039-20260328-104218.080-GET.http | +| 0040 | mirror | ☑ | GET /streaming/software/update/account/{{accountId}} | 200 OK | ./mirror/streaming/software/update/account/{accountId}/0040-20260328-104218.267-GET.http | +| 0041 | self | ☑ | GET /updates/soundtouch?serialnumber=_serial_ | 200 OK | ./self/updates/soundtouch/0041-20260328-104218.524-GET.http | +| 0042 | self | ☑ | GET /streaming/software/update/account/{{accountId}} | 200 OK | ./self/streaming/software/update/account/{accountId}/0042-20260328-104325.629-GET.http | +| 0043 | mirror | ☑ | GET /streaming/software/update/account/{{accountId}} | 200 OK | ./mirror/streaming/software/update/account/{accountId}/0043-20260328-104325.814-GET.http | +| 0044 | self | ☑ | GET /updates/soundtouch?serialnumber=_serial_ | 200 OK | ./self/updates/soundtouch/0044-20260328-104326.087-GET.http | +| 0045 | upstream | ☑ | DELETE https://streaming.bose.com/streaming/account/{{accountId}}/device/{{device_id}} | 400 Bad Request | ./upstream/streaming/account/{accountId}/device/{device_id}/0045-20260328-104348.987-DELETE.http | +| 0046 | self | ☑ | DELETE /streaming/account/{{accountId}}/device/{{device_id}} | 400 Bad Request | ./self/streaming/account/{accountId}/device/{device_id}/0046-20260328-104348.988-DELETE.http | +| 0047 | mirror | ☑ | DELETE /streaming/account/{{accountId}}/device/{{device_id}} | 200 OK | ./mirror/streaming/account/{accountId}/device/{device_id}/0047-20260328-104348.989-DELETE.http | +| 0048 | self | ☑ | POST /streaming/support/power_on | 200 OK | ./self/streaming/support/power_on/0048-20260328-104523.826-POST.http | +| 0049 | self | ☑ | GET /bmx/registry/v1/services | 200 OK | ./self/bmx/registry/v1/services/0049-20260328-104523.828-GET.http | +| 0050 | mirror | ☑ | POST /streaming/support/power_on | 400 Bad Request | ./mirror/streaming/support/power_on/0050-20260328-104524.002-POST.http | +| 0051 | mirror | ☑ | GET /bmx/registry/v1/services | 200 OK | ./mirror/bmx/registry/v1/services/0051-20260328-104524.277-GET.http | +| 0052 | mirror | ☑ | POST /streaming/account/{{accountId}}/device/ | 500 Internal Server Error | ./mirror/streaming/account/{accountId}/device/0052-20260328-105134.442-POST.http | +| 0053 | upstream | ☑ | POST https://streaming.bose.com/streaming/account/{{accountId}}/device/ | 201 Created | ./upstream/streaming/account/{accountId}/device/0053-20260328-105134.482-POST.http | +| 0054 | self | ☑ | POST /streaming/account/{{accountId}}/device/ | 201 Created | ./self/streaming/account/{accountId}/device/0054-20260328-105134.483-POST.http | +| 0055 | self | ☑ | GET /streaming/sourceproviders | 200 OK | ./self/streaming/sourceproviders/0055-20260328-105134.757-GET.http | +| 0056 | self | | GET /streaming/account/{{accountId}}/full | 200 OK | ./self/streaming/account/{accountId}/full/0056-20260328-105135.102-GET.http | +| 0057 | mirror | | GET /streaming/account/{{accountId}}/full | 200 OK | ./mirror/streaming/account/{accountId}/full/0057-20260328-105135.727-GET.http | +| 0058 | self | ☑ | GET /streaming/account/{{accountId}}/provider_settings | 200 OK | ./self/streaming/account/{accountId}/provider_settings/0058-20260328-105138.259-GET.http | +| 0059 | self | ☑ | GET /streaming/account/{{accountId}}/device/{{device_id}}/group/ | 200 OK | ./self/streaming/account/{accountId}/device/{device_id}/group/0059-20260328-105138.265-GET.http | +| 0060 | self | ☑ | POST /streaming/support/customersupport | 200 OK | ./self/streaming/support/customersupport/0060-20260328-105138.304-POST.http | +| 0061 | self | ☑ | GET /streaming/account/{{accountId}}/provider_settings | 200 OK | ./self/streaming/account/{accountId}/provider_settings/0061-20260328-105138.369-GET.http | +| 0062 | mirror | ☑ | GET /streaming/account/{{accountId}}/provider_settings | 200 OK | ./mirror/streaming/account/{accountId}/provider_settings/0062-20260328-105138.442-GET.http | +| 0063 | mirror | ☑ | GET /streaming/account/{{accountId}}/device/{{device_id}}/group/ | 200 OK | ./mirror/streaming/account/{accountId}/device/{device_id}/group/0063-20260328-105138.464-GET.http | +| 0064 | mirror | ☑ | POST /streaming/support/customersupport | 200 OK | ./mirror/streaming/support/customersupport/0064-20260328-105138.499-POST.http | +| 0065 | mirror | ☑ | GET /streaming/account/{{accountId}}/provider_settings | 200 OK | ./mirror/streaming/account/{accountId}/provider_settings/0065-20260328-105138.554-GET.http | +| 0066 | upstream | ☑ | GET https://events.api.bosecm.com/v1/blacklist/{{device_id}} | 405 Method Not Allowed | ./upstream/v1/blacklist/{device_id}/0066-20260328-105138.587-GET.http | +| 0067 | self | ☑ | GET /v1/blacklist/{{device_id}} | 405 Method Not Allowed | ./self/v1/blacklist/{device_id}/0067-20260328-105138.588-GET.http | +| 0068 | self | ☑ | GET /streaming/device/{{device_id}}/streaming_token | 200 OK | ./self/streaming/device/{device_id}/streaming_token/0068-20260328-105138.703-GET.http | +| 0069 | self | ☑ | GET / | 200 OK | ./self/root/0069-20260328-105138.868-GET.http | +| 0070 | self | ☑ | GET /streaming/software/update/account/{{accountId}} | 200 OK | ./self/streaming/software/update/account/{accountId}/0070-20260328-105139.565-GET.http | +| 0071 | self | ☑ | GET /streaming/sourceproviders | 200 OK | ./self/streaming/sourceproviders/0071-20260328-105139.581-GET.http | +| 0072 | self | ☑ | GET /streaming/account/{{accountId}}/provider_settings | 200 OK | ./self/streaming/account/{accountId}/provider_settings/0072-20260328-105139.612-GET.http | +| 0073 | mirror | ☑ | GET /streaming/software/update/account/{{accountId}} | 200 OK | ./mirror/streaming/software/update/account/{accountId}/0073-20260328-105139.857-GET.http | +| 0074 | mirror | ☑ | GET /streaming/account/{{accountId}}/provider_settings | 200 OK | ./mirror/streaming/account/{accountId}/provider_settings/0074-20260328-105139.861-GET.http | +| 0075 | self | | GET /streaming/account/{{accountId}}/full | 200 OK | ./self/streaming/account/{accountId}/full/0075-20260328-105140.030-GET.http | +| 0076 | mirror | | GET /streaming/account/{{accountId}}/full | 200 OK | ./mirror/streaming/account/{accountId}/full/0076-20260328-105140.172-GET.http | +| 0077 | self | ☑ | GET /updates/soundtouch?serialnumber=_serial_ | 200 OK | ./self/updates/soundtouch/0077-20260328-105140.196-GET.http | +| 0078 | upstream | ☑ | GET https://events.api.bosecm.com/v1/blacklist/{{device_id}} | 405 Method Not Allowed | ./upstream/v1/blacklist/{device_id}/0078-20260328-105146.094-GET.http | +| 0079 | self | ☑ | GET /v1/blacklist/{{device_id}} | 405 Method Not Allowed | ./self/v1/blacklist/{device_id}/0079-20260328-105146.094-GET.http | +| 0080 | self | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./self/v1/scmudc/{device_id}/0080-20260328-105146.457-POST.http | +| 0081 | mirror | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./mirror/v1/scmudc/{device_id}/0081-20260328-105146.867-POST.http | +| 0082 | self | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./self/v1/scmudc/{device_id}/0082-20260328-105148.464-POST.http | +| 0083 | mirror | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./mirror/v1/scmudc/{device_id}/0083-20260328-105148.876-POST.http | +| 0084 | self | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./self/v1/scmudc/{device_id}/0084-20260328-105549.637-POST.http | +| 0085 | self | ☑ | GET /bmx/registry/v1/services | 200 OK | ./self/bmx/registry/v1/services/0085-20260328-105549.645-GET.http | +| 0086 | self | ☑ | POST /streaming/support/power_on | 200 OK | ./self/streaming/support/power_on/0086-20260328-105549.665-POST.http | +| 0087 | mirror | ☑ | POST /streaming/support/power_on | 200 OK | ./mirror/streaming/support/power_on/0087-20260328-105549.864-POST.http | +| 0088 | mirror | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./mirror/v1/scmudc/{device_id}/0088-20260328-105550.089-POST.http | +| 0089 | mirror | ☑ | GET /bmx/registry/v1/services | 200 OK | ./mirror/bmx/registry/v1/services/0089-20260328-105550.097-GET.http | +| 0090 | self | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./self/v1/scmudc/{device_id}/0090-20260328-105551.010-POST.http | +| 0091 | self | ☑ | GET / | 200 OK | ./self/root/0091-20260328-105551.041-GET.http | +| 0092 | self | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./self/v1/scmudc/{device_id}/0092-20260328-105551.096-POST.http | +| 0093 | self | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./self/v1/scmudc/{device_id}/0093-20260328-105551.181-POST.http | +| 0094 | mirror | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./mirror/v1/scmudc/{device_id}/0094-20260328-105551.431-POST.http | +| 0095 | mirror | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./mirror/v1/scmudc/{device_id}/0095-20260328-105551.503-POST.http | +| 0096 | mirror | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./mirror/v1/scmudc/{device_id}/0096-20260328-105551.592-POST.http | +| 0097 | self | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./self/v1/scmudc/{device_id}/0097-20260328-105552.101-POST.http | +| 0098 | self | ☑ | GET /streaming/sourceproviders | 200 OK | ./self/streaming/sourceproviders/0098-20260328-105552.239-GET.http | +| 0099 | mirror | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./mirror/v1/scmudc/{device_id}/0099-20260328-105552.510-POST.http | +| 0100 | self | | GET /streaming/account/{{accountId}}/full | 200 OK | ./self/streaming/account/{accountId}/full/0100-20260328-105552.656-GET.http | +| 0101 | mirror | | GET /streaming/account/{{accountId}}/full | 200 OK | ./mirror/streaming/account/{accountId}/full/0101-20260328-105552.796-GET.http | +| 0102 | self | ☑ | GET /streaming/account/{{accountId}}/provider_settings | 200 OK | ./self/streaming/account/{accountId}/provider_settings/0102-20260328-105554.172-GET.http | +| 0103 | self | ☑ | GET /streaming/device/{{device_id}}/streaming_token | 200 OK | ./self/streaming/device/{device_id}/streaming_token/0103-20260328-105554.207-GET.http | +| 0104 | self | ☑ | GET /streaming/account/{{accountId}}/device/{{device_id}}/group/ | 200 OK | ./self/streaming/account/{accountId}/device/{device_id}/group/0104-20260328-105554.210-GET.http | +| 0105 | self | ☑ | GET /streaming/account/{{accountId}}/provider_settings | 200 OK | ./self/streaming/account/{accountId}/provider_settings/0105-20260328-105554.216-GET.http | +| 0106 | mirror | ☑ | GET /streaming/account/{{accountId}}/provider_settings | 200 OK | ./mirror/streaming/account/{accountId}/provider_settings/0106-20260328-105554.347-GET.http | +| 0107 | mirror | ☑ | GET /streaming/account/{{accountId}}/provider_settings | 200 OK | ./mirror/streaming/account/{accountId}/provider_settings/0107-20260328-105554.395-GET.http | +| 0108 | mirror | ☑ | GET /streaming/account/{{accountId}}/device/{{device_id}}/group/ | 200 OK | ./mirror/streaming/account/{accountId}/device/{device_id}/group/0108-20260328-105554.406-GET.http | +| 0109 | self | ☑ | POST /oauth/device/{{device_id}}/music/musicprovider/15/token/cs3 | 200 OK | ./self/oauth/device/{device_id}/music/musicprovider/15/token/cs3/0109-20260328-105556.138-POST.http | +| 0110 | self | ☑ | GET /streaming/software/update/account/{{accountId}} | 200 OK | ./self/streaming/software/update/account/{accountId}/0110-20260328-105606.529-GET.http | +| 0111 | mirror | ☑ | GET /streaming/software/update/account/{{accountId}} | 200 OK | ./mirror/streaming/software/update/account/{accountId}/0111-20260328-105606.699-GET.http | +| 0112 | self | ☑ | GET /updates/soundtouch?serialnumber=_serial_ | 200 OK | ./self/updates/soundtouch/0112-20260328-105606.961-GET.http | +| 0113 | self | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./self/v1/scmudc/{device_id}/0113-20260328-105612.425-POST.http | +| 0114 | self | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./self/v1/scmudc/{device_id}/0114-20260328-105612.493-POST.http | +| 0115 | self | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./self/v1/scmudc/{device_id}/0115-20260328-105612.582-POST.http | +| 0116 | mirror | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./mirror/v1/scmudc/{device_id}/0116-20260328-105612.851-POST.http | +| 0117 | mirror | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./mirror/v1/scmudc/{device_id}/0117-20260328-105612.906-POST.http | +| 0118 | mirror | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./mirror/v1/scmudc/{device_id}/0118-20260328-105613.000-POST.http | +| 0119 | self | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./self/v1/scmudc/{device_id}/0119-20260328-105614.239-POST.http | +| 0120 | mirror | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./mirror/v1/scmudc/{device_id}/0120-20260328-105614.649-POST.http | +| 0121 | self | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./self/v1/scmudc/{device_id}/0121-20260328-111412.273-POST.http | +| 0122 | mirror | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./mirror/v1/scmudc/{device_id}/0122-20260328-111412.689-POST.http | +| 0123 | self | ☑ | GET /streaming/account/{{accountId}}/device/{{device_id}}/group/ | 200 OK | ./self/streaming/account/{accountId}/device/{device_id}/group/0123-20260328-170446.020-GET.http | +| 0124 | mirror | ☑ | GET /streaming/account/{{accountId}}/device/{{device_id}}/group/ | 200 OK | ./mirror/streaming/account/{accountId}/device/{device_id}/group/0124-20260328-170446.206-GET.http | +| 0125 | self | ☑ | GET /streaming/account/{{accountId}}/device/{{device_id}}/group/ | 200 OK | ./self/streaming/account/{accountId}/device/{device_id}/group/0125-20260328-202258.172-GET.http | +| 0126 | mirror | ☑ | GET /streaming/account/{{accountId}}/device/{{device_id}}/group/ | 200 OK | ./mirror/streaming/account/{accountId}/device/{device_id}/group/0126-20260328-202258.374-GET.http | +| 0127 | self | ☑ | GET /streaming/account/{{accountId}}/device/{{device_id}}/group/ | 200 OK | ./self/streaming/account/{accountId}/device/{device_id}/group/0127-20260328-202300.656-GET.http | +| 0128 | mirror | ☑ | GET /streaming/account/{{accountId}}/device/{{device_id}}/group/ | 200 OK | ./mirror/streaming/account/{accountId}/device/{device_id}/group/0128-20260328-202300.841-GET.http | +| 0129 | self | ☑ | GET /streaming/account/{{accountId}}/device/{{device_id}}/group/ | 200 OK | ./self/streaming/account/{accountId}/device/{device_id}/group/0129-20260328-205953.361-GET.http | +| 0130 | mirror | ☑ | GET /streaming/account/{{accountId}}/device/{{device_id}}/group/ | 200 OK | ./mirror/streaming/account/{accountId}/device/{device_id}/group/0130-20260328-205953.560-GET.http | +| 0131 | self | ☑ | GET /streaming/account/{{accountId}}/device/{{device_id}}/group/ | 200 OK | ./self/streaming/account/{accountId}/device/{device_id}/group/0131-20260328-210005.518-GET.http | +| 0132 | mirror | ☑ | GET /streaming/account/{{accountId}}/device/{{device_id}}/group/ | 200 OK | ./mirror/streaming/account/{accountId}/device/{device_id}/group/0132-20260328-210005.707-GET.http | +| 0133 | self | ☑ | GET /streaming/account/{{accountId}}/device/{{device_id}}/group/ | 200 OK | ./self/streaming/account/{accountId}/device/{device_id}/group/0133-20260329-094502.893-GET.http | +| 0134 | mirror | ☑ | GET /streaming/account/{{accountId}}/device/{{device_id}}/group/ | 200 OK | ./mirror/streaming/account/{accountId}/device/{device_id}/group/0134-20260329-094503.109-GET.http | +| 0135 | self | ☑ | GET /streaming/account/{{accountId}}/device/{{device_id}}/group/ | 200 OK | ./self/streaming/account/{accountId}/device/{device_id}/group/0135-20260329-094510.575-GET.http | +| 0136 | mirror | ☑ | GET /streaming/account/{{accountId}}/device/{{device_id}}/group/ | 200 OK | ./mirror/streaming/account/{accountId}/device/{device_id}/group/0136-20260329-094510.907-GET.http | +| 0137 | self | ☑ | GET /streaming/account/{{accountId}}/device/{{device_id}}/group/ | 200 OK | ./self/streaming/account/{accountId}/device/{device_id}/group/0137-20260329-102911.229-GET.http | +| 0138 | mirror | ☑ | GET /streaming/account/{{accountId}}/device/{{device_id}}/group/ | 200 OK | ./mirror/streaming/account/{accountId}/device/{device_id}/group/0138-20260329-102911.443-GET.http | +| 0139 | self | ☑ | GET /streaming/account/{{accountId}}/device/{{device_id}}/group/ | 200 OK | ./self/streaming/account/{accountId}/device/{device_id}/group/0139-20260329-102923.636-GET.http | +| 0140 | mirror | ☑ | GET /streaming/account/{{accountId}}/device/{{device_id}}/group/ | 200 OK | ./mirror/streaming/account/{accountId}/device/{device_id}/group/0140-20260329-102923.807-GET.http | +| 0141 | self | ☑ | GET /streaming/account/{{accountId}}/device/{{device_id}}/group/ | 200 OK | ./self/streaming/account/{accountId}/device/{device_id}/group/0141-20260329-155214.420-GET.http | +| 0142 | mirror | ☑ | GET /streaming/account/{{accountId}}/device/{{device_id}}/group/ | 200 OK | ./mirror/streaming/account/{accountId}/device/{device_id}/group/0142-20260329-155216.805-GET.http | +| 0143 | self | ☑ | GET /streaming/account/{{accountId}}/device/{{device_id}}/group/ | 200 OK | ./self/streaming/account/{accountId}/device/{device_id}/group/0143-20260329-155221.905-GET.http | +| 0144 | mirror | ☑ | GET /streaming/account/{{accountId}}/device/{{device_id}}/group/ | 200 OK | ./mirror/streaming/account/{accountId}/device/{device_id}/group/0144-20260329-155222.082-GET.http | +| 0145 | mirror | ☑ | GET /streaming/account/{{accountId}}/device/{{device_id}}/recents | 200 OK | ./mirror/streaming/account/{accountId}/device/{device_id}/recents/0145-20260329-185442.017-GET.http | +| 0146 | upstream | ☑ | GET https://streaming.bose.com/streaming/account/{{accountId}}/device/{{device_id}}/recents | 200 OK | ./upstream/streaming/account/{accountId}/device/{device_id}/recents/0146-20260329-185442.128-GET.http | +| 0147 | self | ☑ | GET /streaming/account/{{accountId}}/device/{{device_id}}/recents | 200 OK | ./self/streaming/account/{accountId}/device/{device_id}/recents/0147-20260329-185442.130-GET.http | +| 0148 | self | ☑ | GET /streaming/account/{{accountId}}/device/{{device_id}}/group/ | 200 OK | ./self/streaming/account/{accountId}/device/{device_id}/group/0148-20260329-193915.264-GET.http | +| 0149 | mirror | ☑ | GET /streaming/account/{{accountId}}/device/{{device_id}}/group/ | 200 OK | ./mirror/streaming/account/{accountId}/device/{device_id}/group/0149-20260329-193915.468-GET.http | +| 0150 | self | ☑ | GET /streaming/account/{{accountId}}/device/{{device_id}}/group/ | 200 OK | ./self/streaming/account/{accountId}/device/{device_id}/group/0150-20260329-215246.808-GET.http | +| 0151 | mirror | ☑ | GET /streaming/account/{{accountId}}/device/{{device_id}}/group/ | 200 OK | ./mirror/streaming/account/{accountId}/device/{device_id}/group/0151-20260329-215247.001-GET.http | +| 0152 | self | ☑ | GET / | 200 OK | ./self/root/0152-20260329-233126.264-GET.http | +| 0153 | self | ☑ | GET /mgmt/spotify/accounts | 200 OK | ./self/mgmt/spotify/accounts/0153-20260329-233126.506-GET.http | +| 0154 | self | ☑ | GET /mgmt/spotify/accounts | 200 OK | ./self/mgmt/spotify/accounts/0154-20260329-233126.515-GET.http | +| 0155 | self | ☑ | GET /mgmt/spotify/accounts | 200 OK | ./self/mgmt/spotify/accounts/0155-20260329-233126.531-GET.http | +| 0156 | self | ☑ | GET /mgmt/spotify/accounts | 200 OK | ./self/mgmt/spotify/accounts/0156-20260329-233126.542-GET.http | +| 0157 | self | ☑ | GET / | 200 OK | ./self/root/0157-20260329-233128.611-GET.http | +| 0158 | self | ☑ | GET / | 200 OK | ./self/root/0158-20260329-233128.790-GET.http | +| 0159 | self | ☑ | GET /mgmt/spotify/accounts | 200 OK | ./self/mgmt/spotify/accounts/0159-20260329-233129.065-GET.http | +| 0160 | self | ☑ | GET /mgmt/spotify/accounts | 200 OK | ./self/mgmt/spotify/accounts/0160-20260329-233129.089-GET.http | +| 0161 | self | ☑ | GET /mgmt/spotify/accounts | 200 OK | ./self/mgmt/spotify/accounts/0161-20260329-233129.099-GET.http | +| 0162 | self | ☑ | GET /mgmt/spotify/accounts | 200 OK | ./self/mgmt/spotify/accounts/0162-20260329-233129.105-GET.http | +| 0163 | self | ☑ | GET /mgmt/spotify/accounts | 200 OK | ./self/mgmt/spotify/accounts/0163-20260329-233137.103-GET.http | +| 0164 | self | ☑ | GET /mgmt/spotify/accounts | 200 OK | ./self/mgmt/spotify/accounts/0164-20260329-233137.130-GET.http | +| 0165 | self | ☑ | GET /mgmt/accounts | 200 OK | ./self/mgmt/accounts/0165-20260329-233206.623-GET.http | +| 0166 | self | ☑ | GET /mgmt/accounts/{{accountId}} | 200 OK | ./self/mgmt/accounts/{accountId}/0166-20260329-233206.693-GET.http | +| 0167 | self | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./self/v1/scmudc/{device_id}/0167-20260329-233249.970-POST.http | +| 0168 | mirror | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./mirror/v1/scmudc/{device_id}/0168-20260329-233250.408-POST.http | +| 0169 | self | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./self/v1/scmudc/{device_id}/0169-20260329-233257.652-POST.http | +| 0170 | self | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./self/v1/scmudc/{device_id}/0170-20260329-233257.674-POST.http | +| 0171 | mirror | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./mirror/v1/scmudc/{device_id}/0171-20260329-233258.075-POST.http | +| 0172 | mirror | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./mirror/v1/scmudc/{device_id}/0172-20260329-233258.097-POST.http | +| 0173 | mirror | ☑ | GET /bmx/tunein/v1/playback/station/s166521 | 401 Unauthorized | ./mirror/bmx/tunein/v1/playback/station/s166521/0173-20260329-233258.121-GET.http | +| 0174 | self | ☑ | GET /bmx/tunein/v1/playback/station/s166521 | 200 OK | ./self/bmx/tunein/v1/playback/station/s166521/0174-20260329-233258.171-GET.http | +| 0175 | self | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./self/v1/scmudc/{device_id}/0175-20260329-233258.625-POST.http | +| 0176 | upstream | ☑ | POST https://content.api.bose.io/bmx/tunein/v1/token | 200 OK | ./upstream/bmx/tunein/v1/token/0176-20260329-233259.006-POST.http | +| 0177 | self | ☑ | POST /bmx/tunein/v1/token | 200 OK | ./self/bmx/tunein/v1/token/0177-20260329-233259.008-POST.http | +| 0178 | mirror | ☑ | POST /bmx/tunein/v1/token | 200 OK | ./mirror/bmx/tunein/v1/token/0178-20260329-233259.013-POST.http | +| 0179 | mirror | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./mirror/v1/scmudc/{device_id}/0179-20260329-233259.046-POST.http | +| 0180 | self | ☑ | GET /bmx/tunein/v1/playback/station/s166521 | 200 OK | ./self/bmx/tunein/v1/playback/station/s166521/0180-20260329-233259.719-GET.http | +| 0181 | mirror | ☑ | GET /bmx/tunein/v1/playback/station/s166521 | 200 OK | ./mirror/bmx/tunein/v1/playback/station/s166521/0181-20260329-233300.084-GET.http | +| 0182 | self | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./self/v1/scmudc/{device_id}/0182-20260329-233302.393-POST.http | +| 0183 | self | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./self/v1/scmudc/{device_id}/0183-20260329-233302.636-POST.http | +| 0184 | self | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./self/v1/scmudc/{device_id}/0184-20260329-233302.655-POST.http | +| 0185 | self | ☑ | POST /streaming/account/{{accountId}}/device/{{device_id}}/recent | 201 Created | ./self/streaming/account/{accountId}/device/{device_id}/recent/0185-20260329-233302.671-POST.http | +| 0186 | mirror | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./mirror/v1/scmudc/{device_id}/0186-20260329-233302.906-POST.http | +| 0187 | mirror | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./mirror/v1/scmudc/{device_id}/0187-20260329-233303.115-POST.http | +| 0188 | mirror | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./mirror/v1/scmudc/{device_id}/0188-20260329-233303.118-POST.http | +| 0189 | mirror | ☑ | POST /streaming/account/{{accountId}}/device/{{device_id}}/recent | 201 Created | ./mirror/streaming/account/{accountId}/device/{device_id}/recent/0189-20260329-233303.759-POST.http | +| 0190 | self | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./self/v1/scmudc/{device_id}/0190-20260329-233304.143-POST.http | +| 0191 | self | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./self/v1/scmudc/{device_id}/0191-20260329-233304.269-POST.http | +| 0192 | mirror | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./mirror/v1/scmudc/{device_id}/0192-20260329-233304.554-POST.http | +| 0193 | mirror | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./mirror/v1/scmudc/{device_id}/0193-20260329-233304.685-POST.http | +| 0194 | self | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./self/v1/scmudc/{device_id}/0194-20260329-233305.629-POST.http | +| 0195 | mirror | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./mirror/v1/scmudc/{device_id}/0195-20260329-233306.040-POST.http | +| 0196 | mirror | ☑ | POST /bmx/tunein/v1/report?stream_id=e536753726&guide_id=s166521&listen_id=1774819980&stream_type=liveRadio | 200 OK | ./mirror/bmx/tunein/v1/report/0196-20260329-233306.072-POST.http | +| 0197 | upstream | ☑ | POST https://content.api.bose.io/bmx/tunein/v1/report?stream_id=e536753726&guide_id=s166521&listen_id=1774819980&stream_type=liveRadio | 200 OK | ./upstream/bmx/tunein/v1/report/0197-20260329-233306.182-POST.http | +| 0198 | self | ☑ | POST /bmx/tunein/v1/report?stream_id=e536753726&guide_id=s166521&listen_id=1774819980&stream_type=liveRadio | 200 OK | ./self/bmx/tunein/v1/report/0198-20260329-233306.184-POST.http | +| 0199 | self | ☑ | GET /streaming/software/update/account/{{accountId}} | 200 OK | ./self/streaming/software/update/account/{accountId}/0199-20260329-233317.196-GET.http | +| 0200 | self | ☑ | GET /streaming/account/{{accountId}}/device/{{device_id}}/presets | 200 OK | ./self/streaming/account/{accountId}/device/{device_id}/presets/0200-20260329-233317.206-GET.http | +| 0201 | mirror | ☑ | GET /streaming/account/{{accountId}}/device/{{device_id}}/presets | 200 OK | ./mirror/streaming/account/{accountId}/device/{device_id}/presets/0201-20260329-233317.394-GET.http | +| 0202 | mirror | ☑ | GET /streaming/software/update/account/{{accountId}} | 200 OK | ./mirror/streaming/software/update/account/{accountId}/0202-20260329-233317.409-GET.http | +| 0203 | self | ☑ | GET /updates/soundtouch?serialnumber=_serial_ | 200 OK | ./self/updates/soundtouch/0203-20260329-233317.838-GET.http | +| 0204 | self | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./self/v1/scmudc/{device_id}/0204-20260329-233330.871-POST.http | +| 0205 | mirror | ☑ | PUT /streaming/account/{{accountId}}/device/{{device_id}}/preset/6 | 200 OK | ./mirror/streaming/account/{accountId}/device/{device_id}/preset/6/0205-20260329-233331.093-PUT.http | +| 0206 | upstream | ☑ | PUT https://streaming.bose.com/streaming/account/{{accountId}}/device/{{device_id}}/preset/6 | 500 Internal Server Error | ./upstream/streaming/account/{accountId}/device/{device_id}/preset/6/0206-20260329-233331.096-PUT.http | +| 0207 | self | ☑ | PUT /streaming/account/{{accountId}}/device/{{device_id}}/preset/6 | 500 Internal Server Error | ./self/streaming/account/{accountId}/device/{device_id}/preset/6/0207-20260329-233331.096-PUT.http | +| 0208 | mirror | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./mirror/v1/scmudc/{device_id}/0208-20260329-233331.323-POST.http | +| 0209 | self | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./self/v1/scmudc/{device_id}/0209-20260329-233331.938-POST.http | +| 0210 | self | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./self/v1/scmudc/{device_id}/0210-20260329-233331.982-POST.http | +| 0211 | mirror | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./mirror/v1/scmudc/{device_id}/0211-20260329-233332.366-POST.http | +| 0212 | mirror | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./mirror/v1/scmudc/{device_id}/0212-20260329-233332.396-POST.http | +| 0213 | self | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./self/v1/scmudc/{device_id}/0213-20260329-233344.994-POST.http | +| 0214 | self | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./self/v1/scmudc/{device_id}/0214-20260329-233345.001-POST.http | +| 0215 | mirror | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./mirror/v1/scmudc/{device_id}/0215-20260329-233345.427-POST.http | +| 0216 | mirror | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./mirror/v1/scmudc/{device_id}/0216-20260329-233345.430-POST.http | +| 0217 | mirror | ☑ | POST /bmx/tunein/v1/report?stream_id=e536753726&guide_id=s166521&listen_id=1774819980&last_titt=0&duration_balance=0&stream_type=liveRadio | 200 OK | ./mirror/bmx/tunein/v1/report/0217-20260329-233345.547-POST.http | +| 0218 | upstream | ☑ | POST https://content.api.bose.io/bmx/tunein/v1/report?stream_id=e536753726&guide_id=s166521&listen_id=1774819980&last_titt=0&duration_balance=0&stream_type=liveRadio | 200 OK | ./upstream/bmx/tunein/v1/report/0218-20260329-233345.651-POST.http | +| 0219 | self | ☑ | POST /bmx/tunein/v1/report?stream_id=e536753726&guide_id=s166521&listen_id=1774819980&last_titt=0&duration_balance=0&stream_type=liveRadio | 200 OK | ./self/bmx/tunein/v1/report/0219-20260329-233345.651-POST.http | +| 0220 | self | ☑ | GET /bmx/registry/v1/services | 200 OK | ./self/bmx/registry/v1/services/0220-20260329-233504.445-GET.http | +| 0221 | self | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./self/v1/scmudc/{device_id}/0221-20260329-233504.467-POST.http | +| 0222 | self | ☑ | POST /streaming/support/power_on | 200 OK | ./self/streaming/support/power_on/0222-20260329-233504.475-POST.http | +| 0223 | mirror | ☑ | POST /streaming/support/power_on | 200 OK | ./mirror/streaming/support/power_on/0223-20260329-233504.668-POST.http | +| 0224 | mirror | ☑ | GET /bmx/registry/v1/services | 200 OK | ./mirror/bmx/registry/v1/services/0224-20260329-233504.879-GET.http | +| 0225 | mirror | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./mirror/v1/scmudc/{device_id}/0225-20260329-233504.891-POST.http | +| 0226 | self | ☑ | GET / | 200 OK | ./self/root/0226-20260329-233505.214-GET.http | +| 0227 | self | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./self/v1/scmudc/{device_id}/0227-20260329-233505.548-POST.http | +| 0228 | self | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./self/v1/scmudc/{device_id}/0228-20260329-233505.560-POST.http | +| 0229 | self | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./self/v1/scmudc/{device_id}/0229-20260329-233505.735-POST.http | +| 0230 | mirror | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./mirror/v1/scmudc/{device_id}/0230-20260329-233505.980-POST.http | +| 0231 | mirror | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./mirror/v1/scmudc/{device_id}/0231-20260329-233505.994-POST.http | +| 0232 | mirror | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./mirror/v1/scmudc/{device_id}/0232-20260329-233506.158-POST.http | +| 0233 | self | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./self/v1/scmudc/{device_id}/0233-20260329-233506.707-POST.http | +| 0234 | self | ☑ | GET /streaming/sourceproviders | 200 OK | ./self/streaming/sourceproviders/0234-20260329-233506.769-GET.http | +| 0235 | self | | GET /streaming/account/{{accountId}}/full | 200 OK | ./self/streaming/account/{accountId}/full/0235-20260329-233507.099-GET.http | +| 0236 | mirror | ☑ | POST /v1/scmudc/{{device_id}} | 200 OK | ./mirror/v1/scmudc/{device_id}/0236-20260329-233507.137-POST.http | +| 0237 | mirror | | GET /streaming/account/{{accountId}}/full | 200 OK | ./mirror/streaming/account/{accountId}/full/0237-20260329-233507.277-GET.http | +| 0238 | self | ☑ | GET /streaming/account/{{accountId}}/device/{{device_id}}/group/ | 200 OK | ./self/streaming/account/{accountId}/device/{device_id}/group/0238-20260329-233508.639-GET.http | +| 0239 | self | ☑ | GET /streaming/device/{{device_id}}/streaming_token | 200 OK | ./self/streaming/device/{device_id}/streaming_token/0239-20260329-233508.642-GET.http | +| 0240 | self | ☑ | GET /streaming/account/{{accountId}}/provider_settings | 200 OK | ./self/streaming/account/{accountId}/provider_settings/0240-20260329-233508.755-GET.http | +| 0241 | mirror | ☑ | GET /streaming/account/{{accountId}}/device/{{device_id}}/group/ | 200 OK | ./mirror/streaming/account/{accountId}/device/{device_id}/group/0241-20260329-233508.809-GET.http | +| 0242 | self | ☑ | GET /streaming/account/{{accountId}}/provider_settings | 200 OK | ./self/streaming/account/{accountId}/provider_settings/0242-20260329-233508.866-GET.http | +| 0243 | mirror | ☑ | GET /streaming/account/{{accountId}}/provider_settings | 200 OK | ./mirror/streaming/account/{accountId}/provider_settings/0243-20260329-233508.968-GET.http | +| 0244 | mirror | ☑ | GET /streaming/account/{{accountId}}/provider_settings | 200 OK | ./mirror/streaming/account/{accountId}/provider_settings/0244-20260329-233509.041-GET.http | +| 0245 | self | ☑ | POST /oauth/device/{{device_id}}/music/musicprovider/15/token/cs3 | 200 OK | ./self/oauth/device/{device_id}/music/musicprovider/15/token/cs3/0245-20260329-233510.807-POST.http | +| 0246 | self | ☑ | POST /streaming/music/musicprovider/{{providerID}}/trial/is_eligible | 200 OK | ../scripts/android/mitm/bose-pairing-20260502-165549/mirror/streaming/music/musicprovider/14/trial/is_eligible/0005-20260502-165628.675-POST.http | +| 0247 | self | ☑ | POST /bmx/tunein/v1/favorite/{{stationId}} | 202 Accepted | ../scripts/android/captures/var/lib/soundtouch-service/interactions/20260502-170853-2882944/self/bmx/tunein/v1/favorite/s25260/0172-20260502-173202.662-POST.http | diff --git a/tests/interactions_20260502_missing_external.md b/tests/interactions_20260502_missing_external.md new file mode 100644 index 0000000..9e7979b --- /dev/null +++ b/tests/interactions_20260502_missing_external.md @@ -0,0 +1,48 @@ +Endpoints observed in `bose-pairing-20260502-155542`, `bose-pairing-20260502-165549` mitm captures +and `20260502-170853-2882944` service interaction recording that are either served by external hosts +not redirected to soundtouch-service, or are third-party analytics calls that the service does not +need to handle. + +## Redirected Bose hosts — implemented ✅ + +These hosts are now in the DNS redirect list and the service handles them natively. + +| host | request | handler | notes | +|---------------------|----------------------------------------------------------------------|---------------------------------|--------------------------------------------------------------------------------------------------------------| +| streaming.bose.com | `POST /streaming/music/musicprovider/{providerID}/trial/is_eligible` | `HandleMusicProviderIsEligible` | reuses same handler as `/is_eligible`; response: `false` | +| content.api.bose.io | `POST /bmx/tunein/v1/favorite/{stationID}` | `HandleTuneInFavorite` | returns 202 Accepted `{}`; row 0247 in interactions_20260328-103522-477978.md | +| downloads.bose.com | `GET /ced/soundtouch/mr4_22097fe2/index.xml` | `HandleCedStatic` | firmware index XML; static file embedded from `static/ced/` | +| downloads.bose.com | `GET /ced/soundtouch/mr4_22097fe2/relnotes/releasenotes_en.xml` | `HandleCedStatic` | firmware release notes; static file embedded | +| downloads.bose.com | `GET /ced/soundtouch/soundtouch_app_help/en/*.xml` | `HandleCedStatic` | 10 in-app help XMLs embedded (gabbo_*, name_device, welcome, etc.) | +| media.bose.io | `GET /bmx-icons/tunein/monochromeSvg.svg` | `HandleBmxIcons` | already in `static/media/bmx-icons/tunein/` | +| media.bose.io | `GET /bmx-icons/tunein/smallSvg.svg` | `HandleBmxIcons` | already in `static/media/bmx-icons/tunein/` | +| media.bose.io | `GET /bmx-icons/tunein/top-menu/*.png` | `HandleBmxIcons` | 6 PNGs embedded (bubble, location, microphone, news, note, podcasts); speaker.png was 403 from CDN | + +## Remaining: external host requiring action + +| host | request | notes | +|-------------------|---------------------------|-----------------------------------------------------------------------------------------------------------------------------------------| +| voice.api.bose.io | `POST /alexa/certificate` | Alexa IoT cert provisioning; CSR + auth token → AWS IoT cert + endpoint; not in DNS redirect list; Alexa setup will fail after shutdown | + +## Third-party analytics (no action needed) + +These are calls to third-party analytics services made by the Bose app itself. +soundtouch-service does not handle or intercept them. + +| host | request | notes | +|-----------------------|------------------------------|--------------------------------------------------------------------| +| api.segment.io | `POST /v1/i` | Segment analytics — identify event | +| api.segment.io | `POST /v1/p` | Segment analytics — page event | +| api.segment.io | `POST /v1/t` | Segment analytics — track event | +| events.api.bosecm.com | `POST /v1/stapp/{accountId}` | Bose app telemetry; handled by service at `/v1/stapp/{deviceId}` ✅ | + +## TuneIn / Spotify CDN (no action needed) + +Image CDNs used by TuneIn browse and Spotify artwork — not Bose infrastructure. + +| host | request pattern | +|--------------------------------|-----------------------------------| +| cdn-profiles.tunein.com | `GET /{stationId}/images/logog.*` | +| cdn-albums.tunein.com | `GET /gn/*.jpg` | +| cdn-radiotime-logos.tunein.com | `GET /s*.png` | +| i.scdn.co | `GET /image/{hash}` |