Browse Source

Local media storage

master
Jan-Lukas Else 1 week ago
parent
commit
4c87a95e73
5 changed files with 79 additions and 22 deletions
  1. +3
    -3
      config.go
  2. +4
    -3
      http.go
  3. +39
    -0
      media.go
  4. +3
    -5
      micropub.go
  5. +30
    -11
      micropubMedia.go

+ 3
- 3
config.go View File

@ -247,10 +247,10 @@ func initConfig() error {
if appConfig.Micropub.MediaStorage.MediaURL == "" ||
appConfig.Micropub.MediaStorage.BunnyStorageKey == "" ||
appConfig.Micropub.MediaStorage.BunnyStorageName == "" {
appConfig.Micropub.MediaStorage = nil
} else {
appConfig.Micropub.MediaStorage.MediaURL = strings.TrimSuffix(appConfig.Micropub.MediaStorage.MediaURL, "/")
appConfig.Micropub.MediaStorage.BunnyStorageKey = ""
appConfig.Micropub.MediaStorage.BunnyStorageName = ""
}
appConfig.Micropub.MediaStorage.MediaURL = strings.TrimSuffix(appConfig.Micropub.MediaStorage.MediaURL, "/")
}
return nil
}

+ 4
- 3
http.go View File

@ -103,9 +103,7 @@ func buildHandler() (http.Handler, error) {
mpRouter.Use(checkIndieAuth, middleware.NoCache, minifier.Middleware)
mpRouter.Get("/", serveMicropubQuery)
mpRouter.Post("/", serveMicropubPost)
if appConfig.Micropub.MediaStorage != nil {
mpRouter.Post(micropubMediaSubPath, serveMicropubMedia)
}
mpRouter.Post(micropubMediaSubPath, serveMicropubMedia)
})
// Editor
@ -182,6 +180,9 @@ func buildHandler() (http.Handler, error) {
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
r.With(cacheMiddleware).Get("/s/{id:[0-9a-fA-F]+}", redirectToLongPath)


+ 39
- 0
media.go View File

@ -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)
}

+ 3
- 5
micropub.go View File

@ -26,11 +26,9 @@ func serveMicropubQuery(w http.ResponseWriter, r *http.Request) {
case "config":
w.Header().Add(contentType, contentTypeJSONUTF8)
w.WriteHeader(http.StatusOK)
mc := &micropubConfig{}
if appConfig.Micropub.MediaStorage != nil {
mc.MediaEndpoint = appConfig.Server.PublicAddress + micropubPath + micropubMediaSubPath
}
_ = json.NewEncoder(w).Encode(mc)
_ = json.NewEncoder(w).Encode(&micropubConfig{
MediaEndpoint: appConfig.Server.PublicAddress + micropubPath + micropubMediaSubPath,
})
case "source":
var mf interface{}
if urlString := r.URL.Query().Get("url"); urlString != "" {


+ 30
- 11
micropubMedia.go View File

@ -63,34 +63,53 @@ func serveMicropubMedia(w http.ResponseWriter, r *http.Request) {
}
}
fileName += strings.ToLower(fileExtension)
location, err := appConfig.Micropub.MediaStorage.uploadToBunny(fileName, file)
// Save file
location, err := uploadFile(fileName, file)
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
}
if appConfig.Micropub.MediaStorage.TinifyKey != "" {
compressedLocation, err := appConfig.Micropub.MediaStorage.tinify(location)
// Try to compress file
if ms := appConfig.Micropub.MediaStorage; ms != nil && ms.TinifyKey != "" {
compressedLocation, err := tinify(location, ms)
if err != nil {
serveError(w, r, "failed to compress file: "+err.Error(), http.StatusInternalServerError)
return
} else if compressedLocation != "" {
location = compressedLocation
} else {
serveError(w, r, "No compressed location", http.StatusInternalServerError)
}
}
http.Redirect(w, r, location, http.StatusCreated)
}
func (mediaConf *configMicropubMedia) uploadToBunny(filename string, file multipart.File) (location string, err error) {
req, _ := http.NewRequest(http.MethodPut, fmt.Sprintf("https://storage.bunnycdn.com/%s/%s", url.PathEscape(mediaConf.BunnyStorageName), url.PathEscape(filename)), file)
req.Header.Add("AccessKey", mediaConf.BunnyStorageKey)
func uploadFile(filename string, f io.Reader) (string, error) {
ms := appConfig.Micropub.MediaStorage
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)
if err != nil || resp.StatusCode != http.StatusCreated {
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 {
spliced := strings.Split(url, ".")
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)) {
return "", nil
}
tfgo.SetKey(mediaConf.TinifyKey)
tfgo.SetKey(config.TinifyKey)
s, err := tfgo.FromUrl(url)
if err != nil {
return "", err
@ -134,7 +153,7 @@ func (mediaConf *configMicropubMedia) tinify(url string) (location string, err e
if err != nil {
return "", err
}
location, err = mediaConf.uploadToBunny(fileName+"."+fileExtension, file)
location, err = uploadFile(fileName+"."+fileExtension, file)
return
}


Loading…
Cancel
Save