package main import ( "bytes" "flag" "fmt" "log" "log/slog" "net/http" "os" "time" "anime.bike/slogutil/slogenv" "anime.bike/stint" "git.tuxpa.in/a/nori/renderer" "git.tuxpa.in/a/nori" "git.tuxpa.in/a/nori/utils" "github.com/go-chi/chi/v5" "github.com/go-chi/chi/v5/middleware" ) var ( servePtr = flag.Bool("serve", false, "launch web server") dumpPtr = flag.Bool("d", false, "dump nri file to zip") silentPtr = flag.Bool("s", false, "silent") filePtr = flag.String("f", "example.nri", "file to load") outputPtr = flag.String("o", "output.zip", "output zip file") ) func init() { slog.SetDefault(slog.New(stint.NewHandler(os.Stderr, &stint.Options{ AddSource: true, Level: slogenv.EnvLevel(), }))) } func main() { flag.Parse() if *servePtr { serve() return } if *dumpPtr { filename := *filePtr output := *outputPtr if _, err := os.Stat(filename); err != nil { printIf("could not find file %s\n", filename) return } err := dump(filename, output) if err != nil { fmt.Println(err) return } return } flag.PrintDefaults() } func printIf(s string, args ...interface{}) { if !*silentPtr { fmt.Printf(s, args...) } } func dump(filename string, output string) error { start := time.Now() printIf("reading file '%s'\n", filename) n, err := nori.FromFile(filename) if err != nil { return fmt.Errorf("decode: %w", err) } out := new(bytes.Buffer) printIf("rendering %d animation(s)\n", n.AnimationCount) animations, err := renderer.RenderAnimationsApng(n) if err != nil { return fmt.Errorf("animation: %w", err) } printIf("saving to %s \n", output) if err := utils.ZipApngs(out, animations); err != nil { return fmt.Errorf("zipping: %w", err) } printIf("done in %v \n", time.Now().Sub(start)) os.WriteFile(output, out.Bytes(), 0740) return nil } func serve() { r := chi.NewRouter() r.Use(middleware.RequestID) r.Use(middleware.RealIP) r.Use(middleware.Logger) r.Use(middleware.Recoverer) r.Use(middleware.Timeout(60 * time.Second)) r.Post("/animations", func(w http.ResponseWriter, r *http.Request) { output_type := r.URL.Query().Get("format") switch output_type { case "": output_type = "apng" case "apng": default: http.Error(w, "output type not supported", 500) return } n := nori.New() if err := n.Decode(r.Body); err != nil { http.Error(w, err.Error(), 500) } frames, err := renderer.RenderAnimationsApng(n) if err != nil { http.Error(w, err.Error(), 500) } if err := utils.ZipApngs(w, frames); err != nil { http.Error(w, err.Error(), 500) } w.WriteHeader(200) }) log.Println("listening on 3333") http.ListenAndServe(":3333", r) }