mirror of https://github.com/gabehf/Koito.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
97 lines
2.8 KiB
97 lines
2.8 KiB
// package mbz provides functions for interacting with the musicbrainz api
|
|
package mbz
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"io"
|
|
"net/http"
|
|
|
|
"github.com/gabehf/koito/internal/cfg"
|
|
"github.com/gabehf/koito/internal/logger"
|
|
"github.com/gabehf/koito/queue"
|
|
"github.com/google/uuid"
|
|
)
|
|
|
|
type MusicBrainzArea struct {
|
|
Name string `json:"name"`
|
|
Iso3166_1Codes []string `json:"iso-3166-1-codes"`
|
|
}
|
|
|
|
type MusicBrainzClient struct {
|
|
url string
|
|
userAgent string
|
|
requestQueue *queue.RequestQueue
|
|
}
|
|
|
|
type MusicBrainzCaller interface {
|
|
GetArtistPrimaryAliases(ctx context.Context, id uuid.UUID) ([]string, error)
|
|
GetReleaseTitles(ctx context.Context, RGID uuid.UUID) ([]string, error)
|
|
GetTrack(ctx context.Context, id uuid.UUID) (*MusicBrainzTrack, error)
|
|
GetReleaseGroup(ctx context.Context, id uuid.UUID) (*MusicBrainzReleaseGroup, error)
|
|
GetRelease(ctx context.Context, id uuid.UUID) (*MusicBrainzRelease, error)
|
|
Shutdown()
|
|
}
|
|
|
|
func NewMusicBrainzClient() *MusicBrainzClient {
|
|
ret := new(MusicBrainzClient)
|
|
ret.url = cfg.MusicBrainzUrl()
|
|
ret.userAgent = cfg.UserAgent()
|
|
ret.requestQueue = queue.NewRequestQueue(cfg.MusicBrainzRateLimit(), cfg.MusicBrainzRateLimit())
|
|
return ret
|
|
}
|
|
|
|
func (c *MusicBrainzClient) Shutdown() {
|
|
c.requestQueue.Shutdown()
|
|
}
|
|
|
|
func (c *MusicBrainzClient) getEntity(ctx context.Context, fmtStr string, id uuid.UUID, result any) error {
|
|
l := logger.FromContext(ctx)
|
|
url := fmt.Sprintf(fmtStr, c.url, id.String())
|
|
req, err := http.NewRequest("GET", url, nil)
|
|
if err != nil {
|
|
l.Err(err).Msg("Failed to build MusicBrainz request")
|
|
return fmt.Errorf("getEntity: %w", err)
|
|
}
|
|
l.Debug().Msg("Adding MusicBrainz request to queue")
|
|
body, err := c.queue(ctx, req)
|
|
if err != nil {
|
|
l.Err(err).Msg("MusicBrainz request failed")
|
|
return fmt.Errorf("getEntity: %w", err)
|
|
}
|
|
|
|
err = json.Unmarshal(body, result)
|
|
if err != nil {
|
|
l.Err(err).Str("body", string(body)).Msg("Failed to unmarshal MusicBrainz response body")
|
|
return fmt.Errorf("getEntity: %w", err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (c *MusicBrainzClient) queue(ctx context.Context, req *http.Request) ([]byte, error) {
|
|
l := logger.FromContext(ctx)
|
|
req.Header.Set("User-Agent", c.userAgent)
|
|
req.Header.Set("Accept", "application/json")
|
|
|
|
resultChan := c.requestQueue.Enqueue(func(client *http.Client, done chan<- queue.RequestResult) {
|
|
resp, err := client.Do(req)
|
|
if err != nil {
|
|
l.Err(err).Str("url", req.RequestURI).Msg("Failed to contact MusicBrainz")
|
|
done <- queue.RequestResult{Err: err}
|
|
return
|
|
} else if resp.StatusCode >= 300 || resp.StatusCode < 200 {
|
|
err = fmt.Errorf("recieved non-ok status from MusicBrainz: %s", resp.Status)
|
|
done <- queue.RequestResult{Body: nil, Err: err}
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
body, err := io.ReadAll(resp.Body)
|
|
done <- queue.RequestResult{Body: body, Err: err}
|
|
})
|
|
|
|
result := <-resultChan
|
|
return result.Body, result.Err
|
|
}
|