1. 支持转账、通话、链接消息的显示
2. 支持名片、视频号、QQ音乐、小程序、定位等消息的显示 3. 支持直播、游戏消息、语音通话、视频通话等消息的显示 4. 解密前判断对数据库是否有读权限 5. system消息html格式转文本
This commit is contained in:
parent
f1a32a3f9a
commit
c13e680b3d
10
README.md
10
README.md
@ -39,6 +39,16 @@ wails build
|
||||
- [x] 支持链接消息
|
||||
- [x] 支持语音消息
|
||||
- [x] 支持文件消息
|
||||
- [x] 支持名片消息
|
||||
- [x] 支持定位消息
|
||||
- [x] 支持视频/语音通话消息
|
||||
- [x] 支持QQ音乐消息
|
||||
- [x] 支持第三方视频软件分享消息
|
||||
- [x] 支持分享表情集消息
|
||||
- [x] 支持小程序消息
|
||||
- [x] 支持视频号/直播消息
|
||||
- [x] 支持转账消息
|
||||
- [x] 支持腾讯游戏分享消息
|
||||
- [x] 支持原始表情显示
|
||||
- [x] 支持按类型检索
|
||||
- [x] 支持日期检索
|
||||
|
2
app.go
2
app.go
@ -23,7 +23,7 @@ const (
|
||||
configDefaultUserKey = "userConfig.defaultUser"
|
||||
configUsersKey = "userConfig.users"
|
||||
configExportPathKey = "exportPath"
|
||||
appVersion = "v1.0.6"
|
||||
appVersion = "v1.1.0"
|
||||
)
|
||||
|
||||
type FileLoader struct {
|
||||
|
12
changelog.md
12
changelog.md
@ -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
|
||||
1. 图片/视频查看重新实现,保持与微信一致
|
||||
2. 增加软件信息页面
|
||||
|
BIN
frontend/dist/assets/applet.ce6471b1.png
vendored
Normal file
BIN
frontend/dist/assets/applet.ce6471b1.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 7.0 KiB |
BIN
frontend/dist/assets/channels.33204285.png
vendored
Normal file
BIN
frontend/dist/assets/channels.33204285.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 8.7 KiB |
BIN
frontend/dist/assets/channels_error.1d149df5.png
vendored
Normal file
BIN
frontend/dist/assets/channels_error.1d149df5.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.6 KiB |
533
frontend/dist/assets/index.04e85ebe.js
vendored
Normal file
533
frontend/dist/assets/index.04e85ebe.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
frontend/dist/assets/index.3ddb0aa4.css
vendored
Normal file
1
frontend/dist/assets/index.3ddb0aa4.css
vendored
Normal file
File diff suppressed because one or more lines are too long
1
frontend/dist/assets/index.a11c4643.css
vendored
1
frontend/dist/assets/index.a11c4643.css
vendored
File diff suppressed because one or more lines are too long
533
frontend/dist/assets/index.d5e97187.js
vendored
533
frontend/dist/assets/index.d5e97187.js
vendored
File diff suppressed because one or more lines are too long
BIN
frontend/dist/assets/map.b91d2cda.png
vendored
Normal file
BIN
frontend/dist/assets/map.b91d2cda.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 16 KiB |
BIN
frontend/dist/assets/music_note.02e237d9.png
vendored
Normal file
BIN
frontend/dist/assets/music_note.02e237d9.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 7.1 KiB |
BIN
frontend/dist/assets/qq_music.b548e6a1.png
vendored
Normal file
BIN
frontend/dist/assets/qq_music.b548e6a1.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 7.0 KiB |
4
frontend/dist/index.html
vendored
4
frontend/dist/index.html
vendored
@ -4,8 +4,8 @@
|
||||
<meta charset="UTF-8"/>
|
||||
<meta content="width=device-width, initial-scale=1.0" name="viewport"/>
|
||||
<title>wechatDataBackup</title>
|
||||
<script type="module" crossorigin src="/assets/index.d5e97187.js"></script>
|
||||
<link rel="stylesheet" href="/assets/index.a11c4643.css">
|
||||
<script type="module" crossorigin src="/assets/index.04e85ebe.js"></script>
|
||||
<link rel="stylesheet" href="/assets/index.3ddb0aa4.css">
|
||||
</head>
|
||||
<body >
|
||||
<div id="root"></div>
|
||||
|
2
go.mod
2
go.mod
@ -13,6 +13,7 @@ require (
|
||||
github.com/shirou/gopsutil/v3 v3.24.2
|
||||
github.com/spf13/viper v1.18.2
|
||||
github.com/wailsapp/wails/v2 v2.9.1
|
||||
golang.org/x/net v0.25.0
|
||||
golang.org/x/sys v0.20.0
|
||||
google.golang.org/protobuf v1.31.0
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.2.1
|
||||
@ -62,7 +63,6 @@ require (
|
||||
go.uber.org/multierr v1.9.0 // indirect
|
||||
golang.org/x/crypto v0.23.0 // 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
|
||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
|
@ -1,6 +1,8 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
@ -8,10 +10,12 @@ import (
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/pkg/browser"
|
||||
"github.com/shirou/gopsutil/v3/disk"
|
||||
"golang.org/x/net/html"
|
||||
"golang.org/x/sys/windows/registry"
|
||||
)
|
||||
|
||||
@ -150,3 +154,79 @@ func CopyFile(src, dst string) (int64, error) {
|
||||
|
||||
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)
|
||||
}
|
||||
|
@ -697,6 +697,12 @@ func Is64BitProcess(pid uint32) (bool, error) {
|
||||
}
|
||||
|
||||
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))
|
||||
if err != nil {
|
||||
log.Println("Error opening process:", err)
|
||||
|
@ -13,6 +13,7 @@ import (
|
||||
"strings"
|
||||
sync "sync"
|
||||
"time"
|
||||
"wechatDataBackup/pkg/utils"
|
||||
|
||||
"github.com/beevik/etree"
|
||||
_ "github.com/mattn/go-sqlite3"
|
||||
@ -21,27 +22,36 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
Wechat_Message_Type_Text = 1
|
||||
Wechat_Message_Type_Picture = 3
|
||||
Wechat_Message_Type_Voice = 34
|
||||
Wechat_Message_Type_Video = 43
|
||||
Wechat_Message_Type_Emoji = 47
|
||||
Wechat_Message_Type_Misc = 49
|
||||
Wechat_Message_Type_System = 10000
|
||||
Wechat_Message_Type_Text = 1
|
||||
Wechat_Message_Type_Picture = 3
|
||||
Wechat_Message_Type_Voice = 34
|
||||
Wechat_Message_Type_Visit_Card = 42
|
||||
Wechat_Message_Type_Video = 43
|
||||
Wechat_Message_Type_Emoji = 47
|
||||
Wechat_Message_Type_Location = 48
|
||||
Wechat_Message_Type_Misc = 49
|
||||
Wechat_Message_Type_Voip = 50
|
||||
Wechat_Message_Type_System = 10000
|
||||
)
|
||||
|
||||
const (
|
||||
Wechat_Misc_Message_TEXT = 1
|
||||
Wechat_Misc_Message_Music = 3
|
||||
Wechat_Misc_Message_ThirdVideo = 4
|
||||
Wechat_Misc_Message_CardLink = 5
|
||||
Wechat_Misc_Message_File = 6
|
||||
Wechat_Misc_Message_CustomEmoji = 8
|
||||
Wechat_Misc_Message_ShareEmoji = 15
|
||||
Wechat_Misc_Message_ForwardMessage = 19
|
||||
Wechat_Misc_Message_Applet = 33
|
||||
Wechat_Misc_Message_Applet2 = 36
|
||||
Wechat_Misc_Message_Channels = 51
|
||||
Wechat_Misc_Message_Refer = 57
|
||||
Wechat_Misc_Message_Live = 63
|
||||
Wechat_Misc_Message_Game = 68
|
||||
Wechat_Misc_Message_Notice = 87
|
||||
Wechat_Misc_Message_Live2 = 88
|
||||
Wechat_Misc_Message_TingListen = 92
|
||||
Wechat_Misc_Message_Transfer = 2000
|
||||
Wechat_Misc_Message_RedPacket = 2003
|
||||
)
|
||||
@ -107,9 +117,43 @@ type ReferInfo struct {
|
||||
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 {
|
||||
LocalId int `json:"LocalId"`
|
||||
MsgSvrId int64 `json:"MsgSvrId"`
|
||||
MsgSvrId string `json:"MsgSvrId"`
|
||||
Type int `json:"type"`
|
||||
SubType int `json:"SubType"`
|
||||
IsSender int `json:"IsSender"`
|
||||
@ -126,6 +170,12 @@ type WeChatMessage struct {
|
||||
UserInfo WeChatUserInfo `json:"userInfo"`
|
||||
LinkInfo LinkInfo `json:"LinkInfo"`
|
||||
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
|
||||
bytesExtra []byte
|
||||
}
|
||||
@ -400,7 +450,7 @@ func (P *WechatDataProvider) WeChatGetSessionList(pageIndex int, pageSize int) (
|
||||
List := &WeChatSessionList{}
|
||||
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)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
@ -410,9 +460,10 @@ func (P *WechatDataProvider) WeChatGetSessionList(pageIndex int, pageSize int) (
|
||||
|
||||
var strUsrName, strNickName, strContent string
|
||||
var nTime uint64
|
||||
var nMsgType int
|
||||
for dbRows.Next() {
|
||||
var session WeChatSession
|
||||
err = dbRows.Scan(&strUsrName, &strNickName, &strContent, &nTime)
|
||||
err = dbRows.Scan(&strUsrName, &strNickName, &strContent, &nMsgType, &nTime)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
continue
|
||||
@ -424,7 +475,7 @@ func (P *WechatDataProvider) WeChatGetSessionList(pageIndex int, pageSize int) (
|
||||
|
||||
session.UserName = strUsrName
|
||||
session.NickName = strNickName
|
||||
session.Content = revokemsg_parse(strContent)
|
||||
session.Content = systemMsgParse(nMsgType, strContent)
|
||||
session.Time = nTime
|
||||
session.IsGroup = strings.HasSuffix(strUsrName, "@chatroom")
|
||||
info, err := P.WechatGetUserInfoByNameOnCache(strUsrName)
|
||||
@ -555,14 +606,15 @@ func (P *WechatDataProvider) weChatGetMessageListByTime(userName string, time in
|
||||
log.Println("rows.Scan failed", err)
|
||||
return List, err
|
||||
}
|
||||
|
||||
message.LocalId = localId
|
||||
message.MsgSvrId = MsgSvrID
|
||||
message.MsgSvrId = fmt.Sprintf("%d", MsgSvrID)
|
||||
message.Type = Type
|
||||
message.SubType = SubType
|
||||
message.IsSender = IsSender
|
||||
message.CreateTime = CreateTime
|
||||
message.Talker = StrTalker
|
||||
message.Content = revokemsg_parse(StrContent)
|
||||
message.Content = systemMsgParse(Type, StrContent)
|
||||
message.IsChatRoom = strings.HasSuffix(StrTalker, "@chatroom")
|
||||
message.compressContent = make([]byte, len(CompressContent))
|
||||
message.bytesExtra = make([]byte, len(BytesExtra))
|
||||
@ -572,6 +624,9 @@ func (P *WechatDataProvider) weChatGetMessageListByTime(userName string, time in
|
||||
P.wechatMessageGetUserInfo(&message)
|
||||
P.wechatMessageEmojiHandle(&message)
|
||||
P.wechatMessageCompressContentHandle(&message)
|
||||
P.wechatMessageVoipHandle(&message)
|
||||
P.wechatMessageVisitHandke(&message)
|
||||
P.wechatMessageLocationHandke(&message)
|
||||
List.Rows = append(List.Rows, message)
|
||||
List.Total += 1
|
||||
}
|
||||
@ -805,8 +860,16 @@ func (P *WechatDataProvider) wechatMessageExtraHandle(msg *WeChatMessage) {
|
||||
msg.UserInfo.UserName = ext.Field2
|
||||
}
|
||||
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) {
|
||||
msg.ThumbPath = P.prefixResPath + ext.Field2[len(P.SelfInfo.UserName):]
|
||||
if len(ext.Field2) > 0 {
|
||||
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:
|
||||
if len(ext.Field2) > 0 {
|
||||
@ -822,7 +885,7 @@ func (P *WechatDataProvider) wechatMessageExtraHandle(msg *WeChatMessage) {
|
||||
}
|
||||
|
||||
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)
|
||||
return
|
||||
}
|
||||
|
||||
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.Description = root.FindElementValue("/msg/appmsg/des")
|
||||
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 {
|
||||
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 {
|
||||
msg.Content = root.FindElementValue("/msg/appmsg/title")
|
||||
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.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) {
|
||||
who := msg.Talker
|
||||
if msg.IsSender == 1 {
|
||||
@ -1031,9 +1168,11 @@ func weChatMessageContains(msg *WeChatMessage, chars string) bool {
|
||||
switch msg.Type {
|
||||
case Wechat_Message_Type_Text:
|
||||
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:
|
||||
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)
|
||||
case Wechat_Misc_Message_Refer:
|
||||
return strings.Contains(msg.Content, chars)
|
||||
@ -1056,7 +1195,7 @@ func weChatMessageTypeFilter(msg *WeChatMessage, msgType string) bool {
|
||||
case "图片与视频":
|
||||
return msg.Type == Wechat_Message_Type_Picture || msg.Type == Wechat_Message_Type_Video
|
||||
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:
|
||||
if strings.HasPrefix(msgType, "群成员") {
|
||||
userName := msgType[len("群成员"):]
|
||||
@ -1219,11 +1358,36 @@ func WechatGetAccountInfo(resPath, prefixRes, accountName string) (*WeChatAccoun
|
||||
return info, nil
|
||||
}
|
||||
|
||||
func revokemsg_parse(content string) string {
|
||||
if strings.HasPrefix(content, "<revokemsg>") && strings.HasSuffix(content, "</revokemsg>") {
|
||||
trimmed := strings.TrimSuffix(strings.TrimPrefix(content, "<revokemsg>"), "</revokemsg>")
|
||||
return trimmed
|
||||
func systemMsgParse(msgType int, content string) string {
|
||||
if msgType != Wechat_Message_Type_System {
|
||||
return content
|
||||
}
|
||||
|
||||
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]
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user