mirror of
https://github.com/stashapp/stash.git
synced 2025-12-06 00:13:46 +01:00
159 lines
4 KiB
Go
159 lines
4 KiB
Go
package api
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"net/http"
|
|
"strconv"
|
|
|
|
"github.com/go-chi/chi/v5"
|
|
|
|
"github.com/stashapp/stash/internal/manager/config"
|
|
"github.com/stashapp/stash/internal/static"
|
|
"github.com/stashapp/stash/pkg/image"
|
|
"github.com/stashapp/stash/pkg/logger"
|
|
"github.com/stashapp/stash/pkg/models"
|
|
"github.com/stashapp/stash/pkg/utils"
|
|
)
|
|
|
|
type GalleryFinder interface {
|
|
models.GalleryGetter
|
|
FindByChecksum(ctx context.Context, checksum string) ([]*models.Gallery, error)
|
|
}
|
|
|
|
type GalleryImageFinder interface {
|
|
FindByGalleryIDIndex(ctx context.Context, galleryID int, index uint) (*models.Image, error)
|
|
image.Queryer
|
|
image.CoverQueryer
|
|
}
|
|
|
|
type galleryRoutes struct {
|
|
routes
|
|
imageRoutes imageRoutes
|
|
galleryFinder GalleryFinder
|
|
imageFinder GalleryImageFinder
|
|
fileGetter models.FileGetter
|
|
}
|
|
|
|
func (rs galleryRoutes) Routes() chi.Router {
|
|
r := chi.NewRouter()
|
|
|
|
r.Route("/{galleryId}", func(r chi.Router) {
|
|
r.Use(rs.GalleryCtx)
|
|
|
|
r.Get("/cover", rs.Cover)
|
|
r.Get("/preview/{imageIndex}", rs.Preview)
|
|
})
|
|
|
|
return r
|
|
}
|
|
|
|
func (rs galleryRoutes) Cover(w http.ResponseWriter, r *http.Request) {
|
|
g := r.Context().Value(galleryKey).(*models.Gallery)
|
|
|
|
var i *models.Image
|
|
_ = rs.withReadTxn(r, func(ctx context.Context) error {
|
|
// Find cover image first
|
|
i, _ = image.FindGalleryCover(ctx, rs.imageFinder, g.ID, config.GetInstance().GetGalleryCoverRegex())
|
|
if i == nil {
|
|
return nil
|
|
}
|
|
|
|
// serveThumbnail needs files populated
|
|
if err := i.LoadPrimaryFile(ctx, rs.fileGetter); err != nil {
|
|
if !errors.Is(err, context.Canceled) {
|
|
logger.Errorf("error loading primary file for image %d: %v", i.ID, err)
|
|
}
|
|
// set image to nil so that it doesn't try to use the primary file
|
|
i = nil
|
|
}
|
|
|
|
return nil
|
|
})
|
|
|
|
if i == nil {
|
|
// fallback to default image
|
|
image := static.ReadAll(static.DefaultGalleryImage)
|
|
utils.ServeImage(w, r, image)
|
|
return
|
|
}
|
|
|
|
rs.imageRoutes.serveThumbnail(w, r, i, &g.UpdatedAt)
|
|
}
|
|
|
|
func (rs galleryRoutes) Preview(w http.ResponseWriter, r *http.Request) {
|
|
g := r.Context().Value(galleryKey).(*models.Gallery)
|
|
indexQueryParam := chi.URLParam(r, "imageIndex")
|
|
var i *models.Image
|
|
|
|
index, err := strconv.Atoi(indexQueryParam)
|
|
if err != nil || index < 0 {
|
|
http.Error(w, "bad index", 400)
|
|
return
|
|
}
|
|
|
|
_ = rs.withReadTxn(r, func(ctx context.Context) error {
|
|
qb := rs.imageFinder
|
|
i, _ = qb.FindByGalleryIDIndex(ctx, g.ID, uint(index))
|
|
if i == nil {
|
|
return nil
|
|
}
|
|
// TODO - handle errors?
|
|
|
|
// serveThumbnail needs files populated
|
|
if err := i.LoadPrimaryFile(ctx, rs.fileGetter); err != nil {
|
|
if !errors.Is(err, context.Canceled) {
|
|
logger.Errorf("error loading primary file for image %d: %v", i.ID, err)
|
|
}
|
|
// set image to nil so that it doesn't try to use the primary file
|
|
i = nil
|
|
}
|
|
|
|
return nil
|
|
})
|
|
if i == nil {
|
|
http.Error(w, http.StatusText(404), 404)
|
|
return
|
|
}
|
|
|
|
rs.imageRoutes.serveThumbnail(w, r, i, nil)
|
|
}
|
|
|
|
func (rs galleryRoutes) GalleryCtx(next http.Handler) http.Handler {
|
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
galleryIdentifierQueryParam := chi.URLParam(r, "galleryId")
|
|
galleryID, _ := strconv.Atoi(galleryIdentifierQueryParam)
|
|
|
|
var gallery *models.Gallery
|
|
_ = rs.withReadTxn(r, func(ctx context.Context) error {
|
|
qb := rs.galleryFinder
|
|
if galleryID == 0 {
|
|
galleries, _ := qb.FindByChecksum(ctx, galleryIdentifierQueryParam)
|
|
if len(galleries) > 0 {
|
|
gallery = galleries[0]
|
|
}
|
|
} else {
|
|
gallery, _ = qb.Find(ctx, galleryID)
|
|
}
|
|
|
|
if gallery != nil {
|
|
if err := gallery.LoadPrimaryFile(ctx, rs.fileGetter); err != nil {
|
|
if !errors.Is(err, context.Canceled) {
|
|
logger.Errorf("error loading primary file for gallery %d: %v", galleryID, err)
|
|
}
|
|
// set image to nil so that it doesn't try to use the primary file
|
|
gallery = nil
|
|
}
|
|
}
|
|
|
|
return nil
|
|
})
|
|
if gallery == nil {
|
|
http.Error(w, http.StatusText(404), 404)
|
|
return
|
|
}
|
|
|
|
ctx := context.WithValue(r.Context(), galleryKey, gallery)
|
|
next.ServeHTTP(w, r.WithContext(ctx))
|
|
})
|
|
}
|