Initial qiwei secondary development handoff
This commit is contained in:
236
helper/after_sales_image.go
Normal file
236
helper/after_sales_image.go
Normal file
@@ -0,0 +1,236 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var afterSalesImageKeys = map[string]struct{}{
|
||||
"file_path": {},
|
||||
"filepath": {},
|
||||
"file_name": {},
|
||||
"filename": {},
|
||||
"path": {},
|
||||
"local_path": {},
|
||||
"localpath": {},
|
||||
"image_path": {},
|
||||
"imagepath": {},
|
||||
"thumb_path": {},
|
||||
"thumbnail": {},
|
||||
"url": {},
|
||||
"image_url": {},
|
||||
"file_id": {},
|
||||
"fileid": {},
|
||||
"aes_key": {},
|
||||
"md5": {},
|
||||
"content": {},
|
||||
"message": {},
|
||||
"text": {},
|
||||
}
|
||||
|
||||
func extractAfterSalesImage(raw map[string]interface{}) (string, string) {
|
||||
values := collectImageLikeStrings(raw)
|
||||
for _, value := range values {
|
||||
if isLocalImagePath(value) {
|
||||
return value, ""
|
||||
}
|
||||
}
|
||||
for _, value := range values {
|
||||
if looksLikeImageRef(value) {
|
||||
return "", value
|
||||
}
|
||||
}
|
||||
return "", ""
|
||||
}
|
||||
|
||||
func extractAfterSalesImageFromMessage(msg autoReplyMessage, raw map[string]interface{}) (string, string) {
|
||||
for _, value := range []string{msg.MediaLocalPath, msg.MediaFileName} {
|
||||
if isLocalImagePath(value) {
|
||||
return normalizedLocalImagePath(value), ""
|
||||
}
|
||||
}
|
||||
if path, _ := extractAfterSalesImage(raw); path != "" {
|
||||
return normalizedLocalImagePath(path), ""
|
||||
}
|
||||
if shouldDownloadAfterSalesImage(msg, raw) {
|
||||
if path, err := ensureAutoReplyMediaLocalPath(msg); err == nil && isLocalImagePath(path) {
|
||||
return normalizedLocalImagePath(path), ""
|
||||
}
|
||||
}
|
||||
if _, ref := extractAfterSalesImage(raw); ref != "" {
|
||||
return "", ref
|
||||
}
|
||||
for _, value := range []string{msg.MediaURL, msg.MediaFileID} {
|
||||
if looksLikeImageRef(value) {
|
||||
return "", value
|
||||
}
|
||||
}
|
||||
return "", ""
|
||||
}
|
||||
|
||||
func shouldDownloadAfterSalesImage(msg autoReplyMessage, raw map[string]interface{}) bool {
|
||||
switch strings.TrimSpace(msg.MediaKind) {
|
||||
case "image", "emoji":
|
||||
return true
|
||||
}
|
||||
if msg.RawType == 11042 {
|
||||
return true
|
||||
}
|
||||
if strings.TrimSpace(msg.MediaURL) != "" || strings.TrimSpace(msg.MediaFileID) != "" {
|
||||
return looksLikeImageMessage(raw)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func normalizedLocalImagePath(value string) string {
|
||||
value = strings.Trim(strings.TrimSpace(value), "\"'")
|
||||
if value == "" {
|
||||
return ""
|
||||
}
|
||||
if filepath.IsAbs(value) {
|
||||
return value
|
||||
}
|
||||
candidate := resolveAutoReplyPath(value)
|
||||
if _, err := os.Stat(candidate); err == nil {
|
||||
return candidate
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
func resolveAfterSalesImageRef(value string) string {
|
||||
value = strings.TrimSpace(value)
|
||||
if value == "" {
|
||||
return ""
|
||||
}
|
||||
if isLocalImagePath(value) {
|
||||
return normalizedLocalImagePath(value)
|
||||
}
|
||||
lower := strings.ToLower(value)
|
||||
if !strings.HasPrefix(lower, "http://") && !strings.HasPrefix(lower, "https://") {
|
||||
return ""
|
||||
}
|
||||
parsed, err := url.Parse(value)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
ext := strings.ToLower(filepath.Ext(parsed.Path))
|
||||
switch ext {
|
||||
case ".jpg", ".jpeg", ".png", ".gif", ".bmp", ".webp":
|
||||
default:
|
||||
ext = ".jpg"
|
||||
}
|
||||
base := filepath.Base(parsed.Path)
|
||||
if base == "." || base == string(filepath.Separator) || strings.TrimSpace(base) == "" {
|
||||
base = "after_sales_image"
|
||||
}
|
||||
savePath := generateSavePath("after_sales_images", base, ext)
|
||||
if savePath == "" {
|
||||
return ""
|
||||
}
|
||||
if err := downloadPlainMedia(value, savePath); err != nil {
|
||||
return ""
|
||||
}
|
||||
if isLocalImagePath(savePath) {
|
||||
return savePath
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func looksLikeImageMessage(raw map[string]interface{}) bool {
|
||||
if raw == nil {
|
||||
return false
|
||||
}
|
||||
if typeVal, ok := raw["type"]; ok {
|
||||
switch intFromAny(typeVal) {
|
||||
case 11042, 11044, 11045, 11046:
|
||||
return true
|
||||
}
|
||||
}
|
||||
values := collectImageLikeStrings(raw)
|
||||
for _, value := range values {
|
||||
if isLocalImagePath(value) || looksLikeImageRef(value) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func collectImageLikeStrings(value interface{}) []string {
|
||||
var result []string
|
||||
var walk func(interface{}, string)
|
||||
walk = func(item interface{}, key string) {
|
||||
switch v := item.(type) {
|
||||
case map[string]interface{}:
|
||||
for k, child := range v {
|
||||
walk(child, strings.ToLower(strings.TrimSpace(k)))
|
||||
}
|
||||
case []interface{}:
|
||||
for _, child := range v {
|
||||
walk(child, key)
|
||||
}
|
||||
case string:
|
||||
text := strings.TrimSpace(v)
|
||||
if text == "" {
|
||||
return
|
||||
}
|
||||
if _, ok := afterSalesImageKeys[key]; ok || isLocalImagePath(text) || looksLikeImageRef(text) {
|
||||
result = append(result, text)
|
||||
}
|
||||
case fmt.Stringer:
|
||||
text := strings.TrimSpace(v.String())
|
||||
if text != "" {
|
||||
result = append(result, text)
|
||||
}
|
||||
}
|
||||
}
|
||||
walk(value, "")
|
||||
return uniqueNonEmptyStrings(result)
|
||||
}
|
||||
|
||||
func isLocalImagePath(value string) bool {
|
||||
value = strings.Trim(strings.TrimSpace(value), "\"'")
|
||||
if value == "" {
|
||||
return false
|
||||
}
|
||||
if strings.HasPrefix(strings.ToLower(value), "http://") || strings.HasPrefix(strings.ToLower(value), "https://") {
|
||||
return false
|
||||
}
|
||||
ext := strings.ToLower(filepath.Ext(value))
|
||||
switch ext {
|
||||
case ".jpg", ".jpeg", ".png", ".gif", ".bmp", ".webp":
|
||||
default:
|
||||
return false
|
||||
}
|
||||
if filepath.IsAbs(value) {
|
||||
if _, err := os.Stat(value); err == nil {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
candidate := resolveAutoReplyPath(value)
|
||||
if _, err := os.Stat(candidate); err == nil {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func looksLikeImageRef(value string) bool {
|
||||
value = strings.TrimSpace(value)
|
||||
if value == "" {
|
||||
return false
|
||||
}
|
||||
lower := strings.ToLower(value)
|
||||
if strings.HasPrefix(lower, "http://") || strings.HasPrefix(lower, "https://") {
|
||||
if parsed, err := url.Parse(value); err == nil {
|
||||
ext := strings.ToLower(filepath.Ext(parsed.Path))
|
||||
return ext == ".jpg" || ext == ".jpeg" || ext == ".png" || ext == ".gif" || ext == ".bmp" || ext == ".webp" || strings.Contains(lower, "image")
|
||||
}
|
||||
return strings.Contains(lower, "image")
|
||||
}
|
||||
ext := strings.ToLower(filepath.Ext(value))
|
||||
return ext == ".jpg" || ext == ".jpeg" || ext == ".png" || ext == ".gif" || ext == ".bmp" || ext == ".webp" ||
|
||||
strings.Contains(lower, "image") || strings.Contains(lower, "file_id") || strings.Contains(lower, "fileid")
|
||||
}
|
||||
Reference in New Issue
Block a user