From 027049ff76ea199092d3640c4b36c4d9e8b1beba Mon Sep 17 00:00:00 2001 From: Stu Leak Date: Sat, 3 Jan 2026 23:53:07 -0500 Subject: [PATCH] Improve contact sheet progress reporting --- internal/thumbnail/generator.go | 45 ++++++++++++++++++++++----------- 1 file changed, 30 insertions(+), 15 deletions(-) diff --git a/internal/thumbnail/generator.go b/internal/thumbnail/generator.go index 901839c..947ab2d 100644 --- a/internal/thumbnail/generator.go +++ b/internal/thumbnail/generator.go @@ -433,8 +433,8 @@ func (g *Generator) generateContactSheet(ctx context.Context, config Config, dur args = append(args, outputPath) if config.Progress != nil { - args = append(args, "-progress", "pipe:1", "-nostats") - if err := runFFmpegWithProgress(ctx, g.FFmpegPath, args, duration, config.Progress); err != nil { + args = append(args, "-progress", "pipe:1", "-stats_period", "0.2", "-nostats") + if err := runFFmpegWithProgress(ctx, g.FFmpegPath, args, availableDuration, totalThumbs, config.Progress); err != nil { return "", fmt.Errorf("failed to generate contact sheet: %w", err) } } else { @@ -565,7 +565,7 @@ func escapeFilterPath(path string) string { return escaped } -func runFFmpegWithProgress(ctx context.Context, ffmpegPath string, args []string, totalDuration float64, progress func(float64)) error { +func runFFmpegWithProgress(ctx context.Context, ffmpegPath string, args []string, totalDuration float64, expectedFrames int, progress func(float64)) error { cmd := exec.CommandContext(ctx, ffmpegPath, args...) stdout, err := cmd.StdoutPipe() if err != nil { @@ -583,30 +583,45 @@ func runFFmpegWithProgress(ctx context.Context, ffmpegPath string, args []string } go func() { - if progress == nil || totalDuration <= 0 { + if progress == nil { return } scanner := bufio.NewScanner(stdout) var lastPct float64 + var lastFrame int for scanner.Scan() { line := scanner.Text() parts := strings.SplitN(line, "=", 2) if len(parts) != 2 { continue } - if parts[0] != "out_time_ms" { + key, val := parts[0], parts[1] + var pct float64 + updated := false + if key == "out_time_ms" && totalDuration > 0 { + if ms, err := strconv.ParseFloat(val, 64); err == nil { + currentSec := ms / 1000000.0 + pct = (currentSec / totalDuration) * 100 + updated = true + } + } else if key == "frame" && expectedFrames > 0 { + if frame, err := strconv.Atoi(val); err == nil { + if frame > lastFrame { + lastFrame = frame + } + pct = (float64(lastFrame) / float64(expectedFrames)) * 100 + updated = true + } + } + if !updated { continue } - if ms, err := strconv.ParseFloat(parts[1], 64); err == nil { - currentSec := ms / 1000000.0 - pct := (currentSec / totalDuration) * 100 - if pct > 100 { - pct = 100 - } - if pct-lastPct >= 0.5 || pct >= 100 { - lastPct = pct - progress(pct) - } + if pct > 100 { + pct = 100 + } + if pct-lastPct >= 0.5 || pct >= 100 { + lastPct = pct + progress(pct) } } }()