From 5217357b4635fad76ca35e655517387f61ccbb2a Mon Sep 17 00:00:00 2001 From: "Gabriel A. Giovanini" Date: Mon, 1 Apr 2024 16:05:51 +0200 Subject: feat: Add view to select series --- main.go | 33 +++++++-- static/index.html | 212 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 238 insertions(+), 7 deletions(-) create mode 100644 static/index.html diff --git a/main.go b/main.go index 22d1489..7a8d2a6 100644 --- a/main.go +++ b/main.go @@ -2,10 +2,12 @@ package main import ( "context" + "embed" "errors" "flag" "fmt" "io" + "log/slog" "net/http" "os" "regexp" @@ -20,15 +22,17 @@ import ( ) const ( - FeedUrl = "https://api.jovemnerd.com.br/feed-nerdcast/" + feedUrl = "https://api.jovemnerd.com.br/feed-nerdcast/" ) type ( - ErrorRequestHandler func(w http.ResponseWriter, r *http.Request) error + errorRequestHandler func(w http.ResponseWriter, r *http.Request) error ) var ( - SerieRegex = regexp.MustCompile(`(?P.+) (?P[0-9abc]+) \- (?P.+)`) + //go:embed static/* + assets embed.FS + serieRegex = regexp.MustCompile(`(?P<serie>.+) (?P<number>[0-9abc]+) \- (?P<title>.+)`) ) var ( @@ -46,7 +50,6 @@ var ( "cloud": "Nerd na Cloud [0-9]+", "contar": "Vou (T|t)e Contar [0-9]+", "parceiro": "Papo de Parceiro [0-9]+", - "cash": "NerdCash [0-9]+", } feedRequest = promauto.NewHistogramVec(prometheus.HistogramOpts{ @@ -105,7 +108,7 @@ func fetchXML(_ context.Context) ([]byte, error) { feedRequest.WithLabelValues(code).Observe(since) }() - res, err := http.Get(FeedUrl) + res, err := http.Get(feedUrl) if err != nil { return nil, err } @@ -157,9 +160,10 @@ func filterBySeries(series []string, xml []byte, temper bool) ([]byte, error) { return doc.WriteToBytes() } -func handleError(next ErrorRequestHandler) http.HandlerFunc { +func handleError(next errorRequestHandler) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { if err := next(w, r); err != nil { + slog.ErrorContext(r.Context(), "Error", "error", err.Error()) w.WriteHeader(http.StatusInternalServerError) } } @@ -217,6 +221,20 @@ func titles(w http.ResponseWriter, r *http.Request) error { return nil } +func view(w http.ResponseWriter, r *http.Request) error { + data, err := assets.ReadFile("static/index.html") + if err != nil { + return err + } + + _, err = w.Write(data) + if err != nil { + return err + } + + return nil +} + func podcast(w http.ResponseWriter, r *http.Request) error { xml, err := fetchXML(r.Context()) if err != nil { @@ -253,7 +271,7 @@ func genSeries() error { els := doc.FindElements("//channel/item") for _, e := range els { txt := e.FindElement("title").Text() - res := SerieRegex.FindStringSubmatch(txt) + res := serieRegex.FindStringSubmatch(txt) if len(res) > 1 { unique[res[1]] = nil } @@ -284,6 +302,7 @@ func main() { mux := http.NewServeMux() mux.Handle("/metrics", promhttp.Handler()) mux.HandleFunc("/titles", wrap(handleError(titles))) + mux.HandleFunc("/view", wrap(handleError(view))) mux.HandleFunc("/", wrap(observe(handleError(podcast)))) server := http.Server{ diff --git a/static/index.html b/static/index.html new file mode 100644 index 0000000..25341fe --- /dev/null +++ b/static/index.html @@ -0,0 +1,212 @@ +<!DOCTYPE html> +<html> + <head lang="pt"> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <link rel="shortcut icon" href="data:image/x-icon;," type="image/x-icon"> + <style type="text/css" media="screen"> +/* Resettings some html properties */ +html, body, div, h1, header,section{ + margin: 0; + padding: 0; + border: 0; + font-family: monospace; +} + +h1 { + font-size: 1.25rem; + color: #fff; + text-transform: uppercase; +} + +ul { + margin: 0; +} + +body { + font-family: sans-serif; + background-color: #f4f4f4; +} + +header { + display: flex; + justify-content: space-between; + margin: auto; + margin-bottom: 1em; + background: #0062cc; + padding: .75em; + max-width: 960px; +} + +nav { + top: .75em; + right: .75em; +} + +.warning { + font-size: small; + color: red; + visibility: hidden; +} + +.btn { + display: inline-block; + padding: .1rem .75rem; + background: #e9ecef; + border: #343a40 1px solid; + font-size: .9rem; + font-weight: 400; + line-height: 1.5; + cursor: pointer; + color: #000; + border-radius: 0; + text-decoration: none; + transition: 0.5s all; +} + +.btn:hover { + background-color: #fff; +} + +nav li { + display: inline; + margin: 0 0 0 0; +} + +.section { + justify-content: left; + margin-bottom: 1em; + display: flex; +} + +.section input { + max-width: 10em; +} + +.form-ctl { + width: 1.3em; + height: 1.3em; + background-color: white; + border-radius: 0; + vertical-align: middle; + border: 1px solid #ddd; + appearance: none; + -webkit-appearance: none; + outline: none; +} + +.form-ctl:checked { + background-color: gray; +} + +a { + display: flex; + justify-content: center; + align-content: center; + flex-direction: column; + padding-left: 5px; +} + +main { + width: 40%; + margin: 0 auto; +} + +#feedUrl { + text-overflow: ellipsis; + max-width: 100%; + white-space: normal; + word-break: break-all; +} + +@media (width <= 600px) { + main { + width: 90%; + } +} + + </style> + </head> + <body> + <header> + <h1>Filtro para o Nerdcast</h1> + <nav> + <ul> + <li> + <a class="btn" href="https://git.gabrielgio.me/jnfilter/">Código fonte ➤</a> + </li> + </ul> + </nav> + </header> + <main> + <div class="section"> + Selecione os quadros: + </div> + <div class="section"> + <input class="form-ctl" type="checkbox" onchange="updateList(this)" id="nerdcast" /><a>NerdCast</a> + </div> + <div class="section"> + <input class="form-ctl" type="checkbox" onchange="updateList(this)" id="empreendedor" /><a>Empreendedor</a> + </div> + <div class="section"> + <input class="form-ctl" type="checkbox" onchange="updateList(this)" id="mamicas" /><a>Canecas de Mamicas</a> + </div> + <div class="section"> + <input class="form-ctl" type="checkbox" onchange="updateList(this)" id="english" /><a>Speak English</a> + </div> + <div class="section"> + <input class="form-ctl" type="checkbox" onchange="updateList(this)" id="nerdcash" /><a>NerdCash</a> + </div> + <div class="section"> + <input class="form-ctl" type="checkbox" onchange="updateList(this)" id="bunker" /><a>Lá do Bunker</a> + </div> + <div class="section"> + <input class="form-ctl" type="checkbox" onchange="updateList(this)" id="tech" /><a>NerdTech</a> + </div> + <div class="section"> + <input class="form-ctl" type="checkbox" onchange="updateList(this)" id="genera" /><a>Generacast</a> + </div> + <div class="section"> + <input class="form-ctl" type="checkbox" onchange="updateList(this)" id="rpg" /><a>NerdCast RPG</a> + </div> + <div class="section"> + <input class="form-ctl" type="checkbox" onchange="updateList(this)" id="catar" /><a>Vai te Catar</a> + </div> + <div class="section"> + <input class="form-ctl" type="checkbox" onchange="updateList(this)" id="cloud" /><a>Nerd na Cloud</a> + </div> + <div class="section"> + <input class="form-ctl" type="checkbox" onchange="updateList(this)" id="contar" /><a>Vou te Contar</a> + </div> + <div class="section"> + <input class="form-ctl" type="checkbox" onchange="updateList(this)" id="parceiro" /><a>Papo de Parceiro</a> + </div> + <div class="section"> + <a id="feedUrl" href="https://jnfilter.gabrielgio.me?q=mamicas" type="textbox">https://jnfilter.gabrielgio.me</a> + </div> + </main> + <script> +var feedUrl = document.getElementById("feedUrl") +var fields = new Set() + +function updateFeedUrl() { + if (fields.size == 0) { + url = "https://jnfilter.gabrielgio.me" + } else { + url = "https://jnfilter.gabrielgio.me?q="+[...fields].join(',') + } + feedUrl.textContent = url + feedUrl.href = url +} + +function updateList(elem) { + if (elem.checked){ + fields.add(elem.id) + } else { + fields.delete(elem.id) + } + updateFeedUrl() +} + </script> + </body> +</html> -- cgit v1.2.3