mirror of
https://github.com/gesellix/Bose-SoundTouch.git
synced 2026-08-18 16:46:17 +00:00
- Used 'golangci-lint run --fix' to automatically resolve formatting issues - Fixed all 52 remaining wsl_v5 (whitespace) issues automatically - Applied go fmt to ensure consistent formatting across codebase - Touched 49 files with automatic formatting improvements MAJOR PROGRESS: Reduced total issues from 79 to 27 (66% reduction!) Remaining issues: - gocyclo: 14 (complexity - requires manual refactoring) - revive: 5 (style/naming) - staticcheck: 5 (static analysis) - unparam: 3 (unused parameters)
178 lines
4.4 KiB
Go
178 lines
4.4 KiB
Go
// Package models provides data structures and types for the Bose SoundTouch API.
|
|
package models
|
|
|
|
import (
|
|
"encoding/xml"
|
|
"fmt"
|
|
)
|
|
|
|
// Balance represents the response from /balance endpoint
|
|
type Balance struct {
|
|
XMLName xml.Name `xml:"balance"`
|
|
DeviceID string `xml:"deviceID,attr"`
|
|
TargetBalance int `xml:"targetbalance"`
|
|
ActualBalance int `xml:"actualbalance"`
|
|
}
|
|
|
|
// BalanceRequest represents the request for POST /balance endpoint
|
|
type BalanceRequest struct {
|
|
XMLName xml.Name `xml:"balance"`
|
|
Level int `xml:",chardata"`
|
|
}
|
|
|
|
// Balance level constants
|
|
const (
|
|
BalanceLevelMin = -50
|
|
BalanceLevelMax = 50
|
|
BalanceLevelDefault = 0
|
|
)
|
|
|
|
// NewBalanceRequest creates a new balance request with validation
|
|
func NewBalanceRequest(level int) (*BalanceRequest, error) {
|
|
if !ValidateBalanceLevel(level) {
|
|
return nil, fmt.Errorf("invalid balance level: %d (must be between %d and %d)", level, BalanceLevelMin, BalanceLevelMax)
|
|
}
|
|
|
|
return &BalanceRequest{
|
|
Level: level,
|
|
}, nil
|
|
}
|
|
|
|
// ValidateBalanceLevel validates that a balance level is within the allowed range
|
|
func ValidateBalanceLevel(level int) bool {
|
|
return level >= BalanceLevelMin && level <= BalanceLevelMax
|
|
}
|
|
|
|
// ClampBalanceLevel clamps a balance level to the valid range
|
|
func ClampBalanceLevel(level int) int {
|
|
if level < BalanceLevelMin {
|
|
return BalanceLevelMin
|
|
}
|
|
|
|
if level > BalanceLevelMax {
|
|
return BalanceLevelMax
|
|
}
|
|
|
|
return level
|
|
}
|
|
|
|
// GetLevel returns the target balance level
|
|
func (b *Balance) GetLevel() int {
|
|
return b.TargetBalance
|
|
}
|
|
|
|
// GetActualLevel returns the actual balance level
|
|
func (b *Balance) GetActualLevel() int {
|
|
return b.ActualBalance
|
|
}
|
|
|
|
// IsAtTarget returns true if actual balance matches target balance
|
|
func (b *Balance) IsAtTarget() bool {
|
|
return b.TargetBalance == b.ActualBalance
|
|
}
|
|
|
|
// GetBalanceLevelName returns a descriptive name for the balance level
|
|
func GetBalanceLevelName(level int) string {
|
|
switch {
|
|
case level < -30:
|
|
return "Far Left"
|
|
case level < -10:
|
|
return "Left"
|
|
case level < 0:
|
|
return "Slightly Left"
|
|
case level == 0:
|
|
return "Center"
|
|
case level <= 10:
|
|
return "Slightly Right"
|
|
case level <= 30:
|
|
return "Right"
|
|
default:
|
|
return "Far Right"
|
|
}
|
|
}
|
|
|
|
// GetBalanceLevelCategory returns the balance category
|
|
func GetBalanceLevelCategory(level int) string {
|
|
switch {
|
|
case level < 0:
|
|
return "Left Channel"
|
|
case level == 0:
|
|
return "Balanced"
|
|
default:
|
|
return "Right Channel"
|
|
}
|
|
}
|
|
|
|
// String returns a human-readable string representation
|
|
func (b *Balance) String() string {
|
|
return fmt.Sprintf("Balance: %d (%s)", b.GetLevel(), GetBalanceLevelName(b.GetLevel()))
|
|
}
|
|
|
|
// UnmarshalXML implements custom XML unmarshaling with validation
|
|
func (b *Balance) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
|
|
// Use a temporary struct to avoid infinite recursion
|
|
type TempBalance Balance
|
|
|
|
temp := (*TempBalance)(b)
|
|
|
|
if err := d.DecodeElement(temp, &start); err != nil {
|
|
return err
|
|
}
|
|
|
|
// Validate balance levels are within acceptable range
|
|
if !ValidateBalanceLevel(b.TargetBalance) {
|
|
return fmt.Errorf("invalid target balance level: %d", b.TargetBalance)
|
|
}
|
|
|
|
if !ValidateBalanceLevel(b.ActualBalance) {
|
|
return fmt.Errorf("invalid actual balance level: %d", b.ActualBalance)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// MarshalXML implements custom XML marshaling
|
|
func (b *Balance) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
|
|
type TempBalance Balance
|
|
|
|
temp := (*TempBalance)(b)
|
|
|
|
return e.EncodeElement(temp, start)
|
|
}
|
|
|
|
// IsLeftBalance returns true if balance favors left channel (negative level)
|
|
func (b *Balance) IsLeftBalance() bool {
|
|
return b.GetLevel() < 0
|
|
}
|
|
|
|
// IsRightBalance returns true if balance favors right channel (positive level)
|
|
func (b *Balance) IsRightBalance() bool {
|
|
return b.GetLevel() > 0
|
|
}
|
|
|
|
// IsBalanced returns true if balance is centered (zero level)
|
|
func (b *Balance) IsBalanced() bool {
|
|
return b.GetLevel() == 0
|
|
}
|
|
|
|
// GetBalanceChangeNeeded returns the amount of change needed to reach target from actual
|
|
func (b *Balance) GetBalanceChangeNeeded() int {
|
|
return b.TargetBalance - b.ActualBalance
|
|
}
|
|
|
|
// GetLeftRightPercentage returns the balance as left/right percentages
|
|
func (b *Balance) GetLeftRightPercentage() (left, right int) {
|
|
level := b.GetLevel()
|
|
if level <= 0 {
|
|
// Left emphasis or center
|
|
left = 50 + (-level / 2)
|
|
right = 50 - (-level / 2)
|
|
} else {
|
|
// Right emphasis
|
|
left = 50 - (level / 2)
|
|
right = 50 + (level / 2)
|
|
}
|
|
|
|
return left, right
|
|
}
|