diff --git a/testdata/ffmpeg.d/cmd/prune/main.go b/testdata/ffmpeg.d/cmd/prune/main.go index c296cda..bf28185 100644 --- a/testdata/ffmpeg.d/cmd/prune/main.go +++ b/testdata/ffmpeg.d/cmd/prune/main.go @@ -4,7 +4,6 @@ import ( "context" "fmt" "io" - "log" "math/big" "os" "os/exec" @@ -15,7 +14,6 @@ import ( "strconv" "strings" "syscall" - "time" ) func main() { @@ -30,79 +28,65 @@ func main() { func Run(ctx context.Context, args []string) error { cams, err := lsd(args[0]) if err != nil { - return err + return fmt.Errorf("failed to lsd %s: %w", args[0], err) } for _, cam := range cams { files, err := lsf(cam) if err != nil { - return err + return fmt.Errorf("failed to lsf %s: %w", cam, err) } else if len(files) < 1 { continue } - lastChunk := strings.Split(path.Base(files[len(files)-1]), ".")[0] - files = slices.DeleteFunc(files, func(f string) bool { - return strings.Contains(f, lastChunk) - }) - if len(files) == 0 { + series := []string{} + for _, f := range files { + series = append(series, strings.Split(path.Base(f), ".")[0]) + } + series = slices.Compact(series) + if len(series) < 1 { continue } + series = series[:len(series)-1] - lastMovementAt := time.Unix(0, 0) - prevF := files[0] - for _, f := range files[1:] { - prev, err := os.Stat(prevF) - if err != nil { - return err - } - - if ok, err := hasMovement(ctx, prevF, f); err != nil { - return err - } else if ok { - lastMovementAt = prev.ModTime() - } - - target := "trash" - if prev.ModTime().Before(lastMovementAt.Add(3 * time.Minute)) { - target = "movement" - } - if target == "trash" { - log.Println("deleting", prevF) - if err := os.Remove(prevF); err != nil { + for _, series := range series { + if err := func() error { + seriesFiles := []string{} + for _, file := range files { + if strings.HasPrefix(path.Base(file), series) { + seriesFiles = append(seriesFiles, file) + } + } + if seriesHasMovement, err := func() (bool, error) { + for i := 1; i < len(files); i++ { + f := files[i-1] + g := files[i] + if hasMovement, err := hasMovement(ctx, f, g); err != nil { + return false, fmt.Errorf("failed to check for movement between %s and %s: %w", f, g, err) + } else if hasMovement { + return true, nil + } + } + return false, nil + }(); err != nil { return err + } else if seriesHasMovement { + for _, seriesFile := range seriesFiles { + if err := mv(strings.ReplaceAll(seriesFile, "record", "movement"), seriesFile); err != nil { + return fmt.Errorf("failed to mv series %s: %w", series, err) + } + } + } else { + for _, seriesFile := range seriesFiles { + if err := os.Remove(seriesFile); err != nil { + return fmt.Errorf("failed to rm series %s[%s]: %w", series, seriesFile, err) + } + } } - } else if err := func() error { - gName := strings.ReplaceAll(prevF, "record", target) - if gName == prevF { - return fmt.Errorf("would overwrite original %s", prevF) - } - os.MkdirAll(path.Dir(gName), os.ModePerm) - - log.Println("moving", prevF, "to", gName) - - f, err := os.Open(prevF) - if err != nil { - return err - } - defer f.Close() - - g, err := os.Create(gName) - if err != nil { - return err - } - defer g.Close() - - if _, err := io.Copy(g, f); err != nil { - return err - } - - return os.Remove(prevF) + return nil }(); err != nil { return err } - - prevF = f } } return nil @@ -117,11 +101,11 @@ func hasMovement(ctx context.Context, a, b string) (bool, error) { hw := strings.Fields(string(sizeOfOutput))[2] h, err := strconv.ParseInt(strings.Split(hw, "x")[0], 10, 16) if err != nil { - return false, err + return false, fmt.Errorf("failed parsing %s for HxW: %w", hw, err) } w, err := strconv.ParseInt(strings.Split(hw, "x")[1], 10, 16) if err != nil { - return false, err + return false, fmt.Errorf("failed parsing %s for HxW: %w", hw, err) } total := h * w @@ -130,7 +114,7 @@ func hasMovement(ctx context.Context, a, b string) (bool, error) { f, _, err := big.ParseFloat(string(compareOutput), 10, 0, big.ToNearestEven) if err != nil { - return false, err + return false, fmt.Errorf("failed to parse %s for a number of changed pixels: %w", compareOutput, err) } i := new(big.Int) f.Int(i) @@ -140,6 +124,29 @@ func hasMovement(ctx context.Context, a, b string) (bool, error) { return percentPixelsChanged > 10, nil } +func mv(wPath, rPath string) error { + r, err := os.Open(rPath) + if err != nil { + return err + } + defer r.Close() + + os.MkdirAll(path.Dir(wPath), os.ModePerm) + w, err := os.Create(wPath) + if err != nil { + return err + } + defer w.Close() + + if _, err := io.Copy(w, r); err != nil { + w.Close() + os.Remove(wPath) + return err + } + + return os.Remove(rPath) +} + func lsd(d string) ([]string, error) { return ls(d, true) } diff --git a/testdata/ffmpeg.d/cmd/prune/main_test.go b/testdata/ffmpeg.d/cmd/prune/main_test.go index 431b0bb..920bad1 100644 --- a/testdata/ffmpeg.d/cmd/prune/main_test.go +++ b/testdata/ffmpeg.d/cmd/prune/main_test.go @@ -28,23 +28,20 @@ func TestRun(t *testing.T) { t.Fatal(err) } - t.Log("lsd", path.Dir(d)) - t.Log(lsd(path.Dir(d))) - - t.Log("lsf", d) - t.Log(lsf(d)) - if err := Run(context.Background(), []string{path.Dir(d)}); err != nil { t.Fatal(err) } if results, err := lsf(path.Join(path.Dir(d), "movement")); err != nil { - t.Fatal(err) - } else if len(results) < 2 { + t.Fatal("failed to lsf for results:", err) + } else if len(results) < 3 { t.Fatal(results) - } else if path.Base(results[0]) != "series.1.jpg" { + } else if path.Base(results[0]) != "series.0.jpg" { t.Fatal(results) - } else if path.Base(results[1]) != "series.2.jpg" { + } else if path.Base(results[1]) != "series.1.jpg" { + t.Fatal(results) + } else if path.Base(results[2]) != "series.2.jpg" { t.Fatal(results) } + // TODO assert originals deleted }