Add Cloudflare as image compression service

This commit is contained in:
Jan-Lukas Else 2021-04-21 20:10:32 +02:00
parent adb6a31b3d
commit a24cad5699
4 changed files with 84 additions and 27 deletions

View File

@ -170,11 +170,12 @@ type configMicropub struct {
}
type configMicropubMedia struct {
MediaURL string `mapstructure:"mediaUrl"`
BunnyStorageKey string `mapstructure:"bunnyStorageKey"`
BunnyStorageName string `mapstructure:"bunnyStorageName"`
TinifyKey string `mapstructure:"tinifyKey"`
ShortPixelKey string `mapstructure:"shortPixelKey"`
MediaURL string `mapstructure:"mediaUrl"`
BunnyStorageKey string `mapstructure:"bunnyStorageKey"`
BunnyStorageName string `mapstructure:"bunnyStorageName"`
TinifyKey string `mapstructure:"tinifyKey"`
ShortPixelKey string `mapstructure:"shortPixelKey"`
CloudflareCompressionEnabled bool `mapstructure:"cloudflareCompressionEnabled"`
}
type configRegexRedirect struct {

View File

@ -78,9 +78,10 @@ micropub:
# BunnyCDN storage (optional)
bunnyStorageKey: BUNNY-STORAGE-KEY # Secret key for BunnyCDN storage
bunnyStorageName: storagename # BunnyCDN storage name
# Image compression (optional, you can define no, one or both)
tinifyKey: TINIFY-KEY # Secret key for the Tinify.com API
# Image compression (optional, you can define no, one or multiple services, disabled when private mode enabled)
shortPixelKey: SHORT-PIXEL-KEY # Secret key for the ShortPixel API
tinifyKey: TINIFY-KEY # Secret key for the Tinify.com API (first fallback)
cloudflareCompressionEnabled: true # Use Cloudflare's compression as a second fallback
# MicroPub parameters (defaults already set, set to overwrite)
# You can set parameters via the UI of your MicroPub editor or via front matter in the content
categoryParam: tags

View File

@ -149,3 +149,47 @@ func shortPixel(url string, config *configMicropubMedia) (location string, err e
location, err = uploadFile(fileName+"."+fileExtension, tmpFile)
return
}
func cloudflare(url string) (location string, err error) {
// Check url
_, allowed := compressionIsSupported(url, "jpg", "jpeg", "png")
if !allowed {
return "", nil
}
// Force jpeg
fileExtension := "jpeg"
// Compress
req, err := http.NewRequest(http.MethodGet, fmt.Sprintf("https://www.cloudflare.com/cdn-cgi/image/f=jpeg,q=75,metadata=none,fit=scale-down,w=%d,h=%d/%s", defaultCompressionWidth, defaultCompressionHeight, url), nil)
if err != nil {
return "", err
}
resp, err := appHttpClient.Do(req)
if err != nil {
return "", err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
_, _ = io.Copy(io.Discard, resp.Body)
return "", fmt.Errorf("cloudflare failed to compress image, status code %d", resp.StatusCode)
}
tmpFile, err := os.CreateTemp("", "tiny-*."+fileExtension)
if err != nil {
_, _ = io.Copy(io.Discard, resp.Body)
return "", err
}
defer func() {
_ = tmpFile.Close()
_ = os.Remove(tmpFile.Name())
}()
if _, err = io.Copy(tmpFile, resp.Body); err != nil {
_, _ = io.Copy(io.Discard, resp.Body)
return "", err
}
fileName, err := getSHA256(tmpFile)
if err != nil {
return "", err
}
// Upload compressed file
location, err = uploadFile(fileName+"."+fileExtension, tmpFile)
return
}

View File

@ -60,31 +60,42 @@ func serveMicropubMedia(w http.ResponseWriter, r *http.Request) {
serveError(w, r, "failed to save original file: "+err.Error(), http.StatusInternalServerError)
return
}
// Try to compress file
if ms := appConfig.Micropub.MediaStorage; ms != nil {
// Try to compress file (only when not in private mode)
if pm := appConfig.PrivateMode; !(pm != nil && pm.Enabled) {
serveCompressionError := func(ce error) {
serveError(w, r, "failed to compress file: "+ce.Error(), http.StatusInternalServerError)
}
var compressedLocation string
var compressionErr error
// Default ShortPixel
if ms.ShortPixelKey != "" {
compressedLocation, compressionErr = shortPixel(location, ms)
}
if compressionErr != nil {
serveCompressionError(compressionErr)
return
}
// Fallback Tinify
if compressedLocation == "" && ms.TinifyKey != "" {
compressedLocation, compressionErr = tinify(location, ms)
}
if compressionErr != nil {
serveCompressionError(compressionErr)
return
}
if compressedLocation != "" {
location = compressedLocation
if ms := appConfig.Micropub.MediaStorage; ms != nil {
// Default ShortPixel
if ms.ShortPixelKey != "" {
compressedLocation, compressionErr = shortPixel(location, ms)
}
if compressionErr != nil {
serveCompressionError(compressionErr)
return
}
// Fallback Tinify
if compressedLocation == "" && ms.TinifyKey != "" {
compressedLocation, compressionErr = tinify(location, ms)
}
if compressionErr != nil {
serveCompressionError(compressionErr)
return
}
// Fallback Cloudflare
if compressedLocation == "" && ms.CloudflareCompressionEnabled {
compressedLocation, compressionErr = cloudflare(location)
}
if compressionErr != nil {
serveCompressionError(compressionErr)
return
}
// Overwrite location
if compressedLocation != "" {
location = compressedLocation
}
}
}
http.Redirect(w, r, location, http.StatusCreated)