mirror of
https://github.com/LC044/WeChatMsg
synced 2025-04-29 01:08:11 +08:00
Merge branch 'master' into master
This commit is contained in:
commit
050920d2c0
@ -63,6 +63,37 @@ class MicroMsg:
|
|||||||
lock.release()
|
lock.release()
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
def get_contact_by_username(self, username):
|
||||||
|
if not self.open_flag:
|
||||||
|
return None
|
||||||
|
try:
|
||||||
|
lock.acquire(True)
|
||||||
|
sql = '''SELECT UserName, Alias, Type, Remark, NickName, PYInitial, RemarkPYInitial, ContactHeadImgUrl.smallHeadImgUrl, ContactHeadImgUrl.bigHeadImgUrl
|
||||||
|
FROM Contact
|
||||||
|
INNER JOIN ContactHeadImgUrl ON Contact.UserName = ContactHeadImgUrl.usrName
|
||||||
|
WHERE UserName = ?
|
||||||
|
'''
|
||||||
|
self.cursor.execute(sql, [username])
|
||||||
|
result = self.cursor.fetchone()
|
||||||
|
finally:
|
||||||
|
lock.release()
|
||||||
|
return result
|
||||||
|
|
||||||
|
def get_chatroom_info(self, chatroomname):
|
||||||
|
'''
|
||||||
|
获取群聊信息
|
||||||
|
'''
|
||||||
|
if not self.open_flag:
|
||||||
|
return None
|
||||||
|
try:
|
||||||
|
lock.acquire(True)
|
||||||
|
sql = '''SELECT ChatRoomName, RoomData FROM ChatRoom WHERE ChatRoomName = ?'''
|
||||||
|
self.cursor.execute(sql, [chatroomname])
|
||||||
|
result = self.cursor.fetchone()
|
||||||
|
finally:
|
||||||
|
lock.release()
|
||||||
|
return result
|
||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
if self.open_flag:
|
if self.open_flag:
|
||||||
try:
|
try:
|
||||||
|
@ -72,7 +72,7 @@ class Msg:
|
|||||||
|
|
||||||
def get_messages_all(self):
|
def get_messages_all(self):
|
||||||
sql = '''
|
sql = '''
|
||||||
select localId,TalkerId,Type,SubType,IsSender,CreateTime,Status,StrContent,strftime('%Y-%m-%d %H:%M:%S',CreateTime,'unixepoch','localtime') as StrTime,MsgSvrID
|
select localId,TalkerId,Type,SubType,IsSender,CreateTime,Status,StrContent,strftime('%Y-%m-%d %H:%M:%S',CreateTime,'unixepoch','localtime') as StrTime,MsgSvrID,BytesExtra,StrTalker,Reserved1
|
||||||
from MSG
|
from MSG
|
||||||
order by CreateTime
|
order by CreateTime
|
||||||
'''
|
'''
|
||||||
@ -126,19 +126,19 @@ class Msg:
|
|||||||
lock.release()
|
lock.release()
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def get_messages_by_keyword(self, username_, keyword, num=5):
|
def get_messages_by_keyword(self, username_, keyword, num=5, max_len=10):
|
||||||
if not self.open_flag:
|
if not self.open_flag:
|
||||||
return None
|
return None
|
||||||
sql = '''
|
sql = '''
|
||||||
select localId,TalkerId,Type,SubType,IsSender,CreateTime,Status,StrContent,strftime('%Y-%m-%d %H:%M:%S',CreateTime,'unixepoch','localtime') as StrTime,MsgSvrID
|
select localId,TalkerId,Type,SubType,IsSender,CreateTime,Status,StrContent,strftime('%Y-%m-%d %H:%M:%S',CreateTime,'unixepoch','localtime') as StrTime,MsgSvrID
|
||||||
from MSG
|
from MSG
|
||||||
where StrTalker=? and Type=1 and StrContent like ?
|
where StrTalker=? and Type=1 and LENGTH(StrContent)<? and StrContent like ?
|
||||||
order by CreateTime desc
|
order by CreateTime desc
|
||||||
'''
|
'''
|
||||||
temp = []
|
temp = []
|
||||||
try:
|
try:
|
||||||
lock.acquire(True)
|
lock.acquire(True)
|
||||||
self.cursor.execute(sql, [username_, f'%{keyword}%'])
|
self.cursor.execute(sql, [username_, max_len, f'%{keyword}%'])
|
||||||
messages = self.cursor.fetchall()
|
messages = self.cursor.fetchall()
|
||||||
finally:
|
finally:
|
||||||
lock.release()
|
lock.release()
|
||||||
@ -213,4 +213,4 @@ if __name__ == '__main__':
|
|||||||
pprint(msg.get_message_by_num('wxid_0o18ef858vnu22', local_id))
|
pprint(msg.get_message_by_num('wxid_0o18ef858vnu22', local_id))
|
||||||
print(msg.get_messages_by_keyword(wxid, '干嘛'))
|
print(msg.get_messages_by_keyword(wxid, '干嘛'))
|
||||||
pprint(msg.get_messages_by_keyword(wxid, '干嘛')[0])
|
pprint(msg.get_messages_by_keyword(wxid, '干嘛')[0])
|
||||||
print(msg.get_first_time_of_message('wxid_0o18ef858vnu22'))
|
print(msg.get_first_time_of_message('wxid_fervbwign7m822'))
|
||||||
|
@ -5,13 +5,23 @@ import os
|
|||||||
from PyQt5.QtCore import pyqtSignal, QThread
|
from PyQt5.QtCore import pyqtSignal, QThread
|
||||||
|
|
||||||
from . import msg_db
|
from . import msg_db
|
||||||
|
from .package_msg import PackageMsg
|
||||||
from ..DataBase import hard_link_db
|
from ..DataBase import hard_link_db
|
||||||
from ..person_pc import MePC
|
from ..person_pc import MePC
|
||||||
from ..util import get_abs_path
|
from ..util import path
|
||||||
|
|
||||||
os.makedirs('./data/聊天记录', exist_ok=True)
|
os.makedirs('./data/聊天记录', exist_ok=True)
|
||||||
|
|
||||||
|
|
||||||
|
def makedirs(path):
|
||||||
|
os.makedirs(path,exist_ok=True)
|
||||||
|
os.makedirs(os.path.join(path, 'image'), exist_ok=True)
|
||||||
|
os.makedirs(os.path.join(path, 'emoji'), exist_ok=True)
|
||||||
|
os.makedirs(os.path.join(path, 'video'), exist_ok=True)
|
||||||
|
os.makedirs(os.path.join(path, 'voice'), exist_ok=True)
|
||||||
|
os.makedirs(os.path.join(path, 'file'), exist_ok=True)
|
||||||
|
|
||||||
|
|
||||||
def escape_js_and_html(input_str):
|
def escape_js_and_html(input_str):
|
||||||
# 转义HTML特殊字符
|
# 转义HTML特殊字符
|
||||||
html_escaped = html.escape(input_str, quote=False)
|
html_escaped = html.escape(input_str, quote=False)
|
||||||
@ -65,8 +75,10 @@ class Output(QThread):
|
|||||||
# columns = ["用户名", "消息内容", "发送时间", "发送状态", "消息类型", "isSend", "msgId"]
|
# columns = ["用户名", "消息内容", "发送时间", "发送状态", "消息类型", "isSend", "msgId"]
|
||||||
columns = ['localId', 'TalkerId', 'Type', 'SubType',
|
columns = ['localId', 'TalkerId', 'Type', 'SubType',
|
||||||
'IsSender', 'CreateTime', 'Status', 'StrContent',
|
'IsSender', 'CreateTime', 'Status', 'StrContent',
|
||||||
'StrTime']
|
'StrTime', 'Remark', 'NickName', 'Sender']
|
||||||
messages = msg_db.get_messages_all()
|
# messages = msg_db.get_messages_all()
|
||||||
|
packagemsg = PackageMsg()
|
||||||
|
messages = packagemsg.get_package_message_all()
|
||||||
# 写入CSV文件
|
# 写入CSV文件
|
||||||
with open(filename, mode='w', newline='', encoding='utf-8') as file:
|
with open(filename, mode='w', newline='', encoding='utf-8') as file:
|
||||||
writer = csv.writer(file)
|
writer = csv.writer(file)
|
||||||
@ -165,8 +177,10 @@ class ChildThread(QThread):
|
|||||||
# columns = ["用户名", "消息内容", "发送时间", "发送状态", "消息类型", "isSend", "msgId"]
|
# columns = ["用户名", "消息内容", "发送时间", "发送状态", "消息类型", "isSend", "msgId"]
|
||||||
columns = ['localId', 'TalkerId', 'Type', 'SubType',
|
columns = ['localId', 'TalkerId', 'Type', 'SubType',
|
||||||
'IsSender', 'CreateTime', 'Status', 'StrContent',
|
'IsSender', 'CreateTime', 'Status', 'StrContent',
|
||||||
'StrTime']
|
'StrTime', 'Remark', 'NickName', 'Sender']
|
||||||
messages = msg_db.get_messages_all()
|
# messages = msg_db.get_messages_all()
|
||||||
|
packagemsg = PackageMsg()
|
||||||
|
messages = packagemsg.get_package_message_all()
|
||||||
# 写入CSV文件
|
# 写入CSV文件
|
||||||
with open(filename, mode='w', newline='', encoding='utf-8') as file:
|
with open(filename, mode='w', newline='', encoding='utf-8') as file:
|
||||||
writer = csv.writer(file)
|
writer = csv.writer(file)
|
||||||
@ -434,7 +448,7 @@ class ChildThread(QThread):
|
|||||||
|
|
||||||
def to_html_(self):
|
def to_html_(self):
|
||||||
origin_docx_path = f"{os.path.abspath('.')}/data/聊天记录/{self.contact.remark}"
|
origin_docx_path = f"{os.path.abspath('.')}/data/聊天记录/{self.contact.remark}"
|
||||||
os.makedirs(origin_docx_path, exist_ok=True)
|
makedirs(origin_docx_path)
|
||||||
messages = msg_db.get_messages(self.contact.wxid)
|
messages = msg_db.get_messages(self.contact.wxid)
|
||||||
filename = f"{os.path.abspath('.')}/data/聊天记录/{self.contact.remark}/{self.contact.remark}.html"
|
filename = f"{os.path.abspath('.')}/data/聊天记录/{self.contact.remark}/{self.contact.remark}.html"
|
||||||
f = open(filename, 'w', encoding='utf-8')
|
f = open(filename, 'w', encoding='utf-8')
|
||||||
@ -671,6 +685,13 @@ input {
|
|||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.emoji_img {
|
||||||
|
width: 26px;
|
||||||
|
height: 26px;
|
||||||
|
position: relative;
|
||||||
|
bottom: -6px;
|
||||||
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
@ -723,6 +744,116 @@ const chatMessages = [
|
|||||||
MePC().avatar.save(os.path.join(origin_docx_path, 'myhead.png'))
|
MePC().avatar.save(os.path.join(origin_docx_path, 'myhead.png'))
|
||||||
self.contact.avatar.save(os.path.join(origin_docx_path, 'tahead.png'))
|
self.contact.avatar.save(os.path.join(origin_docx_path, 'tahead.png'))
|
||||||
self.rangeSignal.emit(len(messages))
|
self.rangeSignal.emit(len(messages))
|
||||||
|
emoji = {
|
||||||
|
'[微笑]': '<img src="https://res.wx.qq.com/t/wx_fed/we-emoji/res/v1.2.8/assets/Expression/Expression_1@2x.png" id="微笑" class="emoji_img">',
|
||||||
|
'[撇嘴]': '<img src="https://res.wx.qq.com/t/wx_fed/we-emoji/res/v1.2.8/assets/Expression/Expression_2@2x.png" id="撇嘴" class="emoji_img">',
|
||||||
|
'[色]': '<img src="https://res.wx.qq.com/t/wx_fed/we-emoji/res/v1.2.8/assets/Expression/Expression_3@2x.png" id="色" class="emoji_img">',
|
||||||
|
'[发呆]': '<img src="https://res.wx.qq.com/t/wx_fed/we-emoji/res/v1.2.8/assets/Expression/Expression_4@2x.png" id="发呆" class="emoji_img">',
|
||||||
|
'[得意]': '<img src="https://res.wx.qq.com/t/wx_fed/we-emoji/res/v1.2.8/assets/Expression/Expression_5@2x.png" id="得意" class="emoji_img">',
|
||||||
|
'[流泪]': '<img src="https://res.wx.qq.com/t/wx_fed/we-emoji/res/v1.2.8/assets/Expression/Expression_6@2x.png" id="流泪" class="emoji_img">',
|
||||||
|
'[害羞]': '<img src="https://res.wx.qq.com/t/wx_fed/we-emoji/res/v1.2.8/assets/Expression/Expression_7@2x.png" id="害羞" class="emoji_img">',
|
||||||
|
'[闭嘴]': '<img src="https://res.wx.qq.com/t/wx_fed/we-emoji/res/v1.2.8/assets/Expression/Expression_8@2x.png" id="闭嘴" class="emoji_img">',
|
||||||
|
'[睡]': '<img src="https://res.wx.qq.com/t/wx_fed/we-emoji/res/v1.2.8/assets/Expression/Expression_9@2x.png" id="睡" class="emoji_img">',
|
||||||
|
'[大哭]': '<img src="https://res.wx.qq.com/t/wx_fed/we-emoji/res/v1.2.8/assets/Expression/Expression_10@2x.png" id="大哭" class="emoji_img">',
|
||||||
|
'[尴尬]': '<img src="https://res.wx.qq.com/t/wx_fed/we-emoji/res/v1.2.8/assets/Expression/Expression_11@2x.png" id="尴尬" class="emoji_img">',
|
||||||
|
'[发怒]': '<img src="https://res.wx.qq.com/t/wx_fed/we-emoji/res/v1.2.8/assets/Expression/Expression_12@2x.png" id="发怒" class="emoji_img">',
|
||||||
|
'[调皮]': '<img src="https://res.wx.qq.com/t/wx_fed/we-emoji/res/v1.2.8/assets/Expression/Expression_13@2x.png" id="调皮" class="emoji_img">',
|
||||||
|
'[呲牙]': '<img src="https://res.wx.qq.com/t/wx_fed/we-emoji/res/v1.2.8/assets/Expression/Expression_14@2x.png" id="呲牙" class="emoji_img">',
|
||||||
|
'[惊讶]': '<img src="https://res.wx.qq.com/t/wx_fed/we-emoji/res/v1.2.8/assets/Expression/Expression_15@2x.png" id="惊讶" class="emoji_img">',
|
||||||
|
'[难过]': '<img src="https://res.wx.qq.com/t/wx_fed/we-emoji/res/v1.2.8/assets/Expression/Expression_16@2x.png" id="难过" class="emoji_img">',
|
||||||
|
'[抓狂]': '<img src="https://res.wx.qq.com/t/wx_fed/we-emoji/res/v1.2.8/assets/Expression/Expression_19@2x.png" id="抓狂" class="emoji_img">',
|
||||||
|
'[吐]': '<img src="https://res.wx.qq.com/t/wx_fed/we-emoji/res/v1.2.8/assets/Expression/Expression_20@2x.png" id="吐" class="emoji_img">',
|
||||||
|
'[偷笑]': '<img src="https://res.wx.qq.com/t/wx_fed/we-emoji/res/v1.2.8/assets/Expression/Expression_21@2x.png" id="偷笑" class="emoji_img">',
|
||||||
|
'[愉快]': '<img src="https://res.wx.qq.com/t/wx_fed/we-emoji/res/v1.2.8/assets/Expression/Expression_22@2x.png" id="愉快" class="emoji_img">',
|
||||||
|
'[白眼]': '<img src="https://res.wx.qq.com/t/wx_fed/we-emoji/res/v1.2.8/assets/Expression/Expression_23@2x.png" id="白 眼" class="emoji_img">',
|
||||||
|
'[傲慢]': '<img src="https://res.wx.qq.com/t/wx_fed/we-emoji/res/v1.2.8/assets/Expression/Expression_24@2x.png" id="傲慢" class="emoji_img">',
|
||||||
|
'[困]': '<img src="https://res.wx.qq.com/t/wx_fed/we-emoji/res/v1.2.8/assets/Expression/Expression_26@2x.png" id="困" class="emoji_img">',
|
||||||
|
'[惊恐]': '<img src="https://res.wx.qq.com/t/wx_fed/we-emoji/res/v1.2.8/assets/Expression/Expression_27@2x.png" id="惊恐" class="emoji_img">',
|
||||||
|
'[憨笑]': '<img src="https://res.wx.qq.com/t/wx_fed/we-emoji/res/v1.2.8/assets/Expression/Expression_29@2x.png" id="憨笑" class="emoji_img">',
|
||||||
|
'[悠闲]': '<img src="https://res.wx.qq.com/t/wx_fed/we-emoji/res/v1.2.8/assets/Expression/Expression_30@2x.png" id="悠闲" class="emoji_img">',
|
||||||
|
'[咒骂]': '<img src="https://res.wx.qq.com/t/wx_fed/we-emoji/res/v1.2.8/assets/Expression/Expression_32@2x.png" id="咒骂" class="emoji_img">',
|
||||||
|
'[疑问]': '<img src="https://res.wx.qq.com/t/wx_fed/we-emoji/res/v1.2.8/assets/Expression/Expression_33@2x.png" id="疑问" class="emoji_img">',
|
||||||
|
'[嘘]': '<img src="https://res.wx.qq.com/t/wx_fed/we-emoji/res/v1.2.8/assets/Expression/Expression_34@2x.png" id="嘘" class="emoji_img">',
|
||||||
|
'[晕]': '<img src="https://res.wx.qq.com/t/wx_fed/we-emoji/res/v1.2.8/assets/Expression/Expression_35@2x.png" id="晕" class="emoji_img">',
|
||||||
|
'[衰]': '<img src="https://res.wx.qq.com/t/wx_fed/we-emoji/res/v1.2.8/assets/Expression/Expression_37@2x.png" id="衰" class="emoji_img">',
|
||||||
|
'[骷髅]': '<img src="https://res.wx.qq.com/t/wx_fed/we-emoji/res/v1.2.8/assets/Expression/Expression_38@2x.png" id="骷髅" class="emoji_img">',
|
||||||
|
'[敲打]': '<img src="https://res.wx.qq.com/t/wx_fed/we-emoji/res/v1.2.8/assets/Expression/Expression_39@2x.png" id="敲打" class="emoji_img">',
|
||||||
|
'[再见]': '<img src="https://res.wx.qq.com/t/wx_fed/we-emoji/res/v1.2.8/assets/Expression/Expression_40@2x.png" id="再见" class="emoji_img">',
|
||||||
|
'[擦汗]': '<img src="https://res.wx.qq.com/t/wx_fed/we-emoji/res/v1.2.8/assets/Expression/Expression_41@2x.png" id="擦汗" class="emoji_img">',
|
||||||
|
'[抠鼻]': '<img src="https://res.wx.qq.com/t/wx_fed/we-emoji/res/v1.2.8/assets/Expression/Expression_42@2x.png" id="抠鼻" class="emoji_img">',
|
||||||
|
'[鼓掌]': '<img src="https://res.wx.qq.com/t/wx_fed/we-emoji/res/v1.2.8/assets/Expression/Expression_43@2x.png" id="鼓掌" class="emoji_img">',
|
||||||
|
'[坏笑]': '<img src="https://res.wx.qq.com/t/wx_fed/we-emoji/res/v1.2.8/assets/Expression/Expression_45@2x.png" id="坏笑" class="emoji_img">',
|
||||||
|
'[右哼哼]': '<img src="https://res.wx.qq.com/t/wx_fed/we-emoji/res/v1.2.8/assets/Expression/Expression_47@2x.png" id="右哼哼" class="emoji_img">',
|
||||||
|
'[鄙视]': '<img src="https://res.wx.qq.com/t/wx_fed/we-emoji/res/v1.2.8/assets/Expression/Expression_49@2x.png" id="鄙视" class="emoji_img">',
|
||||||
|
'[委屈]': '<img src="https://res.wx.qq.com/t/wx_fed/we-emoji/res/v1.2.8/assets/Expression/Expression_50@2x.png" id="委屈" class="emoji_img">',
|
||||||
|
'[快哭了]': '<img src="https://res.wx.qq.com/t/wx_fed/we-emoji/res/v1.2.8/assets/Expression/Expression_51@2x.png" id="快哭了" class="emoji_img">',
|
||||||
|
'[阴险]': '<img src="https://res.wx.qq.com/t/wx_fed/we-emoji/res/v1.2.8/assets/Expression/Expression_52@2x.png" id="阴险" class="emoji_img">',
|
||||||
|
'[亲亲]': '<img src="https://res.wx.qq.com/t/wx_fed/we-emoji/res/v1.2.8/assets/Expression/Expression_53@2x.png" id="亲亲" class="emoji_img">',
|
||||||
|
'[可怜]': '<img src="https://res.wx.qq.com/t/wx_fed/we-emoji/res/v1.2.8/assets/Expression/Expression_55@2x.png" id="可怜" class="emoji_img">',
|
||||||
|
'[笑脸]': '<img src="https://res.wx.qq.com/t/wx_fed/we-emoji/res/v1.2.8/assets/newemoji/Happy.png" id="笑脸" class="emoji_img">',
|
||||||
|
'[生病]': '<img src="https://res.wx.qq.com/t/wx_fed/we-emoji/res/v1.2.8/assets/newemoji/Sick.png" id="生病" class="emoji_img">',
|
||||||
|
'[脸红]': '<img src="https://res.wx.qq.com/t/wx_fed/we-emoji/res/v1.2.8/assets/newemoji/Flushed.png" id="脸红" class="emoji_img">',
|
||||||
|
'[破涕为笑]': '<img src="https://res.wx.qq.com/t/wx_fed/we-emoji/res/v1.2.8/assets/newemoji/Lol.png" id="破涕为笑" class="emoji_img">',
|
||||||
|
'[恐惧]': '<img src="https://res.wx.qq.com/t/wx_fed/we-emoji/res/v1.2.8/assets/newemoji/Terror.png" id="恐惧" class="emoji_img">',
|
||||||
|
'[失望]': '<img src="https://res.wx.qq.com/t/wx_fed/we-emoji/res/v1.2.8/assets/newemoji/LetDown.png" id="失望" class="emoji_img">',
|
||||||
|
'[无语]': '<img src="https://res.wx.qq.com/t/wx_fed/we-emoji/res/v1.2.8/assets/newemoji/Duh.png" id="无语" class="emoji_img">',
|
||||||
|
'[嘿哈]': '<img src="https://res.wx.qq.com/t/wx_fed/we-emoji/res/v1.2.8/assets/newemoji/2_04.png" id="嘿哈" class="emoji_img">',
|
||||||
|
'[捂脸]': '<img src="https://res.wx.qq.com/t/wx_fed/we-emoji/res/v1.2.8/assets/newemoji/2_05.png" id="捂脸" class="emoji_img">',
|
||||||
|
'[奸笑]': '<img src="https://res.wx.qq.com/t/wx_fed/we-emoji/res/v1.2.8/assets/newemoji/2_02.png" id="奸笑" class="emoji_img">',
|
||||||
|
'[机智]': '<img src="https://res.wx.qq.com/t/wx_fed/we-emoji/res/v1.2.8/assets/newemoji/2_06.png" id="机智" class="emoji_img">',
|
||||||
|
'[皱眉]': '<img src="https://res.wx.qq.com/t/wx_fed/we-emoji/res/v1.2.8/assets/newemoji/2_12.png" id="皱眉" class="emoji_img">',
|
||||||
|
'[耶]': '<img src="https://res.wx.qq.com/t/wx_fed/we-emoji/res/v1.2.8/assets/newemoji/2_11.png" id="耶" class="emoji_img">',
|
||||||
|
'[吃瓜]': '<img src="https://res.wx.qq.com/t/wx_fed/we-emoji/res/v1.2.8/assets/newemoji/Watermelon.png" id="吃瓜" class="emoji_img">',
|
||||||
|
'[加油]': '<img src="https://res.wx.qq.com/t/wx_fed/we-emoji/res/v1.2.8/assets/newemoji/Addoil.png" id="加油" class="emoji_img">',
|
||||||
|
'[汗]': '<img src="https://res.wx.qq.com/t/wx_fed/we-emoji/res/v1.2.8/assets/newemoji/Sweat.png" id="汗" class="emoji_img">',
|
||||||
|
'[天啊]': '<img src="https://res.wx.qq.com/t/wx_fed/we-emoji/res/v1.2.8/assets/newemoji/Shocked.png" id="天啊" class="emoji_img">',
|
||||||
|
'[Emm]': '<img src="https://res.wx.qq.com/t/wx_fed/we-emoji/res/v1.2.8/assets/newemoji/Cold.png" id="Emm" class="emoji_img">',
|
||||||
|
'[社会社会]': '<img src="https://res.wx.qq.com/t/wx_fed/we-emoji/res/v1.2.8/assets/newemoji/Social.png" id="社会社会" class="emoji_img">',
|
||||||
|
'[旺柴]': '<img src="https://res.wx.qq.com/t/wx_fed/we-emoji/res/v1.2.8/assets/newemoji/Yellowdog.png" id="旺柴" class="emoji_img">',
|
||||||
|
'[好的]': '<img src="https://res.wx.qq.com/t/wx_fed/we-emoji/res/v1.2.8/assets/newemoji/NoProb.png" id="好的" class="emoji_img">',
|
||||||
|
'[打脸]': '<img src="https://res.wx.qq.com/t/wx_fed/we-emoji/res/v1.2.8/assets/newemoji/Slap.png" id="打脸" class="emoji_img">',
|
||||||
|
'[哇]': '<img src="https://res.wx.qq.com/t/wx_fed/we-emoji/res/v1.2.8/assets/newemoji/Wow.png" id="哇" class="emoji_img">',
|
||||||
|
'[翻白眼]': '<img src="https://res.wx.qq.com/t/wx_fed/we-emoji/res/v1.2.8/assets/newemoji/Boring.png" id="翻白眼" class="emoji_img">',
|
||||||
|
'[666]': '<img src="https://res.wx.qq.com/t/wx_fed/we-emoji/res/v1.2.8/assets/newemoji/666.png" id="666" class="emoji_img">',
|
||||||
|
'[让我看看]': '<img src="https://res.wx.qq.com/t/wx_fed/we-emoji/res/v1.2.8/assets/newemoji/LetMeSee.png" id="让我看看" class="emoji_img">',
|
||||||
|
'[叹气]': '<img src="https://res.wx.qq.com/t/wx_fed/we-emoji/res/v1.2.8/assets/newemoji/Sigh.png" id="叹气" class="emoji_img">',
|
||||||
|
'[苦涩]': '<img src="https://res.wx.qq.com/t/wx_fed/we-emoji/res/v1.2.8/assets/newemoji/Hurt.png" id="苦涩" class="emoji_img">',
|
||||||
|
'[裂开]': '<img src="https://res.wx.qq.com/t/wx_fed/we-emoji/res/v1.2.8/assets/newemoji/Broken.png" id="裂开" class="emoji_img">',
|
||||||
|
'[嘴唇]': '<img src="https://res.wx.qq.com/t/wx_fed/we-emoji/res/v1.2.8/assets/Expression/Expression_66@2x.png" id="嘴唇" class="emoji_img">',
|
||||||
|
'[爱心]': '<img src="https://res.wx.qq.com/t/wx_fed/we-emoji/res/v1.2.8/assets/Expression/Expression_67@2x.png" id="爱心" class="emoji_img">',
|
||||||
|
'[心碎]': '<img src="https://res.wx.qq.com/t/wx_fed/we-emoji/res/v1.2.8/assets/Expression/Expression_68@2x.png" id="心碎" class="emoji_img">',
|
||||||
|
'[拥抱]': '<img src="https://res.wx.qq.com/t/wx_fed/we-emoji/res/v1.2.8/assets/Expression/Expression_79@2x.png" id="拥抱" class="emoji_img">',
|
||||||
|
'[强]': '<img src="https://res.wx.qq.com/t/wx_fed/we-emoji/res/v1.2.8/assets/Expression/Expression_80@2x.png" id="强" class="emoji_img">',
|
||||||
|
'[弱]': '<img src="https://res.wx.qq.com/t/wx_fed/we-emoji/res/v1.2.8/assets/Expression/Expression_81@2x.png" id="弱" class="emoji_img">',
|
||||||
|
'[握手]': '<img src="https://res.wx.qq.com/t/wx_fed/we-emoji/res/v1.2.8/assets/Expression/Expression_82@2x.png" id="握手" class="emoji_img">',
|
||||||
|
'[胜利]': '<img src="https://res.wx.qq.com/t/wx_fed/we-emoji/res/v1.2.8/assets/Expression/Expression_83@2x.png" id="胜利" class="emoji_img">',
|
||||||
|
'[抱拳]': '<img src="https://res.wx.qq.com/t/wx_fed/we-emoji/res/v1.2.8/assets/Expression/Expression_84@2x.png" id="抱拳" class="emoji_img">',
|
||||||
|
'[勾引]': '<img src="https://res.wx.qq.com/t/wx_fed/we-emoji/res/v1.2.8/assets/Expression/Expression_85@2x.png" id="勾引" class="emoji_img">',
|
||||||
|
'[拳头]': '<img src="https://res.wx.qq.com/t/wx_fed/we-emoji/res/v1.2.8/assets/Expression/Expression_86@2x.png" id="拳头" class="emoji_img">',
|
||||||
|
'[OK]': '<img src="https://res.wx.qq.com/t/wx_fed/we-emoji/res/v1.2.8/assets/Expression/Expression_90@2x.png" id="OK" class="emoji_img">',
|
||||||
|
'[合十]': '<img src="https://res.wx.qq.com/t/wx_fed/we-emoji/res/v1.2.8/assets/newemoji/Worship.png" id="合十" class="emoji_img">',
|
||||||
|
'[啤酒]': '<img src="https://res.wx.qq.com/t/wx_fed/we-emoji/res/v1.2.8/assets/Expression/Expression_58@2x.png" id="啤酒" class="emoji_img">',
|
||||||
|
'[咖啡]': '<img src="https://res.wx.qq.com/t/wx_fed/we-emoji/res/v1.2.8/assets/Expression/Expression_61@2x.png" id="咖啡" class="emoji_img">',
|
||||||
|
'[蛋糕]': '<img src="https://res.wx.qq.com/t/wx_fed/we-emoji/res/v1.2.8/assets/Expression/Expression_69@2x.png" id="蛋糕" class="emoji_img">',
|
||||||
|
'[玫瑰]': '<img src="https://res.wx.qq.com/t/wx_fed/we-emoji/res/v1.2.8/assets/Expression/Expression_64@2x.png" id="玫 瑰" class="emoji_img">',
|
||||||
|
'[凋谢]': '<img src="https://res.wx.qq.com/t/wx_fed/we-emoji/res/v1.2.8/assets/Expression/Expression_65@2x.png" id="凋谢" class="emoji_img">',
|
||||||
|
'[菜刀]': '<img src="https://res.wx.qq.com/t/wx_fed/we-emoji/res/v1.2.8/assets/Expression/Expression_56@2x.png" id="菜刀" class="emoji_img">',
|
||||||
|
'[炸弹]': '<img src="https://res.wx.qq.com/t/wx_fed/we-emoji/res/v1.2.8/assets/Expression/Expression_71@2x.png" id="炸弹" class="emoji_img">',
|
||||||
|
'[便便]': '<img src="https://res.wx.qq.com/t/wx_fed/we-emoji/res/v1.2.8/assets/Expression/Expression_75@2x.png" id="便便" class="emoji_img">',
|
||||||
|
'[月亮]': '<img src="https://res.wx.qq.com/t/wx_fed/we-emoji/res/v1.2.8/assets/Expression/Expression_76@2x.png" id="月亮" class="emoji_img">',
|
||||||
|
'[太阳]': '<img src="https://res.wx.qq.com/t/wx_fed/we-emoji/res/v1.2.8/assets/Expression/Expression_77@2x.png" id="太阳" class="emoji_img">',
|
||||||
|
'[庆 祝]': '<img src="https://res.wx.qq.com/t/wx_fed/we-emoji/res/v1.2.8/assets/newemoji/Party.png" id="庆祝" class="emoji_img">',
|
||||||
|
'[礼物]': '<img src="https://res.wx.qq.com/t/wx_fed/we-emoji/res/v1.2.8/assets/Expression/Expression_78@2x.png" id="礼物" class="emoji_img">',
|
||||||
|
'[红包]': '<img src="https://res.wx.qq.com/t/wx_fed/we-emoji/res/v1.2.8/assets/newemoji/2_09.png" id="红包" class="emoji_img">',
|
||||||
|
'[發]': '<img src="https://res.wx.qq.com/t/wx_fed/we-emoji/res/v1.2.8/assets/newemoji/2_16.png" id="發" class="emoji_img">',
|
||||||
|
'[福]': '<img src="https://res.wx.qq.com/t/wx_fed/we-emoji/res/v1.2.8/assets/newemoji/2_15.png" id="福" class="emoji_img">',
|
||||||
|
'[烟花]': '<img src="https://res.wx.qq.com/t/wx_fed/we-emoji/res/v1.2.8/assets/newemoji/Fireworks.png" id="烟花" class="emoji_img">',
|
||||||
|
'[爆竹]': '<img src="https://res.wx.qq.com/t/wx_fed/we-emoji/res/v1.2.8/assets/newemoji/Firecracker.png" id="爆竹" class="emoji_img">',
|
||||||
|
'[猪头]': '<img src="https://res.wx.qq.com/t/wx_fed/we-emoji/res/v1.2.8/assets/Expression/Expression_63@2x.png" id="猪头" class="emoji_img">',
|
||||||
|
'[跳跳]': '<img src="https://res.wx.qq.com/t/wx_fed/we-emoji/res/v1.2.8/assets/Expression/Expression_93@2x.png" id="跳跳" class="emoji_img">',
|
||||||
|
'[发抖]': '<img src="https://res.wx.qq.com/t/wx_fed/we-emoji/res/v1.2.8/assets/Expression/Expression_94@2x.png" id="发抖" class="emoji_img">',
|
||||||
|
'[转圈]': '<img src="https://res.wx.qq.com/t/wx_fed/we-emoji/res/v1.2.8/assets/Expression/Expression_96@2x.png" id="转圈" class="emoji_img">'}
|
||||||
|
from re import findall
|
||||||
for index, message in enumerate(messages):
|
for index, message in enumerate(messages):
|
||||||
type_ = message[2]
|
type_ = message[2]
|
||||||
str_content = message[7]
|
str_content = message[7]
|
||||||
@ -740,6 +871,11 @@ const chatMessages = [
|
|||||||
f.write(
|
f.write(
|
||||||
f'''{{ type:0, text: '{str_time}',is_send:0,avatar_path:''}},'''
|
f'''{{ type:0, text: '{str_time}',is_send:0,avatar_path:''}},'''
|
||||||
)
|
)
|
||||||
|
|
||||||
|
emojiText = findall(r"(\[.+?\])", str_content)
|
||||||
|
for emoji_text in emojiText:
|
||||||
|
if emoji_text in emoji:
|
||||||
|
str_content = str_content.replace(emoji_text, emoji[emoji_text])
|
||||||
f.write(
|
f.write(
|
||||||
f'''{{ type:{type_}, text: '{str_content}',is_send:{is_send},avatar_path:'{avatar}'}},'''
|
f'''{{ type:{type_}, text: '{str_content}',is_send:{is_send},avatar_path:'{avatar}'}},'''
|
||||||
)
|
)
|
||||||
@ -753,9 +889,8 @@ const chatMessages = [
|
|||||||
match = re.search(pattern2, str_content)
|
match = re.search(pattern2, str_content)
|
||||||
if match:
|
if match:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
image_path = hard_link_db.get_image(content=str_content, thumb=False)
|
image_path = hard_link_db.get_image(content=str_content, thumb=False)
|
||||||
image_path = get_abs_path(image_path)
|
image_path = path.get_relative_path(image_path, base_path=f'/data/聊天记录/{self.contact.remark}/image')
|
||||||
image_path = image_path.replace('\\', '/')
|
image_path = image_path.replace('\\', '/')
|
||||||
# print(f"tohtml:---{image_path}")
|
# print(f"tohtml:---{image_path}")
|
||||||
if self.is_5_min(timestamp):
|
if self.is_5_min(timestamp):
|
||||||
|
103
app/DataBase/package_msg.py
Normal file
103
app/DataBase/package_msg.py
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
import threading
|
||||||
|
|
||||||
|
from app.DataBase import msg_db, micro_msg_db
|
||||||
|
from app.util.protocbuf.msg_pb2 import MessageBytesExtra
|
||||||
|
from app.util.protocbuf.roomdata_pb2 import ChatRoomData
|
||||||
|
|
||||||
|
lock = threading.Lock()
|
||||||
|
|
||||||
|
|
||||||
|
def singleton(cls):
|
||||||
|
_instance = {}
|
||||||
|
|
||||||
|
def inner():
|
||||||
|
if cls not in _instance:
|
||||||
|
_instance[cls] = cls()
|
||||||
|
return _instance[cls]
|
||||||
|
|
||||||
|
return inner
|
||||||
|
|
||||||
|
|
||||||
|
@singleton
|
||||||
|
class PackageMsg:
|
||||||
|
def __init__(self):
|
||||||
|
self.ChatRoomMap = {}
|
||||||
|
|
||||||
|
def get_package_message_all(self):
|
||||||
|
'''
|
||||||
|
获取完整的聊天记录
|
||||||
|
'''
|
||||||
|
updated_messages = [] # 用于存储修改后的消息列表
|
||||||
|
|
||||||
|
messages = msg_db.get_messages_all()
|
||||||
|
for row in messages:
|
||||||
|
row_list = list(row)
|
||||||
|
# 删除不使用的几个字段
|
||||||
|
del row_list[12]
|
||||||
|
del row_list[11]
|
||||||
|
del row_list[10]
|
||||||
|
|
||||||
|
strtalker = row[11]
|
||||||
|
info = micro_msg_db.get_contact_by_username(strtalker)
|
||||||
|
if info is not None:
|
||||||
|
row_list.append(info[3])
|
||||||
|
row_list.append(info[4])
|
||||||
|
# 判断是否是群聊
|
||||||
|
if strtalker.__contains__('@chatroom'):
|
||||||
|
# 自己发送
|
||||||
|
if row[12] == 1:
|
||||||
|
row_list.append('我')
|
||||||
|
else:
|
||||||
|
# 存在BytesExtra为空的情况,此时消息类型应该为提示性消息。跳过不处理
|
||||||
|
if row[10] is None:
|
||||||
|
continue
|
||||||
|
# 解析BytesExtra
|
||||||
|
msgbytes = MessageBytesExtra()
|
||||||
|
msgbytes.ParseFromString(row[10])
|
||||||
|
wxid = ''
|
||||||
|
for tmp in msgbytes.message2:
|
||||||
|
if tmp.field1 != 1:
|
||||||
|
continue
|
||||||
|
wxid = tmp.field2
|
||||||
|
sender = ''
|
||||||
|
# 获取群聊成员列表
|
||||||
|
membersMap = self.get_chatroom_member_list(strtalker)
|
||||||
|
if membersMap is not None:
|
||||||
|
if wxid in membersMap:
|
||||||
|
sender = membersMap.get(wxid)
|
||||||
|
else:
|
||||||
|
senderinfo = micro_msg_db.get_contact_by_username(wxid)
|
||||||
|
if senderinfo is not None:
|
||||||
|
sender = senderinfo[4]
|
||||||
|
membersMap[wxid] = senderinfo[4]
|
||||||
|
if len(senderinfo[3]) > 0:
|
||||||
|
sender = senderinfo[3]
|
||||||
|
membersMap[wxid] = senderinfo[3]
|
||||||
|
row_list.append(sender)
|
||||||
|
updated_messages.append(tuple(row_list))
|
||||||
|
return updated_messages
|
||||||
|
|
||||||
|
def get_chatroom_member_list(self, strtalker):
|
||||||
|
membermap = {}
|
||||||
|
'''
|
||||||
|
获取群聊成员
|
||||||
|
'''
|
||||||
|
try:
|
||||||
|
lock.acquire(True)
|
||||||
|
if strtalker in self.ChatRoomMap:
|
||||||
|
membermap = self.ChatRoomMap.get(strtalker)
|
||||||
|
else:
|
||||||
|
chatroom = micro_msg_db.get_chatroom_info(strtalker)
|
||||||
|
if chatroom is None:
|
||||||
|
return None
|
||||||
|
# 解析RoomData数据
|
||||||
|
parsechatroom = ChatRoomData()
|
||||||
|
parsechatroom.ParseFromString(chatroom[1])
|
||||||
|
# 群成员数据放入字典存储
|
||||||
|
for mem in parsechatroom.members:
|
||||||
|
if mem.displayName is not None and len(mem.displayName) > 0:
|
||||||
|
membermap[mem.wxID] = mem.displayName
|
||||||
|
self.ChatRoomMap[strtalker] = membermap
|
||||||
|
finally:
|
||||||
|
lock.release()
|
||||||
|
return membermap
|
@ -19,6 +19,13 @@ wordcloud_height = 720
|
|||||||
def wordcloud(wxid):
|
def wordcloud(wxid):
|
||||||
import jieba
|
import jieba
|
||||||
txt_messages = msg_db.get_messages_by_type(wxid, MsgType.TEXT)
|
txt_messages = msg_db.get_messages_by_type(wxid, MsgType.TEXT)
|
||||||
|
if not txt_messages:
|
||||||
|
return {
|
||||||
|
'chart_data': None,
|
||||||
|
'keyword': "没有聊天你想分析啥",
|
||||||
|
'max_num': "0",
|
||||||
|
'dialogs': []
|
||||||
|
}
|
||||||
text = ''.join(map(lambda x: x[7], txt_messages))
|
text = ''.join(map(lambda x: x[7], txt_messages))
|
||||||
total_msg_len = len(text)
|
total_msg_len = len(text)
|
||||||
# 使用jieba进行分词,并加入停用词
|
# 使用jieba进行分词,并加入停用词
|
||||||
@ -26,7 +33,7 @@ def wordcloud(wxid):
|
|||||||
# 统计词频
|
# 统计词频
|
||||||
word_count = Counter(words)
|
word_count = Counter(words)
|
||||||
# 过滤停用词
|
# 过滤停用词
|
||||||
stopwords_file = './app/data/stopwords.txt'
|
stopwords_file = './app000/data/stopwords.txt'
|
||||||
try:
|
try:
|
||||||
with open(stopwords_file, "r", encoding="utf-8") as stopword_file:
|
with open(stopwords_file, "r", encoding="utf-8") as stopword_file:
|
||||||
stopwords = set(stopword_file.read().splitlines())
|
stopwords = set(stopword_file.read().splitlines())
|
||||||
@ -65,7 +72,7 @@ def wordcloud(wxid):
|
|||||||
'chart_data': w.dump_options_with_quotes(),
|
'chart_data': w.dump_options_with_quotes(),
|
||||||
'keyword': keyword,
|
'keyword': keyword,
|
||||||
'max_num': str(max_num),
|
'max_num': str(max_num),
|
||||||
'dialogs': msg_db.get_messages_by_keyword(wxid, keyword, num=5)
|
'dialogs': msg_db.get_messages_by_keyword(wxid, keyword, num=5, max_len=12)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
version = '0.2.6'
|
version = '0.2.7'
|
||||||
contact = '474379264'
|
contact = '474379264'
|
||||||
description = [
|
description = [
|
||||||
'1. 支持获取个人信息<br>',
|
'1. 支持获取个人信息<br>',
|
||||||
'2. 支持显示聊天界面<br>',
|
'2. 支持显示聊天界面<br>',
|
||||||
'3. 支持导出聊天记录<br> * csv<br> * html<br>',
|
'3. 支持导出聊天记录<br> * csv<br> * html<br>',
|
||||||
'4. 查找联系人<br>',
|
'4. 查找联系人<br>',
|
||||||
|
'5. 生成年度报告<br>',
|
||||||
]
|
]
|
||||||
|
File diff suppressed because it is too large
Load Diff
2561
app/resources/stopwords.txt
Normal file
2561
app/resources/stopwords.txt
Normal file
File diff suppressed because it is too large
Load Diff
@ -50,14 +50,15 @@ def decode_dat(file_path, out_path):
|
|||||||
|
|
||||||
if decode_code == -1:
|
if decode_code == -1:
|
||||||
return
|
return
|
||||||
|
filename = os.path.basename(file_path)
|
||||||
if file_type == 1:
|
if file_type == 1:
|
||||||
pic_name = os.path.basename(file_path)[:-4] + ".jpg"
|
pic_name = os.path.basename(file_path)[:-4] + ".jpg"
|
||||||
elif file_type == 3:
|
elif file_type == 3:
|
||||||
pic_name = file_path[:-4] + ".png"
|
pic_name = filename[:-4] + ".png"
|
||||||
elif file_type == 5:
|
elif file_type == 5:
|
||||||
pic_name = file_path[:-4] + ".gif"
|
pic_name = filename[:-4] + ".gif"
|
||||||
else:
|
else:
|
||||||
pic_name = file_path[:-4] + ".jpg"
|
pic_name = filename[:-4] + ".jpg"
|
||||||
file_outpath = os.path.join(out_path, pic_name)
|
file_outpath = os.path.join(out_path, pic_name)
|
||||||
if os.path.exists(file_outpath):
|
if os.path.exists(file_outpath):
|
||||||
return file_outpath
|
return file_outpath
|
||||||
|
@ -7,16 +7,26 @@ from app.util import dat2pic
|
|||||||
os.makedirs('./data/image', exist_ok=True)
|
os.makedirs('./data/image', exist_ok=True)
|
||||||
|
|
||||||
|
|
||||||
def get_abs_path(path):
|
def get_abs_path(path, base_path="/data/image"):
|
||||||
# return os.path.join(os.getcwd(), 'app/data/icons/404.png')
|
# return os.path.join(os.getcwd(), 'app/data/icons/404.png')
|
||||||
if path:
|
if path:
|
||||||
base_path = os.getcwd() + "/data/image"
|
base_path = os.getcwd() + base_path
|
||||||
output_path = dat2pic.decode_dat(os.path.join(MePC().wx_dir, path), base_path) # './data/image')
|
output_path = dat2pic.decode_dat(os.path.join(MePC().wx_dir, path), base_path)
|
||||||
return output_path if output_path else ':/icons/icons/404.png'
|
return output_path if output_path else ':/icons/icons/404.png'
|
||||||
else:
|
else:
|
||||||
return ':/icons/icons/404.png'
|
return ':/icons/icons/404.png'
|
||||||
|
|
||||||
|
|
||||||
|
def get_relative_path(path, base_path):
|
||||||
|
if path:
|
||||||
|
base_path = os.getcwd() + base_path
|
||||||
|
output_path = dat2pic.decode_dat(os.path.join(MePC().wx_dir, path), base_path)
|
||||||
|
relative_path = './image/'+os.path.basename(output_path) if output_path else 'https://www.bing.com/images/search?view=detailV2&ccid=Zww6woP3&id=CCC91337C740656E800E51247E928ACD3052FECF&thid=OIP.Zww6woP3Em49TdSG_lnggAHaEK&mediaurl=https%3a%2f%2fmeekcitizen.files.wordpress.com%2f2018%2f09%2f404.jpg%3fw%3d656&exph=360&expw=640&q=404&simid=608040792714530493&FORM=IRPRST&ck=151E7337A86F1B9C5C5DB08B15B90809&selectedIndex=21&itb=0'
|
||||||
|
return relative_path
|
||||||
|
else:
|
||||||
|
return ':/icons/icons/404.png'
|
||||||
|
|
||||||
|
|
||||||
def mkdir(path):
|
def mkdir(path):
|
||||||
if not os.path.exists(path):
|
if not os.path.exists(path):
|
||||||
os.mkdir(path)
|
os.mkdir(path)
|
||||||
@ -44,4 +54,3 @@ def wx_path():
|
|||||||
return wx_location
|
return wx_location
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
return '.'
|
return '.'
|
||||||
|
|
||||||
|
0
app/util/protocbuf/__init__.py
Normal file
0
app/util/protocbuf/__init__.py
Normal file
18
app/util/protocbuf/msg.proto
Normal file
18
app/util/protocbuf/msg.proto
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
package app.protobuf;
|
||||||
|
option go_package=".;proto";
|
||||||
|
|
||||||
|
message SubMessage1 {
|
||||||
|
int32 field1 = 1;
|
||||||
|
int32 field2 = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message SubMessage2 {
|
||||||
|
int32 field1 = 1;
|
||||||
|
string field2 = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message MessageBytesExtra {
|
||||||
|
SubMessage1 message1 = 1;
|
||||||
|
repeated SubMessage2 message2 = 3;
|
||||||
|
}
|
54
app/util/protocbuf/msg_pb2.py
Normal file
54
app/util/protocbuf/msg_pb2.py
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||||
|
# source: msg.proto
|
||||||
|
"""Generated protocol buffer code."""
|
||||||
|
from google.protobuf import descriptor as _descriptor
|
||||||
|
from google.protobuf import descriptor_pool as _descriptor_pool
|
||||||
|
from google.protobuf import message as _message
|
||||||
|
from google.protobuf import reflection as _reflection
|
||||||
|
from google.protobuf import symbol_database as _symbol_database
|
||||||
|
# @@protoc_insertion_point(imports)
|
||||||
|
|
||||||
|
_sym_db = _symbol_database.Default()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\tmsg.proto\x12\x0c\x61pp.protobuf\"-\n\x0bSubMessage1\x12\x0e\n\x06\x66ield1\x18\x01 \x01(\x05\x12\x0e\n\x06\x66ield2\x18\x02 \x01(\x05\"-\n\x0bSubMessage2\x12\x0e\n\x06\x66ield1\x18\x01 \x01(\x05\x12\x0e\n\x06\x66ield2\x18\x02 \x01(\t\"m\n\x11MessageBytesExtra\x12+\n\x08message1\x18\x01 \x01(\x0b\x32\x19.app.protobuf.SubMessage1\x12+\n\x08message2\x18\x03 \x03(\x0b\x32\x19.app.protobuf.SubMessage2b\x06proto3')
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
_SUBMESSAGE1 = DESCRIPTOR.message_types_by_name['SubMessage1']
|
||||||
|
_SUBMESSAGE2 = DESCRIPTOR.message_types_by_name['SubMessage2']
|
||||||
|
_MESSAGEBYTESEXTRA = DESCRIPTOR.message_types_by_name['MessageBytesExtra']
|
||||||
|
SubMessage1 = _reflection.GeneratedProtocolMessageType('SubMessage1', (_message.Message,), {
|
||||||
|
'DESCRIPTOR' : _SUBMESSAGE1,
|
||||||
|
'__module__' : 'msg_pb2'
|
||||||
|
# @@protoc_insertion_point(class_scope:app.protobuf.SubMessage1)
|
||||||
|
})
|
||||||
|
_sym_db.RegisterMessage(SubMessage1)
|
||||||
|
|
||||||
|
SubMessage2 = _reflection.GeneratedProtocolMessageType('SubMessage2', (_message.Message,), {
|
||||||
|
'DESCRIPTOR' : _SUBMESSAGE2,
|
||||||
|
'__module__' : 'msg_pb2'
|
||||||
|
# @@protoc_insertion_point(class_scope:app.protobuf.SubMessage2)
|
||||||
|
})
|
||||||
|
_sym_db.RegisterMessage(SubMessage2)
|
||||||
|
|
||||||
|
MessageBytesExtra = _reflection.GeneratedProtocolMessageType('MessageBytesExtra', (_message.Message,), {
|
||||||
|
'DESCRIPTOR' : _MESSAGEBYTESEXTRA,
|
||||||
|
'__module__' : 'msg_pb2'
|
||||||
|
# @@protoc_insertion_point(class_scope:app.protobuf.MessageBytesExtra)
|
||||||
|
})
|
||||||
|
_sym_db.RegisterMessage(MessageBytesExtra)
|
||||||
|
|
||||||
|
if _descriptor._USE_C_DESCRIPTORS == False:
|
||||||
|
|
||||||
|
DESCRIPTOR._options = None
|
||||||
|
_SUBMESSAGE1._serialized_start=27
|
||||||
|
_SUBMESSAGE1._serialized_end=72
|
||||||
|
_SUBMESSAGE2._serialized_start=74
|
||||||
|
_SUBMESSAGE2._serialized_end=119
|
||||||
|
_MESSAGEBYTESEXTRA._serialized_start=121
|
||||||
|
_MESSAGEBYTESEXTRA._serialized_end=230
|
||||||
|
# @@protoc_insertion_point(module_scope)
|
34
app/util/protocbuf/readme.md
Normal file
34
app/util/protocbuf/readme.md
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
# 说明
|
||||||
|
|
||||||
|
## 解析
|
||||||
|
```shell
|
||||||
|
protoc --decode_raw < msg_data.txt
|
||||||
|
```
|
||||||
|
|
||||||
|
## 根据解析结果,设置.proto文件
|
||||||
|
```shell
|
||||||
|
1 {
|
||||||
|
1: 16
|
||||||
|
2: 0
|
||||||
|
}
|
||||||
|
3 {
|
||||||
|
1: 1
|
||||||
|
2: "wxid_4b1t09d63spw22"
|
||||||
|
}
|
||||||
|
3 {
|
||||||
|
1: 7
|
||||||
|
2: "<msgsource>\n\t<alnode>\n\t\t<fr>2</fr>\n\t</alnode>\n\t<sec_msg_node>\n\t\t<uuid>c6680ab2c57499a1a22e44a7eada76e8_</uuid>\n\t</sec_msg_node>\n\t<silence>1</silence>\n\t<membercount>198</membercount>\n\t<signature>v1_Gj7hfmi5</signature>\n\t<tmp_node>\n\t\t<publisher-id></publisher-id>\n\t</tmp_node>\n</msgsource>\n"
|
||||||
|
}
|
||||||
|
3 {
|
||||||
|
1: 2
|
||||||
|
2: "c13acbc95512d1a59bb686d684fd64d8"
|
||||||
|
}
|
||||||
|
3 {
|
||||||
|
1: 4
|
||||||
|
2: "yiluoAK_47\\FileStorage\\Cache\\2023-08\\2286b5852db82f6cbd9c2084ccd52358"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
## 生成python文件
|
||||||
|
```shell
|
||||||
|
protoc --python_out=. msg.proto
|
||||||
|
```
|
19
app/util/protocbuf/roomdata.proto
Normal file
19
app/util/protocbuf/roomdata.proto
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
package app.protobuf;
|
||||||
|
option go_package=".;proto";
|
||||||
|
|
||||||
|
message ChatRoomData {
|
||||||
|
message ChatRoomMember {
|
||||||
|
string wxID = 1;
|
||||||
|
string displayName = 2;
|
||||||
|
int32 state = 3;
|
||||||
|
}
|
||||||
|
repeated ChatRoomMember members = 1;
|
||||||
|
int32 field_2 = 2;
|
||||||
|
int32 field_3 = 3;
|
||||||
|
int32 field_4 = 4;
|
||||||
|
int32 room_capacity = 5;
|
||||||
|
int32 field_6 = 6;
|
||||||
|
int64 field_7 = 7;
|
||||||
|
int64 field_8 = 8;
|
||||||
|
}
|
45
app/util/protocbuf/roomdata_pb2.py
Normal file
45
app/util/protocbuf/roomdata_pb2.py
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||||
|
# source: roomdata.proto
|
||||||
|
"""Generated protocol buffer code."""
|
||||||
|
from google.protobuf import descriptor as _descriptor
|
||||||
|
from google.protobuf import descriptor_pool as _descriptor_pool
|
||||||
|
from google.protobuf import message as _message
|
||||||
|
from google.protobuf import reflection as _reflection
|
||||||
|
from google.protobuf import symbol_database as _symbol_database
|
||||||
|
# @@protoc_insertion_point(imports)
|
||||||
|
|
||||||
|
_sym_db = _symbol_database.Default()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x0eroomdata.proto\x12\x0c\x61pp.protobuf\"\x8b\x02\n\x0c\x43hatRoomData\x12:\n\x07members\x18\x01 \x03(\x0b\x32).app.protobuf.ChatRoomData.ChatRoomMember\x12\x0f\n\x07\x66ield_2\x18\x02 \x01(\x05\x12\x0f\n\x07\x66ield_3\x18\x03 \x01(\x05\x12\x0f\n\x07\x66ield_4\x18\x04 \x01(\x05\x12\x15\n\rroom_capacity\x18\x05 \x01(\x05\x12\x0f\n\x07\x66ield_6\x18\x06 \x01(\x05\x12\x0f\n\x07\x66ield_7\x18\x07 \x01(\x03\x12\x0f\n\x07\x66ield_8\x18\x08 \x01(\x03\x1a\x42\n\x0e\x43hatRoomMember\x12\x0c\n\x04wxID\x18\x01 \x01(\t\x12\x13\n\x0b\x64isplayName\x18\x02 \x01(\t\x12\r\n\x05state\x18\x03 \x01(\x05\x62\x06proto3')
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
_CHATROOMDATA = DESCRIPTOR.message_types_by_name['ChatRoomData']
|
||||||
|
_CHATROOMDATA_CHATROOMMEMBER = _CHATROOMDATA.nested_types_by_name['ChatRoomMember']
|
||||||
|
ChatRoomData = _reflection.GeneratedProtocolMessageType('ChatRoomData', (_message.Message,), {
|
||||||
|
|
||||||
|
'ChatRoomMember' : _reflection.GeneratedProtocolMessageType('ChatRoomMember', (_message.Message,), {
|
||||||
|
'DESCRIPTOR' : _CHATROOMDATA_CHATROOMMEMBER,
|
||||||
|
'__module__' : 'roomdata_pb2'
|
||||||
|
# @@protoc_insertion_point(class_scope:app.protobuf.ChatRoomData.ChatRoomMember)
|
||||||
|
})
|
||||||
|
,
|
||||||
|
'DESCRIPTOR' : _CHATROOMDATA,
|
||||||
|
'__module__' : 'roomdata_pb2'
|
||||||
|
# @@protoc_insertion_point(class_scope:app.protobuf.ChatRoomData)
|
||||||
|
})
|
||||||
|
_sym_db.RegisterMessage(ChatRoomData)
|
||||||
|
_sym_db.RegisterMessage(ChatRoomData.ChatRoomMember)
|
||||||
|
|
||||||
|
if _descriptor._USE_C_DESCRIPTORS == False:
|
||||||
|
|
||||||
|
DESCRIPTOR._options = None
|
||||||
|
_CHATROOMDATA._serialized_start=33
|
||||||
|
_CHATROOMDATA._serialized_end=300
|
||||||
|
_CHATROOMDATA_CHATROOMMEMBER._serialized_start=234
|
||||||
|
_CHATROOMDATA_CHATROOMMEMBER._serialized_end=300
|
||||||
|
# @@protoc_insertion_point(module_scope)
|
@ -42,16 +42,16 @@ def index0():
|
|||||||
@app.route('/home')
|
@app.route('/home')
|
||||||
def home():
|
def home():
|
||||||
try:
|
try:
|
||||||
|
first_message, first_time = msg_db.get_first_time_of_message(contact.wxid)
|
||||||
|
except TypeError:
|
||||||
|
return set_text('咱就是说,一次都没聊过就别分析了')
|
||||||
data = {
|
data = {
|
||||||
'sub_title': '二零二三年度报告',
|
'sub_title': '二零二三年度报告',
|
||||||
'avatar_path': contact.avatar_path,
|
'avatar_path': contact.avatar_path,
|
||||||
'nickname': contact.remark,
|
'nickname': contact.remark,
|
||||||
'first_time': msg_db.get_first_time_of_message(contact.wxid)[1],
|
'first_time': first_time,
|
||||||
}
|
}
|
||||||
return render_template('home.html', **data)
|
return render_template('home.html', **data)
|
||||||
except IndexError:
|
|
||||||
return set_text('咱就是说,一次都没聊过就别分析了')
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@app.route('/wordcloud')
|
@app.route('/wordcloud')
|
||||||
|
BIN
chat_window1.png
BIN
chat_window1.png
Binary file not shown.
Before Width: | Height: | Size: 178 KiB |
@ -9,7 +9,7 @@ from PyQt5.QtWidgets import *
|
|||||||
from app.log import logger
|
from app.log import logger
|
||||||
from app.ui_pc import mainview
|
from app.ui_pc import mainview
|
||||||
from app.ui_pc.tool.pc_decrypt import pc_decrypt
|
from app.ui_pc.tool.pc_decrypt import pc_decrypt
|
||||||
|
from app.config import version
|
||||||
ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID("WeChatReport")
|
ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID("WeChatReport")
|
||||||
|
|
||||||
|
|
||||||
@ -39,7 +39,7 @@ class ViewController(QWidget):
|
|||||||
self.viewMainWindow = mainview.MainWinController(username=username)
|
self.viewMainWindow = mainview.MainWinController(username=username)
|
||||||
self.viewMainWindow.exitSignal.connect(self.close)
|
self.viewMainWindow.exitSignal.connect(self.close)
|
||||||
try:
|
try:
|
||||||
self.viewMainWindow.setWindowTitle("留痕")
|
self.viewMainWindow.setWindowTitle(f"留痕-{version}")
|
||||||
self.viewMainWindow.show()
|
self.viewMainWindow.show()
|
||||||
end = time.time()
|
end = time.time()
|
||||||
print('ok', '本次加载用了', end - start, 's')
|
print('ok', '本次加载用了', end - start, 's')
|
||||||
|
@ -294,7 +294,8 @@ python main.py
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
> 声明:该项目有且仅有一个目的:“留痕”——我的数据我做主,前提是“我的数据”其次才是“我做主”,禁止任何人以任何形式将其用于任何非法用途,对于使用该程序所造成的任何后果,所有创作者不承担任何责任🙄
|
> 声明:该项目有且仅有一个目的:“留痕”——我的数据我做主,前提是“我的数据”其次才是“我做主”,禁止任何人以任何形式将其用于任何非法用途,对于使用该程序所造成的任何后果,所有创作者不承担任何责任🙄<br>
|
||||||
|
> 该软件不会对您使用的微信造成任何影响,更不会对他人的微信造成任何影响,不能找回删除的聊天记录,任何企图篡改微信聊天数据的想法都是无稽之谈。本项目所有功能均建立在”前言“的基础之上,基于该项目的所有开发者均不能接受任何有悖于”前言“的功能需求,违者后果自负。
|
||||||
|
|
||||||
[](https://star-history.com/?utm_source=bestxtools.com#LC044/WeChatMsg&Date)
|
[](https://star-history.com/?utm_source=bestxtools.com#LC044/WeChatMsg&Date)
|
||||||
|
|
||||||
|
BIN
requirements.txt
BIN
requirements.txt
Binary file not shown.
@ -12,3 +12,6 @@ requests
|
|||||||
flask==3.0.0
|
flask==3.0.0
|
||||||
pyecharts==2.0.1
|
pyecharts==2.0.1
|
||||||
jieba==0.42.1
|
jieba==0.42.1
|
||||||
|
google==3.0.0
|
||||||
|
protobuf==4.25.1
|
||||||
|
soupsieve==2.5
|
||||||
|
Loading…
Reference in New Issue
Block a user