1. 支持转账、通话、链接消息的显示

2. 支持名片、视频号、QQ音乐、小程序、定位等消息的显示
3. 支持直播、游戏消息、语音通话、视频通话等消息的显示
4. 解密前判断对数据库是否有读权限
5. system消息html格式转文本
This commit is contained in:
HAL 2025-01-13 23:42:02 +08:00
parent f1a32a3f9a
commit c13e680b3d
18 changed files with 835 additions and 563 deletions

View File

@ -39,6 +39,16 @@ wails build
- [x] 支持链接消息 - [x] 支持链接消息
- [x] 支持语音消息 - [x] 支持语音消息
- [x] 支持文件消息 - [x] 支持文件消息
- [x] 支持名片消息
- [x] 支持定位消息
- [x] 支持视频/语音通话消息
- [x] 支持QQ音乐消息
- [x] 支持第三方视频软件分享消息
- [x] 支持分享表情集消息
- [x] 支持小程序消息
- [x] 支持视频号/直播消息
- [x] 支持转账消息
- [x] 支持腾讯游戏分享消息
- [x] 支持原始表情显示 - [x] 支持原始表情显示
- [x] 支持按类型检索 - [x] 支持按类型检索
- [x] 支持日期检索 - [x] 支持日期检索

2
app.go
View File

@ -23,7 +23,7 @@ const (
configDefaultUserKey = "userConfig.defaultUser" configDefaultUserKey = "userConfig.defaultUser"
configUsersKey = "userConfig.users" configUsersKey = "userConfig.users"
configExportPathKey = "exportPath" configExportPathKey = "exportPath"
appVersion = "v1.0.6" appVersion = "v1.1.0"
) )
type FileLoader struct { type FileLoader struct {

View File

@ -1,3 +1,15 @@
## v1.1.0
1. 支持转账、通话、链接消息的显示
2. 支持名片、视频号、QQ音乐、小程序、定位等消息的显示
3. 支持直播、游戏消息、语音通话、视频通话等消息的显示
4. 解密前判断对数据库是否有读权限
5. system消息html格式转文本
## v1.0.7
1. 修复出现空数据库时不显示,聊天显示不全的问题
2. 解决安卓平板扫码登陆的情况下解密失败的问题
3. 移除lame和silk代码改用mod的方式引入
## v1.0.6 ## v1.0.6
1. 图片/视频查看重新实现,保持与微信一致 1. 图片/视频查看重新实现,保持与微信一致
2. 增加软件信息页面 2. 增加软件信息页面

BIN
frontend/dist/assets/applet.ce6471b1.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

533
frontend/dist/assets/index.04e85ebe.js vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

BIN
frontend/dist/assets/map.b91d2cda.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

View File

@ -4,8 +4,8 @@
<meta charset="UTF-8"/> <meta charset="UTF-8"/>
<meta content="width=device-width, initial-scale=1.0" name="viewport"/> <meta content="width=device-width, initial-scale=1.0" name="viewport"/>
<title>wechatDataBackup</title> <title>wechatDataBackup</title>
<script type="module" crossorigin src="/assets/index.d5e97187.js"></script> <script type="module" crossorigin src="/assets/index.04e85ebe.js"></script>
<link rel="stylesheet" href="/assets/index.a11c4643.css"> <link rel="stylesheet" href="/assets/index.3ddb0aa4.css">
</head> </head>
<body > <body >
<div id="root"></div> <div id="root"></div>

2
go.mod
View File

@ -13,6 +13,7 @@ require (
github.com/shirou/gopsutil/v3 v3.24.2 github.com/shirou/gopsutil/v3 v3.24.2
github.com/spf13/viper v1.18.2 github.com/spf13/viper v1.18.2
github.com/wailsapp/wails/v2 v2.9.1 github.com/wailsapp/wails/v2 v2.9.1
golang.org/x/net v0.25.0
golang.org/x/sys v0.20.0 golang.org/x/sys v0.20.0
google.golang.org/protobuf v1.31.0 google.golang.org/protobuf v1.31.0
gopkg.in/natefinch/lumberjack.v2 v2.2.1 gopkg.in/natefinch/lumberjack.v2 v2.2.1
@ -62,7 +63,6 @@ require (
go.uber.org/multierr v1.9.0 // indirect go.uber.org/multierr v1.9.0 // indirect
golang.org/x/crypto v0.23.0 // indirect golang.org/x/crypto v0.23.0 // indirect
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect
golang.org/x/net v0.25.0 // indirect
golang.org/x/text v0.15.0 // indirect golang.org/x/text v0.15.0 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect

View File

@ -1,6 +1,8 @@
package utils package utils
import ( import (
"crypto/md5"
"encoding/hex"
"errors" "errors"
"fmt" "fmt"
"io" "io"
@ -8,10 +10,12 @@ import (
"os" "os"
"os/exec" "os/exec"
"path/filepath" "path/filepath"
"regexp"
"strings" "strings"
"github.com/pkg/browser" "github.com/pkg/browser"
"github.com/shirou/gopsutil/v3/disk" "github.com/shirou/gopsutil/v3/disk"
"golang.org/x/net/html"
"golang.org/x/sys/windows/registry" "golang.org/x/sys/windows/registry"
) )
@ -150,3 +154,79 @@ func CopyFile(src, dst string) (int64, error) {
return bytesWritten, nil return bytesWritten, nil
} }
func extractTextFromHTML(htmlStr string) string {
doc, err := html.Parse(strings.NewReader(htmlStr))
if err != nil {
fmt.Println("Error parsing HTML:", err)
return ""
}
var extractText func(*html.Node) string
extractText = func(n *html.Node) string {
if n.Type == html.TextNode {
return n.Data
}
var text string
for c := n.FirstChild; c != nil; c = c.NextSibling {
text += extractText(c)
}
return text
}
return extractText(doc)
}
func removeCustomTags(input string) string {
re := regexp.MustCompile(`<(_wc_custom_link_)[^>]*?>`)
return re.ReplaceAllString(input, `$2`)
}
func Html2Text(htmlStr string) string {
if htmlStr[0] != '<' {
return htmlStr
}
text := extractTextFromHTML(htmlStr)
if strings.Contains(text, `<_wc_custom_link_`) {
text = "\U0001F9E7" + removeCustomTags(text)
}
return text
}
func HtmlMsgGetAttr(htmlStr, tag string) map[string]string {
doc, err := html.Parse(strings.NewReader(htmlStr))
if err != nil {
fmt.Println("Error parsing HTML:", err)
return nil
}
var attributes map[string]string
var findAttributes func(*html.Node)
findAttributes = func(n *html.Node) {
if n.Type == html.ElementNode && n.Data == tag {
attributes = make(map[string]string)
for _, attr := range n.Attr {
attributes[attr.Key] = attr.Val
}
}
for c := n.FirstChild; c != nil; c = c.NextSibling {
findAttributes(c)
}
}
findAttributes(doc)
return attributes
}
func Hash256Sum(data []byte) string {
hash := md5.New()
hash.Write([]byte(data))
hashSum := hash.Sum(nil)
return hex.EncodeToString(hashSum)
}

View File

@ -697,6 +697,12 @@ func Is64BitProcess(pid uint32) (bool, error) {
} }
func GetWeChatKey(info *WeChatInfo) string { func GetWeChatKey(info *WeChatInfo) string {
mediaDB := info.FilePath + "\\Msg\\Media.db"
if _, err := os.Stat(mediaDB); err != nil {
log.Printf("open db %s error: %v", mediaDB, err)
return ""
}
handle, err := windows.OpenProcess(windows.PROCESS_QUERY_INFORMATION|windows.PROCESS_VM_READ, false, uint32(info.ProcessID)) handle, err := windows.OpenProcess(windows.PROCESS_QUERY_INFORMATION|windows.PROCESS_VM_READ, false, uint32(info.ProcessID))
if err != nil { if err != nil {
log.Println("Error opening process:", err) log.Println("Error opening process:", err)

View File

@ -13,6 +13,7 @@ import (
"strings" "strings"
sync "sync" sync "sync"
"time" "time"
"wechatDataBackup/pkg/utils"
"github.com/beevik/etree" "github.com/beevik/etree"
_ "github.com/mattn/go-sqlite3" _ "github.com/mattn/go-sqlite3"
@ -21,27 +22,36 @@ import (
) )
const ( const (
Wechat_Message_Type_Text = 1 Wechat_Message_Type_Text = 1
Wechat_Message_Type_Picture = 3 Wechat_Message_Type_Picture = 3
Wechat_Message_Type_Voice = 34 Wechat_Message_Type_Voice = 34
Wechat_Message_Type_Video = 43 Wechat_Message_Type_Visit_Card = 42
Wechat_Message_Type_Emoji = 47 Wechat_Message_Type_Video = 43
Wechat_Message_Type_Misc = 49 Wechat_Message_Type_Emoji = 47
Wechat_Message_Type_System = 10000 Wechat_Message_Type_Location = 48
Wechat_Message_Type_Misc = 49
Wechat_Message_Type_Voip = 50
Wechat_Message_Type_System = 10000
) )
const ( const (
Wechat_Misc_Message_TEXT = 1 Wechat_Misc_Message_TEXT = 1
Wechat_Misc_Message_Music = 3
Wechat_Misc_Message_ThirdVideo = 4
Wechat_Misc_Message_CardLink = 5 Wechat_Misc_Message_CardLink = 5
Wechat_Misc_Message_File = 6 Wechat_Misc_Message_File = 6
Wechat_Misc_Message_CustomEmoji = 8 Wechat_Misc_Message_CustomEmoji = 8
Wechat_Misc_Message_ShareEmoji = 15
Wechat_Misc_Message_ForwardMessage = 19 Wechat_Misc_Message_ForwardMessage = 19
Wechat_Misc_Message_Applet = 33 Wechat_Misc_Message_Applet = 33
Wechat_Misc_Message_Applet2 = 36 Wechat_Misc_Message_Applet2 = 36
Wechat_Misc_Message_Channels = 51
Wechat_Misc_Message_Refer = 57 Wechat_Misc_Message_Refer = 57
Wechat_Misc_Message_Live = 63 Wechat_Misc_Message_Live = 63
Wechat_Misc_Message_Game = 68
Wechat_Misc_Message_Notice = 87 Wechat_Misc_Message_Notice = 87
Wechat_Misc_Message_Live2 = 88 Wechat_Misc_Message_Live2 = 88
Wechat_Misc_Message_TingListen = 92
Wechat_Misc_Message_Transfer = 2000 Wechat_Misc_Message_Transfer = 2000
Wechat_Misc_Message_RedPacket = 2003 Wechat_Misc_Message_RedPacket = 2003
) )
@ -107,9 +117,43 @@ type ReferInfo struct {
Content string `json:"Content"` Content string `json:"Content"`
} }
type PayInfo struct {
Type int
Memo string
BeginTime string
Feedesc string
}
type VoipInfo struct {
Type int
Msg string
}
type ChannelsInfo struct {
ThumbPath string
ThumbCache string
NickName string
}
type MusicInfo struct {
ThumbPath string
Title string
Description string
DisPlayName string
DataUrl string
}
type LocationInfo struct {
Label string
PoiName string
X string
Y string
ThumbPath string
}
type WeChatMessage struct { type WeChatMessage struct {
LocalId int `json:"LocalId"` LocalId int `json:"LocalId"`
MsgSvrId int64 `json:"MsgSvrId"` MsgSvrId string `json:"MsgSvrId"`
Type int `json:"type"` Type int `json:"type"`
SubType int `json:"SubType"` SubType int `json:"SubType"`
IsSender int `json:"IsSender"` IsSender int `json:"IsSender"`
@ -126,6 +170,12 @@ type WeChatMessage struct {
UserInfo WeChatUserInfo `json:"userInfo"` UserInfo WeChatUserInfo `json:"userInfo"`
LinkInfo LinkInfo `json:"LinkInfo"` LinkInfo LinkInfo `json:"LinkInfo"`
ReferInfo ReferInfo `json:"ReferInfo"` ReferInfo ReferInfo `json:"ReferInfo"`
PayInfo PayInfo `json:"PayInfo"`
VoipInfo VoipInfo `json:"VoipInfo"`
VisitInfo WeChatUserInfo `json:"VisitInfo"`
ChannelsInfo ChannelsInfo `json:"ChannelsInfo"`
MusicInfo MusicInfo `json:"MusicInfo"`
LocationInfo LocationInfo `json:"LocationInfo"`
compressContent []byte compressContent []byte
bytesExtra []byte bytesExtra []byte
} }
@ -400,7 +450,7 @@ func (P *WechatDataProvider) WeChatGetSessionList(pageIndex int, pageSize int) (
List := &WeChatSessionList{} List := &WeChatSessionList{}
List.Rows = make([]WeChatSession, 0) List.Rows = make([]WeChatSession, 0)
querySql := fmt.Sprintf("select ifnull(strUsrName,'') as strUsrName,ifnull(strNickName,'') as strNickName,ifnull(strContent,'') as strContent, nTime from Session order by nOrder desc limit %d, %d;", pageIndex*pageSize, pageSize) querySql := fmt.Sprintf("select ifnull(strUsrName,'') as strUsrName,ifnull(strNickName,'') as strNickName,ifnull(strContent,'') as strContent, nMsgType, nTime from Session order by nOrder desc limit %d, %d;", pageIndex*pageSize, pageSize)
dbRows, err := P.microMsg.Query(querySql) dbRows, err := P.microMsg.Query(querySql)
if err != nil { if err != nil {
log.Println(err) log.Println(err)
@ -410,9 +460,10 @@ func (P *WechatDataProvider) WeChatGetSessionList(pageIndex int, pageSize int) (
var strUsrName, strNickName, strContent string var strUsrName, strNickName, strContent string
var nTime uint64 var nTime uint64
var nMsgType int
for dbRows.Next() { for dbRows.Next() {
var session WeChatSession var session WeChatSession
err = dbRows.Scan(&strUsrName, &strNickName, &strContent, &nTime) err = dbRows.Scan(&strUsrName, &strNickName, &strContent, &nMsgType, &nTime)
if err != nil { if err != nil {
log.Println(err) log.Println(err)
continue continue
@ -424,7 +475,7 @@ func (P *WechatDataProvider) WeChatGetSessionList(pageIndex int, pageSize int) (
session.UserName = strUsrName session.UserName = strUsrName
session.NickName = strNickName session.NickName = strNickName
session.Content = revokemsg_parse(strContent) session.Content = systemMsgParse(nMsgType, strContent)
session.Time = nTime session.Time = nTime
session.IsGroup = strings.HasSuffix(strUsrName, "@chatroom") session.IsGroup = strings.HasSuffix(strUsrName, "@chatroom")
info, err := P.WechatGetUserInfoByNameOnCache(strUsrName) info, err := P.WechatGetUserInfoByNameOnCache(strUsrName)
@ -555,14 +606,15 @@ func (P *WechatDataProvider) weChatGetMessageListByTime(userName string, time in
log.Println("rows.Scan failed", err) log.Println("rows.Scan failed", err)
return List, err return List, err
} }
message.LocalId = localId message.LocalId = localId
message.MsgSvrId = MsgSvrID message.MsgSvrId = fmt.Sprintf("%d", MsgSvrID)
message.Type = Type message.Type = Type
message.SubType = SubType message.SubType = SubType
message.IsSender = IsSender message.IsSender = IsSender
message.CreateTime = CreateTime message.CreateTime = CreateTime
message.Talker = StrTalker message.Talker = StrTalker
message.Content = revokemsg_parse(StrContent) message.Content = systemMsgParse(Type, StrContent)
message.IsChatRoom = strings.HasSuffix(StrTalker, "@chatroom") message.IsChatRoom = strings.HasSuffix(StrTalker, "@chatroom")
message.compressContent = make([]byte, len(CompressContent)) message.compressContent = make([]byte, len(CompressContent))
message.bytesExtra = make([]byte, len(BytesExtra)) message.bytesExtra = make([]byte, len(BytesExtra))
@ -572,6 +624,9 @@ func (P *WechatDataProvider) weChatGetMessageListByTime(userName string, time in
P.wechatMessageGetUserInfo(&message) P.wechatMessageGetUserInfo(&message)
P.wechatMessageEmojiHandle(&message) P.wechatMessageEmojiHandle(&message)
P.wechatMessageCompressContentHandle(&message) P.wechatMessageCompressContentHandle(&message)
P.wechatMessageVoipHandle(&message)
P.wechatMessageVisitHandke(&message)
P.wechatMessageLocationHandke(&message)
List.Rows = append(List.Rows, message) List.Rows = append(List.Rows, message)
List.Total += 1 List.Total += 1
} }
@ -805,8 +860,16 @@ func (P *WechatDataProvider) wechatMessageExtraHandle(msg *WeChatMessage) {
msg.UserInfo.UserName = ext.Field2 msg.UserInfo.UserName = ext.Field2
} }
case 3: case 3:
if len(ext.Field2) > 0 && (msg.Type == Wechat_Message_Type_Picture || msg.Type == Wechat_Message_Type_Video || msg.Type == Wechat_Message_Type_Misc) { if len(ext.Field2) > 0 {
msg.ThumbPath = P.prefixResPath + ext.Field2[len(P.SelfInfo.UserName):] if msg.Type == Wechat_Message_Type_Picture || msg.Type == Wechat_Message_Type_Video || msg.Type == Wechat_Message_Type_Misc {
msg.ThumbPath = P.prefixResPath + ext.Field2[len(P.SelfInfo.UserName):]
}
if msg.Type == Wechat_Message_Type_Misc && (msg.SubType == Wechat_Misc_Message_Music || msg.SubType == Wechat_Misc_Message_TingListen) {
msg.MusicInfo.ThumbPath = P.prefixResPath + ext.Field2[len(P.SelfInfo.UserName):]
} else if msg.Type == Wechat_Message_Type_Location {
msg.LocationInfo.ThumbPath = P.prefixResPath + ext.Field2[len(P.SelfInfo.UserName):]
}
} }
case 4: case 4:
if len(ext.Field2) > 0 { if len(ext.Field2) > 0 {
@ -822,7 +885,7 @@ func (P *WechatDataProvider) wechatMessageExtraHandle(msg *WeChatMessage) {
} }
if msg.Type == Wechat_Message_Type_Voice { if msg.Type == Wechat_Message_Type_Voice {
msg.VoicePath = fmt.Sprintf("%s\\FileStorage\\Voice\\%d.mp3", P.prefixResPath, msg.MsgSvrId) msg.VoicePath = fmt.Sprintf("%s\\FileStorage\\Voice\\%s.mp3", P.prefixResPath, msg.MsgSvrId)
} }
} }
@ -889,9 +952,8 @@ func (P *WechatDataProvider) wechatMessageCompressContentHandle(msg *WeChatMessa
log.Println("ReadFromBytes failed:", err) log.Println("ReadFromBytes failed:", err)
return return
} }
root := NewxmlDocument(compMsg) root := NewxmlDocument(compMsg)
if msg.Type == Wechat_Message_Type_Misc && msg.SubType == Wechat_Misc_Message_CardLink { if msg.Type == Wechat_Message_Type_Misc && isLinkSubType(msg.SubType) {
msg.LinkInfo.Title = root.FindElementValue("/msg/appmsg/title") msg.LinkInfo.Title = root.FindElementValue("/msg/appmsg/title")
msg.LinkInfo.Description = root.FindElementValue("/msg/appmsg/des") msg.LinkInfo.Description = root.FindElementValue("/msg/appmsg/des")
msg.LinkInfo.Url = root.FindElementValue("/msg/appmsg/url") msg.LinkInfo.Url = root.FindElementValue("/msg/appmsg/url")
@ -900,6 +962,10 @@ func (P *WechatDataProvider) wechatMessageCompressContentHandle(msg *WeChatMessa
if len(msg.LinkInfo.DisPlayName) == 0 && len(appName) > 0 { if len(msg.LinkInfo.DisPlayName) == 0 && len(appName) > 0 {
msg.LinkInfo.DisPlayName = appName msg.LinkInfo.DisPlayName = appName
} }
thumburl := root.FindElementValue("/msg/appmsg/thumburl")
if len(msg.ThumbPath) == 0 && len(thumburl) > 0 && strings.HasPrefix(thumburl, "http") {
msg.ThumbPath = thumburl
}
} else if msg.Type == Wechat_Message_Type_Misc && msg.SubType == Wechat_Misc_Message_Refer { } else if msg.Type == Wechat_Message_Type_Misc && msg.SubType == Wechat_Misc_Message_Refer {
msg.Content = root.FindElementValue("/msg/appmsg/title") msg.Content = root.FindElementValue("/msg/appmsg/title")
msg.ReferInfo.Type, _ = strconv.Atoi(root.FindElementValue("/msg/appmsg/refermsg/type")) msg.ReferInfo.Type, _ = strconv.Atoi(root.FindElementValue("/msg/appmsg/refermsg/type"))
@ -918,9 +984,80 @@ func (P *WechatDataProvider) wechatMessageCompressContentHandle(msg *WeChatMessa
msg.ReferInfo.Content = root.FindElementValue("/msg/appmsg/title") msg.ReferInfo.Content = root.FindElementValue("/msg/appmsg/title")
msg.ReferInfo.SubType, _ = strconv.Atoi(root.FindElementValue("/msg/appmsg/type")) msg.ReferInfo.SubType, _ = strconv.Atoi(root.FindElementValue("/msg/appmsg/type"))
} }
} else if msg.Type == Wechat_Message_Type_Misc && msg.SubType == Wechat_Misc_Message_Transfer {
msg.PayInfo.Type, _ = strconv.Atoi(root.FindElementValue("/msg/appmsg/wcpayinfo/paysubtype"))
msg.PayInfo.Feedesc = root.FindElementValue("/msg/appmsg/wcpayinfo/feedesc")
msg.PayInfo.BeginTime = root.FindElementValue("/msg/appmsg/wcpayinfo/begintransfertime")
msg.PayInfo.Memo = root.FindElementValue("/msg/appmsg/wcpayinfo/pay_memo")
} else if msg.Type == Wechat_Message_Type_Misc && msg.SubType == Wechat_Misc_Message_TEXT {
msg.Content = root.FindElementValue("/msg/appmsg/title")
} else if msg.Type == Wechat_Message_Type_Misc && msg.SubType == Wechat_Misc_Message_Channels {
msg.ChannelsInfo.NickName = root.FindElementValue("/msg/appmsg/finderFeed/nickname")
msg.ChannelsInfo.ThumbPath = root.FindElementValue("/msg/appmsg/finderFeed/mediaList/media/thumbUrl")
msg.ChannelsInfo.ThumbPath = P.urlconvertCacheName(msg.ChannelsInfo.ThumbPath, msg.CreateTime)
} else if msg.Type == Wechat_Message_Type_Misc && msg.SubType == Wechat_Misc_Message_Live {
msg.ChannelsInfo.NickName = root.FindElementValue("/msg/appmsg/finderLive/nickname")
msg.ChannelsInfo.ThumbPath = root.FindElementValue("/msg/appmsg/finderLive/media/coverUrl")
msg.ChannelsInfo.ThumbPath = P.urlconvertCacheName(msg.ChannelsInfo.ThumbPath, msg.CreateTime)
} else if msg.Type == Wechat_Message_Type_Misc && (msg.SubType == Wechat_Misc_Message_Music || msg.SubType == Wechat_Misc_Message_TingListen) {
msg.MusicInfo.Title = root.FindElementValue("/msg/appmsg/title")
msg.MusicInfo.Description = root.FindElementValue("/msg/appmsg/des")
msg.MusicInfo.DataUrl = root.FindElementValue("/msg/appmsg/dataurl")
msg.MusicInfo.DisPlayName = root.FindElementValue("/msg/appinfo/appname")
} }
} }
func (P *WechatDataProvider) wechatMessageVoipHandle(msg *WeChatMessage) {
if msg.Type != Wechat_Message_Type_Voip {
return
}
xmlMsg := etree.NewDocument()
if err := xmlMsg.ReadFromBytes([]byte(msg.Content)); err != nil {
// os.WriteFile("D:\\tmp\\"+string(msg.LocalId)+".xml", unCompressContent[:ulen], 0600)
log.Println("ReadFromBytes failed:", err)
return
}
root := NewxmlDocument(xmlMsg)
msg.VoipInfo.Type, _ = strconv.Atoi(root.FindElementValue("/voipmsg/VoIPBubbleMsg/room_type"))
msg.VoipInfo.Msg = root.FindElementValue("/voipmsg/VoIPBubbleMsg/msg")
}
func (P *WechatDataProvider) wechatMessageVisitHandke(msg *WeChatMessage) {
if msg.Type != Wechat_Message_Type_Visit_Card {
return
}
attr := utils.HtmlMsgGetAttr(msg.Content, "msg")
userName, exists := attr["username"]
if !exists {
return
}
userInfo, err := P.WechatGetUserInfoByNameOnCache(userName)
if err == nil {
msg.VisitInfo = *userInfo
} else {
msg.VisitInfo.UserName = userName
msg.VisitInfo.Alias = attr["alias"]
msg.VisitInfo.NickName = attr["nickname"]
msg.VisitInfo.SmallHeadImgUrl = attr["smallheadimgurl"]
msg.VisitInfo.BigHeadImgUrl = attr["bigheadimgurl"]
}
}
func (P *WechatDataProvider) wechatMessageLocationHandke(msg *WeChatMessage) {
if msg.Type != Wechat_Message_Type_Location {
return
}
attr := utils.HtmlMsgGetAttr(msg.Content, "location")
msg.LocationInfo.Label = attr["label"]
msg.LocationInfo.PoiName = attr["poiname"]
msg.LocationInfo.X = attr["x"]
msg.LocationInfo.Y = attr["y"]
}
func (P *WechatDataProvider) wechatMessageGetUserInfo(msg *WeChatMessage) { func (P *WechatDataProvider) wechatMessageGetUserInfo(msg *WeChatMessage) {
who := msg.Talker who := msg.Talker
if msg.IsSender == 1 { if msg.IsSender == 1 {
@ -1031,9 +1168,11 @@ func weChatMessageContains(msg *WeChatMessage, chars string) bool {
switch msg.Type { switch msg.Type {
case Wechat_Message_Type_Text: case Wechat_Message_Type_Text:
return strings.Contains(msg.Content, chars) return strings.Contains(msg.Content, chars)
case Wechat_Message_Type_Location:
return strings.Contains(msg.LocationInfo.Label, chars) || strings.Contains(msg.LocationInfo.PoiName, chars)
case Wechat_Message_Type_Misc: case Wechat_Message_Type_Misc:
switch msg.SubType { switch msg.SubType {
case Wechat_Misc_Message_CardLink: case Wechat_Misc_Message_CardLink, Wechat_Misc_Message_ThirdVideo, Wechat_Misc_Message_Applet, Wechat_Misc_Message_Applet2:
return strings.Contains(msg.LinkInfo.Title, chars) || strings.Contains(msg.LinkInfo.Description, chars) return strings.Contains(msg.LinkInfo.Title, chars) || strings.Contains(msg.LinkInfo.Description, chars)
case Wechat_Misc_Message_Refer: case Wechat_Misc_Message_Refer:
return strings.Contains(msg.Content, chars) return strings.Contains(msg.Content, chars)
@ -1056,7 +1195,7 @@ func weChatMessageTypeFilter(msg *WeChatMessage, msgType string) bool {
case "图片与视频": case "图片与视频":
return msg.Type == Wechat_Message_Type_Picture || msg.Type == Wechat_Message_Type_Video return msg.Type == Wechat_Message_Type_Picture || msg.Type == Wechat_Message_Type_Video
case "链接": case "链接":
return msg.Type == Wechat_Misc_Message_CardLink || msg.SubType == Wechat_Misc_Message_CardLink return msg.Type == Wechat_Message_Type_Misc && (msg.SubType == Wechat_Misc_Message_CardLink || msg.SubType == Wechat_Misc_Message_ThirdVideo)
default: default:
if strings.HasPrefix(msgType, "群成员") { if strings.HasPrefix(msgType, "群成员") {
userName := msgType[len("群成员"):] userName := msgType[len("群成员"):]
@ -1219,11 +1358,36 @@ func WechatGetAccountInfo(resPath, prefixRes, accountName string) (*WeChatAccoun
return info, nil return info, nil
} }
func revokemsg_parse(content string) string { func systemMsgParse(msgType int, content string) string {
if strings.HasPrefix(content, "<revokemsg>") && strings.HasSuffix(content, "</revokemsg>") { if msgType != Wechat_Message_Type_System {
trimmed := strings.TrimSuffix(strings.TrimPrefix(content, "<revokemsg>"), "</revokemsg>") return content
return trimmed
} }
return content return utils.Html2Text(content)
}
func (P *WechatDataProvider) urlconvertCacheName(url string, timestamp int64) string {
t := time.Unix(timestamp, 0)
yearMonth := t.Format("2006-01")
md5String := utils.Hash256Sum([]byte(url))
realPath := fmt.Sprintf("%s\\FileStorage\\Cache\\%s\\%s.jpg", P.resPath, yearMonth, md5String)
path := fmt.Sprintf("%s\\FileStorage\\Cache\\%s\\%s.jpg", P.prefixResPath, yearMonth, md5String)
if _, err := os.Stat(realPath); err == nil {
return path
}
return url
}
func isLinkSubType(subType int) bool {
targetSubTypes := map[int]bool{
Wechat_Misc_Message_CardLink: true,
Wechat_Misc_Message_ThirdVideo: true,
Wechat_Misc_Message_ShareEmoji: true,
Wechat_Misc_Message_Applet: true,
Wechat_Misc_Message_Applet2: true,
Wechat_Misc_Message_Game: true,
}
return targetSubTypes[subType]
} }