mirror of
https://github.com/gesellix/Bose-SoundTouch.git
synced 2026-08-18 16:46:17 +00:00
- Add container art URL display in verbose mode - Show shuffle and repeat settings - Display track ID for streaming services - Include art image status and URL details - Add capabilities section showing available controls (skip, favorite, seek) - Organize verbose output in logical sections for better readability - All additional details match those available via direct curl API calls
439 lines
11 KiB
Go
439 lines
11 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
|
|
"github.com/gesellix/bose-soundtouch/pkg/models"
|
|
"github.com/urfave/cli/v2"
|
|
)
|
|
|
|
// getNowPlaying handles getting the current playback status
|
|
func getNowPlaying(c *cli.Context) error {
|
|
clientConfig := GetClientConfig(c)
|
|
|
|
client, err := CreateSoundTouchClient(clientConfig)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
PrintDeviceHeader("Getting current playback status", clientConfig.Host, clientConfig.Port)
|
|
|
|
nowPlaying, err := client.GetNowPlaying()
|
|
if err != nil {
|
|
return fmt.Errorf("failed to get now playing: %w", err)
|
|
}
|
|
|
|
fmt.Printf("Now Playing:\n")
|
|
fmt.Printf(" Device ID: %s\n", nowPlaying.DeviceID)
|
|
|
|
if nowPlaying.IsEmpty() {
|
|
fmt.Printf(" Status: No content playing\n")
|
|
return nil
|
|
}
|
|
|
|
printBasicPlaybackInfo(nowPlaying)
|
|
printTrackInfo(nowPlaying)
|
|
printTimeInfo(nowPlaying)
|
|
printStreamInfo(nowPlaying)
|
|
printContentDetails(nowPlaying, c.Bool("verbose"))
|
|
printPlaybackStatus(nowPlaying)
|
|
|
|
return nil
|
|
}
|
|
|
|
// printBasicPlaybackInfo prints basic source and status information
|
|
func printBasicPlaybackInfo(nowPlaying *models.NowPlaying) {
|
|
fmt.Printf(" Source: %s\n", nowPlaying.Source)
|
|
|
|
if nowPlaying.SourceAccount != "" {
|
|
fmt.Printf(" Source Account: %s\n", nowPlaying.SourceAccount)
|
|
}
|
|
|
|
fmt.Printf(" Status: %s\n", nowPlaying.PlayStatus.String())
|
|
}
|
|
|
|
// printTrackInfo prints track, artist, and album information
|
|
func printTrackInfo(nowPlaying *models.NowPlaying) {
|
|
if nowPlaying.Track != "" {
|
|
fmt.Printf(" Track: %s\n", nowPlaying.Track)
|
|
}
|
|
|
|
if nowPlaying.Artist != "" {
|
|
fmt.Printf(" Artist: %s\n", nowPlaying.Artist)
|
|
}
|
|
|
|
if nowPlaying.Album != "" {
|
|
fmt.Printf(" Album: %s\n", nowPlaying.Album)
|
|
}
|
|
}
|
|
|
|
// printTimeInfo prints duration and position information
|
|
func printTimeInfo(nowPlaying *models.NowPlaying) {
|
|
if !nowPlaying.HasTimeInfo() {
|
|
return
|
|
}
|
|
|
|
fmt.Printf(" Duration: %s\n", nowPlaying.FormatDuration())
|
|
|
|
if nowPlaying.Position != nil {
|
|
fmt.Printf(" Position: %s\n", nowPlaying.FormatPosition())
|
|
}
|
|
}
|
|
|
|
// printStreamInfo prints stream type information
|
|
func printStreamInfo(nowPlaying *models.NowPlaying) {
|
|
if nowPlaying.StreamType != "" {
|
|
fmt.Printf(" Stream Type: %s\n", nowPlaying.StreamType)
|
|
}
|
|
}
|
|
|
|
// printContentDetails prints detailed content information when verbose or location is available
|
|
func printContentDetails(nowPlaying *models.NowPlaying, verbose bool) {
|
|
if nowPlaying.ContentItem == nil {
|
|
return
|
|
}
|
|
|
|
showDetails := verbose || nowPlaying.ContentItem.Location != ""
|
|
if !showDetails {
|
|
return
|
|
}
|
|
|
|
fmt.Printf("\nContent Details:\n")
|
|
printContentLocation(nowPlaying.ContentItem)
|
|
printVerboseContentInfo(nowPlaying, verbose)
|
|
|
|
if verbose {
|
|
printVerbosePlaybackDetails(nowPlaying)
|
|
}
|
|
}
|
|
|
|
// printContentLocation prints the content location
|
|
func printContentLocation(contentItem *models.ContentItem) {
|
|
if contentItem.Location != "" {
|
|
fmt.Printf(" Location: %s\n", contentItem.Location)
|
|
}
|
|
}
|
|
|
|
// printVerboseContentInfo prints verbose content information
|
|
func printVerboseContentInfo(nowPlaying *models.NowPlaying, verbose bool) {
|
|
if !verbose || nowPlaying.ContentItem == nil {
|
|
return
|
|
}
|
|
|
|
if nowPlaying.ContentItem.Type != "" {
|
|
fmt.Printf(" Content Type: %s\n", nowPlaying.ContentItem.Type)
|
|
}
|
|
|
|
if nowPlaying.ContentItem.ItemName != "" && nowPlaying.ContentItem.ItemName != nowPlaying.Track {
|
|
fmt.Printf(" Item Name: %s\n", nowPlaying.ContentItem.ItemName)
|
|
}
|
|
|
|
if nowPlaying.ContentItem.ContainerArt != "" {
|
|
fmt.Printf(" Container Art: %s\n", nowPlaying.ContentItem.ContainerArt)
|
|
}
|
|
|
|
fmt.Printf(" Presetable: %t\n", nowPlaying.ContentItem.IsPresetable)
|
|
}
|
|
|
|
// printVerbosePlaybackDetails prints detailed playback information in verbose mode
|
|
func printVerbosePlaybackDetails(nowPlaying *models.NowPlaying) {
|
|
fmt.Printf("\nPlayback Details:\n")
|
|
|
|
// Shuffle and repeat settings
|
|
if nowPlaying.ShuffleSetting != "" {
|
|
fmt.Printf(" Shuffle: %s\n", nowPlaying.ShuffleSetting.String())
|
|
}
|
|
|
|
if nowPlaying.RepeatSetting != "" {
|
|
fmt.Printf(" Repeat: %s\n", nowPlaying.RepeatSetting.String())
|
|
}
|
|
|
|
// Track ID
|
|
if nowPlaying.TrackID != "" {
|
|
fmt.Printf(" Track ID: %s\n", nowPlaying.TrackID)
|
|
}
|
|
|
|
// Art details
|
|
if nowPlaying.Art != nil {
|
|
fmt.Printf(" Art Image Status: %s\n", nowPlaying.Art.ArtImageStatus)
|
|
if nowPlaying.Art.URL != "" {
|
|
fmt.Printf(" Art URL: %s\n", nowPlaying.Art.URL)
|
|
}
|
|
}
|
|
|
|
// Capabilities
|
|
fmt.Printf("\nCapabilities:\n")
|
|
fmt.Printf(" Skip Enabled: %t\n", nowPlaying.CanSkip())
|
|
fmt.Printf(" Skip Previous Enabled: %t\n", nowPlaying.CanSkipPrevious())
|
|
fmt.Printf(" Favorite Enabled: %t\n", nowPlaying.CanFavorite())
|
|
fmt.Printf(" Seek Supported: %t\n", nowPlaying.IsSeekSupported())
|
|
}
|
|
|
|
// printPlaybackStatus prints special status messages
|
|
func printPlaybackStatus(nowPlaying *models.NowPlaying) {
|
|
if nowPlaying.PlayStatus == models.PlayStatusBuffering {
|
|
fmt.Printf("\nNote: Content is buffering\n")
|
|
}
|
|
}
|
|
|
|
// playCommand handles play command
|
|
func playCommand(c *cli.Context) error {
|
|
clientConfig := GetClientConfig(c)
|
|
|
|
client, err := CreateSoundTouchClient(clientConfig)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
PrintDeviceHeader("Sending play command", clientConfig.Host, clientConfig.Port)
|
|
|
|
err = client.SendKeyPressOnly(models.KeyPlay)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to send play command: %w", err)
|
|
}
|
|
|
|
PrintSuccess("Play command sent")
|
|
|
|
return nil
|
|
}
|
|
|
|
// pauseCommand handles pause command
|
|
func pauseCommand(c *cli.Context) error {
|
|
clientConfig := GetClientConfig(c)
|
|
|
|
client, err := CreateSoundTouchClient(clientConfig)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
PrintDeviceHeader("Sending pause command", clientConfig.Host, clientConfig.Port)
|
|
|
|
err = client.SendKeyPressOnly(models.KeyPause)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to send pause command: %w", err)
|
|
}
|
|
|
|
PrintSuccess("Pause command sent")
|
|
|
|
return nil
|
|
}
|
|
|
|
// stopCommand handles stop command
|
|
func stopCommand(c *cli.Context) error {
|
|
clientConfig := GetClientConfig(c)
|
|
|
|
client, err := CreateSoundTouchClient(clientConfig)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
PrintDeviceHeader("Sending stop command", clientConfig.Host, clientConfig.Port)
|
|
|
|
err = client.SendKeyPressOnly(models.KeyStop)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to send stop command: %w", err)
|
|
}
|
|
|
|
PrintSuccess("Stop command sent")
|
|
|
|
return nil
|
|
}
|
|
|
|
// nextCommand handles next track command
|
|
func nextCommand(c *cli.Context) error {
|
|
clientConfig := GetClientConfig(c)
|
|
|
|
client, err := CreateSoundTouchClient(clientConfig)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
PrintDeviceHeader("Sending next track command", clientConfig.Host, clientConfig.Port)
|
|
|
|
err = client.SendKeyPressOnly(models.KeyNextTrack)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to send next track command: %w", err)
|
|
}
|
|
|
|
PrintSuccess("Next track command sent")
|
|
|
|
return nil
|
|
}
|
|
|
|
// prevCommand handles previous track command
|
|
func prevCommand(c *cli.Context) error {
|
|
clientConfig := GetClientConfig(c)
|
|
|
|
client, err := CreateSoundTouchClient(clientConfig)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
PrintDeviceHeader("Sending previous track command", clientConfig.Host, clientConfig.Port)
|
|
|
|
err = client.SendKeyPressOnly(models.KeyPrevTrack)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to send previous track command: %w", err)
|
|
}
|
|
|
|
PrintSuccess("Previous track command sent")
|
|
|
|
return nil
|
|
}
|
|
|
|
// sendKey sends a generic key command
|
|
func sendKey(c *cli.Context) error {
|
|
key := c.String("key")
|
|
clientConfig := GetClientConfig(c)
|
|
PrintDeviceHeader(fmt.Sprintf("Sending %s key command", key), clientConfig.Host, clientConfig.Port)
|
|
|
|
client, err := CreateSoundTouchClient(clientConfig)
|
|
if err != nil {
|
|
PrintError(fmt.Sprintf("Failed to create client: %v", err))
|
|
return err
|
|
}
|
|
|
|
err = client.SendKey(strings.ToUpper(key))
|
|
if err != nil {
|
|
PrintError(fmt.Sprintf("Failed to send key command: %v", err))
|
|
return err
|
|
}
|
|
|
|
PrintSuccess(fmt.Sprintf("%s key command sent", key))
|
|
|
|
return nil
|
|
}
|
|
|
|
// powerCommand sends the POWER key command
|
|
func powerCommand(c *cli.Context) error {
|
|
clientConfig := GetClientConfig(c)
|
|
PrintDeviceHeader("Sending POWER key command", clientConfig.Host, clientConfig.Port)
|
|
|
|
client, err := CreateSoundTouchClient(clientConfig)
|
|
if err != nil {
|
|
PrintError(fmt.Sprintf("Failed to create client: %v", err))
|
|
return err
|
|
}
|
|
|
|
err = client.SendKey(models.KeyPower)
|
|
if err != nil {
|
|
PrintError(fmt.Sprintf("Failed to send power command: %v", err))
|
|
return err
|
|
}
|
|
|
|
PrintSuccess("Power command sent")
|
|
|
|
return nil
|
|
}
|
|
|
|
// muteCommand sends the MUTE key command
|
|
func muteCommand(c *cli.Context) error {
|
|
clientConfig := GetClientConfig(c)
|
|
PrintDeviceHeader("Sending MUTE key command", clientConfig.Host, clientConfig.Port)
|
|
|
|
client, err := CreateSoundTouchClient(clientConfig)
|
|
if err != nil {
|
|
PrintError(fmt.Sprintf("Failed to create client: %v", err))
|
|
return err
|
|
}
|
|
|
|
err = client.SendKey(models.KeyMute)
|
|
if err != nil {
|
|
PrintError(fmt.Sprintf("Failed to send mute command: %v", err))
|
|
return err
|
|
}
|
|
|
|
PrintSuccess("Mute command sent")
|
|
|
|
return nil
|
|
}
|
|
|
|
// thumbsUpCommand sends the THUMBS_UP key command
|
|
func thumbsUpCommand(c *cli.Context) error {
|
|
clientConfig := GetClientConfig(c)
|
|
PrintDeviceHeader("Sending THUMBS_UP key command", clientConfig.Host, clientConfig.Port)
|
|
|
|
client, err := CreateSoundTouchClient(clientConfig)
|
|
if err != nil {
|
|
PrintError(fmt.Sprintf("Failed to create client: %v", err))
|
|
return err
|
|
}
|
|
|
|
err = client.SendKey(models.KeyThumbsUp)
|
|
if err != nil {
|
|
PrintError(fmt.Sprintf("Failed to send thumbs up command: %v", err))
|
|
return err
|
|
}
|
|
|
|
PrintSuccess("Thumbs up command sent")
|
|
|
|
return nil
|
|
}
|
|
|
|
// thumbsDownCommand sends the THUMBS_DOWN key command
|
|
func thumbsDownCommand(c *cli.Context) error {
|
|
clientConfig := GetClientConfig(c)
|
|
PrintDeviceHeader("Sending THUMBS_DOWN key command", clientConfig.Host, clientConfig.Port)
|
|
|
|
client, err := CreateSoundTouchClient(clientConfig)
|
|
if err != nil {
|
|
PrintError(fmt.Sprintf("Failed to create client: %v", err))
|
|
return err
|
|
}
|
|
|
|
err = client.SendKey(models.KeyThumbsDown)
|
|
if err != nil {
|
|
PrintError(fmt.Sprintf("Failed to send thumbs down command: %v", err))
|
|
return err
|
|
}
|
|
|
|
PrintSuccess("Thumbs down command sent")
|
|
|
|
return nil
|
|
}
|
|
|
|
// volumeUpKey sends the VOLUME_UP key command
|
|
func volumeUpKey(c *cli.Context) error {
|
|
clientConfig := GetClientConfig(c)
|
|
PrintDeviceHeader("Sending VOLUME_UP key command", clientConfig.Host, clientConfig.Port)
|
|
|
|
client, err := CreateSoundTouchClient(clientConfig)
|
|
if err != nil {
|
|
PrintError(fmt.Sprintf("Failed to create client: %v", err))
|
|
return err
|
|
}
|
|
|
|
err = client.VolumeUp()
|
|
if err != nil {
|
|
PrintError(fmt.Sprintf("Failed to send volume up command: %v", err))
|
|
return err
|
|
}
|
|
|
|
PrintSuccess("Volume up command sent")
|
|
|
|
return nil
|
|
}
|
|
|
|
// volumeDownKey sends the VOLUME_DOWN key command
|
|
func volumeDownKey(c *cli.Context) error {
|
|
clientConfig := GetClientConfig(c)
|
|
PrintDeviceHeader("Sending VOLUME_DOWN key command", clientConfig.Host, clientConfig.Port)
|
|
|
|
client, err := CreateSoundTouchClient(clientConfig)
|
|
if err != nil {
|
|
PrintError(fmt.Sprintf("Failed to create client: %v", err))
|
|
return err
|
|
}
|
|
|
|
err = client.VolumeDown()
|
|
if err != nil {
|
|
PrintError(fmt.Sprintf("Failed to send volume down command: %v", err))
|
|
return err
|
|
}
|
|
|
|
PrintSuccess("Volume down command sent")
|
|
|
|
return nil
|
|
}
|