支持导出引用消息类型

This commit is contained in:
shuaikangzhou 2023-12-11 22:49:17 +08:00
parent 3a5131b39c
commit cdf8a59ae2
5 changed files with 145 additions and 54 deletions

View File

@ -38,11 +38,11 @@ def decompress_CompressContent(data):
if data is None or not isinstance(data, bytes):
return None
try:
try:
dst = lz4.block.decompress(data, uncompressed_size=len(data) << 10)
decoded_string = dst.decode().replace('\x00', '') # Remove any null characters
except lz4.block.LZ4BlockError:
print("Decompression failed: potentially corrupt input or insufficient buffer size.")
print("Decompression failed: potentially corrupt input or insufficient buffer size.")
return None
# 处理 HTML 转义字符串如 &amp;gt; 等。可能会递归嵌套,我们只考虑原会话和第一级引用会话,不考虑更深的引用,故只执行两遍。
@ -384,9 +384,14 @@ if __name__ == '__main__':
db_path = "./Msg/MSG.db"
msg = Msg()
msg.init_database()
result = msg.get_message_by_num('wxid_0o18ef858vnu22', 9999999)
result = msg.get_message_by_num('wxid_vtz9jk9ulzjt22', 9999999)
print(result)
result = msg.get_messages_by_type('wxid_0o18ef858vnu22',43)
bytes_ = result[-1][-1]
print(bytes_)
print(bytes_)
result = msg.get_messages_by_type('wxid_vtz9jk9ulzjt22',49)
for r in result:
type_ = r[2]
sub_type = r[3]
if type_ == 49 and sub_type == 57:
# print(r)
# print(r[-1])
print(decompress_CompressContent(r[-1]))
break

View File

@ -12,6 +12,7 @@ from ..person_pc import MePC
from ..util import path
import shutil
from ..util.compress_content import parser_reply
from ..util.emoji import get_emoji
os.makedirs('./data/聊天记录', exist_ok=True)
@ -179,7 +180,7 @@ class ChildThread(QThread):
if emoji_text in emoji:
str_content = str_content.replace(emoji_text, emoji[emoji_text])
doc.write(
f'''{{ type:{type_}, text: '{str_content}',is_send:{is_send},avatar_path:'{avatar}'}},'''
f'''{{ type:{1}, text: '{str_content}',is_send:{is_send},avatar_path:'{avatar}'}},'''
)
elif self.output_type == Output.TXT:
name = '' if is_send else self.contact.remark
@ -248,8 +249,33 @@ class ChildThread(QThread):
def retract_message(self, doc, isSend, content, status):
return
def reply(self, doc, isSend, content, status):
return
def refermsg(self, doc,message):
"""
处理回复消息
@param doc:
@param message:
@return:
"""
type_ = message[2]
str_content = message[7]
str_time = message[8]
is_send = message[4]
avatar = 'myhead.png' if is_send else 'tahead.png'
content = parser_reply(message[11])
refer_msg = content.get('refer')
if self.output_type == Output.HTML:
doc.write(
f'''{{ type:1, text: '{content.get('title')}',is_send:{is_send},avatar_path:'{avatar}'}},'''
)
doc.write(
f'''{{ type:{49},sub_type:{content.get('type')}, text: '{refer_msg.get('displayname')}:{refer_msg.get('content')}',is_send:{is_send},avatar_path:''}},'''
)
elif self.output_type==Output.TXT:
name = '' if is_send else self.contact.remark
doc.write(
f'''{str_time} {name}\n{content.get('title')}\n引用:{refer_msg.get('displayname')}:{refer_msg.get('content')}\n\n'''
)
def system_msg(self, doc, message):
str_content = message[7]
@ -349,6 +375,7 @@ class ChildThread(QThread):
total_steps = len(messages)
for index, message in enumerate(messages):
type_ = message[2]
sub_type = message[3]
self.progressSignal.emit(int((index + 1) / total_steps * 100))
if type_ == 1 and self.message_types.get(type_):
self.text(f, message)
@ -360,6 +387,8 @@ class ChildThread(QThread):
self.emoji(f, message)
elif type_ == 10000 and self.message_types.get(type_):
self.system_msg(f, message)
elif type_ == 49 and sub_type == 57:
self.refermsg(f,message)
f.write(html_end)
f.close()
self.okSignal.emit(1)
@ -373,6 +402,7 @@ class ChildThread(QThread):
with open(filename, mode='w', newline='', encoding='utf-8') as f:
for index, message in enumerate(messages):
type_ = message[2]
sub_type = message[3]
self.progressSignal.emit(int((index + 1) / total_steps * 100))
if type_ == 1 and self.message_types.get(type_):
self.text(f, message)
@ -384,6 +414,8 @@ class ChildThread(QThread):
self.emoji(f, message)
elif type_ == 10000 and self.message_types.get(type_):
self.system_msg(f, message)
elif type_ == 49 and sub_type == 57:
self.refermsg(f, message)
self.okSignal.emit(1)
def run(self):
if self.output_type == Output.DOCX:
@ -576,6 +608,22 @@ body{
word-wrap:break-word;
word-break:normal;
}
.chat-refer{
max-width: 400px;
padding: 3px;
border-radius: 5px;
position: relative;
color: #000;
background-color: #e8e8e8;
word-wrap:break-word;
word-break:normal;
}
.chat-refer-right{
margin-right:55px;
}
.chat-refer-left{
margin-left:55px;
}
.item-left .bubble{
margin-left: 15px;
background-color: #fff;
@ -700,7 +748,7 @@ textarea{
.pagination-container {
display: flex;
flex-direction: column;
align-items: center;
align-items: center;
margin-top: 20px;
margin-left: 20px; /* 新增的左边距 */
}
@ -802,47 +850,6 @@ input {
'''
html_end = '''
];
function renderMessages(messages) {
for (const message of messages) {
const messageElement = document.createElement('div');
if (message.type == 1) {
if (message.is_send == 1) {
messageElement.className = "item item-right";
messageElement.innerHTML = `<div class='bubble bubble-right'>${message.text}</div><div class='avatar'><img src="${message.avatar_path}" /></div>`
}
else if (message.is_send == 0) {
messageElement.className = "item item-left";
messageElement.innerHTML = `<div class='avatar'><img src="${message.avatar_path}" /></div><div class='bubble bubble-right'>${message.text}</div>`
}
}
else if (message.type == 0) {
messageElement.className = "item item-center";
messageElement.innerHTML = `<span>${message.text}</span>`
}
else if (message.type == 3) {
if (message.is_send == 1) {
messageElement.className = "item item-right";
messageElement.innerHTML = `<div class='chat-image'><img src="${message.text}" /></div><div class='avatar'><img src="${message.avatar_path}" /></div>`
}
else if (message.is_send == 0) {
messageElement.className = "item item-left";
messageElement.innerHTML = `<div class='avatar'><img src="${message.avatar_path}" /></div><div class='chat-image'><img src="${message.text}" /></div>`
}
}
else if (message.type == 43) {
if (message.is_send == 1) {
messageElement.className = "item item-right";
messageElement.innerHTML = `<div class='chat-video'><video src="${message.text}" controls /></div><div class='avatar'><img src="${message.avatar_path}" /></div>`
}
else if (message.is_send == 0) {
messageElement.className = "item item-left";
messageElement.innerHTML = `<div class='avatar'><img src="${message.avatar_path}" /></div><div class='chat-video'><video src="${message.text}" controls /></div>`
}
}
chatContainer.appendChild(messageElement);
}
}
function checkEnter(event) {
if (event.keyCode === 13) {
gotoPage();
@ -898,6 +905,18 @@ html_end = '''
messageElement.innerHTML = `<div class='avatar'><img src="${message.avatar_path}" /></div><div class='chat-video'><video src="${message.text}" controls "/></div>`
}
}
else if (message.type == 49) {
if (message.sub_type == 57){
if (message.is_send == 1) {
messageElement.className = "item item-right";
messageElement.innerHTML = `<div class='chat-refer chat-refer-right'>${message.text}</div></div>`
}
else if (message.is_send == 0) {
messageElement.className = "item item-left";
messageElement.innerHTML = `<div class='chat-refer chat-refer-left'>${message.text}</div></div>`
}
}
}
chatContainer.appendChild(messageElement);
}
document.querySelector("#chat-container").scrollTop = 0;

View File

@ -1,4 +1,5 @@
import os.path
import re
from typing import Dict
from PyQt5.QtCore import Qt
@ -47,7 +48,7 @@ class ContactPC:
self.nickName = contact_info.get('NickName')
if not self.remark:
self.remark = self.nickName
self.remark.replace('*', '_').replace('/', '_').replace('\\', '_')
self.remark = re.sub(r'[\/:*?"<>|]', '_', self.remark)
self.smallHeadImgUrl = contact_info.get('smallHeadImgUrl')
self.smallHeadImgBLOG = b''
self.avatar = QPixmap()

View File

@ -0,0 +1,66 @@
import html
import xml.etree.ElementTree as ET
import lz4
def decompress_CompressContent(data):
"""
解压缩MsgCompressContent内容
:param data:
:return:
"""
if data is None or not isinstance(data, bytes):
return ''
try:
dst = lz4.block.decompress(data, uncompressed_size=len(data) << 10)
decoded_string = dst.decode().replace('\x00', '') # Remove any null characters
except lz4.block.LZ4BlockError:
print("Decompression failed: potentially corrupt input or insufficient buffer size.")
return ''
return decoded_string
def escape_js_and_html(input_str):
# 转义HTML特殊字符
html_escaped = html.escape(input_str, quote=False)
# 手动处理JavaScript转义字符
js_escaped = (
html_escaped
.replace("\\", "\\\\")
.replace("'", r"\'")
.replace('"', r'\"')
.replace("\n", r'\n')
.replace("\r", r'\r')
.replace("\t", r'\t')
)
return js_escaped
def parser_reply(data: bytes):
xml_content = decompress_CompressContent(data)
if not xml_content:
return {
'type': 57,
'title': "发生错误",
'refer': {
'type': '1',
'content': '引用错误',
'displayname': '用户名',
}
}
root = ET.XML(xml_content)
appmsg = root.find('appmsg')
msg_type = appmsg.find('type').text
title = appmsg.find('title').text
refermsg_content = appmsg.find('refermsg').find('content').text
refermsg_type = appmsg.find('refermsg').find('type').text
refermsg_displayname = appmsg.find('refermsg').find('displayname').text
return {
'type': msg_type,
'title': title,
'refer': {
'type': refermsg_type,
'content': escape_js_and_html(refermsg_content),
'displayname': escape_js_and_html(refermsg_displayname),
}
}

View File

@ -15,4 +15,4 @@ jieba==0.42.1
google==3.0.0
protobuf==4.25.1
soupsieve==2.5
lz4
lz4==4.3.2