Ver código fonte

fix: avoid blank haibao screenshots

Codex 3 semanas atrás
pai
commit
5fbfe756ce

+ 86 - 13
go/gopath/src/fohow.com/apps/controllers/tool_controller/qrcode_controller.go

@@ -1,14 +1,19 @@
 package tool_controller
 
 import (
+	"bytes"
 	"context"
 	"fmt"
+	"image"
+	_ "image/jpeg"
+	_ "image/png"
 	"strings"
 	"time"
 
 	"github.com/chromedp/chromedp"
 
 	// "os"
+	"net/http"
 	"net/url"
 	// "strings"
 
@@ -77,24 +82,25 @@ func (self *ToolController) GetHaibaoWithGoogle() {
 	defer cancel()
 
 	// 运行任务(导航到网页,并捕获屏幕截图)
-	var buf []byte
 	err = chromedp.Run(ctx,
 		chromedp.EmulateViewport(1400, 800), // 设置视口宽度为 1400,高度为 800
 		chromedp.Navigate(decodedUri),       // 替换为你想截图的网页地址
-		//chromedp.WaitReady("body", chromedp.ByQuery), // 等待页面的 <body> 元素加载完成
-		chromedp.WaitReady("#overload", chromedp.ByID),
-		//chromedp.Sleep(5*time.Second),
-		// chromedp.FullScreenshot(&buf, 90), // 调整质量参数
-		chromedp.FullScreenshot(&buf, 60), // 调整质量参数
+		chromedp.WaitReady("body", chromedp.ByQuery),
 	)
 	if err != nil {
 		beego.BeeLogger.Error("GetHaibaoWithGoogle screenshot failed: err=[%s] url=[%s]", err, maskURLForLog(decodedUri))
 		self.ReturnError(504, apps.NetworkBusy, "", nil)
 		return
 	}
+	buf, err := captureNonBlankScreenshot(ctx, maskURLForLog(decodedUri), 60)
+	if err != nil {
+		beego.BeeLogger.Error("GetHaibaoWithGoogle screenshot failed: err=[%s] url=[%s]", err, maskURLForLog(decodedUri))
+		self.ReturnError(504, apps.NetworkBusy, "", nil)
+		return
+	}
 
 	beego.BeeLogger.Info("GetHaibaoWithGoogle success url=[%s] bytes=[%d]", maskURLForLog(decodedUri), len(buf))
-	self.Ctx.Output.Header("Content-Type", "image/png")
+	self.Ctx.Output.Header("Content-Type", http.DetectContentType(buf))
 	self.Ctx.Output.Body(buf)
 
 	//log.Println("Screenshot saved as screenshot.png")
@@ -122,23 +128,25 @@ func (self *ToolController) GetOtherHaibaoWithGoogle() {
 	defer cancel()
 
 	// 运行任务(导航到网页,并捕获屏幕截图)
-	var buf []byte
 	err = chromedp.Run(ctx,
 		chromedp.EmulateViewport(1400, 800),          // 设置视口宽度为 1400,高度为 800
 		chromedp.Navigate(decodedUri),                // 替换为你想截图的网页地址
 		chromedp.WaitReady("body", chromedp.ByQuery), // 等待页面的 <body> 元素加载完成
-		//chromedp.WaitReady("#overload", chromedp.ByID),
-		chromedp.Sleep(5*time.Second),
-		chromedp.FullScreenshot(&buf, 90), // 调整质量参数
 	)
 	if err != nil {
 		beego.BeeLogger.Error("GetOtherHaibaoWithGoogle screenshot failed: err=[%s] url=[%s]", err, maskURLForLog(decodedUri))
 		self.ReturnError(504, apps.NetworkBusy, "", nil)
 		return
 	}
+	buf, err := captureNonBlankScreenshot(ctx, maskURLForLog(decodedUri), 90)
+	if err != nil {
+		beego.BeeLogger.Error("GetOtherHaibaoWithGoogle screenshot failed: err=[%s] url=[%s]", err, maskURLForLog(decodedUri))
+		self.ReturnError(504, apps.NetworkBusy, "", nil)
+		return
+	}
 
 	beego.BeeLogger.Info("GetOtherHaibaoWithGoogle success url=[%s] bytes=[%d]", maskURLForLog(decodedUri), len(buf))
-	self.Ctx.Output.Header("Content-Type", "image/png")
+	self.Ctx.Output.Header("Content-Type", http.DetectContentType(buf))
 	self.Ctx.Output.Body(buf)
 
 	//log.Println("Screenshot saved as screenshot.png")
@@ -206,8 +214,73 @@ func maskURLForLog(rawURL string) string {
 func chromedpErrorLogf(format string, args ...interface{}) {
 	msg := fmt.Sprintf(format, args...)
 	if strings.Contains(msg, "could not unmarshal event") {
-		beego.BeeLogger.Warning("chromedp ignored protocol event: %s", msg)
 		return
 	}
 	beego.BeeLogger.Error("chromedp error: %s", msg)
 }
+
+func captureNonBlankScreenshot(ctx context.Context, safeURL string, quality int) ([]byte, error) {
+	waitPlan := []time.Duration{
+		3 * time.Second,
+		3 * time.Second,
+		5 * time.Second,
+		8 * time.Second,
+		10 * time.Second,
+	}
+	var last []byte
+	for attempt, wait := range waitPlan {
+		var buf []byte
+		if err := chromedp.Run(ctx,
+			chromedp.Sleep(wait),
+			chromedp.FullScreenshot(&buf, quality),
+		); err != nil {
+			return nil, err
+		}
+		last = buf
+		if !isBlankScreenshot(buf) {
+			if attempt > 0 {
+				beego.BeeLogger.Info("haibao screenshot ready after retry url=[%s] attempt=[%d] bytes=[%d]", safeURL, attempt+1, len(buf))
+			}
+			return buf, nil
+		}
+		beego.BeeLogger.Warning("haibao screenshot blank, retry url=[%s] attempt=[%d] bytes=[%d]", safeURL, attempt+1, len(buf))
+	}
+	return nil, fmt.Errorf("screenshot stayed blank after retries, last_bytes=%d", len(last))
+}
+
+func isBlankScreenshot(data []byte) bool {
+	if len(data) == 0 {
+		return true
+	}
+	img, _, err := image.Decode(bytes.NewReader(data))
+	if err != nil {
+		return false
+	}
+	bounds := img.Bounds()
+	width := bounds.Dx()
+	height := bounds.Dy()
+	if width <= 0 || height <= 0 {
+		return true
+	}
+	stepX := maxInt(width/90, 1)
+	stepY := maxInt(height/90, 1)
+	total := 0
+	nonWhite := 0
+	for y := bounds.Min.Y; y < bounds.Max.Y; y += stepY {
+		for x := bounds.Min.X; x < bounds.Max.X; x += stepX {
+			r, g, b, _ := img.At(x, y).RGBA()
+			total++
+			if uint8(r>>8) < 245 || uint8(g>>8) < 245 || uint8(b>>8) < 245 {
+				nonWhite++
+			}
+		}
+	}
+	return total == 0 || float64(nonWhite)/float64(total) < 0.001
+}
+
+func maxInt(a, b int) int {
+	if a > b {
+		return a
+	}
+	return b
+}