diff --git a/lyrics/composer.go b/lyrics/composer.go index e84fbb2..892105d 100644 --- a/lyrics/composer.go +++ b/lyrics/composer.go @@ -13,6 +13,7 @@ var composers = []Composer{} type Composer interface { search(*entity.Track, ...context.Context) ([]byte, error) + get(string, ...context.Context) ([]byte, error) } // not found entries return no error @@ -60,3 +61,32 @@ func Search(track *entity.Track) (string, error) { return string(result), os.WriteFile(track.Path().Lyrics(), result, 0o644) } + +func Get(url string) (string, error) { + var ( + workers []nursery.ConcurrentJob + result []byte + ctxBackground = context.Background() + ctx, ctxCancel = context.WithCancel(ctxBackground) + ) + defer ctxCancel() + + for _, composer := range composers { + workers = append(workers, func(c Composer) func(context.Context, chan error) { + return func(ctx context.Context, ch chan error) { + scopedLyrics, err := c.get(url, ctx) + if err != nil { + ch <- err + return + } + + if len(scopedLyrics) > len(result) { + result = scopedLyrics + ctxCancel() + } + } + }(composer)) + } + + return string(result), nursery.RunConcurrentlyWithContext(ctx, workers...) +} diff --git a/lyrics/composer_test.go b/lyrics/composer_test.go index 019b249..8fee4ca 100644 --- a/lyrics/composer_test.go +++ b/lyrics/composer_test.go @@ -114,3 +114,38 @@ func TestSearchCannotCreateDir(t *testing.T) { // testing assert.EqualError(t, util.ErrOnly(Search(track)), "ko") } + +func TestGet(t *testing.T) { + // monkey patching + ch := make(chan bool, 1) + defer gomonkey.NewPatches(). + ApplyPrivateMethod(reflect.TypeOf(genius{}), "get", func() ([]byte, error) { + close(ch) + return []byte("glyrics"), nil + }). + ApplyPrivateMethod(reflect.TypeOf(lyricsOvh{}), "get", func() ([]byte, error) { + <-ch + return []byte("olyrics"), nil + }). + Reset() + + // testing + lyrics, err := Get("http://localhost") + assert.Nil(t, err) + assert.Equal(t, "glyrics", lyrics) +} + +func TestGetFailure(t *testing.T) { + // monkey patching + defer gomonkey.NewPatches(). + ApplyPrivateMethod(reflect.TypeOf(genius{}), "get", func() ([]byte, error) { + return nil, errors.New("ko") + }). + ApplyPrivateMethod(reflect.TypeOf(lyricsOvh{}), "get", func() ([]byte, error) { + return nil, errors.New("ko") + }). + Reset() + + // testing + assert.EqualError(t, util.ErrOnly(Get("http://localhost")), "ko") +} diff --git a/lyrics/genius.go b/lyrics/genius.go index e1bb4bb..115cfbd 100644 --- a/lyrics/genius.go +++ b/lyrics/genius.go @@ -120,10 +120,15 @@ func (composer genius) search(track *entity.Track, ctxs ...context.Context) ([]b track, context.WithValue(ctx, contextValueLabel(contextValueLabelMainArtist), true)) } - return composer.fromGeniusURL(url, ctx) + return composer.get(url, ctx) } -func (composer genius) fromGeniusURL(url string, ctx context.Context) ([]byte, error) { +func (composer genius) get(url string, ctxs ...context.Context) ([]byte, error) { + ctx := context.Background() + if len(ctxs) > 0 { + ctx = ctxs[0] + } + request, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil) if err != nil { return nil, err @@ -139,7 +144,7 @@ func (composer genius) fromGeniusURL(url string, ctx context.Context) ([]byte, e if response.StatusCode == 429 { util.SleepUntilRetry(response.Header) - return composer.fromGeniusURL(url, ctx) + return composer.get(url, ctx) } else if response.StatusCode != 200 { return nil, errors.New("cannot fetch lyrics on genius: " + response.Status) } diff --git a/lyrics/genius_test.go b/lyrics/genius_test.go index bcc2a0a..b027183 100644 --- a/lyrics/genius_test.go +++ b/lyrics/genius_test.go @@ -220,7 +220,7 @@ func TestGeniusLyricsNewRequestFailure(t *testing.T) { }).Reset() // testing - assert.EqualError(t, util.ErrOnly(genius{}.fromGeniusURL("http://genius.com/test", context.Background())), "ko") + assert.EqualError(t, util.ErrOnly(genius{}.get("http://genius.com/test", context.Background())), "ko") } func TestGeniusLyricsNewRequestContextCanceled(t *testing.T) { diff --git a/lyrics/lyricsovh.go b/lyrics/lyricsovh.go index 122dcc6..946099e 100644 --- a/lyrics/lyricsovh.go +++ b/lyrics/lyricsovh.go @@ -31,9 +31,18 @@ func (composer lyricsOvh) search(track *entity.Track, ctxs ...context.Context) ( ctx = ctxs[0] } - request, err := http.NewRequestWithContext(ctx, http.MethodGet, fmt.Sprintf("https://api.lyrics.ovh/v1/%s/%s", + return composer.get(fmt.Sprintf("https://api.lyrics.ovh/v1/%s/%s", url.QueryEscape(track.Artists[0]), - url.QueryEscape(track.Title)), nil) + url.QueryEscape(track.Title)), ctx) +} + +func (composer lyricsOvh) get(url string, ctxs ...context.Context) ([]byte, error) { + ctx := context.Background() + if len(ctxs) > 0 { + ctx = ctxs[0] + } + + request, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil) if err != nil { return nil, err } @@ -50,7 +59,7 @@ func (composer lyricsOvh) search(track *entity.Track, ctxs ...context.Context) ( return nil, nil } else if response.StatusCode == 429 { util.SleepUntilRetry(response.Header) - return composer.search(track, ctx) + return composer.get(url, ctx) } else if response.StatusCode != 200 { return nil, errors.New("cannot fetch results on lyrics.ovh: " + response.Status) }