aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGabriel A. Giovanini <mail@gabrielgio.me>2024-04-01 16:05:51 +0200
committerGabriel A. Giovanini <mail@gabrielgio.me>2024-04-01 16:10:01 +0200
commit5217357b4635fad76ca35e655517387f61ccbb2a (patch)
treed7c347473cd1f6986e32d8358232eb25df0c1a30
parentf0c2bbf9a990b963a225d244974062ee727103d1 (diff)
downloadjnfilter-5217357b4635fad76ca35e655517387f61ccbb2a.tar.gz
jnfilter-5217357b4635fad76ca35e655517387f61ccbb2a.tar.bz2
jnfilter-5217357b4635fad76ca35e655517387f61ccbb2a.zip
feat: Add view to select series
-rw-r--r--main.go33
-rw-r--r--static/index.html212
2 files changed, 238 insertions, 7 deletions
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<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>