jnfilter @ v0.1.3

  1package main
  2
  3import (
  4	"context"
  5	"errors"
  6	"flag"
  7	"fmt"
  8	"io"
  9	"net/http"
 10	"regexp"
 11	"strings"
 12
 13	"github.com/beevik/etree"
 14)
 15
 16type ErrorRequestHandler func(w http.ResponseWriter, r *http.Request) error
 17
 18var RegexCollection = map[string]string{
 19	"nerdcast":     "NerdCast [0-9]+[a-c]* -",
 20	"empreendedor": "Empreendedor [0-9]+ -",
 21	"mamicas":      "Caneca de Mamicas [0-9]+ -",
 22	"english":      "Speak English [0-9]+ -",
 23	"nerdcash":     "NerdCash [0-9]+ -",
 24	"bunker":       "Lá do Bunker [0-9]+ -",
 25	"tech":         "NerdTech [0-9]+ -",
 26	"genera":       "Generacast [0-9]+ -",
 27}
 28
 29const (
 30	FeedUrl = "https://api.jovemnerd.com.br/feed-nerdcast/"
 31)
 32
 33func getSeries(r *http.Request) []string {
 34	query := r.URL.Query().Get("q")
 35
 36	var series []string
 37
 38	for _, q := range strings.Split(query, ",") {
 39		if _, ok := RegexCollection[q]; ok {
 40			series = append(series, q)
 41		}
 42	}
 43
 44	if len(series) > 0 {
 45		return series
 46	}
 47
 48	return []string{"nerdcast"}
 49}
 50
 51func match(title string, series []string) bool {
 52	for _, s := range series {
 53		if ok, err := regexp.MatchString(RegexCollection[s], title); err == nil && ok {
 54			return true
 55		}
 56	}
 57
 58	return false
 59}
 60
 61func fetchXML(_ context.Context) ([]byte, error) {
 62	res, err := http.Get(FeedUrl)
 63	if err != nil {
 64		return nil, err
 65	}
 66	defer res.Body.Close()
 67
 68	if res.StatusCode == http.StatusOK {
 69		return io.ReadAll(res.Body)
 70	}
 71
 72	return nil, errors.New("Invalid http code")
 73}
 74
 75func appendTag(tag *etree.Element, ap string) {
 76	text := tag.Text()
 77	tag.SetText(text + ap)
 78}
 79
 80func filterBySeries(series []string, xml []byte, temper bool) ([]byte, error) {
 81	doc := etree.NewDocument()
 82	err := doc.ReadFromBytes(xml)
 83	if err != nil {
 84		return nil, err
 85	}
 86
 87	channel := doc.FindElement("//channel")
 88
 89	if temper {
 90		tmp := strings.ToUpper(strings.Join(series, ","))
 91		tmp = fmt.Sprintf(" [%s]", tmp)
 92		appendTag(channel.FindElement("title"), tmp)
 93		appendTag(channel.FindElement("description"), tmp)
 94		appendTag(channel.FindElement("link"), "?"+tmp)
 95		appendTag(channel.FindElement("author[namespace-prefix()='itunes']"), tmp)
 96		appendTag(channel.FindElement("subtitle[namespace-prefix()='itunes']"), tmp)
 97		appendTag(channel.FindElement("summary[namespace-prefix()='itunes']"), tmp)
 98		appendTag(channel.FindElement("author[namespace-prefix()='googleplay']"), tmp)
 99
100	}
101
102	for _, tag := range channel.FindElements("item") {
103		title := tag.FindElement("title").Text()
104		if !match(title, series) {
105			channel.RemoveChild(tag)
106		}
107	}
108
109	return doc.WriteToBytes()
110}
111
112func wrap(next ErrorRequestHandler) http.HandlerFunc {
113	return func(w http.ResponseWriter, r *http.Request) {
114		if err := next(w, r); err != nil {
115			w.WriteHeader(http.StatusInternalServerError)
116		}
117	}
118}
119
120func titles(w http.ResponseWriter, r *http.Request) error {
121	xml, err := fetchXML(r.Context())
122	if err != nil {
123		return err
124	}
125
126	doc := etree.NewDocument()
127	err = doc.ReadFromBytes(xml)
128	if err != nil {
129		return err
130	}
131
132	series := getSeries(r)
133
134	els := doc.FindElements("//channel/item")
135	for _, e := range els {
136		txt := e.FindElement("title").Text() + "\n"
137		if match(txt, series) {
138			_, err = w.Write([]byte(txt))
139			if err != nil {
140				return err
141			}
142		}
143	}
144
145	return nil
146}
147
148func podcast(w http.ResponseWriter, r *http.Request) error {
149	xml, err := fetchXML(r.Context())
150	if err != nil {
151		return err
152	}
153
154	series := getSeries(r)
155	filterdXML, err := filterBySeries(series, xml, true)
156	if err != nil {
157		return err
158	}
159
160	_, err = w.Write(filterdXML)
161	if err != nil {
162		return err
163	}
164
165	return nil
166}
167
168func main() {
169	var (
170		addr = flag.String("addr", ":8080", "Server address")
171	)
172
173	flag.Parse()
174
175	mux := http.NewServeMux()
176	mux.HandleFunc("/titles", wrap(titles))
177	mux.HandleFunc("/", wrap(podcast))
178
179	server := http.Server{
180		Handler: mux,
181		Addr:    *addr,
182	}
183
184	err := server.ListenAndServe()
185	if err != nil {
186		fmt.Printf("Server error: %s", err.Error())
187	}
188}