Major improvements to device discovery system:
🔧 **SSDP Discovery Fixed**:
- Fixed networking issue where SSDP used connected UDP socket instead of UDP listener
- SSDP now properly receives unicast responses from multicast requests
- UPnP discovery now works reliably and finds all MediaRenderer devices
✨ **Enhanced DiscoveredDevice Model**:
- Added consistent URL fields (APIBaseURL, InfoURL) for all discovery methods
- Added protocol-specific fields (UPnPLocation, UPnPUSN, MDNSHostname, etc.)
- Added DiscoveryMethod tracking to show how devices were found
- Added device merging support for same device found via multiple protocols
🚀 **Unified Discovery Improvements**:
- Fixed device merging logic to properly combine protocol-specific data
- Discovery methods now correctly show combinations like 'Configuration+SSDP/UPnP+mDNS/Bonjour'
- Removed duplicate configuration device loading in individual services
- All three discovery methods (SSDP, mDNS, Configuration) work together seamlessly
🛠 **Updated Tools & Examples**:
- Updated soundtouch-cli to display new consistent field structure
- Enhanced all example programs with better device information display
- Added new unified discovery example demonstrating all three methods
- Fixed context timeout issues in example programs
📋 **Comprehensive Testing**:
- All tests updated and passing
- Real-world validation with actual Bose SoundTouch devices
- Confirmed discovery methods properly merge device data
Every discovered device now has consistent http://host:port/info URLs regardless
of discovery method, while preserving valuable protocol-specific metadata.
- Force IPv4-only mDNS queries with DisableIPv6=true to avoid routing issues
- Add automatic IPv4 interface selection for better compatibility
- Filter mDNS results to only include SoundTouch devices
- Clean up device names by unescaping mDNS characters
- Fix timeout flag handling to respect DISCOVERY_TIMEOUT from .env file
- Only override discovery timeout when --timeout flag is explicitly provided
- Add file operations safety guidelines to docs/CLAUDE.md
- Remove duplicate timeout flags from discover command, use global flags
Fixes IPv6 'no route to host' errors that prevented mDNS discovery.
Now discovers same devices as native dns-sd and dig tools.
This document outlines the Contributor Covenant Code of Conduct, detailing our pledge, standards, enforcement responsibilities, and guidelines for community behavior.
- Simplify section headers to standard markdown format
- Remove emojis and special characters that break anchor generation
- Update table of contents links to match simplified headers
- Fix ampersand and special character encoding issues in anchors
- All internal links now work with GitHub's automatic anchor generation
Completes documentation link fixes for CI
- Simplify section headers to use standard markdown format
- Remove complex emojis and special characters that break anchor generation
- Update table of contents links to match simplified headers
- Fix 'Volume & Audio' section title with ampersand that caused encoding issues
- All internal links now work properly with GitHub's automatic anchor generation
Resolves failing CI documentation check
- Change '// Output:' to '// Example output:' in all examples
- Examples will still appear in pkg.go.dev documentation
- Prevents examples from running as tests and trying to connect to real devices
- Examples are for documentation purposes, not runtime testing
- Fix GetInfo() to GetDeviceInfo() in client examples
- Update discovery examples to use proper constructor patterns
- Fix Volume.Muted to Volume.MuteEnabled field reference
- Correct DiscoveredDevice field names (remove non-existent MACAddress)
- Fix ZoneMember to use IP field instead of IPAddress
- Update Presets examples to use Preset slice and proper methods
- Replace non-existent SubscribeToEvents with NewWebSocketClient pattern
- Fix Capabilities to use Capability field instead of Sources
- Remove duplicate example function names
- Ensure all examples compile and use correct API surface
- Add root package documentation with quick start guide and feature overview
- Enhance client package with detailed usage examples and API coverage
- Add comprehensive discovery package documentation with protocol explanations
- Create models package documentation explaining all data structures
- Add extensive example functions for all major use cases:
* Basic device control and playback
* Volume, bass, and balance management
* Source selection and preset handling
* Multiroom zone management
* Real-time WebSocket event monitoring
* Device discovery with UPnP and mDNS
* Error handling and context cancellation
- Include code examples for pkg.go.dev's example rendering
- Document API endpoints, data structures, and best practices
- Add hardware compatibility and implementation notes
- Replace hardcoded version with build-time injected variables
- Add version, commit, and date variables to main.go with default values
- Update Makefile ldflags to use consistent variable names
- Add detailed 'version' subcommand showing build info, Go version, and platform
- Maintain compatibility with existing release workflow
- Support both --version flag (simple) and version subcommand (detailed)
- Use dedicated collection directory to avoid naming conflicts
- Simplify file movement logic by using release-files directory
- Update artifact upload paths to match new structure
- Resolves mv errors when files have same names as directories
Add ls -la output for:
- Working directory before/after build
- Go build cache location and contents
- Go module cache contents
- Post-build state verification
Simple directory listings often reveal file permission issues,
cached artifacts, or leftover files that cause 'File exists' errors
better than complex debugging output.
- Clean build environment before building (remove existing files, clean cache)
- Add atomic checksum generation using temp directory
- Improve error handling with explicit build failure detection
- Add debugging output to diagnose 'File exists' errors
- Use basename in temp operations to avoid path issues
This should resolve the 'Cannot open: File exists' errors occurring
during the darwin/arm64 build process.
Use find -mindepth 2 to only move files from subdirectories, avoiding
the 'mv: cannot overwrite directory' error when flattening the artifact
directory structure. This ensures only the actual binary and checksum
files are moved, not the directories themselves.
Fixes the sha256sum failure in the Generate Checksums workflow step.
- Generate individual SHA256/SHA512 checksums for each binary in matrix jobs
- Maintain combined checksums.sha256/checksums.sha512 files for all binaries
- Upload both types to release assets for maximum user flexibility
- Update release notes with examples for both verification methods
- Filter binary lists to exclude checksum files from combined checksums
Users can now choose between:
- Combined checksums (checksums.sha256) with --ignore-missing flag
- Individual checksums (per-binary .sha256 files) for simpler verification
This provides the best of both approaches for different user preferences.
- Each build job uploads artifact with unique name (binary filename)
- Checksums job downloads all artifacts and flattens structure
- Use 'find . -type f' to only move files, avoiding directory conflicts
- Add debugging output to troubleshoot artifact structure
Fixes 'artifact with this name already exists' error that was
preventing multiple build jobs from uploading simultaneously.
- Upload all binaries to single 'binaries' artifact instead of separate artifacts
- Remove complex directory flattening logic that was causing mv errors
- Add better error handling and debugging output for checksum generation
- Simplify artifact download process
Fixes the 'mv: cannot overwrite directory' errors that were causing
the Generate Checksums step to fail during release builds.
- Remove push:tags trigger that duplicated release:published trigger
- Keep workflow_dispatch for manual releases
- Simplify conditional logic for release creation
- Fix tag name resolution for different event types
- Ensure single workflow run per release creation
Resolves double-triggering issue where GitHub web UI release
creation would trigger both push:tags and release:published events.
- Reference original API documentation source from Bose Corporation
- Link to official Bose SoundTouch End-of-Life page
- Clarify this is an independent implementation
- Add disclaimer about non-affiliation with Bose Corporation
- Provide both online and local documentation references
- Move --host, --port, and --timeout from individual commands to global app level
- Enables cleaner syntax: 'soundtouch-cli --host 192.168.1.10 volume get'
- Consistent with Docker, kubectl, and other CLI tools that use global connection flags
- Environment variables (SOUNDTOUCH_HOST, SOUNDTOUCH_PORT) work seamlessly
- Remove repetitive CommonFlags from all individual commands
- Maintains backward compatibility - all functionality works exactly the same
- Discovery commands ignore host flag when not needed
BREAKING: CLI syntax improved from 'volume --host IP get' to '--host IP volume get'
- Update README.md CLI examples from old flag-based format to current subcommand structure
- Fix GETTING-STARTED.md CLI examples to use proper syntax
- Add comprehensive CLI-REFERENCE.md with complete command documentation
- All examples now use correct format: soundtouch-cli --host <device> <command> <subcommand>
- Document all available commands: discover, info, play, volume, source, bass, balance, clock, network, zone
- Include usage patterns, examples, and troubleshooting guidance
- Replace outdated flat flag format (-info, -volume) with hierarchical commands (info, volume get)
Breaking: CLI syntax has changed from flags to subcommands for better organization
- Use net.SplitHostPort instead of simple string splitting to properly handle IPv6 addresses like [::1]:8090
- Add port range validation (1-65535)
- Return extracted host instead of full hostPort string on parse errors
- Add net import for SplitHostPort function
- Fixes all failing tests in cmd/soundtouch-cli package
- Fix range copy issues in cmd_network.go (use indexing instead of copying 168-byte structs)
- Rename DiscoveryService to Service to avoid package name stuttering
- Update all references to use new Service constructor names
- Apply automatic whitespace fixes using golangci-lint --fix
- Reduce linting issues from 32 to 7 (only cyclomatic complexity remains)
Remaining issues are architectural complexity violations that require manual refactoring.
- Added urfave/cli/v2 dependency for better CLI structure
- Created modular command structure with separate files:
- common.go: Shared utilities and client setup
- cmd_discover.go: Device discovery commands
- cmd_info.go: Device information commands
- cmd_volume.go: Volume control commands
- cmd_playback.go: Playback control commands
- cmd_source.go: Source selection commands
- Replaced giant main() function (complexity 149) with organized subcommands
- Added proper flag handling and validation
- Improved help text and user experience
WIP: Some issues remain (flag conflicts, missing commands)
Next: Complete remaining commands and fix conflicts
- Removed unused result parameter from internal post() method
- Updated all 18 callers to remove nil result parameter
- Deleted unused XML unmarshaling logic for POST responses
- Simplified method signature from post(endpoint, payload, result) to post(endpoint, payload)
Since all callers passed nil for result parameter, this simplifies the API
without breaking any functionality. POST operations in this API don't
return data that needs unmarshaling.
Progress: Resolved final unparam issue
Total issues: 16 → 15 (6% improvement)
Remaining:
- gocyclo: 14 (high function complexity)
- revive: 1 (DiscoveryService naming)
- Fixed nil pointer dereference warnings by using t.Fatal instead of t.Error
- In unified_test.go: Changed service nil check to use t.Fatal
- In clockdisplay_test.go: Changed request nil check to use t.Fatal
Using t.Fatal ensures test execution stops if pointer is nil,
eliminating possibility of subsequent nil pointer dereference.
Progress: Eliminated all 5 staticcheck issues
Total issues: 21 → 16 (24% improvement)
Remaining:
- gocyclo: 14 (complexity - requires refactoring)
- revive: 1 (DiscoveryService naming)
- unparam: 1 (client.post result parameter)
- Added defaultSoundTouchPort constant (8090) to client.go
- Updated parseBassHostPort and parseHostPort test utility functions to use constant
- Removed unnecessary defaultPort parameters that always received 8090
- Fixed function signatures and all call sites in integration tests
Progress: Reduced unparam issues from 3 to 1 (only client.go post method remains)
Total issues: 23 → 21 (9% improvement)
Remaining:
- gocyclo: 14 (complexity)
- revive: 1 (DiscoveryService naming)
- staticcheck: 5
- unparam: 1 (client.post result parameter - kept for future extensibility)
- Fix whitespace issues in test files (bass_test.go, client_test.go, source_selection_test.go)
- Fix whitespace issues in discovery/mdns.go
- Fix whitespace issues in config/config_test.go
- Fix whitespace issues in soundtouch-cli main.go ranges and loops
- Fix whitespace issues in models/websocket_test.go
Progress: Reduced wsl_v5 issues from 50 to 45 (10% improvement)
Total remaining: 79 issues (down from 84)
- Fix all errcheck issues by properly checking error return values
- Fix gocritic exitAfterDefer issues by replacing log.Fatalf with return statements
- Fix rangeValCopy issues by using index-based iteration for large structs
- Add missing package comments for all packages
- Fix unused parameter issues by renaming to underscore
- Fix empty block issues by adding explicit error handling
- Add documentation for exported methods and constants
- Fix shadow variable issues
- Replace deprecated strings.Title with manual implementation
- Fix defer function error handling
Reduced lint issues from 108 to 84 (22% improvement)
All critical error handling and code quality issues resolved
- Fix bodyclose issues by properly closing WebSocket response body
- Fix errcheck issues by checking errors on resp.Body.Close(), conn.Close(), etc.
- Fix errorlint issue by using errors.As() instead of type assertion
- Fix nilerr issue by adding proper logging for UPnP discovery failures
- Fix gocritic issues:
- Convert if-else chains to switch statements
- Fix parameter type combining (paramTypeCombine)
- Fix range value copying (rangeValCopy)
- Fix exitAfterDefer by calling cancel() before log.Fatalf()
- Add package comments to fix revive package-comments issues
- Rename ClientConfig to Config to avoid type name stuttering
- Add missing exported constant comments
- Fix unused parameter issues by renaming to _
- Fix empty block issues
- Add t.Helper() to test helper functions
- Update User-Agent and fix GetNetworkSummary behavior to match test expectations
Reduces linting issues from 151 to 108 (28% improvement).
All tests now pass.
- Replace gosec with govulncheck (official Go vulnerability scanner)
- Add dedicated security.yml workflow with multiple tools:
- govulncheck: Official Go team vulnerability scanner
- Nancy: Sonatype dependency vulnerability scanner
- Staticcheck: Go static analysis with security checks
- Semgrep: Multi-language security scanner
- CodeQL: GitHub semantic security analysis
- Dependency Review: Automated dependency vulnerability checking
- Update golangci-lint config to temporarily disable gosec
- Add CodeQL configuration for enhanced Go security analysis
- Separate fast CI checks from comprehensive security scanning
- Schedule daily security scans at 2 AM UTC
- Integrate with GitHub Security tab via SARIF reports
- Remove securecodewarrior/github-action-gosec@master (repository not found)
- Install gosec directly using go install
- Run gosec ./... command directly instead of through action
- This provides the same security scanning functionality with better reliability
Fixes the security scan job failure due to missing third-party action.
- Use client.NewClientFromHost instead of non-existent client.New
- Use models.DeviceInfo instead of non-existent models.Info
- Use discovery.UnifiedDiscoveryService instead of non-existent discovery.Scanner
- Use config.DefaultConfig instead of non-existent config.NewConfig
- Add config package import for discovery service creation
This fixes the integration test failure where undefined symbols were being referenced.
- Remove exit 1 from status check to prevent workflow failure
- Add proper GitHub permissions (statuses: write, contents: read)
- Add error handling for commit status API calls
- Add detailed logging to show which specific CI jobs failed
- Ensure workflow completes successfully even when CI checks fail
Fixes the 403 HTTP error and improves debugging visibility.