Skip to content
Snippets Groups Projects
info_controller.go 2.17 KiB
Newer Older
package info_controller

import (
	"bytes"
	"image/png"

	"github.com/buckket/go-blurhash"
	"github.com/disintegration/imaging"
	"github.com/turt2live/matrix-media-repo/common/rcontext"
	"github.com/turt2live/matrix-media-repo/controllers/download_controller"
	"github.com/turt2live/matrix-media-repo/storage"
	"github.com/turt2live/matrix-media-repo/types"
	"github.com/turt2live/matrix-media-repo/util/stream_util"
)

func GetOrCalculateBlurhash(media *types.Media, rctx rcontext.RequestContext) (string, error) {
	rctx.Log.Info("Attempting fetch of blurhash for sha256 of " + media.Sha256Hash)
	db := storage.GetDatabase().GetMetadataStore(rctx)
	cached, err := db.GetBlurhash(media.Sha256Hash)
	if err != nil {
		return "", err
	}

	if cached != "" {
		rctx.Log.Info("Returning cached blurhash: " + cached)
		return cached, nil
	}

	rctx.Log.Info("Getting minimal media record to calculate blurhash")
	minMedia, err := download_controller.FindMinimalMediaRecord(media.Origin, media.MediaId, true, rctx)
	if err != nil {
		return "", err
	}
	defer stream_util.DumpAndCloseStream(minMedia.Stream)

	// No cached blurhash: calculate one
	rctx.Log.Info("Decoding image for blurhash calculation")
	imgSrc, err := imaging.Decode(minMedia.Stream)
	if err != nil {
		return "", err
	}

	// Resize the image to make the blurhash a bit more reasonable to calculate
	rctx.Log.Info("Resizing image for blurhash (faster calculation)")
	smallImg := imaging.Fill(imgSrc, rctx.Config.Features.MSC2448Blurhash.GenerateWidth, rctx.Config.Features.MSC2448Blurhash.GenerateHeight, imaging.Center, imaging.Lanczos)
	imgBuf := &bytes.Buffer{}
	err = imaging.Encode(imgBuf, smallImg, imaging.PNG)
	if err != nil {
		return "", err
	}
	decoded, err := png.Decode(imgBuf)
	if err != nil {
		return "", err
	}

	rctx.Log.Info("Calculating blurhash")
	encoded, err := blurhash.Encode(rctx.Config.Features.MSC2448Blurhash.XComponents, rctx.Config.Features.MSC2448Blurhash.YComponents, decoded)
	if err != nil {
		return "", err
	}

	// Save the blurhash for next time
	rctx.Log.Infof("Saving blurhash %s and returning", encoded)
	err = db.InsertBlurhash(media.Sha256Hash, encoded)
	if err != nil {
		return "", err
	}

	return encoded, nil
}