// Package resolver handles cross-service music link resolution. package resolver import ( "context" "fmt" "musiclink/internal/services" ) // Resolver uses the idonthavespotify API to resolve music links. type Resolver struct { client *services.Client } // New creates a new Resolver. func New(apiURL string) *Resolver { return &Resolver{ client: services.NewClient(apiURL), } } // Resolve takes a music link URL and returns equivalent links on other platforms. func (r *Resolver) Resolve(ctx context.Context, link string) (*services.ResolvedLinks, error) { resp, err := r.client.Resolve(ctx, link) if err != nil { return nil, fmt.Errorf("resolving link: %w", err) } return resp.ToResolvedLinks(), nil } // Format creates a formatted message from resolved links. func Format(resolved *services.ResolvedLinks, title string) string { var msg string // Header with track info if title != "" { msg = fmt.Sprintf("%s\n\n", title) } // Service links in a consistent order order := []services.ServiceType{ services.ServiceSpotify, services.ServiceYouTube, services.ServiceAppleMusic, services.ServiceDeezer, services.ServiceTidal, services.ServiceSoundCloud, services.ServiceBandcamp, services.ServiceQobuz, } for _, svc := range order { if url, ok := resolved.Links[svc]; ok { msg += fmt.Sprintf("%s: %s\n", serviceName(svc), url) } } return msg } // serviceName returns a human-readable name for a service. func serviceName(svc services.ServiceType) string { switch svc { case services.ServiceSpotify: return "Spotify" case services.ServiceYouTube: return "YouTube" case services.ServiceAppleMusic: return "Apple Music" case services.ServiceDeezer: return "Deezer" case services.ServiceTidal: return "Tidal" case services.ServiceSoundCloud: return "SoundCloud" case services.ServiceBandcamp: return "Bandcamp" case services.ServiceQobuz: return "Qobuz" default: return string(svc) } }