mirror of
https://github.com/gesellix/Bose-SoundTouch.git
synced 2026-08-19 09:06:14 +00:00
✨ New Features: - Implement missing /supportedURLs endpoint with full XML parsing - Add comprehensive endpoint-to-feature mapping system (15+ features, 9 categories) - Create device capability analysis with personalized recommendations - Add intelligent device classification (Premium, Standard, Basic, Essential, Limited) 🔧 CLI Enhancements: - Add 'supported-urls' command with --features and --verbose flags - Add 'analyze' command for comprehensive device capability analysis - Add 'station list' command for saved station management - Add 'source availability' and 'source compare' commands - Enhanced service availability checking across all commands 📚 Models & API: - New SupportedURLsResponse model with rich helper methods - Enhanced ServiceAvailability model with validation utilities - New EndpointFeature mapping system with CLI command references - Feature completeness scoring and partial implementation detection 🧪 Testing: - 35+ new test cases covering all functionality - Comprehensive feature mapping validation tests - Service availability integration tests with real device scenarios - Mock server tests for error handling and edge cases 📖 Documentation: - New FEATURE-MAPPING-GUIDE.md with comprehensive usage examples - Updated API documentation with correct implementation status - CLI command reference organized by feature category - Device troubleshooting guide with capability checking 🎯 Key Capabilities: - Device feature coverage scoring (0-100%) - Essential vs optional feature classification - Personalized CLI command recommendations - Missing capability detection with usage impact analysis - Smart device type classification based on supported endpoints This resolves the documentation inconsistency where /supportedURLs was marked as implemented but was actually missing from the client. The new implementation goes far beyond basic endpoint listing to provide intelligent device capability analysis and personalized usage recommendations.
215 lines
5.8 KiB
Go
215 lines
5.8 KiB
Go
package models
|
|
|
|
import "encoding/xml"
|
|
|
|
// ServiceAvailability represents the response from /serviceAvailability endpoint
|
|
type ServiceAvailability struct {
|
|
XMLName xml.Name `xml:"serviceAvailability"`
|
|
Services *ServiceList `xml:"services"`
|
|
}
|
|
|
|
// ServiceList contains the list of available services
|
|
type ServiceList struct {
|
|
Service []Service `xml:"service"`
|
|
}
|
|
|
|
// Service represents an individual service availability status
|
|
type Service struct {
|
|
Type string `xml:"type,attr"`
|
|
IsAvailable bool `xml:"isAvailable,attr"`
|
|
Reason string `xml:"reason,attr,omitempty"`
|
|
}
|
|
|
|
// ServiceType represents known service types
|
|
type ServiceType string
|
|
|
|
const (
|
|
// ServiceTypeAirPlay represents Apple AirPlay streaming service
|
|
ServiceTypeAirPlay ServiceType = "AIRPLAY"
|
|
ServiceTypeAlexa ServiceType = "ALEXA"
|
|
ServiceTypeAmazon ServiceType = "AMAZON"
|
|
ServiceTypeBluetooth ServiceType = "BLUETOOTH"
|
|
ServiceTypeBMX ServiceType = "BMX"
|
|
ServiceTypeDeezer ServiceType = "DEEZER"
|
|
ServiceTypeIHeart ServiceType = "IHEART"
|
|
ServiceTypeLocalInternetRadio ServiceType = "LOCAL_INTERNET_RADIO"
|
|
ServiceTypeLocalMusic ServiceType = "LOCAL_MUSIC"
|
|
ServiceTypeNotification ServiceType = "NOTIFICATION"
|
|
ServiceTypePandora ServiceType = "PANDORA"
|
|
ServiceTypeSpotify ServiceType = "SPOTIFY"
|
|
ServiceTypeTuneIn ServiceType = "TUNEIN"
|
|
)
|
|
|
|
// GetReason returns the reason why a service is unavailable (if any)
|
|
func (s *Service) GetReason() string {
|
|
return s.Reason
|
|
}
|
|
|
|
// IsType checks if the service is of a specific type
|
|
func (s *Service) IsType(serviceType ServiceType) bool {
|
|
return s.Type == string(serviceType)
|
|
}
|
|
|
|
// GetAvailableServices returns only services that are available
|
|
func (sa *ServiceAvailability) GetAvailableServices() []Service {
|
|
if sa.Services == nil {
|
|
return []Service{}
|
|
}
|
|
|
|
var available []Service
|
|
for _, service := range sa.Services.Service {
|
|
if service.IsAvailable {
|
|
available = append(available, service)
|
|
}
|
|
}
|
|
return available
|
|
}
|
|
|
|
// GetUnavailableServices returns only services that are unavailable
|
|
func (sa *ServiceAvailability) GetUnavailableServices() []Service {
|
|
if sa.Services == nil {
|
|
return []Service{}
|
|
}
|
|
|
|
var unavailable []Service
|
|
for _, service := range sa.Services.Service {
|
|
if !service.IsAvailable {
|
|
unavailable = append(unavailable, service)
|
|
}
|
|
}
|
|
return unavailable
|
|
}
|
|
|
|
// IsServiceAvailable checks if a specific service type is available
|
|
func (sa *ServiceAvailability) IsServiceAvailable(serviceType ServiceType) bool {
|
|
if sa.Services == nil {
|
|
return false
|
|
}
|
|
|
|
for _, service := range sa.Services.Service {
|
|
if service.Type == string(serviceType) && service.IsAvailable {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
// GetServiceByType returns the service information for a specific type
|
|
func (sa *ServiceAvailability) GetServiceByType(serviceType ServiceType) *Service {
|
|
if sa.Services == nil {
|
|
return nil
|
|
}
|
|
|
|
for _, service := range sa.Services.Service {
|
|
if service.Type == string(serviceType) {
|
|
return &service
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// HasSpotify returns true if Spotify service is available
|
|
func (sa *ServiceAvailability) HasSpotify() bool {
|
|
return sa.IsServiceAvailable(ServiceTypeSpotify)
|
|
}
|
|
|
|
// HasAlexa returns true if Alexa service is available
|
|
func (sa *ServiceAvailability) HasAlexa() bool {
|
|
return sa.IsServiceAvailable(ServiceTypeAlexa)
|
|
}
|
|
|
|
// HasBluetooth returns true if Bluetooth service is available
|
|
func (sa *ServiceAvailability) HasBluetooth() bool {
|
|
return sa.IsServiceAvailable(ServiceTypeBluetooth)
|
|
}
|
|
|
|
// HasAirPlay returns true if AirPlay service is available
|
|
func (sa *ServiceAvailability) HasAirPlay() bool {
|
|
return sa.IsServiceAvailable(ServiceTypeAirPlay)
|
|
}
|
|
|
|
// HasTuneIn returns true if TuneIn service is available
|
|
func (sa *ServiceAvailability) HasTuneIn() bool {
|
|
return sa.IsServiceAvailable(ServiceTypeTuneIn)
|
|
}
|
|
|
|
// HasPandora returns true if Pandora service is available
|
|
func (sa *ServiceAvailability) HasPandora() bool {
|
|
return sa.IsServiceAvailable(ServiceTypePandora)
|
|
}
|
|
|
|
// HasLocalMusic returns true if Local Music service is available
|
|
func (sa *ServiceAvailability) HasLocalMusic() bool {
|
|
return sa.IsServiceAvailable(ServiceTypeLocalMusic)
|
|
}
|
|
|
|
// GetStreamingServices returns all streaming service types
|
|
func (sa *ServiceAvailability) GetStreamingServices() []Service {
|
|
if sa.Services == nil {
|
|
return []Service{}
|
|
}
|
|
|
|
streamingTypes := []ServiceType{
|
|
ServiceTypeSpotify,
|
|
ServiceTypePandora,
|
|
ServiceTypeTuneIn,
|
|
ServiceTypeAmazon,
|
|
ServiceTypeDeezer,
|
|
ServiceTypeIHeart,
|
|
ServiceTypeLocalInternetRadio,
|
|
}
|
|
|
|
var streaming []Service
|
|
for _, service := range sa.Services.Service {
|
|
for _, streamingType := range streamingTypes {
|
|
if service.Type == string(streamingType) {
|
|
streaming = append(streaming, service)
|
|
break
|
|
}
|
|
}
|
|
}
|
|
return streaming
|
|
}
|
|
|
|
// GetLocalServices returns all local service types
|
|
func (sa *ServiceAvailability) GetLocalServices() []Service {
|
|
if sa.Services == nil {
|
|
return []Service{}
|
|
}
|
|
|
|
localTypes := []ServiceType{
|
|
ServiceTypeBluetooth,
|
|
ServiceTypeAirPlay,
|
|
ServiceTypeLocalMusic,
|
|
}
|
|
|
|
var local []Service
|
|
for _, service := range sa.Services.Service {
|
|
for _, localType := range localTypes {
|
|
if service.Type == string(localType) {
|
|
local = append(local, service)
|
|
break
|
|
}
|
|
}
|
|
}
|
|
return local
|
|
}
|
|
|
|
// GetServiceCount returns the total number of services
|
|
func (sa *ServiceAvailability) GetServiceCount() int {
|
|
if sa.Services == nil {
|
|
return 0
|
|
}
|
|
return len(sa.Services.Service)
|
|
}
|
|
|
|
// GetAvailableServiceCount returns the number of available services
|
|
func (sa *ServiceAvailability) GetAvailableServiceCount() int {
|
|
return len(sa.GetAvailableServices())
|
|
}
|
|
|
|
// GetUnavailableServiceCount returns the number of unavailable services
|
|
func (sa *ServiceAvailability) GetUnavailableServiceCount() int {
|
|
return len(sa.GetUnavailableServices())
|
|
}
|