Files

88 lines
2.5 KiB
Go

package scanner_tasks
import (
"fmt"
"image"
_ "image/jpeg"
"os"
"github.com/buckket/go-blurhash"
"github.com/photoview/photoview/api/graphql/models"
"github.com/photoview/photoview/api/log"
"github.com/photoview/photoview/api/scanner/media_encoding"
"github.com/photoview/photoview/api/scanner/scanner_task"
)
type BlurhashTask struct {
scanner_task.ScannerTaskBase
}
func (t BlurhashTask) AfterProcessMedia(ctx scanner_task.TaskContext, mediaData *media_encoding.EncodeMediaData, updatedURLs []*models.MediaURL, mediaIndex int, mediaTotal int) error {
hasThumbnailUpdated := false
for _, url := range updatedURLs {
if url.Purpose == models.PhotoThumbnail || url.Purpose == models.VideoThumbnail {
hasThumbnailUpdated = true
break
}
}
var media *models.Media
if err := ctx.GetDB().Preload("MediaURL").Where("id = ?", mediaData.Media.ID).First(&media).Error; err != nil {
return fmt.Errorf("failed to get media(id:%d): %w", mediaData.Media.ID, err)
}
if media.Blurhash != nil && !hasThumbnailUpdated {
log.Info(ctx, "No thumbnail updated, ignore generating blurhash", "media", media.Path)
return nil
}
thumbnail, err := media.GetThumbnail()
if err != nil {
return fmt.Errorf("failed to get thumbnail of image %q: %w", mediaData.Media.Path, err)
}
hashStr, err := generateBlurhashFromThumbnail(thumbnail)
if err != nil {
return fmt.Errorf("failed to generate blurhash of image %q: %w", mediaData.Media.Path, err)
}
media.Blurhash = &hashStr
if err := ctx.GetDB().Select("blurhash").Save(media).Error; err != nil {
return fmt.Errorf("failed to store blurhash of image %q: %w", mediaData.Media.Path, err)
}
log.Info(ctx, "Generated blurhash of image", "media", mediaData.Media.Path)
return nil
}
// generateBlurhashFromThumbnail generates a blurhash for a single media and stores it in the database
func generateBlurhashFromThumbnail(thumbnail *models.MediaURL) (string, error) {
path, err := thumbnail.CachedPath()
if err != nil {
return "", fmt.Errorf("get path of media(id:%d) error: %w", thumbnail.MediaID, err)
}
f, err := os.Open(path)
if err != nil {
return "", fmt.Errorf("open %q error: %w", path, err)
}
defer f.Close()
imageData, _, err := image.Decode(f)
if err != nil {
return "", fmt.Errorf("decode %q error: %w", path, err)
}
const (
componentX = 4
componentY = 3
)
hashStr, err := blurhash.Encode(componentX, componentY, imageData)
if err != nil {
return "", fmt.Errorf("encode blurhash of %q error: %w", path, err)
}
return hashStr, nil
}