package main import ( "fmt" "path/filepath" "runtime" "log" "os" "math/rand" "strings" "lcthw.dev/go/vidcrunch/config" "github.com/modfy/fluent-ffmpeg" ) func ModFile(fname string, encoding config.VideoOpts) string { cleaned := filepath.Clean(fname) dir, file := filepath.Split(cleaned) ext := filepath.Ext(file) base, found := strings.CutSuffix(file, ext) if !found { panic("no extension found?!") } dim := strings.Replace(encoding.Scale, ":", ".", 1) renamed := fmt.Sprint(base, ".", dim, ".", encoding.Format) return filepath.Join(dir, renamed) } func Run(encoding config.VideoOpts, pass int, pid int, input string, output string) { encode := fluentffmpeg.NewCommand("") extras := []string{ "-pix_fmt", "yuv420p", "-pass", fmt.Sprint(pass), "-passlogfile", fmt.Sprintf("ffmpegpass-%x.log", pid), } if encoding.Preset != "" { extras = append(extras, "-preset", encoding.Preset) } if encoding.Resize { extras = append(extras, "-vf", fmt.Sprintf("scale=%s:flags=lanczos", encoding.Scale), "-aspect", encoding.Scale) } if pass != encoding.Passes { extras = append(extras, "-an") } else { encode.AudioCodec(encoding.AudioCodec) extras = append(extras, "-b:a", fmt.Sprint(encoding.AudioBitrate * 1024)) } if encoding.Test > 0 { encode.InputOptions( "-ss", fmt.Sprintf("00:%d", encoding.TestStart)) extras = append(extras, "-t", fmt.Sprint(encoding.Test)) } encode.VideoCodec(encoding.VideoCodec). VideoBitRate(encoding.VideoBitrate * 1024). FrameRate(encoding.FPS). ConstantRateFactor(encoding.CRF) extras = append(extras, encoding.Extras...) encode.OutputOptions(extras...) cmd := encode.InputPath(input). OutputFormat(encoding.Format). OutputPath(output). OutputLogs(os.Stdout). Overwrite(true). Build() fmt.Println(">", cmd.String()) err := cmd.Run() if err != nil { log.Fatalf("%v", err) } } func DevNull() string { if runtime.GOOS == "windows" { return "NUL" } else { return "/dev/null" } } func RenderFile(encoding config.VideoOpts, pid int, path string, target string) { for i := 1; i < encoding.Passes; i++ { Run(encoding, i, pid, path, DevNull()) } Run(encoding, encoding.Passes, pid, path, target) } func RenderToDir(encoding config.VideoOpts, force bool) { matches, err := filepath.Glob(encoding.Input) if err != nil { log.Fatalf("%v", err) } for _, path := range matches { base := filepath.Base(path) target := filepath.Join(encoding.OutDir, base) target = ModFile(target, encoding) _, err := os.Stat(target) if err != nil || force { fmt.Println("--- PATH", path, "->", target) RenderFile(encoding, rand.Int(), path, target) } else { fmt.Println("^^^ SKIP", path, "->", target) } } } func main() { settings := config.Load() for _, encoding := range settings.Encodings { if encoding.OutDir != "" { RenderToDir(encoding, settings.Force) } else { log.Fatal("config file needs either Output or OutDir") } } }