2020-06-26 14:26:36 +02:00
|
|
|
package api
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"image"
|
|
|
|
"image/color"
|
|
|
|
"net/http"
|
|
|
|
"os"
|
|
|
|
"path"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/disintegration/imaging"
|
|
|
|
"github.com/gin-gonic/gin"
|
2022-09-28 09:01:17 +02:00
|
|
|
|
2020-06-26 14:26:36 +02:00
|
|
|
"github.com/photoprism/photoprism/internal/entity"
|
|
|
|
"github.com/photoprism/photoprism/internal/form"
|
|
|
|
"github.com/photoprism/photoprism/internal/photoprism"
|
2021-09-18 15:32:39 +02:00
|
|
|
"github.com/photoprism/photoprism/internal/search"
|
2020-06-26 14:26:36 +02:00
|
|
|
"github.com/photoprism/photoprism/internal/service"
|
|
|
|
"github.com/photoprism/photoprism/internal/thumb"
|
2022-09-28 09:01:17 +02:00
|
|
|
"github.com/photoprism/photoprism/pkg/clean"
|
2020-06-26 14:26:36 +02:00
|
|
|
"github.com/photoprism/photoprism/pkg/fs"
|
|
|
|
)
|
|
|
|
|
2021-09-05 13:48:53 +02:00
|
|
|
// SharePreview returns a link share preview image.
|
|
|
|
//
|
2020-06-26 14:26:36 +02:00
|
|
|
// GET /s/:token/:uid/preview
|
|
|
|
// TODO: Proof of concept, needs refactoring.
|
|
|
|
func SharePreview(router *gin.RouterGroup) {
|
2022-10-02 11:38:30 +02:00
|
|
|
router.GET("/:token/:shared/preview", func(c *gin.Context) {
|
2020-06-26 14:26:36 +02:00
|
|
|
conf := service.Config()
|
|
|
|
|
2022-04-15 09:42:07 +02:00
|
|
|
token := clean.Token(c.Param("token"))
|
2022-10-02 11:38:30 +02:00
|
|
|
shared := clean.Token(c.Param("shared"))
|
|
|
|
links := entity.FindLinks(token, shared)
|
2020-06-26 14:26:36 +02:00
|
|
|
|
|
|
|
if len(links) != 1 {
|
|
|
|
log.Warn("share: invalid token (preview)")
|
|
|
|
c.Redirect(http.StatusTemporaryRedirect, conf.SitePreview())
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2022-04-18 13:55:17 +02:00
|
|
|
thumbPath := path.Join(conf.ThumbCachePath(), "share")
|
2020-06-26 14:26:36 +02:00
|
|
|
|
|
|
|
if err := os.MkdirAll(thumbPath, os.ModePerm); err != nil {
|
|
|
|
log.Error(err)
|
|
|
|
c.Redirect(http.StatusTemporaryRedirect, conf.SitePreview())
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2022-10-02 11:38:30 +02:00
|
|
|
previewFilename := fmt.Sprintf("%s/%s.jpg", thumbPath, shared)
|
2020-06-26 14:26:36 +02:00
|
|
|
yesterday := time.Now().Add(-24 * time.Hour)
|
|
|
|
|
|
|
|
if info, err := os.Stat(previewFilename); err != nil {
|
2022-10-02 11:38:30 +02:00
|
|
|
log.Debugf("share: creating new preview for %s", clean.Log(shared))
|
2020-06-26 14:26:36 +02:00
|
|
|
} else if info.ModTime().After(yesterday) {
|
2022-10-02 11:38:30 +02:00
|
|
|
log.Debugf("share: using cached preview for %s", clean.Log(shared))
|
2020-06-26 14:26:36 +02:00
|
|
|
c.File(previewFilename)
|
|
|
|
return
|
|
|
|
} else if err := os.Remove(previewFilename); err != nil {
|
2022-10-02 11:38:30 +02:00
|
|
|
log.Errorf("share: could not remove old preview of %s", clean.Log(shared))
|
2020-06-26 14:26:36 +02:00
|
|
|
c.Redirect(http.StatusTemporaryRedirect, conf.SitePreview())
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2021-11-26 13:59:10 +01:00
|
|
|
var f form.SearchPhotos
|
2020-06-26 14:26:36 +02:00
|
|
|
|
2021-10-01 16:44:50 +02:00
|
|
|
// Covers may only contain public content in shared albums.
|
2022-10-02 11:38:30 +02:00
|
|
|
f.Album = shared
|
2020-06-26 14:26:36 +02:00
|
|
|
f.Public = true
|
|
|
|
f.Private = false
|
|
|
|
f.Hidden = false
|
|
|
|
f.Archived = false
|
|
|
|
f.Review = false
|
2020-06-28 15:23:15 +02:00
|
|
|
f.Primary = true
|
2020-06-26 14:26:36 +02:00
|
|
|
|
|
|
|
// Get first 12 album entries.
|
|
|
|
f.Count = 12
|
|
|
|
f.Order = "relevance"
|
|
|
|
|
2022-08-01 15:57:19 +02:00
|
|
|
if err := f.ParseQueryString(); err != nil {
|
|
|
|
log.Errorf("preview: %s", err)
|
|
|
|
c.Redirect(http.StatusTemporaryRedirect, conf.SitePreview())
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2021-09-18 15:32:39 +02:00
|
|
|
p, count, err := search.Photos(f)
|
2020-06-26 14:26:36 +02:00
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
log.Error(err)
|
|
|
|
c.Redirect(http.StatusTemporaryRedirect, conf.SitePreview())
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2020-06-28 15:23:15 +02:00
|
|
|
if count == 0 {
|
|
|
|
c.Redirect(http.StatusTemporaryRedirect, conf.SitePreview())
|
|
|
|
return
|
|
|
|
} else if count < 12 {
|
|
|
|
f := p[0]
|
2021-09-05 13:48:53 +02:00
|
|
|
size, _ := thumb.Sizes[thumb.Fit720]
|
2020-06-28 15:23:15 +02:00
|
|
|
|
|
|
|
fileName := photoprism.FileName(f.FileRoot, f.FileName)
|
|
|
|
|
|
|
|
if !fs.FileExists(fileName) {
|
2022-04-15 09:42:07 +02:00
|
|
|
log.Errorf("share: file %s is missing (preview)", clean.Log(f.FileName))
|
2020-06-28 15:23:15 +02:00
|
|
|
c.Redirect(http.StatusTemporaryRedirect, conf.SitePreview())
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2022-04-18 13:55:17 +02:00
|
|
|
thumbnail, err := thumb.FromFile(fileName, f.FileHash, conf.ThumbCachePath(), size.Width, size.Height, f.FileOrientation, size.Options...)
|
2020-06-28 15:23:15 +02:00
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
log.Error(err)
|
|
|
|
c.Redirect(http.StatusTemporaryRedirect, conf.SitePreview())
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
c.File(thumbnail)
|
|
|
|
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2020-06-26 14:26:36 +02:00
|
|
|
width := 908
|
|
|
|
height := 680
|
|
|
|
x := 0
|
|
|
|
y := 0
|
|
|
|
|
|
|
|
preview := imaging.New(width, height, color.NRGBA{255, 255, 255, 255})
|
2021-09-05 13:48:53 +02:00
|
|
|
size, _ := thumb.Sizes[thumb.Tile224]
|
2020-06-26 14:26:36 +02:00
|
|
|
|
|
|
|
for _, f := range p {
|
|
|
|
fileName := photoprism.FileName(f.FileRoot, f.FileName)
|
|
|
|
|
|
|
|
if !fs.FileExists(fileName) {
|
2022-04-15 09:42:07 +02:00
|
|
|
log.Errorf("share: file %s is missing (preview)", clean.Log(f.FileName))
|
2020-06-26 14:26:36 +02:00
|
|
|
c.Redirect(http.StatusTemporaryRedirect, conf.SitePreview())
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2022-04-18 13:55:17 +02:00
|
|
|
thumbnail, err := thumb.FromFile(fileName, f.FileHash, conf.ThumbCachePath(), size.Width, size.Height, f.FileOrientation, size.Options...)
|
2020-06-26 14:26:36 +02:00
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
log.Error(err)
|
|
|
|
c.Redirect(http.StatusTemporaryRedirect, conf.SitePreview())
|
2020-06-28 15:23:15 +02:00
|
|
|
return
|
2020-06-26 14:26:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
src, err := imaging.Open(thumbnail)
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
log.Error(err)
|
|
|
|
c.Redirect(http.StatusTemporaryRedirect, conf.SitePreview())
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
preview = imaging.Paste(preview, src, image.Pt(x, y))
|
|
|
|
|
|
|
|
x += 228
|
|
|
|
|
|
|
|
if x > width {
|
|
|
|
x = 0
|
|
|
|
y += 228
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Save the resulting image as JPEG.
|
|
|
|
err = imaging.Save(preview, previewFilename)
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
log.Error(err)
|
|
|
|
c.Redirect(http.StatusTemporaryRedirect, conf.SitePreview())
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
c.File(previewFilename)
|
|
|
|
})
|
|
|
|
}
|