mirror of
https://github.com/LC044/WeChatMsg
synced 2025-02-21 18:12:18 +08:00
解决多次解密导致的消息重复的问题
This commit is contained in:
parent
360419ead9
commit
40c57c5891
@ -15,9 +15,20 @@ from .media_msg import MediaMsg
|
|||||||
from .misc import Misc
|
from .misc import Misc
|
||||||
from .msg import Msg
|
from .msg import Msg
|
||||||
from .msg import MsgType
|
from .msg import MsgType
|
||||||
|
|
||||||
misc_db = Misc()
|
misc_db = Misc()
|
||||||
msg_db = Msg()
|
msg_db = Msg()
|
||||||
micro_msg_db = MicroMsg()
|
micro_msg_db = MicroMsg()
|
||||||
hard_link_db = HardLink()
|
hard_link_db = HardLink()
|
||||||
media_msg_db = MediaMsg()
|
media_msg_db = MediaMsg()
|
||||||
__all__ = ["data", 'output', 'misc_db', 'micro_msg_db', 'msg_db', 'hard_link_db','MsgType', "media_msg_db"]
|
|
||||||
|
|
||||||
|
def close_db():
|
||||||
|
misc_db.close()
|
||||||
|
msg_db.close()
|
||||||
|
micro_msg_db.close()
|
||||||
|
hard_link_db.close()
|
||||||
|
media_msg_db.close()
|
||||||
|
|
||||||
|
|
||||||
|
__all__ = ['output', 'misc_db', 'micro_msg_db', 'msg_db', 'hard_link_db', 'MsgType', "media_msg_db"]
|
||||||
|
@ -100,7 +100,17 @@ class MediaMsg:
|
|||||||
return transtext
|
return transtext
|
||||||
except:
|
except:
|
||||||
return ""
|
return ""
|
||||||
|
def close(self):
|
||||||
|
if self.open_flag:
|
||||||
|
try:
|
||||||
|
lock.acquire(True)
|
||||||
|
self.open_flag = False
|
||||||
|
self.DB.close()
|
||||||
|
finally:
|
||||||
|
lock.release()
|
||||||
|
|
||||||
|
def __del__(self):
|
||||||
|
self.close()
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
db_path = './Msg/MediaMSG.db'
|
db_path = './Msg/MediaMSG.db'
|
||||||
|
@ -3,8 +3,6 @@ import sqlite3
|
|||||||
import threading
|
import threading
|
||||||
|
|
||||||
lock = threading.Lock()
|
lock = threading.Lock()
|
||||||
DB = None
|
|
||||||
cursor = None
|
|
||||||
db_path = "./app/Database/Msg/MicroMsg.db"
|
db_path = "./app/Database/Msg/MicroMsg.db"
|
||||||
|
|
||||||
|
|
||||||
@ -22,61 +20,6 @@ def singleton(cls):
|
|||||||
def is_database_exist():
|
def is_database_exist():
|
||||||
return os.path.exists(db_path)
|
return os.path.exists(db_path)
|
||||||
|
|
||||||
lockMSG = threading.Lock()
|
|
||||||
DBMSG = None
|
|
||||||
cursorMSG = None
|
|
||||||
db_msg_path = "./app/Database/Msg/MSG.db"
|
|
||||||
|
|
||||||
@singleton
|
|
||||||
class MicroMSGMsg:
|
|
||||||
def __init__(self):
|
|
||||||
self.DBMSG = None
|
|
||||||
self.cursorMSG = None
|
|
||||||
self.open_flag = False
|
|
||||||
self.init_database()
|
|
||||||
|
|
||||||
def init_database(self):
|
|
||||||
if not self.open_flag:
|
|
||||||
if os.path.exists(db_msg_path):
|
|
||||||
self.DBMSG = sqlite3.connect(db_msg_path, check_same_thread=False)
|
|
||||||
# '''创建游标'''
|
|
||||||
self.cursorMSG = self.DBMSG.cursor()
|
|
||||||
self.open_flag = True
|
|
||||||
if lockMSG.locked():
|
|
||||||
lockMSG.release()
|
|
||||||
|
|
||||||
def get_contact(self, contacts):
|
|
||||||
if not self.open_flag:
|
|
||||||
return None
|
|
||||||
try:
|
|
||||||
lockMSG.acquire(True)
|
|
||||||
sql = '''select StrTalker, MAX(CreateTime) from MSG group by StrTalker'''
|
|
||||||
self.cursorMSG.execute(sql)
|
|
||||||
res = self.cursorMSG.fetchall()
|
|
||||||
res = {StrTalker: CreateTime for StrTalker, CreateTime in res}
|
|
||||||
contacts = [list(cur_contact) for cur_contact in contacts]
|
|
||||||
for i, cur_contact in enumerate(contacts):
|
|
||||||
if cur_contact[0] in res:
|
|
||||||
contacts[i].append(res[cur_contact[0]])
|
|
||||||
else:
|
|
||||||
contacts[i].append(0)
|
|
||||||
contacts.sort(key=lambda cur_contact: cur_contact[-1], reverse=True)
|
|
||||||
finally:
|
|
||||||
lockMSG.release()
|
|
||||||
return contacts
|
|
||||||
|
|
||||||
def close(self):
|
|
||||||
if self.open_flag:
|
|
||||||
try:
|
|
||||||
lockMSG.acquire(True)
|
|
||||||
self.open_flag = False
|
|
||||||
self.DBMSG.close()
|
|
||||||
finally:
|
|
||||||
lockMSG.release()
|
|
||||||
|
|
||||||
def __del__(self):
|
|
||||||
self.close()
|
|
||||||
|
|
||||||
|
|
||||||
@singleton
|
@singleton
|
||||||
class MicroMsg:
|
class MicroMsg:
|
||||||
@ -116,7 +59,8 @@ class MicroMsg:
|
|||||||
result = self.cursor.fetchall()
|
result = self.cursor.fetchall()
|
||||||
finally:
|
finally:
|
||||||
lock.release()
|
lock.release()
|
||||||
return MicroMSGMsg().get_contact(result)
|
from app.DataBase import msg_db
|
||||||
|
return msg_db.get_contact(result)
|
||||||
|
|
||||||
def get_contact_by_username(self, username):
|
def get_contact_by_username(self, username):
|
||||||
if not self.open_flag:
|
if not self.open_flag:
|
||||||
|
@ -208,7 +208,25 @@ class Msg:
|
|||||||
))
|
))
|
||||||
print(keyword,res)
|
print(keyword,res)
|
||||||
return res
|
return res
|
||||||
|
def get_contact(self, contacts):
|
||||||
|
if not self.open_flag:
|
||||||
|
return None
|
||||||
|
try:
|
||||||
|
lock.acquire(True)
|
||||||
|
sql = '''select StrTalker, MAX(CreateTime) from MSG group by StrTalker'''
|
||||||
|
self.cursor.execute(sql)
|
||||||
|
res = self.cursor.fetchall()
|
||||||
|
finally:
|
||||||
|
lock.release()
|
||||||
|
res = {StrTalker: CreateTime for StrTalker, CreateTime in res}
|
||||||
|
contacts = [list(cur_contact) for cur_contact in contacts]
|
||||||
|
for i, cur_contact in enumerate(contacts):
|
||||||
|
if cur_contact[0] in res:
|
||||||
|
contacts[i].append(res[cur_contact[0]])
|
||||||
|
else:
|
||||||
|
contacts[i].append(0)
|
||||||
|
contacts.sort(key=lambda cur_contact: cur_contact[-1], reverse=True)
|
||||||
|
return contacts
|
||||||
def get_messages_by_days(self, username_, is_Annual_report_=False, year_='2023'):
|
def get_messages_by_days(self, username_, is_Annual_report_=False, year_='2023'):
|
||||||
if is_Annual_report_:
|
if is_Annual_report_:
|
||||||
sql = '''
|
sql = '''
|
||||||
|
@ -365,6 +365,7 @@ class ChildThread(QThread):
|
|||||||
image_path = path.get_relative_path(image_path, base_path=f'/data/聊天记录/{self.contact.remark}/image')
|
image_path = path.get_relative_path(image_path, base_path=f'/data/聊天记录/{self.contact.remark}/image')
|
||||||
image_path = image_path
|
image_path = image_path
|
||||||
try:
|
try:
|
||||||
|
# todo 网络图片问题
|
||||||
print(origin_docx_path + image_path[1:])
|
print(origin_docx_path + image_path[1:])
|
||||||
os.utime(origin_docx_path + image_path[1:], (timestamp, timestamp))
|
os.utime(origin_docx_path + image_path[1:], (timestamp, timestamp))
|
||||||
image_path = image_path.replace('\\', '/')
|
image_path = image_path.replace('\\', '/')
|
||||||
|
@ -168,7 +168,7 @@ def get_key(db_path, addr_len):
|
|||||||
return key_bytes
|
return key_bytes
|
||||||
|
|
||||||
def verify_key(key, wx_db_path):
|
def verify_key(key, wx_db_path):
|
||||||
if not wx_db_path:
|
if wx_db_path == "None":
|
||||||
return True
|
return True
|
||||||
KEY_SIZE = 32
|
KEY_SIZE = 32
|
||||||
DEFAULT_PAGESIZE = 4096
|
DEFAULT_PAGESIZE = 4096
|
||||||
@ -287,6 +287,8 @@ def read_info(version_list, is_logging=False):
|
|||||||
print("=" * 32)
|
print("=" * 32)
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
@ -297,7 +299,6 @@ def resource_path(relative_path):
|
|||||||
return os.path.join(base_path, relative_path)
|
return os.path.join(base_path, relative_path)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def get_info(VERSION_LIST):
|
def get_info(VERSION_LIST):
|
||||||
result = read_info(VERSION_LIST, True) # 读取微信信息
|
result = read_info(VERSION_LIST, True) # 读取微信信息
|
||||||
return result
|
return result
|
||||||
|
@ -15,7 +15,7 @@ from PyQt5.QtGui import QPixmap, QFont, QDesktopServices, QIcon
|
|||||||
from PyQt5.QtWidgets import QMainWindow, QLabel, QListWidgetItem, QMessageBox
|
from PyQt5.QtWidgets import QMainWindow, QLabel, QListWidgetItem, QMessageBox
|
||||||
|
|
||||||
from app import config
|
from app import config
|
||||||
from app.DataBase import msg_db, misc_db, micro_msg_db, hard_link_db
|
from app.DataBase import msg_db, misc_db, micro_msg_db, hard_link_db, close_db
|
||||||
from app.ui.Icon import Icon
|
from app.ui.Icon import Icon
|
||||||
from . import mainwindow
|
from . import mainwindow
|
||||||
from .chat import ChatWindow
|
from .chat import ChatWindow
|
||||||
@ -234,12 +234,19 @@ class MainWinController(QMainWindow, mainwindow.Ui_MainWindow):
|
|||||||
QMessageBox.about(self, "解密成功", "请重新启动")
|
QMessageBox.about(self, "解密成功", "请重新启动")
|
||||||
self.close()
|
self.close()
|
||||||
|
|
||||||
|
def closeEvent(self, event):
|
||||||
|
reply = QMessageBox.question(self, '确认退出', '确定要退出吗?',
|
||||||
|
QMessageBox.Yes | QMessageBox.No,
|
||||||
|
QMessageBox.No)
|
||||||
|
|
||||||
|
if reply == QMessageBox.Yes:
|
||||||
|
close_db()
|
||||||
|
event.accept()
|
||||||
|
else:
|
||||||
|
event.ignore()
|
||||||
def close(self) -> bool:
|
def close(self) -> bool:
|
||||||
|
close_db()
|
||||||
super().close()
|
super().close()
|
||||||
misc_db.close()
|
|
||||||
msg_db.close()
|
|
||||||
micro_msg_db.close()
|
|
||||||
hard_link_db.close()
|
|
||||||
self.contact_window.close()
|
self.contact_window.close()
|
||||||
self.exitSignal.emit(True)
|
self.exitSignal.emit(True)
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@ from PyQt5.QtCore import pyqtSignal, QThread, QUrl, QFile, QIODevice, QTextStrea
|
|||||||
from PyQt5.QtGui import QDesktopServices
|
from PyQt5.QtGui import QDesktopServices
|
||||||
from PyQt5.QtWidgets import QWidget, QMessageBox, QFileDialog
|
from PyQt5.QtWidgets import QWidget, QMessageBox, QFileDialog
|
||||||
|
|
||||||
from app.DataBase import msg_db, misc_db
|
from app.DataBase import msg_db, misc_db, media_msg_db, close_db
|
||||||
from app.DataBase.merge import merge_databases, merge_MediaMSG_databases
|
from app.DataBase.merge import merge_databases, merge_MediaMSG_databases
|
||||||
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
|
||||||
@ -131,6 +131,7 @@ class DecryptControl(QWidget, decryptUi.Ui_Dialog):
|
|||||||
return
|
return
|
||||||
if self.info.get('key') == 'none':
|
if self.info.get('key') == 'none':
|
||||||
QMessageBox.critical(self, "错误", "密钥错误\n请检查微信版本是否为最新和微信路径是否正确")
|
QMessageBox.critical(self, "错误", "密钥错误\n请检查微信版本是否为最新和微信路径是否正确")
|
||||||
|
close_db()
|
||||||
self.label_tip.setVisible(True)
|
self.label_tip.setVisible(True)
|
||||||
self.label_tip.setText('点我之后没有反应那就多等儿吧,不要再点了')
|
self.label_tip.setText('点我之后没有反应那就多等儿吧,不要再点了')
|
||||||
self.thread2 = DecryptThread(db_dir, self.info['key'])
|
self.thread2 = DecryptThread(db_dir, self.info['key'])
|
||||||
@ -171,6 +172,7 @@ class DecryptControl(QWidget, decryptUi.Ui_Dialog):
|
|||||||
'name': self.info['name'],
|
'name': self.info['name'],
|
||||||
'mobile': self.info['mobile']
|
'mobile': self.info['mobile']
|
||||||
}
|
}
|
||||||
|
|
||||||
try:
|
try:
|
||||||
os.makedirs('./app/data', exist_ok=True)
|
os.makedirs('./app/data', exist_ok=True)
|
||||||
with open('./app/data/info.json', 'w', encoding='utf-8') as f:
|
with open('./app/data/info.json', 'w', encoding='utf-8') as f:
|
||||||
@ -183,6 +185,8 @@ class DecryptControl(QWidget, decryptUi.Ui_Dialog):
|
|||||||
# 源数据库文件列表
|
# 源数据库文件列表
|
||||||
source_databases = [f"app/DataBase/Msg/MSG{i}.db" for i in range(1, 200)]
|
source_databases = [f"app/DataBase/Msg/MSG{i}.db" for i in range(1, 200)]
|
||||||
import shutil
|
import shutil
|
||||||
|
if os.path.exists(target_database):
|
||||||
|
os.remove(target_database)
|
||||||
shutil.copy2("app/DataBase/Msg/MSG0.db", target_database) # 使用一个数据库文件作为模板
|
shutil.copy2("app/DataBase/Msg/MSG0.db", target_database) # 使用一个数据库文件作为模板
|
||||||
# 合并数据库
|
# 合并数据库
|
||||||
try:
|
try:
|
||||||
@ -193,6 +197,8 @@ class DecryptControl(QWidget, decryptUi.Ui_Dialog):
|
|||||||
# 音频数据库文件
|
# 音频数据库文件
|
||||||
target_database = "app/DataBase/Msg/MediaMSG.db"
|
target_database = "app/DataBase/Msg/MediaMSG.db"
|
||||||
# 源数据库文件列表
|
# 源数据库文件列表
|
||||||
|
if os.path.exists(target_database):
|
||||||
|
os.remove(target_database)
|
||||||
source_databases = [f"app/DataBase/Msg/MediaMSG{i}.db" for i in range(1, 200)]
|
source_databases = [f"app/DataBase/Msg/MediaMSG{i}.db" for i in range(1, 200)]
|
||||||
shutil.copy2("app/DataBase/Msg/MediaMSG0.db", target_database) # 使用一个数据库文件作为模板
|
shutil.copy2("app/DataBase/Msg/MediaMSG0.db", target_database) # 使用一个数据库文件作为模板
|
||||||
# 合并数据库
|
# 合并数据库
|
||||||
|
@ -35,23 +35,47 @@ def mkdir(path):
|
|||||||
|
|
||||||
def wx_path():
|
def wx_path():
|
||||||
try:
|
try:
|
||||||
## 获取当前用户名
|
is_w_dir = False
|
||||||
user_home = os.environ.get("USERPROFILE")
|
|
||||||
## 找到3ebffe94.ini配置文件
|
try:
|
||||||
f = open(user_home + '\\AppData\\Roaming\\Tencent\\WeChat\\All Users\\config\\3ebffe94.ini', encoding='utf-8')
|
key = winreg.OpenKey(winreg.HKEY_CURRENT_USER, r"Software\Tencent\WeChat", 0, winreg.KEY_READ)
|
||||||
txt = f.read()
|
value, _ = winreg.QueryValueEx(key, "FileSavePath")
|
||||||
f.close()
|
winreg.CloseKey(key)
|
||||||
# 打开Windows注册表
|
w_dir = value
|
||||||
reg_key = winreg.OpenKey(winreg.HKEY_CURRENT_USER,
|
is_w_dir = True
|
||||||
"Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders")
|
except Exception as e:
|
||||||
# 获取“我的文档”路径的注册表键值
|
w_dir = "MyDocument:"
|
||||||
documents_path_value = winreg.QueryValueEx(reg_key, "Personal")
|
|
||||||
# 输出路径
|
if not is_w_dir:
|
||||||
##读取文件将路径放到wx_location变量里
|
try:
|
||||||
if txt == 'MyDocument:':
|
user_profile = os.environ.get("USERPROFILE")
|
||||||
wx_location = documents_path_value[0] + '\WeChat Files'
|
path_3ebffe94 = os.path.join(user_profile, "AppData", "Roaming", "Tencent", "WeChat", "All Users",
|
||||||
else:
|
"config",
|
||||||
wx_location = txt + "\WeChat Files"
|
"3ebffe94.ini")
|
||||||
return wx_location
|
with open(path_3ebffe94, "r", encoding="utf-8") as f:
|
||||||
|
w_dir = f.read()
|
||||||
|
is_w_dir = True
|
||||||
|
except Exception as e:
|
||||||
|
w_dir = "MyDocument:"
|
||||||
|
|
||||||
|
if w_dir == "MyDocument:":
|
||||||
|
try:
|
||||||
|
# 打开注册表路径
|
||||||
|
key = winreg.OpenKey(winreg.HKEY_CURRENT_USER,
|
||||||
|
r"Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders")
|
||||||
|
documents_path = winreg.QueryValueEx(key, "Personal")[0] # 读取文档实际目录路径
|
||||||
|
winreg.CloseKey(key) # 关闭注册表
|
||||||
|
documents_paths = os.path.split(documents_path)
|
||||||
|
if "%" in documents_paths[0]:
|
||||||
|
w_dir = os.environ.get(documents_paths[0].replace("%", ""))
|
||||||
|
w_dir = os.path.join(w_dir, os.path.join(*documents_paths[1:]))
|
||||||
|
# print(1, w_dir)
|
||||||
|
else:
|
||||||
|
w_dir = documents_path
|
||||||
|
except Exception as e:
|
||||||
|
profile = os.environ.get("USERPROFILE")
|
||||||
|
w_dir = os.path.join(profile, "Documents")
|
||||||
|
msg_dir = os.path.join(w_dir, "WeChat Files")
|
||||||
|
return msg_dir
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
return '.'
|
return '.'
|
||||||
|
5
main.py
5
main.py
@ -6,6 +6,7 @@ import traceback
|
|||||||
from PyQt5.QtGui import QFont
|
from PyQt5.QtGui import QFont
|
||||||
from PyQt5.QtWidgets import *
|
from PyQt5.QtWidgets import *
|
||||||
|
|
||||||
|
from app.DataBase import close_db
|
||||||
from app.log import logger
|
from app.log import logger
|
||||||
from app.ui import mainview
|
from app.ui import mainview
|
||||||
from app.ui.tool.pc_decrypt import pc_decrypt
|
from app.ui.tool.pc_decrypt import pc_decrypt
|
||||||
@ -51,7 +52,9 @@ class ViewController(QWidget):
|
|||||||
def show_success(self):
|
def show_success(self):
|
||||||
QMessageBox.about(self, "解密成功", "数据库文件存储在\napp/DataBase/Msg\n文件夹下")
|
QMessageBox.about(self, "解密成功", "数据库文件存储在\napp/DataBase/Msg\n文件夹下")
|
||||||
|
|
||||||
|
def close(self) -> bool:
|
||||||
|
close_db()
|
||||||
|
super().close()
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
app = QApplication(sys.argv)
|
app = QApplication(sys.argv)
|
||||||
font = QFont('微软雅黑', 12) # 使用 Times New Roman 字体,字体大小为 14
|
font = QFont('微软雅黑', 12) # 使用 Times New Roman 字体,字体大小为 14
|
||||||
|
Loading…
Reference in New Issue
Block a user