hugo-micropub/imagecompression.go

141 lines
3.0 KiB
Go
Raw Normal View History

2020-01-19 09:55:18 +00:00
package main
import (
2020-07-21 19:40:39 +00:00
"bytes"
"encoding/json"
2020-01-19 09:55:18 +00:00
"errors"
2020-07-21 19:40:39 +00:00
"io"
2020-01-19 09:55:18 +00:00
"io/ioutil"
2020-07-21 19:40:39 +00:00
"net/http"
2020-01-19 09:55:18 +00:00
"os"
"sort"
"strings"
)
type ImageCompression interface {
Compress(url string) (location string, err error)
}
// Tinify
type Tinify struct {
// API Key
key string
}
2020-04-20 18:59:11 +00:00
func (t *Tinify) Compress(url string) (location string, err error) {
2020-01-19 09:55:18 +00:00
fileExtension := func() string {
spliced := strings.Split(url, ".")
return spliced[len(spliced)-1]
}()
supportedTypes := []string{"jpg", "jpeg", "png"}
sort.Strings(supportedTypes)
i := sort.SearchStrings(supportedTypes, strings.ToLower(fileExtension))
if !(i < len(supportedTypes) && supportedTypes[i] == strings.ToLower(fileExtension)) {
err = errors.New("file not supported")
return
}
2020-07-21 19:40:39 +00:00
// Shrink
shrinkedUrl, e := t.shrink(url)
2020-01-19 09:55:18 +00:00
if e != nil {
err = errors.New("failed to compress file")
return
}
2020-07-21 19:40:39 +00:00
// Create temp file
2020-01-19 09:55:18 +00:00
file, e := ioutil.TempFile("", "tiny-*."+fileExtension)
if e != nil {
err = errors.New("failed to create temporary file")
return
}
defer func() {
2020-07-21 19:40:39 +00:00
// Cleanup
2020-04-20 21:04:01 +00:00
_ = file.Close()
2020-01-19 09:55:18 +00:00
_ = os.Remove(file.Name())
}()
2020-07-21 19:40:39 +00:00
// Resize and download image
e = t.resize(shrinkedUrl, file)
2020-01-19 09:55:18 +00:00
if e != nil {
2020-07-21 19:40:39 +00:00
err = errors.New("failed to resize file or save compressed file")
2020-01-19 09:55:18 +00:00
return
}
hashFile, e := os.Open(file.Name())
defer func() { _ = hashFile.Close() }()
if e != nil {
err = errors.New("failed to open temporary file")
return
}
fileName, err := getSHA256(hashFile)
if err != nil {
return
}
location, err = SelectedMediaStorage.Upload(fileName+"."+fileExtension, file)
return
}
2020-07-21 19:40:39 +00:00
func (t *Tinify) shrink(source string) (string, error) {
type Source struct {
Url string `json:"url"`
}
data := struct {
Source Source `json:"source"`
}{
Source: Source{
Url: source,
},
}
body := new(bytes.Buffer)
err := json.NewEncoder(body).Encode(data)
if err != nil {
return "", err
}
req, err := http.NewRequest("POST", "https://api.tinify.com/shrink", body)
if err != nil {
return "", err
}
req.SetBasicAuth("api", t.key)
req.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
return "", err
}
if resp.StatusCode != 201 {
return "", errors.New("not 201 response code")
}
return resp.Header.Get("Location"), nil
}
func (t *Tinify) resize(output string, file *os.File) error {
type Resize struct {
Method string `json:"method"`
Width int `json:"width"`
}
data := struct {
Resize Resize `json:"resize"`
}{
Resize: Resize{
Method: "scale",
Width: 2000,
},
}
body := new(bytes.Buffer)
err := json.NewEncoder(body).Encode(data)
if err != nil {
return err
}
req, err := http.NewRequest("POST", output, body)
if err != nil {
return err
}
req.SetBasicAuth("api", t.key)
req.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
if resp.StatusCode != 200 {
return errors.New("not 201 response code")
}
defer resp.Body.Close()
_, err = io.Copy(file, resp.Body)
return err
}