diff --git a/app/DataBase/__init__.py b/app/DataBase/__init__.py index 28f97df..a93e8e3 100644 --- a/app/DataBase/__init__.py +++ b/app/DataBase/__init__.py @@ -15,9 +15,20 @@ from .media_msg import MediaMsg from .misc import Misc from .msg import Msg from .msg import MsgType + misc_db = Misc() msg_db = Msg() micro_msg_db = MicroMsg() hard_link_db = HardLink() 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"] diff --git a/app/DataBase/media_msg.py b/app/DataBase/media_msg.py index cb73125..1cee12d 100644 --- a/app/DataBase/media_msg.py +++ b/app/DataBase/media_msg.py @@ -100,7 +100,17 @@ class MediaMsg: return transtext except: 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__': db_path = './Msg/MediaMSG.db' diff --git a/app/DataBase/micro_msg.py b/app/DataBase/micro_msg.py index 7cc2ee2..043cfce 100644 --- a/app/DataBase/micro_msg.py +++ b/app/DataBase/micro_msg.py @@ -3,8 +3,6 @@ import sqlite3 import threading lock = threading.Lock() -DB = None -cursor = None db_path = "./app/Database/Msg/MicroMsg.db" @@ -22,61 +20,6 @@ def singleton(cls): def is_database_exist(): 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 class MicroMsg: @@ -116,7 +59,8 @@ class MicroMsg: result = self.cursor.fetchall() finally: 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): if not self.open_flag: diff --git a/app/DataBase/msg.py b/app/DataBase/msg.py index ecbfab4..19d6a8f 100644 --- a/app/DataBase/msg.py +++ b/app/DataBase/msg.py @@ -208,7 +208,25 @@ class Msg: )) print(keyword,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'): if is_Annual_report_: sql = ''' diff --git a/app/DataBase/output_pc.py b/app/DataBase/output_pc.py index ade15de..e186e60 100644 --- a/app/DataBase/output_pc.py +++ b/app/DataBase/output_pc.py @@ -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 = image_path try: + # todo 网络图片问题 print(origin_docx_path + image_path[1:]) os.utime(origin_docx_path + image_path[1:], (timestamp, timestamp)) image_path = image_path.replace('\\', '/') diff --git a/app/decrypt/get_wx_info.py b/app/decrypt/get_wx_info.py index 9b84414..584e9a1 100644 --- a/app/decrypt/get_wx_info.py +++ b/app/decrypt/get_wx_info.py @@ -168,7 +168,7 @@ def get_key(db_path, addr_len): return key_bytes def verify_key(key, wx_db_path): - if not wx_db_path: + if wx_db_path == "None": return True KEY_SIZE = 32 DEFAULT_PAGESIZE = 4096 @@ -287,6 +287,8 @@ def read_info(version_list, is_logging=False): print("=" * 32) return result + + import os import sys @@ -297,7 +299,6 @@ def resource_path(relative_path): return os.path.join(base_path, relative_path) - def get_info(VERSION_LIST): result = read_info(VERSION_LIST, True) # 读取微信信息 return result diff --git a/app/ui/mainview.py b/app/ui/mainview.py index f46829b..dba129b 100644 --- a/app/ui/mainview.py +++ b/app/ui/mainview.py @@ -15,7 +15,7 @@ from PyQt5.QtGui import QPixmap, QFont, QDesktopServices, QIcon from PyQt5.QtWidgets import QMainWindow, QLabel, QListWidgetItem, QMessageBox 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 . import mainwindow from .chat import ChatWindow @@ -234,12 +234,19 @@ class MainWinController(QMainWindow, mainwindow.Ui_MainWindow): QMessageBox.about(self, "解密成功", "请重新启动") 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: + close_db() super().close() - misc_db.close() - msg_db.close() - micro_msg_db.close() - hard_link_db.close() self.contact_window.close() self.exitSignal.emit(True) diff --git a/app/ui/tool/pc_decrypt/pc_decrypt.py b/app/ui/tool/pc_decrypt/pc_decrypt.py index f6ee7a3..e559663 100644 --- a/app/ui/tool/pc_decrypt/pc_decrypt.py +++ b/app/ui/tool/pc_decrypt/pc_decrypt.py @@ -7,7 +7,7 @@ from PyQt5.QtCore import pyqtSignal, QThread, QUrl, QFile, QIODevice, QTextStrea from PyQt5.QtGui import QDesktopServices 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.decrypt import get_wx_info, decrypt from app.log import logger @@ -131,6 +131,7 @@ class DecryptControl(QWidget, decryptUi.Ui_Dialog): return if self.info.get('key') == 'none': QMessageBox.critical(self, "错误", "密钥错误\n请检查微信版本是否为最新和微信路径是否正确") + close_db() self.label_tip.setVisible(True) self.label_tip.setText('点我之后没有反应那就多等儿吧,不要再点了') self.thread2 = DecryptThread(db_dir, self.info['key']) @@ -171,6 +172,7 @@ class DecryptControl(QWidget, decryptUi.Ui_Dialog): 'name': self.info['name'], 'mobile': self.info['mobile'] } + try: os.makedirs('./app/data', exist_ok=True) 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)] import shutil + if os.path.exists(target_database): + os.remove(target_database) shutil.copy2("app/DataBase/Msg/MSG0.db", target_database) # 使用一个数据库文件作为模板 # 合并数据库 try: @@ -193,6 +197,8 @@ class DecryptControl(QWidget, decryptUi.Ui_Dialog): # 音频数据库文件 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)] shutil.copy2("app/DataBase/Msg/MediaMSG0.db", target_database) # 使用一个数据库文件作为模板 # 合并数据库 diff --git a/app/util/path.py b/app/util/path.py index e8d4439..ae5718d 100644 --- a/app/util/path.py +++ b/app/util/path.py @@ -35,23 +35,47 @@ def mkdir(path): def wx_path(): try: - ## 获取当前用户名 - user_home = os.environ.get("USERPROFILE") - ## 找到3ebffe94.ini配置文件 - f = open(user_home + '\\AppData\\Roaming\\Tencent\\WeChat\\All Users\\config\\3ebffe94.ini', encoding='utf-8') - txt = f.read() - f.close() - # 打开Windows注册表 - reg_key = winreg.OpenKey(winreg.HKEY_CURRENT_USER, - "Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders") - # 获取“我的文档”路径的注册表键值 - documents_path_value = winreg.QueryValueEx(reg_key, "Personal") - # 输出路径 - ##读取文件将路径放到wx_location变量里 - if txt == 'MyDocument:': - wx_location = documents_path_value[0] + '\WeChat Files' - else: - wx_location = txt + "\WeChat Files" - return wx_location + is_w_dir = False + + try: + key = winreg.OpenKey(winreg.HKEY_CURRENT_USER, r"Software\Tencent\WeChat", 0, winreg.KEY_READ) + value, _ = winreg.QueryValueEx(key, "FileSavePath") + winreg.CloseKey(key) + w_dir = value + is_w_dir = True + except Exception as e: + w_dir = "MyDocument:" + + if not is_w_dir: + try: + user_profile = os.environ.get("USERPROFILE") + path_3ebffe94 = os.path.join(user_profile, "AppData", "Roaming", "Tencent", "WeChat", "All Users", + "config", + "3ebffe94.ini") + 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: return '.' diff --git a/main.py b/main.py index b84628f..cd73f0b 100644 --- a/main.py +++ b/main.py @@ -6,6 +6,7 @@ import traceback from PyQt5.QtGui import QFont from PyQt5.QtWidgets import * +from app.DataBase import close_db from app.log import logger from app.ui import mainview from app.ui.tool.pc_decrypt import pc_decrypt @@ -51,7 +52,9 @@ class ViewController(QWidget): def show_success(self): QMessageBox.about(self, "解密成功", "数据库文件存储在\napp/DataBase/Msg\n文件夹下") - + def close(self) -> bool: + close_db() + super().close() if __name__ == '__main__': app = QApplication(sys.argv) font = QFont('微软雅黑', 12) # 使用 Times New Roman 字体,字体大小为 14