2024-03-04 14:59:47 +01:00
|
|
|
package data
|
2022-06-30 21:32:56 +01:00
|
|
|
|
|
|
|
import (
|
2023-03-12 12:37:35 +01:00
|
|
|
"encoding/json"
|
2022-06-30 21:32:56 +01:00
|
|
|
"fmt"
|
2022-10-08 22:46:48 +01:00
|
|
|
"strings"
|
2022-06-30 21:32:56 +01:00
|
|
|
|
|
|
|
"github.com/PuerkitoBio/goquery"
|
2024-05-03 12:45:58 +01:00
|
|
|
"github.com/rramiachraf/dumb/utils"
|
2022-06-30 21:32:56 +01:00
|
|
|
)
|
|
|
|
|
2024-03-04 14:59:47 +01:00
|
|
|
type Song struct {
|
2024-03-04 17:41:01 +01:00
|
|
|
Artist string
|
|
|
|
Title string
|
|
|
|
Image string
|
|
|
|
Lyrics string
|
|
|
|
Credits map[string]string
|
|
|
|
About [2]string
|
|
|
|
Album struct {
|
|
|
|
URL string
|
|
|
|
Name string
|
|
|
|
Image string
|
|
|
|
}
|
2022-06-30 21:32:56 +01:00
|
|
|
}
|
|
|
|
|
2023-03-12 12:37:35 +01:00
|
|
|
type songResponse struct {
|
|
|
|
Response struct {
|
|
|
|
Song struct {
|
|
|
|
ArtistNames string `json:"artist_names"`
|
|
|
|
Image string `json:"song_art_image_thumbnail_url"`
|
|
|
|
Title string
|
|
|
|
Description struct {
|
|
|
|
Plain string
|
|
|
|
}
|
2023-09-05 16:47:21 -04:00
|
|
|
Album struct {
|
2024-03-04 17:41:01 +01:00
|
|
|
URL string `json:"url"`
|
|
|
|
Name string `json:"name"`
|
|
|
|
Image string `json:"cover_art_url"`
|
2023-09-05 16:47:21 -04:00
|
|
|
}
|
2023-03-12 12:37:35 +01:00
|
|
|
CustomPerformances []customPerformance `json:"custom_performances"`
|
2024-05-12 16:14:33 -06:00
|
|
|
WriterArtists []struct {
|
|
|
|
Name string
|
|
|
|
} `json:"writer_artists"`
|
|
|
|
ProducerArtists []struct {
|
|
|
|
Name string
|
|
|
|
} `json:"producer_artists"`
|
2023-03-12 12:37:35 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
type customPerformance struct {
|
|
|
|
Label string
|
|
|
|
Artists []struct {
|
|
|
|
Name string
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-05-02 21:29:50 +01:00
|
|
|
func (s *Song) parseLyrics(doc *goquery.Document) error {
|
|
|
|
var htmlError error
|
|
|
|
|
2022-06-30 21:32:56 +01:00
|
|
|
doc.Find("[data-lyrics-container='true']").Each(func(i int, ss *goquery.Selection) {
|
2023-01-22 16:19:35 +01:00
|
|
|
h, err := ss.Html()
|
|
|
|
if err != nil {
|
2024-05-02 21:29:50 +01:00
|
|
|
htmlError = err
|
2022-06-30 21:32:56 +01:00
|
|
|
}
|
2023-01-22 16:19:35 +01:00
|
|
|
s.Lyrics += h
|
2022-06-30 21:32:56 +01:00
|
|
|
})
|
2024-05-02 21:29:50 +01:00
|
|
|
|
|
|
|
if htmlError != nil {
|
|
|
|
return htmlError
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
2022-06-30 21:32:56 +01:00
|
|
|
}
|
|
|
|
|
2024-05-02 21:29:50 +01:00
|
|
|
func (s *Song) parseSongData(doc *goquery.Document) error {
|
2023-03-12 12:37:35 +01:00
|
|
|
attr, exists := doc.Find("meta[property='twitter:app:url:iphone']").Attr("content")
|
2022-06-30 21:32:56 +01:00
|
|
|
if exists {
|
2023-03-12 12:37:35 +01:00
|
|
|
songID := strings.Replace(attr, "genius://songs/", "", 1)
|
2023-09-05 16:47:21 -04:00
|
|
|
|
2023-03-12 12:37:35 +01:00
|
|
|
u := fmt.Sprintf("https://genius.com/api/songs/%s?text_format=plain", songID)
|
2022-06-30 21:32:56 +01:00
|
|
|
|
2024-05-03 12:45:58 +01:00
|
|
|
res, err := utils.SendRequest(u)
|
2023-03-12 12:37:35 +01:00
|
|
|
if err != nil {
|
2024-05-02 21:29:50 +01:00
|
|
|
return err
|
2023-03-12 12:37:35 +01:00
|
|
|
}
|
2022-06-30 21:32:56 +01:00
|
|
|
|
2023-03-12 12:37:35 +01:00
|
|
|
defer res.Body.Close()
|
2022-07-02 17:06:29 +01:00
|
|
|
|
2023-03-12 12:37:35 +01:00
|
|
|
var data songResponse
|
|
|
|
decoder := json.NewDecoder(res.Body)
|
|
|
|
err = decoder.Decode(&data)
|
|
|
|
if err != nil {
|
2024-05-02 21:29:50 +01:00
|
|
|
return err
|
2023-03-12 12:37:35 +01:00
|
|
|
}
|
2022-07-02 17:06:29 +01:00
|
|
|
|
2023-03-12 12:37:35 +01:00
|
|
|
songData := data.Response.Song
|
|
|
|
s.Artist = songData.ArtistNames
|
|
|
|
s.Image = songData.Image
|
|
|
|
s.Title = songData.Title
|
|
|
|
s.About[0] = songData.Description.Plain
|
|
|
|
s.About[1] = truncateText(songData.Description.Plain)
|
|
|
|
s.Credits = make(map[string]string)
|
2024-03-04 17:41:01 +01:00
|
|
|
s.Album.Name = songData.Album.Name
|
|
|
|
s.Album.URL = strings.Replace(songData.Album.URL, "https://genius.com", "", -1)
|
|
|
|
s.Album.Image = ExtractImageURL(songData.Album.Image)
|
2023-03-12 12:37:35 +01:00
|
|
|
|
2024-05-12 16:14:33 -06:00
|
|
|
s.Credits["Writers"] = joinNames(songData.WriterArtists)
|
|
|
|
s.Credits["Producers"] = joinNames(songData.ProducerArtists)
|
2023-03-12 12:37:35 +01:00
|
|
|
for _, perf := range songData.CustomPerformances {
|
2024-05-12 16:14:33 -06:00
|
|
|
s.Credits[perf.Label] = joinNames(perf.Artists)
|
2023-03-12 12:37:35 +01:00
|
|
|
}
|
|
|
|
}
|
2024-05-02 21:29:50 +01:00
|
|
|
|
|
|
|
return nil
|
2022-07-02 17:06:29 +01:00
|
|
|
}
|
|
|
|
|
2024-05-12 16:14:33 -06:00
|
|
|
func joinNames(data []struct {
|
|
|
|
Name string
|
|
|
|
}) string {
|
|
|
|
var names []string
|
|
|
|
for _, hasName := range data {
|
|
|
|
names = append(names, hasName.Name)
|
|
|
|
}
|
|
|
|
return strings.Join(names, ", ")
|
|
|
|
}
|
|
|
|
|
2023-03-12 12:37:35 +01:00
|
|
|
func truncateText(text string) string {
|
|
|
|
textArr := strings.Split(text, "")
|
2022-10-08 22:46:48 +01:00
|
|
|
|
2023-03-12 12:37:35 +01:00
|
|
|
if len(textArr) > 250 {
|
|
|
|
return strings.Join(textArr[0:250], "") + "..."
|
2022-10-08 22:46:48 +01:00
|
|
|
}
|
2023-03-12 12:37:35 +01:00
|
|
|
|
|
|
|
return text
|
2022-07-02 17:06:29 +01:00
|
|
|
}
|
|
|
|
|
2024-05-02 21:29:50 +01:00
|
|
|
func (s *Song) Parse(doc *goquery.Document) error {
|
|
|
|
if err := s.parseLyrics(doc); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := s.parseSongData(doc); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
2022-06-30 21:32:56 +01:00
|
|
|
}
|