mb.go 4.2 KB

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