2022-06-30 20:32:56 +00:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"net/http"
|
2022-10-11 13:23:10 +00:00
|
|
|
"net/url"
|
2022-06-30 20:32:56 +00:00
|
|
|
"path"
|
2022-10-08 21:46:48 +00:00
|
|
|
"strings"
|
2022-06-30 20:32:56 +00:00
|
|
|
"text/template"
|
|
|
|
|
|
|
|
"github.com/PuerkitoBio/goquery"
|
|
|
|
"github.com/gorilla/mux"
|
|
|
|
)
|
|
|
|
|
|
|
|
type song struct {
|
2022-07-02 16:06:29 +00:00
|
|
|
Artist string
|
|
|
|
Title string
|
|
|
|
Image string
|
|
|
|
Lyrics string
|
|
|
|
Credits map[string]string
|
2022-10-08 21:46:48 +00:00
|
|
|
About [2]string
|
2022-06-30 20:32:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (s *song) parseLyrics(doc *goquery.Document) {
|
|
|
|
doc.Find("[data-lyrics-container='true']").Each(func(i int, ss *goquery.Selection) {
|
2022-07-02 16:06:29 +00:00
|
|
|
if h, err := ss.Html(); err == nil {
|
|
|
|
s.Lyrics += h
|
2022-06-30 20:32:56 +00:00
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *song) parseMetadata(doc *goquery.Document) {
|
|
|
|
artist := doc.Find("a[class*='Artist']").First().Text()
|
|
|
|
title := doc.Find("h1[class*='Title']").First().Text()
|
|
|
|
image, exists := doc.Find("meta[property='og:image']").Attr("content")
|
|
|
|
if exists {
|
2022-10-11 13:23:10 +00:00
|
|
|
if u, err := url.Parse(image); err == nil {
|
|
|
|
s.Image = fmt.Sprintf("/images%s", u.Path)
|
|
|
|
}
|
2022-06-30 20:32:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
s.Title = title
|
|
|
|
s.Artist = artist
|
|
|
|
}
|
|
|
|
|
2022-07-02 16:06:29 +00:00
|
|
|
func (s *song) parseCredits(doc *goquery.Document) {
|
|
|
|
credits := make(map[string]string)
|
|
|
|
|
|
|
|
doc.Find("[class*='SongInfo__Credit']").Each(func(i int, ss *goquery.Selection) {
|
|
|
|
key := ss.Children().First().Text()
|
|
|
|
value := ss.Children().Last().Text()
|
|
|
|
credits[key] = value
|
|
|
|
})
|
|
|
|
|
|
|
|
s.Credits = credits
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *song) parseAbout(doc *goquery.Document) {
|
2022-10-08 21:46:48 +00:00
|
|
|
s.About[0] = doc.Find("[class*='SongDescription__Content']").Text()
|
|
|
|
summary := strings.Split(s.About[0], "")
|
|
|
|
|
|
|
|
if len(summary) > 250 {
|
|
|
|
s.About[1] = strings.Join(summary[0:250], "") + "..."
|
|
|
|
}
|
2022-07-02 16:06:29 +00:00
|
|
|
}
|
|
|
|
|
2022-06-30 20:32:56 +00:00
|
|
|
func (s *song) parse(doc *goquery.Document) {
|
|
|
|
s.parseLyrics(doc)
|
|
|
|
s.parseMetadata(doc)
|
2022-07-02 16:06:29 +00:00
|
|
|
s.parseCredits(doc)
|
|
|
|
s.parseAbout(doc)
|
2022-06-30 20:32:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func lyricsHandler(w http.ResponseWriter, r *http.Request) {
|
|
|
|
id := mux.Vars(r)["id"]
|
|
|
|
|
2022-07-01 22:40:13 +00:00
|
|
|
if data, err := getCache(id); err == nil {
|
|
|
|
render(w, data)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2022-06-30 20:32:56 +00:00
|
|
|
url := fmt.Sprintf("https://genius.com/%s-lyrics", id)
|
|
|
|
resp, err := http.Get(url)
|
|
|
|
if err != nil {
|
|
|
|
write(w, http.StatusInternalServerError, []byte("can't reach genius servers"))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if resp.StatusCode == http.StatusNotFound {
|
|
|
|
write(w, http.StatusNotFound, []byte("Not found"))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
doc, err := goquery.NewDocumentFromReader(resp.Body)
|
|
|
|
if err != nil {
|
|
|
|
write(w, http.StatusInternalServerError, []byte("something went wrong"))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
var s song
|
|
|
|
s.parse(doc)
|
|
|
|
|
|
|
|
w.Header().Set("content-type", "text/html")
|
|
|
|
t, err := template.ParseFiles(path.Join("views", "lyrics.tmpl"))
|
|
|
|
if err != nil {
|
|
|
|
write(w, http.StatusInternalServerError, []byte("something went wrong"))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
t.Execute(w, s)
|
2022-07-01 22:40:13 +00:00
|
|
|
setCache(id, s)
|
2022-06-30 20:32:56 +00:00
|
|
|
}
|