1. 增加首次使用的引导功能
2. 增加多开微信可选择导出功能 3. 增加多账号数据可以切换查看功能
This commit is contained in:
parent
e6d8ab9de9
commit
073d586aea
142
app.go
142
app.go
@ -18,16 +18,17 @@ const (
|
|||||||
defaultConfig = "config"
|
defaultConfig = "config"
|
||||||
configDefaultUserKey = "userConfig.defaultUser"
|
configDefaultUserKey = "userConfig.defaultUser"
|
||||||
configUsersKey = "userConfig.users"
|
configUsersKey = "userConfig.users"
|
||||||
appVersion = "v1.0.2"
|
appVersion = "v1.0.3"
|
||||||
)
|
)
|
||||||
|
|
||||||
// App struct
|
// App struct
|
||||||
type App struct {
|
type App struct {
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
info wechat.WeChatInfo
|
infoList *wechat.WeChatInfoList
|
||||||
provider *wechat.WechatDataProvider
|
provider *wechat.WechatDataProvider
|
||||||
defaultUser string
|
defaultUser string
|
||||||
users []string
|
users []string
|
||||||
|
firstStart bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type WeChatInfo struct {
|
type WeChatInfo struct {
|
||||||
@ -39,6 +40,17 @@ type WeChatInfo struct {
|
|||||||
DBKey string `json:"DBkey"`
|
DBKey string `json:"DBkey"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type WeChatInfoList struct {
|
||||||
|
Info []WeChatInfo `json:"Info"`
|
||||||
|
Total int `json:"Total"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type WeChatAccountInfos struct {
|
||||||
|
CurrentAccount string `json:"CurrentAccount"`
|
||||||
|
Info []wechat.WeChatAccountInfo `json:"Info"`
|
||||||
|
Total int `json:"Total"`
|
||||||
|
}
|
||||||
|
|
||||||
// NewApp creates a new App application struct
|
// NewApp creates a new App application struct
|
||||||
func NewApp() *App {
|
func NewApp() *App {
|
||||||
a := &App{}
|
a := &App{}
|
||||||
@ -52,6 +64,7 @@ func NewApp() *App {
|
|||||||
// log.Println(a.defaultUser)
|
// log.Println(a.defaultUser)
|
||||||
// log.Println(a.users)
|
// log.Println(a.users)
|
||||||
} else {
|
} else {
|
||||||
|
a.firstStart = true
|
||||||
log.Println("not config exist")
|
log.Println("not config exist")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -65,39 +78,41 @@ func (a *App) startup(ctx context.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (a *App) beforeClose(ctx context.Context) (prevent bool) {
|
func (a *App) beforeClose(ctx context.Context) (prevent bool) {
|
||||||
dialog, err := runtime.MessageDialog(ctx, runtime.MessageDialogOptions{
|
|
||||||
Type: runtime.QuestionDialog,
|
|
||||||
Title: "Quit?",
|
|
||||||
Message: "Are you sure you want to quit?",
|
|
||||||
})
|
|
||||||
|
|
||||||
if err != nil || dialog == "Yes" {
|
if a.provider != nil {
|
||||||
a.provider.WechatWechatDataProviderClose()
|
a.provider.WechatWechatDataProviderClose()
|
||||||
a.provider = nil
|
a.provider = nil
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true
|
return false
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *App) GetWeChatAllInfo() string {
|
func (a *App) GetWeChatAllInfo() string {
|
||||||
a.info, _ = wechat.GetWeChatAllInfo()
|
infoList := WeChatInfoList{}
|
||||||
|
infoList.Info = make([]WeChatInfo, 0)
|
||||||
|
infoList.Total = 0
|
||||||
|
|
||||||
|
a.infoList = wechat.GetWeChatAllInfo()
|
||||||
|
for i := range a.infoList.Info {
|
||||||
var info WeChatInfo
|
var info WeChatInfo
|
||||||
info.ProcessID = a.info.ProcessID
|
info.ProcessID = a.infoList.Info[i].ProcessID
|
||||||
info.FilePath = a.info.FilePath
|
info.FilePath = a.infoList.Info[i].FilePath
|
||||||
info.AcountName = a.info.AcountName
|
info.AcountName = a.infoList.Info[i].AcountName
|
||||||
info.Version = a.info.Version
|
info.Version = a.infoList.Info[i].Version
|
||||||
info.Is64Bits = a.info.Is64Bits
|
info.Is64Bits = a.infoList.Info[i].Is64Bits
|
||||||
info.DBKey = a.info.DBKey
|
info.DBKey = a.infoList.Info[i].DBKey
|
||||||
|
infoList.Info = append(infoList.Info, info)
|
||||||
infoStr, _ := json.Marshal(info)
|
infoList.Total += 1
|
||||||
log.Println(string(infoStr))
|
log.Printf("ProcessID %d, FilePath %s, AcountName %s, Version %s, Is64Bits %t", info.ProcessID, info.FilePath, info.AcountName, info.Version, info.Is64Bits)
|
||||||
|
}
|
||||||
|
infoStr, _ := json.Marshal(infoList)
|
||||||
|
// log.Println(string(infoStr))
|
||||||
|
|
||||||
return string(infoStr)
|
return string(infoStr)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *App) ExportWeChatAllData(full bool) {
|
func (a *App) ExportWeChatAllData(full bool, acountName string) {
|
||||||
|
|
||||||
if a.provider != nil {
|
if a.provider != nil {
|
||||||
a.provider.WechatWechatDataProviderClose()
|
a.provider.WechatWechatDataProviderClose()
|
||||||
@ -106,13 +121,26 @@ func (a *App) ExportWeChatAllData(full bool) {
|
|||||||
|
|
||||||
progress := make(chan string)
|
progress := make(chan string)
|
||||||
go func() {
|
go func() {
|
||||||
|
var pInfo *wechat.WeChatInfo
|
||||||
|
for i := range a.infoList.Info {
|
||||||
|
if a.infoList.Info[i].AcountName == acountName {
|
||||||
|
pInfo = &a.infoList.Info[i]
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if pInfo == nil {
|
||||||
|
close(progress)
|
||||||
|
runtime.EventsEmit(a.ctx, "exportData", fmt.Sprintf("{\"status\":\"error\", \"result\":\"%s error\"}", acountName))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
_, err := os.Stat(".\\User")
|
_, err := os.Stat(".\\User")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
os.Mkdir(".\\User", os.ModeDir)
|
os.Mkdir(".\\User", os.ModeDir)
|
||||||
}
|
}
|
||||||
|
|
||||||
expPath := ".\\User\\" + a.info.AcountName
|
expPath := ".\\User\\" + pInfo.AcountName
|
||||||
_, err = os.Stat(expPath)
|
_, err = os.Stat(expPath)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
if !full {
|
if !full {
|
||||||
@ -127,26 +155,23 @@ func (a *App) ExportWeChatAllData(full bool) {
|
|||||||
os.Mkdir(expPath, os.ModeDir)
|
os.Mkdir(expPath, os.ModeDir)
|
||||||
}
|
}
|
||||||
|
|
||||||
go wechat.ExportWeChatAllData(a.info, expPath, progress)
|
go wechat.ExportWeChatAllData(*pInfo, expPath, progress)
|
||||||
|
|
||||||
for p := range progress {
|
for p := range progress {
|
||||||
log.Println(p)
|
log.Println(p)
|
||||||
runtime.EventsEmit(a.ctx, "exportData", p)
|
runtime.EventsEmit(a.ctx, "exportData", p)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(a.defaultUser) == 0 {
|
a.defaultUser = pInfo.AcountName
|
||||||
a.defaultUser = a.info.AcountName
|
|
||||||
}
|
|
||||||
|
|
||||||
hasUser := false
|
hasUser := false
|
||||||
for _, user := range a.users {
|
for _, user := range a.users {
|
||||||
if user == a.info.AcountName {
|
if user == pInfo.AcountName {
|
||||||
hasUser = true
|
hasUser = true
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !hasUser {
|
if !hasUser {
|
||||||
a.users = append(a.users, a.info.AcountName)
|
a.users = append(a.users, pInfo.AcountName)
|
||||||
}
|
}
|
||||||
a.setCurrentConfig()
|
a.setCurrentConfig()
|
||||||
}()
|
}()
|
||||||
@ -158,6 +183,12 @@ func (a *App) createWechatDataProvider(resPath string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if a.provider != nil {
|
||||||
|
a.provider.WechatWechatDataProviderClose()
|
||||||
|
a.provider = nil
|
||||||
|
log.Println("createWechatDataProvider WechatWechatDataProviderClose")
|
||||||
|
}
|
||||||
|
|
||||||
provider, err := wechat.CreateWechatDataProvider(resPath)
|
provider, err := wechat.CreateWechatDataProvider(resPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println("CreateWechatDataProvider failed:", resPath)
|
log.Println("CreateWechatDataProvider failed:", resPath)
|
||||||
@ -256,6 +287,10 @@ func (a *App) setCurrentConfig() {
|
|||||||
err := viper.SafeWriteConfig()
|
err := viper.SafeWriteConfig()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
|
err = viper.WriteConfig()
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -302,3 +337,52 @@ func (a *App) GetWeChatRoomUserList(roomId string) string {
|
|||||||
func (a *App) GetAppVersion() string {
|
func (a *App) GetAppVersion() string {
|
||||||
return appVersion
|
return appVersion
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *App) GetAppIsFirstStart() bool {
|
||||||
|
defer func() { a.firstStart = false }()
|
||||||
|
return a.firstStart
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *App) GetWechatLocalAccountInfo() string {
|
||||||
|
infos := WeChatAccountInfos{}
|
||||||
|
infos.Info = make([]wechat.WeChatAccountInfo, 0)
|
||||||
|
infos.Total = 0
|
||||||
|
infos.CurrentAccount = a.defaultUser
|
||||||
|
for i := range a.users {
|
||||||
|
resPath := ".\\User\\" + a.users[i]
|
||||||
|
if _, err := os.Stat(resPath); err != nil {
|
||||||
|
log.Println("GetWechatLocalAccountInfo:", resPath, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
info, err := wechat.WechatGetAccountInfo(resPath, a.users[i])
|
||||||
|
if err != nil {
|
||||||
|
log.Println("GetWechatLocalAccountInfo", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
infos.Info = append(infos.Info, *info)
|
||||||
|
infos.Total += 1
|
||||||
|
}
|
||||||
|
|
||||||
|
infoString, _ := json.Marshal(infos)
|
||||||
|
log.Println(string(infoString))
|
||||||
|
|
||||||
|
return string(infoString)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *App) WechatSwitchAccount(account string) bool {
|
||||||
|
for i := range a.users {
|
||||||
|
if a.users[i] == account {
|
||||||
|
if a.provider != nil {
|
||||||
|
a.provider.WechatWechatDataProviderClose()
|
||||||
|
a.provider = nil
|
||||||
|
}
|
||||||
|
a.defaultUser = account
|
||||||
|
a.setCurrentConfig()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
@ -1,3 +1,8 @@
|
|||||||
|
## v1.0.3
|
||||||
|
1. 增加首次使用的引导功能
|
||||||
|
2. 增加多开微信可选择导出功能
|
||||||
|
3. 增加多账号数据可以切换查看功能
|
||||||
|
|
||||||
## v1.0.2
|
## v1.0.2
|
||||||
1. 对话列表按照导出时微信显示顺序显示
|
1. 对话列表按照导出时微信显示顺序显示
|
||||||
2. 增加版本更新检测按钮
|
2. 增加版本更新检测按钮
|
||||||
|
503
frontend/dist/assets/index.425764f5.js
vendored
Normal file
503
frontend/dist/assets/index.425764f5.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
frontend/dist/assets/index.b10575d2.css
vendored
Normal file
1
frontend/dist/assets/index.b10575d2.css
vendored
Normal file
File diff suppressed because one or more lines are too long
4
frontend/dist/index.html
vendored
4
frontend/dist/index.html
vendored
@ -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.c5ad2349.js"></script>
|
<script type="module" crossorigin src="/assets/index.425764f5.js"></script>
|
||||||
<link rel="stylesheet" href="/assets/index.abf5d552.css">
|
<link rel="stylesheet" href="/assets/index.b10575d2.css">
|
||||||
</head>
|
</head>
|
||||||
<body >
|
<body >
|
||||||
<div id="root"></div>
|
<div id="root"></div>
|
||||||
|
@ -38,22 +38,25 @@ type WeChatInfo struct {
|
|||||||
DBKey string
|
DBKey string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type WeChatInfoList struct {
|
||||||
|
Info []WeChatInfo `json:"Info"`
|
||||||
|
Total int `json:"Total"`
|
||||||
|
}
|
||||||
|
|
||||||
type wechatMediaMSG struct {
|
type wechatMediaMSG struct {
|
||||||
Key string
|
Key string
|
||||||
MsgSvrID int
|
MsgSvrID int
|
||||||
Buf []byte
|
Buf []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetWeChatAllInfo() (WeChatInfo, error) {
|
func GetWeChatAllInfo() *WeChatInfoList {
|
||||||
info, err := GetWeChatInfo()
|
list := GetWeChatInfo()
|
||||||
if err != nil {
|
|
||||||
log.Println("GetWeChatInfo:", err)
|
for i := range list.Info {
|
||||||
return info, err
|
list.Info[i].DBKey = GetWeChatKey(&list.Info[i])
|
||||||
}
|
}
|
||||||
|
|
||||||
info.DBKey = GetWeChatKey(&info)
|
return list
|
||||||
|
|
||||||
return info, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func ExportWeChatAllData(info WeChatInfo, expPath string, progress chan<- string) {
|
func ExportWeChatAllData(info WeChatInfo, expPath string, progress chan<- string) {
|
||||||
@ -98,6 +101,8 @@ func exportWeChatVoice(info WeChatInfo, expPath string, progress chan<- string)
|
|||||||
}
|
}
|
||||||
|
|
||||||
var wg sync.WaitGroup
|
var wg sync.WaitGroup
|
||||||
|
var reportWg sync.WaitGroup
|
||||||
|
quitChan := make(chan struct{})
|
||||||
index = -1
|
index = -1
|
||||||
MSGChan := make(chan wechatMediaMSG, 100)
|
MSGChan := make(chan wechatMediaMSG, 100)
|
||||||
go func() {
|
go func() {
|
||||||
@ -156,22 +161,27 @@ func exportWeChatVoice(info WeChatInfo, expPath string, progress chan<- string)
|
|||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
wg.Add(1)
|
reportWg.Add(1)
|
||||||
go func() {
|
go func() {
|
||||||
defer wg.Done()
|
defer reportWg.Done()
|
||||||
for {
|
for {
|
||||||
if handleNumber >= fileNumber {
|
select {
|
||||||
break
|
case <-quitChan:
|
||||||
}
|
log.Println("WeChat voice report progress end")
|
||||||
|
return
|
||||||
|
default:
|
||||||
filePercent := float64(handleNumber) / float64(fileNumber)
|
filePercent := float64(handleNumber) / float64(fileNumber)
|
||||||
totalPercent := 61 + (filePercent * (100 - 61))
|
totalPercent := 61 + (filePercent * (100 - 61))
|
||||||
totalPercentStr := fmt.Sprintf("{\"status\":\"processing\", \"result\":\"export WeChat voice doing\", \"progress\": %d}", int(totalPercent))
|
totalPercentStr := fmt.Sprintf("{\"status\":\"processing\", \"result\":\"export WeChat voice doing\", \"progress\": %d}", int(totalPercent))
|
||||||
progress <- totalPercentStr
|
progress <- totalPercentStr
|
||||||
time.Sleep(time.Second)
|
time.Sleep(time.Second)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
|
close(quitChan)
|
||||||
|
reportWg.Wait()
|
||||||
progress <- "{\"status\":\"processing\", \"result\":\"export WeChat voice end\", \"progress\": 100}"
|
progress <- "{\"status\":\"processing\", \"result\":\"export WeChat voice end\", \"progress\": 100}"
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -190,6 +200,8 @@ func exportWeChatVideoAndFile(info WeChatInfo, expPath string, progress chan<- s
|
|||||||
log.Println("VideoAndFile ", fileNumber)
|
log.Println("VideoAndFile ", fileNumber)
|
||||||
|
|
||||||
var wg sync.WaitGroup
|
var wg sync.WaitGroup
|
||||||
|
var reportWg sync.WaitGroup
|
||||||
|
quitChan := make(chan struct{})
|
||||||
taskChan := make(chan [2]string, 100)
|
taskChan := make(chan [2]string, 100)
|
||||||
go func() {
|
go func() {
|
||||||
for _, rootPath := range rootPaths {
|
for _, rootPath := range rootPaths {
|
||||||
@ -241,21 +253,26 @@ func exportWeChatVideoAndFile(info WeChatInfo, expPath string, progress chan<- s
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
wg.Add(1)
|
reportWg.Add(1)
|
||||||
go func() {
|
go func() {
|
||||||
defer wg.Done()
|
defer reportWg.Done()
|
||||||
for {
|
for {
|
||||||
if handleNumber >= fileNumber {
|
select {
|
||||||
break
|
case <-quitChan:
|
||||||
}
|
log.Println("WeChat Video and File report progress end")
|
||||||
|
return
|
||||||
|
default:
|
||||||
filePercent := float64(handleNumber) / float64(fileNumber)
|
filePercent := float64(handleNumber) / float64(fileNumber)
|
||||||
totalPercent := 41 + (filePercent * (60 - 41))
|
totalPercent := 41 + (filePercent * (60 - 41))
|
||||||
totalPercentStr := fmt.Sprintf("{\"status\":\"processing\", \"result\":\"export WeChat Video and File doing\", \"progress\": %d}", int(totalPercent))
|
totalPercentStr := fmt.Sprintf("{\"status\":\"processing\", \"result\":\"export WeChat Video and File doing\", \"progress\": %d}", int(totalPercent))
|
||||||
progress <- totalPercentStr
|
progress <- totalPercentStr
|
||||||
time.Sleep(time.Second)
|
time.Sleep(time.Second)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}()
|
}()
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
|
close(quitChan)
|
||||||
|
reportWg.Wait()
|
||||||
progress <- "{\"status\":\"processing\", \"result\":\"export WeChat Video and File end\", \"progress\": 60}"
|
progress <- "{\"status\":\"processing\", \"result\":\"export WeChat Video and File end\", \"progress\": 60}"
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -271,6 +288,8 @@ func exportWeChatBat(info WeChatInfo, expPath string, progress chan<- string) {
|
|||||||
handleNumber := int64(0)
|
handleNumber := int64(0)
|
||||||
fileNumber := getPathFileNumber(datRootPath, ".dat")
|
fileNumber := getPathFileNumber(datRootPath, ".dat")
|
||||||
var wg sync.WaitGroup
|
var wg sync.WaitGroup
|
||||||
|
var reportWg sync.WaitGroup
|
||||||
|
quitChan := make(chan struct{})
|
||||||
taskChan := make(chan [2]string, 100)
|
taskChan := make(chan [2]string, 100)
|
||||||
go func() {
|
go func() {
|
||||||
err = filepath.Walk(datRootPath, func(path string, finfo os.FileInfo, err error) error {
|
err = filepath.Walk(datRootPath, func(path string, finfo os.FileInfo, err error) error {
|
||||||
@ -320,22 +339,26 @@ func exportWeChatBat(info WeChatInfo, expPath string, progress chan<- string) {
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
wg.Add(1)
|
reportWg.Add(1)
|
||||||
go func() {
|
go func() {
|
||||||
defer wg.Done()
|
defer reportWg.Done()
|
||||||
for {
|
for {
|
||||||
if handleNumber >= fileNumber {
|
select {
|
||||||
break
|
case <-quitChan:
|
||||||
}
|
log.Println("WeChat Dat report progress end")
|
||||||
|
return
|
||||||
|
default:
|
||||||
filePercent := float64(handleNumber) / float64(fileNumber)
|
filePercent := float64(handleNumber) / float64(fileNumber)
|
||||||
totalPercent := 21 + (filePercent * (40 - 21))
|
totalPercent := 21 + (filePercent * (40 - 21))
|
||||||
totalPercentStr := fmt.Sprintf("{\"status\":\"processing\", \"result\":\"export WeChat Dat doing\", \"progress\": %d}", int(totalPercent))
|
totalPercentStr := fmt.Sprintf("{\"status\":\"processing\", \"result\":\"export WeChat Dat doing\", \"progress\": %d}", int(totalPercent))
|
||||||
progress <- totalPercentStr
|
progress <- totalPercentStr
|
||||||
time.Sleep(time.Second)
|
time.Sleep(time.Second)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}()
|
}()
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
|
close(quitChan)
|
||||||
|
reportWg.Wait()
|
||||||
progress <- "{\"status\":\"processing\", \"result\":\"export WeChat Dat end\", \"progress\": 40}"
|
progress <- "{\"status\":\"processing\", \"result\":\"export WeChat Dat end\", \"progress\": 40}"
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -353,6 +376,8 @@ func exportWeChatDateBase(info WeChatInfo, expPath string, progress chan<- strin
|
|||||||
handleNumber := int64(0)
|
handleNumber := int64(0)
|
||||||
fileNumber := getPathFileNumber(info.FilePath+"\\Msg", ".db")
|
fileNumber := getPathFileNumber(info.FilePath+"\\Msg", ".db")
|
||||||
var wg sync.WaitGroup
|
var wg sync.WaitGroup
|
||||||
|
var reportWg sync.WaitGroup
|
||||||
|
quitChan := make(chan struct{})
|
||||||
taskChan := make(chan [2]string, 20)
|
taskChan := make(chan [2]string, 20)
|
||||||
go func() {
|
go func() {
|
||||||
err = filepath.Walk(info.FilePath+"\\Msg", func(path string, finfo os.FileInfo, err error) error {
|
err = filepath.Walk(info.FilePath+"\\Msg", func(path string, finfo os.FileInfo, err error) error {
|
||||||
@ -399,49 +424,55 @@ func exportWeChatDateBase(info WeChatInfo, expPath string, progress chan<- strin
|
|||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
wg.Add(1)
|
reportWg.Add(1)
|
||||||
go func() {
|
go func() {
|
||||||
defer wg.Done()
|
defer reportWg.Done()
|
||||||
for {
|
for {
|
||||||
if handleNumber >= fileNumber {
|
select {
|
||||||
break
|
case <-quitChan:
|
||||||
}
|
log.Println("WeChat DateBase report progress end")
|
||||||
|
return
|
||||||
|
default:
|
||||||
filePercent := float64(handleNumber) / float64(fileNumber)
|
filePercent := float64(handleNumber) / float64(fileNumber)
|
||||||
totalPercent := 1 + (filePercent * (20 - 1))
|
totalPercent := 1 + (filePercent * (20 - 1))
|
||||||
totalPercentStr := fmt.Sprintf("{\"status\":\"processing\", \"result\":\"export WeChat DateBase doing\", \"progress\": %d}", int(totalPercent))
|
totalPercentStr := fmt.Sprintf("{\"status\":\"processing\", \"result\":\"export WeChat DateBase doing\", \"progress\": %d}", int(totalPercent))
|
||||||
progress <- totalPercentStr
|
progress <- totalPercentStr
|
||||||
time.Sleep(time.Second)
|
time.Sleep(time.Second)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}()
|
}()
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
|
close(quitChan)
|
||||||
|
reportWg.Wait()
|
||||||
progress <- "{\"status\":\"processing\", \"result\":\"export WeChat DateBase end\", \"progress\": 20}"
|
progress <- "{\"status\":\"processing\", \"result\":\"export WeChat DateBase end\", \"progress\": 20}"
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetWeChatInfo() (info WeChatInfo, rerr error) {
|
func GetWeChatInfo() (list *WeChatInfoList) {
|
||||||
info = WeChatInfo{}
|
list = &WeChatInfoList{}
|
||||||
|
list.Info = make([]WeChatInfo, 0)
|
||||||
|
list.Total = 0
|
||||||
|
|
||||||
processes, err := process.Processes()
|
processes, err := process.Processes()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println("Error getting processes:", err)
|
log.Println("Error getting processes:", err)
|
||||||
rerr = err
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
found := false
|
|
||||||
for _, p := range processes {
|
for _, p := range processes {
|
||||||
name, err := p.Name()
|
name, err := p.Name()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
info := WeChatInfo{}
|
||||||
if name == "WeChat.exe" {
|
if name == "WeChat.exe" {
|
||||||
found = true
|
|
||||||
info.ProcessID = uint32(p.Pid)
|
info.ProcessID = uint32(p.Pid)
|
||||||
info.Is64Bits, _ = Is64BitProcess(info.ProcessID)
|
info.Is64Bits, _ = Is64BitProcess(info.ProcessID)
|
||||||
log.Println("ProcessID", info.ProcessID)
|
log.Println("ProcessID", info.ProcessID)
|
||||||
files, err := p.OpenFiles()
|
files, err := p.OpenFiles()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println("OpenFiles failed")
|
log.Println("OpenFiles failed")
|
||||||
return
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, f := range files {
|
for _, f := range files {
|
||||||
@ -450,7 +481,8 @@ func GetWeChatInfo() (info WeChatInfo, rerr error) {
|
|||||||
filePath := f.Path[4:]
|
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 {
|
||||||
return info, errors.New("Error filePath " + filePath)
|
log.Println("Error filePath " + filePath)
|
||||||
|
break
|
||||||
}
|
}
|
||||||
info.FilePath = strings.Join(parts[:len(parts)-2], string(filepath.Separator))
|
info.FilePath = strings.Join(parts[:len(parts)-2], string(filepath.Separator))
|
||||||
info.AcountName = strings.Join(parts[len(parts)-3:len(parts)-2], string(filepath.Separator))
|
info.AcountName = strings.Join(parts[len(parts)-3:len(parts)-2], string(filepath.Separator))
|
||||||
@ -459,14 +491,14 @@ func GetWeChatInfo() (info WeChatInfo, rerr error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if len(info.FilePath) == 0 {
|
if len(info.FilePath) == 0 {
|
||||||
rerr = errors.New("wechat not log in")
|
log.Println("wechat not log in")
|
||||||
return
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
hModuleSnap, err := windows.CreateToolhelp32Snapshot(windows.TH32CS_SNAPMODULE|windows.TH32CS_SNAPMODULE32, uint32(p.Pid))
|
hModuleSnap, err := windows.CreateToolhelp32Snapshot(windows.TH32CS_SNAPMODULE|windows.TH32CS_SNAPMODULE32, uint32(p.Pid))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println("CreateToolhelp32Snapshot failed", err)
|
log.Println("CreateToolhelp32Snapshot failed", err)
|
||||||
return
|
continue
|
||||||
}
|
}
|
||||||
defer windows.CloseHandle(hModuleSnap)
|
defer windows.CloseHandle(hModuleSnap)
|
||||||
|
|
||||||
@ -476,7 +508,7 @@ func GetWeChatInfo() (info WeChatInfo, rerr error) {
|
|||||||
err = windows.Module32First(hModuleSnap, &me32)
|
err = windows.Module32First(hModuleSnap, &me32)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println("Module32First failed", err)
|
log.Println("Module32First failed", err)
|
||||||
return
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
for ; err == nil; err = windows.Module32Next(hModuleSnap, &me32) {
|
for ; err == nil; err = windows.Module32Next(hModuleSnap, &me32) {
|
||||||
@ -493,19 +525,19 @@ func GetWeChatInfo() (info WeChatInfo, rerr error) {
|
|||||||
infoSize, err := windows.GetFileVersionInfoSize(driverPath, &zero)
|
infoSize, err := windows.GetFileVersionInfoSize(driverPath, &zero)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println("GetFileVersionInfoSize failed", err)
|
log.Println("GetFileVersionInfoSize failed", err)
|
||||||
return
|
break
|
||||||
}
|
}
|
||||||
versionInfo := make([]byte, infoSize)
|
versionInfo := make([]byte, infoSize)
|
||||||
if err = windows.GetFileVersionInfo(driverPath, 0, infoSize, unsafe.Pointer(&versionInfo[0])); err != nil {
|
if err = windows.GetFileVersionInfo(driverPath, 0, infoSize, unsafe.Pointer(&versionInfo[0])); err != nil {
|
||||||
log.Println("GetFileVersionInfo failed", err)
|
log.Println("GetFileVersionInfo failed", err)
|
||||||
return
|
break
|
||||||
}
|
}
|
||||||
var fixedInfo *windows.VS_FIXEDFILEINFO
|
var fixedInfo *windows.VS_FIXEDFILEINFO
|
||||||
fixedInfoLen := uint32(unsafe.Sizeof(*fixedInfo))
|
fixedInfoLen := uint32(unsafe.Sizeof(*fixedInfo))
|
||||||
err = windows.VerQueryValue(unsafe.Pointer(&versionInfo[0]), `\`, (unsafe.Pointer)(&fixedInfo), &fixedInfoLen)
|
err = windows.VerQueryValue(unsafe.Pointer(&versionInfo[0]), `\`, (unsafe.Pointer)(&fixedInfo), &fixedInfoLen)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println("VerQueryValue failed", err)
|
log.Println("VerQueryValue failed", err)
|
||||||
return
|
break
|
||||||
}
|
}
|
||||||
// fmt.Printf("%s: v%d.%d.%d.%d\n", windows.UTF16ToString(me32.Module[:]),
|
// fmt.Printf("%s: v%d.%d.%d.%d\n", windows.UTF16ToString(me32.Module[:]),
|
||||||
// (fixedInfo.FileVersionMS>>16)&0xff,
|
// (fixedInfo.FileVersionMS>>16)&0xff,
|
||||||
@ -518,16 +550,13 @@ func GetWeChatInfo() (info WeChatInfo, rerr error) {
|
|||||||
(fixedInfo.FileVersionMS>>0)&0xff,
|
(fixedInfo.FileVersionMS>>0)&0xff,
|
||||||
(fixedInfo.FileVersionLS>>16)&0xff,
|
(fixedInfo.FileVersionLS>>16)&0xff,
|
||||||
(fixedInfo.FileVersionLS>>0)&0xff)
|
(fixedInfo.FileVersionLS>>0)&0xff)
|
||||||
|
list.Info = append(list.Info, info)
|
||||||
|
list.Total += 1
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !found {
|
|
||||||
rerr = errors.New("not found process")
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -567,7 +596,7 @@ func GetWeChatKey(info *WeChatInfo) string {
|
|||||||
for {
|
for {
|
||||||
index := hasDeviceSybmol(buffer[offset:])
|
index := hasDeviceSybmol(buffer[offset:])
|
||||||
if index == -1 {
|
if index == -1 {
|
||||||
fmt.Println("hasDeviceSybmolxxxx")
|
log.Println("hasDeviceSybmolxxxx")
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
fmt.Printf("hasDeviceSybmol: 0x%X\n", index)
|
fmt.Printf("hasDeviceSybmol: 0x%X\n", index)
|
||||||
@ -638,7 +667,7 @@ func findDBkey(handle windows.Handle, path string, keys [][]byte) (string, error
|
|||||||
if keyAddrPtr == 0x00 {
|
if keyAddrPtr == 0x00 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
log.Println("keyAddrPtr: 0x%X\n", keyAddrPtr)
|
log.Printf("keyAddrPtr: 0x%X\n", keyAddrPtr)
|
||||||
keyBuffer := make([]byte, 0x20)
|
keyBuffer := make([]byte, 0x20)
|
||||||
err = windows.ReadProcessMemory(handle, uintptr(keyAddrPtr), &keyBuffer[0], uintptr(len(keyBuffer)), nil)
|
err = windows.ReadProcessMemory(handle, uintptr(keyAddrPtr), &keyBuffer[0], uintptr(len(keyBuffer)), nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -144,6 +144,15 @@ type WeChatUserList struct {
|
|||||||
Total int `json:"Total"`
|
Total int `json:"Total"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type WeChatAccountInfo struct {
|
||||||
|
AccountName string `json:"AccountName"`
|
||||||
|
AliasName string `json:"AliasName"`
|
||||||
|
ReMarkName string `json:"ReMarkName"`
|
||||||
|
NickName string `json:"NickName"`
|
||||||
|
SmallHeadImgUrl string `json:"SmallHeadImgUrl"`
|
||||||
|
BigHeadImgUrl string `json:"BigHeadImgUrl"`
|
||||||
|
}
|
||||||
|
|
||||||
type wechatMsgDB struct {
|
type wechatMsgDB struct {
|
||||||
path string
|
path string
|
||||||
db *sql.DB
|
db *sql.DB
|
||||||
@ -220,13 +229,19 @@ func CreateWechatDataProvider(resPath string) (*WechatDataProvider, error) {
|
|||||||
|
|
||||||
func (P *WechatDataProvider) WechatWechatDataProviderClose() {
|
func (P *WechatDataProvider) WechatWechatDataProviderClose() {
|
||||||
if P.microMsg != nil {
|
if P.microMsg != nil {
|
||||||
P.microMsg.Close()
|
err := P.microMsg.Close()
|
||||||
|
if err != nil {
|
||||||
|
log.Println("db close:", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, db := range P.msgDBs {
|
for _, db := range P.msgDBs {
|
||||||
db.db.Close()
|
err := db.db.Close()
|
||||||
|
if err != nil {
|
||||||
|
log.Println("db close:", err)
|
||||||
}
|
}
|
||||||
log.Println("WechatWechatDataProviderClose")
|
}
|
||||||
|
log.Println("WechatWechatDataProviderClose:", P.resPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (P *WechatDataProvider) WechatGetUserInfoByName(name string) (*WeChatUserInfo, error) {
|
func (P *WechatDataProvider) WechatGetUserInfoByName(name string) (*WeChatUserInfo, error) {
|
||||||
@ -876,3 +891,49 @@ func (P *WechatDataProvider) WechatGetUserInfoByNameOnCache(name string) (*WeCha
|
|||||||
|
|
||||||
return pinfo, nil
|
return pinfo, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func WechatGetAccountInfo(resPath, accountName string) (*WeChatAccountInfo, error) {
|
||||||
|
MicroMsgDBPath := resPath + "\\Msg\\" + MicroMsgDB
|
||||||
|
if _, err := os.Stat(MicroMsgDBPath); err != nil {
|
||||||
|
log.Println("MicroMsgDBPath:", MicroMsgDBPath, err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
microMsg, err := sql.Open("sqlite3", MicroMsgDBPath)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("open db %s error: %v", MicroMsgDBPath, err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer microMsg.Close()
|
||||||
|
|
||||||
|
info := &WeChatAccountInfo{}
|
||||||
|
|
||||||
|
var UserName, Alias, ReMark, NickName string
|
||||||
|
querySql := fmt.Sprintf("select ifnull(UserName,'') as UserName, ifnull(Alias,'') as Alias, ifnull(ReMark,'') as ReMark, ifnull(NickName,'') as NickName from Contact where UserName='%s';", accountName)
|
||||||
|
// log.Println(querySql)
|
||||||
|
err = microMsg.QueryRow(querySql).Scan(&UserName, &Alias, &ReMark, &NickName)
|
||||||
|
if err != nil {
|
||||||
|
log.Println("not found User:", err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("UserName %s, Alias %s, ReMark %s, NickName %s\n", UserName, Alias, ReMark, NickName)
|
||||||
|
|
||||||
|
var smallHeadImgUrl, bigHeadImgUrl string
|
||||||
|
querySql = fmt.Sprintf("select ifnull(smallHeadImgUrl,'') as smallHeadImgUrl, ifnull(bigHeadImgUrl,'') as bigHeadImgUrl from ContactHeadImgUrl where usrName='%s';", UserName)
|
||||||
|
// log.Println(querySql)
|
||||||
|
err = microMsg.QueryRow(querySql).Scan(&smallHeadImgUrl, &bigHeadImgUrl)
|
||||||
|
if err != nil {
|
||||||
|
log.Println("not find headimg", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
info.AccountName = UserName
|
||||||
|
info.AliasName = Alias
|
||||||
|
info.ReMarkName = ReMark
|
||||||
|
info.NickName = NickName
|
||||||
|
info.SmallHeadImgUrl = smallHeadImgUrl
|
||||||
|
info.BigHeadImgUrl = bigHeadImgUrl
|
||||||
|
|
||||||
|
// log.Println(info)
|
||||||
|
return info, nil
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user