diff options
| -rw-r--r-- | main.go | 33 | ||||
| -rw-r--r-- | static/index.html | 212 | 
2 files changed, 238 insertions, 7 deletions
@@ -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<serie>.+) (?P<number>[0-9abc]+) \- (?P<title>.+)`) +	//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>  | 
