summaryrefslogtreecommitdiff
path: root/internal/thumb
diff options
context:
space:
mode:
Diffstat (limited to 'internal/thumb')
-rw-r--r--internal/thumb/thumb.go13
-rw-r--r--internal/thumb/thumb_test.go38
2 files changed, 34 insertions, 17 deletions
diff --git a/internal/thumb/thumb.go b/internal/thumb/thumb.go
index 53a139b..8b49e41 100644
--- a/internal/thumb/thumb.go
+++ b/internal/thumb/thumb.go
@@ -39,15 +39,22 @@ func (g *FFmpegGenerator) Generate(ctx context.Context, inputPath, outputPath st
}
}
- cmd := g.execer(ctx, "ffmpeg",
- "-ss", fmt.Sprintf("%.3f", offset),
- "-i", inputPath,
+ // Build args: only add -ss when we have a real duration (video).
+ // For static images, -ss before -i produces no output frame on some
+ // ffmpeg versions (it skips past the single image2 frame).
+ args := []string{"-i", inputPath}
+ if duration > 0 {
+ // Prepend -ss before -i for fast seek when we have a video.
+ args = append([]string{"-ss", fmt.Sprintf("%.3f", offset)}, args...)
+ }
+ args = append(args,
"-vf", "scale=320:-1",
"-frames:v", "1",
"-q:v", "2",
"-y",
outputPath,
)
+ cmd := g.execer(ctx, "ffmpeg", args...)
if err := cmd.Run(); err != nil {
return fmt.Errorf("ffmpeg generate thumbnail for %s: %w", inputPath, err)
}
diff --git a/internal/thumb/thumb_test.go b/internal/thumb/thumb_test.go
index d6272a9..3ed9dfd 100644
--- a/internal/thumb/thumb_test.go
+++ b/internal/thumb/thumb_test.go
@@ -13,14 +13,14 @@ import (
func TestFFmpegGenerator_Generate(t *testing.T) {
ctx := context.Background()
- called := false
- fakeExecer := func(_ context.Context, name string, arg ...string) *exec.Cmd {
- called = true
+ // Video with duration > 0 should include -ss.
+ videoCalled := false
+ fakeExecerVideo := func(_ context.Context, name string, arg ...string) *exec.Cmd {
+ videoCalled = true
if name != "ffmpeg" {
t.Errorf("expected ffmpeg, got %s", name)
}
- // Verify some expected flags exist.
args := strings.Join(arg, " ")
if !strings.Contains(args, "-ss") {
t.Error("missing -ss flag")
@@ -34,25 +34,35 @@ func TestFFmpegGenerator_Generate(t *testing.T) {
if !strings.Contains(args, "-y") {
t.Error("missing -y flag")
}
- // Return a command that does nothing successfully.
return exec.Command("true")
}
-
- g := &FFmpegGenerator{execer: fakeExecer, rnd: rand.New(rand.NewSource(1))}
- if err := g.Generate(ctx, "input.mp4", "output.jpg", 120.0); err != nil {
+ g := &FFmpegGenerator{execer: fakeExecerVideo, rnd: rand.New(rand.NewSource(1))}
+ if err := g.Generate(ctx, "input.mp4", "out.jpg", 120.0); err != nil {
t.Fatalf("unexpected error: %v", err)
}
- if !called {
+ if !videoCalled {
t.Fatal("expected fake execer to be called")
}
- // Duration zero or negative should still call execer with valid offset.
- called = false
- if err := g.Generate(ctx, "input.mp4", "output.jpg", 0); err != nil {
+ // Image with duration == 0 should NOT include -ss.
+ imgCalled := false
+ fakeExecerImage := func(_ context.Context, name string, arg ...string) *exec.Cmd {
+ imgCalled = true
+ args := strings.Join(arg, " ")
+ if strings.Contains(args, "-ss") {
+ t.Error("unexpected -ss flag for image")
+ }
+ if !strings.Contains(args, "-i") {
+ t.Error("missing -i flag")
+ }
+ return exec.Command("true")
+ }
+ gi := &FFmpegGenerator{execer: fakeExecerImage, rnd: rand.New(rand.NewSource(1))}
+ if err := gi.Generate(ctx, "photo.jpg", "thumb.jpg", 0); err != nil {
t.Fatalf("unexpected error: %v", err)
}
- if !called {
- t.Fatal("expected fake execer to be called for zero duration")
+ if !imgCalled {
+ t.Fatal("expected fake execer to be called for image")
}
}