mirror of https://github.com/jlelse/GoBlog
Local media storage
This commit is contained in:
parent
b2c618f300
commit
4c87a95e73
|
@ -247,10 +247,10 @@ func initConfig() error {
|
||||||
if appConfig.Micropub.MediaStorage.MediaURL == "" ||
|
if appConfig.Micropub.MediaStorage.MediaURL == "" ||
|
||||||
appConfig.Micropub.MediaStorage.BunnyStorageKey == "" ||
|
appConfig.Micropub.MediaStorage.BunnyStorageKey == "" ||
|
||||||
appConfig.Micropub.MediaStorage.BunnyStorageName == "" {
|
appConfig.Micropub.MediaStorage.BunnyStorageName == "" {
|
||||||
appConfig.Micropub.MediaStorage = nil
|
appConfig.Micropub.MediaStorage.BunnyStorageKey = ""
|
||||||
} else {
|
appConfig.Micropub.MediaStorage.BunnyStorageName = ""
|
||||||
appConfig.Micropub.MediaStorage.MediaURL = strings.TrimSuffix(appConfig.Micropub.MediaStorage.MediaURL, "/")
|
|
||||||
}
|
}
|
||||||
|
appConfig.Micropub.MediaStorage.MediaURL = strings.TrimSuffix(appConfig.Micropub.MediaStorage.MediaURL, "/")
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
7
http.go
7
http.go
|
@ -103,9 +103,7 @@ func buildHandler() (http.Handler, error) {
|
||||||
mpRouter.Use(checkIndieAuth, middleware.NoCache, minifier.Middleware)
|
mpRouter.Use(checkIndieAuth, middleware.NoCache, minifier.Middleware)
|
||||||
mpRouter.Get("/", serveMicropubQuery)
|
mpRouter.Get("/", serveMicropubQuery)
|
||||||
mpRouter.Post("/", serveMicropubPost)
|
mpRouter.Post("/", serveMicropubPost)
|
||||||
if appConfig.Micropub.MediaStorage != nil {
|
mpRouter.Post(micropubMediaSubPath, serveMicropubMedia)
|
||||||
mpRouter.Post(micropubMediaSubPath, serveMicropubMedia)
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
// Editor
|
// Editor
|
||||||
|
@ -182,6 +180,9 @@ func buildHandler() (http.Handler, error) {
|
||||||
r.With(cacheMiddleware).Get(path, serveStaticFile)
|
r.With(cacheMiddleware).Get(path, serveStaticFile)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Media files
|
||||||
|
r.With(cacheMiddleware).Get(`/m/{file:[0-9a-fA-F]+(\.[0-9a-zA-Z]+)?}`, serveMediaFile)
|
||||||
|
|
||||||
// Short paths
|
// Short paths
|
||||||
r.With(cacheMiddleware).Get("/s/{id:[0-9a-fA-F]+}", redirectToLongPath)
|
r.With(cacheMiddleware).Get("/s/{id:[0-9a-fA-F]+}", redirectToLongPath)
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,39 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
|
"github.com/go-chi/chi"
|
||||||
|
)
|
||||||
|
|
||||||
|
const mediaFilePath = "data/media"
|
||||||
|
|
||||||
|
func saveMediaFile(filename string, mediaFile io.Reader) (string, error) {
|
||||||
|
err := os.MkdirAll(mediaFilePath, 0644)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
newFile, err := os.Create(filepath.Join(mediaFilePath, filename))
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
_, err = io.Copy(newFile, mediaFile)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return "/m/" + filename, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func serveMediaFile(w http.ResponseWriter, r *http.Request) {
|
||||||
|
f := filepath.Join(mediaFilePath, chi.URLParam(r, "file"))
|
||||||
|
_, err := os.Stat(f)
|
||||||
|
if err != nil {
|
||||||
|
serve404(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
w.Header().Add("Cache-Control", "public,max-age=31536000,immutable")
|
||||||
|
http.ServeFile(w, r, f)
|
||||||
|
}
|
|
@ -26,11 +26,9 @@ func serveMicropubQuery(w http.ResponseWriter, r *http.Request) {
|
||||||
case "config":
|
case "config":
|
||||||
w.Header().Add(contentType, contentTypeJSONUTF8)
|
w.Header().Add(contentType, contentTypeJSONUTF8)
|
||||||
w.WriteHeader(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
mc := µpubConfig{}
|
_ = json.NewEncoder(w).Encode(µpubConfig{
|
||||||
if appConfig.Micropub.MediaStorage != nil {
|
MediaEndpoint: appConfig.Server.PublicAddress + micropubPath + micropubMediaSubPath,
|
||||||
mc.MediaEndpoint = appConfig.Server.PublicAddress + micropubPath + micropubMediaSubPath
|
})
|
||||||
}
|
|
||||||
_ = json.NewEncoder(w).Encode(mc)
|
|
||||||
case "source":
|
case "source":
|
||||||
var mf interface{}
|
var mf interface{}
|
||||||
if urlString := r.URL.Query().Get("url"); urlString != "" {
|
if urlString := r.URL.Query().Get("url"); urlString != "" {
|
||||||
|
|
|
@ -63,34 +63,53 @@ func serveMicropubMedia(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fileName += strings.ToLower(fileExtension)
|
fileName += strings.ToLower(fileExtension)
|
||||||
location, err := appConfig.Micropub.MediaStorage.uploadToBunny(fileName, file)
|
// Save file
|
||||||
|
location, err := uploadFile(fileName, file)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
serveError(w, r, "failed to upload original file: "+err.Error(), http.StatusInternalServerError)
|
serveError(w, r, "failed to save original file: "+err.Error(), http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if appConfig.Micropub.MediaStorage.TinifyKey != "" {
|
// Try to compress file
|
||||||
compressedLocation, err := appConfig.Micropub.MediaStorage.tinify(location)
|
if ms := appConfig.Micropub.MediaStorage; ms != nil && ms.TinifyKey != "" {
|
||||||
|
compressedLocation, err := tinify(location, ms)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
serveError(w, r, "failed to compress file: "+err.Error(), http.StatusInternalServerError)
|
serveError(w, r, "failed to compress file: "+err.Error(), http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
} else if compressedLocation != "" {
|
} else if compressedLocation != "" {
|
||||||
location = compressedLocation
|
location = compressedLocation
|
||||||
|
} else {
|
||||||
|
serveError(w, r, "No compressed location", http.StatusInternalServerError)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
http.Redirect(w, r, location, http.StatusCreated)
|
http.Redirect(w, r, location, http.StatusCreated)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (mediaConf *configMicropubMedia) uploadToBunny(filename string, file multipart.File) (location string, err error) {
|
func uploadFile(filename string, f io.Reader) (string, error) {
|
||||||
req, _ := http.NewRequest(http.MethodPut, fmt.Sprintf("https://storage.bunnycdn.com/%s/%s", url.PathEscape(mediaConf.BunnyStorageName), url.PathEscape(filename)), file)
|
ms := appConfig.Micropub.MediaStorage
|
||||||
req.Header.Add("AccessKey", mediaConf.BunnyStorageKey)
|
if ms != nil && ms.BunnyStorageKey != "" && ms.BunnyStorageName != "" {
|
||||||
|
return uploadToBunny(filename, f, ms)
|
||||||
|
}
|
||||||
|
loc, err := saveMediaFile(filename, f)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
if ms != nil && ms.MediaURL != "" {
|
||||||
|
return ms.MediaURL + loc, nil
|
||||||
|
}
|
||||||
|
return loc, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func uploadToBunny(filename string, f io.Reader, config *configMicropubMedia) (location string, err error) {
|
||||||
|
req, _ := http.NewRequest(http.MethodPut, fmt.Sprintf("https://storage.bunnycdn.com/%s/%s", url.PathEscape(config.BunnyStorageName), url.PathEscape(filename)), f)
|
||||||
|
req.Header.Add("AccessKey", config.BunnyStorageKey)
|
||||||
resp, err := http.DefaultClient.Do(req)
|
resp, err := http.DefaultClient.Do(req)
|
||||||
if err != nil || resp.StatusCode != http.StatusCreated {
|
if err != nil || resp.StatusCode != http.StatusCreated {
|
||||||
return "", errors.New("failed to upload file to BunnyCDN")
|
return "", errors.New("failed to upload file to BunnyCDN")
|
||||||
}
|
}
|
||||||
return mediaConf.MediaURL + "/" + filename, nil
|
return config.MediaURL + "/" + filename, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (mediaConf *configMicropubMedia) tinify(url string) (location string, err error) {
|
func tinify(url string, config *configMicropubMedia) (location string, err error) {
|
||||||
fileExtension := func() string {
|
fileExtension := func() string {
|
||||||
spliced := strings.Split(url, ".")
|
spliced := strings.Split(url, ".")
|
||||||
return spliced[len(spliced)-1]
|
return spliced[len(spliced)-1]
|
||||||
|
@ -101,7 +120,7 @@ func (mediaConf *configMicropubMedia) tinify(url string) (location string, err e
|
||||||
if !(i < len(supportedTypes) && supportedTypes[i] == strings.ToLower(fileExtension)) {
|
if !(i < len(supportedTypes) && supportedTypes[i] == strings.ToLower(fileExtension)) {
|
||||||
return "", nil
|
return "", nil
|
||||||
}
|
}
|
||||||
tfgo.SetKey(mediaConf.TinifyKey)
|
tfgo.SetKey(config.TinifyKey)
|
||||||
s, err := tfgo.FromUrl(url)
|
s, err := tfgo.FromUrl(url)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
|
@ -134,7 +153,7 @@ func (mediaConf *configMicropubMedia) tinify(url string) (location string, err e
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
location, err = mediaConf.uploadToBunny(fileName+"."+fileExtension, file)
|
location, err = uploadFile(fileName+"."+fileExtension, file)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue