Support Media Message (#9)
This commit is contained in:
@@ -1,11 +1,12 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/sjzar/chatlog/internal/model/wxproto"
|
||||
"github.com/sjzar/chatlog/pkg/util/lz4"
|
||||
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
@@ -23,7 +24,7 @@ type Message struct {
|
||||
TalkerID int `json:"talkerID"` // 聊天对象,Name2ID 表序号,索引值
|
||||
Talker string `json:"talker"` // 聊天对象,微信 ID or 群 ID
|
||||
IsSender int `json:"isSender"` // 是否为发送消息,0 接收消息,1 发送消息
|
||||
Type int `json:"type"` // 消息类型
|
||||
Type int64 `json:"type"` // 消息类型
|
||||
SubType int `json:"subType"` // 消息子类型
|
||||
Content string `json:"content"` // 消息内容,文字聊天内容 或 XML
|
||||
CompressContent []byte `json:"compressContent"` // 非文字聊天内容,如图片、语音、视频等
|
||||
@@ -32,8 +33,9 @@ type Message struct {
|
||||
|
||||
// Fill Info
|
||||
// 从联系人等信息中填充
|
||||
DisplayName string `json:"-"` // 显示名称
|
||||
ChatRoomName string `json:"-"` // 群聊名称
|
||||
DisplayName string `json:"-"` // 显示名称
|
||||
ChatRoomName string `json:"-"` // 群聊名称
|
||||
MediaMessage *MediaMessage `json:"-"` // 多媒体消息
|
||||
|
||||
Version string `json:"-"` // 消息版本,内部判断
|
||||
}
|
||||
@@ -72,7 +74,7 @@ type MessageV3 struct {
|
||||
TalkerID int `json:"TalkerId"` // 聊天对象,Name2ID 表序号,索引值
|
||||
StrTalker string `json:"StrTalker"` // 聊天对象,微信 ID or 群 ID
|
||||
IsSender int `json:"IsSender"` // 是否为发送消息,0 接收消息,1 发送消息
|
||||
Type int `json:"Type"` // 消息类型
|
||||
Type int64 `json:"Type"` // 消息类型
|
||||
SubType int `json:"SubType"` // 消息子类型
|
||||
StrContent string `json:"StrContent"` // 消息内容,文字聊天内容 或 XML
|
||||
CompressContent []byte `json:"CompressContent"` // 非文字聊天内容,如图片、语音、视频等
|
||||
@@ -99,14 +101,7 @@ type MessageV3 struct {
|
||||
|
||||
func (m *MessageV3) Wrap() *Message {
|
||||
|
||||
isChatRoom := strings.HasSuffix(m.StrTalker, "@chatroom")
|
||||
|
||||
var chatRoomSender string
|
||||
if len(m.BytesExtra) != 0 && isChatRoom {
|
||||
chatRoomSender = ParseBytesExtra(m.BytesExtra)
|
||||
}
|
||||
|
||||
return &Message{
|
||||
_m := &Message{
|
||||
Sequence: m.Sequence,
|
||||
CreateTime: time.Unix(m.CreateTime, 0),
|
||||
TalkerID: m.TalkerID,
|
||||
@@ -116,33 +111,65 @@ func (m *MessageV3) Wrap() *Message {
|
||||
SubType: m.SubType,
|
||||
Content: m.StrContent,
|
||||
CompressContent: m.CompressContent,
|
||||
IsChatRoom: isChatRoom,
|
||||
ChatRoomSender: chatRoomSender,
|
||||
Version: WeChatV3,
|
||||
}
|
||||
|
||||
_m.IsChatRoom = strings.HasSuffix(_m.Talker, "@chatroom")
|
||||
|
||||
if _m.Type == 49 {
|
||||
b, err := lz4.Decompress(m.CompressContent)
|
||||
if err == nil {
|
||||
_m.Content = string(b)
|
||||
}
|
||||
}
|
||||
|
||||
if _m.Type != 1 {
|
||||
mediaMessage, err := NewMediaMessage(_m.Type, _m.Content)
|
||||
if err == nil {
|
||||
_m.MediaMessage = mediaMessage
|
||||
}
|
||||
}
|
||||
|
||||
if len(m.BytesExtra) != 0 {
|
||||
if bytesExtra := ParseBytesExtra(m.BytesExtra); bytesExtra != nil {
|
||||
if _m.IsChatRoom {
|
||||
_m.ChatRoomSender = bytesExtra[1]
|
||||
}
|
||||
// FIXME xml 中的 md5 数据无法匹配到 hardlink 记录,所以直接用 proto 数据
|
||||
if _m.Type == 43 {
|
||||
path := bytesExtra[4]
|
||||
parts := strings.Split(filepath.ToSlash(path), "/")
|
||||
if len(parts) > 1 {
|
||||
path = strings.Join(parts[1:], "/")
|
||||
}
|
||||
_m.MediaMessage.MediaPath = path
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return _m
|
||||
}
|
||||
|
||||
// ParseBytesExtra 解析额外数据
|
||||
// 按需解析
|
||||
func ParseBytesExtra(b []byte) (chatRoomSender string) {
|
||||
func ParseBytesExtra(b []byte) map[int]string {
|
||||
var pbMsg wxproto.BytesExtra
|
||||
if err := proto.Unmarshal(b, &pbMsg); err != nil {
|
||||
return
|
||||
return nil
|
||||
}
|
||||
if pbMsg.Items == nil {
|
||||
return
|
||||
return nil
|
||||
}
|
||||
|
||||
ret := make(map[int]string, len(pbMsg.Items))
|
||||
for _, item := range pbMsg.Items {
|
||||
if item.Type == 1 {
|
||||
return item.Value
|
||||
}
|
||||
ret[int(item.Type)] = item.Value
|
||||
}
|
||||
|
||||
return
|
||||
return ret
|
||||
}
|
||||
|
||||
func (m *Message) PlainText(showChatRoom bool) string {
|
||||
func (m *Message) PlainText(showChatRoom bool, host string) string {
|
||||
buf := strings.Builder{}
|
||||
|
||||
talker := m.Talker
|
||||
@@ -177,51 +204,13 @@ func (m *Message) PlainText(showChatRoom bool) string {
|
||||
buf.WriteString(m.CreateTime.Format("2006-01-02 15:04:05"))
|
||||
buf.WriteString("\n")
|
||||
|
||||
switch m.Type {
|
||||
case 1:
|
||||
if m.MediaMessage != nil {
|
||||
m.MediaMessage.SetHost(host)
|
||||
buf.WriteString(m.MediaMessage.String())
|
||||
} else {
|
||||
buf.WriteString(m.Content)
|
||||
case 3:
|
||||
buf.WriteString("[图片]")
|
||||
case 34:
|
||||
buf.WriteString("[语音]")
|
||||
case 43:
|
||||
buf.WriteString("[视频]")
|
||||
case 47:
|
||||
buf.WriteString("[动画表情]")
|
||||
case 49:
|
||||
switch m.SubType {
|
||||
case 6:
|
||||
buf.WriteString("[文件]")
|
||||
case 8:
|
||||
buf.WriteString("[GIF表情]")
|
||||
case 19:
|
||||
buf.WriteString("[合并转发]")
|
||||
case 33, 36:
|
||||
buf.WriteString("[小程序]")
|
||||
case 57:
|
||||
buf.WriteString("[引用]")
|
||||
case 63:
|
||||
buf.WriteString("[视频号]")
|
||||
case 87:
|
||||
buf.WriteString("[群公告]")
|
||||
case 2000:
|
||||
buf.WriteString("[转账]")
|
||||
case 2003:
|
||||
buf.WriteString("[红包封面]")
|
||||
default:
|
||||
buf.WriteString("[分享]")
|
||||
}
|
||||
case 50:
|
||||
buf.WriteString("[语音通话]")
|
||||
case 10000:
|
||||
buf.WriteString("[系统消息]")
|
||||
default:
|
||||
content := m.Content
|
||||
if len(content) > 120 {
|
||||
content = content[:120] + "<...>"
|
||||
}
|
||||
buf.WriteString(fmt.Sprintf("Type: %d Content: %s", m.Type, content))
|
||||
}
|
||||
|
||||
buf.WriteString("\n")
|
||||
|
||||
return buf.String()
|
||||
|
||||
Reference in New Issue
Block a user