Add support for image compression

master
Jan-Lukas Else 2020-01-19 10:55:18 +01:00
parent 962818c931
commit 9ca7da9ae5
6 changed files with 106 additions and 9 deletions

View File

@ -9,6 +9,7 @@ import (
var (
BlogUrl string
MediaEndpointUrl string
IgnoredWebmentionUrls []string
SyndicationTargets []SyndicationTarget
SelectedStorage Storage
@ -16,7 +17,7 @@ var (
SelectedCdn Cdn
SelectedSocials Socials
SelectedNotificationServices NotificationServices
MediaEndpointUrl string
SelectedImageCompression ImageCompression
)
type SyndicationTarget struct {
@ -39,6 +40,7 @@ type config struct {
TelegramBotToken string `env:"TELEGRAM_BOT_TOKEN"`
IgnoredWebmentionUrls []string `env:"WEBMENTION_IGNORED" envSeparator:","`
SyndicationTargets []string `env:"SYNDICATION" envSeparator:","`
TinifyKey string `env:"TINIFY_KEY"`
}
func initConfig() (err error) {
@ -138,5 +140,18 @@ func initConfig() (err error) {
if SelectedNotificationServices == nil {
log.Println("No notification services configured")
}
// Find configured image compression service (optional)
SelectedImageCompression = func() ImageCompression {
// Tinify
if len(cfg.TinifyKey) > 0 {
return &Tinify{
key: cfg.TinifyKey,
}
}
return nil
}()
if SelectedImageCompression == nil {
log.Println("no image compression configured")
}
return nil
}

1
go.mod
View File

@ -5,6 +5,7 @@ go 1.13
require (
github.com/caarlos0/env/v6 v6.1.0
github.com/go-telegram-bot-api/telegram-bot-api v4.6.5-0.20190904012038-b33efeebc785+incompatible
github.com/gwpp/tinify-go v0.0.0-20170613055357-77b9df15f343
github.com/technoweenie/multipartstreamer v1.0.1 // indirect
gopkg.in/yaml.v2 v2.2.7
willnorris.com/go/webmention v0.0.0-20191104072158-c7fb13569b62

2
go.sum
View File

@ -8,6 +8,8 @@ github.com/go-telegram-bot-api/telegram-bot-api v4.6.5-0.20190904012038-b33efeeb
github.com/go-telegram-bot-api/telegram-bot-api v4.6.5-0.20190904012038-b33efeebc785+incompatible/go.mod h1:qf9acutJ8cwBUhm1bqgz6Bei9/C/c93FPDljKWwsOgM=
github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/gwpp/tinify-go v0.0.0-20170613055357-77b9df15f343 h1:QbWv77mi5YeTWR3FxLqx5eeC2H0fUL07Kj2Uhza9/A8=
github.com/gwpp/tinify-go v0.0.0-20170613055357-77b9df15f343/go.mod h1:FP1q8rlReJYgAj3zqyQfD745uokKzl0baffXAcxDcl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=

65
imagecompression.go Normal file
View File

@ -0,0 +1,65 @@
package main
import (
"errors"
tfgo "github.com/gwpp/tinify-go/tinify"
"io/ioutil"
"os"
"sort"
"strings"
)
type ImageCompression interface {
Compress(url string) (location string, err error)
}
// Tinify
type Tinify struct {
// API Key
key string
}
func (t Tinify) Compress(url string) (location string, err error) {
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
}
tfgo.SetKey(t.key)
s, e := tfgo.FromUrl(url)
if e != nil {
err = errors.New("failed to compress file")
return
}
file, e := ioutil.TempFile("", "tiny-*."+fileExtension)
if e != nil {
err = errors.New("failed to create temporary file")
return
}
defer func() {
_ = os.Remove(file.Name())
}()
e = s.ToFile(file.Name())
if e != nil {
err = errors.New("failed to save compressed file")
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
}

View File

@ -1,9 +1,6 @@
package main
import (
"crypto/sha256"
"fmt"
"io"
"mime"
"net/http"
"path/filepath"
@ -44,14 +41,13 @@ func HandleMedia(w http.ResponseWriter, r *http.Request) {
return
}
hashFile, _, _ := r.FormFile("file")
h := sha256.New()
defer func() { _ = hashFile.Close() }()
if _, err := io.Copy(h, hashFile); err != nil {
fileName, err := getSHA256(hashFile)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
_, _ = w.Write([]byte("Failed to calculate hash of file"))
_, _ = w.Write([]byte(err.Error()))
return
}
fileName := fmt.Sprintf("%x", h.Sum(nil))
fileExtension := filepath.Ext(header.Filename)
if len(fileExtension) == 0 {
// Find correct file extension if original filename does not contain one
@ -67,9 +63,15 @@ func HandleMedia(w http.ResponseWriter, r *http.Request) {
location, err := SelectedMediaStorage.Upload(fileName, file)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
_, _ = w.Write([]byte("Failed to upload file"))
_, _ = w.Write([]byte("Failed to upload original file"))
return
}
if SelectedImageCompression != nil {
compressedLocation, err := SelectedImageCompression.Compress(location)
if err == nil && len(compressedLocation) > 0 {
location = compressedLocation
}
}
w.Header().Add("Location", location)
w.WriteHeader(http.StatusCreated)
} else {

View File

@ -1,7 +1,10 @@
package main
import (
"crypto/sha256"
"errors"
"fmt"
"io"
"mime/multipart"
"net/http"
"net/url"
@ -33,3 +36,12 @@ func (b BunnyCdnStorage) Upload(fileName string, file multipart.File) (location
}
return b.baseLocation + fileName, nil
}
func getSHA256(file multipart.File) (filename string, err error) {
h := sha256.New()
if _, e := io.Copy(h, file); e != nil {
err = errors.New("failed to calculate hash of file")
return
}
return fmt.Sprintf("%x", h.Sum(nil)), nil
}