2023-01-05 06:41:21 +00:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"encoding/json"
|
|
|
|
"flag"
|
|
|
|
"fmt"
|
2024-08-06 03:35:53 +00:00
|
|
|
"log"
|
|
|
|
"log/slog"
|
2023-01-05 06:41:21 +00:00
|
|
|
"os"
|
|
|
|
"path/filepath"
|
2023-01-05 07:08:48 +00:00
|
|
|
"runtime/pprof"
|
2023-01-05 06:41:21 +00:00
|
|
|
"strings"
|
|
|
|
"time"
|
|
|
|
|
2024-08-06 03:35:53 +00:00
|
|
|
"anime.bike/slogutil/slogenv"
|
|
|
|
"anime.bike/stint"
|
2023-01-05 07:08:48 +00:00
|
|
|
"git.tuxpa.in/a/nori/renderer"
|
|
|
|
"gitlab.com/gfxlabs/gfximg/apng"
|
|
|
|
"golang.org/x/sync/errgroup"
|
|
|
|
|
2023-01-05 06:41:21 +00:00
|
|
|
"git.tuxpa.in/a/nori"
|
|
|
|
"git.tuxpa.in/a/nori/utils"
|
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
|
|
|
dumpPtr = flag.Bool("d", false, "dump nri file to zip")
|
|
|
|
silentPtr = flag.Bool("s", false, "silent")
|
|
|
|
bulkDumpPtr = flag.Bool("b", false, "bulk dump nris from a folder")
|
|
|
|
jsonDumpPtr = flag.Bool("j", false, "bulk dump nri animation names from a folder")
|
|
|
|
directoryPtr = flag.String("dir", "nri", "directory to bulk dump from")
|
|
|
|
destinationPtr = flag.String("dest", "", "directory to bulk dump to")
|
|
|
|
filePtr = flag.String("f", "example.nri", "file to load")
|
|
|
|
outputPtr = flag.String("o", "output.zip", "output zip file")
|
2023-01-05 07:08:48 +00:00
|
|
|
|
|
|
|
cpuprofile = flag.String("cpuprofile", "", "write cpu profile to file")
|
2023-01-05 06:41:21 +00:00
|
|
|
)
|
|
|
|
|
2024-08-06 03:35:53 +00:00
|
|
|
func init() {
|
|
|
|
slog.SetDefault(slog.New(stint.NewHandler(os.Stderr, &stint.Options{
|
|
|
|
AddSource: true,
|
|
|
|
Level: slogenv.EnvLevel(),
|
|
|
|
})))
|
|
|
|
}
|
|
|
|
|
2023-01-05 06:41:21 +00:00
|
|
|
func main() {
|
|
|
|
flag.Parse()
|
2023-01-05 07:08:48 +00:00
|
|
|
if len(os.Args) < 2 {
|
|
|
|
flag.PrintDefaults()
|
|
|
|
}
|
|
|
|
if *cpuprofile != "" {
|
|
|
|
f, err := os.Create(*cpuprofile)
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
pprof.StartCPUProfile(f)
|
|
|
|
defer pprof.StopCPUProfile()
|
|
|
|
}
|
2023-01-05 06:41:21 +00:00
|
|
|
if *dumpPtr {
|
|
|
|
filename := *filePtr
|
|
|
|
output := *outputPtr
|
|
|
|
if _, err := os.Stat(filename); err != nil {
|
|
|
|
printIf("could not find file %s\n", filename)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
dump(filename, output)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
dir := *directoryPtr
|
|
|
|
dest := *destinationPtr
|
|
|
|
if dest == "" {
|
|
|
|
dest = dir
|
|
|
|
}
|
|
|
|
printIf("output: %s\n", dest)
|
|
|
|
if *bulkDumpPtr || *jsonDumpPtr {
|
2023-01-05 07:08:48 +00:00
|
|
|
files, err := os.ReadDir(dir)
|
2023-01-05 06:41:21 +00:00
|
|
|
if err != nil {
|
|
|
|
printIf("%s: %s\n", dir, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
egg := errgroup.Group{}
|
|
|
|
egg.SetLimit(12)
|
|
|
|
for _, ff := range files {
|
|
|
|
f := ff
|
|
|
|
if strings.HasSuffix(f.Name(), ".nri") {
|
|
|
|
egg.Go(func() error {
|
|
|
|
if *bulkDumpPtr {
|
2023-01-05 07:08:48 +00:00
|
|
|
if err := dump_nozip(dir+"/"+f.Name(), dest); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2023-01-05 06:41:21 +00:00
|
|
|
}
|
|
|
|
if *jsonDumpPtr {
|
2023-01-05 07:08:48 +00:00
|
|
|
if err := dump_nozip(dir+"/"+f.Name(), dest); err != nil {
|
|
|
|
return dump_anim_json(dir+"/"+f.Name(), dest)
|
|
|
|
}
|
2023-01-05 06:41:21 +00:00
|
|
|
}
|
|
|
|
return nil
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if err := egg.Wait(); err != nil {
|
|
|
|
log.Panicf("oh fuck: %s\n", err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func printIf(s string, args ...interface{}) {
|
|
|
|
if !*silentPtr {
|
|
|
|
fmt.Printf(s, args...)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-01-05 07:08:48 +00:00
|
|
|
func dump_anim_json(filename string, destination string) error {
|
2023-01-05 06:41:21 +00:00
|
|
|
n, err := nori.FromFile(filename)
|
|
|
|
if err != nil {
|
2023-01-05 07:08:48 +00:00
|
|
|
return fmt.Errorf("decode: %s", err)
|
2023-01-05 06:41:21 +00:00
|
|
|
}
|
|
|
|
names, err := nori.GetAnimationNames(n)
|
|
|
|
if err != nil {
|
2023-01-05 07:08:48 +00:00
|
|
|
return fmt.Errorf("animation: %s", err)
|
2023-01-05 06:41:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
json, err := json.Marshal(names)
|
|
|
|
if err != nil {
|
2023-01-05 07:08:48 +00:00
|
|
|
return fmt.Errorf("could not marshal json: %s\n", err)
|
2023-01-05 06:41:21 +00:00
|
|
|
}
|
|
|
|
baseName := filepath.Base(strings.TrimSuffix(filename, filepath.Ext(filename)))
|
|
|
|
output := fmt.Sprintf("%s/%s.json", destination, baseName)
|
2023-01-05 07:08:48 +00:00
|
|
|
return os.WriteFile(output, json, 0o740)
|
2023-01-05 06:41:21 +00:00
|
|
|
}
|
|
|
|
|
2023-01-05 07:08:48 +00:00
|
|
|
func dump_nozip(filename string, destination string) error {
|
2023-01-05 06:41:21 +00:00
|
|
|
start := time.Now()
|
|
|
|
n, err := nori.FromFile(filename)
|
|
|
|
if err != nil {
|
2023-01-05 07:08:48 +00:00
|
|
|
return fmt.Errorf("decode: %s", err)
|
2023-01-05 06:41:21 +00:00
|
|
|
}
|
|
|
|
// printIf("rendering %d animation(s)\n", n.AnimationCount)
|
|
|
|
animations, err := renderer.RenderAnimationsApng(n)
|
|
|
|
if err != nil {
|
2023-01-05 07:08:48 +00:00
|
|
|
return fmt.Errorf("animation: %s", err)
|
2023-01-05 06:41:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
baseName := filepath.Base(strings.TrimSuffix(filename, filepath.Ext(filename)))
|
|
|
|
for i, v := range animations {
|
|
|
|
output := fmt.Sprintf(destination+"/%s_%d.png", baseName, i)
|
|
|
|
// printIf("saving to %s \n", output)
|
|
|
|
f, fErr := os.OpenFile(output, os.O_CREATE, 0740)
|
|
|
|
if fErr != nil {
|
2023-01-05 07:08:48 +00:00
|
|
|
return fErr
|
2023-01-05 06:41:21 +00:00
|
|
|
}
|
|
|
|
defer f.Close()
|
|
|
|
if err := apng.Encode(f, *v); err != nil {
|
2023-01-05 07:08:48 +00:00
|
|
|
return err
|
2023-01-05 06:41:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
//if err := utils.ZipApngs(out, animations); err != nil {
|
2023-01-05 07:08:48 +00:00
|
|
|
// return fmt.Errorf("zipping: %s", err)
|
2023-01-05 06:41:21 +00:00
|
|
|
//}
|
|
|
|
printIf("done in %v \n", time.Now().Sub(start))
|
|
|
|
//os.WriteFile(output, out.Bytes(), 0740)
|
2023-01-05 07:08:48 +00:00
|
|
|
return nil
|
2023-01-05 06:41:21 +00:00
|
|
|
}
|
|
|
|
|
2023-01-05 07:08:48 +00:00
|
|
|
func dump(filename string, output string) error {
|
2023-01-05 06:41:21 +00:00
|
|
|
start := time.Now()
|
|
|
|
n, err := nori.FromFile(filename)
|
|
|
|
if err != nil {
|
2023-01-05 07:08:48 +00:00
|
|
|
return fmt.Errorf("decode: %s", err)
|
2023-01-05 06:41:21 +00:00
|
|
|
}
|
|
|
|
out := new(bytes.Buffer)
|
|
|
|
printIf("rendering %d animation(s)\n", n.AnimationCount)
|
|
|
|
animations, err := renderer.RenderAnimationsApng(n)
|
|
|
|
if err != nil {
|
2023-01-05 07:08:48 +00:00
|
|
|
return fmt.Errorf("animation: %s", err)
|
2023-01-05 06:41:21 +00:00
|
|
|
}
|
|
|
|
printIf("saving to %s \n", output)
|
|
|
|
if err := utils.ZipApngs(out, animations); err != nil {
|
2023-01-05 07:08:48 +00:00
|
|
|
return fmt.Errorf("zipping: %s", err)
|
2023-01-05 06:41:21 +00:00
|
|
|
}
|
|
|
|
printIf("done in %v \n", time.Now().Sub(start))
|
|
|
|
os.WriteFile(output, out.Bytes(), 0740)
|
2023-01-05 07:08:48 +00:00
|
|
|
return nil
|
2023-01-05 06:41:21 +00:00
|
|
|
}
|