mirror of
https://github.com/gesellix/Bose-SoundTouch.git
synced 2026-08-18 08:36:13 +00:00
Applied automatic fixes using golangci-lint --fix which resolved: - All remaining wsl_v5 whitespace issues (28 issues) - All whitespace formatting issues (1 issue) - Improved code formatting consistency across the entire codebase All tests passing and functionality preserved.
512 lines
13 KiB
Go
512 lines
13 KiB
Go
package models
|
|
|
|
import "encoding/xml"
|
|
|
|
// SupportedURLsResponse represents the response from the /supportedURLs endpoint
|
|
type SupportedURLsResponse struct {
|
|
XMLName xml.Name `xml:"supportedURLs"`
|
|
DeviceID string `xml:"deviceID,attr"`
|
|
URLs []URL `xml:"URL"`
|
|
}
|
|
|
|
// URL represents a single supported URL endpoint
|
|
type URL struct {
|
|
Location string `xml:"location,attr"`
|
|
}
|
|
|
|
// GetURLs returns a slice of all supported URL locations
|
|
func (s *SupportedURLsResponse) GetURLs() []string {
|
|
urls := make([]string, len(s.URLs))
|
|
for i, url := range s.URLs {
|
|
urls[i] = url.Location
|
|
}
|
|
|
|
return urls
|
|
}
|
|
|
|
// HasURL checks if a specific URL location is supported
|
|
func (s *SupportedURLsResponse) HasURL(location string) bool {
|
|
for _, url := range s.URLs {
|
|
if url.Location == location {
|
|
return true
|
|
}
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
// GetURLCount returns the total number of supported URLs
|
|
func (s *SupportedURLsResponse) GetURLCount() int {
|
|
return len(s.URLs)
|
|
}
|
|
|
|
// GetCoreURLs returns URLs for core device functionality
|
|
func (s *SupportedURLsResponse) GetCoreURLs() []string {
|
|
coreEndpoints := []string{
|
|
"/info", "/capabilities", "/name", "/sources", "/volume",
|
|
"/bass", "/balance", "/presets", "/nowPlaying", "/clock",
|
|
"/key", "/powerManagement",
|
|
}
|
|
|
|
var available []string
|
|
|
|
for _, endpoint := range coreEndpoints {
|
|
if s.HasURL(endpoint) {
|
|
available = append(available, endpoint)
|
|
}
|
|
}
|
|
|
|
return available
|
|
}
|
|
|
|
// GetStreamingURLs returns URLs for streaming service functionality
|
|
func (s *SupportedURLsResponse) GetStreamingURLs() []string {
|
|
streamingEndpoints := []string{
|
|
"/navigate", "/search", "/addStation", "/removeStation",
|
|
"/serviceAvailability", "/sources", "/select",
|
|
}
|
|
|
|
var available []string
|
|
|
|
for _, endpoint := range streamingEndpoints {
|
|
if s.HasURL(endpoint) {
|
|
available = append(available, endpoint)
|
|
}
|
|
}
|
|
|
|
return available
|
|
}
|
|
|
|
// GetAdvancedURLs returns URLs for advanced audio and system functionality
|
|
func (s *SupportedURLsResponse) GetAdvancedURLs() []string {
|
|
advancedEndpoints := []string{
|
|
"/audiodspcontrols", "/audioproducttonecontrols",
|
|
"/audioproductlevelcontrols", "/videoSyncAudioDelay",
|
|
"/group", "/setZone", "/addZoneSlave", "/removeZoneSlave",
|
|
"/bassCapabilities", "/recents", "/trackInfo",
|
|
}
|
|
|
|
var available []string
|
|
|
|
for _, endpoint := range advancedEndpoints {
|
|
if s.HasURL(endpoint) {
|
|
available = append(available, endpoint)
|
|
}
|
|
}
|
|
|
|
return available
|
|
}
|
|
|
|
// GetNetworkURLs returns URLs for network and connectivity functionality
|
|
func (s *SupportedURLsResponse) GetNetworkURLs() []string {
|
|
networkEndpoints := []string{
|
|
"/networkInfo", "/netStats", "/wifiProfile", "/bluetoothInfo",
|
|
"/airplay", "/wirelessProfile",
|
|
}
|
|
|
|
var available []string
|
|
|
|
for _, endpoint := range networkEndpoints {
|
|
if s.HasURL(endpoint) {
|
|
available = append(available, endpoint)
|
|
}
|
|
}
|
|
|
|
return available
|
|
}
|
|
|
|
// HasCorePlaybackSupport checks if device supports basic playback functionality
|
|
func (s *SupportedURLsResponse) HasCorePlaybackSupport() bool {
|
|
required := []string{"/nowPlaying", "/key", "/volume"}
|
|
for _, endpoint := range required {
|
|
if !s.HasURL(endpoint) {
|
|
return false
|
|
}
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
// HasPresetSupport checks if device supports preset functionality
|
|
func (s *SupportedURLsResponse) HasPresetSupport() bool {
|
|
return s.HasURL("/presets")
|
|
}
|
|
|
|
// HasMultiroomSupport checks if device supports multiroom/zone functionality
|
|
func (s *SupportedURLsResponse) HasMultiroomSupport() bool {
|
|
return s.HasURL("/setZone") || s.HasURL("/addZoneSlave")
|
|
}
|
|
|
|
// HasAdvancedAudioSupport checks if device supports advanced audio controls
|
|
func (s *SupportedURLsResponse) HasAdvancedAudioSupport() bool {
|
|
return s.HasURL("/audiodspcontrols") || s.HasURL("/audioproducttonecontrols")
|
|
}
|
|
|
|
// HasStreamingSupport checks if device supports streaming service navigation
|
|
func (s *SupportedURLsResponse) HasStreamingSupport() bool {
|
|
return s.HasURL("/navigate") || s.HasURL("/search")
|
|
}
|
|
|
|
// GetUnsupportedURLs returns a list of common URLs that this device doesn't support
|
|
func (s *SupportedURLsResponse) GetUnsupportedURLs(checkList []string) []string {
|
|
var unsupported []string
|
|
|
|
for _, endpoint := range checkList {
|
|
if !s.HasURL(endpoint) {
|
|
unsupported = append(unsupported, endpoint)
|
|
}
|
|
}
|
|
|
|
return unsupported
|
|
}
|
|
|
|
// EndpointFeature represents a feature that maps to one or more endpoints
|
|
type EndpointFeature struct {
|
|
Name string `json:"name"`
|
|
Description string `json:"description"`
|
|
Endpoints []string `json:"endpoints"`
|
|
Category string `json:"category"`
|
|
Essential bool `json:"essential"` // Required for basic operation
|
|
CLICommand string `json:"cli_command"` // Corresponding CLI command
|
|
}
|
|
|
|
// GetEndpointFeatureMap returns a comprehensive mapping of endpoints to implemented features
|
|
func GetEndpointFeatureMap() []EndpointFeature {
|
|
return []EndpointFeature{
|
|
// Core Device Information
|
|
{
|
|
Name: "Device Information",
|
|
Description: "Basic device details, name, and identification",
|
|
Endpoints: []string{"/info", "/name"},
|
|
Category: "Core",
|
|
Essential: true,
|
|
CLICommand: "info get, name get/set",
|
|
},
|
|
{
|
|
Name: "Device Capabilities",
|
|
Description: "Supported device features and endpoints discovery",
|
|
Endpoints: []string{"/capabilities", "/supportedURLs"},
|
|
Category: "Core",
|
|
Essential: true,
|
|
CLICommand: "capabilities, supported-urls",
|
|
},
|
|
{
|
|
Name: "Network Information",
|
|
Description: "Network configuration and connectivity status",
|
|
Endpoints: []string{"/networkInfo", "/netStats", "/wifiProfile"},
|
|
Category: "Network",
|
|
Essential: false,
|
|
CLICommand: "network info",
|
|
},
|
|
|
|
// Audio Control
|
|
{
|
|
Name: "Volume Control",
|
|
Description: "Audio volume management and adjustment",
|
|
Endpoints: []string{"/volume"},
|
|
Category: "Audio",
|
|
Essential: true,
|
|
CLICommand: "volume get/set/up/down",
|
|
},
|
|
{
|
|
Name: "Bass Control",
|
|
Description: "Bass level adjustment and capabilities",
|
|
Endpoints: []string{"/bass", "/bassCapabilities"},
|
|
Category: "Audio",
|
|
Essential: false,
|
|
CLICommand: "bass get/set/up/down",
|
|
},
|
|
{
|
|
Name: "Balance Control",
|
|
Description: "Left/right audio balance adjustment",
|
|
Endpoints: []string{"/balance"},
|
|
Category: "Audio",
|
|
Essential: false,
|
|
CLICommand: "balance get/set/left/right",
|
|
},
|
|
{
|
|
Name: "Advanced Audio Controls",
|
|
Description: "DSP controls, tone controls, and audio processing",
|
|
Endpoints: []string{"/audiodspcontrols", "/audioproducttonecontrols", "/audioproductlevelcontrols"},
|
|
Category: "Audio",
|
|
Essential: false,
|
|
CLICommand: "audio dsp/tone/level",
|
|
},
|
|
|
|
// Playback Control
|
|
{
|
|
Name: "Playback Control",
|
|
Description: "Play, pause, stop, and track navigation",
|
|
Endpoints: []string{"/key", "/nowPlaying"},
|
|
Category: "Playback",
|
|
Essential: true,
|
|
CLICommand: "play start/stop/pause, key send",
|
|
},
|
|
{
|
|
Name: "Track Information",
|
|
Description: "Currently playing track details and metadata",
|
|
Endpoints: []string{"/trackInfo", "/recents"},
|
|
Category: "Playback",
|
|
Essential: false,
|
|
CLICommand: "play now, track get",
|
|
},
|
|
|
|
// Source Management
|
|
{
|
|
Name: "Audio Sources",
|
|
Description: "Available audio sources and source selection",
|
|
Endpoints: []string{"/sources", "/select"},
|
|
Category: "Sources",
|
|
Essential: true,
|
|
CLICommand: "source list/select/spotify/bluetooth/aux",
|
|
},
|
|
{
|
|
Name: "Service Availability",
|
|
Description: "Streaming service availability and status",
|
|
Endpoints: []string{"/serviceAvailability"},
|
|
Category: "Sources",
|
|
Essential: false,
|
|
CLICommand: "source availability/compare",
|
|
},
|
|
|
|
// Content Navigation
|
|
{
|
|
Name: "Content Navigation",
|
|
Description: "Browse music libraries and streaming services",
|
|
Endpoints: []string{"/navigate", "/search"},
|
|
Category: "Content",
|
|
Essential: false,
|
|
CLICommand: "browse content/tunein/pandora/spotify",
|
|
},
|
|
{
|
|
Name: "Station Management",
|
|
Description: "Add, remove, and manage radio stations",
|
|
Endpoints: []string{"/addStation", "/removeStation"},
|
|
Category: "Content",
|
|
Essential: false,
|
|
CLICommand: "station add/remove/search/list",
|
|
},
|
|
|
|
// Presets
|
|
{
|
|
Name: "Preset Management",
|
|
Description: "Store and recall favorite content as presets",
|
|
Endpoints: []string{"/presets"},
|
|
Category: "Presets",
|
|
Essential: false,
|
|
CLICommand: "preset list/set/select/remove",
|
|
},
|
|
|
|
// Multiroom/Zone
|
|
{
|
|
Name: "Multiroom Zones",
|
|
Description: "Create and manage speaker groups",
|
|
Endpoints: []string{"/setZone", "/getZone", "/addZoneSlave", "/removeZoneSlave"},
|
|
Category: "Multiroom",
|
|
Essential: false,
|
|
CLICommand: "zone create/add/remove/list",
|
|
},
|
|
|
|
// System Features
|
|
{
|
|
Name: "Clock and Time",
|
|
Description: "Device clock settings and time display",
|
|
Endpoints: []string{"/clock"},
|
|
Category: "System",
|
|
Essential: false,
|
|
CLICommand: "clock get/set",
|
|
},
|
|
{
|
|
Name: "Power Management",
|
|
Description: "Device power state and standby control",
|
|
Endpoints: []string{"/powerManagement"},
|
|
Category: "System",
|
|
Essential: false,
|
|
CLICommand: "key power",
|
|
},
|
|
{
|
|
Name: "Bluetooth Connectivity",
|
|
Description: "Bluetooth pairing and device management",
|
|
Endpoints: []string{"/bluetoothInfo", "/bluetoothPair"},
|
|
Category: "Network",
|
|
Essential: false,
|
|
CLICommand: "source bluetooth",
|
|
},
|
|
{
|
|
Name: "AirPlay Support",
|
|
Description: "Apple AirPlay streaming capability",
|
|
Endpoints: []string{"/airplay"},
|
|
Category: "Network",
|
|
Essential: false,
|
|
CLICommand: "source select --source AIRPLAY",
|
|
},
|
|
}
|
|
}
|
|
|
|
// GetFeaturesByCategory returns features grouped by category
|
|
func (s *SupportedURLsResponse) GetFeaturesByCategory() map[string][]EndpointFeature {
|
|
features := GetEndpointFeatureMap()
|
|
result := make(map[string][]EndpointFeature)
|
|
|
|
for _, feature := range features {
|
|
// Check if device supports this feature (any of its endpoints)
|
|
supported := false
|
|
|
|
for _, endpoint := range feature.Endpoints {
|
|
if s.HasURL(endpoint) {
|
|
supported = true
|
|
break
|
|
}
|
|
}
|
|
|
|
if supported {
|
|
result[feature.Category] = append(result[feature.Category], feature)
|
|
}
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
// GetSupportedFeatures returns all features supported by this device
|
|
func (s *SupportedURLsResponse) GetSupportedFeatures() []EndpointFeature {
|
|
features := GetEndpointFeatureMap()
|
|
|
|
var supported []EndpointFeature
|
|
|
|
for _, feature := range features {
|
|
// Check if device supports this feature (any of its endpoints)
|
|
hasSupport := false
|
|
|
|
for _, endpoint := range feature.Endpoints {
|
|
if s.HasURL(endpoint) {
|
|
hasSupport = true
|
|
break
|
|
}
|
|
}
|
|
|
|
if hasSupport {
|
|
supported = append(supported, feature)
|
|
}
|
|
}
|
|
|
|
return supported
|
|
}
|
|
|
|
// GetUnsupportedFeatures returns features not supported by this device
|
|
func (s *SupportedURLsResponse) GetUnsupportedFeatures() []EndpointFeature {
|
|
features := GetEndpointFeatureMap()
|
|
|
|
var unsupported []EndpointFeature
|
|
|
|
for _, feature := range features {
|
|
// Check if device supports this feature (any of its endpoints)
|
|
hasSupport := false
|
|
|
|
for _, endpoint := range feature.Endpoints {
|
|
if s.HasURL(endpoint) {
|
|
hasSupport = true
|
|
break
|
|
}
|
|
}
|
|
|
|
if !hasSupport {
|
|
unsupported = append(unsupported, feature)
|
|
}
|
|
}
|
|
|
|
return unsupported
|
|
}
|
|
|
|
// GetPartiallyImplementedFeatures returns features where only some endpoints are supported
|
|
func (s *SupportedURLsResponse) GetPartiallyImplementedFeatures() []EndpointFeature {
|
|
features := GetEndpointFeatureMap()
|
|
|
|
var partial []EndpointFeature
|
|
|
|
for _, feature := range features {
|
|
if len(feature.Endpoints) <= 1 {
|
|
continue // Skip single-endpoint features
|
|
}
|
|
|
|
supportedCount := 0
|
|
|
|
for _, endpoint := range feature.Endpoints {
|
|
if s.HasURL(endpoint) {
|
|
supportedCount++
|
|
}
|
|
}
|
|
|
|
// Partially implemented if some but not all endpoints are supported
|
|
if supportedCount > 0 && supportedCount < len(feature.Endpoints) {
|
|
partial = append(partial, feature)
|
|
}
|
|
}
|
|
|
|
return partial
|
|
}
|
|
|
|
// GetMissingEssentialFeatures returns essential features that are not supported
|
|
func (s *SupportedURLsResponse) GetMissingEssentialFeatures() []EndpointFeature {
|
|
features := GetEndpointFeatureMap()
|
|
|
|
var missing []EndpointFeature
|
|
|
|
for _, feature := range features {
|
|
if !feature.Essential {
|
|
continue
|
|
}
|
|
|
|
// Check if device supports this essential feature
|
|
hasSupport := false
|
|
|
|
for _, endpoint := range feature.Endpoints {
|
|
if s.HasURL(endpoint) {
|
|
hasSupport = true
|
|
break
|
|
}
|
|
}
|
|
|
|
if !hasSupport {
|
|
missing = append(missing, feature)
|
|
}
|
|
}
|
|
|
|
return missing
|
|
}
|
|
|
|
// GetFeatureCompleteness returns a completeness score (0-100) based on supported features
|
|
func (s *SupportedURLsResponse) GetFeatureCompleteness() (int, int, int) {
|
|
features := GetEndpointFeatureMap()
|
|
|
|
var total, supported, essential int
|
|
|
|
for _, feature := range features {
|
|
total++
|
|
|
|
if feature.Essential {
|
|
essential++
|
|
}
|
|
|
|
// Check if device supports this feature
|
|
hasSupport := false
|
|
|
|
for _, endpoint := range feature.Endpoints {
|
|
if s.HasURL(endpoint) {
|
|
hasSupport = true
|
|
break
|
|
}
|
|
}
|
|
|
|
if hasSupport {
|
|
supported++
|
|
}
|
|
}
|
|
|
|
completeness := 0
|
|
if total > 0 {
|
|
completeness = (supported * 100) / total
|
|
}
|
|
|
|
return completeness, supported, total
|
|
}
|