Browse Source

feat: added songlyrics support, modified interface

pull/1/head
Rohan Verma 4 years ago
parent
commit
cbc94fefc1
  1. 8
      example/search.go
  2. 4
      goquery_helpers/helpers.go
  3. 90
      lyrics.go
  4. 31
      songlyrics/fetch.go
  5. 45
      songlyrics/fetch_test.go

8
example/search.go

@ -12,5 +12,11 @@ func main() {
song = "Imagine"
)
fmt.Println(lyrics.Fetch(artist, song))
l := lyrics.New()
lyric, err := l.Search(artist, song)
if err != nil {
fmt.Printf("Lyrics for %v-%v were not found", artist, song)
}
fmt.Println(lyric)
}

4
goquery_helpers/helpers.go

@ -7,6 +7,10 @@ import (
"golang.org/x/net/html"
)
// RenderSelection is a helper function modified from
// github.com/PuerkitoBio/goquery - Text() function
// it expects and additional separator to add between each
// line.
func RenderSelection(s *goquery.Selection, seperator string) string {
var buf bytes.Buffer
var f func(*html.Node)

90
lyrics.go

@ -1,15 +1,93 @@
package lyrics
import (
"errors"
"github.com/rhnvrm/lyric-api-go/lyricswikia"
"github.com/rhnvrm/lyric-api-go/songlyrics"
)
// Fetch attempts to search for lyrics using artist and song
// by trying various lyrics providers.
type provider func(artist, song string) string
// Supported Providers:
// - Lyrics Wikia (github.com/rhnvrm/lyric-api-go/lyricswikia)
// - Lyrics Wikia (github.com/rhnvrm/lyric-api-go/lyricswikia)
// - Song Lyrics (github.com/rhnvrm/lyric-api-go/songlyrics)
var defaultProviders = []provider{
lyricswikia.Fetch,
songlyrics.Fetch,
}
// Lyric API.
type Lyric struct {
providers []provider
}
// Option type describes Option Configuration Decorator return type.
type Option func(Lyric) Lyric
// WithAllProviders is an Option Configuration Decorator that sets
// Lyric to attempt fetching lyrics using all providers.
func WithAllProviders() Option {
return func(l Lyric) Lyric {
l.providers = defaultProviders
return l
}
}
// WithLyricsWikia is an Option Configuration Decorator that adds
// Lyrics Wikia Provider to the list of providers to attempt fetching
// lyrics from.
func WithLyricsWikia() Option {
return func(l Lyric) Lyric {
l.providers = append(l.providers, lyricswikia.Fetch)
return l
}
}
// WithSongLyrics is an Option Configuration Decorator that adds
// Song Lyrics Provider to the list of providers to attempt fetching
// lyrics from.
func WithSongLyrics() Option {
return func(l Lyric) Lyric {
l.providers = append(l.providers, songlyrics.Fetch)
return l
}
}
// New creates a new Lyric API, which can be used to Search for Lyrics
// using various providers. The default behaviour is to use all
// providers available, although it can be explicitly set to the same
// using, eg.
// lyrics.New(WithAllProviders())
// In case your usecase requires using only specific providers,
// you can provide New() with
// the specific WithXXXXProvider() as an optional parameter.
//
// Eg. to attempt only with Lyrics Wikia:
// lyrics.New(WithLyricsWikia())
//
// (support for other providers will be added in the future)
func Fetch(artist, song string) string {
return lyricswikia.Fetch(artist, song)
// Eg. to attempt with both Lyrics Wikia and Song Lyrics:
// lyrics.New(WithLyricsWikia(), WithSongLyrics())
func New(o ...Option) Lyric {
l := Lyric{
providers: defaultProviders,
}
for _, option := range o {
l = option(l)
}
return l
}
// Search attempts to search for lyrics using artist and song
// by trying various lyrics providers one by one.
func (l *Lyric) Search(artist, song string) (string, error) {
for _, p := range l.providers {
lyric := p(artist, song)
if len(lyric) > 5 { // Arbitrary size to make sure not empty.
return lyric, nil
}
}
return "", errors.New("Not Found")
}

31
songlyrics/fetch.go

@ -0,0 +1,31 @@
package songlyrics
import (
"log"
"net/http"
"github.com/PuerkitoBio/goquery"
"github.com/gosimple/slug"
"github.com/rhnvrm/lyric-api-go/goquery_helpers"
)
// Fetch scrapes Lyrics Wikia by based on Artist and Song.
func Fetch(artist, song string) string {
url := "http://www.songlyrics.com/" + slug.Make(artist) + "/" + slug.Make(song) + "-lyrics/"
// Make HTTP request
response, err := http.Get(url)
if err != nil {
log.Fatal(err)
}
defer response.Body.Close()
// Create a goquery document from the HTTP response
document, err := goquery.NewDocumentFromReader(response.Body)
if err != nil {
log.Fatal("Error loading HTTP response body. ", err)
}
result := document.Find("#songLyricsDiv").First()
return goquery_helpers.RenderSelection(result, "")
}

45
songlyrics/fetch_test.go

@ -0,0 +1,45 @@
package songlyrics
import (
"testing"
. "github.com/smartystreets/goconvey/convey"
)
func TestFetch(t *testing.T) {
type args struct {
artist string
song string
}
Convey("For each song in the test cases", t, func() {
tests := []struct {
name string
args args
want string
}{
{
name: "Linkin Park - Numb",
args: args{
artist: "Linkin Park",
song: "Numb",
},
want: `And every second I waste is more than I can take`,
},
{
name: "John Lennon - Imagine",
args: args{
artist: "John Lennon",
song: "Imagine",
},
want: `No need for greed or hunger`,
},
}
Convey("Want should be a substring of Got", func() {
for _, tt := range tests {
So(Fetch(tt.args.artist, tt.args.song), ShouldContainSubstring, tt.want)
}
})
})
}
Loading…
Cancel
Save