Add support for image compression
parent
962818c931
commit
9ca7da9ae5
17
config.go
17
config.go
|
@ -9,6 +9,7 @@ import (
|
||||||
|
|
||||||
var (
|
var (
|
||||||
BlogUrl string
|
BlogUrl string
|
||||||
|
MediaEndpointUrl string
|
||||||
IgnoredWebmentionUrls []string
|
IgnoredWebmentionUrls []string
|
||||||
SyndicationTargets []SyndicationTarget
|
SyndicationTargets []SyndicationTarget
|
||||||
SelectedStorage Storage
|
SelectedStorage Storage
|
||||||
|
@ -16,7 +17,7 @@ var (
|
||||||
SelectedCdn Cdn
|
SelectedCdn Cdn
|
||||||
SelectedSocials Socials
|
SelectedSocials Socials
|
||||||
SelectedNotificationServices NotificationServices
|
SelectedNotificationServices NotificationServices
|
||||||
MediaEndpointUrl string
|
SelectedImageCompression ImageCompression
|
||||||
)
|
)
|
||||||
|
|
||||||
type SyndicationTarget struct {
|
type SyndicationTarget struct {
|
||||||
|
@ -39,6 +40,7 @@ type config struct {
|
||||||
TelegramBotToken string `env:"TELEGRAM_BOT_TOKEN"`
|
TelegramBotToken string `env:"TELEGRAM_BOT_TOKEN"`
|
||||||
IgnoredWebmentionUrls []string `env:"WEBMENTION_IGNORED" envSeparator:","`
|
IgnoredWebmentionUrls []string `env:"WEBMENTION_IGNORED" envSeparator:","`
|
||||||
SyndicationTargets []string `env:"SYNDICATION" envSeparator:","`
|
SyndicationTargets []string `env:"SYNDICATION" envSeparator:","`
|
||||||
|
TinifyKey string `env:"TINIFY_KEY"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func initConfig() (err error) {
|
func initConfig() (err error) {
|
||||||
|
@ -138,5 +140,18 @@ func initConfig() (err error) {
|
||||||
if SelectedNotificationServices == nil {
|
if SelectedNotificationServices == nil {
|
||||||
log.Println("No notification services configured")
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
1
go.mod
1
go.mod
|
@ -5,6 +5,7 @@ go 1.13
|
||||||
require (
|
require (
|
||||||
github.com/caarlos0/env/v6 v6.1.0
|
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/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
|
github.com/technoweenie/multipartstreamer v1.0.1 // indirect
|
||||||
gopkg.in/yaml.v2 v2.2.7
|
gopkg.in/yaml.v2 v2.2.7
|
||||||
willnorris.com/go/webmention v0.0.0-20191104072158-c7fb13569b62
|
willnorris.com/go/webmention v0.0.0-20191104072158-c7fb13569b62
|
||||||
|
|
2
go.sum
2
go.sum
|
@ -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/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 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY=
|
||||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
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 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
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=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
|
@ -1,9 +1,6 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/sha256"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"mime"
|
"mime"
|
||||||
"net/http"
|
"net/http"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
@ -44,14 +41,13 @@ func HandleMedia(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
hashFile, _, _ := r.FormFile("file")
|
hashFile, _, _ := r.FormFile("file")
|
||||||
h := sha256.New()
|
|
||||||
defer func() { _ = hashFile.Close() }()
|
defer func() { _ = hashFile.Close() }()
|
||||||
if _, err := io.Copy(h, hashFile); err != nil {
|
fileName, err := getSHA256(hashFile)
|
||||||
|
if err != nil {
|
||||||
w.WriteHeader(http.StatusInternalServerError)
|
w.WriteHeader(http.StatusInternalServerError)
|
||||||
_, _ = w.Write([]byte("Failed to calculate hash of file"))
|
_, _ = w.Write([]byte(err.Error()))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
fileName := fmt.Sprintf("%x", h.Sum(nil))
|
|
||||||
fileExtension := filepath.Ext(header.Filename)
|
fileExtension := filepath.Ext(header.Filename)
|
||||||
if len(fileExtension) == 0 {
|
if len(fileExtension) == 0 {
|
||||||
// Find correct file extension if original filename does not contain one
|
// 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)
|
location, err := SelectedMediaStorage.Upload(fileName, file)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
w.WriteHeader(http.StatusInternalServerError)
|
w.WriteHeader(http.StatusInternalServerError)
|
||||||
_, _ = w.Write([]byte("Failed to upload file"))
|
_, _ = w.Write([]byte("Failed to upload original file"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if SelectedImageCompression != nil {
|
||||||
|
compressedLocation, err := SelectedImageCompression.Compress(location)
|
||||||
|
if err == nil && len(compressedLocation) > 0 {
|
||||||
|
location = compressedLocation
|
||||||
|
}
|
||||||
|
}
|
||||||
w.Header().Add("Location", location)
|
w.Header().Add("Location", location)
|
||||||
w.WriteHeader(http.StatusCreated)
|
w.WriteHeader(http.StatusCreated)
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -1,7 +1,10 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"crypto/sha256"
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
"mime/multipart"
|
"mime/multipart"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
@ -33,3 +36,12 @@ func (b BunnyCdnStorage) Upload(fileName string, file multipart.File) (location
|
||||||
}
|
}
|
||||||
return b.baseLocation + fileName, nil
|
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
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue