package api import ( "encoding/json" "strings" ) // ID represents an identifier that can be decoded from either a JSON string or integer. type ID string func (id *ID) UnmarshalJSON(b []byte) error { if len(b) == 0 || string(b) == "null" { *id = "" return nil } if b[0] == '"' { var s string if err := json.Unmarshal(b, &s); err != nil { return err } *id = ID(s) return nil } *id = ID(strings.TrimSpace(string(b))) return nil } func (id ID) String() string { return string(id) } // Quality represents audio streaming and download quality formats. type Quality int const ( QualityMp3 Quality = 5 // MP3 320kbps QualityLossless Quality = 6 // 16-bit / 44.1kHz (CD Quality) QualityHiRes Quality = 7 // 24-bit / ≤96kHz QualityUltraHiRes Quality = 27 // 24-bit / >96kHz ) // ID returns the numeric format identifier. func (q Quality) ID() int { return int(q) } // Label returns a human-readable description of the quality setting. func (q Quality) Label() string { switch q { case QualityMp3: return "MP3 320kbps" case QualityLossless: return "FLAC 16-bit/44.1kHz" case QualityHiRes: return "FLAC 24-bit/≤96kHz" case QualityUltraHiRes: return "FLAC 24-bit/>96kHz" default: return "Unknown" } } // IsValid reports whether the quality setting is a known format. func (q Quality) IsValid() bool { switch q { case QualityMp3, QualityLossless, QualityHiRes, QualityUltraHiRes: return true default: return false } } // Image holds artwork URLs across various resolutions. type Image struct { Small string `json:"small,omitempty"` Thumbnail string `json:"thumbnail,omitempty"` Medium string `json:"medium,omitempty"` Large string `json:"large,omitempty"` ExtraLarge string `json:"extralarge,omitempty"` Mega string `json:"mega,omitempty"` Back string `json:"back,omitempty"` } // Best returns the highest-resolution image URL available. func (img Image) Best() string { if img.Mega != "" { return img.Mega } if img.ExtraLarge != "" { return img.ExtraLarge } if img.Large != "" { return img.Large } if img.Thumbnail != "" { return img.Thumbnail } return img.Small } // Smallest returns the lowest-resolution image URL available. func (img Image) Smallest() string { if img.Small != "" { return img.Small } if img.Thumbnail != "" { return img.Thumbnail } if img.Large != "" { return img.Large } if img.ExtraLarge != "" { return img.ExtraLarge } return img.Mega } // Label represents record label metadata. type Label struct { ID ID `json:"id"` Name string `json:"name"` AlbumsCount int `json:"albums_count,omitempty"` Slug string `json:"slug,omitempty"` SupplierID int `json:"supplier_id,omitempty"` } // Genre represents musical genre classification. type Genre struct { ID int `json:"id"` Name string `json:"name"` Path []int `json:"path,omitempty"` Slug string `json:"slug,omitempty"` Color string `json:"color,omitempty"` } // AlbumAward represents press and catalog accolades. type AlbumAward struct { ID ID `json:"id"` AwardID ID `json:"award_id,omitempty"` Name string `json:"name"` AwardedAt ID `json:"awarded_at,omitempty"` } func (a *AlbumAward) UnmarshalJSON(b []byte) error { var raw struct { ID ID `json:"id"` AwardID ID `json:"award_id"` AwardIDCamel ID `json:"awardId"` Name string `json:"name"` AwardedAt ID `json:"awarded_at"` AwardedAtCamel ID `json:"awardedAt"` } if err := json.Unmarshal(b, &raw); err != nil { return err } a.Name = raw.Name if raw.ID != "" { a.ID = raw.ID } else if raw.AwardID != "" { a.ID = raw.AwardID } else { a.ID = raw.AwardIDCamel } a.AwardID = a.ID if raw.AwardedAt != "" { a.AwardedAt = raw.AwardedAt } else { a.AwardedAt = raw.AwardedAtCamel } return nil } // Dates contains release date timestamps. type Dates struct { Original string `json:"original,omitempty"` Download string `json:"download,omitempty"` Stream string `json:"stream,omitempty"` } // AudioInfo describes audio resolution and replaygain metadata. type AudioInfo struct { MaximumSamplingRate float64 `json:"maximum_sampling_rate,omitempty"` MaximumBitDepth int `json:"maximum_bit_depth,omitempty"` MaximumChannelCount int `json:"maximum_channel_count,omitempty"` ReplayGainTrackGain float64 `json:"replaygain_track_gain,omitempty"` ReplayGainTrackPeak float64 `json:"replaygain_track_peak,omitempty"` } // Rights specifies streaming, purchase, and download availability. type Rights struct { Streamable *bool `json:"streamable,omitempty"` HiResStreamable *bool `json:"hires_streamable,omitempty"` HiResPurchasable *bool `json:"hires_purchasable,omitempty"` Purchasable *bool `json:"purchasable,omitempty"` Downloadable *bool `json:"downloadable,omitempty"` Previewable *bool `json:"previewable,omitempty"` Sampleable *bool `json:"sampleable,omitempty"` } // Goodie represents supplementary media such as digital booklets. type Goodie struct { ID ID `json:"id"` Name string `json:"name"` URL string `json:"url"` OriginalURL string `json:"original_url,omitempty"` FileURL string `json:"file_url,omitempty"` FileFormatID int `json:"file_format_id,omitempty"` Description string `json:"description,omitempty"` } // Restriction describes playback or streaming limitations. type Restriction struct { Code string `json:"code"` Msg string `json:"msg,omitempty"` }