Quellcode durchsuchen

新增分析模块:聊天频率分析,全消息库内容搜索
新增强制搜索已删除人员(从消息库搜索)

Suxue vor 1 Jahr
Ursprung
Commit
5ccf928be8
9 geänderte Dateien mit 245 neuen und 23 gelöschten Zeilen
  1. 2 1
      .gitignore
  2. 36 0
      Analyse.xaml
  3. 106 0
      Analyse.xaml.cs
  4. 5 3
      Main.xaml
  5. 30 3
      Main.xaml.cs
  6. 10 0
      Model/WXModel.cs
  7. 9 6
      README.md
  8. 44 7
      WXUserReader.cs
  9. 3 3
      WechatPCMsgBakTool.csproj

+ 2 - 1
.gitignore

@@ -360,4 +360,5 @@ MigrationBackup/
 .ionide/
 
 # Fody - auto-generated XML schema
-FodyWeavers.xsd
+FodyWeavers.xsd
+/WechatPCMsgBakTool.csproj

+ 36 - 0
Analyse.xaml

@@ -0,0 +1,36 @@
+<Window x:Class="WechatPCMsgBakTool.Analyse"
+        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+        xmlns:local="clr-namespace:WechatPCMsgBakTool"
+        mc:Ignorable="d"
+        WindowStartupLocation="CenterScreen"
+        Title="溯雪微信备份工具-分析" Height="450" Width="900">
+    <Grid>
+        <ListView Name="list_msg_group" Margin="41,75,0,19" HorizontalAlignment="Left" Width="420" SelectionChanged="list_msg_group_SelectionChanged">
+            <ListView.View>
+                <GridView>
+                    <GridViewColumn Header="昵称" Width="120" DisplayMemberBinding="{Binding NickName}" />
+                    <GridViewColumn Header="原始ID" Width="120" DisplayMemberBinding="{Binding UserName}" />
+                    <GridViewColumn Header="数量" Width="140" DisplayMemberBinding="{Binding MsgCount}" />
+                </GridView>
+            </ListView.View>
+        </ListView>
+        <Button x:Name="btn_analyse" Content="分析" HorizontalAlignment="Left" Margin="42,43,0,0" VerticalAlignment="Top" Width="72" Click="btn_analyse_Click"/>
+        <Button x:Name="btn_copy_id" Content="复制id" HorizontalAlignment="Left" Margin="366,43,0,0" VerticalAlignment="Top" Width="94" Click="btn_copy_id_Click"/>
+
+        <ListView Name="list_msg_search" Margin="500,75,0,19" HorizontalAlignment="Left" Width="350">
+            <ListView.View>
+                <GridView>
+                    <GridViewColumn Header="原始ID" Width="120" DisplayMemberBinding="{Binding StrTalker}" />
+                    <GridViewColumn Header="消息" Width="200" DisplayMemberBinding="{Binding StrContent}" />
+                </GridView>
+            </ListView.View>
+        </ListView>
+        <TextBox Name="txt_search_text" HorizontalAlignment="Left" Margin="574,43,0,0" TextWrapping="Wrap" Text="" VerticalAlignment="Top" Width="120" Height="20"/>
+        <Label Content="消息搜索:" HorizontalAlignment="Left" Margin="504,41,0,0" VerticalAlignment="Top"/>
+        <Button x:Name="btn_search" Content="搜索" HorizontalAlignment="Left" Margin="708,43,0,0" VerticalAlignment="Top" Width="65" Click="btn_search_Click" />
+        <Button x:Name="btn_search_copy_id" Content="复制id" HorizontalAlignment="Left" Margin="784,43,0,0" VerticalAlignment="Top" Width="65" Click="btn_search_copy_id_Click" />
+    </Grid>
+</Window>

+ 106 - 0
Analyse.xaml.cs

@@ -0,0 +1,106 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Data;
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+using System.Windows.Shapes;
+using WechatPCMsgBakTool.Model;
+
+namespace WechatPCMsgBakTool
+{
+    /// <summary>
+    /// Analyse.xaml 的交互逻辑
+    /// </summary>
+    public partial class Analyse : Window
+    {
+        private UserBakConfig UserBakConfig;
+        private WXUserReader UserReader;
+        public Analyse(UserBakConfig userBakConfig,WXUserReader reader)
+        {
+            UserBakConfig = userBakConfig;
+            UserReader = reader;
+            InitializeComponent();
+        }
+
+        private void btn_analyse_Click(object sender, RoutedEventArgs e)
+        {
+            List<WXContact>? contacts = UserReader.GetWXContacts();
+            List<WXMsgGroup> list = UserReader.GetWXMsgGroup().OrderByDescending(x => x.MsgCount).ToList();
+            if(contacts == null)
+                contacts = new List<WXContact>();
+
+            foreach (WXMsgGroup item in list)
+            {
+                WXContact? contact = contacts.Find(x => x.UserName == item.UserName);
+                if (contact != null)
+                {
+                    item.NickName = contact.NickName;
+                }
+                else
+                    item.NickName = "已删除人员:" + item.UserName;
+            }
+            list_msg_group.ItemsSource = list;
+        }
+
+        private void btn_copy_id_Click(object sender, RoutedEventArgs e)
+        {
+            WXMsgGroup? msgGroup = list_msg_group.SelectedItem as WXMsgGroup;
+            if(msgGroup == null)
+            {
+                MessageBox.Show("请先选择数据");
+                return;
+            }
+            else
+            {
+                Clipboard.SetDataObject(msgGroup.UserName);
+            }
+            
+        }
+
+        private void list_msg_group_SelectionChanged(object sender, SelectionChangedEventArgs e)
+        {
+            WXMsgGroup? wXMsgGroup = list_msg_group.SelectedItem as WXMsgGroup;
+            if(wXMsgGroup != null)
+            {
+                List<WXMsg>? wXMsgs = UserReader.GetWXMsgs(wXMsgGroup.UserName);
+                if(wXMsgs != null)
+                {
+                    wXMsgs = wXMsgs.OrderByDescending(x => x.CreateTime).ToList();
+                    list_msg_search.ItemsSource = wXMsgs;
+                }
+                    
+            }
+        }
+
+        private void btn_search_Click(object sender, RoutedEventArgs e)
+        {
+            List<WXMsg>? wXMsgs = UserReader.GetWXMsgs("",txt_search_text.Text);
+            if (wXMsgs != null)
+            {
+                wXMsgs = wXMsgs.OrderByDescending(x => x.CreateTime).ToList();
+                list_msg_search.ItemsSource = wXMsgs;
+            }
+        }
+
+        private void btn_search_copy_id_Click(object sender, RoutedEventArgs e)
+        {
+            WXMsg? wxMsg = list_msg_search.SelectedItem as WXMsg;
+            if (wxMsg == null)
+            {
+                MessageBox.Show("请先选择数据");
+                return;
+            }
+            else
+            {
+                Clipboard.SetDataObject(wxMsg.StrTalker);
+            }
+        }
+    }
+}

+ 5 - 3
Main.xaml

@@ -30,9 +30,11 @@
                 </GridView>
             </ListView.View>
         </ListView>
-        <Button Content="导出所选人员聊天记录" HorizontalAlignment="Left" Margin="609,130,0,0" VerticalAlignment="Top" Width="142" Click="Button_Click"/>
+        <Button Content="导出所选人员聊天记录" HorizontalAlignment="Left" Margin="609,130,0,0" VerticalAlignment="Top" Width="140" Click="Button_Click"/>
         <Label Content="搜索:" HorizontalAlignment="Left" Margin="278,92,0,0" VerticalAlignment="Top"/>
-        <TextBox Name="find_user" HorizontalAlignment="Left" Margin="323,96,0,0" TextWrapping="Wrap" Text="" VerticalAlignment="Top" Width="120" Height="20"/>
-        <Button Name="btn_search" Content="搜索" HorizontalAlignment="Left" Margin="451,96,0,0" VerticalAlignment="Top" Width="43" Click="btn_search_Click"/>
+        <TextBox Name="find_user" HorizontalAlignment="Left" Margin="323,96,0,0" TextWrapping="Wrap" Text="" VerticalAlignment="Top" Width="194" Height="20"/>
+        <Button Name="btn_search" Content="搜索" HorizontalAlignment="Left" Margin="525,96,0,0" VerticalAlignment="Top" Width="43" Click="btn_search_Click"/>
+        <Button Name="btn_analyse" Content="消息分析工具" HorizontalAlignment="Left" Margin="609,160,0,0" VerticalAlignment="Top" Width="140" Click="btn_analyse_Click"/>
+        <CheckBox Name="cb_del_search" Content="已删除人员强制从记录搜索" HorizontalAlignment="Left" Margin="610,99,0,0" VerticalAlignment="Top"/>
     </Grid>
 </Window>

+ 30 - 3
Main.xaml.cs

@@ -146,7 +146,6 @@ namespace WechatPCMsgBakTool
             string path = Path.Combine(CurrentUserBakConfig.UserWorkspacePath, wXContact.UserName + ".html");
             export.Save(path);
             MessageBox.Show("导出完成");
-
         }
 
         private void Button_Click_1(object sender, RoutedEventArgs e)
@@ -167,7 +166,6 @@ namespace WechatPCMsgBakTool
                 {
                     MessageBox.Show("创建工作区失败,请检查路径是否正确");
                 }
-                
             }
         }
 
@@ -178,7 +176,36 @@ namespace WechatPCMsgBakTool
                 MessageBox.Show("请先读取工作区数据");
                 return;
             }
-            list_sessions.ItemsSource = UserReader.GetWXContacts(find_user.Text);
+            if(cb_del_search.IsChecked != null)
+            {
+                if (!(bool)cb_del_search.IsChecked)
+                    list_sessions.ItemsSource = UserReader.GetWXContacts(find_user.Text);
+                else
+                {
+                    List<WXMsg>? wXMsgs = UserReader.GetWXMsgs(find_user.Text);
+                    if(wXMsgs != null)
+                    {
+                        if(wXMsgs.Count > 0)
+                        {
+                            List<WXContact> wXContacts = new List<WXContact>() { new WXContact() { NickName = wXMsgs[0].StrTalker, UserName = wXMsgs[0].StrTalker } };
+                            list_sessions.ItemsSource = wXContacts;
+                        }
+                    }
+                }
+
+            }
+            
+        }
+
+        private void btn_analyse_Click(object sender, RoutedEventArgs e)
+        {
+            if(UserReader == null || CurrentUserBakConfig == null)
+            {
+                MessageBox.Show("请先读取数据");
+                return;
+            }
+            Analyse analyse = new Analyse(CurrentUserBakConfig, UserReader);
+            analyse.Show();
         }
     }
 }

+ 10 - 0
Model/WXModel.cs

@@ -24,6 +24,16 @@ namespace WechatPCMsgBakTool.Model
         }
     }
 
+    public class WXMsgGroup
+    {
+        [Column("StrTalker")]
+        public string UserName { get; set; } = "";
+
+        [Column("MsgCount")]
+        public int MsgCount { get; set; }
+        public string NickName { get; set; } = "";
+    }
+
     public class WXUserInfo
     {
         public string UserName { get; set; } = "";

+ 9 - 6
README.md

@@ -4,22 +4,25 @@
 - 支持3.9.6.33版本后,若版本更新可在version.json添加版本号和地址即可完成新版本支持
 - 导出图片、视频、音频
 - 导出Html文件
+- 支持聊天频率分析,全消息库内容搜索
 
-本项目仅做学习使用,供个人备份自己的微信,请勿做其他用途使用。
-
+本项目仅做学习使用,主要供个人备份自己的微信记录,请勿用于非法用途。
 本项目严禁商用。
+如果有什么好的建议或意见,或者遇到什么问题,欢迎提issue,看到会回。
 
 #### 使用
 <p>1.打开微信,并登录。</p>
 <p>2.在工作区上方点击新增,选择要创建的工作区微信</p>
-<p>3.选中刚刚创建的工作区,点击解密。(如当前多开微信,请选择对应的微信进行解谜)</p>
-<p>4.选中刚刚创建的工作区,点击读取</p>
+<p>3.点新建会弹出Handle64的协议说明,同意即可。如没有内容显示,重新点一下新建即可</p>
+<p>4.选中刚刚创建的工作区,点击解密。(如当前多开微信,请选择对应的微信进行解谜)</p>
+<p>5.选中刚刚创建的工作区,点击读取</p>
 <p><b>尽情使用吧!</b></p>
 
 #### 注意
+<p>本项目基于.NET开发,需要安装.NET Desktop Runtime,如未安装,双击EXE时会提示。</p>
 <p>如果使用过程中发生崩溃,请删除工作区试一下,工作区即根据用户名在运行目录下生成的md5文件夹。</p>
-<p>已解谜的工作区可以直接读取</p>
-<p>再次强调,仅供个人备份自己微信使用 </p>
+<p>已解密的工作区可以直接读取。</p>
+<p>再次强调,主要用于个人备份自己微信使用,请勿用于非法用途,严禁商用!</p>
 
 #### 参考/引用
 都是站在大佬们的肩膀上完成的项目,本项目 参考/引用 了以下 项目/文章 内代码。

+ 44 - 7
WXUserReader.cs

@@ -52,7 +52,7 @@ namespace WechatPCMsgBakTool
             return con.Query<WXContact>(query);
         }
 
-        public List<WXMsg>? GetWXMsgs(string uid)
+        public List<WXMsg>? GetWXMsgs(string uid,string msg = "")
         {
             List<WXMsg> tmp = new List<WXMsg>();
             for (int i = 0; i <= 99; i++)
@@ -63,8 +63,23 @@ namespace WechatPCMsgBakTool
                     if (con == null)
                         return tmp;
 
-                    string query = "select * from MSG where StrTalker=?";
-                    List<WXMsg> wXMsgs = con.Query<WXMsg>(query, uid);
+                    List<WXMsg>? wXMsgs = null;
+                    if (msg == "")
+                    {
+                        string query = "select * from MSG where StrTalker=?";
+                        wXMsgs = con.Query<WXMsg>(query, uid);
+                    }
+                    else if(uid == "")
+                    {
+                        string query = "select * from MSG where StrContent like ?";
+                        wXMsgs = con.Query<WXMsg>(query, string.Format("%{0}%", msg));
+                    }
+                    else
+                    {
+                        string query = "select * from MSG where StrTalker=? and StrContent like ?";
+                        wXMsgs = con.Query<WXMsg>(query, uid, string.Format("%{0}%", msg));
+                    }
+
                     foreach (WXMsg w in wXMsgs)
                     {
                         tmp.Add(w);
@@ -73,7 +88,6 @@ namespace WechatPCMsgBakTool
             }
             return tmp;
         }
-
         public WXSessionAttachInfo? GetWXMsgAtc(WXMsg msg)
         {
             SQLiteConnection con = DBInfo["MultiSearchChatMsg"];
@@ -101,7 +115,6 @@ namespace WechatPCMsgBakTool
             else
                 return null;
         }
-
         public WXMediaMsg? GetVoiceMsg(WXMsg msg)
         {
             for (int i = 0; i <= 99; i++)
@@ -120,7 +133,6 @@ namespace WechatPCMsgBakTool
             }
             return null;
         }
-
         public string? GetAttachment(WXMsgType type, WXMsg msg)
         {
             if (UserBakConfig == null)
@@ -182,7 +194,7 @@ namespace WechatPCMsgBakTool
             if (path == null)
                 return null;
 
-            // 相对路径
+            // 相对路径
             path = path.Replace(UserBakConfig.UserWorkspacePath + "\\", "");
             return path;
 
@@ -217,6 +229,31 @@ namespace WechatPCMsgBakTool
             }
             return file_path;
         }
+        public List<WXMsgGroup> GetWXMsgGroup()
+        {
+            List<WXMsgGroup> g = new List<WXMsgGroup>();
+            for (int i = 0; i <= 99; i++)
+            {
+                if (DBInfo.ContainsKey("MSG" + i.ToString()))
+                {
+                    SQLiteConnection con = DBInfo["MSG" + i.ToString()];
+                    if (con == null)
+                        return g;
+
+                    string query = "select StrTalker,Count(localId) as MsgCount from MSG GROUP BY StrTalker";
+                    List<WXMsgGroup> wXMsgs = con.Query<WXMsgGroup>(query);
+                    foreach (WXMsgGroup w in wXMsgs)
+                    {
+                        WXMsgGroup? tmp = g.Find(x => x.UserName == w.UserName);
+                        if (tmp == null)
+                            g.Add(w);
+                        else
+                            tmp.MsgCount += g.Count;
+                    }
+                }
+            }
+            return g;
+        }
     }
 
     public enum WXMsgType

+ 3 - 3
WechatPCMsgBakTool.csproj

@@ -6,9 +6,9 @@
     <Nullable>enable</Nullable>
     <UseWPF>true</UseWPF>
     <AllowUnsafeBlocks>True</AllowUnsafeBlocks>
-    <AssemblyVersion>0.3.1.0</AssemblyVersion>
-    <FileVersion>0.3.1.0</FileVersion>
-    <Version>0.3.1.0</Version>
+    <AssemblyVersion>0.4.0.0</AssemblyVersion>
+    <FileVersion>0.4.0.0</FileVersion>
+    <Version>0.4.0.0</Version>
   </PropertyGroup>
 
   <ItemGroup>