mirror of
https://github.com/gesellix/Bose-SoundTouch.git
synced 2026-08-24 14:47:23 +00:00
refactor: reduce cyclomatic complexity for all high-complexity functions
Major refactoring to improve code maintainability and readability: - printNavigationResults: Split into multiple helper functions (16->9) - printSearchResults: Extract song/artist/station printing functions (18->8) - compareSourcesAndAvailability: Separate comparison logic and summary (17->7) - storePreset: Extract parameter validation and content creation (19->8) - getNowPlaying: Break into focused helper functions (23->5) Benefits: - All cyclomatic complexity issues resolved (5->0) - Improved code readability and maintainability - Single responsibility principle applied to helper functions - Easier testing and debugging of individual components - Maintained all existing functionality Resolves all gocyclo linting issues while preserving functionality.
This commit is contained in:
@@ -204,40 +204,61 @@ func printNavigationResults(response *models.NavigateResponse, title string) {
|
||||
|
||||
fmt.Printf(" Items:\n")
|
||||
for i, item := range response.Items {
|
||||
fmt.Printf(" %d. %s\n", i+1, item.GetDisplayName())
|
||||
|
||||
// Show type and source for identification
|
||||
if item.ContentItem != nil {
|
||||
if item.ContentItem.Source != "" && item.ContentItem.Source != response.Source {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
// Show additional metadata
|
||||
if item.ArtistName != "" {
|
||||
fmt.Printf(" Artist: %s\n", item.ArtistName)
|
||||
}
|
||||
if item.AlbumName != "" {
|
||||
fmt.Printf(" Album: %s\n", item.AlbumName)
|
||||
}
|
||||
|
||||
// Show if it's a container that can be browsed further
|
||||
if item.IsDirectory() {
|
||||
fmt.Printf(" 📁 Directory (can browse into)\n")
|
||||
} else if item.IsPlayable() {
|
||||
fmt.Printf(" ▶️ Playable content\n")
|
||||
}
|
||||
|
||||
fmt.Println()
|
||||
printNavigationItem(item, i+1, response.Source)
|
||||
}
|
||||
|
||||
// Show navigation hints
|
||||
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 <location> --type <type>\n")
|
||||
|
||||
@@ -32,61 +32,100 @@ func getNowPlaying(c *cli.Context) error {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
if nowPlaying.HasTimeInfo() {
|
||||
fmt.Printf(" Duration: %s\n", nowPlaying.FormatDuration())
|
||||
|
||||
if nowPlaying.Position != nil {
|
||||
fmt.Printf(" Position: %s\n", nowPlaying.FormatPosition())
|
||||
}
|
||||
// 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)
|
||||
}
|
||||
}
|
||||
|
||||
// Show ContentItem details if verbose flag is set or always show location if available
|
||||
verbose := c.Bool("verbose")
|
||||
showDetails := verbose || (nowPlaying.ContentItem != nil && nowPlaying.ContentItem.Location != "")
|
||||
|
||||
if showDetails && nowPlaying.ContentItem != nil {
|
||||
fmt.Printf("\nContent Details:\n")
|
||||
if nowPlaying.ContentItem.Location != "" {
|
||||
fmt.Printf(" Location: %s\n", nowPlaying.ContentItem.Location)
|
||||
}
|
||||
if verbose && nowPlaying.ContentItem.Type != "" {
|
||||
fmt.Printf(" Content Type: %s\n", nowPlaying.ContentItem.Type)
|
||||
}
|
||||
if verbose && nowPlaying.ContentItem.ItemName != "" && nowPlaying.ContentItem.ItemName != nowPlaying.Track {
|
||||
fmt.Printf(" Item Name: %s\n", nowPlaying.ContentItem.ItemName)
|
||||
}
|
||||
if verbose {
|
||||
fmt.Printf(" Presetable: %t\n", nowPlaying.ContentItem.IsPresetable)
|
||||
}
|
||||
// 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)
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
fmt.Printf(" Presetable: %t\n", nowPlaying.ContentItem.IsPresetable)
|
||||
}
|
||||
|
||||
// printPlaybackStatus prints special status messages
|
||||
func printPlaybackStatus(nowPlaying *models.NowPlaying) {
|
||||
if nowPlaying.PlayStatus == models.PlayStatusBuffering {
|
||||
fmt.Printf("\nNote: Content is buffering\n")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// playCommand handles play command
|
||||
|
||||
@@ -70,67 +70,78 @@ func storeCurrentPreset(c *cli.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// storePreset handles storing specific content as preset
|
||||
func storePreset(c *cli.Context) error {
|
||||
slot := c.Int("slot")
|
||||
source := c.String("source")
|
||||
location := c.String("location")
|
||||
sourceAccount := c.String("source-account")
|
||||
name := c.String("name")
|
||||
itemType := c.String("type")
|
||||
artwork := c.String("artwork")
|
||||
// presetParams holds parameters for storing a preset
|
||||
type presetParams struct {
|
||||
slot int
|
||||
source string
|
||||
location string
|
||||
sourceAccount string
|
||||
name string
|
||||
itemType string
|
||||
artwork string
|
||||
}
|
||||
|
||||
// Resolve location and source from potential URLs
|
||||
resolvedSource, resolvedLocation := resolveLocation(source, location)
|
||||
if resolvedLocation != location && (source == "" || source == "TUNEIN") {
|
||||
// extractPresetParams extracts parameters from CLI context
|
||||
func extractPresetParams(c *cli.Context) *presetParams {
|
||||
return &presetParams{
|
||||
slot: c.Int("slot"),
|
||||
source: c.String("source"),
|
||||
location: c.String("location"),
|
||||
sourceAccount: c.String("source-account"),
|
||||
name: c.String("name"),
|
||||
itemType: c.String("type"),
|
||||
artwork: c.String("artwork"),
|
||||
}
|
||||
}
|
||||
|
||||
// resolveLocationAndMetadata resolves location and fetches metadata if needed
|
||||
func resolveLocationAndMetadata(params *presetParams) error {
|
||||
resolvedSource, resolvedLocation := resolveLocation(params.source, params.location)
|
||||
if resolvedLocation != params.location && (params.source == "" || params.source == "TUNEIN") {
|
||||
// If location was a TuneIn URL, fetch metadata if name or artwork is missing
|
||||
if name == "" || artwork == "" {
|
||||
metadata, err := fetchTuneInMetadata(location)
|
||||
if params.name == "" || params.artwork == "" {
|
||||
metadata, err := fetchTuneInMetadata(params.location)
|
||||
if err == nil && metadata != nil {
|
||||
if name == "" {
|
||||
name = metadata.Name
|
||||
if params.name == "" {
|
||||
params.name = metadata.Name
|
||||
}
|
||||
if artwork == "" {
|
||||
artwork = metadata.Artwork
|
||||
if params.artwork == "" {
|
||||
params.artwork = metadata.Artwork
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
source = resolvedSource
|
||||
location = resolvedLocation
|
||||
params.source = resolvedSource
|
||||
params.location = resolvedLocation
|
||||
return nil
|
||||
}
|
||||
|
||||
clientConfig := GetClientConfig(c)
|
||||
|
||||
if source == "" {
|
||||
// validatePresetParams validates required preset parameters
|
||||
func validatePresetParams(params *presetParams) error {
|
||||
if params.source == "" {
|
||||
return fmt.Errorf("source is required (use --source)")
|
||||
}
|
||||
|
||||
if location == "" {
|
||||
if params.location == "" {
|
||||
return fmt.Errorf("location is required (use --location)")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
PrintDeviceHeader(fmt.Sprintf("Storing %s content as preset %d", source, slot), clientConfig.Host, clientConfig.Port)
|
||||
|
||||
client, err := CreateSoundTouchClient(clientConfig)
|
||||
if err != nil {
|
||||
PrintError(fmt.Sprintf("Failed to create client: %v", err))
|
||||
return err
|
||||
}
|
||||
|
||||
// Create content item
|
||||
// createContentItem creates a ContentItem from preset parameters
|
||||
func createContentItem(params *presetParams) *models.ContentItem {
|
||||
contentItem := &models.ContentItem{
|
||||
Source: source,
|
||||
Type: itemType,
|
||||
Location: location,
|
||||
SourceAccount: sourceAccount,
|
||||
Source: params.source,
|
||||
Type: params.itemType,
|
||||
Location: params.location,
|
||||
SourceAccount: params.sourceAccount,
|
||||
IsPresetable: true,
|
||||
ItemName: name,
|
||||
ContainerArt: artwork,
|
||||
ItemName: params.name,
|
||||
ContainerArt: params.artwork,
|
||||
}
|
||||
|
||||
// Set default type if not specified
|
||||
if itemType == "" {
|
||||
switch source {
|
||||
if params.itemType == "" {
|
||||
switch params.source {
|
||||
case "SPOTIFY":
|
||||
contentItem.Type = "uri"
|
||||
case "TUNEIN", "LOCAL_INTERNET_RADIO":
|
||||
@@ -140,26 +151,58 @@ func storePreset(c *cli.Context) error {
|
||||
}
|
||||
}
|
||||
|
||||
// Show what we're storing
|
||||
return contentItem
|
||||
}
|
||||
|
||||
// printPresetContent displays what content will be stored
|
||||
func printPresetContent(params *presetParams) {
|
||||
fmt.Printf("Content to store:\n")
|
||||
fmt.Printf(" Name: %s\n", name)
|
||||
fmt.Printf(" Source: %s\n", source)
|
||||
fmt.Printf(" Location: %s\n", location)
|
||||
if sourceAccount != "" {
|
||||
fmt.Printf(" Source Account: %s\n", sourceAccount)
|
||||
fmt.Printf(" Name: %s\n", params.name)
|
||||
fmt.Printf(" Source: %s\n", params.source)
|
||||
fmt.Printf(" Location: %s\n", params.location)
|
||||
if params.sourceAccount != "" {
|
||||
fmt.Printf(" Source Account: %s\n", params.sourceAccount)
|
||||
}
|
||||
if itemType != "" {
|
||||
fmt.Printf(" Type: %s\n", itemType)
|
||||
if params.itemType != "" {
|
||||
fmt.Printf(" Type: %s\n", params.itemType)
|
||||
}
|
||||
}
|
||||
|
||||
// storePreset handles storing specific content as preset
|
||||
func storePreset(c *cli.Context) error {
|
||||
// Extract parameters
|
||||
params := extractPresetParams(c)
|
||||
|
||||
// Resolve location and fetch metadata if needed
|
||||
if err := resolveLocationAndMetadata(params); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Validate required parameters
|
||||
if err := validatePresetParams(params); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
clientConfig := GetClientConfig(c)
|
||||
PrintDeviceHeader(fmt.Sprintf("Storing %s content as preset %d", params.source, params.slot), clientConfig.Host, clientConfig.Port)
|
||||
|
||||
client, err := CreateSoundTouchClient(clientConfig)
|
||||
if err != nil {
|
||||
PrintError(fmt.Sprintf("Failed to create client: %v", err))
|
||||
return err
|
||||
}
|
||||
|
||||
contentItem := createContentItem(params)
|
||||
printPresetContent(params)
|
||||
|
||||
// Store preset
|
||||
err = client.StorePreset(slot, contentItem)
|
||||
err = client.StorePreset(params.slot, contentItem)
|
||||
if err != nil {
|
||||
PrintError(fmt.Sprintf("Failed to store preset: %v", err))
|
||||
return err
|
||||
}
|
||||
|
||||
PrintSuccess(fmt.Sprintf("Stored content as preset %d", slot))
|
||||
PrintSuccess(fmt.Sprintf("Stored content as preset %d", params.slot))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -309,6 +309,14 @@ func compareSourcesAndAvailability(c *cli.Context) error {
|
||||
|
||||
fmt.Printf("Source vs Availability Comparison:\n\n")
|
||||
|
||||
performSourceComparisons(sources, serviceAvailability)
|
||||
printSourceSummary(sources, serviceAvailability)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// performSourceComparisons compares configured sources with availability
|
||||
func performSourceComparisons(sources *models.Sources, serviceAvailability *models.ServiceAvailability) {
|
||||
// Check key services
|
||||
comparisons := []struct {
|
||||
name string
|
||||
@@ -331,40 +339,48 @@ func compareSourcesAndAvailability(c *cli.Context) error {
|
||||
}
|
||||
|
||||
for _, comp := range comparisons {
|
||||
configured := comp.configuredCheck()
|
||||
available := comp.availableCheck()
|
||||
compareServiceStatus(comp.name, comp.configuredCheck(), comp.availableCheck(), serviceAvailability)
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Printf("🔍 %s:\n", comp.name)
|
||||
fmt.Printf(" Configured: %s\n", boolToStatus(configured))
|
||||
fmt.Printf(" Available: %s\n", boolToStatus(available))
|
||||
// compareServiceStatus compares a single service's configuration vs availability
|
||||
func compareServiceStatus(serviceName string, configured, available bool, serviceAvailability *models.ServiceAvailability) {
|
||||
fmt.Printf("🔍 %s:\n", serviceName)
|
||||
fmt.Printf(" Configured: %s\n", boolToStatus(configured))
|
||||
fmt.Printf(" Available: %s\n", boolToStatus(available))
|
||||
|
||||
switch {
|
||||
case available && !configured:
|
||||
fmt.Printf(" 💡 %s is available but not configured - consider setting it up\n", comp.name)
|
||||
case configured && !available:
|
||||
fmt.Printf(" ⚠️ %s is configured but not available - check device status\n", comp.name)
|
||||
switch {
|
||||
case available && !configured:
|
||||
fmt.Printf(" 💡 %s is available but not configured - consider setting it up\n", serviceName)
|
||||
case configured && !available:
|
||||
fmt.Printf(" ⚠️ %s is configured but not available - check device status\n", serviceName)
|
||||
printServiceUnavailableReason(serviceName, serviceAvailability)
|
||||
case configured && available:
|
||||
fmt.Printf(" ✅ %s is properly configured and available\n", serviceName)
|
||||
default:
|
||||
fmt.Printf(" ➖ %s is neither configured nor available\n", serviceName)
|
||||
}
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
// Show specific reason if available
|
||||
switch comp.name {
|
||||
case "Spotify":
|
||||
service := serviceAvailability.GetServiceByType(models.ServiceTypeSpotify)
|
||||
if service != nil && service.Reason != "" {
|
||||
fmt.Printf(" 📝 Reason: %s\n", service.Reason)
|
||||
}
|
||||
case "Bluetooth":
|
||||
service := serviceAvailability.GetServiceByType(models.ServiceTypeBluetooth)
|
||||
if service != nil && service.Reason != "" {
|
||||
fmt.Printf(" 📝 Reason: %s\n", service.Reason)
|
||||
}
|
||||
}
|
||||
case configured && available:
|
||||
fmt.Printf(" ✅ %s is properly configured and available\n", comp.name)
|
||||
default:
|
||||
fmt.Printf(" ➖ %s is neither configured nor available\n", comp.name)
|
||||
}
|
||||
fmt.Println()
|
||||
// printServiceUnavailableReason prints the reason why a service is unavailable
|
||||
func printServiceUnavailableReason(serviceName string, serviceAvailability *models.ServiceAvailability) {
|
||||
var service *models.Service
|
||||
|
||||
switch serviceName {
|
||||
case "Spotify":
|
||||
service = serviceAvailability.GetServiceByType(models.ServiceTypeSpotify)
|
||||
case "Bluetooth":
|
||||
service = serviceAvailability.GetServiceByType(models.ServiceTypeBluetooth)
|
||||
}
|
||||
|
||||
if service != nil && service.Reason != "" {
|
||||
fmt.Printf(" 📝 Reason: %s\n", service.Reason)
|
||||
}
|
||||
}
|
||||
|
||||
// printSourceSummary prints a summary of sources and services
|
||||
func printSourceSummary(sources *models.Sources, serviceAvailability *models.ServiceAvailability) {
|
||||
// Summary
|
||||
fmt.Printf("📊 Summary:\n")
|
||||
fmt.Printf(" Total configured sources: %d\n", sources.GetSourceCount())
|
||||
@@ -372,7 +388,6 @@ func compareSourcesAndAvailability(c *cli.Context) error {
|
||||
fmt.Printf(" Total available services: %d\n", serviceAvailability.GetAvailableServiceCount())
|
||||
fmt.Printf(" Total possible services: %d\n", serviceAvailability.GetServiceCount())
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// boolToStatus converts boolean to user-friendly status
|
||||
|
||||
@@ -269,55 +269,77 @@ func printSearchResults(response *models.SearchStationResponse, searchTerm strin
|
||||
artists := response.GetArtists()
|
||||
stations := response.GetStations()
|
||||
|
||||
if len(songs) > 0 {
|
||||
fmt.Printf("\n 🎵 Songs (%d):\n", len(songs))
|
||||
for i := range songs {
|
||||
song := &songs[i]
|
||||
fmt.Printf(" %d. %s\n", i+1, song.GetDisplayName())
|
||||
if song.Artist != "" {
|
||||
fmt.Printf(" Artist: %s\n", song.Artist)
|
||||
}
|
||||
if song.Album != "" {
|
||||
fmt.Printf(" Album: %s\n", song.Album)
|
||||
}
|
||||
if song.SourceAccount != "" {
|
||||
fmt.Printf(" Account: %s\n", song.SourceAccount)
|
||||
}
|
||||
fmt.Printf(" Token: %s\n", song.Token)
|
||||
fmt.Println()
|
||||
}
|
||||
printSongs(songs)
|
||||
printArtists(artists)
|
||||
printStations(stations)
|
||||
printSearchHints(response, songs, artists, stations)
|
||||
}
|
||||
|
||||
// printSongs prints song search results
|
||||
func printSongs(songs []models.SearchResult) {
|
||||
if len(songs) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
if len(artists) > 0 {
|
||||
fmt.Printf(" 🎤 Artists (%d):\n", len(artists))
|
||||
for i := range artists {
|
||||
artist := &artists[i]
|
||||
fmt.Printf(" %d. %s\n", i+1, artist.GetDisplayName())
|
||||
if artist.SourceAccount != "" {
|
||||
fmt.Printf(" Account: %s\n", artist.SourceAccount)
|
||||
}
|
||||
fmt.Printf(" Token: %s\n", artist.Token)
|
||||
fmt.Println()
|
||||
fmt.Printf("\n 🎵 Songs (%d):\n", len(songs))
|
||||
for i := range songs {
|
||||
song := &songs[i]
|
||||
fmt.Printf(" %d. %s\n", i+1, song.GetDisplayName())
|
||||
if song.Artist != "" {
|
||||
fmt.Printf(" Artist: %s\n", song.Artist)
|
||||
}
|
||||
if song.Album != "" {
|
||||
fmt.Printf(" Album: %s\n", song.Album)
|
||||
}
|
||||
if song.SourceAccount != "" {
|
||||
fmt.Printf(" Account: %s\n", song.SourceAccount)
|
||||
}
|
||||
fmt.Printf(" Token: %s\n", song.Token)
|
||||
fmt.Println()
|
||||
}
|
||||
}
|
||||
|
||||
// printArtists prints artist search results
|
||||
func printArtists(artists []models.SearchResult) {
|
||||
if len(artists) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
if len(stations) > 0 {
|
||||
fmt.Printf(" 📻 Stations (%d):\n", len(stations))
|
||||
for i := range stations {
|
||||
station := &stations[i]
|
||||
fmt.Printf(" %d. %s\n", i+1, station.GetDisplayName())
|
||||
if station.SourceAccount != "" {
|
||||
fmt.Printf(" Account: %s\n", station.SourceAccount)
|
||||
}
|
||||
fmt.Printf(" Token: %s\n", station.Token)
|
||||
if station.Description != "" {
|
||||
fmt.Printf(" Description: %s\n", station.Description)
|
||||
}
|
||||
fmt.Println()
|
||||
fmt.Printf(" 🎤 Artists (%d):\n", len(artists))
|
||||
for i := range artists {
|
||||
artist := &artists[i]
|
||||
fmt.Printf(" %d. %s\n", i+1, artist.GetDisplayName())
|
||||
if artist.SourceAccount != "" {
|
||||
fmt.Printf(" Account: %s\n", artist.SourceAccount)
|
||||
}
|
||||
fmt.Printf(" Token: %s\n", artist.Token)
|
||||
fmt.Println()
|
||||
}
|
||||
}
|
||||
|
||||
// printStations prints station search results
|
||||
func printStations(stations []models.SearchResult) {
|
||||
if len(stations) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
// Show usage hints
|
||||
fmt.Printf(" 📻 Stations (%d):\n", len(stations))
|
||||
for i := range stations {
|
||||
station := &stations[i]
|
||||
fmt.Printf(" %d. %s\n", i+1, station.GetDisplayName())
|
||||
if station.SourceAccount != "" {
|
||||
fmt.Printf(" Account: %s\n", station.SourceAccount)
|
||||
}
|
||||
fmt.Printf(" Token: %s\n", station.Token)
|
||||
if station.Description != "" {
|
||||
fmt.Printf(" Description: %s\n", station.Description)
|
||||
}
|
||||
fmt.Println()
|
||||
}
|
||||
}
|
||||
|
||||
// printSearchHints prints usage hints for search results
|
||||
func printSearchHints(response *models.SearchStationResponse, songs, artists, stations []models.SearchResult) {
|
||||
fmt.Printf("💡 Usage hints:\n")
|
||||
fmt.Printf(" • To add a station and play it: station add --source %s --token <token> --name <name>\n", response.Source)
|
||||
if hasAccountResults(response) {
|
||||
|
||||
Reference in New Issue
Block a user