giffer

Create .gif images from sites like youtube.com
Log | Files | Refs | LICENSE

commit 9385ac9a4d38d740bc836cc25b5074d5e00c8da0
parent 6ae2b35917c871e9d65259e1042bfb5611a90fb1
Author: Jack Mordaunt <jackmordaunt@gmail.com>
Date:   Mon, 12 Nov 2018 18:53:09 +1300

[~] Cleanup hash code and respond to upstream api changes.

Diffstat:
Mcmd/desktop/giffer.go | 91++++++++++++++++---------------------------------------------------------------
1 file changed, 18 insertions(+), 73 deletions(-)

diff --git a/cmd/desktop/giffer.go b/cmd/desktop/giffer.go @@ -3,16 +3,11 @@ package main import ( "bytes" "fmt" - "image" - "image/gif" "io" - "log" "path/filepath" "strings" - "sync" "github.com/OneOfOne/xxhash" - "github.com/disintegration/imaging" "github.com/jackmordaunt/giffer" "github.com/pkg/errors" ) @@ -41,14 +36,11 @@ func (g Giffer) GififyURL( if g.Store == nil { return g.make(url, start, end, fps, width, height, q) } - hasher := xxhash.New64() - input := fmt.Sprintf("%s_%f_%f_%f_%d_%d_%d", url, start, end, fps, width, height, q) - _, err := hasher.WriteString(input) + key, err := hash(fmt.Sprintf("%s_%f_%f_%f_%d_%d_%d", url, start, end, fps, width, height, q)) if err != nil { - return nil, errors.Wrap(err, "hashing input") + return nil, err } - hash := fmt.Sprintf("%d", hasher.Sum64()) - img, ok, err := g.Store.Lookup(hash) + img, ok, err := g.Store.Lookup(key) if err != nil { return nil, errors.Wrap(err, "store lookup") } @@ -63,7 +55,7 @@ func (g Giffer) GififyURL( Reader: bytes.NewBuffer([]byte(img.Reader.(*bytes.Buffer).String())), FileName: img.FileName, } - if err := g.Store.Insert(hash, dup); err != nil { + if err := g.Store.Insert(key, dup); err != nil { return nil, errors.Wrap(err, "inserting gif into store") } return img, nil @@ -75,71 +67,14 @@ func (g Giffer) make( width, height int, q giffer.Quality, ) (*RenderedGif, error) { - videofile, err := g.Download(url, q) + video, err := g.Download(url, q) if err != nil { return nil, errors.Wrap(err, "downloading") } - frames, err := g.Extract(videofile, start, end, fps) - if err != nil { - return nil, errors.Wrap(err, "extracting frames") - } - type processed struct { - Img *image.Paletted - Index int - } - images := make(chan processed) - wg := &sync.WaitGroup{} - wg.Add(len(frames)) - for ii, frame := range frames { - ii := ii - frame := frame - go func() { - defer wg.Done() - if width != 0 || height != 0 { - frame = imaging.Resize(frame, width, height, imaging.Box) - } - buf := bytes.Buffer{} - if err := gif.Encode(&buf, frame, nil); err != nil { - log.Printf("encoding gif: %v", err) - return - } - tmpimg, err := gif.Decode(&buf) - if err != nil { - log.Printf("decoding gif: %v", err) - return - } - images <- processed{ - Img: tmpimg.(*image.Paletted), - Index: ii, - } - }() - } - go func() { - wg.Wait() - close(images) - }() - paletted := make([]*image.Paletted, len(frames)) - for frame := range images { - paletted[frame.Index] = frame.Img - } - delays := make([]int, len(frames)) - delay := int(100 / fps) - for ii := range delays { - delays[ii] = delay - } - buf := bytes.NewBuffer(nil) - cfg := &gif.GIF{ - Image: paletted, - Delay: delays, - LoopCount: 0, - } - if err := gif.EncodeAll(buf, cfg); err != nil { - return nil, errors.Wrap(err, "encoding animated gif") - } + gif, err := g.Convert(video, start, end, fps, width, height, "gif", "gif") img := &RenderedGif{ - Reader: buf, - // Keep the title but replace the .mp4 extension with .gif - FileName: sanitiseFilepath(strings.Split(filepath.Base(videofile), ".")[0] + ".gif"), + Reader: gif, + FileName: sanitiseFilepath(strings.Split(filepath.Base(video), ".")[0] + ".gif"), } return img, nil } @@ -150,3 +85,13 @@ type RenderedGif struct { // FileName is <title>.<ext> FileName string } + +func hash(input string) (string, error) { + hasher := xxhash.New64() + _, err := hasher.WriteString(input) + if err != nil { + return "", errors.Wrap(err, "hashing input") + } + h := fmt.Sprintf("%d", hasher.Sum64()) + return h, nil +}