Browse Source

feat: Improve image metadata extraction and thumbnail handling

- Enhance image dimension detection by decoding actual image data
- Add support for detecting image dimensions from downloaded images
- Implement fallback to Open Graph tags if image decoding fails
- Handle square images by setting width and height to nil
- Improve thumbnail upload process for WhatsApp messages
- Add logging for image dimensions and thumbnail upload status
pull/271/head
Aldino Kemal 1 year ago
parent
commit
d79bb43782
  1. 69
      src/pkg/utils/general.go
  2. 36
      src/services/send.go

69
src/pkg/utils/general.go

@ -1,7 +1,12 @@
package utils package utils
import ( import (
"bytes"
"fmt" "fmt"
"image"
_ "image/gif" // Register GIF format
_ "image/jpeg" // Register JPEG format
_ "image/png" // Register PNG format
"io" "io"
"log" "log"
"net/http" "net/http"
@ -100,22 +105,6 @@ func GetMetaDataFromURL(url string) (meta Metadata, err error) {
meta.Image, _ = element.Attr("content") meta.Image, _ = element.Attr("content")
}) })
document.Find("meta[property='og:image:width']").Each(func(index int, element *goquery.Selection) {
if content, exists := element.Attr("content"); exists {
width, _ := strconv.Atoi(content)
widthUint32 := uint32(width)
meta.Width = &widthUint32
}
})
document.Find("meta[property='og:image:height']").Each(func(index int, element *goquery.Selection) {
if content, exists := element.Attr("content"); exists {
height, _ := strconv.Atoi(content)
heightUint32 := uint32(height)
meta.Height = &heightUint32
}
})
// If an og:image is found, download it and store its content in ImageThumb // If an og:image is found, download it and store its content in ImageThumb
if meta.Image != "" { if meta.Image != "" {
imageResponse, err := http.Get(meta.Image) imageResponse, err := http.Get(meta.Image)
@ -123,11 +112,59 @@ func GetMetaDataFromURL(url string) (meta Metadata, err error) {
log.Printf("Failed to download image: %v", err) log.Printf("Failed to download image: %v", err)
} else { } else {
defer imageResponse.Body.Close() defer imageResponse.Body.Close()
// Read image data
imageData, err := io.ReadAll(imageResponse.Body) imageData, err := io.ReadAll(imageResponse.Body)
if err != nil { if err != nil {
log.Printf("Failed to read image data: %v", err) log.Printf("Failed to read image data: %v", err)
} else { } else {
meta.ImageThumb = imageData meta.ImageThumb = imageData
// Get image dimensions from the actual image rather than OG tags
imageReader := bytes.NewReader(imageData)
img, _, err := image.Decode(imageReader)
if err == nil {
bounds := img.Bounds()
width := uint32(bounds.Max.X - bounds.Min.X)
height := uint32(bounds.Max.Y - bounds.Min.Y)
// Check if image is square (1:1 ratio)
if width == height {
// For 1:1 ratio, leave width and height as nil
meta.Width = nil
meta.Height = nil
} else {
meta.Width = &width
meta.Height = &height
}
log.Printf("Image dimensions: %dx%d", width, height)
} else {
log.Printf("Failed to decode image to get dimensions: %v", err)
// Fallback to OG tags if image decoding fails
document.Find("meta[property='og:image:width']").Each(func(index int, element *goquery.Selection) {
if content, exists := element.Attr("content"); exists {
width, _ := strconv.Atoi(content)
widthUint32 := uint32(width)
meta.Width = &widthUint32
}
})
document.Find("meta[property='og:image:height']").Each(func(index int, element *goquery.Selection) {
if content, exists := element.Attr("content"); exists {
height, _ := strconv.Atoi(content)
heightUint32 := uint32(height)
meta.Height = &heightUint32
}
})
// Check if the OG tags indicate a 1:1 ratio
if meta.Width != nil && meta.Height != nil && *meta.Width == *meta.Height {
meta.Width = nil
meta.Height = nil
}
}
} }
} }
} }

36
src/services/send.go

@ -435,16 +435,38 @@ func (service serviceSend) SendLink(ctx context.Context, request domainSend.Link
return response, err return response, err
} }
// Log image dimensions if available, otherwise note it's a square image or dimensions not available
if getMetaDataFromURL.Width != nil && getMetaDataFromURL.Height != nil {
fmt.Printf("Image dimensions: %dx%d\n", *getMetaDataFromURL.Width, *getMetaDataFromURL.Height)
} else {
fmt.Println("Image dimensions: Square image or dimensions not available")
}
// Create the message
msg := &waE2E.Message{ExtendedTextMessage: &waE2E.ExtendedTextMessage{ msg := &waE2E.Message{ExtendedTextMessage: &waE2E.ExtendedTextMessage{
Text: proto.String(fmt.Sprintf("%s\n%s", request.Caption, request.Link)),
Title: proto.String(getMetaDataFromURL.Title),
MatchedText: proto.String(request.Link),
Description: proto.String(getMetaDataFromURL.Description),
JPEGThumbnail: getMetaDataFromURL.ImageThumb,
ThumbnailHeight: getMetaDataFromURL.Height,
ThumbnailWidth: getMetaDataFromURL.Width,
Text: proto.String(fmt.Sprintf("%s\n%s", request.Caption, request.Link)),
Title: proto.String(getMetaDataFromURL.Title),
MatchedText: proto.String(request.Link),
Description: proto.String(getMetaDataFromURL.Description),
JPEGThumbnail: getMetaDataFromURL.ImageThumb,
}} }}
// If we have a thumbnail image, upload it to WhatsApp's servers
if len(getMetaDataFromURL.ImageThumb) > 0 && getMetaDataFromURL.Height != nil && getMetaDataFromURL.Width != nil {
uploadedThumb, err := service.uploadMedia(ctx, whatsmeow.MediaImage, getMetaDataFromURL.ImageThumb, dataWaRecipient)
if err == nil {
// Update the message with the uploaded thumbnail information
msg.ExtendedTextMessage.ThumbnailDirectPath = proto.String(uploadedThumb.DirectPath)
msg.ExtendedTextMessage.ThumbnailSHA256 = uploadedThumb.FileSHA256
msg.ExtendedTextMessage.ThumbnailEncSHA256 = uploadedThumb.FileEncSHA256
msg.ExtendedTextMessage.MediaKey = uploadedThumb.MediaKey
msg.ExtendedTextMessage.ThumbnailHeight = getMetaDataFromURL.Height
msg.ExtendedTextMessage.ThumbnailWidth = getMetaDataFromURL.Width
} else {
logrus.Warnf("Failed to upload thumbnail: %v, continue without uploaded thumbnail", err)
}
}
content := "🔗 " + request.Link content := "🔗 " + request.Link
if request.Caption != "" { if request.Caption != "" {
content = "🔗 " + request.Caption content = "🔗 " + request.Caption

Loading…
Cancel
Save