2017-11-18 00:11:39 +00:00
|
|
|
package contented
|
|
|
|
|
|
|
|
import (
|
2018-09-09 06:31:25 +00:00
|
|
|
"context"
|
2017-11-18 00:11:39 +00:00
|
|
|
"errors"
|
|
|
|
"fmt"
|
|
|
|
"log"
|
|
|
|
"net/http"
|
|
|
|
"path/filepath"
|
|
|
|
|
|
|
|
"code.ivysaur.me/thumbnail"
|
|
|
|
)
|
|
|
|
|
2018-06-09 06:09:57 +00:00
|
|
|
func getThumbnailerConfig(t byte) (*thumbnail.Config, error) {
|
2017-11-18 00:11:39 +00:00
|
|
|
// Modelled on what imgur.com offers
|
|
|
|
// @ref https://api.imgur.com/models/image#thumbs
|
|
|
|
|
2018-06-09 06:09:57 +00:00
|
|
|
opts := thumbnail.Config{
|
|
|
|
Aspect: thumbnail.FitOutside,
|
|
|
|
Output: thumbnail.Jpeg,
|
|
|
|
Scale: thumbnail.Bicubic,
|
|
|
|
}
|
2017-11-18 00:11:39 +00:00
|
|
|
|
|
|
|
switch t {
|
|
|
|
case 's':
|
2018-06-09 06:09:57 +00:00
|
|
|
opts.Width = 90
|
|
|
|
opts.Height = 90
|
2017-11-18 00:11:39 +00:00
|
|
|
case 'b':
|
2018-06-09 06:09:57 +00:00
|
|
|
opts.Width = 160
|
|
|
|
opts.Height = 160
|
2017-11-18 00:11:39 +00:00
|
|
|
case 't':
|
2018-06-09 06:09:57 +00:00
|
|
|
opts.Width = 160
|
|
|
|
opts.Height = 160
|
|
|
|
// thumbnail.ASPECT_RESPECT_MAX_DIMENSION_ONLY
|
2017-11-18 00:11:39 +00:00
|
|
|
case 'm':
|
2018-06-09 06:09:57 +00:00
|
|
|
opts.Width = 340
|
|
|
|
opts.Height = 340
|
|
|
|
// thumbnail.ASPECT_RESPECT_MAX_DIMENSION_ONLY
|
2017-11-18 00:11:39 +00:00
|
|
|
case 'l':
|
2018-06-09 06:09:57 +00:00
|
|
|
opts.Width = 640
|
|
|
|
opts.Height = 640
|
|
|
|
// thumbnail.ASPECT_RESPECT_MAX_DIMENSION_ONLY
|
2017-11-18 00:11:39 +00:00
|
|
|
case 'h':
|
2018-06-09 06:09:57 +00:00
|
|
|
opts.Width = 1024
|
|
|
|
opts.Height = 1024
|
|
|
|
// thumbnail.ASPECT_RESPECT_MAX_DIMENSION_ONLY
|
2017-11-18 00:11:39 +00:00
|
|
|
default:
|
|
|
|
return nil, errors.New("Unsupported thumbnail type (should be s/b/t/m/l/h)")
|
|
|
|
}
|
2018-06-09 06:09:57 +00:00
|
|
|
|
|
|
|
return &opts, nil
|
2017-11-18 00:11:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (this *Server) handleThumb(w http.ResponseWriter, r *http.Request, thumbnailType byte, fileId string) {
|
2018-09-09 06:31:25 +00:00
|
|
|
ctx := r.Context()
|
|
|
|
|
2018-06-09 06:09:57 +00:00
|
|
|
opts, err := getThumbnailerConfig(thumbnailType)
|
2017-11-18 00:11:39 +00:00
|
|
|
if err != nil {
|
|
|
|
log.Printf("%s Thumbnail failed: %s\n", this.remoteIP(r), err.Error())
|
2017-11-18 00:27:07 +00:00
|
|
|
http.Error(w, err.Error(), 400)
|
|
|
|
return
|
2017-11-18 00:11:39 +00:00
|
|
|
}
|
|
|
|
|
2018-09-09 06:31:25 +00:00
|
|
|
// Only calculate one thumbnail at a time
|
|
|
|
this.thumbnailSem.Lock()
|
|
|
|
defer this.thumbnailSem.Unlock()
|
|
|
|
|
|
|
|
if ctx.Err() != nil {
|
|
|
|
// The request was already cancelled
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2018-06-09 06:09:57 +00:00
|
|
|
t := thumbnail.NewThumbnailerEx(opts)
|
|
|
|
|
2018-09-09 06:31:25 +00:00
|
|
|
err = this.handleThumbInternal(ctx, w, t, fileId)
|
2017-11-18 00:11:39 +00:00
|
|
|
if err != nil {
|
2017-11-18 00:27:07 +00:00
|
|
|
log.Printf("%s Thumbnail failed: %s\n", this.remoteIP(r), err.Error())
|
|
|
|
|
2018-06-09 06:09:57 +00:00
|
|
|
w.Header().Set(`Location`, fmt.Sprintf(`/nothumb_%d.png`, opts.Height))
|
2017-11-18 00:27:07 +00:00
|
|
|
w.WriteHeader(302)
|
2017-11-18 00:11:39 +00:00
|
|
|
}
|
2017-11-18 00:27:07 +00:00
|
|
|
}
|
|
|
|
|
2018-09-09 06:31:25 +00:00
|
|
|
func (this *Server) handleThumbInternal(ctx context.Context, w http.ResponseWriter, t thumbnail.Thumbnailer, fileId string) error {
|
2017-11-18 00:11:39 +00:00
|
|
|
|
|
|
|
// Load metadata
|
|
|
|
m, err := this.Metadata(fileId)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
filePath := filepath.Join(this.opts.DataDirectory, m.FileHash)
|
2018-06-09 06:09:57 +00:00
|
|
|
thumb, err := t.RenderFileAs(filePath, m.MimeType)
|
2017-11-18 00:11:39 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
w.Header().Set(`Content-Length`, fmt.Sprintf("%d", len(thumb)))
|
|
|
|
w.Header().Set(`Content-Type`, `image/jpeg`)
|
|
|
|
w.WriteHeader(200)
|
|
|
|
w.Write(thumb)
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|