From de93a9a7ad2d3d1d6f36615f44b1a9da5958a17c Mon Sep 17 00:00:00 2001 From: Max Holland Date: Mon, 23 Oct 2023 10:45:59 +0100 Subject: [PATCH] Generate latest thumbnail image for each segment (#37) * Generate latest thumbnail image for each segment * more efficient to just set the timepoint to extract from * log context * resize * Revert "log context" This reverts commit 2bc16887368ac69505d509068a9f21e0a80901c1. * return error and log --- core/uploader.go | 60 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 59 insertions(+), 1 deletion(-) diff --git a/core/uploader.go b/core/uploader.go index 85d2d6a..f367892 100644 --- a/core/uploader.go +++ b/core/uploader.go @@ -7,6 +7,9 @@ import ( "fmt" "io" "log" + "os" + "os/exec" + "path/filepath" "strings" "time" @@ -38,7 +41,14 @@ func Upload(input io.Reader, outputURI string, waitBetweenWrites, writeTimeout t // For segments we just write them in one go here and return early. // (Otherwise the incremental write logic below caused issues with clipping since it results in partial segments being written.) _, err := session.SaveData(context.Background(), "", input, fields, writeTimeout) - return err + if err != nil { + return err + } + + if err = extractThumb(session); err != nil { + log.Printf("extracting thumbnail failed: %s", err) + } + return nil } var fileContents = []byte{} @@ -88,3 +98,51 @@ func Upload(input io.Reader, outputURI string, waitBetweenWrites, writeTimeout t return nil } + +func extractThumb(session drivers.OSSession) error { + presigned, err := session.Presign("", 5*time.Minute) + if err != nil { + return fmt.Errorf("presigning failed: %w", err) + } + + outDir, err := os.MkdirTemp(os.TempDir(), "thumb-*") + if err != nil { + return fmt.Errorf("temp file creation failed: %w", err) + } + defer os.RemoveAll(outDir) + outFile := filepath.Join(outDir, "out.jpg") + + args := []string{ + "-i", presigned, + "-ss", "00:00:00", + "-vframes", "1", + "-vf", "scale=320:240:force_original_aspect_ratio=decrease", + "-y", + outFile, + } + + timeout, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + cmd := exec.CommandContext(timeout, "ffmpeg", args...) + + var outputBuf bytes.Buffer + var stdErr bytes.Buffer + cmd.Stdout = &outputBuf + cmd.Stderr = &stdErr + + err = cmd.Run() + if err != nil { + return fmt.Errorf("ffmpeg failed[%s] [%s]: %w", outputBuf.String(), stdErr.String(), err) + } + + f, err := os.Open(outFile) + if err != nil { + return fmt.Errorf("opening file failed: %w", err) + } + defer f.Close() + _, err = session.SaveData(context.Background(), "../latest.jpg", f, &drivers.FileProperties{CacheControl: "max-age=5"}, 10*time.Second) + if err != nil { + return fmt.Errorf("saving thumbnail failed: %w", err) + } + return nil +}