package mb import ( "encoding/json" "fmt" "net/http" "sort" "time" ) const ( apiURI = "https://musicbrainz.org/ws/2" artistSearchEndpoint = "artist?query" ) //MB holds the http client type MB struct { Client http.Client } //Search holds the search returns type Search struct { artist artistSearch } //NewMusicBrainz returns a new Search object func NewMusicBrainz() MB { var mb MB timeout := time.Duration(10 * time.Second) mb.Client = http.Client{Timeout: timeout} return mb } //SearchForArtist return a list of artists using `query` as parameter if none found returns error func (m MB) SearchForArtist(query string) (*Search, error) { var ret Search uri := fmt.Sprintf("%s/%s=%s", apiURI, artistSearchEndpoint, query) req, err := http.NewRequest( "GET", uri, nil) req.Header.Set( "User-Agent", "Go Application Development: Create spotify playlist based on artist") req.Header.Set("Content-Type", "application/json") req.Header.Set("Accept", "application/json") if err != nil { fmt.Printf("error creating request\n%v", err) return nil, err } resp, err := m.Client.Do(req) if err != nil { fmt.Printf("error opening request\n%v", err) return nil, err } defer resp.Body.Close() if err != nil { fmt.Printf("could not read body\n%v", err) return nil, err } err = json.NewDecoder(resp.Body).Decode(&ret.artist) if err != nil { fmt.Printf("could not decode body\n%v", err) return nil, err } if ret.artist.Count == 0 { return nil, fmt.Errorf("cound not found artist: %s", query) } return &ret, nil } //GetArtistName get the artist with the highest score on the search func (s Search) GetArtistName() (string, error) { if len(s.artist.Artists) == 0 { return "", fmt.Errorf("could not find any artist") } return s.artist.Artists[0].Name, nil } //GetArtistTags returns the tags in order of relevance of the current artist func (s Search) GetArtistTags() []Tags { var t []Tags for _, elem := range s.artist.Artists[0].Tags { if int(elem.Count) > 0 { t = append(t, elem) } } sort.Sort(ByInverseCount(t)) return t } type artistSearch struct { Created time.Time `json:"created"` Count int `json:"count"` Offset int `json:"offset"` Artists []artists `json:"artists"` } type area struct { ID string `json:"id"` Type string `json:"type"` TypeID string `json:"type-id"` Name string `json:"name"` SortName string `json:"sort-name"` LifeSpan struct { Ended interface{} `json:"ended"` } `json:"life-span"` } type alias struct { SortName string `json:"sort-name"` TypeID string `json:"type-id,omitempty"` Name string `json:"name"` Locale interface{} `json:"locale"` Type string `json:"type"` Primary interface{} `json:"primary"` BeginDate interface{} `json:"begin-date"` EndDate interface{} `json:"end-date"` } type artists struct { ID string `json:"id"` Type string `json:"type,omitempty"` TypeID string `json:"type-id,omitempty"` Score int `json:"score"` Name string `json:"name"` SortName string `json:"sort-name"` Country string `json:"country,omitempty"` Area area `json:"area,omitempty"` BeginArea struct { ID string `json:"id"` Type string `json:"type"` TypeID string `json:"type-id"` Name string `json:"name"` SortName string `json:"sort-name"` LifeSpan struct { Ended interface{} `json:"ended"` } `json:"life-span"` } `json:"begin-area,omitempty"` Isnis []string `json:"isnis,omitempty"` LifeSpan struct { Begin string `json:"begin"` Ended interface{} `json:"ended"` } `json:"life-span,omitempty"` Aliases []alias `json:"aliases,omitempty"` Tags []Tags `json:"tags,omitempty"` Disambiguation string `json:"disambiguation,omitempty"` } //Tags represent Artist tags (eg. Rock, Punk, Late 2000s) type Tags struct { Count int `json:"count"` Name string `json:"name"` } //ByInverseCount return the tags in relevance order type ByInverseCount []Tags func (t ByInverseCount) Len() int { return len(t) } func (t ByInverseCount) Less(i, j int) bool { return t[i].Count >= t[j].Count } func (t ByInverseCount) Swap(i, j int) { t[i], t[j] = t[j], t[i] }