giffer

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

main.go (4101B)


      1 // build functions as a build script, building and bundling the package.
      2 package main
      3 
      4 import (
      5 	"archive/zip"
      6 	"bytes"
      7 	"flag"
      8 	"fmt"
      9 	"image/png"
     10 	"io"
     11 	"log"
     12 	"net/http"
     13 	"os"
     14 	"path/filepath"
     15 	"runtime"
     16 	"strings"
     17 
     18 	"github.com/jackmordaunt/icns"
     19 	"github.com/pkg/errors"
     20 )
     21 
     22 var (
     23 	dist   string
     24 	tags   string
     25 	icon   string
     26 	ui     string
     27 	ffmpeg string
     28 )
     29 
     30 func init() {
     31 	flag.StringVar(&dist, "dist", "dist", "folder to put artifact")
     32 	flag.StringVar(&icon, "icon", icon, "path to icon file (.png or .icns)")
     33 	flag.StringVar(&tags, "tags", tags, "build tags to pass to go build")
     34 	flag.StringVar(&ffmpeg, "ffmpeg", ffmpeg, "path to ffmpeg binary")
     35 	flag.StringVar(&ui, "ui", ui, "path to UI files")
     36 	flag.Parse()
     37 }
     38 
     39 func main() {
     40 	switch runtime.GOOS {
     41 	case "darwin":
     42 		builder := &Darwin{
     43 			Bin:       "giffer",
     44 			Pkg:       "github.com/jackmordaunt/giffer/cmd/desktop",
     45 			UI:        ui,
     46 			Icon:      icon,
     47 			FFmpeg:    ffmpeg,
     48 			BuildTags: tags,
     49 		}
     50 		if err := builder.Build(dist); err != nil {
     51 			log.Fatalf("building Giffer for MacOS: %v", err)
     52 		}
     53 	case "windows":
     54 		builder := &Windows{
     55 			Bin:       "giffer.exe",
     56 			Pkg:       "github.com/jackmordaunt/giffer/cmd/desktop",
     57 			UI:        ui,
     58 			Icon:      icon,
     59 			FFmpeg:    ffmpeg,
     60 			BuildTags: tags,
     61 		}
     62 		if err := builder.Build(dist); err != nil {
     63 			log.Fatalf("building Giffer for Windows: %v", err)
     64 		}
     65 	default:
     66 		log.Fatalf("OS %s is not supported", runtime.GOOS)
     67 	}
     68 
     69 }
     70 
     71 // WriteIcon writes out the icon.icns using specified source icon.
     72 // If the source icon is a .png then it is converted to .icns.
     73 func WriteIcon(in, out string) error {
     74 	var (
     75 		src io.ReadWriter
     76 		ext = filepath.Ext(in)
     77 	)
     78 	if ext != ".png" && ext != ".icns" {
     79 		return fmt.Errorf("icon must be .icns or .png: %s", icon)
     80 	}
     81 	inf, err := os.Open(in)
     82 	if err != nil {
     83 		return errors.Wrap(err, "opening input file")
     84 	}
     85 	defer inf.Close()
     86 	src = inf
     87 	if ext == ".png" {
     88 		img, err := png.Decode(inf)
     89 		if err != nil {
     90 			return errors.Wrap(err, "decoding png")
     91 		}
     92 		buf := bytes.NewBuffer(nil)
     93 		if err := icns.Encode(buf, img); err != nil {
     94 			return errors.Wrap(err, "encoding icns")
     95 		}
     96 		src = buf
     97 	}
     98 	outf, err := os.Create(out)
     99 	if err != nil {
    100 		return errors.Wrap(err, "creating output file")
    101 	}
    102 	defer outf.Close()
    103 	if _, err := io.Copy(outf, src); err != nil {
    104 		return err
    105 	}
    106 	return nil
    107 }
    108 
    109 // openZip returns the first file in the zip that contains the pattern.
    110 func openZip(u, dir, pattern string) (*bytes.Buffer, error) {
    111 	file, err := download(u, filepath.Join(dir, "ffmpeg.zip"))
    112 	if err != nil {
    113 		return nil, errors.Wrap(err, "downloading")
    114 	}
    115 	defer file.Close()
    116 	info, err := file.Stat()
    117 	if err != nil {
    118 		return nil, errors.Wrap(err, "getting file info")
    119 	}
    120 	zr, err := zip.NewReader(file, info.Size())
    121 	if err != nil {
    122 		return nil, errors.Wrap(err, "creating zip reader")
    123 	}
    124 	for _, zf := range zr.File {
    125 		if strings.Contains(zf.Name, pattern) {
    126 			var buf = bytes.NewBuffer(nil)
    127 			zfr, err := zf.Open()
    128 			if err != nil {
    129 				return nil, errors.Wrap(err, "reading zipped file")
    130 			}
    131 			defer zfr.Close()
    132 			if _, err := io.Copy(buf, zfr); err != nil {
    133 				return nil, errors.Wrap(err, "buffering zipped file")
    134 			}
    135 			return buf, nil
    136 		}
    137 	}
    138 	return nil, fmt.Errorf("no file found in zip for given pattern %q", pattern)
    139 }
    140 
    141 // download the file at the specified url.
    142 // If a file exists at dst, that file is returned.
    143 func download(u, dst string) (*os.File, error) {
    144 	dstf, err := os.Open(dst)
    145 	if err != nil && !os.IsNotExist(err) {
    146 		return nil, errors.Wrap(err, "opening downloaded file")
    147 	}
    148 	if err == nil {
    149 		return dstf, nil
    150 	}
    151 	resp, err := http.Get(u)
    152 	if err != nil {
    153 		return nil, errors.Wrap(err, "GET")
    154 	}
    155 	defer resp.Body.Close()
    156 	if !(resp.StatusCode >= http.StatusOK && resp.StatusCode < http.StatusMultipleChoices) {
    157 		return nil, fmt.Errorf("status %d", resp.StatusCode)
    158 	}
    159 	zipf, err := os.Create(dst)
    160 	if err != nil {
    161 		return nil, errors.Wrap(err, "creating destination file")
    162 	}
    163 	if _, err := io.Copy(zipf, resp.Body); err != nil {
    164 		return nil, errors.Wrap(err, "copying body")
    165 	}
    166 	return zipf, nil
    167 }