feat: add search functionality

This commit is contained in:
rramiachraf 2023-03-09 17:11:37 +01:00
parent b7c91e7f1b
commit dd0ee8723b
8 changed files with 198 additions and 6 deletions

View File

@ -3,7 +3,6 @@ package main
import (
"fmt"
"net/http"
"net/url"
"strings"
"github.com/PuerkitoBio/goquery"
@ -34,9 +33,7 @@ func (s *song) parseMetadata(doc *goquery.Document) {
title := doc.Find("h1[class*='Title']").First().Text()
image, exists := doc.Find("meta[property='og:image']").Attr("content")
if exists {
if u, err := url.Parse(image); err == nil {
s.Image = fmt.Sprintf("/images%s", u.Path)
}
s.Image = extractURL(image)
}
s.Title = title

View File

@ -27,6 +27,7 @@ func main() {
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("/images/{filename}.{ext}", proxyHandler)
r.PathPrefix("/static/").Handler(http.StripPrefix("/static/", http.FileServer(http.Dir("static"))))

View File

@ -4,6 +4,7 @@ import (
"fmt"
"io"
"net/http"
"net/url"
"strings"
"github.com/gorilla/mux"
@ -20,6 +21,15 @@ func isValidExt(ext string) bool {
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"]

60
search.go Normal file
View File

@ -0,0 +1,60 @@
package main
import (
"encoding/json"
"fmt"
"net/http"
)
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`, query)
res, err := http.Get(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)
d.Decode(&data)
vars := renderVars{query, data.Response.Sections}
render("search", w, vars)
}

View File

@ -247,6 +247,70 @@ footer a:hover {
color: #222;
}
.main {
flex-grow: 1;
}
#search-page {
display: flex;
flex-direction: column;
gap: 3rem;
padding: 2rem 1rem;
}
@media screen and (min-width: 800px) {
#search-page {
width: 80rem;
margin: 0 auto;
}
}
#search-input {
width: 100%;
padding: 1rem 2rem;
box-sizing: border-box;
border-radius: 5px;
border: 1px solid #ddd;
color: #222;
}
#search-results {
display: flex;
flex-direction: column;
gap: 1rem;
}
#search-results h1 {
text-align:center;
color: #111;
font-size: 2.5rem;
}
#search-item {
display: flex;
height: 8rem;
border: 1px solid #eee;
border-radius: 5px;
gap: 1rem;
padding: 1rem;
box-shadow: 0 1px 1px #ddd;
}
#search-item h2 {
font-size: 1.8rem;
color: #222;
}
#search-item span {
font-size: 1.3rem;
color: #333;
}
#search-item img {
width: 8rem;
border-radius: 5px;
}
/* dark mode */
@media (prefers-color-scheme: dark) {
body {
@ -287,4 +351,24 @@ footer a:hover {
#home p, #error p{
color: #ddd;
}
#search-input {
background-color: #ddd;
}
#search-page h1 {
color: #eee;
}
#search-item {
border: 1px solid #888;
}
#search-item h2 {
color: #ddd;
}
#search-item span {
color: #bbb;
}
}

View File

@ -62,7 +62,8 @@ func getTemplates(templates ...string) []string {
func render(n string, w http.ResponseWriter, data interface{}) {
w.Header().Set("content-type", "text/html")
t, err := template.ParseFiles(getTemplates(n, "navbar", "footer")...)
t := template.New(n + ".tmpl").Funcs(template.FuncMap{"extractURL": extractURL})
t, err := t.ParseFiles(getTemplates(n, "navbar", "footer")...)
if err != nil {
logger.Errorln(err)
w.WriteHeader(http.StatusInternalServerError)

View File

@ -14,7 +14,10 @@
<h1>Welcome to dumb</h1>
<p>An alternative frontend for genius.com</p>
</div>
<code>Just redirect Genius URLs to this instance and It's all good.</code>
<form method="GET" action="/search">
<input type="text" name="q" id="search-input" placeholder="Search..." />
</form>
</div>
{{template "footer"}}
</div>

36
views/search.tmpl Normal file
View File

@ -0,0 +1,36 @@
<!DOCTYPE html>
<html>
<head>
<title>Search - dumb</title>
<meta charset="utf-8" />
<link rel="stylesheet" type="text/css" href="/static/style.css" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
</head>
<body>
<main id="app">
{{template "navbar"}}
<div id="search-page" class="main">
<form method="GET">
<input type="text" name="q" id="search-input" placeholder="Search..." value="{{.Query}}" />
</form>
<div id="search-results">
{{range .Sections}}
{{if eq .Type "song"}}
<h1>Songs</h1>
{{range .Hits}}
<a id="search-item" href="{{.Result.Path}}">
<img src="{{extractURL .Result.Thumbnail}}"/>
<div>
<span>{{.Result.ArtistNames}}</span>
<h2>{{.Result.Title}}</h2>
</div>
</a>
{{end}}
{{end}}
{{end}}
</div>
</div>
{{template "footer"}}
</div>
</body>
</html>