package message import ( "encoding/json" "fmt" "net/url" "regexp" "strconv" "strings" ) type ImageMessage struct { Type string `json:"type"` Data ImageMessageData `json:"data"` } type ImageMessageData struct { File string `json:"file"` SubType string `json:"sub_type"` FileID string `json:"file_id"` URL string `json:"url"` FileSize int `json:"file_size"` FileUnique string `json:"file_unique"` } func init() { RegisterMessageType(TypeImage, func() CQMessage { return &ImageMessage{Type: TypeImage} }) } func (msg *ImageMessage) SetData(data json.RawMessage) error { return json.Unmarshal(data, &msg.Data) } func (msg *ImageMessage) ToCQString() string { if msg.Data.URL == "" && msg.Data.File == "" { return "" } // URL 转义 escapedURL := url.QueryEscape(msg.Data.URL) // 构造 CQ:image 字符串 cqString := fmt.Sprintf("[CQ:image,file=%s,sub_type=%s,file_id=%s,url=%s,file_size=%d,file_unique=%s]", msg.Data.File, msg.Data.SubType, msg.Data.FileID, escapedURL, msg.Data.FileSize, msg.Data.FileUnique) return cqString } func (msg *ImageMessage) ParseMessage(data string) error { // 使用正则表达式提取各个字段 re := regexp.MustCompile(`\[CQ:image,file=(.*?),sub_type=(.*?),file_id=(.*?),url=(.*?),file_size=(\d+),file_unique=(.*?)\]`) matches := re.FindStringSubmatch(data) if len(matches) < 7 { return fmt.Errorf("数据格式不正确") } // 转换file_size为整数 fileSize, err := strconv.Atoi(matches[5]) if err != nil { return fmt.Errorf("解析 file_size 出错: %v", err) } // 处理URL转义 decodedURL, err := url.QueryUnescape(matches[4]) decodedURL = strings.ReplaceAll(decodedURL, ",", ",") decodedURL = strings.ReplaceAll(decodedURL, "[", "[") decodedURL = strings.ReplaceAll(decodedURL, "]", "]") decodedURL = strings.ReplaceAll(decodedURL, "&", "&") if err != nil { return fmt.Errorf("URL 转义失败: %v", err) } msg.Data = ImageMessageData{ File: matches[1], SubType: matches[2], FileID: matches[3], URL: decodedURL, FileSize: fileSize, FileUnique: matches[6], } return nil }