package scanner import ( "fmt" "image" "log" "os" "github.com/buckket/go-blurhash" "github.com/photoview/photoview/api/graphql/models" "gorm.io/gorm" ) // GenerateBlurhashes queries the database for media that are missing a blurhash and computes one for them. // This function blocks until all hashes have been computed func GenerateBlurhashes(db *gorm.DB) error { var results []*models.Media processErrors := make([]error, 0) query := db.Model(&models.Media{}). Preload("MediaURL"). Joins("INNER JOIN media_urls ON media.id = media_urls.media_id"). Where("blurhash IS NULL"). Where("media_urls.purpose = 'thumbnail' OR media_urls.purpose = 'video-thumbnail'") err := query.FindInBatches(&results, 50, func(tx *gorm.DB, batch int) error { log.Printf("generating %d blurhashes", len(results)) hashes := make([]*string, len(results)) for i, row := range results { thumbnail, err := row.GetThumbnail() if err != nil { log.Printf("failed to get thumbnail for media to generate blurhash (%d): %v", row.ID, err) processErrors = append(processErrors, err) continue } hashStr, err := GenerateBlurhashFromThumbnail(thumbnail) if err != nil { log.Printf("failed to generate blurhash for media (%d): %v", row.ID, err) processErrors = append(processErrors, err) continue } hashes[i] = &hashStr results[i].Blurhash = &hashStr } tx.Save(results) // if err := db.Update("blurhash", hashes).Error; err != nil { // return err // } return nil }).Error if err != nil { return err } if len(processErrors) == 0 { return nil } else { return fmt.Errorf("failed to generate %d blurhashes", len(processErrors)) } } // GenerateBlurhashFromThumbnail generates a blurhash for a single media and stores it in the database func GenerateBlurhashFromThumbnail(thumbnail *models.MediaURL) (string, error) { thumbnail_path, err := thumbnail.CachedPath() if err != nil { return "", err } imageFile, err := os.Open(thumbnail_path) if err != nil { return "", err } imageData, _, err := image.Decode(imageFile) if err != nil { return "", err } hashStr, err := blurhash.Encode(4, 3, imageData) if err != nil { return "", err } // if err := db.Model(&models.Media{}).Where("id = ?", thumbnail.MediaID).Update("blurhash", hashStr).Error; err != nil { // return "", err // } return hashStr, nil }