Support Media Message (#9)
This commit is contained in:
355
internal/model/mediamessage.go
Normal file
355
internal/model/mediamessage.go
Normal file
@@ -0,0 +1,355 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"encoding/xml"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/sjzar/chatlog/pkg/util"
|
||||
)
|
||||
|
||||
type MediaMessage struct {
|
||||
Type int64
|
||||
SubType int
|
||||
MediaMD5 string
|
||||
MediaPath string
|
||||
Title string
|
||||
Desc string
|
||||
Content string
|
||||
URL string
|
||||
|
||||
RecordInfo *RecordInfo
|
||||
|
||||
ReferDisplayName string
|
||||
ReferUserName string
|
||||
ReferCreateTime time.Time
|
||||
ReferMessage *MediaMessage
|
||||
|
||||
Host string
|
||||
|
||||
Message XMLMessage
|
||||
}
|
||||
|
||||
func NewMediaMessage(_type int64, data string) (*MediaMessage, error) {
|
||||
|
||||
__type, subType := util.SplitInt64ToTwoInt32(_type)
|
||||
|
||||
m := &MediaMessage{
|
||||
Type: __type,
|
||||
SubType: int(subType),
|
||||
}
|
||||
|
||||
if _type == 1 {
|
||||
m.Content = data
|
||||
return m, nil
|
||||
}
|
||||
|
||||
var msg XMLMessage
|
||||
err := xml.Unmarshal([]byte(data), &msg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
m.Message = msg
|
||||
if err := m.parse(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return m, nil
|
||||
}
|
||||
|
||||
func (m *MediaMessage) parse() error {
|
||||
|
||||
switch m.Type {
|
||||
case 3:
|
||||
m.MediaMD5 = m.Message.Image.MD5
|
||||
case 43:
|
||||
m.MediaMD5 = m.Message.Video.RawMd5
|
||||
case 49:
|
||||
m.SubType = m.Message.App.Type
|
||||
switch m.SubType {
|
||||
case 5:
|
||||
m.Title = m.Message.App.Title
|
||||
m.URL = m.Message.App.URL
|
||||
case 6:
|
||||
m.Title = m.Message.App.Title
|
||||
m.MediaMD5 = m.Message.App.MD5
|
||||
case 19:
|
||||
m.Title = m.Message.App.Title
|
||||
m.Desc = m.Message.App.Des
|
||||
if m.Message.App.RecordItem == nil {
|
||||
break
|
||||
}
|
||||
recordInfo := &RecordInfo{}
|
||||
err := xml.Unmarshal([]byte(m.Message.App.RecordItem.CDATA), recordInfo)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
m.RecordInfo = recordInfo
|
||||
case 57:
|
||||
m.Content = m.Message.App.Title
|
||||
if m.Message.App.ReferMsg == nil {
|
||||
break
|
||||
}
|
||||
subMsg, err := NewMediaMessage(m.Message.App.ReferMsg.Type, m.Message.App.ReferMsg.Content)
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
m.ReferDisplayName = m.Message.App.ReferMsg.DisplayName
|
||||
m.ReferUserName = m.Message.App.ReferMsg.ChatUsr
|
||||
m.ReferCreateTime = time.Unix(m.Message.App.ReferMsg.CreateTime, 0)
|
||||
m.ReferMessage = subMsg
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *MediaMessage) SetHost(host string) {
|
||||
m.Host = host
|
||||
}
|
||||
|
||||
func (m *MediaMessage) String() string {
|
||||
switch m.Type {
|
||||
case 1:
|
||||
return m.Content
|
||||
case 3:
|
||||
return fmt.Sprintf("", m.Host, m.MediaMD5)
|
||||
case 34:
|
||||
return "[语音]"
|
||||
case 43:
|
||||
if m.MediaPath != "" {
|
||||
return fmt.Sprintf("", m.Host, m.MediaPath)
|
||||
}
|
||||
return fmt.Sprintf("", m.Host, m.MediaMD5)
|
||||
case 47:
|
||||
return "[动画表情]"
|
||||
case 49:
|
||||
switch m.SubType {
|
||||
case 5:
|
||||
return fmt.Sprintf("[链接|%s](%s)", m.Title, m.URL)
|
||||
case 6:
|
||||
return fmt.Sprintf("[文件|%s](http://%s/file/%s)", m.Title, m.Host, m.MediaMD5)
|
||||
case 8:
|
||||
return "[GIF表情]"
|
||||
case 19:
|
||||
if m.RecordInfo == nil {
|
||||
return "[合并转发]"
|
||||
}
|
||||
buf := strings.Builder{}
|
||||
for _, item := range m.RecordInfo.DataList.DataItems {
|
||||
buf.WriteString(item.SourceName + ": ")
|
||||
switch item.DataType {
|
||||
case "jpg":
|
||||
buf.WriteString(fmt.Sprintf("", m.Host, item.FullMD5))
|
||||
default:
|
||||
buf.WriteString(item.DataDesc)
|
||||
}
|
||||
buf.WriteString("\n")
|
||||
}
|
||||
return m.Content
|
||||
case 33, 36:
|
||||
return "[小程序]"
|
||||
case 57:
|
||||
if m.ReferMessage == nil {
|
||||
if m.Content == "" {
|
||||
return "[引用]"
|
||||
}
|
||||
return "> [引用]\n" + m.Content
|
||||
}
|
||||
buf := strings.Builder{}
|
||||
buf.WriteString("> ")
|
||||
if m.ReferDisplayName != "" {
|
||||
buf.WriteString(m.ReferDisplayName)
|
||||
buf.WriteString("(")
|
||||
buf.WriteString(m.ReferUserName)
|
||||
buf.WriteString(")")
|
||||
} else {
|
||||
buf.WriteString(m.ReferUserName)
|
||||
}
|
||||
buf.WriteString(" ")
|
||||
buf.WriteString(m.ReferCreateTime.Format("2006-01-02 15:04:05"))
|
||||
buf.WriteString("\n")
|
||||
buf.WriteString("> ")
|
||||
m.ReferMessage.SetHost(m.Host)
|
||||
buf.WriteString(strings.ReplaceAll(m.ReferMessage.String(), "\n", "\n> "))
|
||||
buf.WriteString("\n")
|
||||
buf.WriteString(m.Content)
|
||||
m.Content = buf.String()
|
||||
return m.Content
|
||||
case 63:
|
||||
return "[视频号]"
|
||||
case 87:
|
||||
return "[群公告]"
|
||||
case 2000:
|
||||
return "[转账]"
|
||||
case 2003:
|
||||
return "[红包封面]"
|
||||
default:
|
||||
return "[分享]"
|
||||
}
|
||||
case 50:
|
||||
return "[语音通话]"
|
||||
case 10000:
|
||||
return "[系统消息]"
|
||||
default:
|
||||
content := m.Content
|
||||
if len(content) > 120 {
|
||||
content = content[:120] + "<...>"
|
||||
}
|
||||
return fmt.Sprintf("Type: %d Content: %s", m.Type, content)
|
||||
}
|
||||
}
|
||||
|
||||
type XMLMessage struct {
|
||||
XMLName xml.Name `xml:"msg"`
|
||||
Image Image `xml:"img,omitempty"`
|
||||
Video Video `xml:"videomsg,omitempty"`
|
||||
App App `xml:"appmsg,omitempty"`
|
||||
}
|
||||
|
||||
type XMLImageMessage struct {
|
||||
XMLName xml.Name `xml:"msg"`
|
||||
Img Image `xml:"img"`
|
||||
}
|
||||
|
||||
type Image struct {
|
||||
MD5 string `xml:"md5,attr"`
|
||||
// HdLength string `xml:"hdlength,attr"`
|
||||
// Length string `xml:"length,attr"`
|
||||
// AesKey string `xml:"aeskey,attr"`
|
||||
// EncryVer string `xml:"encryver,attr"`
|
||||
// OriginSourceMd5 string `xml:"originsourcemd5,attr"`
|
||||
// FileKey string `xml:"filekey,attr"`
|
||||
// UploadContinueCount string `xml:"uploadcontinuecount,attr"`
|
||||
// ImgSourceUrl string `xml:"imgsourceurl,attr"`
|
||||
// HevcMidSize string `xml:"hevc_mid_size,attr"`
|
||||
// CdnBigImgUrl string `xml:"cdnbigimgurl,attr"`
|
||||
// CdnMidImgUrl string `xml:"cdnmidimgurl,attr"`
|
||||
// CdnThumbUrl string `xml:"cdnthumburl,attr"`
|
||||
// CdnThumbLength string `xml:"cdnthumblength,attr"`
|
||||
// CdnThumbWidth string `xml:"cdnthumbwidth,attr"`
|
||||
// CdnThumbHeight string `xml:"cdnthumbheight,attr"`
|
||||
// CdnThumbAesKey string `xml:"cdnthumbaeskey,attr"`
|
||||
}
|
||||
|
||||
type XMLVideoMessage struct {
|
||||
XMLName xml.Name `xml:"msg"`
|
||||
VideoMsg Video `xml:"videomsg"`
|
||||
}
|
||||
|
||||
type Video struct {
|
||||
RawMd5 string `xml:"rawmd5,attr"`
|
||||
// Length string `xml:"length,attr"`
|
||||
// PlayLength string `xml:"playlength,attr"`
|
||||
// Offset string `xml:"offset,attr"`
|
||||
// FromUserName string `xml:"fromusername,attr"`
|
||||
// Status string `xml:"status,attr"`
|
||||
// Compress string `xml:"compress,attr"`
|
||||
// CameraType string `xml:"cameratype,attr"`
|
||||
// Source string `xml:"source,attr"`
|
||||
// AesKey string `xml:"aeskey,attr"`
|
||||
// CdnVideoUrl string `xml:"cdnvideourl,attr"`
|
||||
// CdnThumbUrl string `xml:"cdnthumburl,attr"`
|
||||
// CdnThumbLength string `xml:"cdnthumblength,attr"`
|
||||
// CdnThumbWidth string `xml:"cdnthumbwidth,attr"`
|
||||
// CdnThumbHeight string `xml:"cdnthumbheight,attr"`
|
||||
// CdnThumbAesKey string `xml:"cdnthumbaeskey,attr"`
|
||||
// EncryVer string `xml:"encryver,attr"`
|
||||
// RawLength string `xml:"rawlength,attr"`
|
||||
// CdnRawVideoUrl string `xml:"cdnrawvideourl,attr"`
|
||||
// CdnRawVideoAesKey string `xml:"cdnrawvideoaeskey,attr"`
|
||||
}
|
||||
|
||||
type App struct {
|
||||
Type int `xml:"type"`
|
||||
Title string `xml:"title"`
|
||||
Des string `xml:"des"`
|
||||
URL string `xml:"url"` // type 5 分享
|
||||
AppAttach AppAttach `xml:"appattach"` // type 6 文件
|
||||
MD5 string `xml:"md5"` // type 6 文件
|
||||
RecordItem *RecordItem `xml:"recorditem,omitempty"` // type 19 合并转发
|
||||
ReferMsg *ReferMsg `xml:"refermsg,omitempty"` // type 57 引用
|
||||
}
|
||||
|
||||
// ReferMsg 表示引用消息
|
||||
type ReferMsg struct {
|
||||
Type int64 `xml:"type"`
|
||||
SvrID string `xml:"svrid"`
|
||||
FromUsr string `xml:"fromusr"`
|
||||
ChatUsr string `xml:"chatusr"`
|
||||
DisplayName string `xml:"displayname"`
|
||||
MsgSource string `xml:"msgsource"`
|
||||
Content string `xml:"content"`
|
||||
StrID string `xml:"strid"`
|
||||
CreateTime int64 `xml:"createtime"`
|
||||
}
|
||||
|
||||
// AppAttach 表示应用附件
|
||||
type AppAttach struct {
|
||||
TotalLen string `xml:"totallen"`
|
||||
AttachID string `xml:"attachid"`
|
||||
CDNAttachURL string `xml:"cdnattachurl"`
|
||||
EmoticonMD5 string `xml:"emoticonmd5"`
|
||||
AESKey string `xml:"aeskey"`
|
||||
FileExt string `xml:"fileext"`
|
||||
IsLargeFileMsg string `xml:"islargefilemsg"`
|
||||
}
|
||||
|
||||
type RecordItem struct {
|
||||
CDATA string `xml:",cdata"`
|
||||
|
||||
// 解析后的记录信息
|
||||
RecordInfo *RecordInfo
|
||||
}
|
||||
|
||||
// RecordInfo 表示聊天记录信息
|
||||
type RecordInfo struct {
|
||||
XMLName xml.Name `xml:"recordinfo"`
|
||||
FromScene string `xml:"fromscene,omitempty"`
|
||||
FavUsername string `xml:"favusername,omitempty"`
|
||||
FavCreateTime string `xml:"favcreatetime,omitempty"`
|
||||
IsChatRoom string `xml:"isChatRoom,omitempty"`
|
||||
Title string `xml:"title,omitempty"`
|
||||
Desc string `xml:"desc,omitempty"`
|
||||
Info string `xml:"info,omitempty"`
|
||||
DataList DataList `xml:"datalist,omitempty"`
|
||||
}
|
||||
|
||||
// DataList 表示数据列表
|
||||
type DataList struct {
|
||||
Count string `xml:"count,attr,omitempty"`
|
||||
DataItems []DataItem `xml:"dataitem,omitempty"`
|
||||
}
|
||||
|
||||
// DataItem 表示数据项
|
||||
type DataItem struct {
|
||||
DataType string `xml:"datatype,attr,omitempty"`
|
||||
DataID string `xml:"dataid,attr,omitempty"`
|
||||
HTMLID string `xml:"htmlid,attr,omitempty"`
|
||||
DataFmt string `xml:"datafmt,omitempty"`
|
||||
SourceName string `xml:"sourcename,omitempty"`
|
||||
SourceTime string `xml:"sourcetime,omitempty"`
|
||||
SourceHeadURL string `xml:"sourceheadurl,omitempty"`
|
||||
DataDesc string `xml:"datadesc,omitempty"`
|
||||
|
||||
// 图片特有字段
|
||||
ThumbSourcePath string `xml:"thumbsourcepath,omitempty"`
|
||||
ThumbSize string `xml:"thumbsize,omitempty"`
|
||||
CDNDataURL string `xml:"cdndataurl,omitempty"`
|
||||
CDNDataKey string `xml:"cdndatakey,omitempty"`
|
||||
CDNThumbURL string `xml:"cdnthumburl,omitempty"`
|
||||
CDNThumbKey string `xml:"cdnthumbkey,omitempty"`
|
||||
DataSourcePath string `xml:"datasourcepath,omitempty"`
|
||||
FullMD5 string `xml:"fullmd5,omitempty"`
|
||||
ThumbFullMD5 string `xml:"thumbfullmd5,omitempty"`
|
||||
ThumbHead256MD5 string `xml:"thumbhead256md5,omitempty"`
|
||||
DataSize string `xml:"datasize,omitempty"`
|
||||
CDNEncryVer string `xml:"cdnencryver,omitempty"`
|
||||
SrcChatname string `xml:"srcChatname,omitempty"`
|
||||
SrcMsgLocalID string `xml:"srcMsgLocalid,omitempty"`
|
||||
SrcMsgCreateTime string `xml:"srcMsgCreateTime,omitempty"`
|
||||
MessageUUID string `xml:"messageuuid,omitempty"`
|
||||
FromNewMsgID string `xml:"fromnewmsgid,omitempty"`
|
||||
}
|
||||
Reference in New Issue
Block a user