package main import ( "net/http" "log" "embed" "html/template" "os" "io/fs" "strconv" "path/filepath" "sync" ) //go:embed templates var tmplFS embed.FS type img struct { Path string Name string } var imgs map[string][]img = make(map[string][]img) var lock sync.RWMutex func serve(w http.ResponseWriter, data interface{}, funcMap template.FuncMap, views ...string) { aviews := []string{"templates/base.html"} aviews = append(aviews, views...) t, err := template.New("base.html").Funcs(funcMap).ParseFS(tmplFS, aviews...) if err != nil { log.Fatal(err) } if err := t.Execute(w, data); err != nil { log.Fatal(err) } } func index(w http.ResponseWriter, r *http.Request) { q := r.URL.Query() meltee := q.Get("meltee") char := q.Get("char") set := q.Get("set") if meltee == "" || char == "" || set == "" { w.WriteHeader(http.StatusBadRequest) return } fillimgs(meltee, char, set) start := 0 end := min(start + 10, len(imgs)) funcMap := template.FuncMap { "isLast": func(i int, imgs []img) bool { return i == len(imgs) - 1 }, } p := filepath.Join(meltee, char, set) lock.RLock() defer lock.RUnlock() serve(w, struct { Page int Meltee string Char string Set string Imgs []img IsLastPage bool }{ 1, meltee, char, set, imgs[p][start:end], end == len(imgs[p]), }, funcMap, "templates/index.html", "templates/img.html") } func getimgs(w http.ResponseWriter, r *http.Request) { lock.RLock() defer lock.RUnlock() q := r.URL.Query() page := q.Get("page") meltee := q.Get("meltee") char := q.Get("char") set := q.Get("set") if meltee == "" || char == "" || set == "" { w.WriteHeader(http.StatusBadRequest) return } p := filepath.Join(meltee, char, set) ipage, err := strconv.Atoi(page) if err != nil { w.WriteHeader(http.StatusBadRequest) return } start := ipage * 10 end := min(start + 10, len(imgs[p])) if start < 0 || end > len(imgs[p]) { log.Println(start, end, len(imgs[p])) w.WriteHeader(http.StatusBadRequest) return } funcMap := template.FuncMap { "isLast": func(i int, imgs []img) bool { return i == len(imgs) - 1 }, } t, err := template.New("imgs_stub.html").Funcs(funcMap).ParseFS(tmplFS, "templates/imgs_stub.html", "templates/img.html") if err != nil { log.Fatal(err) } info := struct { Page int Meltee string Char string Set string Imgs []img IsLastPage bool }{ ipage + 1, meltee, char, set, imgs[p][start:end], end == len(imgs[p]), } if err := t.Execute(w, info); err != nil { log.Fatal(err) } } func meltees(w http.ResponseWriter, r *http.Request) { files, err := os.ReadDir("static/imgs") if err != nil { log.Fatal(err) } serve(w, files, nil, "templates/meltees.html") } func chars(w http.ResponseWriter, r *http.Request) { q := r.URL.Query() meltee := q.Get("meltee") if meltee == "" { w.WriteHeader(http.StatusBadRequest) return } files, err := os.ReadDir(filepath.Join("static/imgs", meltee)) if err != nil { log.Fatal(err) } serve(w, struct { Items []fs.DirEntry Meltee string }{ files, meltee, }, nil, "templates/chars.html") } func sets(w http.ResponseWriter, r *http.Request) { q := r.URL.Query() meltee := q.Get("meltee") char := q.Get("char") if meltee == "" || char == "" { w.WriteHeader(http.StatusBadRequest) return } p := filepath.Join("static/imgs", meltee, char) files, err := os.ReadDir(p) if err != nil { log.Fatal(err) } serve(w, struct { Items []fs.DirEntry Meltee string Char string }{ files, meltee, char, }, nil, "templates/sets.html") } func fillimgs(meltee string, char string, set string) { lock.Lock() defer lock.Unlock() pa := filepath.Join(meltee, char, set) _, ok := imgs[pa] if ok { return } imgs[pa] = nil d := os.DirFS(".") p := filepath.Join("static/imgs", meltee, char, set) fs.WalkDir(d, p, func(path string, d fs.DirEntry, err error) error { if err != nil { log.Fatal(err) } info, err := d.Info() if err != nil { log.Fatal(err) } if info.IsDir() { return nil } imgs[pa] = append(imgs[pa], img { path, d.Name(), }) return nil }) log.Println(imgs) } func main() { mux := http.NewServeMux() mux.HandleFunc("/", meltees) mux.HandleFunc("/imgs", getimgs) mux.HandleFunc("/chars", chars) mux.HandleFunc("/chars/sets", sets) mux.HandleFunc("/chars/sets/imgs", index) mux.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir("static")))) log.Println("listening on 8080") log.Fatal(http.ListenAndServe(":8080", mux)) }