mirror of
https://github.com/gesellix/Bose-SoundTouch.git
synced 2026-08-18 16:46:17 +00:00
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.
180 lines
4.9 KiB
Go
180 lines
4.9 KiB
Go
// Package main demonstrates introspect functionality for Bose SoundTouch devices.
|
|
package main
|
|
|
|
import (
|
|
"flag"
|
|
"fmt"
|
|
"log"
|
|
"time"
|
|
|
|
"github.com/gesellix/bose-soundtouch/pkg/client"
|
|
"github.com/gesellix/bose-soundtouch/pkg/models"
|
|
)
|
|
|
|
// displayBasicInfo prints basic service information
|
|
func displayBasicInfo(source string, response *models.IntrospectResponse) {
|
|
fmt.Printf("\n=== %s Service Introspect Data ===\n", source)
|
|
fmt.Printf("State: %s\n", response.State)
|
|
|
|
if response.HasUser() {
|
|
fmt.Printf("User: %s\n", response.User)
|
|
}
|
|
|
|
fmt.Printf("Currently Playing: %t\n", response.IsPlaying)
|
|
|
|
if response.HasCurrentContent() {
|
|
fmt.Printf("Current Content: %s\n", response.CurrentURI)
|
|
}
|
|
|
|
fmt.Printf("Shuffle Mode: %s\n", response.ShuffleMode)
|
|
|
|
if response.HasSubscription() {
|
|
fmt.Printf("Subscription Type: %s\n", response.SubscriptionType)
|
|
}
|
|
}
|
|
|
|
// displayServiceState prints service state information
|
|
func displayServiceState(response *models.IntrospectResponse) {
|
|
fmt.Printf("\n=== Service State ===\n")
|
|
|
|
if response.IsActive() {
|
|
fmt.Println("✅ Service is ACTIVE")
|
|
} else if response.IsInactive() {
|
|
fmt.Println("❌ Service is INACTIVE")
|
|
}
|
|
}
|
|
|
|
// displayCapabilities prints service capabilities
|
|
func displayCapabilities(response *models.IntrospectResponse) {
|
|
fmt.Printf("\n=== Service Capabilities ===\n")
|
|
|
|
if response.SupportsSkipPrevious() {
|
|
fmt.Println("✅ Skip Previous supported")
|
|
} else {
|
|
fmt.Println("❌ Skip Previous not supported")
|
|
}
|
|
|
|
if response.SupportsSeek() {
|
|
fmt.Println("✅ Seek supported")
|
|
} else {
|
|
fmt.Println("❌ Seek not supported")
|
|
}
|
|
|
|
if response.SupportsResume() {
|
|
fmt.Println("✅ Resume supported")
|
|
} else {
|
|
fmt.Println("❌ Resume not supported")
|
|
}
|
|
|
|
if response.CollectsData() {
|
|
fmt.Println("📊 Data collection enabled")
|
|
} else {
|
|
fmt.Println("🚫 Data collection disabled")
|
|
}
|
|
}
|
|
|
|
// displayHistoryInfo prints content history information
|
|
func displayHistoryInfo(response *models.IntrospectResponse) {
|
|
historySize := response.GetMaxHistorySize()
|
|
if historySize > 0 {
|
|
fmt.Printf("\n=== Content History ===\n")
|
|
fmt.Printf("Max History Size: %d items\n", historySize)
|
|
}
|
|
}
|
|
|
|
// displayTechnicalDetails prints technical service details
|
|
func displayTechnicalDetails(response *models.IntrospectResponse) {
|
|
if response.TokenLastChangedTimeSeconds > 0 {
|
|
fmt.Printf("\n=== Technical Details ===\n")
|
|
fmt.Printf("Token Last Changed: %d seconds\n", response.TokenLastChangedTimeSeconds)
|
|
|
|
if response.TokenLastChangedTimeMicroseconds > 0 {
|
|
fmt.Printf("Token Microseconds: %d\n", response.TokenLastChangedTimeMicroseconds)
|
|
}
|
|
|
|
fmt.Printf("Play Status State: %s\n", response.PlayStatusState)
|
|
fmt.Printf("Received Playback Request: %t\n", response.ReceivedPlaybackRequest)
|
|
}
|
|
}
|
|
|
|
// displayServiceAvailability shows service availability for comparison
|
|
func displayServiceAvailability(soundTouchClient *client.Client, source string) {
|
|
fmt.Printf("\n=== Service Availability Check ===\n")
|
|
|
|
availability, err := soundTouchClient.GetServiceAvailability()
|
|
if err != nil {
|
|
fmt.Printf("Could not check service availability: %v\n", err)
|
|
return
|
|
}
|
|
|
|
switch source {
|
|
case "SPOTIFY":
|
|
if availability.HasSpotify() {
|
|
fmt.Println("✅ Spotify is available on this device")
|
|
} else {
|
|
fmt.Println("❌ Spotify is not available on this device")
|
|
}
|
|
case "PANDORA":
|
|
if availability.HasPandora() {
|
|
fmt.Println("✅ Pandora is available on this device")
|
|
} else {
|
|
fmt.Println("❌ Pandora is not available on this device")
|
|
}
|
|
case "TUNEIN":
|
|
if availability.HasTuneIn() {
|
|
fmt.Println("✅ TuneIn is available on this device")
|
|
} else {
|
|
fmt.Println("❌ TuneIn is not available on this device")
|
|
}
|
|
default:
|
|
fmt.Printf("Service availability check not implemented for %s\n", source)
|
|
}
|
|
}
|
|
|
|
func main() {
|
|
var (
|
|
host = flag.String("host", "", "SoundTouch device IP address")
|
|
source = flag.String("source", "SPOTIFY", "Music service source (SPOTIFY, PANDORA, TUNEIN)")
|
|
sourceAccount = flag.String("account", "", "Source account name (optional)")
|
|
timeout = flag.Duration("timeout", 10*time.Second, "Request timeout")
|
|
)
|
|
|
|
flag.Parse()
|
|
|
|
if *host == "" {
|
|
log.Fatal("Please provide a SoundTouch device IP address with -host flag")
|
|
}
|
|
|
|
// Create client
|
|
config := &client.Config{
|
|
Host: *host,
|
|
Port: 8090,
|
|
Timeout: *timeout,
|
|
}
|
|
soundTouchClient := client.NewClient(config)
|
|
|
|
fmt.Printf("Getting introspect data for %s", *source)
|
|
|
|
if *sourceAccount != "" {
|
|
fmt.Printf(" (account: %s)", *sourceAccount)
|
|
}
|
|
|
|
fmt.Println()
|
|
|
|
// Get introspect data
|
|
response, err := soundTouchClient.Introspect(*source, *sourceAccount)
|
|
if err != nil {
|
|
log.Fatalf("Failed to get introspect data: %v", err)
|
|
}
|
|
|
|
// Display all information using helper functions
|
|
displayBasicInfo(*source, response)
|
|
displayServiceState(response)
|
|
displayCapabilities(response)
|
|
displayHistoryInfo(response)
|
|
displayTechnicalDetails(response)
|
|
displayServiceAvailability(soundTouchClient, *source)
|
|
|
|
fmt.Println("\nDone!")
|
|
}
|