解决多次解密导致的消息重复的问题

This commit is contained in:
shuaikangzhou 2023-12-16 20:06:43 +08:00
parent 360419ead9
commit 40c57c5891
10 changed files with 112 additions and 87 deletions

View File

@ -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"]

View File

@ -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'

View File

@ -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:

View File

@ -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 = '''

View File

@ -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('\\', '/')

View File

@ -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

View File

@ -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)

View File

@ -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) # 使用一个数据库文件作为模板
# 合并数据库 # 合并数据库

View File

@ -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 '.'

View File

@ -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