237 lines
5.7 KiB
Go
237 lines
5.7 KiB
Go
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")
|
|
}
|