mirror of
https://github.com/LC044/WeChatMsg
synced 2025-02-23 03:22:17 +08:00
支持显示表情包
This commit is contained in:
parent
b732481d9c
commit
cb571e937d
@ -4,13 +4,16 @@
|
||||
<option name="autoReloadType" value="SELECTIVE" />
|
||||
</component>
|
||||
<component name="ChangeListManager">
|
||||
<list default="true" id="84e65474-7da9-466d-baf3-cc88dde3ffdd" name="变更" comment="添加资源文件">
|
||||
<list default="true" id="84e65474-7da9-466d-baf3-cc88dde3ffdd" name="变更" comment="修改文本消息宽度">
|
||||
<change afterPath="$PROJECT_DIR$/app/util/emoji.py" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/app/DataBase/hard_link.py" beforeDir="false" afterPath="$PROJECT_DIR$/app/DataBase/hard_link.py" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/app/components/bubble_message.py" beforeDir="false" afterPath="$PROJECT_DIR$/app/components/bubble_message.py" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/app/decrypt/dat2pic.py" beforeDir="false" afterPath="$PROJECT_DIR$/app/decrypt/dat2pic.py" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/app/ui_pc/chat/chat_window.py" beforeDir="false" afterPath="$PROJECT_DIR$/app/ui_pc/chat/chat_window.py" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/app/ui_pc/contact/contact_window.py" beforeDir="false" afterPath="$PROJECT_DIR$/app/ui_pc/contact/contact_window.py" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/app/decrypt/dat2pic.py" beforeDir="false" afterPath="$PROJECT_DIR$/app/util/dat2pic.py" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/app/decrypt/decrypt.py" beforeDir="false" afterPath="$PROJECT_DIR$/app/decrypt/decrypt.py" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/app/ui_pc/chat/chat_info.py" beforeDir="false" afterPath="$PROJECT_DIR$/app/ui_pc/chat/chat_info.py" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/app/util/path.py" beforeDir="false" afterPath="$PROJECT_DIR$/app/util/path.py" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/main_pc.py" beforeDir="false" afterPath="$PROJECT_DIR$/main_pc.py" afterDir="false" />
|
||||
</list>
|
||||
<option name="SHOW_DIALOG" value="false" />
|
||||
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
||||
@ -108,21 +111,21 @@
|
||||
"DefaultHtmlFileTemplate": "HTML File",
|
||||
"RunOnceActivity.OpenProjectViewOnStart": "true",
|
||||
"RunOnceActivity.ShowReadmeOnStart": "true",
|
||||
"last_opened_file_path": "D:/Project/Python/WeChatMsg/app/resources",
|
||||
"last_opened_file_path": "D:/Project/Python/WeChatMsg/app/util",
|
||||
"settings.editor.selected.configurable": "preferences.pluginManager"
|
||||
}
|
||||
}]]></component>
|
||||
<component name="RecentsManager">
|
||||
<key name="MoveFile.RECENT_KEYS">
|
||||
<recent name="D:\Project\Python\WeChatMsg\app\util" />
|
||||
<recent name="D:\Project\Python\WeChatMsg\app\resources" />
|
||||
<recent name="D:\Project\Python\WeChatMsg\resource" />
|
||||
<recent name="D:\Project\Python\WeChatMsg\app\ui_pc\tool" />
|
||||
<recent name="D:\Project\Python\WeChatMsg\app\" />
|
||||
<recent name="D:\Project\PythonProject\WeChatMsg\app\Ui" />
|
||||
</key>
|
||||
</component>
|
||||
<component name="RunManager" selected="Python.dat2pic">
|
||||
<configuration name="dat2pic" type="PythonConfigurationType" factoryName="Python" temporary="true" nameIsGenerated="true">
|
||||
<component name="RunManager" selected="Python.main_pc">
|
||||
<configuration name="decrypt" type="PythonConfigurationType" factoryName="Python" temporary="true" nameIsGenerated="true">
|
||||
<module name="WeChatMsg" />
|
||||
<option name="INTERPRETER_OPTIONS" value="" />
|
||||
<option name="PARENT_ENVS" value="true" />
|
||||
@ -134,7 +137,7 @@
|
||||
<option name="IS_MODULE_SDK" value="true" />
|
||||
<option name="ADD_CONTENT_ROOTS" value="true" />
|
||||
<option name="ADD_SOURCE_ROOTS" value="true" />
|
||||
<option name="SCRIPT_NAME" value="$PROJECT_DIR$/app/decrypt/dat2pic.py" />
|
||||
<option name="SCRIPT_NAME" value="$PROJECT_DIR$/app/decrypt/decrypt.py" />
|
||||
<option name="PARAMETERS" value="" />
|
||||
<option name="SHOW_COMMAND_LINE" value="false" />
|
||||
<option name="EMULATE_TERMINAL" value="false" />
|
||||
@ -164,6 +167,27 @@
|
||||
<option name="INPUT_FILE" value="" />
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
<configuration name="emoji" type="PythonConfigurationType" factoryName="Python" temporary="true" nameIsGenerated="true">
|
||||
<module name="WeChatMsg" />
|
||||
<option name="INTERPRETER_OPTIONS" value="" />
|
||||
<option name="PARENT_ENVS" value="true" />
|
||||
<envs>
|
||||
<env name="PYTHONUNBUFFERED" value="1" />
|
||||
</envs>
|
||||
<option name="SDK_HOME" value="" />
|
||||
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/app/util" />
|
||||
<option name="IS_MODULE_SDK" value="true" />
|
||||
<option name="ADD_CONTENT_ROOTS" value="true" />
|
||||
<option name="ADD_SOURCE_ROOTS" value="true" />
|
||||
<option name="SCRIPT_NAME" value="$PROJECT_DIR$/app/util/emoji.py" />
|
||||
<option name="PARAMETERS" value="" />
|
||||
<option name="SHOW_COMMAND_LINE" value="false" />
|
||||
<option name="EMULATE_TERMINAL" value="false" />
|
||||
<option name="MODULE_MODE" value="false" />
|
||||
<option name="REDIRECT_INPUT" value="false" />
|
||||
<option name="INPUT_FILE" value="" />
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
<configuration name="hard_link" type="PythonConfigurationType" factoryName="Python" temporary="true" nameIsGenerated="true">
|
||||
<module name="WeChatMsg" />
|
||||
<option name="INTERPRETER_OPTIONS" value="" />
|
||||
@ -200,7 +224,7 @@
|
||||
<option name="SCRIPT_NAME" value="$PROJECT_DIR$/main_pc.py" />
|
||||
<option name="PARAMETERS" value="" />
|
||||
<option name="SHOW_COMMAND_LINE" value="false" />
|
||||
<option name="EMULATE_TERMINAL" value="false" />
|
||||
<option name="EMULATE_TERMINAL" value="true" />
|
||||
<option name="MODULE_MODE" value="false" />
|
||||
<option name="REDIRECT_INPUT" value="false" />
|
||||
<option name="INPUT_FILE" value="" />
|
||||
@ -227,34 +251,13 @@
|
||||
<option name="INPUT_FILE" value="" />
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
<configuration name="test" type="PythonConfigurationType" factoryName="Python" temporary="true" nameIsGenerated="true">
|
||||
<module name="WeChatMsg" />
|
||||
<option name="INTERPRETER_OPTIONS" value="" />
|
||||
<option name="PARENT_ENVS" value="true" />
|
||||
<envs>
|
||||
<env name="PYTHONUNBUFFERED" value="1" />
|
||||
</envs>
|
||||
<option name="SDK_HOME" value="" />
|
||||
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$" />
|
||||
<option name="IS_MODULE_SDK" value="true" />
|
||||
<option name="ADD_CONTENT_ROOTS" value="true" />
|
||||
<option name="ADD_SOURCE_ROOTS" value="true" />
|
||||
<option name="SCRIPT_NAME" value="$PROJECT_DIR$/test.py" />
|
||||
<option name="PARAMETERS" value="" />
|
||||
<option name="SHOW_COMMAND_LINE" value="false" />
|
||||
<option name="EMULATE_TERMINAL" value="false" />
|
||||
<option name="MODULE_MODE" value="false" />
|
||||
<option name="REDIRECT_INPUT" value="false" />
|
||||
<option name="INPUT_FILE" value="" />
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
<recent_temporary>
|
||||
<list>
|
||||
<item itemvalue="Python.dat2pic" />
|
||||
<item itemvalue="Python.hard_link" />
|
||||
<item itemvalue="Python.main_pc" />
|
||||
<item itemvalue="Python.hard_link" />
|
||||
<item itemvalue="Python.emoji" />
|
||||
<item itemvalue="Python.decrypt_window" />
|
||||
<item itemvalue="Python.test" />
|
||||
<item itemvalue="Python.decrypt" />
|
||||
</list>
|
||||
</recent_temporary>
|
||||
</component>
|
||||
@ -270,13 +273,6 @@
|
||||
<option name="presentableId" value="Default" />
|
||||
<updated>1672848140146</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00037" summary="用stackedWidget实现导航栏">
|
||||
<created>1698850498765</created>
|
||||
<option name="number" value="00037" />
|
||||
<option name="presentableId" value="LOCAL-00037" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1698850498765</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00038" summary="修复部分bug">
|
||||
<created>1698853140384</created>
|
||||
<option name="number" value="00038" />
|
||||
@ -613,7 +609,14 @@
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1700751510245</updated>
|
||||
</task>
|
||||
<option name="localTasksCounter" value="86" />
|
||||
<task id="LOCAL-00086" summary="修改文本消息宽度">
|
||||
<created>1700828162843</created>
|
||||
<option name="number" value="00086" />
|
||||
<option name="presentableId" value="LOCAL-00086" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1700828162843</updated>
|
||||
</task>
|
||||
<option name="localTasksCounter" value="87" />
|
||||
<servers />
|
||||
</component>
|
||||
<component name="UnknownFeatures">
|
||||
@ -649,7 +652,6 @@
|
||||
</option>
|
||||
</component>
|
||||
<component name="VcsManagerConfiguration">
|
||||
<MESSAGE value="修复无法查找wxid的bug" />
|
||||
<MESSAGE value="修改UI" />
|
||||
<MESSAGE value="新增联系人头像组件" />
|
||||
<MESSAGE value="头像支持显示二进制" />
|
||||
@ -674,7 +676,8 @@
|
||||
<MESSAGE value="文字消息设置圆角" />
|
||||
<MESSAGE value="更新wx选择的路径" />
|
||||
<MESSAGE value="添加资源文件" />
|
||||
<option name="LAST_COMMIT_MESSAGE" value="添加资源文件" />
|
||||
<MESSAGE value="修改文本消息宽度" />
|
||||
<option name="LAST_COMMIT_MESSAGE" value="修改文本消息宽度" />
|
||||
<option name="OPTIMIZE_IMPORTS_BEFORE_PROJECT_COMMIT" value="true" />
|
||||
<option name="REFORMAT_BEFORE_PROJECT_COMMIT" value="true" />
|
||||
</component>
|
||||
|
@ -54,7 +54,7 @@ def get_md5_from_xml(content):
|
||||
def get_image(content, thumb=False):
|
||||
md5 = get_md5_from_xml(content)
|
||||
# md5 = 'bc37a58c32cb203ee9ac587b068e5853'
|
||||
md5 = '41895664fc5a77878e2155fc96209a19'
|
||||
# md5 = '41895664fc5a77878e2155fc96209a19'
|
||||
result = get_image_by_md5(binascii.unhexlify(md5))
|
||||
if result:
|
||||
# print(result)
|
||||
|
@ -105,7 +105,7 @@ class OpenImageThread(QThread):
|
||||
|
||||
|
||||
class ImageMessage(QLabel):
|
||||
def __init__(self, image, image_link='', max_width=480, max_height=240, parent=None):
|
||||
def __init__(self, image, is_send, image_link='', max_width=480, max_height=240, parent=None):
|
||||
"""
|
||||
param:image 图像路径或者QPixmap对象
|
||||
param:image_link='' 点击图像打开的文件路径
|
||||
@ -124,6 +124,8 @@ class ImageMessage(QLabel):
|
||||
self.image_path = image_link
|
||||
self.setMaximumWidth(self.max_width)
|
||||
self.setMaximumHeight(self.max_height)
|
||||
if is_send:
|
||||
self.setAlignment(Qt.AlignCenter | Qt.AlignRight)
|
||||
# self.setScaledContents(True)
|
||||
|
||||
def set_image(self, pixmap):
|
||||
@ -161,7 +163,7 @@ class BubbleMessage(QWidget):
|
||||
self.message = TextMessage(str_content, is_send)
|
||||
# self.message.setMaximumWidth(int(self.width() * 0.6))
|
||||
elif Type == MessageType.Image:
|
||||
self.message = ImageMessage(str_content)
|
||||
self.message = ImageMessage(str_content, is_send)
|
||||
else:
|
||||
raise ValueError("未知的消息类型")
|
||||
|
||||
|
@ -119,11 +119,6 @@ def batch_decrypt(key: str, db_path: Union[str, List[str]], out_path: str):
|
||||
if __name__ == '__main__':
|
||||
# 调用 decrypt 函数,并传入参数
|
||||
key = "2aafab10af7940328bb92ac9d2a8ab5fc07a685646b14f2e9ae6948a7060c0fc"
|
||||
db_path = "D:\Project\Python\PyWxDump\pywxdump\decrypted"
|
||||
out_path = "test"
|
||||
result = batch_decrypt(key, db_path, out_path)
|
||||
for i in result:
|
||||
if isinstance(i, str):
|
||||
print(i)
|
||||
else:
|
||||
print(f'[+] "{i[1]}" -> "{i[2]}"')
|
||||
db_path = "E:\86390\Documents\WeChat Files\wxid_27hqbq7vx5hf22\FileStorage\CustomEmotion\\71\\71CE49ED3CE9E57E43E07F802983BF45"
|
||||
out_path = "./test/1.png"
|
||||
print(decrypt(key, db_path, out_path))
|
||||
|
@ -7,6 +7,7 @@ from app.DataBase import msg, hard_link
|
||||
from app.components.bubble_message import BubbleMessage, ChatWidget, Notice
|
||||
from app.person import MePC
|
||||
from app.util import get_abs_path
|
||||
from app.util.emoji import get_emoji
|
||||
|
||||
|
||||
class ChatInfo(QWidget):
|
||||
@ -113,6 +114,20 @@ class ChatInfo(QWidget):
|
||||
is_send
|
||||
)
|
||||
self.chat_window.add_message_item(bubble_message, 0)
|
||||
elif type_ == 47:
|
||||
# return
|
||||
if self.is_5_min(timestamp):
|
||||
time_message = Notice(self.last_str_time)
|
||||
self.last_str_time = str_time
|
||||
self.chat_window.add_message_item(time_message, 0)
|
||||
image_path = get_emoji(str_content, thumb=True)
|
||||
bubble_message = BubbleMessage(
|
||||
image_path,
|
||||
avatar,
|
||||
3,
|
||||
is_send
|
||||
)
|
||||
self.chat_window.add_message_item(bubble_message, 0)
|
||||
except:
|
||||
print(message)
|
||||
traceback.print_exc()
|
||||
|
91
app/util/emoji.py
Normal file
91
app/util/emoji.py
Normal file
@ -0,0 +1,91 @@
|
||||
import os
|
||||
import xml.etree.ElementTree as ET
|
||||
|
||||
import requests
|
||||
|
||||
root_path = './data/emoji/'
|
||||
if not os.path.exists('./data'):
|
||||
os.mkdir('./data')
|
||||
if not os.path.exists(root_path):
|
||||
os.mkdir(root_path)
|
||||
|
||||
|
||||
def get_image_format(header):
|
||||
# 定义图片格式的 magic numbers
|
||||
image_formats = {
|
||||
b'\xFF\xD8\xFF': 'jpeg',
|
||||
b'\x89\x50\x4E\x47\x0D\x0A\x1A\x0A': 'png',
|
||||
b'\x47\x49\x46': 'gif',
|
||||
b'\x42\x4D': 'bmp',
|
||||
# 添加其他图片格式的 magic numbers
|
||||
}
|
||||
# 判断文件的图片格式
|
||||
for magic_number, image_format in image_formats.items():
|
||||
if header.startswith(magic_number):
|
||||
return image_format
|
||||
# 如果无法识别格式,返回 None
|
||||
return None
|
||||
|
||||
|
||||
def parser_xml(xml_string):
|
||||
# Parse the XML string
|
||||
root = ET.fromstring(xml_string)
|
||||
emoji = root.find('./emoji')
|
||||
# Accessing attributes of the 'emoji' element
|
||||
fromusername = emoji.get('fromusername')
|
||||
tousername = emoji.get('tousername')
|
||||
md5 = emoji.get('md5')
|
||||
cdnurl = emoji.get('cdnurl')
|
||||
encrypturl = emoji.get('encrypturl')
|
||||
thumburl = emoji.get('thumburl')
|
||||
externurl = emoji.get('externurl')
|
||||
width = emoji.get('width')
|
||||
height = emoji.get('height')
|
||||
return {
|
||||
'width': width,
|
||||
'height': height,
|
||||
'cdnurl': cdnurl,
|
||||
'thumburl': thumburl if thumburl else cdnurl,
|
||||
'md5': md5
|
||||
}
|
||||
|
||||
|
||||
def download(url, output_dir, name, thumb=False):
|
||||
resp = requests.get(url)
|
||||
byte = resp.content
|
||||
image_format = get_image_format(byte[:8])
|
||||
if image_format:
|
||||
if thumb:
|
||||
output_path = os.path.join(output_dir, 'th_' + name + '.' + image_format)
|
||||
else:
|
||||
output_path = os.path.join(output_dir, name + '.' + image_format)
|
||||
else:
|
||||
output_path = os.path.join(output_dir, name)
|
||||
with open(output_path, 'wb') as f:
|
||||
f.write(resp.content)
|
||||
return output_path
|
||||
|
||||
|
||||
def get_emoji(xml_string, thumb=True) -> str:
|
||||
emoji_info = parser_xml(xml_string)
|
||||
md5 = emoji_info['md5']
|
||||
image_format = ['.png', '.gif', '.jpeg']
|
||||
for f in image_format:
|
||||
prefix = 'th_' if thumb else ''
|
||||
file_path = os.path.join(root_path, prefix + md5 + f)
|
||||
if os.path.exists(file_path):
|
||||
return file_path
|
||||
url = emoji_info['thumburl'] if thumb else emoji_info['cdnurl']
|
||||
print("下载表情包ing:", url)
|
||||
return download(url, root_path, md5, thumb)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
xml_string = '<msg><emoji fromusername = "wxid_0o18ef858vnu22" tousername = "wxid_27hqbq7vx5hf22" type="2" idbuffer="media:0_0" md5="71ce49ed3ce9e57e43e07f802983bf45" len = "352588" productid="com.tencent.xin.emoticon.person.stiker_1678703862259eb01f2ef4a313" androidmd5="71ce49ed3ce9e57e43e07f802983bf45" androidlen="352588" s60v3md5 = "71ce49ed3ce9e57e43e07f802983bf45" s60v3len="352588" s60v5md5 = "71ce49ed3ce9e57e43e07f802983bf45" s60v5len="352588" cdnurl = "http://wxapp.tc.qq.com/262/20304/stodownload?m=71ce49ed3ce9e57e43e07f802983bf45&filekey=30350201010421301f020201060402535a041071ce49ed3ce9e57e43e07f802983bf45020305614c040d00000004627466730000000132&hy=SZ&storeid=263ffa00b000720d03274c5820000010600004f50535a1ca0c950b64287022&bizid=1023" designerid = "" thumburl = "http://mmbiz.qpic.cn/mmemoticon/ajNVdqHZLLDSKTMRgM8agiadpFhKz9IJ3cD5Ra2sTROibOaShdt3D4z6PfE92WkjQY/0" encrypturl = "http://wxapp.tc.qq.com/262/20304/stodownload?m=cbaae1d847aac6389652b65562bacaa2&filekey=30350201010421301f020201060402535a0410cbaae1d847aac6389652b65562bacaa20203056150040d00000004627466730000000132&hy=SZ&storeid=263ffa00b0008d8223274c5820000010600004f50535a17b82910b64764739&bizid=1023" aeskey= "7051ab2a34442dec63434832463f45ce" externurl = "http://wxapp.tc.qq.com/262/20304/stodownload?m=960f68693454dfa64b9966ca5d70dbd3&filekey=30340201010420301e020201060402535a0410960f68693454dfa64b9966ca5d70dbd3020221a0040d00000004627466730000000132&hy=SZ&storeid=26423dbe3000793a8720e40de0000010600004f50535a1d40c950b71be0a50&bizid=1023" externmd5 = "41895664fc5a77878e2155fc96209a19" width= "240" height= "240" tpurl= "" tpauthkey= "" attachedtext= "" attachedtextcolor= "" lensid= "" emojiattr= "" linkid= "" desc= "ChEKB2RlZmF1bHQSBuWNlee6rw==" ></emoji> </msg>'
|
||||
res1 = parser_xml(xml_string)
|
||||
print(res1, res1['md5'])
|
||||
# download(res1['cdnurl'], "./data/emoji/", res1['md5'])
|
||||
# download(res1['thumburl'], "./data/emoji/", res1['md5'], True)
|
||||
print(get_emoji(xml_string, True))
|
||||
print(get_emoji(xml_string, False))
|
||||
# http://vweixinf.tc.qq.com/110/20403/stodownload?m=3a4d439aba02dce4834b2c54e9f15597&filekey=3043020101042f302d02016e0402534804203361346434333961626130326463653438333462326335346539663135353937020213f0040d00000004627466730000000131&hy=SH&storeid=323032313037323030373236313130303039653236646365316535316534383236386234306230303030303036653033303034666233&ef=3&bizid=1022
|
@ -1,7 +1,7 @@
|
||||
import os
|
||||
|
||||
from app.decrypt import dat2pic
|
||||
from app.person_pc import MePC
|
||||
from app.util import dat2pic
|
||||
|
||||
if not os.path.exists('./data/image'):
|
||||
os.mkdir('./data/image')
|
||||
|
@ -15,7 +15,7 @@ class ViewController(QWidget):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.setWindowTitle('解密')
|
||||
self.setWindowIcon(QIcon('./app/data/icons/logo.svg'))
|
||||
self.setWindowIcon(QIcon(':/icons/icons/logo.svg'))
|
||||
self.viewMainWIndow = None
|
||||
self.viewDecrypt = None
|
||||
# 创建加载动画
|
||||
|
Loading…
Reference in New Issue
Block a user