mirror of
https://github.com/gesellix/Bose-SoundTouch.git
synced 2026-09-07 15:07:17 +00:00
fix(player): open the Library for STORED_MUSIC instead of selecting it
A STORED_MUSIC entry names a media server, not something to play: its sourceAccount is a server UDN, and there is one entry per server. Selecting it identifies no track or container, so browsing is the only meaningful action. Clicking one now opens the Library. It never resumes from Recents either: even a resumable album there is a worse guess than showing the user what is on the server. The clicked server is not carried over, matching how the other browser pages let you pick a device rather than inheriting one. Servers that are offline never reach this path anyway: the speaker reports them status="UNAVAILABLE" and the source list only renders READY entries. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
2bf171e8e8
commit
c7319b383c
@@ -68,6 +68,7 @@ render(h(Sources, {
|
||||
sources: { SourceItem: [
|
||||
{ Source: 'RADIO_BROWSER', SourceAccount: '', DisplayName: 'RadioBrowser', Status: 'READY' },
|
||||
{ Source: 'LOCAL_INTERNET_RADIO', SourceAccount: '', DisplayName: 'Local Radio', Status: 'READY' },
|
||||
{ Source: 'STORED_MUSIC', SourceAccount: 'fa095ecc-e13e-40e7-8e6c-e0286d5bc000/0', DisplayName: 'fritz', Status: 'READY' },
|
||||
] },
|
||||
nowPlaying: { Source: 'SPOTIFY', SourceAccount: 'someone' },
|
||||
},
|
||||
@@ -827,6 +828,57 @@ func TestLocalInternetRadioNeverResumes(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestStoredMusicOpensTheLibrary: a STORED_MUSIC entry names a media server,
|
||||
// not something to play, so selecting it identifies no track or container.
|
||||
// Browsing is the only meaningful action.
|
||||
func TestStoredMusicOpensTheLibrary(t *testing.T) {
|
||||
var mu sync.Mutex
|
||||
writes := 0
|
||||
server := newPlayerFixtureServer(t, providerFixtureScript, func(r chi.Router) {
|
||||
r.Get("/api/control/devices/speaker/recents", func(w http.ResponseWriter, _ *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
_, _ = w.Write([]byte(`{"success":true,"data":{"Items":[
|
||||
{"ID":1,"ContentItem":{"Source":"STORED_MUSIC","Type":"dir",
|
||||
"SourceAccount":"fa095ecc-e13e-40e7-8e6c-e0286d5bc000/0",
|
||||
"Location":"/music/album/1","ItemName":"Some Album","IsPresetable":true}}
|
||||
]}}`))
|
||||
})
|
||||
r.Post("/api/control/devices/speaker/play", func(w http.ResponseWriter, _ *http.Request) {
|
||||
mu.Lock()
|
||||
writes++
|
||||
mu.Unlock()
|
||||
})
|
||||
r.Post("/api/control/devices/speaker/action/source", func(w http.ResponseWriter, _ *http.Request) {
|
||||
mu.Lock()
|
||||
writes++
|
||||
mu.Unlock()
|
||||
})
|
||||
})
|
||||
|
||||
ctx := newHeadlessChromeContext(t)
|
||||
var navigated []string
|
||||
if err := chromedp.Run(ctx,
|
||||
chromedp.Navigate(server.URL+"/fixture"),
|
||||
chromedp.WaitVisible(`.source-btn`, chromedp.ByQuery),
|
||||
chromedp.Click(`.source-btn:nth-child(3)`, chromedp.ByQuery),
|
||||
chromedp.Poll(`window.navigated.length === 1`, nil),
|
||||
chromedp.Evaluate(`window.navigated`, &navigated),
|
||||
); err != nil {
|
||||
t.Fatalf("exercise STORED_MUSIC source: %v", err)
|
||||
}
|
||||
|
||||
if len(navigated) != 1 || navigated[0] != "library" {
|
||||
t.Errorf("navigated = %v, want [library]", navigated)
|
||||
}
|
||||
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
// Even with a resumable album in Recents, this source only ever browses.
|
||||
if writes != 0 {
|
||||
t.Errorf("issued %d writes, want 0", writes)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSourceSelectionStopsReadbacksOnceTheEventStreamConfirms(t *testing.T) {
|
||||
var mu sync.Mutex
|
||||
reads := 0
|
||||
|
||||
@@ -43,10 +43,18 @@ const SOURCE_READBACK_DELAYS_MS = [2000, 5000, 10000];
|
||||
// which is what HandlePlayURL emits content for, is predictable instead of
|
||||
// guessing. RADIO_BROWSER and TUNEIN have no such problem: nothing writes
|
||||
// one-shot audio to them, and their Recents hold real stations.
|
||||
//
|
||||
// STORED_MUSIC does not resume either, for a different reason: it is not one
|
||||
// source but one entry per media server (its sourceAccount is a server UDN),
|
||||
// and selecting it identifies no track or container to play. Browsing is the
|
||||
// only meaningful action, so a click opens the Library. The clicked server is
|
||||
// not carried over -- the Library lists the servers itself, the same way the
|
||||
// other browser pages let you pick a device.
|
||||
const PROVIDER_SOURCES = {
|
||||
RADIO_BROWSER: { page: 'radiobrowser', resume: true },
|
||||
TUNEIN: { page: 'tunein', resume: true },
|
||||
LOCAL_INTERNET_RADIO: { page: 'playurl', resume: false },
|
||||
STORED_MUSIC: { page: 'library', resume: false },
|
||||
};
|
||||
|
||||
function isErrorSource(source) {
|
||||
|
||||
Reference in New Issue
Block a user