Merge pull request #21 from LC044/dev_zsk

Dev zsk
This commit is contained in:
SiYuan 2023-11-22 23:09:24 +08:00 committed by GitHub
commit 640d7acadc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
31 changed files with 1023 additions and 13533 deletions

1
.gitignore vendored
View File

@ -13,4 +13,5 @@ app/DataBase/Msg/*
*.db *.db
*.pyc *.pyc
*.log *.log
*.spec
test* test*

View File

@ -4,15 +4,19 @@
<option name="autoReloadType" value="SELECTIVE" /> <option name="autoReloadType" value="SELECTIVE" />
</component> </component>
<component name="ChangeListManager"> <component name="ChangeListManager">
<list default="true" id="84e65474-7da9-466d-baf3-cc88dde3ffdd" name="变更" comment="更新wx选择的路径"> <list default="true" id="84e65474-7da9-466d-baf3-cc88dde3ffdd" name="变更" comment="优化启动过程">
<change afterPath="$PROJECT_DIR$/app/util/path.py" afterDir="false" /> <change afterPath="$PROJECT_DIR$/requirements_decrypt.txt" afterDir="false" />
<change beforePath="$PROJECT_DIR$/.gitignore" beforeDir="false" afterPath="$PROJECT_DIR$/.gitignore" afterDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" 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/config.py" beforeDir="false" afterPath="$PROJECT_DIR$/app/config.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/get_wx_info.py" beforeDir="false" afterPath="$PROJECT_DIR$/app/decrypt/get_wx_info.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/app/ui_pc/Icon.py" beforeDir="false" afterPath="$PROJECT_DIR$/app/ui_pc/Icon.py" afterDir="false" /> <change beforePath="$PROJECT_DIR$/app/log/logger.py" beforeDir="false" afterPath="$PROJECT_DIR$/app/log/logger.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/ui_pc/__init__.py" beforeDir="false" afterPath="$PROJECT_DIR$/app/ui_pc/__init__.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/app/ui_pc/mainview.py" beforeDir="false" afterPath="$PROJECT_DIR$/app/ui_pc/mainview.py" afterDir="false" /> <change beforePath="$PROJECT_DIR$/app/ui_pc/mainview.py" beforeDir="false" afterPath="$PROJECT_DIR$/app/ui_pc/mainview.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/app/util/__init__.py" beforeDir="false" afterPath="$PROJECT_DIR$/app/util/__init__.py" afterDir="false" /> <change beforePath="$PROJECT_DIR$/app/ui_pc/tool/__init__.py" beforeDir="false" afterPath="$PROJECT_DIR$/app/ui_pc/tool/__init__.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/app/ui_pc/tool/pc_decrypt/decryptUi.py" beforeDir="false" afterPath="$PROJECT_DIR$/app/ui_pc/tool/pc_decrypt/decryptUi.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/app/ui_pc/tool/pc_decrypt/pc_decrypt.py" beforeDir="false" afterPath="$PROJECT_DIR$/app/ui_pc/tool/pc_decrypt/pc_decrypt.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/decrypt_window.py" beforeDir="false" afterPath="$PROJECT_DIR$/decrypt_window.py" afterDir="false" />
</list> </list>
<option name="SHOW_DIALOG" value="false" /> <option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" /> <option name="HIGHLIGHT_CONFLICTS" value="true" />
@ -23,8 +27,9 @@
<option name="RECENT_TEMPLATES"> <option name="RECENT_TEMPLATES">
<list> <list>
<option value="Freeze Requirements File" /> <option value="Freeze Requirements File" />
<option value="HTML File" />
<option value="Python Script" /> <option value="Python Script" />
<option value="HTML File" />
<option value="Blank Requirements File" />
</list> </list>
</option> </option>
</component> </component>
@ -45,10 +50,23 @@
</map> </map>
</branch-storage> </branch-storage>
</excluded-from-favorite> </excluded-from-favorite>
<favorite-branches>
<branch-storage>
<map>
<entry type="LOCAL">
<value>
<list>
<branch-info repo="$PROJECT_DIR$" source="dev_zsk" />
</list>
</value>
</entry>
</map>
</branch-storage>
</favorite-branches>
<option name="PUSH_AUTO_UPDATE" value="true" /> <option name="PUSH_AUTO_UPDATE" value="true" />
<option name="RECENT_BRANCH_BY_REPOSITORY"> <option name="RECENT_BRANCH_BY_REPOSITORY">
<map> <map>
<entry key="$PROJECT_DIR$" value="dev_zsk" /> <entry key="$PROJECT_DIR$" value="master" />
</map> </map>
</option> </option>
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" /> <option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
@ -69,12 +87,12 @@
<option name="branches"> <option name="branches">
<list> <list>
<RecentBranch> <RecentBranch>
<option name="branchName" value="master" /> <option name="branchName" value="dev_zsk" />
<option name="lastUsedInstant" value="1700478623" /> <option name="lastUsedInstant" value="1700571991" />
</RecentBranch> </RecentBranch>
<RecentBranch> <RecentBranch>
<option name="branchName" value="dev_zsk" /> <option name="branchName" value="master" />
<option name="lastUsedInstant" value="1700046130" /> <option name="lastUsedInstant" value="1700478623" />
</RecentBranch> </RecentBranch>
</list> </list>
</option> </option>
@ -88,7 +106,7 @@
<component name="GithubPullRequestsUISettings"> <component name="GithubPullRequestsUISettings">
<option name="selectedUrlAndAccountId"> <option name="selectedUrlAndAccountId">
<UrlAndAccount> <UrlAndAccount>
<option name="accountId" value="17f6adba-af7f-4dcb-aeb1-4ed3d744f378" /> <option name="accountId" value="44b9bc65-44ba-4722-bca5-f2a7cbe5ba1f" />
<option name="url" value="https://github.com/LC044/WeChatMsg.git" /> <option name="url" value="https://github.com/LC044/WeChatMsg.git" />
</UrlAndAccount> </UrlAndAccount>
</option> </option>
@ -111,7 +129,7 @@
"RunOnceActivity.OpenProjectViewOnStart": "true", "RunOnceActivity.OpenProjectViewOnStart": "true",
"RunOnceActivity.ShowReadmeOnStart": "true", "RunOnceActivity.ShowReadmeOnStart": "true",
"last_opened_file_path": "D:/Program Files/Python310/Scripts/pyuic5.exe", "last_opened_file_path": "D:/Program Files/Python310/Scripts/pyuic5.exe",
"settings.editor.selected.configurable": "preferences.pluginManager" "settings.editor.selected.configurable": "preferences.externalTools"
} }
}]]></component> }]]></component>
<component name="RecentsManager"> <component name="RecentsManager">
@ -121,7 +139,7 @@
<recent name="D:\Project\PythonProject\WeChatMsg\app\Ui" /> <recent name="D:\Project\PythonProject\WeChatMsg\app\Ui" />
</key> </key>
</component> </component>
<component name="RunManager" selected="Python.main_pc"> <component name="RunManager" selected="Python.decrypt_window">
<configuration name="decrypt_window" type="PythonConfigurationType" factoryName="Python" temporary="true" nameIsGenerated="true"> <configuration name="decrypt_window" type="PythonConfigurationType" factoryName="Python" temporary="true" nameIsGenerated="true">
<module name="WeChatMsg" /> <module name="WeChatMsg" />
<option name="INTERPRETER_OPTIONS" value="" /> <option name="INTERPRETER_OPTIONS" value="" />
@ -143,27 +161,6 @@
<option name="INPUT_FILE" value="" /> <option name="INPUT_FILE" value="" />
<method v="2" /> <method v="2" />
</configuration> </configuration>
<configuration name="hard_link" 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/DataBase" />
<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/DataBase/hard_link.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="main" type="PythonConfigurationType" factoryName="Python" temporary="true" nameIsGenerated="true"> <configuration name="main" type="PythonConfigurationType" factoryName="Python" temporary="true" nameIsGenerated="true">
<module name="WeChatMsg" /> <module name="WeChatMsg" />
<option name="INTERPRETER_OPTIONS" value="" /> <option name="INTERPRETER_OPTIONS" value="" />
@ -179,7 +176,7 @@
<option name="SCRIPT_NAME" value="$PROJECT_DIR$/main.py" /> <option name="SCRIPT_NAME" value="$PROJECT_DIR$/main.py" />
<option name="PARAMETERS" value="" /> <option name="PARAMETERS" value="" />
<option name="SHOW_COMMAND_LINE" value="false" /> <option name="SHOW_COMMAND_LINE" value="false" />
<option name="EMULATE_TERMINAL" value="true" /> <option name="EMULATE_TERMINAL" value="false" />
<option name="MODULE_MODE" value="false" /> <option name="MODULE_MODE" value="false" />
<option name="REDIRECT_INPUT" value="false" /> <option name="REDIRECT_INPUT" value="false" />
<option name="INPUT_FILE" value="" /> <option name="INPUT_FILE" value="" />
@ -200,7 +197,7 @@
<option name="SCRIPT_NAME" value="$PROJECT_DIR$/main_pc.py" /> <option name="SCRIPT_NAME" value="$PROJECT_DIR$/main_pc.py" />
<option name="PARAMETERS" value="" /> <option name="PARAMETERS" value="" />
<option name="SHOW_COMMAND_LINE" value="false" /> <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="MODULE_MODE" value="false" />
<option name="REDIRECT_INPUT" value="false" /> <option name="REDIRECT_INPUT" value="false" />
<option name="INPUT_FILE" value="" /> <option name="INPUT_FILE" value="" />
@ -227,7 +224,7 @@
<option name="INPUT_FILE" value="" /> <option name="INPUT_FILE" value="" />
<method v="2" /> <method v="2" />
</configuration> </configuration>
<configuration name="test" type="PythonConfigurationType" factoryName="Python" temporary="true" nameIsGenerated="true"> <configuration name="test (1)" type="PythonConfigurationType" factoryName="Python" temporary="true" nameIsGenerated="true">
<module name="WeChatMsg" /> <module name="WeChatMsg" />
<option name="INTERPRETER_OPTIONS" value="" /> <option name="INTERPRETER_OPTIONS" value="" />
<option name="PARENT_ENVS" value="true" /> <option name="PARENT_ENVS" value="true" />
@ -248,13 +245,34 @@
<option name="INPUT_FILE" value="" /> <option name="INPUT_FILE" value="" />
<method v="2" /> <method v="2" />
</configuration> </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$/app/components" />
<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/components/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> <recent_temporary>
<list> <list>
<item itemvalue="Python.main_pc" />
<item itemvalue="Python.test" />
<item itemvalue="Python.hard_link" />
<item itemvalue="Python.decrypt_window" /> <item itemvalue="Python.decrypt_window" />
<item itemvalue="Python.main" /> <item itemvalue="Python.main" />
<item itemvalue="Python.main_pc" />
<item itemvalue="Python.test (1)" />
<item itemvalue="Python.test" />
</list> </list>
</recent_temporary> </recent_temporary>
</component> </component>
@ -270,48 +288,6 @@
<option name="presentableId" value="Default" /> <option name="presentableId" value="Default" />
<updated>1672848140146</updated> <updated>1672848140146</updated>
</task> </task>
<task id="LOCAL-00036" summary="重构一些class删除一些不必要的文件">
<created>1698765961025</created>
<option name="number" value="00036" />
<option name="presentableId" value="LOCAL-00036" />
<option name="project" value="LOCAL" />
<updated>1698765961025</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" />
<option name="presentableId" value="LOCAL-00038" />
<option name="project" value="LOCAL" />
<updated>1698853140384</updated>
</task>
<task id="LOCAL-00039" summary="替换chat里的contact">
<created>1698940208580</created>
<option name="number" value="00039" />
<option name="presentableId" value="LOCAL-00039" />
<option name="project" value="LOCAL" />
<updated>1698940208580</updated>
</task>
<task id="LOCAL-00040" summary="增加中文路径提示">
<created>1699025065814</created>
<option name="number" value="00040" />
<option name="presentableId" value="LOCAL-00040" />
<option name="project" value="LOCAL" />
<updated>1699025065814</updated>
</task>
<task id="LOCAL-00041" summary="update readme">
<created>1699026207401</created>
<option name="number" value="00041" />
<option name="presentableId" value="LOCAL-00041" />
<option name="project" value="LOCAL" />
<updated>1699026207401</updated>
</task>
<task id="LOCAL-00042" summary="用stackWidget重写contactUI"> <task id="LOCAL-00042" summary="用stackWidget重写contactUI">
<created>1699104087256</created> <created>1699104087256</created>
<option name="number" value="00042" /> <option name="number" value="00042" />
@ -613,7 +589,49 @@
<option name="project" value="LOCAL" /> <option name="project" value="LOCAL" />
<updated>1700490633275</updated> <updated>1700490633275</updated>
</task> </task>
<option name="localTasksCounter" value="85" /> <task id="LOCAL-00085" summary="显示聊天图片">
<created>1700492891759</created>
<option name="number" value="00085" />
<option name="presentableId" value="LOCAL-00085" />
<option name="project" value="LOCAL" />
<updated>1700492891759</updated>
</task>
<task id="LOCAL-00086" summary="支持显示聊天图片">
<created>1700574536723</created>
<option name="number" value="00086" />
<option name="presentableId" value="LOCAL-00086" />
<option name="project" value="LOCAL" />
<updated>1700574536724</updated>
</task>
<task id="LOCAL-00087" summary="支持导出HTML">
<created>1700576604990</created>
<option name="number" value="00087" />
<option name="presentableId" value="LOCAL-00087" />
<option name="project" value="LOCAL" />
<updated>1700576604990</updated>
</task>
<task id="LOCAL-00088" summary="修复HTML卡顿的问题">
<created>1700583772986</created>
<option name="number" value="00088" />
<option name="presentableId" value="LOCAL-00088" />
<option name="project" value="LOCAL" />
<updated>1700583772986</updated>
</task>
<task id="LOCAL-00089" summary="update readme">
<created>1700583952342</created>
<option name="number" value="00089" />
<option name="presentableId" value="LOCAL-00089" />
<option name="project" value="LOCAL" />
<updated>1700583952342</updated>
</task>
<task id="LOCAL-00090" summary="优化启动过程">
<created>1700658736626</created>
<option name="number" value="00090" />
<option name="presentableId" value="LOCAL-00090" />
<option name="project" value="LOCAL" />
<updated>1700658736626</updated>
</task>
<option name="localTasksCounter" value="91" />
<servers /> <servers />
</component> </component>
<component name="UnknownFeatures"> <component name="UnknownFeatures">
@ -636,7 +654,7 @@
<entry key="branch"> <entry key="branch">
<value> <value>
<list> <list>
<option value="master" /> <option value="dev_zsk" />
</list> </list>
</value> </value>
</entry> </entry>
@ -649,11 +667,6 @@
</option> </option>
</component> </component>
<component name="VcsManagerConfiguration"> <component name="VcsManagerConfiguration">
<MESSAGE value="删除多余的Word文件" />
<MESSAGE value="修复无法查找wxid的bug" />
<MESSAGE value="修改UI" />
<MESSAGE value="新增联系人头像组件" />
<MESSAGE value="头像支持显示二进制" />
<MESSAGE value="显示联系人信息" /> <MESSAGE value="显示联系人信息" />
<MESSAGE value="修复db文件空格路径的bug" /> <MESSAGE value="修复db文件空格路径的bug" />
<MESSAGE value="修复情感分析数值显示过长的bug" /> <MESSAGE value="修复情感分析数值显示过长的bug" />
@ -667,14 +680,19 @@
<MESSAGE value="聊天记录从后往前显示" /> <MESSAGE value="聊天记录从后往前显示" />
<MESSAGE value="聊天消息自适应" /> <MESSAGE value="聊天消息自适应" />
<MESSAGE value="新版本更新" /> <MESSAGE value="新版本更新" />
<MESSAGE value="update readme" />
<MESSAGE value="修复时间插入位置" /> <MESSAGE value="修复时间插入位置" />
<MESSAGE value="修复第一次启动的显示问题" /> <MESSAGE value="修复第一次启动的显示问题" />
<MESSAGE value="支持查找功能" /> <MESSAGE value="支持查找功能" />
<MESSAGE value="修复修改wixd的bug" /> <MESSAGE value="修复修改wixd的bug" />
<MESSAGE value="文字消息设置圆角" /> <MESSAGE value="文字消息设置圆角" />
<MESSAGE value="更新wx选择的路径" /> <MESSAGE value="更新wx选择的路径" />
<option name="LAST_COMMIT_MESSAGE" value="更新wx选择的路径" /> <MESSAGE value="显示聊天图片" />
<MESSAGE value="支持显示聊天图片" />
<MESSAGE value="支持导出HTML" />
<MESSAGE value="修复HTML卡顿的问题" />
<MESSAGE value="update readme" />
<MESSAGE value="优化启动过程" />
<option name="LAST_COMMIT_MESSAGE" value="优化启动过程" />
<option name="OPTIMIZE_IMPORTS_BEFORE_PROJECT_COMMIT" value="true" /> <option name="OPTIMIZE_IMPORTS_BEFORE_PROJECT_COMMIT" value="true" />
<option name="REFORMAT_BEFORE_PROJECT_COMMIT" value="true" /> <option name="REFORMAT_BEFORE_PROJECT_COMMIT" value="true" />
</component> </component>
@ -693,9 +711,24 @@
</line-breakpoint> </line-breakpoint>
<line-breakpoint enabled="true" suspend="THREAD" type="python-line"> <line-breakpoint enabled="true" suspend="THREAD" type="python-line">
<url>file://$PROJECT_DIR$/app/decrypt/decrypt.py</url> <url>file://$PROJECT_DIR$/app/decrypt/decrypt.py</url>
<line>103</line> <line>107</line>
<option name="timeStamp" value="9" /> <option name="timeStamp" value="9" />
</line-breakpoint> </line-breakpoint>
<line-breakpoint enabled="true" suspend="THREAD" type="python-line">
<url>file://$PROJECT_DIR$/app/person.py</url>
<line>103</line>
<option name="timeStamp" value="10" />
</line-breakpoint>
<line-breakpoint enabled="true" suspend="THREAD" type="python-line">
<url>file://$PROJECT_DIR$/app/person.py</url>
<line>101</line>
<option name="timeStamp" value="11" />
</line-breakpoint>
<line-breakpoint enabled="true" suspend="THREAD" type="python-line">
<url>file://$PROJECT_DIR$/app/person.py</url>
<line>102</line>
<option name="timeStamp" value="12" />
</line-breakpoint>
</breakpoints> </breakpoints>
<default-breakpoints> <default-breakpoints>
<breakpoint type="python-exception"> <breakpoint type="python-exception">

View File

@ -49,10 +49,14 @@ def get_messages(username_):
''' '''
result = [] result = []
for cur in cursor: for cur in cursor:
cur.execute(sql, [username_]) try:
result_ = cur.fetchall() lock.acquire(True)
# print(len(result)) cur.execute(sql, [username_])
result += result_ result_ = cur.fetchall()
# print(len(result))
result += result_
finally:
lock.release()
result.sort(key=lambda x: x[5]) result.sort(key=lambda x: x[5])
return result return result
@ -63,7 +67,7 @@ def get_message_by_num(username_, local_id):
from MSG from MSG
where StrTalker = ? and localId < ? where StrTalker = ? and localId < ?
order by CreateTime desc order by CreateTime desc
limit 30 limit 10
''' '''
result = [] result = []
try: try:

View File

@ -5,6 +5,7 @@ from PyQt5.QtCore import pyqtSignal, QThread
from . import msg from . import msg
from ..log import log from ..log import log
from ..person import MePC
if not os.path.exists('./data/聊天记录'): if not os.path.exists('./data/聊天记录'):
os.mkdir('./data/聊天记录') os.mkdir('./data/聊天记录')
@ -24,6 +25,7 @@ class Output(QThread):
def __init__(self, contact, parent=None, type_=DOCX): def __init__(self, contact, parent=None, type_=DOCX):
super().__init__(parent) super().__init__(parent)
self.last_timestamp = 0
self.sec = 2 # 默认1000秒 self.sec = 2 # 默认1000秒
self.contact = contact self.contact = contact
self.ta_username = contact.wxid self.ta_username = contact.wxid
@ -51,9 +53,682 @@ class Output(QThread):
df.to_csv(filename, encoding='utf-8') df.to_csv(filename, encoding='utf-8')
self.okSignal.emit('ok') self.okSignal.emit('ok')
def to_html(self):
self.okSignal.emit('ok')
def is_5_min(self, timestamp):
if abs(timestamp - self.last_timestamp) > 300:
self.last_timestamp = timestamp
return True
return False
def progress(self, value):
self.progressSignal.emit(value)
def run(self): def run(self):
if self.output_type == self.DOCX: if self.output_type == self.DOCX:
return return
elif self.output_type == self.CSV: elif self.output_type == self.CSV:
# print("线程导出csv") # print("线程导出csv")
self.to_csv(self.ta_username, "path") self.to_csv(self.ta_username, "path")
elif self.output_type == self.HTML:
# self.to_html()
self.Child0 = ChildThread(self.contact, type_=ChildThread.HTML)
self.Child0.progressSignal.connect(self.progress)
self.Child0.rangeSignal.connect(self.rangeSignal)
self.Child0.okSignal.connect(self.okSignal)
self.Child0.run()
# self.okSignal.emit(1)
class ChildThread(QThread):
"""
子线程用于导出部分聊天记录
"""
progressSignal = pyqtSignal(int)
rangeSignal = pyqtSignal(int)
okSignal = pyqtSignal(int)
i = 1
CSV = 0
DOCX = 1
HTML = 2
def __init__(self, contact, parent=None, type_=DOCX):
super().__init__(parent)
self.contact = contact
self.last_timestamp = 0
self.sec = 2 # 默认1000秒
self.msg_id = 0
self.output_type = type_
def is_5_min(self, timestamp):
if abs(timestamp - self.last_timestamp) > 300:
self.last_timestamp = timestamp
return True
return False
def text(self, doc, isSend, message, status):
return
def image(self, doc, isSend, Type, content, imgPath):
return
def emoji(self, doc, isSend, content, imgPath):
return
def wx_file(self, doc, isSend, content, status):
return
def retract_message(self, doc, isSend, content, status):
return
def reply(self, doc, isSend, content, status):
return
def pat_a_pat(self, doc, isSend, content, status):
return
def video(self, doc, isSend, content, status, img_path):
return
def to_html(self):
origin_docx_path = f"{os.path.abspath('.')}/data/聊天记录/{self.contact.remark}"
if not os.path.exists(origin_docx_path):
os.mkdir(origin_docx_path)
messages = msg.get_messages(self.contact.wxid)
filename = f"{os.path.abspath('.')}/data/聊天记录/{self.contact.remark}/{self.contact.remark}.html"
f = open(filename, 'w', encoding='utf-8')
html_head = '''
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
*{
padding: 0;
margin: 0;
}
body{
height: 100vh;
width: 100%;
display: flex;
align-items: center;
justify-content: center;
}
.container{
height: 760px;
width: 900px;
border-radius: 4px;
border: 0.5px solid #e0e0e0;
background-color: #f5f5f5;
display: flex;
flex-flow: column;
overflow: hidden;
}
.content{
width: calc(100% - 40px);
padding: 20px;
overflow-y: scroll;
flex: 1;
}
.content:hover::-webkit-scrollbar-thumb{
background:rgba(0,0,0,0.1);
}
.bubble{
max-width: 400px;
padding: 10px;
border-radius: 5px;
position: relative;
color: #000;
word-wrap:break-word;
word-break:normal;
}
.item-left .bubble{
margin-left: 15px;
background-color: #fff;
}
.item-left .bubble:before{
content: "";
position: absolute;
width: 0;
height: 0;
border-left: 10px solid transparent;
border-top: 10px solid transparent;
border-right: 10px solid #fff;
border-bottom: 10px solid transparent;
left: -20px;
}
.item-right .bubble{
margin-right: 15px;
background-color: #9eea6a;
}
.item-right .bubble:before{
content: "";
position: absolute;
width: 0;
height: 0;
border-left: 10px solid #9eea6a;
border-top: 10px solid transparent;
border-right: 10px solid transparent;
border-bottom: 10px solid transparent;
right: -20px;
}
.item{
margin-top: 15px;
display: flex;
width: 100%;
}
.item.item-right{
justify-content: flex-end;
}
.item.item-center{
justify-content: center;
}
.item.item-center span{
font-size: 12px;
padding: 2px 4px;
color: #fff;
background-color: #dadada;
border-radius: 3px;
-moz-user-select:none; /*火狐*/
-webkit-user-select:none; /*webkit浏览器*/
-ms-user-select:none; /*IE10*/
-khtml-user-select:none; /*早期浏览器*/
user-select:none;
}
.avatar img{
width: 42px;
height: 42px;
border-radius: 50%;
}
.input-area{
border-top:0.5px solid #e0e0e0;
height: 150px;
display: flex;
flex-flow: column;
background-color: #fff;
}
textarea{
flex: 1;
padding: 5px;
font-size: 14px;
border: none;
cursor: pointer;
overflow-y: auto;
overflow-x: hidden;
outline:none;
resize:none;
}
.button-area{
display: flex;
height: 40px;
margin-right: 10px;
line-height: 40px;
padding: 5px;
justify-content: flex-end;
}
.button-area button{
width: 80px;
border: none;
outline: none;
border-radius: 4px;
float: right;
cursor: pointer;
}
/* 设置滚动条的样式 */
::-webkit-scrollbar {
width:10px;
}
/* 滚动槽 */
::-webkit-scrollbar-track {
-webkit-box-shadow:inset006pxrgba(0,0,0,0.3);
border-radius:8px;
}
/* 滚动条滑块 */
::-webkit-scrollbar-thumb {
border-radius:10px;
background:rgba(0,0,0,0);
-webkit-box-shadow:inset006pxrgba(0,0,0,0.5);
}
</style>
</head>
<body>
<div class="container" id="container" onscroll="handleScroll()">
<div class="content">
'''
f.write(html_head)
MePC().avatar.save(os.path.join(origin_docx_path, 'myhead.png'))
self.contact.avatar.save(os.path.join(origin_docx_path, 'tahead.png'))
self.rangeSignal.emit(len(messages))
for index, message in enumerate(messages):
type_ = message[2]
str_content = message[7]
str_time = message[8]
# print(type_, type(type_))
is_send = message[4]
avatar = MePC().avatar_path if is_send else self.contact.avatar_path
timestamp = message[5]
self.progressSignal.emit(index)
if type_ == 1:
if self.is_5_min(timestamp):
f.write(
f'''
<div class="item item-center"><span>{str_time}</span></div>
'''
)
if is_send:
f.write(
f'''
<div class="item item-right">
<div class="bubble bubble-right">{str_content}</div>
<div class="avatar">
<img src="myhead.png" />
</div>
</div>
'''
)
else:
f.write(
f'''
<div class="item item-left">
<div class="avatar">
<img src="tahead.png" />
</div>
<div class="bubble bubble-left">{str_content}
</div>
</div>
'''
)
html_end = '''
</div>
</div>
<script>
const container = document.getElementById('container');
const content = document.getElementById('content');
const totalItems = 1000;
const itemsPerPage = 20;
const itemHeight = 50;
function updateContent() {
const scrollTop = container.scrollTop;
const startIndex = Math.floor(scrollTop / itemHeight);
const endIndex = Math.min(startIndex + itemsPerPage, totalItems);
// Remove existing items
content.innerHTML = '';
// Add new items
for (let i = startIndex; i < endIndex; i++) {
const item = document.createElement('div');
item.className = 'item';
item.textContent = `Item ${i}`;
content.appendChild(item);
}
// Update container height to show correct scrollbar
container.style.height = totalItems * itemHeight + 'px';
}
function handleScroll() {
updateContent();
}
// Initial content rendering
updateContent();
</script>
</body>
</html>
'''
f.write(html_end)
f.close()
self.okSignal.emit(1)
def to_html_(self):
origin_docx_path = f"{os.path.abspath('.')}/data/聊天记录/{self.contact.remark}"
if not os.path.exists(origin_docx_path):
os.mkdir(origin_docx_path)
messages = msg.get_messages(self.contact.wxid)
filename = f"{os.path.abspath('.')}/data/聊天记录/{self.contact.remark}/{self.contact.remark}.html"
f = open(filename, 'w', encoding='utf-8')
html_head = '''
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Chat Records</title>
<style>
*{
padding: 0;
margin: 0;
}
body{
height: 100vh;
width: 100%;
display: flex;
align-items: center;
justify-content: center;
}
.container{
height: 760px;
width: 900px;
border-radius: 4px;
border: 0.5px solid #e0e0e0;
background-color: #f5f5f5;
display: flex;
flex-flow: column;
overflow: hidden;
}
.content{
width: calc(100% - 40px);
padding: 20px;
overflow-y: scroll;
flex: 1;
}
.content:hover::-webkit-scrollbar-thumb{
background:rgba(0,0,0,0.1);
}
.bubble{
max-width: 400px;
padding: 10px;
border-radius: 5px;
position: relative;
color: #000;
word-wrap:break-word;
word-break:normal;
}
.item-left .bubble{
margin-left: 15px;
background-color: #fff;
}
.item-left .bubble:before{
content: "";
position: absolute;
width: 0;
height: 0;
border-left: 10px solid transparent;
border-top: 10px solid transparent;
border-right: 10px solid #fff;
border-bottom: 10px solid transparent;
left: -20px;
}
.item-right .bubble{
margin-right: 15px;
background-color: #9eea6a;
}
.item-right .bubble:before{
content: "";
position: absolute;
width: 0;
height: 0;
border-left: 10px solid #9eea6a;
border-top: 10px solid transparent;
border-right: 10px solid transparent;
border-bottom: 10px solid transparent;
right: -20px;
}
.item{
margin-top: 15px;
display: flex;
width: 100%;
}
.item.item-right{
justify-content: flex-end;
}
.item.item-center{
justify-content: center;
}
.item.item-center span{
font-size: 12px;
padding: 2px 4px;
color: #fff;
background-color: #dadada;
border-radius: 3px;
-moz-user-select:none; /*火狐*/
-webkit-user-select:none; /*webkit浏览器*/
-ms-user-select:none; /*IE10*/
-khtml-user-select:none; /*早期浏览器*/
user-select:none;
}
.avatar img{
width: 42px;
height: 42px;
border-radius: 50%;
}
.input-area{
border-top:0.5px solid #e0e0e0;
height: 150px;
display: flex;
flex-flow: column;
background-color: #fff;
}
textarea{
flex: 1;
padding: 5px;
font-size: 14px;
border: none;
cursor: pointer;
overflow-y: auto;
overflow-x: hidden;
outline:none;
resize:none;
}
.button-area{
display: flex;
height: 40px;
margin-right: 10px;
line-height: 40px;
padding: 5px;
justify-content: flex-end;
}
.button-area button{
width: 80px;
border: none;
outline: none;
border-radius: 4px;
float: right;
cursor: pointer;
}
/* 设置滚动条的样式 */
::-webkit-scrollbar {
width:10px;
}
/* 滚动槽 */
::-webkit-scrollbar-track {
-webkit-box-shadow:inset006pxrgba(0,0,0,0.3);
border-radius:8px;
}
/* 滚动条滑块 */
::-webkit-scrollbar-thumb {
border-radius:10px;
background:rgba(0,0,0,0);
-webkit-box-shadow:inset006pxrgba(0,0,0,0.5);
}
</style>
</head>
<body>
<div class="container">
<div class="content" id="chat-container">
<div class="item item-center"><span>昨天 12:35</span></div>
<div class="item item-center"><span>你已添加了凡繁烦现在可以开始聊天了</span></div>
<div class="item item-left">
<div class="avatar">
<img src="https://dss1.bdstatic.com/70cFvXSh_Q1YnxGkpoWK1HF6hhy/it/u=25668084,2889217189&fm=26&gp=0.jpg" />
</div>
<div class="bubble bubble-left">您好,我在武汉你可以直接送过来吗我有时间的话可以自己过去拿<br/><br/>123
</div>
</div>
<div class="item item-right">
<div class="bubble bubble-right">hello<br/>你好呀</div>
<div class="avatar">
<img src="https://ss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=3313909130,2406410525&fm=15&gp=0.jpg" />
</div>
</div>
<div class="item item-center">
<span>昨天 13:15</span>
</div>
</div>
</div>
<div></div>
<div>
<button onclick="prevPage()">上一页</button>
<div id = "paginationInfo"></div>
<button onclick="nextPage()">下一页</button>
<div></div>
<input type="number" id="gotoPageInput" placeholder="跳转到第几页">
<button onclick="gotoPage()">跳转</button>
</div>
<script>
const chatContainer = document.getElementById('chat-container');
// Sample chat messages (replace this with your actual data)
const chatMessages = [
'''
f.write(html_head)
MePC().avatar.save(os.path.join(origin_docx_path, 'myhead.png'))
self.contact.avatar.save(os.path.join(origin_docx_path, 'tahead.png'))
self.rangeSignal.emit(len(messages))
for index, message in enumerate(messages):
type_ = message[2]
str_content = message[7]
str_time = message[8]
# print(type_, type(type_))
is_send = message[4]
# avatar = MePC().avatar_path if is_send else self.contact.avatar_path
# avatar = avatar.replace('\\', '\\\\')
avatar = 'myhead.png' if is_send else 'tahead.png'
timestamp = message[5]
self.progressSignal.emit(index)
str_content = str_content.replace('"', '\\"').replace('{', '\\{').replace('}', '\\}').replace('\n',
'\\n').replace(
"'", "\\'")
if type_ == 1:
if self.is_5_min(timestamp):
f.write(
f'''{{ type:0, text: '{str_time}',is_send:0,avatar_path:''}},'''
)
f.write(
f'''{{ type:{type_}, text: '{str_content}',is_send:{is_send},avatar_path:'{avatar}'}},'''
)
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>`
}
chatContainer.appendChild(messageElement);
}
}
const itemsPerPage = 100; // 每页显示的元素个数
let currentPage = 1; // 当前页
function renderPage(page) {
const container = document.getElementById('chat-container');
container.innerHTML = ''; // 清空容器
// 计算当前页应该显示的元素范围
const startIndex = (page - 1) * itemsPerPage;
const endIndex = startIndex + itemsPerPage;
console.log(page);
// 从数据列表中取出对应范围的元素并添加到容器中
for (let i = startIndex; i < endIndex && i < chatMessages.length; i++) {
const message = chatMessages[i];
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>`
}
chatContainer.appendChild(messageElement);
}
updatePaginationInfo();
}
function prevPage() {
if (currentPage > 1) {
currentPage--;
renderPage(currentPage);
}
}
function nextPage() {
const totalPages = Math.ceil(chatMessages.length / itemsPerPage);
if (currentPage < totalPages) {
currentPage++;
renderPage(currentPage);
}
}
function updatePaginationInfo() {
const totalPages = Math.ceil(chatMessages.length / itemsPerPage);
const paginationInfo = document.getElementById('paginationInfo');
paginationInfo.textContent = ` ${totalPages} 当前第 ${currentPage} `;
}
function gotoPage() {
const totalPages = Math.ceil(chatMessages.length / itemsPerPage);
const inputElement = document.getElementById('gotoPageInput');
const targetPage = parseInt(inputElement.value);
if (targetPage >= 1 && targetPage <= totalPages) {
currentPage = targetPage;
renderPage(currentPage);
} else {
alert('请输入有效的页码');
}
}
// 初始化页面
renderPage(currentPage);
</script>
</body>
</html>
'''
f.write(html_end)
f.close()
self.okSignal.emit(1)
def run(self):
if self.output_type == self.DOCX:
return
elif self.output_type == self.CSV:
return
elif self.output_type == self.HTML:
self.to_html_()

View File

@ -104,25 +104,35 @@ class OpenImageThread(QThread):
class ImageMessage(QLabel): class ImageMessage(QLabel):
def __init__(self, image, image_link='', max_width=480, max_height=720, parent=None): def __init__(self, image, image_link='', max_width=480, max_height=240, parent=None):
""" """
param:image 图像路径或者QPixmap对象 param:image 图像路径或者QPixmap对象
param:image_link='' 点击图像打开的文件路径 param:image_link='' 点击图像打开的文件路径
""" """
super().__init__(parent) super().__init__(parent)
self.image = QLabel(self) self.image = QLabel(self)
self.max_width = max_width
self.max_height = max_height
if isinstance(image, str): if isinstance(image, str):
self.setPixmap(QPixmap(image)) pixmap = QPixmap(image)
self.image_path = image self.image_path = image
elif isinstance(image, QPixmap): elif isinstance(image, QPixmap):
self.setPixmap(image) pixmap = image
self.set_image(pixmap)
if image_link: if image_link:
self.image_path = image_link self.image_path = image_link
self.setMaximumWidth(max_width) self.setMaximumWidth(self.max_width)
self.setMaximumHeight(max_height) self.setMaximumHeight(self.max_height)
# self.setScaledContents(True) # self.setScaledContents(True)
def set_image(self, pixmap):
# 计算调整后的大小
adjusted_width = min(pixmap.width(), self.max_width)
adjusted_height = min(pixmap.height(), self.max_height)
self.setPixmap(pixmap.scaled(adjusted_width, adjusted_height, Qt.KeepAspectRatio))
# 调整QLabel的大小以适应图片的宽高但不超过最大宽高
self.setFixedSize(adjusted_width, adjusted_height)
def mousePressEvent(self, event): def mousePressEvent(self, event):
if event.buttons() == Qt.LeftButton: # 左键按下 if event.buttons() == Qt.LeftButton: # 左键按下
print('打开图像', self.image_path) print('打开图像', self.image_path)

View File

@ -3,6 +3,6 @@ contact = '474379264'
description = [ description = [
'1. 支持获取个人信息\n', '1. 支持获取个人信息\n',
'2. 支持显示聊天界面\n', '2. 支持显示聊天界面\n',
'3. 支持导出scv格式的聊天记录\n', '3. 支持导出聊天记录\n * csv\n * html\n',
'4. 查找联系人\n', '4. 查找联系人\n',
] ]

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,252 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<script src="https://cdn.bootcss.com/jquery/1.10.2/jquery.min.js"></script>
<title></title>
<!--
@time: 2018-08-04
@version: 0.0.1
@author: Mortal
-->
<style type="text/css">
/*
* 说明:
* 标注为慎删的属性暂时认定可以删除,即在作者测试的环境下删除暂时没有影响,但不代表所有环境下删除都没有影响
* 其他属性一概不可以删除
*/
html,
body {
height: 100%;
}
body,
ul,
li,
a,
p,
div {
/*慎删*/
padding: 0px;
margin: 0px;
}
#wrap {
overflow: hidden;
width: 100%;
}
#main {
top: 0;
position: relative;
}
.page {
/*谨删*/
width: 100%;
margin: 0;
}
#pageUl {
position: fixed;
right: 10px;
}
</style>
</head>
<body>
<!--
每个全屏页面div的class为page其中的图片的class为pageImg
ul为右侧的导航栏
pageUlLi和page的数目必须相等修改数目时还应修改最下面js鼠标悬停的跳转代码
-->
<div id="wrap">
<div id="main">
<ul id="pageUl" type="circle">
<li id="pageUlLi1" class="pageUlLi" style="color: red;"> </li>
<li id="pageUlLi2" class="pageUlLi"> </li>
<li id="pageUlLi3" class="pageUlLi"> </li>
<li id="pageUlLi4" class="pageUlLi"> </li>
<li id="pageUlLi5" class="pageUlLi"> </li>
<li id="pageUlLi6" class="pageUlLi"> </li>
<li id="pageUlLi7" class="pageUlLi"> </li>
</ul>
<div id="page1" class="page">
<iframe src="0.html" frameborder="0" height="100%"
width="100%"></iframe>
</div>
<div id="page2" class="page">
<iframe src="1.html" frameborder="0" height="100%"
width="100%"></iframe>
</div>
<div style="background-color: #8a6d3b" id="page3" class="page">
<iframe src="2.html" frameborder="0" id="iframe0" height="100%"
width="100%"></iframe>
</div>
<div style="background-color: #337ab7" id="page4" class="page">
<iframe src="3.html" frameborder="0" id="iframe3" height="100%"
width="100%"></iframe>
</div>
<div style="background-color: #337ab7" id="page5" class="page">
<iframe src="4.html" frameborder="0" id="iframe4" height="100%"
width="100%"></iframe>
</div>
<div style="background-color: #337ab7" id="page6" class="page">
<iframe src="5.html" frameborder="0" id="iframe5" height="100%"
width="100%"></iframe>
</div>
<div style="background-color: #337ab7" id="page7" class="page">
<iframe src="6.html" frameborder="0" id="iframe6" height="100%"
width="100%"></iframe>
</div>
</div>
</div>
</body>
<script type="text/javascript">
//改变窗口大小时调整图片大小
window.onload = resizeImages;
window.onresize = resizeImages;
function resizeImages() {
$(function (e) {
var screenWeight = document.documentElement.clientWidth;
var screenHeight = document.documentElement.clientHeight;
$("[name=pageImg]").css("width", screenWeight).css("height", screenHeight);
$("#pageUl").css("bottom", screenHeight >> 1);
});
}
var index = 1;
var curIndex = 1;
var wrap = document.getElementById("wrap");
var main = document.getElementById("main");
var hei = document.body.clientHeight;
wrap.style.height = hei + "px";
var obj = document.getElementsByTagName("div");
for (var i = 0; i < obj.length; i++) {
if (obj[i].className == 'page') {
obj[i].style.height = hei + "px";
}
}
var pageNum = document.querySelectorAll(".page").length;
//如果不加时间控制,滚动会过度灵敏,一次翻好几屏
var startTime = 0, //翻屏起始时间
endTime = 0,
now = 0;
//浏览器兼容
if ((navigator.userAgent.toLowerCase().indexOf("firefox") != -1)) {
document.addEventListener("DOMMouseScroll", scrollFun, false);
} else if (document.addEventListener) {
document.addEventListener("mousewheel", scrollFun, false);
} else if (document.attachEvent) {
document.attachEvent("onmousewheel", scrollFun);
} else {
document.onmousewheel = scrollFun;
}
//滚动事件处理函数
function scrollFun(event) {
startTime = new Date().getTime();
var delta = event.detail || (-event.wheelDelta);
//mousewheel事件中的 “event.wheelDelta” 属性值:返回的如果是正值说明滚轮是向上滚动
//DOMMouseScroll事件中的 “event.detail” 属性值:返回的如果是负值说明滚轮是向上滚动
if ((endTime - startTime) < -1000) {
if (delta > 0 && parseInt(main.offsetTop) > -(hei * (pageNum - 1))) {
//向下滚动
index++;
toPage(index);
}
if (delta < 0 && parseInt(main.offsetTop) < 0) {
//向上滚动
index--;
toPage(index);
}
endTime = new Date().getTime();
} else {
event.preventDefault();
}
}
function toPage(idx) {
//jquery实现动画效果
if(idx!=curIndex){
index=idx
var delta=idx - curIndex;
now = now - delta * hei;
$("#main").animate({
top: (now + 'px')
}, 500);
curIndex = idx;
//更改列表的选中项
$(".pageUlLi").css("color", "black");
$("#pageUlLi" + idx).css("color", "red");
}
}
// //鼠标悬停翻页
// document.getElementById("pageUlLi1").onmouseover = function () {
// toPage(1);
// }
// document.getElementById("pageUlLi2").onmouseover = function () {
// toPage(2);
// }
// document.getElementById("pageUlLi3").onmouseover = function () {
// toPage(3);
// }
// document.getElementById("pageUlLi4").onmouseover = function () {
// toPage(4);
// }
// document.getElementById("pageUlLi5").onmouseover = function () {
// toPage(5);
// }
//鼠标点击翻页
document.getElementById("pageUlLi1").onclick = function () {
toPage(1);
}
document.getElementById("pageUlLi2").onclick = function () {
toPage(2);
}
document.getElementById("pageUlLi3").onclick = function () {
toPage(3);
}
document.getElementById("pageUlLi4").onclick = function () {
toPage(4);
}
document.getElementById("pageUlLi5").onclick = function () {
toPage(5);
}
</script>
</html>

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 7.5 KiB

View File

@ -1,5 +1,5 @@
import os import os
# 图片字节头信息, # 图片字节头信息,
# [0][1]为jpg头信息 # [0][1]为jpg头信息
# [2][3]为png头信息 # [2][3]为png头信息
@ -21,7 +21,7 @@ def get_code(file_path):
return -1, -1 return -1, -1
dat_file = open(file_path, "rb") dat_file = open(file_path, "rb")
dat_read = dat_file.read(2) dat_read = dat_file.read(2)
print(dat_read) # print(dat_read)
head_index = 0 head_index = 0
while head_index < len(pic_head): while head_index < len(pic_head):
# 使用第一个头信息字节来计算加密码 # 使用第一个头信息字节来计算加密码
@ -33,7 +33,7 @@ def get_code(file_path):
dat_file.close() dat_file.close()
return head_index, code return head_index, code
head_index = head_index + 1 head_index = head_index + 1
dat_file.close()
print("not jpg, png, gif") print("not jpg, png, gif")
return -1, -1 return -1, -1
@ -49,26 +49,24 @@ def decode_dat(file_path, out_path):
if decode_code == -1: if decode_code == -1:
return return
if file_type == 1: if file_type == 1:
pic_name = file_path.split("\\")[-1][:-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 = file_path[:-4] + ".png"
elif file_type == 5: elif file_type == 5:
pic_name = file_path[:-4] + ".gif" pic_name = file_path[:-4] + ".gif"
else: else:
pic_name = file_path[:-4] + ".jpg" pic_name = file_path[:-4] + ".jpg"
dat_file = open(file_path, "rb")
file_outpath = os.path.join(out_path, pic_name) file_outpath = os.path.join(out_path, pic_name)
print(pic_name) if os.path.exists(file_outpath):
print(file_outpath) return file_outpath
pic_write = open(file_outpath, "wb") with open(file_path, 'rb') as file_in:
for dat_data in dat_file: data = file_in.read()
for dat_byte in dat_data: # 对数据进行异或加密/解密
pic_data = dat_byte ^ decode_code encrypted_data = bytes([byte ^ decode_code for byte in data])
pic_write.write(bytes([pic_data])) with open(file_outpath, 'wb') as file_out:
print(pic_name + "完成") file_out.write(encrypted_data)
dat_file.close() print(file_path, '->', file_outpath)
pic_write.close() return file_outpath
def find_datfile(dir_path, out_path): def find_datfile(dir_path, out_path):
@ -88,4 +86,4 @@ if __name__ == "__main__":
outpath = "D:\\test" outpath = "D:\\test"
if not os.path.exists(outpath): if not os.path.exists(outpath):
os.mkdir(outpath) os.mkdir(outpath)
find_datfile(path, outpath) find_datfile(path, outpath)

View File

@ -123,13 +123,25 @@ def read_info(version_list, is_logging=False):
return result return result
import os
import sys
def resource_path(relative_path):
""" Get absolute path to resource, works for dev and for PyInstaller """
base_path = getattr(sys, '_MEIPASS', os.path.dirname(os.path.abspath(__file__)))
return os.path.join(base_path, relative_path)
@log @log
def get_info(): def get_info():
VERSION_LIST_PATH = "app/decrypt/version_list.json" VERSION_LIST_PATH = "app/decrypt/version_list.json"
try:
with open(VERSION_LIST_PATH, "r", encoding="utf-8") as f: with open(VERSION_LIST_PATH, "r", encoding="utf-8") as f:
VERSION_LIST = json.load(f) VERSION_LIST = json.load(f)
except:
with open(resource_path(VERSION_LIST_PATH), "r", encoding="utf-8") as f:
VERSION_LIST = json.load(f)
result = read_info(VERSION_LIST, True) # 读取微信信息 result = read_info(VERSION_LIST, True) # 读取微信信息
return result return result

View File

@ -5,19 +5,21 @@ import traceback
from functools import wraps from functools import wraps
filename = time.strftime("%Y-%m-%d", time.localtime(time.time())) filename = time.strftime("%Y-%m-%d", time.localtime(time.time()))
if not os.path.exists('./app/log/logs'):
os.mkdir('./app/log/logs')
logger = logging.getLogger('test') logger = logging.getLogger('test')
logger.setLevel(level=logging.DEBUG) logger.setLevel(level=logging.DEBUG)
formatter = logging.Formatter('%(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s: %(message)s') formatter = logging.Formatter('%(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s: %(message)s')
file_handler = logging.FileHandler(f'./app/log/logs/{filename}-log.log') try:
if not os.path.exists('./app/log/logs'):
os.mkdir('./app/log/logs')
file_handler = logging.FileHandler(f'./app/log/logs/{filename}-log.log')
except:
file_handler = logging.FileHandler(f'{filename}-log.log')
file_handler.setLevel(level=logging.INFO) file_handler.setLevel(level=logging.INFO)
file_handler.setFormatter(formatter) file_handler.setFormatter(formatter)
stream_handler = logging.StreamHandler() stream_handler = logging.StreamHandler()
stream_handler.setLevel(logging.DEBUG) stream_handler.setLevel(logging.DEBUG)
stream_handler.setFormatter(formatter) stream_handler.setFormatter(formatter)
logger.addHandler(file_handler) logger.addHandler(file_handler)
logger.addHandler(stream_handler) logger.addHandler(stream_handler)

View File

@ -55,6 +55,7 @@ def singleton(cls):
class MePC: class MePC:
def __init__(self): def __init__(self):
self.avatar = QPixmap(Icon.Default_avatar_path) self.avatar = QPixmap(Icon.Default_avatar_path)
self.avatar_path = 'D:\Project\Python\WeChatMsg\\app\data\icons\default_avatar.svg'
self.wxid = '' self.wxid = ''
self.wx_dir = '' self.wx_dir = ''
self.name = '' self.name = ''
@ -82,6 +83,7 @@ class ContactPC:
self.smallHeadImgUrl = contact_info.get('smallHeadImgUrl') self.smallHeadImgUrl = contact_info.get('smallHeadImgUrl')
self.smallHeadImgBLOG = b'' self.smallHeadImgBLOG = b''
self.avatar = QPixmap() self.avatar = QPixmap()
self.avatar_path = 'D:\Project\Python\WeChatMsg\\app\data\icons\default_avatar.svg'
def set_avatar(self, img_bytes): def set_avatar(self, img_bytes):
if not img_bytes: if not img_bytes:
@ -91,6 +93,7 @@ class ContactPC:
self.avatar.loadFromData(img_bytes, format='PNG') self.avatar.loadFromData(img_bytes, format='PNG')
else: else:
self.avatar.loadFromData(img_bytes, format='jfif') self.avatar.loadFromData(img_bytes, format='jfif')
self.avatar.scaled(60, 60, Qt.IgnoreAspectRatio, Qt.SmoothTransformation) self.avatar.scaled(60, 60, Qt.IgnoreAspectRatio, Qt.SmoothTransformation)

View File

@ -1,3 +0,0 @@
from . import mainview
__all__ = ['mainview']

View File

@ -74,7 +74,6 @@ class ChatInfo(QWidget):
def is_5_min(self, timestamp): def is_5_min(self, timestamp):
if abs(timestamp - self.last_timestamp) > 300: if abs(timestamp - self.last_timestamp) > 300:
self.last_timestamp = timestamp self.last_timestamp = timestamp
return True return True
return False return False
@ -100,6 +99,7 @@ class ChatInfo(QWidget):
) )
self.chat_window.add_message_item(bubble_message, 0) self.chat_window.add_message_item(bubble_message, 0)
elif type_ == 3: elif type_ == 3:
# return
if self.is_5_min(timestamp): if self.is_5_min(timestamp):
time_message = Notice(self.last_str_time) time_message = Notice(self.last_str_time)
self.last_str_time = str_time self.last_str_time = str_time

View File

@ -114,12 +114,8 @@ class ContactInfo(QWidget, Ui_Form):
self.outputThread = Output(self.contact, type_=Output.CSV) self.outputThread = Output(self.contact, type_=Output.CSV)
print('导出csv') print('导出csv')
elif self.sender() == self.toHtmlAct: elif self.sender() == self.toHtmlAct:
print('功能暂未实现') self.outputThread = Output(self.contact, type_=Output.HTML)
QMessageBox.warning(self,
"别急别急",
"马上就实现该功能"
)
return
self.outputThread.progressSignal.connect(self.output_progress) self.outputThread.progressSignal.connect(self.output_progress)
self.outputThread.rangeSignal.connect(self.set_progressBar_range) self.outputThread.rangeSignal.connect(self.set_progressBar_range)
self.outputThread.okSignal.connect(self.hide_progress_bar) self.outputThread.okSignal.connect(self.hide_progress_bar)
@ -139,5 +135,6 @@ class ContactInfo(QWidget, Ui_Form):
self.view_userinfo.progressBar.setProperty('value', value) self.view_userinfo.progressBar.setProperty('value', value)
def set_progressBar_range(self, value): def set_progressBar_range(self, value):
print('进度条范围', value)
self.view_userinfo.progressBar.setVisible(True) self.view_userinfo.progressBar.setVisible(True)
self.view_userinfo.progressBar.setRange(0, value) self.view_userinfo.progressBar.setRange(0, value)

View File

@ -9,10 +9,9 @@
""" """
import json import json
import os.path import os.path
from random import randint
from PyQt5.QtCore import * from PyQt5.QtCore import *
from PyQt5.QtGui import QPixmap from PyQt5.QtGui import QPixmap, QFont
from PyQt5.QtWidgets import * from PyQt5.QtWidgets import *
from app import config from app import config
@ -21,7 +20,7 @@ from app.Ui.Icon import Icon
from . import mainwindow from . import mainwindow
from .chat import ChatWindow from .chat import ChatWindow
from .contact import ContactWindow from .contact import ContactWindow
from .tool import ToolWindow from .tool.tool_window import ToolWindow
from ..person import MePC from ..person import MePC
# 美化样式表 # 美化样式表
@ -63,7 +62,8 @@ HistoryPanel::item:hover {
class MainWinController(QMainWindow, mainwindow.Ui_MainWindow): class MainWinController(QMainWindow, mainwindow.Ui_MainWindow):
exitSignal = pyqtSignal() exitSignal = pyqtSignal(bool)
okSignal = pyqtSignal(bool)
# username = '' # username = ''
def __init__(self, username, parent=None): def __init__(self, username, parent=None):
@ -75,8 +75,11 @@ class MainWinController(QMainWindow, mainwindow.Ui_MainWindow):
self.resize(QSize(800, 600)) self.resize(QSize(800, 600))
self.action_desc.triggered.connect(self.about) self.action_desc.triggered.connect(self.about)
self.load_data() self.load_data()
self.init_ui()
self.load_num = 0 self.load_num = 0
self.label = QLabel(self)
self.label.setGeometry((self.width() - 300) // 2, (self.height() - 100) // 2, 300, 100)
self.label.setPixmap(QPixmap('./app/data/icons/loading.svg'))
def load_data(self): def load_data(self):
if os.path.exists('./app/data/info.json'): if os.path.exists('./app/data/info.json'):
@ -98,12 +101,8 @@ class MainWinController(QMainWindow, mainwindow.Ui_MainWindow):
) )
def init_ui(self): def init_ui(self):
# self.movie = QMovie("./app/data/loading.gif") self.listWidget.setVisible(False)
self.label = QLabel(self) self.stackedWidget.setVisible(False)
self.label.setGeometry(0, 0, self.width(), self.height())
self.label.setVisible(False)
# self.label.setMovie(self.movie)
# self.movie.start()
self.listWidget.currentRowChanged.connect(self.setCurrentIndex) self.listWidget.currentRowChanged.connect(self.setCurrentIndex)
tool_item = QListWidgetItem(Icon.MyInfo_Icon, '工具', self.listWidget) tool_item = QListWidgetItem(Icon.MyInfo_Icon, '工具', self.listWidget)
chat_item = QListWidgetItem(Icon.Chat_Icon, '聊天', self.listWidget) chat_item = QListWidgetItem(Icon.Chat_Icon, '聊天', self.listWidget)
@ -116,24 +115,18 @@ class MainWinController(QMainWindow, mainwindow.Ui_MainWindow):
self.stackedWidget.addWidget(tool_window) self.stackedWidget.addWidget(tool_window)
self.listWidget.setCurrentRow(0) self.listWidget.setCurrentRow(0)
self.stackedWidget.setCurrentIndex(0) self.stackedWidget.setCurrentIndex(0)
chat_window = ChatWindow() self.chat_window = ChatWindow()
# chat_window = QWidget() # chat_window = QWidget()
self.stackedWidget.addWidget(chat_window) self.stackedWidget.addWidget(self.chat_window)
contact_window = ContactWindow() self.contact_window = ContactWindow()
self.stackedWidget.addWidget(contact_window) self.stackedWidget.addWidget(self.contact_window)
label = QLabel('我是页面') label = QLabel('该功能暂不支持哦')
label.setFont(QFont("微软雅黑", 50))
label.setAlignment(Qt.AlignCenter) label.setAlignment(Qt.AlignCenter)
# 设置label的背景颜色(这里随机)
# 这里加了一个margin边距(方便区分QStackedWidget和QLabel的颜色)
label.setStyleSheet('background: rgb(%d, %d, %d);margin: 50px;' % (
randint(0, 255), randint(0, 255), randint(0, 255)))
self.stackedWidget.addWidget(label) self.stackedWidget.addWidget(label)
tool_window.load_finish_signal.connect(self.loading) tool_window.load_finish_signal.connect(self.loading)
contact_window.load_finish_signal.connect(self.loading) self.contact_window.load_finish_signal.connect(self.loading)
# chat_window.load_finish_signal.connect(self.loading) self.chat_window.load_finish_signal.connect(self.loading)
# self.load_window_thread = LoadWindowThread(self.stackedWidget)
# self.load_window_thread.okSignal.connect(self.stop_loading)
# self.load_window_thread.start()
def setCurrentIndex(self, row): def setCurrentIndex(self, row):
self.stackedWidget.setCurrentIndex(row) self.stackedWidget.setCurrentIndex(row)
@ -170,11 +163,15 @@ class MainWinController(QMainWindow, mainwindow.Ui_MainWindow):
def loading(self, a0): def loading(self, a0):
self.load_num += 1 self.load_num += 1
self.label.setVisible(False) # self.label.setVisible(False)
# print('加载一个了') print('加载一个了')
if self.load_num == 2: if self.load_num == 2:
# print('ok了') print('ok了')
self.label.setVisible(False) self.label.clear()
self.label.hide()
self.okSignal.emit(True)
self.listWidget.setVisible(True)
self.stackedWidget.setVisible(True)
def about(self): def about(self):
""" """
@ -198,20 +195,20 @@ class LoadWindowThread(QThread):
windowSignal = pyqtSignal(QWidget) windowSignal = pyqtSignal(QWidget)
okSignal = pyqtSignal(bool) okSignal = pyqtSignal(bool)
def __init__(self, stackedWidget): def __init__(self):
super().__init__() super().__init__()
self.stackedWidget = stackedWidget self.num = 0
def loading(self):
self.num += 1
print('加载一个了')
if self.num == 2:
self.okSignal.emit(True)
def run(self): def run(self):
chat_window = ChatWindow() self.chat_window = ChatWindow()
self.stackedWidget.addWidget(chat_window) self.contact_window = ContactWindow()
contact_window = ContactWindow() self.contact_window.load_finish_signal.connect(self.loading)
self.stackedWidget.addWidget(contact_window) self.chat_window.load_finish_signal.connect(self.loading)
label = QLabel('我是页面') print('加载完成')
label.setAlignment(Qt.AlignCenter)
# 设置label的背景颜色(这里随机)
# 这里加了一个margin边距(方便区分QStackedWidget和QLabel的颜色)
label.setStyleSheet('background: rgb(%d, %d, %d);margin: 50px;' % (
randint(0, 255), randint(0, 255), randint(0, 255)))
self.stackedWidget.addWidget(label)
self.okSignal.emit(True) self.okSignal.emit(True)

View File

@ -1,3 +1 @@
from .tool_window import ToolWindow
__all__ = ['ToolWindow']

View File

@ -1,4 +1,9 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from PyQt5.QtCore import Qt, QSize, QCoreApplication, QMetaObject
from PyQt5.QtGui import QFont
from PyQt5.QtWidgets import QHBoxLayout, QVBoxLayout, QSpacerItem, QSizePolicy, QLabel, QGridLayout, QPushButton, \
QCheckBox, QLineEdit, QProgressBar
# Form implementation generated from reading ui file 'decryptUi.ui' # Form implementation generated from reading ui file 'decryptUi.ui'
# #
@ -8,49 +13,46 @@
# run again. Do not edit this file unless you know what you are doing. # run again. Do not edit this file unless you know what you are doing.
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_Dialog(object): class Ui_Dialog(object):
def setupUi(self, Dialog): def setupUi(self, Dialog):
Dialog.setObjectName("Dialog") Dialog.setObjectName("Dialog")
Dialog.resize(611, 519) Dialog.resize(611, 519)
font = QtGui.QFont() font = QFont()
font.setFamily("微软雅黑") font.setFamily("微软雅黑")
Dialog.setFont(font) Dialog.setFont(font)
Dialog.setLayoutDirection(QtCore.Qt.LeftToRight) Dialog.setLayoutDirection(Qt.LeftToRight)
self.horizontalLayout_4 = QtWidgets.QHBoxLayout(Dialog) self.horizontalLayout_4 = QHBoxLayout(Dialog)
self.horizontalLayout_4.setObjectName("horizontalLayout_4") self.horizontalLayout_4.setObjectName("horizontalLayout_4")
self.verticalLayout_2 = QtWidgets.QVBoxLayout() self.verticalLayout_2 = QVBoxLayout()
self.verticalLayout_2.setObjectName("verticalLayout_2") self.verticalLayout_2.setObjectName("verticalLayout_2")
spacerItem = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) spacerItem = QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding)
self.verticalLayout_2.addItem(spacerItem) self.verticalLayout_2.addItem(spacerItem)
self.horizontalLayout_3 = QtWidgets.QHBoxLayout() self.horizontalLayout_3 = QHBoxLayout()
self.horizontalLayout_3.setObjectName("horizontalLayout_3") self.horizontalLayout_3.setObjectName("horizontalLayout_3")
spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) spacerItem1 = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum)
self.horizontalLayout_3.addItem(spacerItem1) self.horizontalLayout_3.addItem(spacerItem1)
self.verticalLayout = QtWidgets.QVBoxLayout() self.verticalLayout = QVBoxLayout()
self.verticalLayout.setObjectName("verticalLayout") self.verticalLayout.setObjectName("verticalLayout")
self.label_3 = QtWidgets.QLabel(Dialog) self.label_3 = QLabel(Dialog)
font = QtGui.QFont() font = QFont()
font.setFamily("一纸情书") font.setFamily("一纸情书")
font.setPointSize(20) font.setPointSize(20)
self.label_3.setFont(font) self.label_3.setFont(font)
self.label_3.setAlignment(QtCore.Qt.AlignCenter) self.label_3.setAlignment(Qt.AlignCenter)
self.label_3.setObjectName("label_3") self.label_3.setObjectName("label_3")
self.verticalLayout.addWidget(self.label_3) self.verticalLayout.addWidget(self.label_3)
self.gridLayout_2 = QtWidgets.QGridLayout() self.gridLayout_2 = QGridLayout()
self.gridLayout_2.setObjectName("gridLayout_2") self.gridLayout_2.setObjectName("gridLayout_2")
self.gridLayout = QtWidgets.QGridLayout() self.gridLayout = QGridLayout()
self.gridLayout.setObjectName("gridLayout") self.gridLayout.setObjectName("gridLayout")
self.label_phone = QtWidgets.QLabel(Dialog) self.label_phone = QLabel(Dialog)
self.label_phone.setText("") self.label_phone.setText("")
self.label_phone.setObjectName("label_phone") self.label_phone.setObjectName("label_phone")
self.gridLayout.addWidget(self.label_phone, 2, 1, 1, 1) self.gridLayout.addWidget(self.label_phone, 2, 1, 1, 1)
self.label_7 = QtWidgets.QLabel(Dialog) self.label_7 = QLabel(Dialog)
self.label_7.setObjectName("label_7") self.label_7.setObjectName("label_7")
self.gridLayout.addWidget(self.label_7, 1, 0, 1, 1) self.gridLayout.addWidget(self.label_7, 1, 0, 1, 1)
self.lineEdit = QtWidgets.QLineEdit(Dialog) self.lineEdit = QLineEdit(Dialog)
self.lineEdit.setStyleSheet("background:transparent;\n" self.lineEdit.setStyleSheet("background:transparent;\n"
"\n" "\n"
" border-radius:5px;\n" " border-radius:5px;\n"
@ -65,43 +67,43 @@ class Ui_Dialog(object):
self.lineEdit.setFrame(False) self.lineEdit.setFrame(False)
self.lineEdit.setObjectName("lineEdit") self.lineEdit.setObjectName("lineEdit")
self.gridLayout.addWidget(self.lineEdit, 4, 1, 1, 1) self.gridLayout.addWidget(self.lineEdit, 4, 1, 1, 1)
self.label_5 = QtWidgets.QLabel(Dialog) self.label_5 = QLabel(Dialog)
self.label_5.setObjectName("label_5") self.label_5.setObjectName("label_5")
self.gridLayout.addWidget(self.label_5, 3, 0, 1, 1) self.gridLayout.addWidget(self.label_5, 3, 0, 1, 1)
self.label_6 = QtWidgets.QLabel(Dialog) self.label_6 = QLabel(Dialog)
self.label_6.setObjectName("label_6") self.label_6.setObjectName("label_6")
self.gridLayout.addWidget(self.label_6, 5, 0, 1, 1) self.gridLayout.addWidget(self.label_6, 5, 0, 1, 1)
self.label_key = QtWidgets.QLabel(Dialog) self.label_key = QLabel(Dialog)
self.label_key.setMaximumSize(QtCore.QSize(400, 16777215)) self.label_key.setMaximumSize(QSize(400, 16777215))
self.label_key.setText("") self.label_key.setText("")
self.label_key.setObjectName("label_key") self.label_key.setObjectName("label_key")
self.gridLayout.addWidget(self.label_key, 5, 1, 1, 1) self.gridLayout.addWidget(self.label_key, 5, 1, 1, 1)
self.label = QtWidgets.QLabel(Dialog) self.label = QLabel(Dialog)
self.label.setObjectName("label") self.label.setObjectName("label")
self.gridLayout.addWidget(self.label, 0, 0, 1, 1) self.gridLayout.addWidget(self.label, 0, 0, 1, 1)
self.label_2 = QtWidgets.QLabel(Dialog) self.label_2 = QLabel(Dialog)
self.label_2.setObjectName("label_2") self.label_2.setObjectName("label_2")
self.gridLayout.addWidget(self.label_2, 2, 0, 1, 1) self.gridLayout.addWidget(self.label_2, 2, 0, 1, 1)
self.label_pid = QtWidgets.QLabel(Dialog) self.label_pid = QLabel(Dialog)
self.label_pid.setText("") self.label_pid.setText("")
self.label_pid.setObjectName("label_pid") self.label_pid.setObjectName("label_pid")
self.gridLayout.addWidget(self.label_pid, 0, 1, 1, 1) self.gridLayout.addWidget(self.label_pid, 0, 1, 1, 1)
self.label_name = QtWidgets.QLabel(Dialog) self.label_name = QLabel(Dialog)
self.label_name.setText("") self.label_name.setText("")
self.label_name.setObjectName("label_name") self.label_name.setObjectName("label_name")
self.gridLayout.addWidget(self.label_name, 3, 1, 1, 1) self.gridLayout.addWidget(self.label_name, 3, 1, 1, 1)
self.label_4 = QtWidgets.QLabel(Dialog) self.label_4 = QLabel(Dialog)
self.label_4.setObjectName("label_4") self.label_4.setObjectName("label_4")
self.gridLayout.addWidget(self.label_4, 4, 0, 1, 1) self.gridLayout.addWidget(self.label_4, 4, 0, 1, 1)
self.label_version = QtWidgets.QLabel(Dialog) self.label_version = QLabel(Dialog)
self.label_version.setText("") self.label_version.setText("")
self.label_version.setObjectName("label_version") self.label_version.setObjectName("label_version")
self.gridLayout.addWidget(self.label_version, 1, 1, 1, 1) self.gridLayout.addWidget(self.label_version, 1, 1, 1, 1)
self.label_8 = QtWidgets.QLabel(Dialog) self.label_8 = QLabel(Dialog)
self.label_8.setObjectName("label_8") self.label_8.setObjectName("label_8")
self.gridLayout.addWidget(self.label_8, 6, 0, 1, 1) self.gridLayout.addWidget(self.label_8, 6, 0, 1, 1)
self.label_db_dir = QtWidgets.QLabel(Dialog) self.label_db_dir = QLabel(Dialog)
self.label_db_dir.setMaximumSize(QtCore.QSize(400, 300)) self.label_db_dir.setMaximumSize(QSize(400, 300))
self.label_db_dir.setText("") self.label_db_dir.setText("")
self.label_db_dir.setObjectName("label_db_dir") self.label_db_dir.setObjectName("label_db_dir")
self.gridLayout.addWidget(self.label_db_dir, 6, 1, 1, 1) self.gridLayout.addWidget(self.label_db_dir, 6, 1, 1, 1)
@ -109,58 +111,58 @@ class Ui_Dialog(object):
self.gridLayout.setColumnStretch(0, 1) self.gridLayout.setColumnStretch(0, 1)
self.gridLayout.setColumnStretch(1, 10) self.gridLayout.setColumnStretch(1, 10)
self.gridLayout_2.addLayout(self.gridLayout, 0, 0, 2, 1) self.gridLayout_2.addLayout(self.gridLayout, 0, 0, 2, 1)
self.btn_getinfo = QtWidgets.QPushButton(Dialog) self.btn_getinfo = QPushButton(Dialog)
self.btn_getinfo.setMinimumSize(QtCore.QSize(0, 60)) self.btn_getinfo.setMinimumSize(QSize(0, 60))
self.btn_getinfo.setObjectName("btn_getinfo") self.btn_getinfo.setObjectName("btn_getinfo")
self.gridLayout_2.addWidget(self.btn_getinfo, 0, 1, 1, 1) self.gridLayout_2.addWidget(self.btn_getinfo, 0, 1, 1, 1)
self.checkBox = QtWidgets.QCheckBox(Dialog) self.checkBox = QCheckBox(Dialog)
self.checkBox.setText("") self.checkBox.setText("")
self.checkBox.setObjectName("checkBox") self.checkBox.setObjectName("checkBox")
self.gridLayout_2.addWidget(self.checkBox, 0, 2, 1, 1) self.gridLayout_2.addWidget(self.checkBox, 0, 2, 1, 1)
self.btn_db_dir = QtWidgets.QPushButton(Dialog) self.btn_db_dir = QPushButton(Dialog)
self.btn_db_dir.setMinimumSize(QtCore.QSize(0, 60)) self.btn_db_dir.setMinimumSize(QSize(0, 60))
self.btn_db_dir.setObjectName("btn_db_dir") self.btn_db_dir.setObjectName("btn_db_dir")
self.gridLayout_2.addWidget(self.btn_db_dir, 1, 1, 1, 1) self.gridLayout_2.addWidget(self.btn_db_dir, 1, 1, 1, 1)
self.checkBox_2 = QtWidgets.QCheckBox(Dialog) self.checkBox_2 = QCheckBox(Dialog)
self.checkBox_2.setText("") self.checkBox_2.setText("")
self.checkBox_2.setObjectName("checkBox_2") self.checkBox_2.setObjectName("checkBox_2")
self.gridLayout_2.addWidget(self.checkBox_2, 1, 2, 1, 1) self.gridLayout_2.addWidget(self.checkBox_2, 1, 2, 1, 1)
self.verticalLayout.addLayout(self.gridLayout_2) self.verticalLayout.addLayout(self.gridLayout_2)
self.horizontalLayout_2 = QtWidgets.QHBoxLayout() self.horizontalLayout_2 = QHBoxLayout()
self.horizontalLayout_2.setObjectName("horizontalLayout_2") self.horizontalLayout_2.setObjectName("horizontalLayout_2")
spacerItem2 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) spacerItem2 = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum)
self.horizontalLayout_2.addItem(spacerItem2) self.horizontalLayout_2.addItem(spacerItem2)
self.pushButton_3 = QtWidgets.QPushButton(Dialog) self.pushButton_3 = QPushButton(Dialog)
self.pushButton_3.setMinimumSize(QtCore.QSize(0, 60)) self.pushButton_3.setMinimumSize(QSize(0, 60))
self.pushButton_3.setMaximumSize(QtCore.QSize(100, 16777215)) self.pushButton_3.setMaximumSize(QSize(100, 16777215))
self.pushButton_3.setObjectName("pushButton_3") self.pushButton_3.setObjectName("pushButton_3")
self.horizontalLayout_2.addWidget(self.pushButton_3) self.horizontalLayout_2.addWidget(self.pushButton_3)
spacerItem3 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) spacerItem3 = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum)
self.horizontalLayout_2.addItem(spacerItem3) self.horizontalLayout_2.addItem(spacerItem3)
self.verticalLayout.addLayout(self.horizontalLayout_2) self.verticalLayout.addLayout(self.horizontalLayout_2)
self.horizontalLayout = QtWidgets.QHBoxLayout() self.horizontalLayout = QHBoxLayout()
self.horizontalLayout.setObjectName("horizontalLayout") self.horizontalLayout.setObjectName("horizontalLayout")
self.label_ready = QtWidgets.QLabel(Dialog) self.label_ready = QLabel(Dialog)
self.label_ready.setObjectName("label_ready") self.label_ready.setObjectName("label_ready")
self.horizontalLayout.addWidget(self.label_ready) self.horizontalLayout.addWidget(self.label_ready)
self.progressBar = QtWidgets.QProgressBar(Dialog) self.progressBar = QProgressBar(Dialog)
self.progressBar.setProperty("value", 50) self.progressBar.setProperty("value", 50)
self.progressBar.setObjectName("progressBar") self.progressBar.setObjectName("progressBar")
self.horizontalLayout.addWidget(self.progressBar) self.horizontalLayout.addWidget(self.progressBar)
self.verticalLayout.addLayout(self.horizontalLayout) self.verticalLayout.addLayout(self.horizontalLayout)
self.horizontalLayout_3.addLayout(self.verticalLayout) self.horizontalLayout_3.addLayout(self.verticalLayout)
spacerItem4 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) spacerItem4 = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum)
self.horizontalLayout_3.addItem(spacerItem4) self.horizontalLayout_3.addItem(spacerItem4)
self.verticalLayout_2.addLayout(self.horizontalLayout_3) self.verticalLayout_2.addLayout(self.horizontalLayout_3)
spacerItem5 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) spacerItem5 = QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding)
self.verticalLayout_2.addItem(spacerItem5) self.verticalLayout_2.addItem(spacerItem5)
self.horizontalLayout_4.addLayout(self.verticalLayout_2) self.horizontalLayout_4.addLayout(self.verticalLayout_2)
self.retranslateUi(Dialog) self.retranslateUi(Dialog)
QtCore.QMetaObject.connectSlotsByName(Dialog) QMetaObject.connectSlotsByName(Dialog)
def retranslateUi(self, Dialog): def retranslateUi(self, Dialog):
_translate = QtCore.QCoreApplication.translate _translate = QCoreApplication.translate
Dialog.setWindowTitle(_translate("Dialog", "Dialog")) Dialog.setWindowTitle(_translate("Dialog", "Dialog"))
self.label_3.setText(_translate("Dialog", "解密数据库")) self.label_3.setText(_translate("Dialog", "解密数据库"))
self.label_7.setText(_translate("Dialog", "版本")) self.label_7.setText(_translate("Dialog", "版本"))

View File

@ -3,10 +3,9 @@ import os.path
import time import time
import traceback import traceback
from PyQt5 import QtWidgets from PyQt5.QtCore import pyqtSignal, QThread
from PyQt5.QtCore import * from PyQt5.QtGui import QIcon
from PyQt5.QtGui import * from PyQt5.QtWidgets import QWidget, QMessageBox, QFileDialog
from PyQt5.QtWidgets import *
from app.decrypt import get_wx_info, decrypt from app.decrypt import get_wx_info, decrypt
from app.log import logger from app.log import logger
@ -21,7 +20,7 @@ class DecryptControl(QWidget, decryptUi.Ui_Dialog):
super(DecryptControl, self).__init__(parent) super(DecryptControl, self).__init__(parent)
self.setupUi(self) self.setupUi(self)
self.setWindowTitle('解密') self.setWindowTitle('解密')
self.setWindowIcon(QIcon('./app/data/icons/logo.svg')) self.setWindowIcon(QIcon(':/icons/logo.svg'))
self.pushButton_3.clicked.connect(self.decrypt) self.pushButton_3.clicked.connect(self.decrypt)
self.btn_getinfo.clicked.connect(self.get_info) self.btn_getinfo.clicked.connect(self.get_info)
self.btn_db_dir.clicked.connect(self.select_db_dir) self.btn_db_dir.clicked.connect(self.select_db_dir)
@ -71,8 +70,8 @@ class DecryptControl(QWidget, decryptUi.Ui_Dialog):
QMessageBox.information(self, "ok", f"wxid修改成功{self.info['wxid']}") QMessageBox.information(self, "ok", f"wxid修改成功{self.info['wxid']}")
def select_db_dir(self): def select_db_dir(self):
directory = QtWidgets.QFileDialog.getExistingDirectory( directory = QFileDialog.getExistingDirectory(
self, "选取微信安装目录——能看到All Users文件夹", self, "选取微信安装目录——能看到Msg文件夹",
"C:/") # 起始路径 "C:/") # 起始路径
db_dir = os.path.join(directory, 'Msg') db_dir = os.path.join(directory, 'Msg')
if not os.path.exists(db_dir): if not os.path.exists(db_dir):
@ -136,8 +135,12 @@ class DecryptControl(QWidget, decryptUi.Ui_Dialog):
'name': self.info['name'], 'name': self.info['name'],
'mobile': self.info['mobile'] 'mobile': self.info['mobile']
} }
with open('./app/data/info.json', 'w', encoding='utf-8') as f: try:
f.write(json.dumps(dic)) with open('./app/data/info.json', 'w', encoding='utf-8') as f:
f.write(json.dumps(dic))
except:
with open('./info.json', 'w', encoding='utf-8') as f:
f.write(json.dumps(dic))
self.DecryptSignal.emit('ok') self.DecryptSignal.emit('ok')
self.close() self.close()
@ -159,8 +162,13 @@ class DecryptThread(QThread):
def run(self): def run(self):
# data.decrypt(self.db_path, self.key) # data.decrypt(self.db_path, self.key)
output_dir = 'app/DataBase/Msg' output_dir = 'app/DataBase/Msg'
if not os.path.exists(output_dir): try:
os.mkdir(output_dir) if not os.path.exists(output_dir):
os.mkdir(output_dir)
except:
os.mkdir('app')
os.mkdir('app/DataBase')
os.mkdir('app/DataBase/Msg')
tasks = [] tasks = []
if os.path.exists(self.db_path): if os.path.exists(self.db_path):
for root, dirs, files in os.walk(self.db_path): for root, dirs, files in os.walk(self.db_path):

View File

@ -1,11 +1,17 @@
import os import os
from app.decrypt import dat2pic
from app.person import MePC from app.person import MePC
if not os.path.exists('./data/image'):
os.mkdir('./data/image')
def get_abs_path(path): def get_abs_path(path):
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:
return os.path.join(MePC().wx_dir, path) # if os.path.exists(os.path.join())
output_path = dat2pic.decode_dat(os.path.join(MePC().wx_dir, path), './data/image')
return output_path
else: else:
return os.path.join(os.getcwd(), 'app/data/icons/404.png') return os.path.join(os.getcwd(), 'app/data/icons/404.png')

View File

@ -1,8 +1,7 @@
import ctypes import ctypes
import sys import sys
from PyQt5.QtGui import QIcon from PyQt5.QtWidgets import QApplication, QMessageBox, QWidget
from PyQt5.QtWidgets import *
from app.ui_pc.tool.pc_decrypt import pc_decrypt from app.ui_pc.tool.pc_decrypt import pc_decrypt
@ -12,8 +11,7 @@ ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID("WeChatReport")
class ViewController(QWidget): class ViewController(QWidget):
def __init__(self): def __init__(self):
super().__init__() super().__init__()
self.setWindowTitle('解密')
self.setWindowIcon(QIcon('./app/data/icons/logo.svg'))
self.viewMainWIn = None self.viewMainWIn = None
self.viewDecrypt = None self.viewDecrypt = None

View File

@ -2,7 +2,7 @@ import ctypes
import sys import sys
import time import time
from PyQt5.QtGui import QIcon from PyQt5.QtGui import QIcon, QMovie
from PyQt5.QtWidgets import * from PyQt5.QtWidgets import *
from app.ui_pc import mainview from app.ui_pc import mainview
@ -16,8 +16,13 @@ class ViewController(QWidget):
super().__init__() super().__init__()
self.setWindowTitle('解密') self.setWindowTitle('解密')
self.setWindowIcon(QIcon('./app/data/icons/logo.svg')) self.setWindowIcon(QIcon('./app/data/icons/logo.svg'))
self.viewMainWIn = None self.viewMainWIndow = None
self.viewDecrypt = None self.viewDecrypt = None
# 创建加载动画
loading_label = QLabel()
movie = QMovie("./app/data/loading.gif") # 替换为你的加载动画文件路径
loading_label.setMovie(movie)
movie.start()
def loadPCDecryptView(self): def loadPCDecryptView(self):
""" """
@ -36,14 +41,16 @@ class ViewController(QWidget):
""" """
username = '' username = ''
start = time.time() start = time.time()
self.viewMainWIn = mainview.MainWinController(username=username) self.viewMainWIndow = mainview.MainWinController(username=username)
self.viewMainWIn.setWindowTitle("Chat") self.viewMainWIndow.setWindowTitle("Chat")
# print(username) # print(username)
self.viewMainWIn.username = username self.viewMainWIndow.username = username
# self.viewMainWIn.exitSignal.connect(self.loadDecryptView) # 不需要回到登录界面可以省略 # self.viewMainWIn.exitSignal.connect(self.loadDecryptView) # 不需要回到登录界面可以省略
self.viewMainWIn.show()
self.viewMainWIndow.show()
end = time.time() end = time.time()
print('ok', end - start) print('ok', end - start)
self.viewMainWIndow.init_ui()
def show_success(self): def show_success(self):
QMessageBox.about(self, "解密成功", "数据库文件存储在\napp/DataBase/Msg\n文件夹下") QMessageBox.about(self, "解密成功", "数据库文件存储在\napp/DataBase/Msg\n文件夹下")
@ -54,5 +61,6 @@ if __name__ == '__main__':
view = ViewController() view = ViewController()
# view.loadPCDecryptView() # view.loadPCDecryptView()
view.loadMainWinView() view.loadMainWinView()
# view.show()
# view.show_success() # view.show_success()
sys.exit(app.exec_()) sys.exit(app.exec_())

View File

@ -22,7 +22,10 @@
- 安卓 or 苹果都可以哦 - 安卓 or 苹果都可以哦
- 破解💻PC端微信数据库 - 破解💻PC端微信数据库
- 还原微信聊天界面 - 还原微信聊天界面
- 文本
- 图片
- 导出聊天记录 - 导出聊天记录
- HTML(文本)
- Word文档 - Word文档
- CSV文档 - CSV文档
- 分析聊天数据,做成可视化年报 - 分析聊天数据,做成可视化年报

9
requirements_decrypt.txt Normal file
View File

@ -0,0 +1,9 @@
PyQt5
psutil
pycryptodomex
pywin32
pymem
silk-python
pyaudio
fuzzywuzzy
python-Levenshtein