MetaTube / route /image.go
henry99a's picture
Clean commit for Hugging Face Spaces without binary files
ca7217f
package route
import (
"bytes"
"image"
"net/http"
"strconv"
"github.com/gin-gonic/gin"
"github.com/gin-gonic/gin/render"
R "github.com/metatube-community/metatube-sdk-go/constant"
"github.com/metatube-community/metatube-sdk-go/engine"
"github.com/metatube-community/metatube-sdk-go/imageutil"
"github.com/metatube-community/metatube-sdk-go/imageutil/badge"
mt "github.com/metatube-community/metatube-sdk-go/provider"
)
type imageType uint8
const (
primaryImageType imageType = iota
thumbImageType
backdropImageType
)
type imageUri struct {
infoUri // same as info uri
}
type imageQuery struct {
URL string `form:"url"`
Ratio float64 `form:"ratio"`
Position float64 `form:"pos"`
Auto bool `form:"auto"`
Badge string `form:"badge"`
Quality int `form:"quality"`
}
func getImage(app *engine.Engine, typ imageType) gin.HandlerFunc {
var ratio float64
switch typ {
case primaryImageType:
ratio = R.PrimaryImageRatio
case thumbImageType:
ratio = R.ThumbImageRatio
case backdropImageType:
ratio = R.BackdropImageRatio
default:
panic("invalid image type")
}
return func(c *gin.Context) {
uri := &imageUri{}
if err := c.ShouldBindUri(uri); err != nil {
abortWithStatusMessage(c, http.StatusBadRequest, err)
return
}
query := &imageQuery{
Ratio: -1,
Position: -1,
Quality: 90,
}
if err := c.ShouldBindQuery(query); err != nil {
abortWithStatusMessage(c, http.StatusBadRequest, err)
return
}
// TODO: how to handle providers that implement
// both actor and movie provider interfaces?
var isActorProvider bool
switch {
case app.IsActorProvider(uri.Provider):
isActorProvider = true
case app.IsMovieProvider(uri.Provider):
isActorProvider = false
default:
abortWithError(c, mt.ErrProviderNotFound)
return
}
var (
img image.Image
err error
)
if query.URL != "" /* specified URL */ {
var provider mt.Provider
if isActorProvider {
provider = app.MustGetActorProviderByName(uri.Provider)
} else {
provider = app.MustGetMovieProviderByName(uri.Provider)
}
// query.Ratio should apply only to the primary images.
if typ != primaryImageType || query.Ratio < 0 {
query.Ratio = ratio
}
img, err = app.GetImageByURL(provider, query.URL, query.Ratio, query.Position, query.Auto)
} else if isActorProvider /* actor */ {
switch typ {
case primaryImageType:
img, err = app.GetActorPrimaryImage(uri.AsProviderID())
case thumbImageType, backdropImageType:
abortWithStatusMessage(c, http.StatusBadRequest, "unsupported image type")
return
}
} else /* movie */ {
switch typ {
case primaryImageType:
img, err = app.GetMoviePrimaryImage(uri.AsProviderID(), query.Ratio, query.Position)
case thumbImageType:
img, err = app.GetMovieThumbImage(uri.AsProviderID())
case backdropImageType:
img, err = app.GetMovieBackdropImage(uri.AsProviderID())
}
}
if err != nil {
abortWithError(c, err)
return
}
if query.Badge != "" {
if img, err = badge.Badge(img, query.Badge); err != nil {
abortWithError(c, err)
return
}
}
c.Header("X-MetaTube-Image-Width", strconv.Itoa(img.Bounds().Dx()))
c.Header("X-MetaTube-Image-Height", strconv.Itoa(img.Bounds().Dy()))
buf := &bytes.Buffer{}
if err = imageutil.EncodeToJPEG(buf, img, query.Quality); err != nil {
panic(err)
}
c.Render(http.StatusOK, render.Reader{
ContentType: jpegImageMIMEType,
ContentLength: int64(buf.Len()),
Reader: buf,
})
}
}
const jpegImageMIMEType = "image/jpeg"