package main import ( "fmt" //"html/template" xmltpl "text/template" "io" "io/ioutil" "log" "net/http" "os" "regexp" "strings" ) type Item struct { ISBN string Author string Title string Filename string Date string } func (i Item) ImageURL() string { return "https://medien.umbreitkatalog.de/bildzentrale_original/" + i.ISBN[0:3] + "/" + i.ISBN[3:6] + "/" + i.ISBN[6:9] + "/" + i.ISBN[9:13] + ".jpg" } func (i Item) targetFilename() string { return "covers/" + i.ISBN + ".jpg" } func (i Item) downloadCover() error { resp, err := http.Get(i.ImageURL()) if err != nil { return err } defer resp.Body.Close() out, err := os.Create(i.targetFilename()) if err != nil { return err } defer out.Close() _, err = io.Copy(out, resp.Body) return err } func getItems(filename string) []Item { var items []Item // Get all book URLS url := "https://git.okoyono.de/mezzo/buch_des_monats/raw/branch/master/" + filename resp, err := http.Get(url) if err != nil { log.Fatal(filename + " is missing") } defer resp.Body.Close() content, err := ioutil.ReadAll(resp.Body) if err != nil { log.Fatal("Can not download the file. Network problem?") } currentYear := "" currentMonth := 0 re := regexp.MustCompile(`^[^[]+ \[(?P[^"]+)"(?P[^"]+)"\]\([^=]+=(?P<isbn>[0-9]+).*$`) yearRe := regexp.MustCompile(`^## (?P<year>20[0-9]{2})$`) var yearBucket []Item for _, line := range strings.Split(string(content), "\n") { // Do we find a year? yearMatches := yearRe.FindStringSubmatch(line) if len(yearMatches) > 0 { currentYear = yearMatches[1] currentMonth = 0 // Add the bucket in reverse order for i := len(yearBucket)-1; i >= 0; i-- { items = append(items, yearBucket[i]) } yearBucket = nil } matches := re.FindStringSubmatch(line) if len(matches) == 4 { currentMonth++ yearBucket = append(yearBucket, Item{ Author: strings.Trim(matches[1], " "), Title: strings.Trim(matches[2], " "), ISBN: matches[3], Date: fmt.Sprintf("01-%02d-%s", currentMonth, currentYear), Filename: filename, }) } } log.Printf("Output all items:") for _, i := range items { log.Printf("%v", i) } return items } func getTemplate(sourceFile string, templateFilename string, w http.ResponseWriter) { // Get all items from the git repo items := getItems(sourceFile) // Generate the restulting HTML t, err := xmltpl.ParseFiles("templates/" + templateFilename) if err != nil { panic(err) } err = t.Execute(w, map[string]interface{}{ "Items": items, }) if err != nil { panic(err) } } func main() { // All static files (CSS, JS) fileServer := http.FileServer(http.Dir("./static")) http.Handle("/static/", http.StripPrefix("/static", fileServer)) // Cover images imageServer := http.FileServer(http.Dir("./covers/")) http.Handle("/covers/", http.StripPrefix("/covers", imageServer)) // Update "Hook" /update?filename=COMIC.mkd http.HandleFunc("/update", func(w http.ResponseWriter, r *http.Request) { filename := r.URL.Query().Get("filename") log.Printf("Update hook triggered for %v", filename) // Get all items from the git repo items := getItems(filename) for _, item := range items { fmt.Printf("Downloading %v ...\n", item.ImageURL()) err := item.downloadCover() if err != nil { fmt.Printf("%v", err) fmt.Printf("ERROR: File %s not found\n", item.ImageURL()) } } }) http.HandleFunc("/book", func(w http.ResponseWriter, r *http.Request) { log.Print("/book") getTemplate("BOOK.mkd", "book.html", w) }) http.HandleFunc("/comic", func(w http.ResponseWriter, r *http.Request) { log.Print("/comic") getTemplate("COMIC.mkd", "comic.html", w) }) http.HandleFunc("/book.xml", func(w http.ResponseWriter, r *http.Request) { log.Print("/book.xml") w.Header().Add("Content-Type", "Application/rss+xml") getTemplate("BOOK.mkd", "book.xml", w) }) http.HandleFunc("/comic.xml", func(w http.ResponseWriter, r *http.Request) { log.Print("/comic.xml") w.Header().Add("Content-Type", "Application/rss+xml") getTemplate("COMIC.mkd", "comic.xml", w) }) // Spawn the webserver (blocking) log.Print("Spawn webserver on port :9783 and waiting for requests ... ...") err := http.ListenAndServe(":9783", nil) if err != nil { panic(err) } }