musicbrainz.go (2817B)
1 package musicbrainz 2 3 import ( 4 "context" 5 "encoding/json" 6 "fmt" 7 "net/http" 8 "time" 9 ) 10 11 type CoverArtQuality string 12 13 const ( 14 CoverArtQuality250 CoverArtQuality = "250" 15 CoverArtQuality500 CoverArtQuality = "500" 16 CoverArtQuality1200 CoverArtQuality = "1200" 17 CoverArtQualitySmall CoverArtQuality = "small" 18 CoverArtQualityLarge CoverArtQuality = "large" 19 CoverArtQualityOriginal CoverArtQuality = "original" 20 ) 21 22 type CoverArtResponse struct { 23 Images []CoverArtImage `json:"images"` 24 } 25 26 type CoverArtImage struct { 27 Front bool `json:"front"` 28 Approved bool `json:"approved"` 29 Image string `json:"image"` 30 Thumbnails map[string]string `json:"thumbnails"` 31 } 32 33 type CoverArt struct { 34 URL string 35 Quality CoverArtQuality 36 } 37 38 var client = &http.Client{ 39 Timeout: 5 * time.Second, 40 } 41 42 func FetchCoverArt(ctx context.Context, mbid string, quality CoverArtQuality) (*CoverArt, error) { 43 req, err := http.NewRequestWithContext( 44 ctx, 45 http.MethodGet, 46 "https://coverartarchive.org/release/"+mbid, 47 nil, 48 ) 49 if err != nil { 50 return nil, err 51 } 52 53 req.Header.Set("Accept", "application/json") 54 req.Header.Set("User-Agent", "lyrics/0.1") 55 56 res, err := client.Do(req) 57 if err != nil { 58 return nil, err 59 } 60 defer res.Body.Close() 61 62 if res.StatusCode == http.StatusNotFound { 63 return nil, nil 64 } 65 if res.StatusCode < 200 || res.StatusCode >= 300 { 66 return nil, fmt.Errorf("cover art request failed: %s", res.Status) 67 } 68 69 var data CoverArtResponse 70 if err := json.NewDecoder(res.Body).Decode(&data); err != nil { 71 return nil, err 72 } 73 74 for _, image := range data.Images { 75 if !image.Front { 76 continue 77 } 78 79 url, actualQuality := coverArtURL(image, quality) 80 if url == "" { 81 return nil, nil 82 } 83 84 return &CoverArt{ 85 URL: url, 86 Quality: actualQuality, 87 }, nil 88 } 89 90 return nil, nil 91 } 92 93 func coverArtURL(image CoverArtImage, quality CoverArtQuality) (string, CoverArtQuality) { 94 switch quality { 95 case CoverArtQualityOriginal: 96 if image.Image != "" { 97 return image.Image, CoverArtQualityOriginal 98 } 99 fallthrough 100 case CoverArtQuality1200: 101 if url := image.Thumbnails["1200"]; url != "" { 102 return url, CoverArtQuality1200 103 } 104 fallthrough 105 case CoverArtQualityLarge: 106 if url := image.Thumbnails["large"]; url != "" { 107 return url, CoverArtQuality500 108 } 109 fallthrough 110 case CoverArtQuality500: 111 if url := image.Thumbnails["500"]; url != "" { 112 return url, CoverArtQuality500 113 } 114 fallthrough 115 case CoverArtQualitySmall: 116 if url := image.Thumbnails["small"]; url != "" { 117 return url, CoverArtQuality250 118 } 119 fallthrough 120 case CoverArtQuality250: 121 if url := image.Thumbnails["250"]; url != "" { 122 return url, CoverArtQuality250 123 } 124 } 125 126 if image.Image != "" { 127 return image.Image, CoverArtQualityOriginal 128 } 129 130 return "", "" 131 }