diff --git a/config/config.go b/config/config.go index 887598e8..d6739645 100644 --- a/config/config.go +++ b/config/config.go @@ -2340,3 +2340,15 @@ func GetLinkNum() int { return instance.Settings.LinkNum } + +// 获取GetDoNotReplaceAppid的值 +func GetDoNotReplaceAppid() bool { + mu.Lock() + defer mu.Unlock() + + if instance == nil { + mylog.Println("Warning: instance is nil when trying to DoNotReplaceAppid value.") + return false + } + return instance.Settings.DoNotReplaceAppid +} diff --git a/handlers/avatar.go b/handlers/avatar.go new file mode 100644 index 00000000..508a402d --- /dev/null +++ b/handlers/avatar.go @@ -0,0 +1,79 @@ +package handlers + +import ( + "fmt" + "regexp" + + "github.com/hoshinonyaruko/gensokyo/config" + "github.com/hoshinonyaruko/gensokyo/idmap" + "github.com/hoshinonyaruko/gensokyo/mylog" +) + +func ProcessCQAvatar(groupID string, text string) string { + // 断言并获取 groupID 和 qq 号 + qqRegex := regexp.MustCompile(`\[CQ:avatar,qq=(\d+)\]`) + qqMatches := qqRegex.FindAllStringSubmatch(text, -1) + + for _, match := range qqMatches { + qqStr := match[1] // 提取 qq 号 + + var originalUserID string + var err error + if config.GetIdmapPro() { + // 如果UserID不是nil且配置为使用Pro版本,则调用RetrieveRowByIDv2Pro + _, originalUserID, err = idmap.RetrieveRowByIDv2Pro(groupID, qqStr) + if err != nil { + mylog.Printf("Error1 retrieving original GroupID: %v", err) + _, originalUserID, err = idmap.RetrieveRowByIDv2Pro("690426430", qqStr) + if err != nil { + mylog.Printf("Error reading private originalUserID: %v", err) + } + } + } else { + originalUserID, err = idmap.RetrieveRowByIDv2(qqStr) + if err != nil { + mylog.Printf("Error retrieving original UserID: %v", err) + } + } + + // 生成头像URL + avatarURL, _ := GenerateAvatarURLV2(originalUserID) + + // 替换文本中的 [CQ:avatar,qq=12345678] 为 [CQ:image,file=avatarurl] + replacement := fmt.Sprintf("[CQ:image,file=%s]", avatarURL) + text = qqRegex.ReplaceAllString(text, replacement) + } + + return text +} + +func GetAvatarCQCode(groupID, qqNumber string) (string, error) { + var originalUserID string + var err error + + if config.GetIdmapPro() { + // 如果配置为使用Pro版本,则调用RetrieveRowByIDv2Pro + _, originalUserID, err = idmap.RetrieveRowByIDv2Pro(groupID, qqNumber) + if err != nil { + mylog.Printf("Error retrieving original GroupID: %v", err) + return "", err + } + } else { + // 否则调用RetrieveRowByIDv2 + originalUserID, err = idmap.RetrieveRowByIDv2(qqNumber) + if err != nil { + mylog.Printf("Error retrieving original UserID: %v", err) + return "", err + } + } + + // 生成头像URL + avatarURL, err := GenerateAvatarURLV2(originalUserID) + if err != nil { + mylog.Printf("Error generating avatar URL: %v", err) + return "", err + } + + // 返回格式化后的字符串 + return fmt.Sprintf("[CQ:image,file=%s]", avatarURL), nil +} diff --git a/handlers/get_avatar.go b/handlers/get_avatar.go index edfabfaf..95360515 100644 --- a/handlers/get_avatar.go +++ b/handlers/get_avatar.go @@ -3,6 +3,7 @@ package handlers import ( "encoding/json" "fmt" + "strconv" "github.com/hoshinonyaruko/gensokyo/callapi" "github.com/hoshinonyaruko/gensokyo/config" @@ -15,6 +16,7 @@ type GetAvatarResponse struct { Message string `json:"message"` RetCode int `json:"retcode"` Echo interface{} `json:"echo"` + UserID int64 `json:"user_id"` } func init() { @@ -46,9 +48,12 @@ func GetAvatar(client callapi.Client, api openapi.OpenAPI, apiv2 openapi.OpenAPI avatarurl, _ := GenerateAvatarURLV2(originalUserID) + useridstr := message.Params.UserID.(string) + response.Message = avatarurl response.RetCode = 0 response.Echo = message.Echo + response.UserID, _ = strconv.ParseInt(useridstr, 10, 64) outputMap := structToMap(response) diff --git a/handlers/message_parser.go b/handlers/message_parser.go index 9948a873..3c621dc2 100644 --- a/handlers/message_parser.go +++ b/handlers/message_parser.go @@ -416,6 +416,8 @@ func parseMessageContent(paramsMessage callapi.ParamsContent, message callapi.Ac if config.GetEnableChangeWord() { messageText = acnode.CheckWordOUT(messageText) } + // 解析[CQ:avatar,qq=123456] + messageText = ProcessCQAvatar(paramsMessage.GroupID.(string), messageText) case []interface{}: //多个映射组成的切片 mylog.Printf("params.message is a slice (segment_type_koishi)\n") @@ -450,6 +452,9 @@ func parseMessageContent(paramsMessage callapi.ParamsContent, message callapi.Ac case "at": qqNumber, _ := segmentMap["data"].(map[string]interface{})["qq"].(string) segmentContent = "[CQ:at,qq=" + qqNumber + "]" + case "avatar": + qqNumber, _ := segmentMap["data"].(map[string]interface{})["qq"].(string) + segmentContent, _ = GetAvatarCQCode(paramsMessage.GroupID.(string), qqNumber) case "markdown": mdContent, ok := segmentMap["data"].(map[string]interface{})["data"] if ok { @@ -518,6 +523,9 @@ func parseMessageContent(paramsMessage callapi.ParamsContent, message callapi.Ac case "at": qqNumber, _ := message["data"].(map[string]interface{})["qq"].(string) messageText = "[CQ:at,qq=" + qqNumber + "]" + case "avatar": + qqNumber, _ := message["data"].(map[string]interface{})["qq"].(string) + messageText, _ = GetAvatarCQCode(paramsMessage.GroupID.(string), qqNumber) case "markdown": mdContent, ok := message["data"].(map[string]interface{})["data"] if ok { @@ -563,8 +571,9 @@ func parseMessageContent(paramsMessage callapi.ParamsContent, message callapi.Ac default: mylog.Println("Unsupported message format: params.message field is not a string, map or slice") } + //处理at - messageText = transformMessageTextAt(messageText) + messageText = transformMessageTextAt(messageText, paramsMessage.GroupID.(string)) //mylog.Printf(messageText) @@ -635,9 +644,12 @@ func isIPAddress(address string) bool { } // at处理 -func transformMessageTextAt(messageText string) string { - // 首先,将AppID替换为BotID - messageText = strings.ReplaceAll(messageText, AppID, BotID) +func transformMessageTextAt(messageText string, groupid string) string { + // DoNotReplaceAppid=false(默认频道bot,需要自己at自己时,否则改成true) + if !config.GetDoNotReplaceAppid() { + // 首先,将AppID替换为BotID + messageText = strings.ReplaceAll(messageText, AppID, BotID) + } // 去除所有[CQ:reply,id=数字] todo 更好的处理办法 replyRE := regexp.MustCompile(`\[CQ:reply,id=\d+\]`) @@ -648,7 +660,13 @@ func transformMessageTextAt(messageText string) string { messageText = re.ReplaceAllStringFunc(messageText, func(m string) string { submatches := re.FindStringSubmatch(m) if len(submatches) > 1 { - realUserID, err := idmap.RetrieveRowByIDv2(submatches[1]) + var realUserID string + var err error + if config.GetIdmapPro() { + _, realUserID, err = idmap.RetrieveRowByIDv2Pro(groupid, submatches[1]) + } else { + realUserID, err = idmap.RetrieveRowByIDv2(submatches[1]) + } if err != nil { // 如果出错,也替换成相应的格式,但使用原始QQ号 mylog.Printf("Error retrieving user ID: %v", err) @@ -758,7 +776,7 @@ func RevertTransformedText(data interface{}, msgtype string, api openapi.OpenAPI //处理前 先去前后空 messageText = strings.TrimSpace(msg.Content) } - var originmessageText = messageText + //mylog.Printf("1[%v]", messageText) // 将messageText里的BotID替换成AppID @@ -802,6 +820,8 @@ func RevertTransformedText(data interface{}, msgtype string, api openapi.OpenAPI messageText = strings.TrimSpace(messageText) } } + + var originmessageText = messageText //mylog.Printf("2[%v]", messageText) // 检查是否需要移除前缀 diff --git a/idmap/service.go b/idmap/service.go index 090b9382..31c1fb48 100644 --- a/idmap/service.go +++ b/idmap/service.go @@ -113,15 +113,15 @@ func CleanBucket(bucketName string) { return fmt.Errorf("bucket %s not found", bucketName) } - // 使用游标遍历bucket + // 使用游标遍历bucket 正向键 k:v 32位openid:大宽int64 64位msgid:大宽int6 c := b.Cursor() for k, v := c.First(); k != nil; k, v = c.Next() { // 检查键或值是否包含冒号 - if bytes.Contains(k, []byte(":")) || bytes.Contains(v, []byte(":")) { + if bytes.Contains(k, []byte(":")) || bytes.Contains(v, []byte(":")) || bytes.Contains(k, []byte("row-")) { continue // 忽略包含冒号的键值对 } - // 检查值id的长度 + // 检查值id的长度 这里是正向键 id := string(k) if len(id) != 32 { if err := c.Delete(); err != nil { @@ -131,14 +131,14 @@ func CleanBucket(bucketName string) { } } - // 再次遍历处理reverseKey的情况 + // 再次遍历处理reverseKey的情况 反向键 row-整数:string 32位openid/64位msgid for k, v := c.First(); k != nil; k, v = c.Next() { if strings.HasPrefix(string(k), "row-") { if bytes.Contains(k, []byte(":")) || bytes.Contains(v, []byte(":")) { continue // 忽略包含冒号的键值对 } - - id := string(b.Get(k)) + // 这里检查反向键是否是32位 + id := string(v) if len(id) != 32 { if err := b.Delete(k); err != nil { return err diff --git a/structs/structs.go b/structs/structs.go index c524b209..624961c5 100644 --- a/structs/structs.go +++ b/structs/structs.go @@ -141,8 +141,9 @@ type Settings struct { EnableChangeWord bool `yaml:"enableChangeWord"` DefaultChangeWord string `yaml:"defaultChangeWord"` //错误临时修复类 - Fix11300 bool `yaml:"fix_11300"` - HttpOnlyBot bool `yaml:"http_only_bot"` + Fix11300 bool `yaml:"fix_11300"` + HttpOnlyBot bool `yaml:"http_only_bot"` + DoNotReplaceAppid bool `yaml:"do_not_replace_appid"` //内置指令 BindPrefix string `yaml:"bind_prefix"` MePrefix string `yaml:"me_prefix"` diff --git a/template/config_template.go b/template/config_template.go index a377af81..e1fdd9d0 100644 --- a/template/config_template.go +++ b/template/config_template.go @@ -184,6 +184,7 @@ settings: #错误临时修复类 fix_11300: false #修复11300报错,需要在develop_bot_id填入自己机器人的appid. 11300原因暂时未知,临时修复方案. http_only_bot : false #这个配置项会自动配置,请不要修改,保持false. + do_not_replace_appid : false #在频道内机器人尝试at自己回at不到,保持false.群内机器人有发送用户头像url的需求时,true(因为用户头像url包含了appid,如果false就会出错.) #内置指令类 bind_prefix : "/bind" #需设置 #增强配置项 master_id 可触发