mirror of
https://github.com/Mrs4s/go-cqhttp.git
synced 2025-05-04 19:17:37 +08:00
feat: support parse multi-source message & support parse and forward guild image message
This commit is contained in:
parent
4d328358e3
commit
52e7ea5bbe
25
coolq/api.go
25
coolq/api.go
@ -540,7 +540,7 @@ func (bot *CQBot) CQSendGroupMessage(groupID int64, m gjson.Result, autoEscape b
|
||||
|
||||
var elem []message.IMessageElement
|
||||
if m.Type == gjson.JSON {
|
||||
elem = bot.ConvertObjectMessage(m, true)
|
||||
elem = bot.ConvertObjectMessage(m, MessageSourceGroup)
|
||||
} else {
|
||||
str := m.String()
|
||||
if str == "" {
|
||||
@ -550,7 +550,7 @@ func (bot *CQBot) CQSendGroupMessage(groupID int64, m gjson.Result, autoEscape b
|
||||
if autoEscape {
|
||||
elem = []message.IMessageElement{message.NewText(str)}
|
||||
} else {
|
||||
elem = bot.ConvertStringMessage(str, true)
|
||||
elem = bot.ConvertStringMessage(str, MessageSourceGroup)
|
||||
}
|
||||
}
|
||||
fixAt(elem)
|
||||
@ -580,9 +580,8 @@ func (bot *CQBot) CQSendGuildChannelMessage(guildID, channelID uint64, m gjson.R
|
||||
return Failed(100, "CHANNEL_NOT_SUPPORTED_TEXT_MSG", "子频道类型错误, 无法发送文本信息")
|
||||
}
|
||||
var elem []message.IMessageElement
|
||||
// todo: 将 converter 适配频道或者为频道单独写一个
|
||||
if m.Type == gjson.JSON {
|
||||
elem = bot.ConvertObjectMessage(m, true)
|
||||
elem = bot.ConvertObjectMessage(m, MessageSourceGuildChannel)
|
||||
} else {
|
||||
str := m.String()
|
||||
if str == "" {
|
||||
@ -592,7 +591,7 @@ func (bot *CQBot) CQSendGuildChannelMessage(guildID, channelID uint64, m gjson.R
|
||||
if autoEscape {
|
||||
elem = []message.IMessageElement{message.NewText(str)}
|
||||
} else {
|
||||
elem = bot.ConvertStringMessage(str, true)
|
||||
elem = bot.ConvertStringMessage(str, MessageSourceGuildChannel)
|
||||
}
|
||||
}
|
||||
mid := bot.SendGuildChannelMessage(guildID, channelID, &message.SendingMessage{Elements: elem})
|
||||
@ -658,7 +657,7 @@ func (bot *CQBot) CQSendGroupForwardMessage(groupID int64, m gjson.Result) globa
|
||||
}
|
||||
return int32(msgTime)
|
||||
}(),
|
||||
Message: resolveElement(bot.ConvertContentMessage(m.Content, true)),
|
||||
Message: resolveElement(bot.ConvertContentMessage(m.Content, MessageSourceGroup)),
|
||||
}
|
||||
}
|
||||
log.Warnf("警告: 引用消息 %v 错误或数据库未开启.", e.Get("data.id").Str)
|
||||
@ -697,7 +696,7 @@ func (bot *CQBot) CQSendGroupForwardMessage(groupID int64, m gjson.Result) globa
|
||||
}
|
||||
}
|
||||
}
|
||||
content := bot.ConvertObjectMessage(e.Get("data.content"), true)
|
||||
content := bot.ConvertObjectMessage(e.Get("data.content"), MessageSourceGroup)
|
||||
if uin != 0 && name != "" && len(content) > 0 {
|
||||
return &message.ForwardNode{
|
||||
SenderId: uin,
|
||||
@ -744,7 +743,7 @@ func (bot *CQBot) CQSendGroupForwardMessage(groupID int64, m gjson.Result) globa
|
||||
func (bot *CQBot) CQSendPrivateMessage(userID int64, groupID int64, m gjson.Result, autoEscape bool) global.MSG {
|
||||
var elem []message.IMessageElement
|
||||
if m.Type == gjson.JSON {
|
||||
elem = bot.ConvertObjectMessage(m, false)
|
||||
elem = bot.ConvertObjectMessage(m, MessageSourcePrivate)
|
||||
} else {
|
||||
str := m.String()
|
||||
if str == "" {
|
||||
@ -753,7 +752,7 @@ func (bot *CQBot) CQSendPrivateMessage(userID int64, groupID int64, m gjson.Resu
|
||||
if autoEscape {
|
||||
elem = []message.IMessageElement{message.NewText(str)}
|
||||
} else {
|
||||
elem = bot.ConvertStringMessage(str, false)
|
||||
elem = bot.ConvertStringMessage(str, MessageSourcePrivate)
|
||||
}
|
||||
}
|
||||
mid := bot.SendPrivateMessage(userID, groupID, &message.SendingMessage{Elements: elem})
|
||||
@ -1339,7 +1338,7 @@ func (bot *CQBot) CQGetForwardMessage(resID string) global.MSG {
|
||||
"nickname": n.SenderName,
|
||||
},
|
||||
"time": n.Time,
|
||||
"content": ToFormattedMessage(n.Message, 0, false),
|
||||
"content": ToFormattedMessage(n.Message, MessageSource{SourceType: MessageSourceGroup}, false),
|
||||
})
|
||||
}
|
||||
return OK(global.MSG{
|
||||
@ -1373,9 +1372,9 @@ func (bot *CQBot) CQGetMessage(messageID int32) global.MSG {
|
||||
switch o := msg.(type) {
|
||||
case *db.StoredGroupMessage:
|
||||
m["group_id"] = o.GroupCode
|
||||
m["message"] = ToFormattedMessage(bot.ConvertContentMessage(o.Content, true), o.GroupCode, false)
|
||||
m["message"] = ToFormattedMessage(bot.ConvertContentMessage(o.Content, MessageSourceGroup), MessageSource{SourceType: MessageSourceGroup, PrimaryID: uint64(o.GroupCode)}, false)
|
||||
case *db.StoredPrivateMessage:
|
||||
m["message"] = ToFormattedMessage(bot.ConvertContentMessage(o.Content, false), 0, false)
|
||||
m["message"] = ToFormattedMessage(bot.ConvertContentMessage(o.Content, MessageSourcePrivate), MessageSource{SourceType: MessageSourcePrivate}, false)
|
||||
}
|
||||
return OK(m)
|
||||
}
|
||||
@ -1474,7 +1473,7 @@ func (bot *CQBot) CQCanSendRecord() global.MSG {
|
||||
// @alias(.ocr_image)
|
||||
// @rename(image_id->image)
|
||||
func (bot *CQBot) CQOcrImage(imageID string) global.MSG {
|
||||
img, err := bot.makeImageOrVideoElem(map[string]string{"file": imageID}, false, true)
|
||||
img, err := bot.makeImageOrVideoElem(map[string]string{"file": imageID}, false, MessageSourceGroup)
|
||||
if err != nil {
|
||||
log.Warnf("load image error: %v", err)
|
||||
return Failed(100, "LOAD_FILE_ERROR", err.Error())
|
||||
|
70
coolq/bot.go
70
coolq/bot.go
@ -523,76 +523,6 @@ func (bot *CQBot) dispatchEventMessage(m global.MSG) {
|
||||
global.PutBuffer(event.buffer)
|
||||
}
|
||||
|
||||
func (bot *CQBot) formatGroupMessage(m *message.GroupMessage) global.MSG {
|
||||
cqm := ToStringMessage(m.Elements, m.GroupCode, true)
|
||||
gm := global.MSG{
|
||||
"anonymous": nil,
|
||||
"font": 0,
|
||||
"group_id": m.GroupCode,
|
||||
"message": ToFormattedMessage(m.Elements, m.GroupCode, false),
|
||||
"message_type": "group",
|
||||
"message_seq": m.Id,
|
||||
"post_type": func() string {
|
||||
if m.Sender.Uin == bot.Client.Uin {
|
||||
return "message_sent"
|
||||
}
|
||||
return "message"
|
||||
}(),
|
||||
"raw_message": cqm,
|
||||
"self_id": bot.Client.Uin,
|
||||
"sender": global.MSG{
|
||||
"age": 0,
|
||||
"area": "",
|
||||
"level": "",
|
||||
"sex": "unknown",
|
||||
"user_id": m.Sender.Uin,
|
||||
},
|
||||
"sub_type": "normal",
|
||||
"time": m.Time,
|
||||
"user_id": m.Sender.Uin,
|
||||
}
|
||||
if m.Sender.IsAnonymous() {
|
||||
gm["anonymous"] = global.MSG{
|
||||
"flag": m.Sender.AnonymousInfo.AnonymousId + "|" + m.Sender.AnonymousInfo.AnonymousNick,
|
||||
"id": m.Sender.Uin,
|
||||
"name": m.Sender.AnonymousInfo.AnonymousNick,
|
||||
}
|
||||
gm["sender"].(global.MSG)["nickname"] = "匿名消息"
|
||||
gm["sub_type"] = "anonymous"
|
||||
} else {
|
||||
group := bot.Client.FindGroup(m.GroupCode)
|
||||
mem := group.FindMember(m.Sender.Uin)
|
||||
if mem == nil {
|
||||
log.Warnf("获取 %v 成员信息失败,尝试刷新成员列表", m.Sender.Uin)
|
||||
t, err := bot.Client.GetGroupMembers(group)
|
||||
if err != nil {
|
||||
log.Warnf("刷新群 %v 成员列表失败: %v", group.Uin, err)
|
||||
return nil
|
||||
}
|
||||
group.Members = t
|
||||
mem = group.FindMember(m.Sender.Uin)
|
||||
if mem == nil {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
ms := gm["sender"].(global.MSG)
|
||||
switch mem.Permission {
|
||||
case client.Owner:
|
||||
ms["role"] = "owner"
|
||||
case client.Administrator:
|
||||
ms["role"] = "admin"
|
||||
case client.Member:
|
||||
ms["role"] = "member"
|
||||
default:
|
||||
ms["role"] = "member"
|
||||
}
|
||||
ms["nickname"] = mem.Nickname
|
||||
ms["card"] = mem.CardName
|
||||
ms["title"] = mem.SpecialTitle
|
||||
}
|
||||
return gm
|
||||
}
|
||||
|
||||
func formatGroupName(group *client.GroupInfo) string {
|
||||
return fmt.Sprintf("%s(%d)", group.Name, group.Code)
|
||||
}
|
||||
|
@ -2,7 +2,9 @@ package coolq
|
||||
|
||||
import (
|
||||
"github.com/Mrs4s/MiraiGo/client"
|
||||
"github.com/Mrs4s/MiraiGo/message"
|
||||
"github.com/Mrs4s/go-cqhttp/global"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
@ -55,6 +57,80 @@ func convertGuildMemberInfo(m *client.GuildMemberInfo) global.MSG {
|
||||
}
|
||||
}
|
||||
|
||||
func (bot *CQBot) formatGroupMessage(m *message.GroupMessage) global.MSG {
|
||||
source := MessageSource{
|
||||
SourceType: MessageSourceGroup,
|
||||
PrimaryID: uint64(m.GroupCode),
|
||||
}
|
||||
cqm := ToStringMessage(m.Elements, source, true)
|
||||
gm := global.MSG{
|
||||
"anonymous": nil,
|
||||
"font": 0,
|
||||
"group_id": m.GroupCode,
|
||||
"message": ToFormattedMessage(m.Elements, source, false),
|
||||
"message_type": "group",
|
||||
"message_seq": m.Id,
|
||||
"post_type": func() string {
|
||||
if m.Sender.Uin == bot.Client.Uin {
|
||||
return "message_sent"
|
||||
}
|
||||
return "message"
|
||||
}(),
|
||||
"raw_message": cqm,
|
||||
"self_id": bot.Client.Uin,
|
||||
"sender": global.MSG{
|
||||
"age": 0,
|
||||
"area": "",
|
||||
"level": "",
|
||||
"sex": "unknown",
|
||||
"user_id": m.Sender.Uin,
|
||||
},
|
||||
"sub_type": "normal",
|
||||
"time": m.Time,
|
||||
"user_id": m.Sender.Uin,
|
||||
}
|
||||
if m.Sender.IsAnonymous() {
|
||||
gm["anonymous"] = global.MSG{
|
||||
"flag": m.Sender.AnonymousInfo.AnonymousId + "|" + m.Sender.AnonymousInfo.AnonymousNick,
|
||||
"id": m.Sender.Uin,
|
||||
"name": m.Sender.AnonymousInfo.AnonymousNick,
|
||||
}
|
||||
gm["sender"].(global.MSG)["nickname"] = "匿名消息"
|
||||
gm["sub_type"] = "anonymous"
|
||||
} else {
|
||||
group := bot.Client.FindGroup(m.GroupCode)
|
||||
mem := group.FindMember(m.Sender.Uin)
|
||||
if mem == nil {
|
||||
log.Warnf("获取 %v 成员信息失败,尝试刷新成员列表", m.Sender.Uin)
|
||||
t, err := bot.Client.GetGroupMembers(group)
|
||||
if err != nil {
|
||||
log.Warnf("刷新群 %v 成员列表失败: %v", group.Uin, err)
|
||||
return nil
|
||||
}
|
||||
group.Members = t
|
||||
mem = group.FindMember(m.Sender.Uin)
|
||||
if mem == nil {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
ms := gm["sender"].(global.MSG)
|
||||
switch mem.Permission {
|
||||
case client.Owner:
|
||||
ms["role"] = "owner"
|
||||
case client.Administrator:
|
||||
ms["role"] = "admin"
|
||||
case client.Member:
|
||||
ms["role"] = "member"
|
||||
default:
|
||||
ms["role"] = "member"
|
||||
}
|
||||
ms["nickname"] = mem.Nickname
|
||||
ms["card"] = mem.CardName
|
||||
ms["title"] = mem.SpecialTitle
|
||||
}
|
||||
return gm
|
||||
}
|
||||
|
||||
func convertChannelInfo(c *client.ChannelInfo) global.MSG {
|
||||
slowModes := make([]global.MSG, 0, len(c.Meta.SlowModes))
|
||||
for _, mode := range c.Meta.SlowModes {
|
||||
|
117
coolq/cqcode.go
117
coolq/cqcode.go
@ -36,11 +36,6 @@ var typeReg = regexp.MustCompile(`\[CQ:(\w+)`)
|
||||
var paramReg = regexp.MustCompile(`,([\w\-.]+?)=([^,\]]+)`)
|
||||
*/
|
||||
|
||||
const (
|
||||
maxImageSize = 1024 * 1024 * 30 // 30MB
|
||||
maxVideoSize = 1024 * 1024 * 100 // 100MB
|
||||
)
|
||||
|
||||
// PokeElement 拍一拍
|
||||
type PokeElement struct {
|
||||
Target int64
|
||||
@ -73,6 +68,27 @@ type LocalVideoElement struct {
|
||||
thumb io.ReadSeeker
|
||||
}
|
||||
|
||||
// MessageSource 消息来源
|
||||
// 如果为私聊或者群聊, PrimaryID 将代表群号/QQ号
|
||||
// 如果为频道, PrimaryID 为 GuildID, SubID 为 ChannelID
|
||||
type MessageSource struct {
|
||||
SourceType MessageSourceType
|
||||
PrimaryID uint64
|
||||
SubID uint64
|
||||
}
|
||||
|
||||
// MessageSourceType 消息来源类型
|
||||
type MessageSourceType int32
|
||||
|
||||
const (
|
||||
maxImageSize = 1024 * 1024 * 30 // 30MB
|
||||
maxVideoSize = 1024 * 1024 * 100 // 100MB
|
||||
|
||||
MessageSourcePrivate MessageSourceType = 0
|
||||
MessageSourceGroup MessageSourceType = 1
|
||||
MessageSourceGuildChannel MessageSourceType = 2
|
||||
)
|
||||
|
||||
// Type implements the message.IMessageElement.
|
||||
func (e *LocalImageElement) Type() message.ElementType {
|
||||
return message.Image
|
||||
@ -114,16 +130,16 @@ func (e *PokeElement) Type() message.ElementType {
|
||||
}
|
||||
|
||||
// ToArrayMessage 将消息元素数组转为MSG数组以用于消息上报
|
||||
func ToArrayMessage(e []message.IMessageElement, groupID int64) (r []global.MSG) {
|
||||
func ToArrayMessage(e []message.IMessageElement, source MessageSource) (r []global.MSG) {
|
||||
r = make([]global.MSG, 0, len(e))
|
||||
m := &message.SendingMessage{Elements: e}
|
||||
reply := m.FirstOrNil(func(e message.IMessageElement) bool {
|
||||
_, ok := e.(*message.ReplyElement)
|
||||
return ok
|
||||
})
|
||||
if reply != nil {
|
||||
if reply != nil && source.SourceType == MessageSourceGroup {
|
||||
replyElem := reply.(*message.ReplyElement)
|
||||
rid := groupID
|
||||
rid := int64(source.PrimaryID)
|
||||
if rid == 0 {
|
||||
rid = replyElem.Sender
|
||||
}
|
||||
@ -138,7 +154,7 @@ func ToArrayMessage(e []message.IMessageElement, groupID int64) (r []global.MSG)
|
||||
"seq": strconv.FormatInt(int64(replyElem.ReplySeq), 10),
|
||||
"qq": strconv.FormatInt(replyElem.Sender, 10),
|
||||
"time": strconv.FormatInt(int64(replyElem.Time), 10),
|
||||
"text": ToStringMessage(replyElem.Elements, groupID),
|
||||
"text": ToStringMessage(replyElem.Elements, source),
|
||||
},
|
||||
})
|
||||
} else {
|
||||
@ -260,7 +276,7 @@ func ToArrayMessage(e []message.IMessageElement, groupID int64) (r []global.MSG)
|
||||
}
|
||||
|
||||
// ToStringMessage 将消息元素数组转为字符串以用于消息上报
|
||||
func ToStringMessage(e []message.IMessageElement, groupID int64, isRaw ...bool) (r string) {
|
||||
func ToStringMessage(e []message.IMessageElement, source MessageSource, isRaw ...bool) (r string) {
|
||||
sb := global.NewBuffer()
|
||||
sb.Reset()
|
||||
write := func(format string, a ...interface{}) {
|
||||
@ -276,9 +292,9 @@ func ToStringMessage(e []message.IMessageElement, groupID int64, isRaw ...bool)
|
||||
_, ok := e.(*message.ReplyElement)
|
||||
return ok
|
||||
})
|
||||
if reply != nil {
|
||||
if reply != nil && source.SourceType == MessageSourceGroup {
|
||||
replyElem := reply.(*message.ReplyElement)
|
||||
rid := groupID
|
||||
rid := int64(source.PrimaryID)
|
||||
if rid == 0 {
|
||||
rid = replyElem.Sender
|
||||
}
|
||||
@ -289,7 +305,7 @@ func ToStringMessage(e []message.IMessageElement, groupID int64, isRaw ...bool)
|
||||
write("[CQ:reply,id=%d,seq=%d,qq=%d,time=%d,text=%s]",
|
||||
db.ToGlobalID(rid, replyElem.ReplySeq),
|
||||
replyElem.ReplySeq, replyElem.Sender, replyElem.Time,
|
||||
CQCodeEscapeValue(ToStringMessage(replyElem.Elements, groupID)))
|
||||
CQCodeEscapeValue(ToStringMessage(replyElem.Elements, source)))
|
||||
} else {
|
||||
write("[CQ:reply,id=%d]", db.ToGlobalID(rid, replyElem.ReplySeq))
|
||||
}
|
||||
@ -352,6 +368,8 @@ func ToStringMessage(e []message.IMessageElement, groupID int64, isRaw ...bool)
|
||||
} else {
|
||||
write("[CQ:image,file=%s,url=%s%s]", hex.EncodeToString(o.Md5)+".image", CQCodeEscapeValue(o.Url), arg)
|
||||
}
|
||||
case *message.GuildImageElement:
|
||||
write("[CQ:image,file=%s,url=%s]", hex.EncodeToString(o.Md5)+".image", CQCodeEscapeValue(o.Url))
|
||||
case *message.DiceElement:
|
||||
write("[CQ:dice,value=%v]", o.Value)
|
||||
case *message.MarketFaceElement:
|
||||
@ -480,7 +498,7 @@ func ToMessageContent(e []message.IMessageElement) (r []global.MSG) {
|
||||
}
|
||||
|
||||
// ConvertStringMessage 将消息字符串转为消息元素数组
|
||||
func (bot *CQBot) ConvertStringMessage(raw string, isGroup bool) (r []message.IMessageElement) {
|
||||
func (bot *CQBot) ConvertStringMessage(raw string, sourceType MessageSourceType) (r []message.IMessageElement) {
|
||||
var t, key string
|
||||
d := map[string]string{}
|
||||
|
||||
@ -516,7 +534,7 @@ func (bot *CQBot) ConvertStringMessage(raw string, isGroup bool) (r []message.IM
|
||||
ReplySeq: org.GetAttribute().MessageSeq,
|
||||
Sender: org.GetAttribute().SenderUin,
|
||||
Time: int32(org.GetAttribute().Timestamp),
|
||||
Elements: bot.ConvertStringMessage(customText, isGroup),
|
||||
Elements: bot.ConvertStringMessage(customText, sourceType),
|
||||
}
|
||||
if senderErr != nil {
|
||||
elem.Sender = sender
|
||||
@ -532,7 +550,7 @@ func (bot *CQBot) ConvertStringMessage(raw string, isGroup bool) (r []message.IM
|
||||
ReplySeq: int32(messageSeq),
|
||||
Sender: sender,
|
||||
Time: int32(msgTime),
|
||||
Elements: bot.ConvertStringMessage(customText, isGroup),
|
||||
Elements: bot.ConvertStringMessage(customText, sourceType),
|
||||
}
|
||||
}
|
||||
r = append([]message.IMessageElement{elem}, r...)
|
||||
@ -544,7 +562,7 @@ func (bot *CQBot) ConvertStringMessage(raw string, isGroup bool) (r []message.IM
|
||||
ReplySeq: org.GetAttribute().MessageSeq,
|
||||
Sender: org.GetAttribute().SenderUin,
|
||||
Time: int32(org.GetAttribute().Timestamp),
|
||||
Elements: bot.ConvertContentMessage(org.GetContent(), isGroup),
|
||||
Elements: bot.ConvertContentMessage(org.GetContent(), sourceType),
|
||||
},
|
||||
}, r...)
|
||||
}
|
||||
@ -565,7 +583,7 @@ func (bot *CQBot) ConvertStringMessage(raw string, isGroup bool) (r []message.IM
|
||||
}
|
||||
return
|
||||
}
|
||||
elem, err := bot.ToElement(t, d, isGroup)
|
||||
elem, err := bot.ToElement(t, d, sourceType)
|
||||
if err != nil {
|
||||
org := "[CQ:" + t
|
||||
for k, v := range d {
|
||||
@ -653,11 +671,11 @@ func (bot *CQBot) ConvertStringMessage(raw string, isGroup bool) (r []message.IM
|
||||
}
|
||||
|
||||
// ConvertObjectMessage 将消息JSON对象转为消息元素数组
|
||||
func (bot *CQBot) ConvertObjectMessage(m gjson.Result, isGroup bool) (r []message.IMessageElement) {
|
||||
func (bot *CQBot) ConvertObjectMessage(m gjson.Result, sourceType MessageSourceType) (r []message.IMessageElement) {
|
||||
d := make(map[string]string)
|
||||
convertElem := func(e gjson.Result) {
|
||||
t := e.Get("type").Str
|
||||
if t == "reply" && isGroup {
|
||||
if t == "reply" && sourceType == MessageSourceGroup {
|
||||
if len(r) > 0 {
|
||||
if _, ok := r[0].(*message.ReplyElement); ok {
|
||||
log.Warnf("警告: 一条信息只能包含一个 Reply 元素.")
|
||||
@ -688,7 +706,7 @@ func (bot *CQBot) ConvertObjectMessage(m gjson.Result, isGroup bool) (r []messag
|
||||
ReplySeq: org.GetAttribute().MessageSeq,
|
||||
Sender: org.GetAttribute().SenderUin,
|
||||
Time: int32(org.GetAttribute().Timestamp),
|
||||
Elements: bot.ConvertStringMessage(customText, isGroup),
|
||||
Elements: bot.ConvertStringMessage(customText, sourceType),
|
||||
}
|
||||
if senderErr != nil {
|
||||
elem.Sender = sender
|
||||
@ -704,7 +722,7 @@ func (bot *CQBot) ConvertObjectMessage(m gjson.Result, isGroup bool) (r []messag
|
||||
ReplySeq: int32(messageSeq),
|
||||
Sender: sender,
|
||||
Time: int32(msgTime),
|
||||
Elements: bot.ConvertStringMessage(customText, isGroup),
|
||||
Elements: bot.ConvertStringMessage(customText, sourceType),
|
||||
}
|
||||
}
|
||||
r = append([]message.IMessageElement{elem}, r...)
|
||||
@ -716,7 +734,7 @@ func (bot *CQBot) ConvertObjectMessage(m gjson.Result, isGroup bool) (r []messag
|
||||
ReplySeq: org.GetAttribute().MessageSeq,
|
||||
Sender: org.GetAttribute().SenderUin,
|
||||
Time: int32(org.GetAttribute().Timestamp),
|
||||
Elements: bot.ConvertContentMessage(org.GetContent(), isGroup),
|
||||
Elements: bot.ConvertContentMessage(org.GetContent(), sourceType),
|
||||
},
|
||||
}, r...)
|
||||
}
|
||||
@ -745,7 +763,7 @@ func (bot *CQBot) ConvertObjectMessage(m gjson.Result, isGroup bool) (r []messag
|
||||
d[key.Str] = value.String()
|
||||
return true
|
||||
})
|
||||
elem, err := bot.ToElement(t, d, isGroup)
|
||||
elem, err := bot.ToElement(t, d, sourceType)
|
||||
if err != nil {
|
||||
log.Warnf("转换CQ码 (%v) 到MiraiGo Element时出现错误: %v 将忽略本段CQ码.", e.Raw, err)
|
||||
return
|
||||
@ -758,7 +776,7 @@ func (bot *CQBot) ConvertObjectMessage(m gjson.Result, isGroup bool) (r []messag
|
||||
}
|
||||
}
|
||||
if m.Type == gjson.String {
|
||||
return bot.ConvertStringMessage(m.Str, isGroup)
|
||||
return bot.ConvertStringMessage(m.Str, sourceType)
|
||||
}
|
||||
if m.IsArray() {
|
||||
m.ForEach(func(_, e gjson.Result) bool {
|
||||
@ -773,14 +791,14 @@ func (bot *CQBot) ConvertObjectMessage(m gjson.Result, isGroup bool) (r []messag
|
||||
}
|
||||
|
||||
// ConvertContentMessage 将数据库用的 content 转换为消息元素数组
|
||||
func (bot *CQBot) ConvertContentMessage(content []global.MSG, group bool) (r []message.IMessageElement) {
|
||||
func (bot *CQBot) ConvertContentMessage(content []global.MSG, sourceType MessageSourceType) (r []message.IMessageElement) {
|
||||
for _, c := range content {
|
||||
data := c["data"].(global.MSG)
|
||||
switch c["type"] {
|
||||
case "text":
|
||||
r = append(r, message.NewText(data["text"].(string)))
|
||||
case "image":
|
||||
e, err := bot.makeImageOrVideoElem(map[string]string{"file": data["file"].(string)}, false, group)
|
||||
e, err := bot.makeImageOrVideoElem(map[string]string{"file": data["file"].(string)}, false, sourceType)
|
||||
if err != nil {
|
||||
log.Warnf("make image elem error: %v", err)
|
||||
continue
|
||||
@ -830,7 +848,7 @@ func (bot *CQBot) ConvertContentMessage(content []global.MSG, group bool) (r []m
|
||||
case "face":
|
||||
r = append(r, message.NewFace(data["id"].(int32)))
|
||||
case "video":
|
||||
e, err := bot.makeImageOrVideoElem(map[string]string{"file": data["file"].(string)}, true, group)
|
||||
e, err := bot.makeImageOrVideoElem(map[string]string{"file": data["file"].(string)}, true, sourceType)
|
||||
if err != nil {
|
||||
log.Warnf("make image elem error: %v", err)
|
||||
continue
|
||||
@ -846,7 +864,7 @@ func (bot *CQBot) ConvertContentMessage(content []global.MSG, group bool) (r []m
|
||||
// 返回 interface{} 存在三种类型
|
||||
//
|
||||
// message.IMessageElement []message.IMessageElement nil
|
||||
func (bot *CQBot) ToElement(t string, d map[string]string, isGroup bool) (m interface{}, err error) {
|
||||
func (bot *CQBot) ToElement(t string, d map[string]string, sourceType MessageSourceType) (m interface{}, err error) {
|
||||
switch t {
|
||||
case "text":
|
||||
if base.SplitURL {
|
||||
@ -858,7 +876,7 @@ func (bot *CQBot) ToElement(t string, d map[string]string, isGroup bool) (m inte
|
||||
}
|
||||
return message.NewText(d["text"]), nil
|
||||
case "image":
|
||||
img, err := bot.makeImageOrVideoElem(d, false, isGroup)
|
||||
img, err := bot.makeImageOrVideoElem(d, false, sourceType)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -892,7 +910,7 @@ func (bot *CQBot) ToElement(t string, d map[string]string, isGroup bool) (m inte
|
||||
t, _ := strconv.ParseInt(d["qq"], 10, 64)
|
||||
return &PokeElement{Target: t}, nil
|
||||
case "gift":
|
||||
if !isGroup {
|
||||
if sourceType != MessageSourceGroup {
|
||||
return nil, errors.New("private gift unsupported") // no free private gift
|
||||
}
|
||||
t, _ := strconv.ParseInt(d["qq"], 10, 64)
|
||||
@ -1088,13 +1106,13 @@ func (bot *CQBot) ToElement(t string, d map[string]string, isGroup bool) (m inte
|
||||
maxWidth := parseIntWithDefault("maxwidth", 500)
|
||||
minHeight := parseIntWithDefault("minheight", 200)
|
||||
maxHeight := parseIntWithDefault("maxheight", 1000)
|
||||
img, err := bot.makeImageOrVideoElem(d, false, isGroup)
|
||||
img, err := bot.makeImageOrVideoElem(d, false, sourceType)
|
||||
if err != nil {
|
||||
return nil, errors.New("send cardimage faild")
|
||||
}
|
||||
return bot.makeShowPic(img, source, brief, icon, minWidth, minHeight, maxWidth, maxHeight, isGroup)
|
||||
return bot.makeShowPic(img, source, brief, icon, minWidth, minHeight, maxWidth, maxHeight, sourceType == MessageSourceGroup)
|
||||
case "video":
|
||||
file, err := bot.makeImageOrVideoElem(d, true, isGroup)
|
||||
file, err := bot.makeImageOrVideoElem(d, true, sourceType)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -1248,7 +1266,7 @@ func CQCodeUnescapeValue(content string) string {
|
||||
}
|
||||
|
||||
// makeImageOrVideoElem 图片 elem 生成器,单独拎出来,用于公用
|
||||
func (bot *CQBot) makeImageOrVideoElem(d map[string]string, video, group bool) (message.IMessageElement, error) {
|
||||
func (bot *CQBot) makeImageOrVideoElem(d map[string]string, video bool, sourceType MessageSourceType) (message.IMessageElement, error) {
|
||||
f := d["file"]
|
||||
if strings.HasPrefix(f, "http") {
|
||||
hash := md5.Sum([]byte(f))
|
||||
@ -1327,11 +1345,18 @@ func (bot *CQBot) makeImageOrVideoElem(d map[string]string, video, group bool) (
|
||||
b, _ := os.ReadFile(rawPath)
|
||||
return bot.readVideoCache(b), nil
|
||||
}
|
||||
// 目前频道内上传的图片均无法被查询到, 需要单独处理
|
||||
if sourceType == MessageSourceGuildChannel {
|
||||
cacheFile := path.Join(global.ImagePath, "guild-images", f)
|
||||
if global.PathExists(cacheFile) {
|
||||
return &LocalImageElement{File: cacheFile}, nil
|
||||
}
|
||||
}
|
||||
if strings.HasSuffix(f, ".image") && cache.EnableCacheDB {
|
||||
hash, err := hex.DecodeString(strings.TrimSuffix(f, ".image"))
|
||||
if err == nil {
|
||||
if b := cache.Image.Get(hash); b != nil {
|
||||
return bot.readImageCache(b, group)
|
||||
return bot.readImageCache(b, sourceType)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1342,7 +1367,7 @@ func (bot *CQBot) makeImageOrVideoElem(d map[string]string, video, group bool) (
|
||||
}
|
||||
if !exist {
|
||||
if d["url"] != "" {
|
||||
return bot.makeImageOrVideoElem(map[string]string{"file": d["url"]}, false, group)
|
||||
return bot.makeImageOrVideoElem(map[string]string{"file": d["url"]}, false, sourceType)
|
||||
}
|
||||
return nil, errors.New("invalid image")
|
||||
}
|
||||
@ -1353,10 +1378,10 @@ func (bot *CQBot) makeImageOrVideoElem(d map[string]string, video, group bool) (
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return bot.readImageCache(b, group)
|
||||
return bot.readImageCache(b, sourceType)
|
||||
}
|
||||
|
||||
func (bot *CQBot) readImageCache(b []byte, group bool) (message.IMessageElement, error) {
|
||||
func (bot *CQBot) readImageCache(b []byte, sourceType MessageSourceType) (message.IMessageElement, error) {
|
||||
var err error
|
||||
if len(b) < 20 {
|
||||
return nil, errors.New("invalid cache")
|
||||
@ -1368,7 +1393,7 @@ func (bot *CQBot) readImageCache(b []byte, group bool) (message.IMessageElement,
|
||||
imageURL := r.ReadString()
|
||||
if size == 0 {
|
||||
if imageURL != "" {
|
||||
return bot.makeImageOrVideoElem(map[string]string{"file": imageURL}, false, group)
|
||||
return bot.makeImageOrVideoElem(map[string]string{"file": imageURL}, false, sourceType)
|
||||
}
|
||||
return nil, errors.New("img size is 0")
|
||||
}
|
||||
@ -1376,15 +1401,23 @@ func (bot *CQBot) readImageCache(b []byte, group bool) (message.IMessageElement,
|
||||
return nil, errors.New("invalid hash")
|
||||
}
|
||||
var rsp message.IMessageElement
|
||||
if group {
|
||||
if sourceType == MessageSourceGroup {
|
||||
rsp, err = bot.Client.QueryGroupImage(int64(rand.Uint32()), hash, size)
|
||||
goto ok
|
||||
}
|
||||
if sourceType == MessageSourceGuildChannel {
|
||||
if len(bot.Client.GuildService.Guilds) == 0 {
|
||||
err = errors.New("cannot query guild image: not any joined guild")
|
||||
}
|
||||
guild := bot.Client.GuildService.Guilds[0]
|
||||
rsp, err = bot.Client.GuildService.QueryImage(guild.GuildId, guild.Channels[0].ChannelId, hash, uint64(size))
|
||||
goto ok
|
||||
}
|
||||
rsp, err = bot.Client.QueryFriendImage(int64(rand.Uint32()), hash, size)
|
||||
ok:
|
||||
if err != nil {
|
||||
if imageURL != "" {
|
||||
return bot.makeImageOrVideoElem(map[string]string{"file": imageURL}, false, group)
|
||||
return bot.makeImageOrVideoElem(map[string]string{"file": imageURL}, false, sourceType)
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
@ -22,18 +22,22 @@ import (
|
||||
)
|
||||
|
||||
// ToFormattedMessage 将给定[]message.IMessageElement转换为通过coolq.SetMessageFormat所定义的消息上报格式
|
||||
func ToFormattedMessage(e []message.IMessageElement, groupID int64, isRaw ...bool) (r interface{}) {
|
||||
func ToFormattedMessage(e []message.IMessageElement, source MessageSource, isRaw ...bool) (r interface{}) {
|
||||
if base.PostFormat == "string" {
|
||||
r = ToStringMessage(e, groupID, isRaw...)
|
||||
r = ToStringMessage(e, source, isRaw...)
|
||||
} else if base.PostFormat == "array" {
|
||||
r = ToArrayMessage(e, groupID)
|
||||
r = ToArrayMessage(e, source)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (bot *CQBot) privateMessageEvent(c *client.QQClient, m *message.PrivateMessage) {
|
||||
bot.checkMedia(m.Elements, m.Sender.Uin)
|
||||
cqm := ToStringMessage(m.Elements, 0, true)
|
||||
source := MessageSource{
|
||||
SourceType: MessageSourcePrivate,
|
||||
PrimaryID: uint64(m.Sender.Uin),
|
||||
}
|
||||
cqm := ToStringMessage(m.Elements, source, true)
|
||||
id := bot.InsertPrivateMessage(m)
|
||||
log.Infof("收到好友 %v(%v) 的消息: %v (%v)", m.Sender.DisplayName(), m.Sender.Uin, cqm, id)
|
||||
fm := global.MSG{
|
||||
@ -48,7 +52,7 @@ func (bot *CQBot) privateMessageEvent(c *client.QQClient, m *message.PrivateMess
|
||||
"message_id": id,
|
||||
"user_id": m.Sender.Uin,
|
||||
"target_id": m.Target,
|
||||
"message": ToFormattedMessage(m.Elements, 0, false),
|
||||
"message": ToFormattedMessage(m.Elements, source, false),
|
||||
"raw_message": cqm,
|
||||
"font": 0,
|
||||
"self_id": c.Uin,
|
||||
@ -86,7 +90,11 @@ func (bot *CQBot) groupMessageEvent(c *client.QQClient, m *message.GroupMessage)
|
||||
return
|
||||
}
|
||||
}
|
||||
cqm := ToStringMessage(m.Elements, m.GroupCode, true)
|
||||
source := MessageSource{
|
||||
SourceType: MessageSourceGroup,
|
||||
PrimaryID: uint64(m.GroupCode),
|
||||
}
|
||||
cqm := ToStringMessage(m.Elements, source, true)
|
||||
id := bot.InsertGroupMessage(m)
|
||||
log.Infof("收到群 %v(%v) 内 %v(%v) 的消息: %v (%v)", m.GroupName, m.GroupCode, m.Sender.DisplayName(), m.Sender.Uin, cqm, id)
|
||||
gm := bot.formatGroupMessage(m)
|
||||
@ -100,7 +108,11 @@ func (bot *CQBot) groupMessageEvent(c *client.QQClient, m *message.GroupMessage)
|
||||
func (bot *CQBot) tempMessageEvent(c *client.QQClient, e *client.TempMessageEvent) {
|
||||
m := e.Message
|
||||
bot.checkMedia(m.Elements, m.Sender.Uin)
|
||||
cqm := ToStringMessage(m.Elements, 0, true)
|
||||
source := MessageSource{
|
||||
SourceType: MessageSourcePrivate,
|
||||
PrimaryID: uint64(e.Session.Sender),
|
||||
}
|
||||
cqm := ToStringMessage(m.Elements, source, true)
|
||||
bot.tempSessionCache.Store(m.Sender.Uin, e.Session)
|
||||
id := m.Id
|
||||
// todo(Mrs4s)
|
||||
@ -115,7 +127,7 @@ func (bot *CQBot) tempMessageEvent(c *client.QQClient, e *client.TempMessageEven
|
||||
"temp_source": e.Session.Source,
|
||||
"message_id": id,
|
||||
"user_id": m.Sender.Uin,
|
||||
"message": ToFormattedMessage(m.Elements, 0, false),
|
||||
"message": ToFormattedMessage(m.Elements, source, false),
|
||||
"raw_message": cqm,
|
||||
"font": 0,
|
||||
"self_id": c.Uin,
|
||||
@ -143,7 +155,12 @@ func (bot *CQBot) guildChannelMessageEvent(c *client.QQClient, m *message.GuildC
|
||||
channel = c
|
||||
}
|
||||
}
|
||||
log.Infof("收到来自频道 %v(%v) 子频道 %v(%v) 内 %v(%v) 的消息: %v", guild.GuildName, guild.GuildId, channel.ChannelName, m.ChannelId, m.Sender.Nickname, m.Sender.TinyId, ToStringMessage(m.Elements, 0, true))
|
||||
source := MessageSource{
|
||||
SourceType: MessageSourceGuildChannel,
|
||||
PrimaryID: m.GuildId,
|
||||
SubID: m.ChannelId,
|
||||
}
|
||||
log.Infof("收到来自频道 %v(%v) 子频道 %v(%v) 内 %v(%v) 的消息: %v", guild.GuildName, guild.GuildId, channel.ChannelName, m.ChannelId, m.Sender.Nickname, m.Sender.TinyId, ToStringMessage(m.Elements, source, true))
|
||||
// todo: 数据库支持
|
||||
bot.dispatchEventMessage(global.MSG{
|
||||
"post_type": "message",
|
||||
@ -153,7 +170,7 @@ func (bot *CQBot) guildChannelMessageEvent(c *client.QQClient, m *message.GuildC
|
||||
"channel_id": m.ChannelId,
|
||||
"message_id": fmt.Sprintf("%v-%v", m.Id, m.InternalId),
|
||||
"user_id": m.Sender.TinyId,
|
||||
"message": ToFormattedMessage(m.Elements, 0, false), // todo: 增加对频道消息 Reply 的支持
|
||||
"message": ToFormattedMessage(m.Elements, source, false), // todo: 增加对频道消息 Reply 的支持
|
||||
"self_id": bot.Client.Uin,
|
||||
"self_tiny_id": bot.Client.GuildService.TinyId,
|
||||
"time": m.Time,
|
||||
@ -665,6 +682,12 @@ func (bot *CQBot) checkMedia(e []message.IMessageElement, sourceID int64) {
|
||||
} else if !global.PathExists(path.Join(global.ImagePath, filename)) {
|
||||
_ = os.WriteFile(path.Join(global.ImagePath, filename), data, 0o644)
|
||||
}
|
||||
|
||||
if i.Url != "" && !global.PathExists(path.Join(global.ImagePath, "guild-images", filename)) {
|
||||
if err := global.DownloadFile(i.Url, path.Join(global.ImagePath, "guild-images", filename), -1, map[string]string{}); err != nil {
|
||||
log.Warnf("下载频道图片时出现错误: %v", err)
|
||||
}
|
||||
}
|
||||
case *message.FriendImageElement:
|
||||
data := binary.NewWriterF(func(w *binary.Writer) {
|
||||
w.Write(i.Md5)
|
||||
|
2
go.mod
2
go.mod
@ -7,7 +7,7 @@ replace github.com/willf/bitset v1.2.0 => github.com/bits-and-blooms/bitset v1.2
|
||||
require (
|
||||
github.com/Baozisoftware/qrcode-terminal-go v0.0.0-20170407111555-c0650d8dff0f
|
||||
github.com/Microsoft/go-winio v0.5.1
|
||||
github.com/Mrs4s/MiraiGo v0.0.0-20211111181749-b85fc25cd59b
|
||||
github.com/Mrs4s/MiraiGo v0.0.0-20211112183036-d3a21e577b02
|
||||
github.com/dustin/go-humanize v1.0.0
|
||||
github.com/fumiama/go-hide-param v0.1.4
|
||||
github.com/gabriel-vasile/mimetype v1.4.0
|
||||
|
4
go.sum
4
go.sum
@ -3,8 +3,8 @@ github.com/Baozisoftware/qrcode-terminal-go v0.0.0-20170407111555-c0650d8dff0f/g
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/Microsoft/go-winio v0.5.1 h1:aPJp2QD7OOrhO5tQXqQoGSJc+DjDtWTGLOmNyAm6FgY=
|
||||
github.com/Microsoft/go-winio v0.5.1/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84=
|
||||
github.com/Mrs4s/MiraiGo v0.0.0-20211111181749-b85fc25cd59b h1:tu/xKD248MLJL63zH/gJttk0u3t4aaMV+GNsU5EmIEc=
|
||||
github.com/Mrs4s/MiraiGo v0.0.0-20211111181749-b85fc25cd59b/go.mod h1:imVKbfKqqeit+C/eaWGb4MKQ3z3gN6pRpBU5RMtp5so=
|
||||
github.com/Mrs4s/MiraiGo v0.0.0-20211112183036-d3a21e577b02 h1:D2a93R7eugdAfuZtVXYznjqGrKlfvtWQ0YTHnwJYq8U=
|
||||
github.com/Mrs4s/MiraiGo v0.0.0-20211112183036-d3a21e577b02/go.mod h1:UOO08UBb5mVisfwrjduINu5GF9+gmsn33f2tnr83xnE=
|
||||
github.com/bits-and-blooms/bitset v1.2.0 h1:Kn4yilvwNtMACtf1eYDlG8H77R07mZSPbMjLyS07ChA=
|
||||
github.com/bits-and-blooms/bitset v1.2.0/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
|
Loading…
x
Reference in New Issue
Block a user