package main import ( "fmt" "github.com/gesellix/bose-soundtouch/pkg/models" "github.com/urfave/cli/v2" ) // browseContent handles browsing content sources func browseContent(c *cli.Context) error { source := c.String("source") sourceAccount := c.String("source-account") startItem := c.Int("start") numItems := c.Int("limit") clientConfig := GetClientConfig(c) PrintDeviceHeader(fmt.Sprintf("Browsing %s content", source), clientConfig.Host, clientConfig.Port) client, err := CreateSoundTouchClient(clientConfig) if err != nil { PrintError(fmt.Sprintf("Failed to create client: %v", err)) return err } response, err := client.Navigate(source, sourceAccount, startItem, numItems) if err != nil { PrintError(fmt.Sprintf("Failed to browse content: %v", err)) return err } printNavigationResults(response, "Content") return nil } // browseWithMenu handles browsing with menu navigation func browseWithMenu(c *cli.Context) error { source := c.String("source") sourceAccount := c.String("source-account") menu := c.String("menu") sort := c.String("sort") startItem := c.Int("start") numItems := c.Int("limit") clientConfig := GetClientConfig(c) PrintDeviceHeader(fmt.Sprintf("Browsing %s menu: %s", source, menu), clientConfig.Host, clientConfig.Port) client, err := CreateSoundTouchClient(clientConfig) if err != nil { PrintError(fmt.Sprintf("Failed to create client: %v", err)) return err } response, err := client.NavigateWithMenu(source, sourceAccount, menu, sort, startItem, numItems) if err != nil { PrintError(fmt.Sprintf("Failed to browse menu: %v", err)) return err } printNavigationResults(response, "Menu Items") return nil } // browseContainer handles browsing into containers/directories func browseContainer(c *cli.Context) error { source := c.String("source") sourceAccount := c.String("source-account") location := c.String("location") itemType := c.String("type") startItem := c.Int("start") numItems := c.Int("limit") clientConfig := GetClientConfig(c) PrintDeviceHeader(fmt.Sprintf("Browsing %s container: %s", source, location), clientConfig.Host, clientConfig.Port) client, err := CreateSoundTouchClient(clientConfig) if err != nil { PrintError(fmt.Sprintf("Failed to create client: %v", err)) return err } // Create container content item containerItem := &models.ContentItem{ Source: source, Location: location, Type: itemType, } response, err := client.NavigateContainer(source, sourceAccount, startItem, numItems, containerItem) if err != nil { PrintError(fmt.Sprintf("Failed to browse container: %v", err)) return err } printNavigationResults(response, "Container Contents") return nil } // browseTuneIn handles browsing TuneIn content func browseTuneIn(c *cli.Context) error { sourceAccount := c.String("source-account") startItem := c.Int("start") numItems := c.Int("limit") clientConfig := GetClientConfig(c) PrintDeviceHeader("Browsing TuneIn stations", clientConfig.Host, clientConfig.Port) client, err := CreateSoundTouchClient(clientConfig) if err != nil { PrintError(fmt.Sprintf("Failed to create client: %v", err)) return err } response, err := client.GetTuneInStations(sourceAccount) if err != nil { PrintError(fmt.Sprintf("Failed to get TuneIn stations: %v", err)) return err } // Apply pagination if different from defaults if startItem != 1 || numItems != 100 { response, err = client.Navigate("TUNEIN", sourceAccount, startItem, numItems) if err != nil { PrintError(fmt.Sprintf("Failed to browse TuneIn with pagination: %v", err)) return err } } printNavigationResults(response, "TuneIn Stations") return nil } // browsePandora handles browsing Pandora content func browsePandora(c *cli.Context) error { sourceAccount := c.String("source-account") if sourceAccount == "" { PrintError("Pandora source account is required") return fmt.Errorf("source account required for Pandora") } clientConfig := GetClientConfig(c) PrintDeviceHeader("Browsing Pandora stations", clientConfig.Host, clientConfig.Port) client, err := CreateSoundTouchClient(clientConfig) if err != nil { PrintError(fmt.Sprintf("Failed to create client: %v", err)) return err } response, err := client.GetPandoraStations(sourceAccount) if err != nil { PrintError(fmt.Sprintf("Failed to get Pandora stations: %v", err)) return err } printNavigationResults(response, "Pandora Stations") return nil } // browseStoredMusic handles browsing local/stored music func browseStoredMusic(c *cli.Context) error { sourceAccount := c.String("source-account") if sourceAccount == "" { PrintError("Source account (device ID) is required for stored music") return fmt.Errorf("source account required for stored music") } clientConfig := GetClientConfig(c) PrintDeviceHeader("Browsing stored music library", clientConfig.Host, clientConfig.Port) client, err := CreateSoundTouchClient(clientConfig) if err != nil { PrintError(fmt.Sprintf("Failed to create client: %v", err)) return err } response, err := client.GetStoredMusicLibrary(sourceAccount) if err != nil { PrintError(fmt.Sprintf("Failed to get stored music library: %v", err)) return err } printNavigationResults(response, "Stored Music Library") return nil } // printNavigationResults formats and displays navigation results func printNavigationResults(response *models.NavigateResponse, title string) { fmt.Printf("%s:\n", title) if response.TotalItems == 0 { fmt.Printf(" No items found\n") return } fmt.Printf(" Total items: %d\n", response.TotalItems) if len(response.Items) == 0 { fmt.Printf(" No items in current page\n") return } fmt.Printf(" Items:\n") for i, item := range response.Items { printNavigationItem(item, i+1, response.Source) } printNavigationHints(response) } // printNavigationItem prints a single navigation item with its metadata func printNavigationItem(item models.NavigateItem, index int, responseSource string) { fmt.Printf(" %d. %s\n", index, item.GetDisplayName()) printContentItemInfo(item, responseSource) printItemMetadata(item) printItemType(item) fmt.Println() } // printContentItemInfo prints content item information (source, type, location) func printContentItemInfo(item models.NavigateItem, responseSource string) { if item.ContentItem == nil { return } if item.ContentItem.Source != "" && item.ContentItem.Source != responseSource { fmt.Printf(" Source: %s\n", item.ContentItem.Source) } if item.Type != "" { fmt.Printf(" Type: %s\n", item.Type) } if item.ContentItem.Location != "" && len(item.ContentItem.Location) < 100 { fmt.Printf(" Location: %s\n", item.ContentItem.Location) } } // printItemMetadata prints additional metadata (artist, album) func printItemMetadata(item models.NavigateItem) { if item.ArtistName != "" { fmt.Printf(" Artist: %s\n", item.ArtistName) } if item.AlbumName != "" { fmt.Printf(" Album: %s\n", item.AlbumName) } } // printItemType prints whether the item is a directory or playable func printItemType(item models.NavigateItem) { if item.IsDirectory() { fmt.Printf(" 📁 Directory (can browse into)\n") } else if item.IsPlayable() { fmt.Printf(" ▶️ Playable content\n") } } // printNavigationHints prints helpful navigation hints func printNavigationHints(response *models.NavigateResponse) { directories := response.GetDirectories() if len(directories) > 0 { fmt.Printf(" 💡 To browse into a directory, use: browse container --location --type \n") } playableItems := response.GetPlayableItems() if len(playableItems) > 0 { fmt.Printf(" 💡 Found %d playable items\n", len(playableItems)) } }