mirror of
https://github.com/LC044/WeChatMsg
synced 2025-02-21 01:52:35 +08:00
支持导出引用消息类型
This commit is contained in:
parent
3a5131b39c
commit
cdf8a59ae2
@ -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 转义字符串如 &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
|
@ -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;
|
||||
|
@ -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()
|
||||
|
66
app/util/compress_content.py
Normal file
66
app/util/compress_content.py
Normal file
@ -0,0 +1,66 @@
|
||||
import html
|
||||
import xml.etree.ElementTree as ET
|
||||
|
||||
import lz4
|
||||
|
||||
|
||||
def decompress_CompressContent(data):
|
||||
"""
|
||||
解压缩Msg:CompressContent内容
|
||||
: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),
|
||||
}
|
||||
}
|
@ -15,4 +15,4 @@ jieba==0.42.1
|
||||
google==3.0.0
|
||||
protobuf==4.25.1
|
||||
soupsieve==2.5
|
||||
lz4
|
||||
lz4==4.3.2
|
Loading…
Reference in New Issue
Block a user