Files
Bose-SoundTouch/pkg/models/account.go
T
Tobias Gesellchen 285f85efa2 feat: implement comprehensive music service account management with full golangci-lint compliance
This commit completes the music service account management implementation
and resolves all golangci-lint issues across the codebase.

Music Service Account Management:
• Add/remove accounts for all major streaming services (Spotify, Pandora, Amazon Music, Deezer, iHeartRadio)
• Support for network music libraries (NAS/UPnP/DLNA servers)
• Generic account management with service-specific convenience methods
• Full CLI integration with 14 account management commands
• Comprehensive test coverage with mock HTTP servers
• Complete API documentation and usage examples

New CLI Commands:
• account list - List configured accounts
• account add/remove - Generic account management
• account add-spotify/remove-spotify - Spotify Premium
• account add-pandora/remove-pandora - Pandora Music Service
• account add-amazon/remove-amazon - Amazon Music
• account add-deezer/remove-deezer - Deezer Premium
• account add-iheart/remove-iheart - iHeartRadio
• account add-nas/remove-nas - Network music libraries

New API Methods:
• SetMusicServiceAccount() / RemoveMusicServiceAccount() - Generic methods
• AddSpotifyAccount() / RemoveSpotifyAccount() - Convenience methods
• AddPandoraAccount() / RemovePandoraAccount() - Convenience methods
• AddAmazonMusicAccount() / RemoveAmazonMusicAccount() - Convenience methods
• AddDeezerAccount() / RemoveDeezerAccount() - Convenience methods
• AddIHeartRadioAccount() / RemoveIHeartRadioAccount() - Convenience methods
• AddStoredMusicAccount() / RemoveStoredMusicAccount() - Network libraries

golangci-lint Fixes (36 issues resolved):
• errcheck (3): Fixed unchecked w.Write() returns in tests
• gocritic (3): Rewrote if-else chains to switch statements
• gocyclo (6): Reduced cyclomatic complexity via helper function extraction
• govet (12): Removed unused test data and field assignments
• revive (6): Added package comments and fixed unused parameters
• staticcheck (2): Replaced deprecated strings.Title usage
• thelper (6): Added t.Helper() calls to test helper functions
• unused (1): Removed unused createTestApp() function
• whitespace/wsl_v5 (7): Fixed whitespace and formatting issues

Code Quality Improvements:
• All functions now have complexity < 15 (down from max 28)
• Consistent error handling and validation patterns
• Better separation of concerns with extracted helper functions
• Zero external dependencies added for simple fixes
• Comprehensive documentation with usage examples
• Full backward compatibility maintained

Files Added:
• pkg/models/account.go - Account management models
• pkg/models/account_test.go - Account model tests
• pkg/client/account_test.go - Account client tests
• cmd/soundtouch-cli/cmd_account.go - Account CLI commands
• examples/account-management/ - Complete usage example
• Updated docs/CLI-REFERENCE.md with account management section

The implementation provides a complete, production-ready music service
account management system with full CLI and programmatic API support.
2026-02-02 17:44:26 +01:00

123 lines
3.9 KiB
Go

// Package models provides data structures and types for music service account management
// on Bose SoundTouch devices.
package models
import (
"encoding/xml"
"fmt"
)
// MusicServiceCredentials represents credentials for music service account operations
type MusicServiceCredentials struct {
XMLName xml.Name `xml:"credentials"`
Source string `xml:"source,attr"`
DisplayName string `xml:"displayName,attr,omitempty"`
User string `xml:"user"`
Pass string `xml:"pass"`
}
// NewMusicServiceCredentials creates new music service credentials
func NewMusicServiceCredentials(source, displayName, user, pass string) *MusicServiceCredentials {
return &MusicServiceCredentials{
Source: source,
DisplayName: displayName,
User: user,
Pass: pass,
}
}
// NewSpotifyCredentials creates credentials for Spotify service
func NewSpotifyCredentials(user, pass string) *MusicServiceCredentials {
return NewMusicServiceCredentials("SPOTIFY", "Spotify Premium", user, pass)
}
// NewPandoraCredentials creates credentials for Pandora service
func NewPandoraCredentials(user, pass string) *MusicServiceCredentials {
return NewMusicServiceCredentials("PANDORA", "Pandora Music Service", user, pass)
}
// NewStoredMusicCredentials creates credentials for STORED_MUSIC (NAS/UPnP) service
func NewStoredMusicCredentials(user, displayName string) *MusicServiceCredentials {
return NewMusicServiceCredentials("STORED_MUSIC", displayName, user, "")
}
// NewAmazonMusicCredentials creates credentials for Amazon Music service
func NewAmazonMusicCredentials(user, pass string) *MusicServiceCredentials {
return NewMusicServiceCredentials("AMAZON", "Amazon Music", user, pass)
}
// NewDeezerCredentials creates credentials for Deezer service
func NewDeezerCredentials(user, pass string) *MusicServiceCredentials {
return NewMusicServiceCredentials("DEEZER", "Deezer Premium", user, pass)
}
// NewIHeartRadioCredentials creates credentials for iHeartRadio service
func NewIHeartRadioCredentials(user, pass string) *MusicServiceCredentials {
return NewMusicServiceCredentials("IHEART", "iHeartRadio", user, pass)
}
// Validate ensures the credentials have required fields
func (cred *MusicServiceCredentials) Validate() error {
if cred.Source == "" {
return fmt.Errorf("source cannot be empty")
}
if cred.User == "" {
return fmt.Errorf("user cannot be empty")
}
// STORED_MUSIC typically doesn't require a password
if cred.Source != "STORED_MUSIC" && cred.Pass == "" {
return fmt.Errorf("password cannot be empty for %s", cred.Source)
}
return nil
}
// IsForRemoval returns true if these credentials are for removing an account (empty password)
func (cred *MusicServiceCredentials) IsForRemoval() bool {
return cred.Pass == ""
}
// HasPassword returns true if credentials include a password
func (cred *MusicServiceCredentials) HasPassword() bool {
return cred.Pass != ""
}
// GetDescription returns a human-readable description of the service
func (cred *MusicServiceCredentials) GetDescription() string {
if cred.DisplayName != "" {
return cred.DisplayName
}
switch cred.Source {
case "SPOTIFY":
return "Spotify Premium"
case "PANDORA":
return "Pandora Music Service"
case "AMAZON":
return "Amazon Music"
case "DEEZER":
return "Deezer Premium"
case "IHEART":
return "iHeartRadio"
case "STORED_MUSIC":
return "Network Music Library"
case "LOCAL_MUSIC":
return "Local Music Server"
default:
return cred.Source
}
}
// MusicServiceAccountResponse represents the response from account management operations
type MusicServiceAccountResponse struct {
XMLName xml.Name `xml:"status"`
Status string `xml:",chardata"`
}
// IsSuccess returns true if the account operation was successful
func (resp *MusicServiceAccountResponse) IsSuccess() bool {
return resp.Status == "/setMusicServiceAccount" || resp.Status == "/removeMusicServiceAccount"
}