From 1b91937004ab149cf2a9e51b833931cd10b2ec90 Mon Sep 17 00:00:00 2001 From: WithoutPants <53250216+WithoutPants@users.noreply.github.com> Date: Mon, 25 Apr 2022 15:56:06 +1000 Subject: [PATCH] Fix image thumbnail generation (#2524) * Better logging for thumbnail generation errors * Reduce verbosity for thumbnail generation * Provide stdin during thumbnail generation --- internal/api/routes_image.go | 6 ++++++ internal/manager/task_scan_image.go | 6 ++++++ pkg/ffmpeg/generate.go | 11 +++++++++-- pkg/ffmpeg/transcoder/image.go | 2 ++ pkg/hash/videophash/phash.go | 2 +- pkg/image/thumbnail.go | 2 +- 6 files changed, 25 insertions(+), 4 deletions(-) diff --git a/internal/api/routes_image.go b/internal/api/routes_image.go index 49dd2a056..8ba2e50d5 100644 --- a/internal/api/routes_image.go +++ b/internal/api/routes_image.go @@ -4,6 +4,7 @@ import ( "context" "errors" "net/http" + "os/exec" "strconv" "github.com/go-chi/chi" @@ -50,6 +51,11 @@ func (rs imageRoutes) Thumbnail(w http.ResponseWriter, r *http.Request) { // don't log for unsupported image format if !errors.Is(err, image.ErrNotSupportedForThumbnail) { logger.Errorf("error generating thumbnail for image: %s", err.Error()) + + var exitErr *exec.ExitError + if errors.As(err, &exitErr) { + logger.Errorf("stderr: %s", string(exitErr.Stderr)) + } } // backwards compatibility - fallback to original image instead diff --git a/internal/manager/task_scan_image.go b/internal/manager/task_scan_image.go index 87aae87eb..36aff5a04 100644 --- a/internal/manager/task_scan_image.go +++ b/internal/manager/task_scan_image.go @@ -4,6 +4,7 @@ import ( "context" "database/sql" "errors" + "os/exec" "path/filepath" "time" @@ -158,6 +159,11 @@ func (t *ScanTask) generateThumbnail(i *models.Image) { // don't log for animated images if !errors.Is(err, image.ErrNotSupportedForThumbnail) { logger.Errorf("error getting thumbnail for image %s: %s", i.Path, err.Error()) + + var exitErr *exec.ExitError + if errors.As(err, &exitErr) { + logger.Errorf("stderr: %s", string(exitErr.Stderr)) + } } return } diff --git a/pkg/ffmpeg/generate.go b/pkg/ffmpeg/generate.go index ac27640c7..934bd1500 100644 --- a/pkg/ffmpeg/generate.go +++ b/pkg/ffmpeg/generate.go @@ -5,6 +5,7 @@ import ( "context" "errors" "fmt" + "io" "os/exec" "strings" ) @@ -35,8 +36,14 @@ func (f FFMpeg) Generate(ctx context.Context, args Args) error { } // GenerateOutput runs ffmpeg with the given args and returns it standard output. -func (f FFMpeg) GenerateOutput(ctx context.Context, args []string) ([]byte, error) { +func (f FFMpeg) GenerateOutput(ctx context.Context, args []string, stdin io.Reader) ([]byte, error) { cmd := f.Command(ctx, args) + cmd.Stdin = stdin - return cmd.Output() + ret, err := cmd.Output() + if err != nil { + return nil, fmt.Errorf("error running ffmpeg command <%s>: %w", strings.Join(args, " "), err) + } + + return ret, nil } diff --git a/pkg/ffmpeg/transcoder/image.go b/pkg/ffmpeg/transcoder/image.go index b6e7642f1..a476dff42 100644 --- a/pkg/ffmpeg/transcoder/image.go +++ b/pkg/ffmpeg/transcoder/image.go @@ -20,6 +20,8 @@ func ImageThumbnail(input string, options ImageThumbnailOptions) ffmpeg.Args { videoFilter = videoFilter.ScaleMaxSize(options.MaxDimensions) var args ffmpeg.Args + args = append(args, "-hide_banner") + args = args.LogLevel(ffmpeg.LogLevelError) args = args.Overwrite(). ImageFormat(options.InputFormat). diff --git a/pkg/hash/videophash/phash.go b/pkg/hash/videophash/phash.go index 6cd96d8bd..8e81d894e 100644 --- a/pkg/hash/videophash/phash.go +++ b/pkg/hash/videophash/phash.go @@ -44,7 +44,7 @@ func generateSpriteScreenshot(encoder ffmpeg.FFMpeg, input string, t float64) (i } args := transcoder.ScreenshotTime(input, t, options) - data, err := encoder.GenerateOutput(context.Background(), args) + data, err := encoder.GenerateOutput(context.Background(), args, nil) if err != nil { return nil, err } diff --git a/pkg/image/thumbnail.go b/pkg/image/thumbnail.go index ed4b2b5ba..62c84cff6 100644 --- a/pkg/image/thumbnail.go +++ b/pkg/image/thumbnail.go @@ -117,5 +117,5 @@ func (e *ThumbnailEncoder) ffmpegImageThumbnail(image *bytes.Buffer, format stri Quality: ffmpegImageQuality, }) - return e.ffmpeg.GenerateOutput(context.TODO(), args) + return e.ffmpeg.GenerateOutput(context.TODO(), args, image) }