From 84cba437249e3c109435c9b93a4026c6098cb491 Mon Sep 17 00:00:00 2001 From: James Mills Date: Sat, 21 Mar 2020 10:46:03 +1000 Subject: [PATCH] Add support for on-demand thumbnail generation via github.com/mutschler/mt --- media/utils.go | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++ media/video.go | 14 +++++++++++++ 2 files changed, 70 insertions(+) create mode 100644 media/utils.go diff --git a/media/utils.go b/media/utils.go new file mode 100644 index 0000000..b67f276 --- /dev/null +++ b/media/utils.go @@ -0,0 +1,56 @@ +package media + +import ( + "bytes" + "fmt" + "os/exec" + "time" +) + +func cmdExists(cmd string) bool { + _, err := exec.LookPath(cmd) + return err == nil +} + +func runCmd(timeout int, command string, args ...string) error { + // instantiate new command + cmd := exec.Command(command, args...) + + // get pipe to standard output + stdout, err := cmd.StdoutPipe() + if err != nil { + return fmt.Errorf("cmd.StdoutPipe() error: %w", err) + } + + // start process via command + if err := cmd.Start(); err != nil { + return fmt.Errorf("cmd.Start() error: %w", err) + } + + // setup a buffer to capture standard output + var buf bytes.Buffer + + // create a channel to capture any errors from wait + done := make(chan error) + go func() { + if _, err := buf.ReadFrom(stdout); err != nil { + panic("buf.Read(stdout) error: " + err.Error()) + } + done <- cmd.Wait() + }() + + // block on select, and switch based on actions received + select { + case <-time.After(time.Duration(timeout) * time.Second): + if err := cmd.Process.Kill(); err != nil { + return fmt.Errorf("failed to kill: %w", err) + } + return fmt.Errorf("timeout reached, process killed") + case err := <-done: + if err != nil { + close(done) + return fmt.Errorf("process done, with error: %w", err) + } + return nil + } +} diff --git a/media/video.go b/media/video.go index 9340e86..9c10b1e 100644 --- a/media/video.go +++ b/media/video.go @@ -1,8 +1,11 @@ package media import ( + "fmt" + "io/ioutil" "os" "path" + "path/filepath" "strings" "time" @@ -72,6 +75,17 @@ func ParseVideo(p *Path, name string) (*Video, error) { if pic != nil { v.Thumb = pic.Data v.ThumbType = pic.MIMEType + } else if cmdExists("mt") { + if err := runCmd(3, "mt", "-s", "-n", "1", pth); err != nil { + return nil, err + } + data, err := ioutil.ReadFile(fmt.Sprintf("%s.jpg", strings.TrimSuffix(pth, filepath.Ext(pth)))) + if err != nil { + return nil, err + } + v.Thumb = data + v.ThumbType = "image/jpeg" } + return v, nil }