package main import ( "context" "errors" "flag" "fmt" "io" "net/http" "regexp" "strings" "github.com/beevik/etree" ) type ErrorRequestHandler func(w http.ResponseWriter, r *http.Request) error var RegexCollection = map[string]string{ "nerdcast": "NerdCast [0-9]+[a-c]* -", "empreendedor": "Empreendedor [0-9]+ -", "mamicas": "Caneca de Mamicas [0-9]+ -", "english": "Speak English [0-9]+ -", "nerdcash": "NerdCash [0-9]+ -", "bunker": "Lá do Bunker [0-9]+ -", "tech": "NerdTech [0-9]+ -", "genera": "Generacast [0-9]+ -", } const ( FeedUrl = "https://api.jovemnerd.com.br/feed-nerdcast/" ) func getSeries(r *http.Request) []string { query := r.URL.Query().Get("q") var series []string for _, q := range strings.Split(query, ",") { if _, ok := RegexCollection[q]; ok { series = append(series, q) } } if len(series) > 0 { return series } return []string{"nerdcast"} } func match(title string, series []string) bool { for _, s := range series { if ok, err := regexp.MatchString(RegexCollection[s], title); err == nil && ok { return true } } return false } func fetchXML(_ context.Context) ([]byte, error) { res, err := http.Get(FeedUrl) if err != nil { return nil, err } defer res.Body.Close() if res.StatusCode == http.StatusOK { return io.ReadAll(res.Body) } return nil, errors.New("Invalid http code") } func appendTag(tag *etree.Element, ap string) { text := tag.Text() tag.SetText(text + ap) } func filterBySeries(series []string, xml []byte, temper bool) ([]byte, error) { doc := etree.NewDocument() err := doc.ReadFromBytes(xml) if err != nil { return nil, err } channel := doc.FindElement("//channel") if temper { tmp := strings.ToUpper(strings.Join(series, ",")) tmp = fmt.Sprintf(" [%s]", tmp) appendTag(channel.FindElement("title"), tmp) appendTag(channel.FindElement("description"), tmp) appendTag(channel.FindElement("link"), "?"+tmp) appendTag(channel.FindElement("author[namespace-prefix()='itunes']"), tmp) appendTag(channel.FindElement("subtitle[namespace-prefix()='itunes']"), tmp) appendTag(channel.FindElement("summary[namespace-prefix()='itunes']"), tmp) appendTag(channel.FindElement("author[namespace-prefix()='googleplay']"), tmp) } for _, tag := range channel.FindElements("item") { title := tag.FindElement("title").Text() if !match(title, series) { channel.RemoveChild(tag) } } return doc.WriteToBytes() } func wrap(next ErrorRequestHandler) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { if err := next(w, r); err != nil { w.WriteHeader(http.StatusInternalServerError) } } } func titles(w http.ResponseWriter, r *http.Request) error { xml, err := fetchXML(r.Context()) if err != nil { return err } doc := etree.NewDocument() err = doc.ReadFromBytes(xml) if err != nil { return err } series := getSeries(r) els := doc.FindElements("//channel/item") for _, e := range els { txt := e.FindElement("title").Text() + "\n" if match(txt, series) { _, err = w.Write([]byte(txt)) if err != nil { return err } } } return nil } func podcast(w http.ResponseWriter, r *http.Request) error { xml, err := fetchXML(r.Context()) if err != nil { return err } series := getSeries(r) filterdXML, err := filterBySeries(series, xml, true) if err != nil { return err } _, err = w.Write(filterdXML) if err != nil { return err } return nil } func main() { var ( addr = flag.String("addr", ":8080", "Server address") ) flag.Parse() mux := http.NewServeMux() mux.HandleFunc("/titles", wrap(titles)) mux.HandleFunc("/", wrap(podcast)) server := http.Server{ Handler: mux, Addr: *addr, } err := server.ListenAndServe() if err != nil { fmt.Printf("Server error: %s", err.Error()) } }