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}