support voice message (#31)

This commit is contained in:
Sarv
2025-04-12 03:10:32 +08:00
committed by GitHub
parent ba3563ad4e
commit f2aa923e99
15 changed files with 338 additions and 137 deletions

View File

@@ -47,33 +47,6 @@ type ContactV3 struct {
Remark string `json:"Remark"`
NickName string `json:"NickName"`
Reserved1 int `json:"Reserved1"` // 1 自己好友或自己加入的群聊; 0 群聊成员(非好友)
// EncryptUserName string `json:"EncryptUserName"`
// DelFlag int `json:"DelFlag"`
// Type int `json:"Type"`
// VerifyFlag int `json:"VerifyFlag"`
// Reserved2 int `json:"Reserved2"`
// Reserved3 string `json:"Reserved3"`
// Reserved4 string `json:"Reserved4"`
// LabelIDList string `json:"LabelIDList"`
// DomainList string `json:"DomainList"`
// ChatRoomType int `json:"ChatRoomType"`
// PYInitial string `json:"PYInitial"`
// QuanPin string `json:"QuanPin"`
// RemarkPYInitial string `json:"RemarkPYInitial"`
// RemarkQuanPin string `json:"RemarkQuanPin"`
// BigHeadImgUrl string `json:"BigHeadImgUrl"`
// SmallHeadImgUrl string `json:"SmallHeadImgUrl"`
// HeadImgMd5 string `json:"HeadImgMd5"`
// ChatRoomNotify int `json:"ChatRoomNotify"`
// Reserved5 int `json:"Reserved5"`
// Reserved6 string `json:"Reserved6"`
// Reserved7 string `json:"Reserved7"`
// ExtraBuf []byte `json:"ExtraBuf"`
// Reserved8 int `json:"Reserved8"`
// Reserved9 int `json:"Reserved9"`
// Reserved10 string `json:"Reserved10"`
// Reserved11 string `json:"Reserved11"`
}
func (c *ContactV3) Wrap() *Contact {

View File

@@ -40,33 +40,6 @@ type ContactDarwinV3 struct {
M_nsRemark string `json:"m_nsRemark"`
M_uiSex int `json:"m_uiSex"`
M_nsAliasName string `json:"m_nsAliasName"`
// M_uiConType int `json:"m_uiConType"`
// M_nsShortPY string `json:"m_nsShortPY"`
// M_nsRemarkPYFull string `json:"m_nsRemarkPYFull"`
// M_nsRemarkPYShort string `json:"m_nsRemarkPYShort"`
// M_uiCertificationFlag int `json:"m_uiCertificationFlag"`
// M_uiType int `json:"m_uiType"` // 本来想拿这个字段来区分是否是好友,但是数据比较乱,好在 darwin v3 Contact 表中没有群聊成员
// M_nsImgStatus string `json:"m_nsImgStatus"`
// M_uiImgKey int `json:"m_uiImgKey"`
// M_nsHeadImgUrl string `json:"m_nsHeadImgUrl"`
// M_nsHeadHDImgUrl string `json:"m_nsHeadHDImgUrl"`
// M_nsHeadHDMd5 string `json:"m_nsHeadHDMd5"`
// M_nsChatRoomMemList string `json:"m_nsChatRoomMemList"`
// M_nsChatRoomAdminList string `json:"m_nsChatRoomAdminList"`
// M_uiChatRoomStatus int `json:"m_uiChatRoomStatus"`
// M_nsChatRoomDesc string `json:"m_nsChatRoomDesc"`
// M_nsDraft string `json:"m_nsDraft"`
// M_nsBrandIconUrl string `json:"m_nsBrandIconUrl"`
// M_nsGoogleContactName string `json:"m_nsGoogleContactName"`
// M_nsEncodeUserName string `json:"m_nsEncodeUserName"`
// M_uiChatRoomVersion int `json:"m_uiChatRoomVersion"`
// M_uiChatRoomMaxCount int `json:"m_uiChatRoomMaxCount"`
// M_uiChatRoomType int `json:"m_uiChatRoomType"`
// M_patSuffix string `json:"m_patSuffix"`
// RichChatRoomDesc string `json:"richChatRoomDesc"`
// Packed_WCContactData string `json:"_packed_WCContactData"`
// OpenIMInfo string `json:"openIMInfo"`
}
func (c *ContactDarwinV3) Wrap() *Contact {

View File

@@ -30,25 +30,6 @@ type ContactV4 struct {
Remark string `json:"remark"`
NickName string `json:"nick_name"`
LocalType int `json:"local_type"` // 2 群聊; 3 群聊成员(非好友); 5,6 企业微信;
// ID int `json:"id"`
// EncryptUserName string `json:"encrypt_username"`
// Flag int `json:"flag"`
// DeleteFlag int `json:"delete_flag"`
// VerifyFlag int `json:"verify_flag"`
// RemarkQuanPin string `json:"remark_quan_pin"`
// RemarkPinYinInitial string `json:"remark_pin_yin_initial"`
// PinYinInitial string `json:"pin_yin_initial"`
// QuanPin string `json:"quan_pin"`
// BigHeadUrl string `json:"big_head_url"`
// SmallHeadUrl string `json:"small_head_url"`
// HeadImgMd5 string `json:"head_img_md5"`
// ChatRoomNotify int `json:"chat_room_notify"`
// IsInChatRoom int `json:"is_in_chat_room"`
// Description string `json:"description"`
// ExtraBuffer []byte `json:"extra_buffer"`
// ChatRoomType int `json:"chat_room_type"`
}
func (c *ContactV4) Wrap() *Contact {

View File

@@ -10,6 +10,7 @@ type Media struct {
Path string `json:"path"`
Name string `json:"name"`
Size int64 `json:"size"`
Data []byte `json:"data"` // for voice
ModifyTime int64 `json:"modifyTime"`
}

View File

@@ -283,9 +283,34 @@ type FinderMegaVideo struct {
}
type SysMsg struct {
SysMsgTemplate SysMsgTemplate `xml:"sysmsgtemplate"`
Type string `xml:"type,attr"`
DelChatRoomMember *DelChatRoomMember `xml:"delchatroommember,omitempty"`
SysMsgTemplate *SysMsgTemplate `xml:"sysmsgtemplate,omitempty"`
}
// 第一种消息类型:删除群成员/二维码邀请
type DelChatRoomMember struct {
Plain string `xml:"plain"`
Text string `xml:"text"`
Link QRLink `xml:"link"`
}
type QRLink struct {
Scene string `xml:"scene"`
Text string `xml:"text"`
MemberList QRMemberList `xml:"memberlist"`
QRCode string `xml:"qrcode"`
}
type QRMemberList struct {
Usernames []UsernameItem `xml:"username"`
}
type UsernameItem struct {
Value string `xml:",chardata"`
}
// 第二种消息类型:系统消息模板
type SysMsgTemplate struct {
ContentTemplate ContentTemplate `xml:"content_template"`
}
@@ -305,7 +330,8 @@ type Link struct {
Name string `xml:"name,attr"`
Type string `xml:"type,attr"`
MemberList MemberList `xml:"memberlist"`
Separator string `xml:"separator"`
Separator string `xml:"separator,omitempty"`
Title string `xml:"title,omitempty"`
}
type MemberList struct {
@@ -318,6 +344,24 @@ type Member struct {
}
func (s *SysMsg) String() string {
if s.Type == "delchatroommember" {
return s.DelChatRoomMemberString()
}
return s.SysMsgTemplateString()
}
func (s *SysMsg) DelChatRoomMemberString() string {
if s.DelChatRoomMember == nil {
return ""
}
return s.DelChatRoomMember.Plain
}
func (s *SysMsg) SysMsgTemplateString() string {
if s.SysMsgTemplate == nil {
return ""
}
template := s.SysMsgTemplate.ContentTemplate.Template
links := s.SysMsgTemplate.ContentTemplate.LinkList.Links
@@ -354,7 +398,11 @@ func (s *SysMsg) String() string {
// 可以根据需要添加其他链接类型的处理逻辑
default:
replacement = ""
if link.Title != "" {
replacement = link.Title
} else {
replacement = ""
}
}
// 将占位符名称和替换内容存入映射

View File

@@ -55,6 +55,8 @@ func (m *Message) ParseMediaInfo(data string) error {
if Debug {
m.SysMsg = &sysMsg
}
m.Sender = "系统消息"
m.SenderName = ""
m.Content = sysMsg.String()
return nil
}
@@ -188,13 +190,8 @@ func (m *Message) PlainText(showChatRoom bool, host string) string {
buf := strings.Builder{}
sender := m.Sender
switch {
case m.Type == 10000:
sender = "系统消息"
case m.IsSelf:
if m.IsSelf {
sender = "我"
default:
sender = m.Sender
}
if m.SenderName != "" {
buf.WriteString(m.SenderName)
@@ -235,6 +232,9 @@ func (m *Message) PlainTextContent() string {
case 3:
return fmt.Sprintf("![图片](http://%s/image/%s)", m.Contents["host"], m.Contents["md5"])
case 34:
if voice, ok := m.Contents["voice"]; ok {
return fmt.Sprintf("[语音](http://%s/voice/%s)", m.Contents["host"], voice)
}
return "[语音]"
case 42:
return "[名片]"

View File

@@ -1,6 +1,7 @@
package model
import (
"fmt"
"path/filepath"
"strings"
"time"
@@ -39,6 +40,7 @@ import (
// BytesTrans BLOB
// )
type MessageV3 struct {
MsgSvrID int64 `json:"MsgSvrID"` // 消息 ID
Sequence int64 `json:"Sequence"` // 消息序号10位时间戳 + 3位序号
CreateTime int64 `json:"CreateTime"` // 消息创建时间10位时间戳
StrTalker string `json:"StrTalker"` // 聊天对象,微信 ID or 群 ID
@@ -77,6 +79,11 @@ func (m *MessageV3) Wrap() *Message {
_m.ParseMediaInfo(_m.Content)
// 语音消息
if _m.Type == 34 {
_m.Contents["voice"] = fmt.Sprint(m.MsgSvrID)
}
if len(m.BytesExtra) != 0 {
if bytesExtra := ParseBytesExtra(m.BytesExtra); bytesExtra != nil {
if _m.IsChatRoom {

View File

@@ -2,6 +2,7 @@ package model
import (
"bytes"
"fmt"
"strings"
"time"
@@ -31,6 +32,7 @@ import (
// )
type MessageV4 struct {
SortSeq int64 `json:"sort_seq"` // 消息序号10位时间戳 + 3位序号
ServerID int64 `json:"server_id"` // 消息 ID用于关联 voice
LocalType int64 `json:"local_type"` // 消息类型
UserName string `json:"user_name"` // 发送人,通过 Join Name2Id 表获得
CreateTime int64 `json:"create_time"` // 消息创建时间10位时间戳
@@ -74,6 +76,11 @@ func (m *MessageV4) Wrap(talker string) *Message {
_m.ParseMediaInfo(content)
// 语音消息
if _m.Type == 34 {
_m.Contents["voice"] = fmt.Sprint(m.ServerID)
}
if len(m.PackedInfoData) != 0 {
if packedInfo := ParsePackedInfo(m.PackedInfoData); packedInfo != nil {
// FIXME 尝试解决 v4 版本 xml 数据无法匹配到 hardlink 记录的问题