mirror of
https://github.com/gesellix/Bose-SoundTouch.git
synced 2026-08-18 16:46:17 +00:00
fix(player): set STORED_MUSIC type when replaying a recent (fix INVALID_SOURCE)
Replaying a STORED_MUSIC item from Recents sent the speaker a ContentItem with an empty type (recents carry no contentItemType for STORED_MUSIC), and the speaker rejects an empty-type STORED_MUSIC select with INVALID_SOURCE. The library play paths work because they pass type "track"/"dir". HandleDevicePlay now derives the type from the speaker-native location, which ends with the item kind (e.g. "1$4$2 TRACK" -> "track"), when the caller didn't supply one. (The recents account itself is already correct via the #503 fix.) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
b8de0f90f0
commit
d6257e6108
@@ -1114,6 +1114,19 @@ func (app *WebApp) HandleDeviceRecents(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
}
|
||||
|
||||
// storedMusicTypeForReplay derives a STORED_MUSIC ContentItem type from the
|
||||
// speaker-native location, which ends with the item kind (e.g. "1$4$2 TRACK"
|
||||
// or a container's "… DIR"). Recents don't store the type, and the speaker
|
||||
// rejects an empty-type STORED_MUSIC select with INVALID_SOURCE. Falls back to
|
||||
// "track" when the location has no kind suffix.
|
||||
func storedMusicTypeForReplay(location string) string {
|
||||
if fields := strings.Fields(location); len(fields) >= 2 {
|
||||
return strings.ToLower(fields[len(fields)-1])
|
||||
}
|
||||
|
||||
return "track"
|
||||
}
|
||||
|
||||
// HandleDevicePlay plays an arbitrary content item on a device. Generic
|
||||
// counterpart to HandlePlayTuneIn — used by the Recents panel to replay
|
||||
// items the speaker reports under /recents, regardless of their source.
|
||||
@@ -1151,9 +1164,18 @@ func (app *WebApp) HandleDevicePlay(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
// Recents don't carry a contentItemType for STORED_MUSIC, and the speaker
|
||||
// rejects an empty-type STORED_MUSIC select with INVALID_SOURCE. The
|
||||
// speaker-native location ends with the item kind (e.g. "1$4$2 TRACK"), so
|
||||
// derive the type from it when the caller didn't supply one.
|
||||
ciType := req.Type
|
||||
if ciType == "" && req.Source == "STORED_MUSIC" {
|
||||
ciType = storedMusicTypeForReplay(req.Location)
|
||||
}
|
||||
|
||||
contentItem := &models.ContentItem{
|
||||
Source: req.Source,
|
||||
Type: req.Type,
|
||||
Type: ciType,
|
||||
Location: req.Location,
|
||||
ItemName: req.ItemName,
|
||||
ContainerArt: req.ContainerArt,
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
package soundtouchweb
|
||||
|
||||
import "testing"
|
||||
|
||||
// TestStoredMusicTypeForReplay covers deriving the ContentItem type from a
|
||||
// STORED_MUSIC recent's location when the stored type is empty. Without a type
|
||||
// the speaker rejects the select with INVALID_SOURCE.
|
||||
func TestStoredMusicTypeForReplay(t *testing.T) {
|
||||
cases := []struct {
|
||||
location string
|
||||
want string
|
||||
}{
|
||||
{"1$4$2 TRACK", "track"},
|
||||
{"5:audio5:part13:5521:5 TRACK", "track"},
|
||||
{"1 DIR", "dir"},
|
||||
{"1 CONTAINER", "container"},
|
||||
{"noSuffix", "track"}, // fallback
|
||||
{"", "track"}, // fallback
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
if got := storedMusicTypeForReplay(c.location); got != c.want {
|
||||
t.Errorf("storedMusicTypeForReplay(%q) = %q, want %q", c.location, got, c.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user