Compare commits

..

No commits in common. "main" and "v1.2.1" have entirely different histories.
main ... v1.2.1

23 changed files with 585 additions and 642 deletions

3
.gitignore vendored
View File

@ -30,5 +30,4 @@ env
User User
config.json config.json
wechatDataBackup.exe wechatDataBackup.exe
app.log app.log
app-*.log

View File

@ -1,34 +1,13 @@
<p align="center" style="text-align: center">
<img src="./res/logo_256.png" width="15%"><br/>
</p>
<p align="center">
<b>wechatDataBackup: PC微信聊天记录数据导出工具</b>
<br/>
<br/>
<a href="https://github.com/git-jiadong/wechatDataBackup/stargazers">
<img src="https://img.shields.io/github/stars/git-jiadong/wechatDataBackup" alt="GitHub Star"/>
</a>
<a href="https://github.com/git-jiadong/wechatDataBackup/releases">
<img src="https://img.shields.io/github/downloads/git-jiadong/wechatDataBackup/total" alt="downloads" />
</a>
<a href="https://github.com/git-jiadong/wechatDataBackup/releases">
<img src="https://img.shields.io/github/v/release/git-jiadong/wechatDataBackup" alt="releases version"/>
</a>
<a href="https://github.com/git-jiadong/wechatDataBackup/commits/main">
<img src="https://img.shields.io/github/last-commit/git-jiadong/wechatDataBackup" alt="last commit" />
</a>
<a href="https://github.com/git-jiadong/wechatDataBackup" >
<img src="https://img.shields.io/github/languages/top/git-jiadong/wechatDataBackup" alt="languages"/>
</a>
<a href="https://github.com/git-jiadong/wechatDataBackup" >
<img src="https://img.shields.io/github/repo-size/git-jiadong/wechatDataBackup" alt="repo size" />
</a>
<a href="https://github.com/git-jiadong/wechatDataBackup/blob/main/LICENSE">
<img src="https://img.shields.io/github/license/git-jiadong/wechatDataBackup" alt="license" />
</a>
</p>
# wechatDataBackup # wechatDataBackup
PC微信聊天记录数据导出工具
[![GitHub stars](https://img.shields.io/github/stars/git-jiadong/wechatDataBackup)](https://github.com/git-jiadong/wechatDataBackup/stargazers)
[![GitHub all releases](https://img.shields.io/github/downloads/git-jiadong/wechatDataBackup/total)](https://github.com/git-jiadong/wechatDataBackup/releases)
[![GitHub release](https://img.shields.io/github/v/release/git-jiadong/wechatDataBackup)](https://github.com/git-jiadong/wechatDataBackup/releases)
[![GitHub last commit](https://img.shields.io/github/last-commit/git-jiadong/wechatDataBackup)](https://github.com/git-jiadong/wechatDataBackup/commits/main)
[![GitHub top language](https://img.shields.io/github/languages/top/git-jiadong/wechatDataBackup)](https://github.com/git-jiadong/wechatDataBackup)
[![GitHub repo size](https://img.shields.io/github/repo-size/git-jiadong/wechatDataBackup)](https://github.com/git-jiadong/wechatDataBackup)
[![GitHub license](https://img.shields.io/github/license/git-jiadong/wechatDataBackup)](https://github.com/git-jiadong/wechatDataBackup/blob/main/LICENSE)
* 基于wails开发 + React前端实现PC端微信聊天记录一键导出功能。 * 基于wails开发 + React前端实现PC端微信聊天记录一键导出功能。
* 导出后数据可以做永久化保存,即使微信停止支持,聊天记录也可以随时查看。 * 导出后数据可以做永久化保存,即使微信停止支持,聊天记录也可以随时查看。

25
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.2.4" appVersion = "v1.2.1"
) )
type FileLoader struct { type FileLoader struct {
@ -832,6 +832,14 @@ func (a *App) ExportWeChatDataByUserName(userName, path string) string {
return "WeChatExportDataByUserName failed:" + err.Error() return "WeChatExportDataByUserName failed:" + err.Error()
} }
exeSrcPath := a.FLoader.FilePrefix + "\\" + "wechatDataBackup.exe"
exeDstPath := exPath + "\\" + "wechatDataBackup.exe"
_, err = utils.CopyFile(exeSrcPath, exeDstPath)
if err != nil {
log.Println("CopyFile:", err)
return "CopyFile:" + err.Error()
}
config := map[string]interface{}{ config := map[string]interface{}{
"exportpath": ".\\", "exportpath": ".\\",
"userconfig": map[string]interface{}{ "userconfig": map[string]interface{}{
@ -853,21 +861,6 @@ func (a *App) ExportWeChatDataByUserName(userName, path string) string {
return "WriteFile:" + err.Error() return "WriteFile:" + err.Error()
} }
exeSrcPath, err := os.Executable()
if err != nil {
log.Println("Executable:", exeSrcPath)
return "Executable:" + err.Error()
}
exeDstPath := exPath + "\\" + "wechatDataBackup.exe"
log.Printf("Copy [%s] -> [%s]\n", exeSrcPath, exeDstPath)
_, err = utils.CopyFile(exeSrcPath, exeDstPath)
if err != nil {
log.Println("CopyFile:", err)
return "CopyFile:" + err.Error()
}
return ""
return "" return ""
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 82 KiB

After

Width:  |  Height:  |  Size: 411 KiB

View File

@ -1,16 +1,3 @@
## v1.2.4
1. 修复FileStorage\Image文件没有导出的问题
2. 增加图片定位到聊天位置的功能
3. 导出界面增加提示
## v1.2.3
1. 修改程序ICON
## v1.2.2
1. UI统一使用“思源黑体”字体
2. 修复导出分享会话时可执行文件可能拷贝错误的情况
3. 修复微信存储路径为网盘时,解密会失败的情况
## v1.2.0 ## v1.2.0
1. 实现最后浏览位置记录和书签功能 1. 实现最后浏览位置记录和书签功能
2. 实现会话导出分享功能 2. 实现会话导出分享功能

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

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

533
frontend/dist/assets/index.e4a8c0f4.js vendored Normal file

File diff suppressed because one or more lines are too long

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 91 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.8be36b27.js"></script> <script type="module" crossorigin src="/assets/index.e4a8c0f4.js"></script>
<link rel="stylesheet" href="/assets/index.00f6955e.css"> <link rel="stylesheet" href="/assets/index.0393a903.css">
</head> </head>
<body > <body >
<div id="root"></div> <div id="root"></div>

View File

@ -310,7 +310,6 @@ func exportWeChatVideoAndFile(info WeChatInfo, expPath string, progress chan<- s
videoRootPath := info.FilePath + "\\FileStorage\\Video" videoRootPath := info.FilePath + "\\FileStorage\\Video"
fileRootPath := info.FilePath + "\\FileStorage\\File" fileRootPath := info.FilePath + "\\FileStorage\\File"
cacheRootPath := info.FilePath + "\\FileStorage\\Cache" cacheRootPath := info.FilePath + "\\FileStorage\\Cache"
rootPaths := []string{videoRootPath, fileRootPath, cacheRootPath} rootPaths := []string{videoRootPath, fileRootPath, cacheRootPath}
handleNumber := int64(0) handleNumber := int64(0)
@ -327,9 +326,6 @@ func exportWeChatVideoAndFile(info WeChatInfo, expPath string, progress chan<- s
go func() { go func() {
for _, rootPath := range rootPaths { for _, rootPath := range rootPaths {
log.Println(rootPath) log.Println(rootPath)
if _, err := os.Stat(rootPath); err != nil {
continue
}
err := filepath.Walk(rootPath, func(path string, finfo os.FileInfo, err error) error { err := filepath.Walk(rootPath, func(path string, finfo os.FileInfo, err error) error {
if err != nil { if err != nil {
log.Printf("filepath.Walk%v\n", err) log.Printf("filepath.Walk%v\n", err)
@ -403,51 +399,43 @@ func exportWeChatVideoAndFile(info WeChatInfo, expPath string, progress chan<- s
func exportWeChatBat(info WeChatInfo, expPath string, progress chan<- string) { func exportWeChatBat(info WeChatInfo, expPath string, progress chan<- string) {
progress <- "{\"status\":\"processing\", \"result\":\"export WeChat Dat start\", \"progress\": 21}" progress <- "{\"status\":\"processing\", \"result\":\"export WeChat Dat start\", \"progress\": 21}"
datRootPath := info.FilePath + "\\FileStorage\\MsgAttach" datRootPath := info.FilePath + "\\FileStorage\\MsgAttach"
imageRootPath := info.FilePath + "\\FileStorage\\Image" fileInfo, err := os.Stat(datRootPath)
rootPaths := []string{datRootPath, imageRootPath} if err != nil || !fileInfo.IsDir() {
progress <- fmt.Sprintf("{\"status\":\"error\", \"result\":\"%s error\"}", datRootPath)
return
}
handleNumber := int64(0) handleNumber := int64(0)
fileNumber := int64(0) fileNumber := getPathFileNumber(datRootPath, ".dat")
for i := range rootPaths {
fileNumber += getPathFileNumber(rootPaths[i], ".dat")
}
log.Println("DatFileNumber ", fileNumber)
var wg sync.WaitGroup var wg sync.WaitGroup
var reportWg sync.WaitGroup var reportWg sync.WaitGroup
quitChan := make(chan struct{}) quitChan := make(chan struct{})
taskChan := make(chan [2]string, 100) taskChan := make(chan [2]string, 100)
go func() { go func() {
for i := range rootPaths { err = filepath.Walk(datRootPath, func(path string, finfo os.FileInfo, err error) error {
if _, err := os.Stat(rootPaths[i]); err != nil {
continue
}
err := filepath.Walk(rootPaths[i], func(path string, finfo os.FileInfo, err error) error {
if err != nil {
log.Printf("filepath.Walk%v\n", err)
return err
}
if !finfo.IsDir() && strings.HasSuffix(path, ".dat") {
expFile := expPath + path[len(info.FilePath):]
_, err := os.Stat(filepath.Dir(expFile))
if err != nil {
os.MkdirAll(filepath.Dir(expFile), 0644)
}
task := [2]string{path, expFile}
taskChan <- task
return nil
}
return nil
})
if err != nil { if err != nil {
log.Println("filepath.Walk:", err) log.Printf("filepath.Walk%v\n", err)
progress <- fmt.Sprintf("{\"status\":\"error\", \"result\":\"%v\"}", err) return err
} }
if !finfo.IsDir() && strings.HasSuffix(path, ".dat") {
expFile := expPath + path[len(info.FilePath):]
_, err := os.Stat(filepath.Dir(expFile))
if err != nil {
os.MkdirAll(filepath.Dir(expFile), 0644)
}
task := [2]string{path, expFile}
taskChan <- task
return nil
}
return nil
})
if err != nil {
log.Println("filepath.Walk:", err)
progress <- fmt.Sprintf("{\"status\":\"error\", \"result\":\"%v\"}", err)
} }
close(taskChan) close(taskChan)
}() }()
@ -457,7 +445,7 @@ func exportWeChatBat(info WeChatInfo, expPath string, progress chan<- string) {
go func() { go func() {
defer wg.Done() defer wg.Done()
for task := range taskChan { for task := range taskChan {
_, err := os.Stat(task[1]) _, err = os.Stat(task[1])
if err == nil { if err == nil {
atomic.AddInt64(&handleNumber, 1) atomic.AddInt64(&handleNumber, 1)
continue continue
@ -610,7 +598,7 @@ func GetWeChatInfo() (list *WeChatInfoList) {
for _, f := range files { for _, f := range files {
if strings.HasSuffix(f.Path, "\\Media.db") { if strings.HasSuffix(f.Path, "\\Media.db") {
// fmt.Printf("opened %s\n", f.Path[4:]) // fmt.Printf("opened %s\n", f.Path[4:])
filePath := f.Path filePath := f.Path[4:]
parts := strings.Split(filePath, string(filepath.Separator)) parts := strings.Split(filePath, string(filepath.Separator))
if len(parts) < 4 { if len(parts) < 4 {
log.Println("Error filePath " + filePath) log.Println("Error filePath " + filePath)

View File

@ -182,7 +182,6 @@ type WeChatMessage struct {
} }
type WeChatMessageList struct { type WeChatMessageList struct {
MsgType string `json:"MsgType"`
KeyWord string `json:"KeyWord"` KeyWord string `json:"KeyWord"`
Total int `json:"Total"` Total int `json:"Total"`
Rows []WeChatMessage `json:"Rows"` Rows []WeChatMessage `json:"Rows"`
@ -693,7 +692,6 @@ func (P *WechatDataProvider) WeChatGetMessageListByKeyWord(userName string, time
List := &WeChatMessageList{} List := &WeChatMessageList{}
List.Rows = make([]WeChatMessage, 0) List.Rows = make([]WeChatMessage, 0)
List.KeyWord = keyWord List.KeyWord = keyWord
List.MsgType = msgType
_time := time _time := time
selectPagesize := pageSize selectPagesize := pageSize
if keyWord != "" || msgType != "" { if keyWord != "" || msgType != "" {
@ -734,7 +732,6 @@ func (P *WechatDataProvider) WeChatGetMessageListByType(userName string, time in
List := &WeChatMessageList{} List := &WeChatMessageList{}
List.Rows = make([]WeChatMessage, 0) List.Rows = make([]WeChatMessage, 0)
List.MsgType = msgType
selectTime := time selectTime := time
selectpageSize := 30 selectpageSize := 30
needSize := pageSize needSize := pageSize

Binary file not shown.

Before

Width:  |  Height:  |  Size: 470 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB