mirror of https://github.com/jlelse/GoBlog
Add Cloudflare as image compression service
This commit is contained in:
parent
adb6a31b3d
commit
a24cad5699
11
config.go
11
config.go
|
@ -170,11 +170,12 @@ type configMicropub struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type configMicropubMedia struct {
|
type configMicropubMedia struct {
|
||||||
MediaURL string `mapstructure:"mediaUrl"`
|
MediaURL string `mapstructure:"mediaUrl"`
|
||||||
BunnyStorageKey string `mapstructure:"bunnyStorageKey"`
|
BunnyStorageKey string `mapstructure:"bunnyStorageKey"`
|
||||||
BunnyStorageName string `mapstructure:"bunnyStorageName"`
|
BunnyStorageName string `mapstructure:"bunnyStorageName"`
|
||||||
TinifyKey string `mapstructure:"tinifyKey"`
|
TinifyKey string `mapstructure:"tinifyKey"`
|
||||||
ShortPixelKey string `mapstructure:"shortPixelKey"`
|
ShortPixelKey string `mapstructure:"shortPixelKey"`
|
||||||
|
CloudflareCompressionEnabled bool `mapstructure:"cloudflareCompressionEnabled"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type configRegexRedirect struct {
|
type configRegexRedirect struct {
|
||||||
|
|
|
@ -78,9 +78,10 @@ micropub:
|
||||||
# BunnyCDN storage (optional)
|
# BunnyCDN storage (optional)
|
||||||
bunnyStorageKey: BUNNY-STORAGE-KEY # Secret key for BunnyCDN storage
|
bunnyStorageKey: BUNNY-STORAGE-KEY # Secret key for BunnyCDN storage
|
||||||
bunnyStorageName: storagename # BunnyCDN storage name
|
bunnyStorageName: storagename # BunnyCDN storage name
|
||||||
# Image compression (optional, you can define no, one or both)
|
# Image compression (optional, you can define no, one or multiple services, disabled when private mode enabled)
|
||||||
tinifyKey: TINIFY-KEY # Secret key for the Tinify.com API
|
|
||||||
shortPixelKey: SHORT-PIXEL-KEY # Secret key for the ShortPixel API
|
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)
|
# 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
|
# You can set parameters via the UI of your MicroPub editor or via front matter in the content
|
||||||
categoryParam: tags
|
categoryParam: tags
|
||||||
|
|
|
@ -149,3 +149,47 @@ func shortPixel(url string, config *configMicropubMedia) (location string, err e
|
||||||
location, err = uploadFile(fileName+"."+fileExtension, tmpFile)
|
location, err = uploadFile(fileName+"."+fileExtension, tmpFile)
|
||||||
return
|
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
|
||||||
|
}
|
||||||
|
|
|
@ -60,31 +60,42 @@ func serveMicropubMedia(w http.ResponseWriter, r *http.Request) {
|
||||||
serveError(w, r, "failed to save original file: "+err.Error(), http.StatusInternalServerError)
|
serveError(w, r, "failed to save original file: "+err.Error(), http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// Try to compress file
|
// Try to compress file (only when not in private mode)
|
||||||
if ms := appConfig.Micropub.MediaStorage; ms != nil {
|
if pm := appConfig.PrivateMode; !(pm != nil && pm.Enabled) {
|
||||||
serveCompressionError := func(ce error) {
|
serveCompressionError := func(ce error) {
|
||||||
serveError(w, r, "failed to compress file: "+ce.Error(), http.StatusInternalServerError)
|
serveError(w, r, "failed to compress file: "+ce.Error(), http.StatusInternalServerError)
|
||||||
}
|
}
|
||||||
var compressedLocation string
|
var compressedLocation string
|
||||||
var compressionErr error
|
var compressionErr error
|
||||||
// Default ShortPixel
|
if ms := appConfig.Micropub.MediaStorage; ms != nil {
|
||||||
if ms.ShortPixelKey != "" {
|
// Default ShortPixel
|
||||||
compressedLocation, compressionErr = shortPixel(location, ms)
|
if ms.ShortPixelKey != "" {
|
||||||
}
|
compressedLocation, compressionErr = shortPixel(location, ms)
|
||||||
if compressionErr != nil {
|
}
|
||||||
serveCompressionError(compressionErr)
|
if compressionErr != nil {
|
||||||
return
|
serveCompressionError(compressionErr)
|
||||||
}
|
return
|
||||||
// Fallback Tinify
|
}
|
||||||
if compressedLocation == "" && ms.TinifyKey != "" {
|
// Fallback Tinify
|
||||||
compressedLocation, compressionErr = tinify(location, ms)
|
if compressedLocation == "" && ms.TinifyKey != "" {
|
||||||
}
|
compressedLocation, compressionErr = tinify(location, ms)
|
||||||
if compressionErr != nil {
|
}
|
||||||
serveCompressionError(compressionErr)
|
if compressionErr != nil {
|
||||||
return
|
serveCompressionError(compressionErr)
|
||||||
}
|
return
|
||||||
if compressedLocation != "" {
|
}
|
||||||
location = compressedLocation
|
// 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)
|
http.Redirect(w, r, location, http.StatusCreated)
|
||||||
|
|
Loading…
Reference in New Issue