buch_des_monats/src/bdm.go

189 lines
4.2 KiB
Go

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<author>[^"]+)"(?P<title>[^"]+)"\]\([^=]+=(?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)
}
}