fix: 修复图片无法获取问题

This commit is contained in:
yaoluxing 2025-07-17 12:46:45 +08:00
parent 10287819b3
commit cc8e4abf60
7 changed files with 210 additions and 15 deletions

View File

@ -1,6 +1,11 @@
package model
import (
"crypto/md5"
"encoding/hex"
"fmt"
"os"
"path/filepath"
"strings"
"time"
)
@ -29,7 +34,7 @@ type MessageDarwinV3 struct {
MesDes int `json:"mesDes"` // 0: 发送, 1: 接收
}
func (m *MessageDarwinV3) Wrap(talker string) *Message {
func (m *MessageDarwinV3) Wrap(talker string, dataDir string) *Message {
_m := &Message{
Time: time.Unix(m.MsgCreateTime, 0),
@ -38,6 +43,7 @@ func (m *MessageDarwinV3) Wrap(talker string) *Message {
IsChatRoom: strings.HasSuffix(talker, "@chatroom"),
IsSelf: m.MesDes == 0,
Version: WeChatDarwinV3,
Contents: make(map[string]interface{}),
}
content := m.MsgContent
@ -53,5 +59,65 @@ func (m *MessageDarwinV3) Wrap(talker string) *Message {
_m.ParseMediaInfo(content)
// 图片消息
if _m.Type == 3 && dataDir != "" {
// 计算talker的MD5
talkerMD5 := md5.Sum([]byte(talker))
talkerMD5Str := hex.EncodeToString(talkerMD5[:])
// 将消息时间转换成秒
timeStr := fmt.Sprintf("%d", m.MsgCreateTime)
// 构建搜索目录
searchDir := filepath.Join(dataDir, "Message", "MessageTemp", talkerMD5Str, "Image")
// 按优先级查找图片文件
patterns := []string{
fmt.Sprintf("%s_.pic.jpg", timeStr),
fmt.Sprintf("%s_.pic_hd.jpg", timeStr),
fmt.Sprintf("%s_.pic_thumb.jpg", timeStr),
}
for _, pattern := range patterns {
if entries, err := os.ReadDir(searchDir); err == nil {
for _, entry := range entries {
if !entry.IsDir() && strings.HasSuffix(entry.Name(), pattern) {
// 找到文件,设置相对路径
_m.Contents["imgfile"] = filepath.Join("/Message/MessageTemp", talkerMD5Str, "Image", entry.Name())
break
}
}
if _, exists := _m.Contents["imgfile"]; exists {
break // 找到文件就退出
}
}
}
}
// 视频消息
if _m.Type == 43 && dataDir != "" {
// 计算talker的MD5
talkerMD5 := md5.Sum([]byte(talker))
talkerMD5Str := hex.EncodeToString(talkerMD5[:])
// 将消息时间转换成秒
timeStr := fmt.Sprintf("%d", m.MsgCreateTime)
// 构建搜索目录
searchDir := filepath.Join(dataDir, "Message", "MessageTemp", talkerMD5Str, "Video")
// 查找视频文件
videoPattern := fmt.Sprintf("%s.mp4", timeStr)
if entries, err := os.ReadDir(searchDir); err == nil {
for _, entry := range entries {
if !entry.IsDir() && strings.HasSuffix(entry.Name(), videoPattern) {
// 找到文件,设置相对路径
_m.Contents["videofile"] = filepath.Join("/Message/MessageTemp", talkerMD5Str, "Video", entry.Name())
break
}
}
}
}
return _m
}

View File

@ -1,7 +1,10 @@
package model
import (
"crypto/md5"
"encoding/hex"
"fmt"
"os"
"path/filepath"
"strings"
"time"
@ -52,7 +55,7 @@ type MessageV3 struct {
BytesExtra []byte `json:"BytesExtra"` // protobuf 额外数据,记录群聊发送人等信息
}
func (m *MessageV3) Wrap() *Message {
func (m *MessageV3) Wrap(dataDir string) *Message {
_m := &Message{
Seq: m.Sequence,
@ -64,6 +67,7 @@ func (m *MessageV3) Wrap() *Message {
SubType: int64(m.SubType),
Content: m.StrContent,
Version: WeChatV3,
Contents: make(map[string]interface{}),
}
if !_m.IsChatRoom && !_m.IsSelf {
@ -79,6 +83,66 @@ func (m *MessageV3) Wrap() *Message {
_m.ParseMediaInfo(_m.Content)
// 图片消息
if _m.Type == 3 && dataDir != "" {
// 计算talker的MD5
talkerMD5 := md5.Sum([]byte(m.StrTalker))
talkerMD5Str := hex.EncodeToString(talkerMD5[:])
// 将消息时间转换成秒
timeStr := fmt.Sprintf("%d", m.CreateTime)
// 构建搜索目录
searchDir := filepath.Join(dataDir, "Message", "MessageTemp", talkerMD5Str, "Image")
// 按优先级查找图片文件
patterns := []string{
fmt.Sprintf("%s_.pic.jpg", timeStr),
fmt.Sprintf("%s_.pic_hd.jpg", timeStr),
fmt.Sprintf("%s_.pic_thumb.jpg", timeStr),
}
for _, pattern := range patterns {
if entries, err := os.ReadDir(searchDir); err == nil {
for _, entry := range entries {
if !entry.IsDir() && strings.HasSuffix(entry.Name(), pattern) {
// 找到文件,设置相对路径
_m.Contents["imgfile"] = filepath.Join("/Message/MessageTemp", talkerMD5Str, "Image", entry.Name())
break
}
}
if _, exists := _m.Contents["imgfile"]; exists {
break // 找到文件就退出
}
}
}
}
// 视频消息
if _m.Type == 43 && dataDir != "" {
// 计算talker的MD5
talkerMD5 := md5.Sum([]byte(m.StrTalker))
talkerMD5Str := hex.EncodeToString(talkerMD5[:])
// 将消息时间转换成秒
timeStr := fmt.Sprintf("%d", m.CreateTime)
// 构建搜索目录
searchDir := filepath.Join(dataDir, "Message", "MessageTemp", talkerMD5Str, "Video")
// 查找视频文件
videoPattern := fmt.Sprintf("%s.mp4", timeStr)
if entries, err := os.ReadDir(searchDir); err == nil {
for _, entry := range entries {
if !entry.IsDir() && strings.HasSuffix(entry.Name(), videoPattern) {
// 找到文件,设置相对路径
_m.Contents["videofile"] = filepath.Join("/Message/MessageTemp", talkerMD5Str, "Video", entry.Name())
break
}
}
}
}
// 语音消息
if _m.Type == 34 {
_m.Contents["voice"] = fmt.Sprint(m.MsgSvrID)

View File

@ -5,6 +5,7 @@ import (
"crypto/md5"
"encoding/hex"
"fmt"
"os"
"path/filepath"
"strings"
"time"
@ -45,7 +46,7 @@ type MessageV4 struct {
Status int `json:"status"` // 消息状态2 是已发送4 是已接收,可以用于判断 IsSenderFIXME 不准, 需要判断 UserName
}
func (m *MessageV4) Wrap(talker string) *Message {
func (m *MessageV4) Wrap(talker string, dataDir string) *Message {
_m := &Message{
Seq: m.SortSeq,
@ -80,6 +81,66 @@ func (m *MessageV4) Wrap(talker string) *Message {
_m.ParseMediaInfo(content)
// 图片消息
if _m.Type == 3 && dataDir != "" {
// 计算talker的MD5
talkerMD5 := md5.Sum([]byte(talker))
talkerMD5Str := hex.EncodeToString(talkerMD5[:])
// 将消息时间转换成秒
timeStr := fmt.Sprintf("%d", m.CreateTime)
// 构建搜索目录
searchDir := filepath.Join(dataDir, "Message", "MessageTemp", talkerMD5Str, "Image")
// 按优先级查找图片文件
patterns := []string{
fmt.Sprintf("%s_.pic.jpg", timeStr),
fmt.Sprintf("%s_.pic_hd.jpg", timeStr),
fmt.Sprintf("%s_.pic_thumb.jpg", timeStr),
}
for _, pattern := range patterns {
if entries, err := os.ReadDir(searchDir); err == nil {
for _, entry := range entries {
if !entry.IsDir() && strings.HasSuffix(entry.Name(), pattern) {
// 找到文件,设置相对路径
_m.Contents["imgfile"] = filepath.Join("/Message/MessageTemp", talkerMD5Str, "Image", entry.Name())
break
}
}
if _, exists := _m.Contents["imgfile"]; exists {
break // 找到文件就退出
}
}
}
}
// 视频消息
if _m.Type == 43 && dataDir != "" {
// 计算talker的MD5
talkerMD5 := md5.Sum([]byte(talker))
talkerMD5Str := hex.EncodeToString(talkerMD5[:])
// 将消息时间转换成秒
timeStr := fmt.Sprintf("%d", m.CreateTime)
// 构建搜索目录
searchDir := filepath.Join(dataDir, "Message", "MessageTemp", talkerMD5Str, "Video")
// 查找视频文件
videoPattern := fmt.Sprintf("%s.mp4", timeStr)
if entries, err := os.ReadDir(searchDir); err == nil {
for _, entry := range entries {
if !entry.IsDir() && strings.HasSuffix(entry.Name(), videoPattern) {
// 找到文件,设置相对路径
_m.Contents["videofile"] = filepath.Join("/Message/MessageTemp", talkerMD5Str, "Video", entry.Name())
break
}
}
}
}
// 语音消息
if _m.Type == 34 {
_m.Contents["voice"] = fmt.Sprint(m.ServerID)

View File

@ -57,16 +57,18 @@ var Groups = []*dbm.Group{
}
type DataSource struct {
path string
dbm *dbm.DBManager
path string
dataDir string
dbm *dbm.DBManager
talkerDBMap map[string]string
user2DisplayName map[string]string
}
func New(path string) (*DataSource, error) {
func New(path string, dataDir string) (*DataSource, error) {
ds := &DataSource{
path: path,
dataDir: dataDir,
dbm: dbm.NewDBManager(path),
talkerDBMap: make(map[string]string),
user2DisplayName: make(map[string]string),
@ -277,7 +279,7 @@ func (ds *DataSource) GetMessages(ctx context.Context, startTime, endTime time.T
}
// 将消息包装为通用模型
message := msg.Wrap(talkerItem)
message := msg.Wrap(talkerItem, ds.dataDir)
// 应用sender过滤
if len(senders) > 0 {

View File

@ -39,11 +39,11 @@ type DataSource interface {
func New(workDir string, dataDir string, platform string, version int) (DataSource, error) {
switch {
case platform == "windows" && version == 3:
return windowsv3.New(workDir)
return windowsv3.New(workDir, dataDir)
case platform == "windows" && version == 4:
return v4.New(workDir, dataDir)
case platform == "darwin" && version == 3:
return darwinv3.New(workDir)
return darwinv3.New(workDir, dataDir)
case platform == "darwin" && version == 4:
return v4.New(workDir, dataDir)
default:

View File

@ -291,7 +291,7 @@ func (ds *DataSource) GetMessages(ctx context.Context, startTime, endTime time.T
}
// 将消息转换为标准格式
message := msg.Wrap(talkerItem)
message := msg.Wrap(talkerItem, ds.dataDir)
// 应用sender过滤
if len(senders) > 0 {

View File

@ -71,17 +71,19 @@ type MessageDBInfo struct {
// DataSource 实现了 DataSource 接口
type DataSource struct {
path string
dbm *dbm.DBManager
path string
dataDir string
dbm *dbm.DBManager
// 消息数据库信息
messageInfos []MessageDBInfo
}
// New 创建一个新的 WindowsV3DataSource
func New(path string) (*DataSource, error) {
func New(path string, dataDir string) (*DataSource, error) {
ds := &DataSource{
path: path,
dataDir: dataDir,
dbm: dbm.NewDBManager(path),
messageInfos: make([]MessageDBInfo, 0),
}
@ -327,8 +329,8 @@ func (ds *DataSource) GetMessages(ctx context.Context, startTime, endTime time.T
msg.CompressContent = compressContent
msg.BytesExtra = bytesExtra
// 将消息转换为标准格式
message := msg.Wrap()
// 将消息转换为标准格式
message := msg.Wrap(ds.dataDir)
// 应用sender过滤
if len(senders) > 0 {