mb.go 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. package mb
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "net/http"
  6. "net/url"
  7. "sort"
  8. "time"
  9. )
  10. const (
  11. apiURI = "https://musicbrainz.org/ws/2"
  12. artistSearchEndpoint = "artist?query"
  13. )
  14. //MB holds the http client
  15. type MB struct {
  16. Client http.Client
  17. }
  18. //Search holds the search returns
  19. type Search struct {
  20. artist artistSearch
  21. }
  22. //NewMusicBrainz returns a new Search object
  23. func NewMusicBrainz() MB {
  24. var mb MB
  25. timeout := time.Duration(10 * time.Second)
  26. mb.Client = http.Client{Timeout: timeout}
  27. return mb
  28. }
  29. //SearchForArtist return a list of artists using `query` as parameter if none found returns error
  30. func (m MB) SearchForArtist(query string) (*Search, error) {
  31. var ret Search
  32. uri := fmt.Sprintf("%s/%s=%s", apiURI, artistSearchEndpoint, url.QueryEscape(query))
  33. req, err := http.NewRequest(
  34. "GET",
  35. uri,
  36. nil)
  37. req.Header.Set(
  38. "User-Agent",
  39. "Go Application Development: Create spotify playlist based on artist")
  40. req.Header.Set("Content-Type", "application/json")
  41. req.Header.Set("Accept", "application/json")
  42. if err != nil {
  43. fmt.Printf("error creating request\n%v", err)
  44. return nil, err
  45. }
  46. resp, err := m.Client.Do(req)
  47. if err != nil {
  48. fmt.Printf("error opening request\n%v", err)
  49. return nil, err
  50. }
  51. defer resp.Body.Close()
  52. if err != nil {
  53. fmt.Printf("could not read body\n%v", err)
  54. return nil, err
  55. }
  56. err = json.NewDecoder(resp.Body).Decode(&ret.artist)
  57. if err != nil {
  58. fmt.Printf("could not decode body\n%v", err)
  59. return nil, err
  60. }
  61. if ret.artist.Count == 0 {
  62. return nil, fmt.Errorf("cound not found artist: %s", query)
  63. }
  64. return &ret, nil
  65. }
  66. //GetArtistName get the artist with the highest score on the search
  67. func (s Search) GetArtistName() (string, error) {
  68. if len(s.artist.Artists) == 0 {
  69. return "", fmt.Errorf("could not find any artist")
  70. }
  71. return s.artist.Artists[0].Name, nil
  72. }
  73. //GetArtistTags returns the tags in order of relevance of the current artist
  74. func (s Search) GetArtistTags() []Tags {
  75. var t []Tags
  76. for _, elem := range s.artist.Artists[0].Tags {
  77. if int(elem.Count) > 0 {
  78. t = append(t, elem)
  79. }
  80. }
  81. sort.Sort(ByInverseCount(t))
  82. return t
  83. }
  84. type artistSearch struct {
  85. Created time.Time `json:"created"`
  86. Count int `json:"count"`
  87. Offset int `json:"offset"`
  88. Artists []artists `json:"artists"`
  89. }
  90. type area struct {
  91. ID string `json:"id"`
  92. Type string `json:"type"`
  93. TypeID string `json:"type-id"`
  94. Name string `json:"name"`
  95. SortName string `json:"sort-name"`
  96. LifeSpan struct {
  97. Ended interface{} `json:"ended"`
  98. } `json:"life-span"`
  99. }
  100. type alias struct {
  101. SortName string `json:"sort-name"`
  102. TypeID string `json:"type-id,omitempty"`
  103. Name string `json:"name"`
  104. Locale interface{} `json:"locale"`
  105. Type string `json:"type"`
  106. Primary interface{} `json:"primary"`
  107. BeginDate interface{} `json:"begin-date"`
  108. EndDate interface{} `json:"end-date"`
  109. }
  110. type artists struct {
  111. ID string `json:"id"`
  112. Type string `json:"type,omitempty"`
  113. TypeID string `json:"type-id,omitempty"`
  114. Score int `json:"score"`
  115. Name string `json:"name"`
  116. SortName string `json:"sort-name"`
  117. Country string `json:"country,omitempty"`
  118. Area area `json:"area,omitempty"`
  119. BeginArea struct {
  120. ID string `json:"id"`
  121. Type string `json:"type"`
  122. TypeID string `json:"type-id"`
  123. Name string `json:"name"`
  124. SortName string `json:"sort-name"`
  125. LifeSpan struct {
  126. Ended interface{} `json:"ended"`
  127. } `json:"life-span"`
  128. } `json:"begin-area,omitempty"`
  129. Isnis []string `json:"isnis,omitempty"`
  130. LifeSpan struct {
  131. Begin string `json:"begin"`
  132. Ended interface{} `json:"ended"`
  133. } `json:"life-span,omitempty"`
  134. Aliases []alias `json:"aliases,omitempty"`
  135. Tags []Tags `json:"tags,omitempty"`
  136. Disambiguation string `json:"disambiguation,omitempty"`
  137. }
  138. //Tags represent Artist tags (eg. Rock, Punk, Late 2000s)
  139. type Tags struct {
  140. Count int `json:"count"`
  141. Name string `json:"name"`
  142. }
  143. //ByInverseCount return the tags in relevance order
  144. type ByInverseCount []Tags
  145. func (t ByInverseCount) Len() int { return len(t) }
  146. func (t ByInverseCount) Less(i, j int) bool { return t[i].Count >= t[j].Count }
  147. func (t ByInverseCount) Swap(i, j int) { t[i], t[j] = t[j], t[i] }