void AndroidRun() { int maxCount = int.MaxValue; if (!softReg.GetIsReg()) { maxCount = 10; MessageBox.Show("非注册用户暂时支持部分导出 \n如果导出全量信息请到https://www.weixinxqm.com/购买注册!", "信息", MessageBoxButtons.OK, MessageBoxIcon.Information); } var saveBase = savePathTextBox.Text; Directory.CreateDirectory(saveBase); AddLog("分析文件夹结构"); AndroidWeChatInterface wechat = null; if (string.IsNullOrEmpty(resPathTextBox.Text)) { wechat = new AndroidWeChatInterface(wechatPathTextBox.Text); } else { wechat = new AndroidWeChatInterface(wechatPathTextBox.Text, resPathTextBox.Text); } wechat.Init(); AddLog("查找UID"); var users = wechat.users; AddLog("找到" + users.Count + "个账号的消息记录"); var uidList = new List <DisplayItem>(); foreach (var user in users) { user.Init(); AddLog("开始处理UID: " + user.uid); AddLog("打开数据库"); if (!user.OpenMMSqlite()) { AddLog("无法打开数据库"); continue; } AddLog("读取账号信息"); if (!user.GetUserBasics()) { AddLog("没有找到本人信息,用默认值替代"); } Friend myself = user.myself; AddLog("微信号:" + myself.ID() + " 昵称:" + myself.DisplayName()); AddLog("读取好友列表"); if (!user.GetFriendsDict(out int friendcount)) { AddLog("获取好友列表失败,跳过"); continue; } if (!user.GetChatRoomMember(out int chatroomCount)) { AddLog("获取聊天室用户列表失败,跳过"); continue; } AddLog("找到" + (friendcount - chatroomCount) + "个好友"); AddLog("找到" + chatroomCount + "个聊天室"); AddLog("查找对话:"); user.GetChatSessions(out List <string> chats); AddLog("找到" + chats.Count + "个对话"); var userSaveBase = Path.Combine(saveBase, myself.ID()); Directory.CreateDirectory(userSaveBase); user.userSaveDir = userSaveBase; AddLog("导出好友列表:"); if (user.saveFriends(maxCount, out int exportCount)) { AddLog("导出" + exportCount + "个好友"); } else { AddLog("导出好友列表出错"); } var emojidown = new HashSet <DownloadTask>(); var chatList = new List <DisplayItem>(); if (htmlRadioButton.Checked) { try { AddLog("复制头像:"); user.CopyResource(); File.Copy("res\\[email protected]", Path.Combine(userSaveBase, "avatar", "*****@*****.**")); } catch (Exception) { } } foreach (var chat in chats) { string displayname = chat; Friend friend = user.GetFriend(chat); if (friend != null) { displayname = friend.DisplayName(); AddLog("处理与" + displayname + "的对话"); } else { AddLog("未找到好友信息,用默认名字代替"); } if (textRadioButton.Checked) { if (user.SaveTextRecord(chat, maxCount, out int count)) { AddLog("成功处理" + count + "条"); } else { AddLog("失败"); } } else if (htmlRadioButton.Checked) { if (user.SaveHtmlRecord(chat, maxCount, out int count, out HashSet <DownloadTask> _emojidown)) { AddLog("成功处理" + count + "条"); chatList.Add(new DisplayItem() { pic = "avatar/" + (friend != null ? friend.GetAndroidUserAvatar() : "*****@*****.**"), text = displayname, link = chat + ".html" }); } else { AddLog("失败"); } emojidown.UnionWith(_emojidown); } } if (htmlRadioButton.Checked) { BaseWeChat.MakeListHTML(chatList, Path.Combine(userSaveBase, "聊天记录.html")); } var downloader = new Downloader(6); var emojidir = Path.Combine(userSaveBase, "Emoji"); Directory.CreateDirectory(emojidir); if (emojidown != null && emojidown.Count > 0) { AddLog("下载" + emojidown.Count + "个表情"); foreach (var item in emojidown) { downloader.AddTask(item.url, Path.Combine(emojidir, item.filename)); } } uidList.Add(new DisplayItem() { pic = myself.ID() + "/avatar/" + user.myself.GetAndroidUserAvatar(), text = myself.DisplayName(), link = myself.ID() + "/聊天记录.html" }); downloader.StartDownload(); downloader.WaitToEnd(); AddLog("完成当前账号"); }
public bool SaveHtmlRecord(string talker, int maxCount, out int count, out HashSet <DownloadTask> emojidown) { bool succ = false; emojidown = new HashSet <DownloadTask>(); count = 0; try { Friend friend = friends[talker]; Dictionary <string, string> chatremark = null; if (talker.EndsWith("@chatroom") && chatRoomUserDict != null) { if (chatRoomUserDict.ContainsKey(talker)) { chatremark = chatRoomUserDict[talker]; } } var messages = dbConn.Table <Message>().Where(t => t.Talker == talker).OrderByDescending(t => t.CreateTime).ToList(); using (var sw = new StreamWriter(Path.Combine(userSaveDir, talker + ".html"))) { sw.WriteLine(@"<!DOCTYPE html PUBLIC ""-//W3C//DTD XHTML 1.0 Transitional//EN"" ""http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"">"); sw.WriteLine(@"<html xmlns=""http://www.w3.org/1999/xhtml""><head><meta http-equiv=""Content-Type"" content=""text/html; charset=utf-8"" /><title>" + friend.DisplayName() + " - 微信聊天记录</title></head>"); sw.WriteLine(@"<body><table width=""600"" border=""0"" style=""font-size:12px;border-collapse:separate;border-spacing:0px 20px;word-break:break-all;table-layout:fixed;word-wrap:break-word;"" align=""center"">"); foreach (var msg in messages) { try { var unixtime = msg.CreateTime; unixtime = unixtime / 1000; var message = msg.Content; var des = msg.IsSend; var type = msg.Type; if (type == 10000) { sw.WriteLine(@"<tr><td width=""80""> </td><td width=""100""> </td><td>系统消息: " + message + @"</td></tr>"); continue; } var ts = ""; if (talker.EndsWith("@chatroom")) { if (des == 1) { var txtsender = myself.DisplayName(); if (chatremark.ContainsKeySafe(myself.UsrName)) { txtsender = chatremark[myself.UsrName]; } else if (chatremark.ContainsKeySafe(myself.alias)) { txtsender = chatremark[myself.alias]; } ts += @"<tr><td width=""80"" align=""center""><img src=""avatar/" + myself.GetAndroidUserAvatar() + @""" width=""50"" height=""50"" /><br />" + txtsender + @"</td>"; } else { var enter = message.IndexOf(":\n"); if (enter > 0 && enter + 2 < message.Length) { var txtsender = message.Substring(0, enter); var senderid = txtsender; message = message.Substring(enter + 2); if (chatremark.ContainsKeySafe(txtsender)) { txtsender = chatremark[txtsender]; } else if (friends.ContainsKeySafe(txtsender)) { txtsender = friends[txtsender].DisplayName(); } if (friends.ContainsKeySafe(senderid)) { ts += @"<tr><td width=""80"" align=""center""><img src=""avatar/" + GetUserAvatar(senderid) + @""" width=""50"" height=""50"" /><br />" + txtsender + @"</td>"; } else { ts += @"<tr><td width=""80"" align=""center""><img src=""avatar/[email protected]"" width=""50"" height=""50"" /><br />" + txtsender + @"</td>"; } } else { ts += @"<tr><td width=""80"" align=""center""> </td>"; } } } else { if (des == 1) { ts += @"<tr><td width=""80"" align=""center""><img src=""avatar/" + myself.GetAndroidUserAvatar() + @""" width=""50"" height=""50"" /><br />" + myself.DisplayName() + @"</td>"; } else if (friend != null) { ts += @"<tr><td width=""80"" align=""center""><img src=""avatar/" + friend.GetAndroidUserAvatar() + @""" width=""50"" height=""50"" /><br />" + friend.DisplayName() + @"</td>"; } else { ts += @"<tr><td width=""80"" align=""center""><img src=""avatar/[email protected]"" width=""50"" height=""50"" /><br />" + friend.DisplayName() + @"</td>"; } } if (type == 34) { var voicelen = -1; string[] audioMsg = message.Split(':'); if (audioMsg.Length == 3) { voicelen = int.Parse(audioMsg[1]); } if (hasRes) { var audiosrc = GetVoicePath(msg.ImgPath); if (audiosrc == null) { message = voicelen == -1 ? "[语音]" : "[语音 " + Utils.DisplayTime(voicelen) + "]"; } else { Utils.ShellWait("lib\\silk_v3_decoder.exe", "\"" + audiosrc + "\" 1.pcm"); Utils.ShellWait("lib\\lame.exe", "-r -s 24000 --preset voice 1.pcm \"" + Path.Combine(userSaveDir, "voice2", msg.MsgId + ".mp3") + "\""); message = "<audio controls><source src=\"voice2/" + msg.MsgId + ".mp3\" type=\"audio/mpeg\"><a href=\"voice2" + msg.MsgId + ".mp3\">播放</a></audio>"; } } else { message = voicelen == -1 ? "[语音]" : "[语音 " + Utils.DisplayTime(voicelen) + "]"; } } else if (type == 47) { var match = Regex.Match(message, @"cdnurl ?= ?""(.+?)"""); if (match.Success) { var localfile = Utils.RemoveCdata(match.Groups[1].Value); var match2 = Regex.Match(localfile, @"\/(\w+?)\/\w*$"); if (!match2.Success) { localfile = Utils.RandomString(10); } else { localfile = match2.Groups[1].Value; } emojidown.Add(new DownloadTask() { url = match.Groups[1].Value, filename = localfile + ".gif" }); message = "<img src=\"Emoji/" + localfile + ".gif\" style=\"max-width:100px;max-height:60px\" />"; } else { message = "[表情]"; } } else if (type == 62) { message = "[视频]"; } else if (type == 50) { message = "[视频/语音通话]"; } else if (type == 3) { if (hasRes && GetImagePath(msg.ImgPath, out string thumPath, out string bigPath)) { if (thumPath != null && bigPath != null) { message = "<a href=\"image2/" + bigPath + "\"><img src=\"image2/" + thumPath + "\" style=\"max-width:100px;max-height:60px\" /></a>"; } else if (thumPath != null) { message = "<img src=\"image2/" + thumPath + "\" style=\"max-width:100px;max-height:60px\" />"; } else if (bigPath != null) { message = "<img src=\"image2/" + bigPath + "\" style=\"max-width:100px;max-height:60px\" />"; } } else { message = "[图片]"; } } else if (type == 48) { var match1 = Regex.Match(message, @"x ?= ?""(.+?)"""); var match2 = Regex.Match(message, @"y ?= ?""(.+?)"""); var match3 = Regex.Match(message, @"label ?= ?""(.+?)"""); if (match1.Success && match2.Success && match3.Success) { message = "[位置 (" + Utils.RemoveCdata(match2.Groups[1].Value) + "," + Utils.RemoveCdata(match1.Groups[1].Value) + ") " + Utils.RemoveCdata(match3.Groups[1].Value) + "]"; } else { message = "[位置]"; } } else if (type == 49) { if (message.Contains("<type>2001<")) { message = "[红包]"; } else if (message.Contains("<type>2000<")) { message = "[转账]"; } else if (message.Contains("<type>17<")) { message = "[实时位置共享]"; } else if (message.Contains("<type>6<")) { message = "[文件]"; } else { var match1 = Regex.Match(message, @"<title>(.+?)<\/title>"); var match2 = Regex.Match(message, @"<des>(.*?)<\/des>"); var match3 = Regex.Match(message, @"<url>(.+?)<\/url>"); var match4 = Regex.Match(message, @"<thumburl>(.+?)<\/thumburl>"); if (match1.Success && match3.Success) { message = ""; if (match4.Success) { message += "<img src=\"" + Utils.RemoveCdata(match4.Groups[1].Value) + "\" style=\"float:left;max-width:100px;max-height:60px\" />"; } message += "<a href=\"" + Utils.RemoveCdata(match3.Groups[1].Value) + "\"><b>" + Utils.RemoveCdata(match1.Groups[1].Value) + "</b></a>"; if (match2.Success) { message += "<br />" + Utils.RemoveCdata(match2.Groups[1].Value); } } else { message = "[链接]"; } } } else if (type == 42) { var match1 = Regex.Match(message, "nickname ?= ?\"(.+?)\""); var match2 = Regex.Match(message, "smallheadimgurl ?= ?\"(.+?)\""); if (match1.Success) { message = ""; if (match2.Success) { message += "<img src=\"" + Utils.RemoveCdata(match2.Groups[1].Value) + "\" style=\"float:left;max-width:100px;max-height:60px\" />"; } message += "[名片] " + Utils.RemoveCdata(match1.Groups[1].Value); } else { message = "[名片]"; } } else { message = Utils.SafeHTML(message); } ts += @"<td width=""100"" align=""center"">" + FromUnixTime(unixtime).ToLocalTime().ToString().Replace(" ", "<br />") + "</td>"; ts += @"<td>" + message + @"</td></tr>"; sw.WriteLine(ts); count++; if (count > maxCount) { break; } } catch (Exception) { } }