From 3e50e52d5e24a3a20739228c38190a624c407430 Mon Sep 17 00:00:00 2001 From: rramiachraf <51409801+rramiachraf@users.noreply.github.com> Date: Sat, 13 Jul 2024 22:06:26 +0100 Subject: [PATCH] chore: second attempt to sync branch with latest changes --- album.go | 146 ---------------------------------------- annotations.go | 131 ------------------------------------ go.sum | 1 - lyrics.go | 176 ------------------------------------------------- main.go | 33 ---------- proxy.go | 77 ---------------------- search.go | 64 ------------------ 7 files changed, 628 deletions(-) delete mode 100644 album.go delete mode 100644 annotations.go delete mode 100644 lyrics.go delete mode 100644 proxy.go delete mode 100644 search.go diff --git a/album.go b/album.go deleted file mode 100644 index 7f48982..0000000 --- a/album.go +++ /dev/null @@ -1,146 +0,0 @@ -package main - -import ( - "encoding/json" - "fmt" - "net/http" - "strings" - - "github.com/PuerkitoBio/goquery" - "github.com/gorilla/mux" -) - -type album struct { - Artist string - Name string - Image string - About [2]string - - Tracks []Track -} - -type Track struct { - Title string - Url string -} - -type albumMetadata struct { - Album struct { - Id int `json:"id"` - Image string `json:"cover_art_thumbnail_url"` - Name string `json:"name"` - Description string `json:"description_preview"` - Artist `json:"artist"` - } - AlbumAppearances []AlbumAppearances `json:"album_appearances"` -} - -type AlbumAppearances struct { - Id int `json:"id"` - TrackNumber int `json:"track_number"` - Song struct { - Title string `json:"title"` - Url string `json:"url"` - } -} - -type Artist struct { - Name string `json:"name"` -} - -func (a *album) parseAlbumData(doc *goquery.Document) { - pageMetadata, exists := doc.Find("meta[itemprop='page_data']").Attr("content") - if !exists { - return - } - - var albumMetadataFromPage albumMetadata - err := json.Unmarshal([]byte(pageMetadata), &albumMetadataFromPage) - if err != nil { - logger.Errorln(err) - } - - albumData := albumMetadataFromPage.Album - a.Artist = albumData.Artist.Name - a.Name = albumData.Name - a.Image = albumData.Image - a.About[0] = albumData.Description - a.About[1] = truncateText(albumData.Description) - - for _, track := range albumMetadataFromPage.AlbumAppearances { - url := strings.Replace(track.Song.Url, "https://genius.com", "", -1) - a.Tracks = append(a.Tracks, Track{Title: track.Song.Title, Url: url}) - } -} - -func (a *album) parse(doc *goquery.Document) { - a.parseAlbumData(doc) -} - -func albumHandler(w http.ResponseWriter, r *http.Request) { - artist := mux.Vars(r)["artist"] - albumName := mux.Vars(r)["albumName"] - - id := fmt.Sprintf("%s/%s", artist, albumName) - - if data, err := getCache(id); err == nil { - render("album", w, data) - return - } - - url := fmt.Sprintf("https://genius.com/albums/%s/%s", artist, albumName) - - resp, err := sendRequest(url) - if err != nil { - logger.Errorln(err) - w.WriteHeader(http.StatusInternalServerError) - render("error", w, map[string]string{ - "Status": "500", - "Error": "cannot reach genius servers", - }) - return - } - - defer resp.Body.Close() - - if resp.StatusCode == http.StatusNotFound { - w.WriteHeader(http.StatusNotFound) - render("error", w, map[string]string{ - "Status": "404", - "Error": "page not found", - }) - return - } - - doc, err := goquery.NewDocumentFromReader(resp.Body) - if err != nil { - logger.Errorln(err) - w.WriteHeader(http.StatusInternalServerError) - render("error", w, map[string]string{ - "Status": "500", - "Error": "something went wrong", - }) - return - } - - cf := doc.Find(".cloudflare_content").Length() - if cf > 0 { - logger.Errorln("cloudflare got in the way") - render("error", w, map[string]string{ - "Status": "500", - "Error": "damn cloudflare, issue #21 on GitHub", - }) - return - } - - var a album - a.parse(doc) - - render("album", w, a) - - err = setCache(id, a) - if err != nil { - logger.Errorln(err) - } - -} diff --git a/annotations.go b/annotations.go deleted file mode 100644 index 715c9ec..0000000 --- a/annotations.go +++ /dev/null @@ -1,131 +0,0 @@ -package main - -import ( - "bytes" - "encoding/json" - "fmt" - "net/http" - "regexp" - "strings" - - "github.com/gorilla/mux" -) - -type annotationsResponse struct { - Response struct { - Referent struct { - Annotations []struct { - Body struct { - Html string `json:"html"` - } `json:"body"` - } `json:"annotations"` - } `json:"referent"` - } `json:"response"` -} - -func annotationsHandler(w http.ResponseWriter, r *http.Request) { - id := mux.Vars(r)["id"] - - if data, err := getCache(id); err == nil { - - response, err := json.Marshal(data) - - if err != nil { - logger.Errorf("could not marshal json: %s\n", err) - w.WriteHeader(http.StatusInternalServerError) - render("error", w, map[string]string{ - "Status": "500", - "Error": "Could not parse genius api response", - }) - return - } - w.Header().Set("content-type", "application/json") - _, err = w.Write(response) - if err != nil { - logger.Errorln("Error sending response: ", err) - } - return - } - - url := fmt.Sprintf("https://genius.com/api/referents/%s?text_format=html", id) - resp, err := sendRequest(url) - - if err != nil { - logger.Errorln(err) - w.WriteHeader(http.StatusInternalServerError) - render("error", w, map[string]string{ - "Status": "500", - "Error": "cannot reach genius servers", - }) - return - } - - defer resp.Body.Close() - - if resp.StatusCode == http.StatusNotFound { - w.WriteHeader(http.StatusNotFound) - render("error", w, map[string]string{ - "Status": "404", - "Error": "page not found", - }) - return - } - - buf := new(bytes.Buffer) - _, err = buf.ReadFrom(resp.Body) - if err != nil { - logger.Errorln("Error paring genius api response", err) - w.WriteHeader(http.StatusInternalServerError) - render("error", w, map[string]string{ - "Status": "500", - "Error": "Parsing error", - }) - return - } - - var data annotationsResponse - err = json.Unmarshal(buf.Bytes(), &data) - if err != nil { - logger.Errorf("could not unmarshal json: %s\n", err) - w.WriteHeader(http.StatusInternalServerError) - render("error", w, map[string]string{ - "Status": "500", - "Error": "Could not parse genius api response", - }) - return - } - - w.Header().Set("content-type", "application/json") - body := data.Response.Referent.Annotations[0].Body - body.Html = cleanBody(body.Html) - response, err := json.Marshal(body) - - if err != nil { - logger.Errorf("could not marshal json: %s\n", err) - w.WriteHeader(http.StatusInternalServerError) - render("error", w, map[string]string{ - "Status": "500", - "Error": "Could not parse genius api response", - }) - return - } - - err = setCache(id, body) - if err != nil { - logger.Errorln(err) - } - - _, err = w.Write(response) - if err != nil { - logger.Errorln("Error sending response: ", err) - } -} - -func cleanBody(body string) string { - var withCleanedImageLinks = strings.Replace(body, "https://images.rapgenius.com/", "/images/", -1) - - var re = regexp.MustCompile(`https?:\/\/[a-z]*.?genius.com`) - var withCleanedLinks = re.ReplaceAllString(withCleanedImageLinks, "") - - return withCleanedLinks -} diff --git a/go.sum b/go.sum index 2bf8f1d..2f38299 100644 --- a/go.sum +++ b/go.sum @@ -50,4 +50,3 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= - diff --git a/lyrics.go b/lyrics.go deleted file mode 100644 index 913844c..0000000 --- a/lyrics.go +++ /dev/null @@ -1,176 +0,0 @@ -package main - -import ( - "encoding/json" - "fmt" - "net/http" - "strings" - - "github.com/PuerkitoBio/goquery" - "github.com/gorilla/mux" -) - -type song struct { - Artist string - Title string - Image string - Lyrics string - Credits map[string]string - About [2]string - Album string - LinkToAlbum string -} - -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 - } - Album struct { - Url string `json:"url"` - Name string `json:"name"` - } - CustomPerformances []customPerformance `json:"custom_performances"` - } - } -} - -type customPerformance struct { - Label string - Artists []struct { - Name string - } -} - -func (s *song) parseLyrics(doc *goquery.Document) { - doc.Find("[data-lyrics-container='true']").Each(func(i int, ss *goquery.Selection) { - h, err := ss.Html() - if err != nil { - logger.Errorln("unable to parse lyrics", err) - } - s.Lyrics += h - }) -} - -func (s *song) parseSongData(doc *goquery.Document) { - attr, exists := doc.Find("meta[property='twitter:app:url:iphone']").Attr("content") - if exists { - songID := strings.Replace(attr, "genius://songs/", "", 1) - - u := fmt.Sprintf("https://genius.com/api/songs/%s?text_format=plain", songID) - - res, err := sendRequest(u) - if err != nil { - logger.Errorln(err) - } - - defer res.Body.Close() - - var data songResponse - decoder := json.NewDecoder(res.Body) - err = decoder.Decode(&data) - if err != nil { - logger.Errorln(err) - } - - 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) - s.Album = songData.Album.Name - s.LinkToAlbum = strings.Replace(songData.Album.Url, "https://genius.com", "", -1) - - for _, perf := range songData.CustomPerformances { - var artists []string - for _, artist := range perf.Artists { - artists = append(artists, artist.Name) - } - s.Credits[perf.Label] = strings.Join(artists, ", ") - } - } -} - -func truncateText(text string) string { - textArr := strings.Split(text, "") - - if len(textArr) > 250 { - return strings.Join(textArr[0:250], "") + "..." - } - - return text -} - -func (s *song) parse(doc *goquery.Document) { - s.parseLyrics(doc) - s.parseSongData(doc) -} - -func lyricsHandler(w http.ResponseWriter, r *http.Request) { - id := mux.Vars(r)["id"] - - if data, err := getCache(id); err == nil { - render("lyrics", w, data) - return - } - - url := fmt.Sprintf("https://genius.com/%s-lyrics", id) - resp, err := sendRequest(url) - if err != nil { - logger.Errorln(err) - w.WriteHeader(http.StatusInternalServerError) - render("error", w, map[string]string{ - "Status": "500", - "Error": "cannot reach genius servers", - }) - return - } - - defer resp.Body.Close() - - if resp.StatusCode == http.StatusNotFound { - w.WriteHeader(http.StatusNotFound) - render("error", w, map[string]string{ - "Status": "404", - "Error": "page not found", - }) - return - } - - doc, err := goquery.NewDocumentFromReader(resp.Body) - if err != nil { - logger.Errorln(err) - w.WriteHeader(http.StatusInternalServerError) - render("error", w, map[string]string{ - "Status": "500", - "Error": "something went wrong", - }) - return - } - - cf := doc.Find(".cloudflare_content").Length() - if cf > 0 { - logger.Errorln("cloudflare got in the way") - render("error", w, map[string]string{ - "Status": "500", - "Error": "damn cloudflare, issue #21 on GitHub", - }) - return - } - - var s song - s.parse(doc) - - render("lyrics", w, s) - err = setCache(id, s) - if err != nil { - logger.Errorln(err) - } - -} diff --git a/main.go b/main.go index 760d907..872745f 100644 --- a/main.go +++ b/main.go @@ -1,11 +1,7 @@ package main import ( -<<<<<<< HEAD - "context" -======= "embed" ->>>>>>> upstream/main "fmt" "net" "net/http" @@ -22,36 +18,7 @@ import ( var staticFiles embed.FS func main() { -<<<<<<< HEAD - ctx := context.Background() - c, err := bigcache.New(ctx, bigcache.DefaultConfig(time.Hour*24)) - if err != nil { - logger.Fatalln("can't initialize caching") - } - cache = c - - r := mux.NewRouter() - - r.Use(securityHeaders) - - r.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { render("home", w, nil) }) - r.HandleFunc("/search", searchHandler).Methods("GET") - r.HandleFunc("/{id}-lyrics", lyricsHandler) - r.HandleFunc("/{id}/{artist-song}/{verse}/annotations", annotationsHandler) - r.HandleFunc("/images/{filename}.{ext}", proxyHandler) - r.PathPrefix("/static/").Handler(http.StripPrefix("/static/", http.FileServer(http.Dir("static")))) - r.HandleFunc("/albums/{artist}/{albumName}", albumHandler) - r.NotFoundHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - w.WriteHeader(http.StatusNotFound) - render("error", w, map[string]string{ - "Status": "404", - "Error": "page not found", - }) - - }) -======= logger := utils.NewLogger(os.Stdout) ->>>>>>> upstream/main server := &http.Server{ Handler: handlers.New(logger, staticFiles), diff --git a/proxy.go b/proxy.go deleted file mode 100644 index bb7005a..0000000 --- a/proxy.go +++ /dev/null @@ -1,77 +0,0 @@ -package main - -import ( - "fmt" - "io" - "net/http" - "net/url" - "strings" - - "github.com/gorilla/mux" -) - -func isValidExt(ext string) bool { - valid := []string{"jpg", "jpeg", "png", "gif"} - for _, c := range valid { - if strings.ToLower(ext) == c { - return true - } - } - - return false -} - -func extractURL(image string) string { - u, err := url.Parse(image) - if err != nil { - return "" - } - - return fmt.Sprintf("/images%s", u.Path) -} - -func proxyHandler(w http.ResponseWriter, r *http.Request) { - v := mux.Vars(r) - f := v["filename"] - ext := v["ext"] - - if !isValidExt(ext) { - w.WriteHeader(http.StatusBadRequest) - render("error", w, map[string]string{ - "Status": "400", - "Error": "Something went wrong", - }) - return - } - - // first segment of URL resize the image to reduce bandwith usage. - url := fmt.Sprintf("https://t2.genius.com/unsafe/300x300/https://images.genius.com/%s.%s", f, ext) - - res, err := sendRequest(url) - if err != nil { - logger.Errorln(err) - w.WriteHeader(http.StatusInternalServerError) - render("error", w, map[string]string{ - "Status": "500", - "Error": "cannot reach genius servers", - }) - return - } - - if res.StatusCode != http.StatusOK { - w.WriteHeader(http.StatusInternalServerError) - render("error", w, map[string]string{ - "Status": "500", - "Error": "something went wrong", - }) - - return - } - - w.Header().Add("Content-type", fmt.Sprintf("image/%s", ext)) - _, err = io.Copy(w, res.Body) - if err != nil { - logger.Errorln(err) - } - -} diff --git a/search.go b/search.go deleted file mode 100644 index cfd28ac..0000000 --- a/search.go +++ /dev/null @@ -1,64 +0,0 @@ -package main - -import ( - "encoding/json" - "fmt" - "net/http" - "net/url" -) - -type response struct { - Response struct { - Sections sections - } -} - -type result struct { - ArtistNames string `json:"artist_names"` - Title string - Path string - Thumbnail string `json:"song_art_image_thumbnail_url"` -} - -type hits []struct { - Result result -} - -type sections []struct { - Type string - Hits hits -} - -type renderVars struct { - Query string - Sections sections -} - -func searchHandler(w http.ResponseWriter, r *http.Request) { - query := r.URL.Query().Get("q") - url := fmt.Sprintf(`https://genius.com/api/search/multi?q=%s`, url.QueryEscape(query)) - - res, err := sendRequest(url) - if err != nil { - logger.Errorln(err) - w.WriteHeader(http.StatusInternalServerError) - render("error", w, map[string]string{ - "Status": "500", - "Error": "cannot reach genius servers", - }) - } - - defer res.Body.Close() - - var data response - - d := json.NewDecoder(res.Body) - err = d.Decode(&data) - if err != nil { - logger.Errorln(err) - } - - vars := renderVars{query, data.Response.Sections} - - render("search", w, vars) -}