Skip to content

Commit

Permalink
1. 图片/视频查看重新实现,保持与微信一致
Browse files Browse the repository at this point in the history
2. 增加软件信息页面
3. 修复企业联系人头像和名称不显示问题
4. 修复撤回消息显示不正常的问题
  • Loading branch information
git-jiadong committed Dec 14, 2024
1 parent 30ccdd6 commit d342257
Show file tree
Hide file tree
Showing 14 changed files with 874 additions and 1,031 deletions.
7 changes: 6 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ PC微信聊天记录数据导出工具
效果图如下:

![](./res/result.png)
![](./res/result2.png)

## 演示视频
[演示视频](https://www.bilibili.com/video/BV1bPH1eWEEy/?share_source=copy_web&vd_source=b5cfa9258a9ad9900a00e9c1ce3cb4b6)
Expand Down Expand Up @@ -47,7 +48,7 @@ wails build
- [x] 多开账号数据切换
- [x] 头像使用本地头像
- [ ] 支持更多消息类型显示
- [ ] 图片查看器重绘
- [x] 图片查看器重绘
- [ ] 实现表情预先下载(实现完全离线查看)
- [ ] 聊天报告
- [ ] AI本地模型应用
Expand All @@ -64,6 +65,10 @@ A: 这是由于可能数据存在于内存中还没有回写到磁盘导致的
**Q: 有些图片、视频打不开**<br>
A: 这是电脑端微信没有点开过这个消息,默认只加载了预览图而已,如果手机有打开过可以把手机的记录迁移到电脑,迁移后重新退出登陆一次微信导出即可。<br>

## Star History

[![Star History Chart](https://api.star-history.com/svg?repos=git-jiadong/wechatDataBackup&type=Date)](https://star-history.com/?utm_source=bestxtools.com#git-jiadong/wechatDataBackup&Date)

## 免责声明
**⚠️ 本项目仅供学习、研究使用,严禁商业使用**<br/>
**⚠️ 用于网络安全用途的,请确保在国家法律法规下使用**<br/>
Expand Down
141 changes: 130 additions & 11 deletions app.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@ import (
"encoding/json"
"fmt"
"log"
"mime"
"net/http"
"os"
"path/filepath"
"strconv"
"strings"
"wechatDataBackup/pkg/utils"
"wechatDataBackup/pkg/wechat"
Expand All @@ -21,7 +23,7 @@ const (
configDefaultUserKey = "userConfig.defaultUser"
configUsersKey = "userConfig.users"
configExportPathKey = "exportPath"
appVersion = "v1.0.5"
appVersion = "v1.0.6"
)

type FileLoader struct {
Expand All @@ -30,6 +32,7 @@ type FileLoader struct {
}

func NewFileLoader(prefix string) *FileLoader {
mime.AddExtensionType(".mp3", "audio/mpeg")
return &FileLoader{FilePrefix: prefix}
}

Expand All @@ -39,16 +42,74 @@ func (h *FileLoader) SetFilePrefix(prefix string) {
}

func (h *FileLoader) ServeHTTP(res http.ResponseWriter, req *http.Request) {
var err error
requestedFilename := h.FilePrefix + "\\" + strings.TrimPrefix(req.URL.Path, "/")
// log.Println("Requesting file:", requestedFilename)
fileData, err := os.ReadFile(requestedFilename)

file, err := os.Open(requestedFilename)
if err != nil {
http.Error(res, fmt.Sprintf("Could not load file %s", requestedFilename), http.StatusBadRequest)
return
}
defer file.Close()

fileInfo, err := file.Stat()
if err != nil {
res.WriteHeader(http.StatusBadRequest)
res.Write([]byte(fmt.Sprintf("Could not load file %s", requestedFilename)))
http.Error(res, "Could not retrieve file info", http.StatusInternalServerError)
return
}

fileSize := fileInfo.Size()
rangeHeader := req.Header.Get("Range")
if rangeHeader == "" {
// 无 Range 请求,直接返回整个文件
res.Header().Set("Content-Length", strconv.FormatInt(fileSize, 10))
http.ServeContent(res, req, requestedFilename, fileInfo.ModTime(), file)
return
}

var start, end int64
if strings.HasPrefix(rangeHeader, "bytes=") {
ranges := strings.Split(strings.TrimPrefix(rangeHeader, "bytes="), "-")
start, _ = strconv.ParseInt(ranges[0], 10, 64)

if len(ranges) > 1 && ranges[1] != "" {
end, _ = strconv.ParseInt(ranges[1], 10, 64)
} else {
end = fileSize - 1
}
} else {
http.Error(res, "Invalid Range header", http.StatusRequestedRangeNotSatisfiable)
return
}

res.Write(fileData)
if start < 0 || end >= fileSize || start > end {
http.Error(res, "Requested range not satisfiable", http.StatusRequestedRangeNotSatisfiable)
return
}

contentType := mime.TypeByExtension(filepath.Ext(requestedFilename))
if contentType == "" {
contentType = "application/octet-stream"
}
res.Header().Set("Content-Type", contentType)
res.Header().Set("Content-Range", fmt.Sprintf("bytes %d-%d/%d", start, end, fileSize))
res.Header().Set("Content-Length", strconv.FormatInt(end-start+1, 10))
res.WriteHeader(http.StatusPartialContent)
buffer := make([]byte, 102400)
file.Seek(start, 0)
for current := start; current <= end; {
readSize := int64(len(buffer))
if end-current+1 < readSize {
readSize = end - current + 1
}

n, err := file.Read(buffer[:readSize])
if err != nil {
break
}

res.Write(buffer[:n])
current += int64(n)
}
}

// App struct
Expand Down Expand Up @@ -90,7 +151,7 @@ type ErrorMessage struct {
// NewApp creates a new App application struct
func NewApp() *App {
a := &App{}

log.Println("App version:", appVersion)
a.firstInit = true
a.FLoader = NewFileLoader(".\\")
viper.SetConfigName(defaultConfig)
Expand Down Expand Up @@ -306,7 +367,7 @@ func (a *App) GetWechatContactList(pageIndex int, pageSize int) string {
}

func (a *App) GetWechatMessageListByTime(userName string, time int64, pageSize int, direction string) string {
log.Println("GetWechatMessageList:", userName, pageSize, time, direction)
log.Println("GetWechatMessageListByTime:", userName, pageSize, time, direction)
if len(userName) == 0 {
return "{\"Total\":0, \"Rows\":[]}"
}
Expand All @@ -318,11 +379,33 @@ func (a *App) GetWechatMessageListByTime(userName string, time int64, pageSize i
}
list, err := a.provider.WeChatGetMessageListByTime(userName, time, pageSize, dire)
if err != nil {
log.Println("WeChatGetMessageList failed:", err)
log.Println("GetWechatMessageListByTime failed:", err)
return ""
}
listStr, _ := json.Marshal(list)
log.Println("GetWechatMessageList:", list.Total)
log.Println("GetWechatMessageListByTime:", list.Total)

return string(listStr)
}

func (a *App) GetWechatMessageListByType(userName string, time int64, pageSize int, msgType string, direction string) string {
log.Println("GetWechatMessageListByType:", userName, pageSize, time, msgType, direction)
if len(userName) == 0 {
return "{\"Total\":0, \"Rows\":[]}"
}
dire := wechat.Message_Search_Forward
if direction == "backward" {
dire = wechat.Message_Search_Backward
} else if direction == "both" {
dire = wechat.Message_Search_Both
}
list, err := a.provider.WeChatGetMessageListByType(userName, time, pageSize, msgType, dire)
if err != nil {
log.Println("WeChatGetMessageListByType failed:", err)
return ""
}
listStr, _ := json.Marshal(list)
log.Println("WeChatGetMessageListByType:", list.Total)

return string(listStr)
}
Expand Down Expand Up @@ -594,3 +677,39 @@ func (a *App) scanAccountByPath(path string) error {
func (a *App) OepnLogFileExplorer() {
utils.OpenFileOrExplorer(".\\app.log", true)
}

func (a *App) SaveFileDialog(file string, alisa string) string {
filePath := a.FLoader.FilePrefix + file
if _, err := os.Stat(filePath); err != nil {
log.Println("SaveFileDialog:", err)
return err.Error()
}

savePath, err := runtime.SaveFileDialog(a.ctx, runtime.SaveDialogOptions{
DefaultFilename: alisa,
Title: "选择保存路径",
})
if err != nil {
log.Println("SaveFileDialog:", err)
return err.Error()
}

if savePath == "" {
return ""
}

dirPath := filepath.Dir(savePath)
if !utils.PathIsCanWriteFile(dirPath) {
errStr := "Path Is Can't Write File: " + filepath.Dir(savePath)
log.Println(errStr)
return errStr
}

_, err = utils.CopyFile(filePath, savePath)
if err != nil {
log.Println("Error CopyFile", filePath, savePath, err)
return err.Error()
}

return ""
}
6 changes: 6 additions & 0 deletions changelog.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
## v1.0.6
1. 图片/视频查看重新实现,保持与微信一致
2. 增加软件信息页面
3. 修复企业联系人头像和名称不显示问题
4. 修复撤回消息显示不正常的问题

## v1.0.5
1. 修复联系人搜索显示异常的问题
2. 修复启动时界面加载显示慢的问题
Expand Down
Binary file added frontend/dist/assets/errorImg.719abbab.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit d342257

Please sign in to comment.