diff --git a/app/DataBase/output_pc.py b/app/DataBase/output_pc.py index 7b786eb..1e21035 100644 --- a/app/DataBase/output_pc.py +++ b/app/DataBase/output_pc.py @@ -1,30 +1,29 @@ import csv import html import os +import shutil import sys import time import traceback from re import findall + +import docx from PyQt5.QtCore import pyqtSignal, QThread from PyQt5.QtWidgets import QFileDialog -from docx.oxml.ns import qn - -from . import msg_db -from .package_msg import PackageMsg -from ..DataBase import hard_link_db -from ..DataBase import media_msg_db -from ..log import logger -from ..person import MePC -from ..util import path -import shutil -from ..util.compress_content import parser_reply -from ..util.emoji import get_emoji_url -from ..util.image import get_image_path, get_image, get_image_abs_path -from ..util.file import get_file -import docx from docx import shared from docx.enum.table import WD_ALIGN_VERTICAL from docx.enum.text import WD_COLOR_INDEX, WD_PARAGRAPH_ALIGNMENT +from docx.oxml.ns import qn + +from .package_msg import PackageMsg +from ..DataBase import media_msg_db, hard_link_db, micro_msg_db, msg_db +from ..log import logger +from ..person import MePC +from ..util import path +from ..util.compress_content import parser_reply +from ..util.emoji import get_emoji_url +from ..util.file import get_file +from ..util.image import get_image_path, get_image, get_image_abs_path os.makedirs('./data/聊天记录', exist_ok=True) @@ -105,7 +104,23 @@ class Output(QThread): def progress(self, value): self.progressSignal.emit(value) + def output_image(self): + """ + 导出全部图片 + @return: + """ + return + def output_emoji(self): + """ + 导出全部表情包 + @return: + """ + return def to_csv_all(self): + """ + 导出全部聊天记录到CSV + @return: + """ origin_docx_path = f"{os.path.abspath('.')}/data/聊天记录/" os.makedirs(origin_docx_path, exist_ok=True) filename = QFileDialog.getSaveFileName(None, "save file", os.path.join(os.getcwd(), 'messages.csv'), @@ -129,6 +144,10 @@ class Output(QThread): self.okSignal.emit(1) def contact_to_csv(self): + """ + 导出联系人到CSV + @return: + """ filename = QFileDialog.getSaveFileName(None, "save file", os.path.join(os.getcwd(), 'contacts.csv'), "csv files (*.csv);;all files(*.*)") if not filename[0]: @@ -193,8 +212,14 @@ class Output(QThread): self.output_image.start() def count_finish_num(self, num): + """ + 记录子线程完成个数 + @param num: + @return: + """ self.num += 1 if self.num == self.total_num: + # 所有子线程都完成之后就发送完成信号 self.okSignal.emit(1) def cancel(self): @@ -241,13 +266,16 @@ class ChildThread(QThread): return True return False - def get_avatar_path(self, is_send, message,is_absolute_path=False) -> str: + def get_avatar_path(self, is_send, message, is_absolute_path=False) -> str: if self.contact.is_chatroom: avatar = message[12].smallHeadImgUrl else: avatar = MePC().smallHeadImgUrl if is_send else self.contact.smallHeadImgUrl if is_absolute_path: - avatar = f"{os.path.abspath('.')}/data/聊天记录/{self.contact.remark}"+avatar + if self.contact.is_chatroom: + avatar = message[12].avatar_path + else: + avatar = MePC().avatar_path if is_send else self.contact.avatar_path return avatar def get_display_name(self, is_send, message) -> str: @@ -268,7 +296,7 @@ class ChildThread(QThread): timestamp = message[5] is_chatroom = 1 if self.contact.is_chatroom else 0 - display_name = self.get_display_name(is_send,message) + display_name = self.get_display_name(is_send, message) if self.output_type == Output.HTML: avatar = self.get_avatar_path(is_send, message) str_content = escape_js_and_html(str_content) @@ -281,7 +309,7 @@ class ChildThread(QThread): f'''{str_time} {name}\n{str_content}\n\n''' ) elif self.output_type == Output.DOCX: - avatar = self.get_avatar_path(is_send,message,True) + avatar = self.get_avatar_path(is_send, message, True) content_cell = self.create_table(doc, is_send, avatar) content_cell.paragraphs[0].add_run(str_content) content_cell.paragraphs[0].font_size = shared.Inches(0.5) @@ -300,7 +328,7 @@ class ChildThread(QThread): timestamp = message[5] is_chatroom = 1 if self.contact.is_chatroom else 0 avatar = self.get_avatar_path(is_send, message) - display_name = self.get_display_name(is_send,message) + display_name = self.get_display_name(is_send, message) if self.output_type == Output.HTML: str_content = escape_js_and_html(str_content) image_path = hard_link_db.get_image(str_content, BytesExtra, thumb=False) @@ -318,7 +346,7 @@ class ChildThread(QThread): f'''{str_time} {display_name}\n[图片]\n\n''' ) elif self.output_type == Output.DOCX: - avatar = self.get_avatar_path(is_send,message,True) + avatar = self.get_avatar_path(is_send, message, True) content = self.create_table(doc, is_send, avatar) run = content.paragraphs[0].add_run() str_content = escape_js_and_html(str_content) @@ -361,7 +389,7 @@ class ChildThread(QThread): f'''{str_time} {display_name}\n[语音]\n\n''' ) elif self.output_type == Output.DOCX: - avatar = self.get_avatar_path(is_send,message,True) + avatar = self.get_avatar_path(is_send, message, True) content_cell = self.create_table(doc, is_send, avatar) content_cell.paragraphs[0].add_run('【表情包】') content_cell.paragraphs[0].font_size = shared.Inches(0.5) @@ -369,6 +397,7 @@ class ChildThread(QThread): p = content_cell.paragraphs[0] p.paragraph_format.alignment = WD_PARAGRAPH_ALIGNMENT.RIGHT doc.add_paragraph() + def emoji(self, doc, message): str_content = message[7] str_time = message[8] @@ -387,7 +416,7 @@ class ChildThread(QThread): f'''{str_time} {display_name}\n[表情包]\n\n''' ) elif self.output_type == Output.DOCX: - avatar = self.get_avatar_path(is_send,message,True) + avatar = self.get_avatar_path(is_send, message, True) content_cell = self.create_table(doc, is_send, avatar) content_cell.paragraphs[0].add_run('【表情包】') content_cell.paragraphs[0].font_size = shared.Inches(0.5) @@ -420,7 +449,7 @@ class ChildThread(QThread): f'''{str_time} {display_name}\n[文件]\n\n''' ) elif self.output_type == Output.DOCX: - avatar = self.get_avatar_path(is_send,message,True) + avatar = self.get_avatar_path(is_send, message, True) content_cell = self.create_table(doc, is_send, avatar) content_cell.paragraphs[0].add_run('【文件】') content_cell.paragraphs[0].font_size = shared.Inches(0.5) @@ -465,7 +494,7 @@ class ChildThread(QThread): f'''{str_time} {display_name}\n{content.get('title')}\n引用:未知\n\n''' ) elif self.output_type == Output.DOCX: - avatar = self.get_avatar_path(is_send,message,True) + avatar = self.get_avatar_path(is_send, message, True) content_cell = self.create_table(doc, is_send, avatar) content_cell.paragraphs[0].add_run(content.get('title')) content_cell.paragraphs[0].font_size = shared.Inches(0.5) @@ -552,7 +581,7 @@ class ChildThread(QThread): f'''{str_time} {display_name}\n[视频]\n\n''' ) elif self.output_type == Output.DOCX: - avatar = self.get_avatar_path(is_send,message,True) + avatar = self.get_avatar_path(is_send, message, True) content_cell = self.create_table(doc, is_send, avatar) content_cell.paragraphs[0].add_run('【视频】') content_cell.paragraphs[0].font_size = shared.Inches(0.5) @@ -612,7 +641,6 @@ class ChildThread(QThread): writer.writerows(messages) self.okSignal.emit('ok') - def to_html_(self): origin_docx_path = f"{os.path.abspath('.')}/data/聊天记录/{self.contact.remark}" makedirs(origin_docx_path) @@ -715,19 +743,19 @@ class ChildThread(QThread): messages = msg_db.get_messages(self.contact.wxid) MePC().avatar.save(os.path.join(f"{origin_docx_path}/avatar/{MePC().wxid}.png")) + MePC().save_avatar(os.path.join(f"{origin_docx_path}/avatar/{MePC().wxid}.png")) if self.contact.is_chatroom: for message in messages: if message[4]: # is_send continue try: chatroom_avatar_path = f"{origin_docx_path}/avatar/{message[12].wxid}.png" - if not os.path.exists(chatroom_avatar_path): - message[12].avatar.save(chatroom_avatar_path) + message[12].save_avatar(chatroom_avatar_path) except: print(message) pass else: - self.contact.avatar.save(os.path.join(f"{origin_docx_path}/avatar/{self.contact.wxid}.png")) + self.contact.save_avatar(os.path.join(f"{origin_docx_path}/avatar/{self.contact.wxid}.png")) self.rangeSignal.emit(len(messages)) for index, message in enumerate(messages): type_ = message[2] @@ -767,8 +795,6 @@ class ChildThread(QThread): self.to_csv() elif self.output_type == Output.HTML: self.to_html_() - elif self.output_type == Output.CSV_ALL: - self.to_csv_all() elif self.output_type == Output.TXT: self.to_txt() @@ -777,6 +803,9 @@ class ChildThread(QThread): class OutputMedia(QThread): + """ + 导出语音消息 + """ okSingal = pyqtSignal(int) progressSignal = pyqtSignal(int) @@ -800,6 +829,9 @@ class OutputMedia(QThread): class OutputEmoji(QThread): + """ + 导出表情包 + """ okSingal = pyqtSignal(int) progressSignal = pyqtSignal(int) @@ -823,6 +855,9 @@ class OutputEmoji(QThread): class OutputImage(QThread): + """ + 导出图片 + """ okSingal = pyqtSignal(int) progressSignal = pyqtSignal(int) @@ -912,26 +947,4 @@ class OutputImageChild(QThread): if __name__ == "__main__": - from app.DataBase import micro_msg_db, misc_db - from app.person import ContactPC - from PyQt5.QtGui import QGuiApplication - - app = QGuiApplication([]) - contact_info_list = micro_msg_db.get_contact_by_username("wxid_lhbdvh3cnn4h22") - contact_info = { - 'UserName': contact_info_list[0], - 'Alias': contact_info_list[1], - 'Type': contact_info_list[2], - 'Remark': contact_info_list[3], - 'NickName': contact_info_list[4], - 'smallHeadImgUrl': contact_info_list[7] - } - contact = ContactPC(contact_info) - contact.smallHeadImgBLOG = misc_db.get_avatar_buffer(contact.wxid) - contact.set_avatar(contact.smallHeadImgBLOG) - mess = {1: True, 3: True, 34: True, 43: True, 47: True, 10000: True} - MePC().name = "无题" - MePC().wx_dir = r"C:\Users\HUAWEI\Documents\WeChat Files\wxid_05rvkbftizq822" - MePC().wxid = "wxid_05rvkbftizq822" - ChildThread(contact, 2, mess).to_html_() - app.quit() + pass diff --git a/app/bg.png b/app/bg.png deleted file mode 100644 index db7a99b..0000000 Binary files a/app/bg.png and /dev/null differ diff --git a/app/person.py b/app/person.py index f67089c..a40852d 100644 --- a/app/person.py +++ b/app/person.py @@ -19,17 +19,7 @@ def singleton(cls): return inner -@singleton -class MePC: - def __init__(self): - self.avatar = QPixmap(Icon.Default_avatar_path) - self.avatar_path = ':/icons/icons/default_avatar.svg' - self.wxid = '' - self.wx_dir = '' - self.name = '' - self.mobile = '' - self.smallHeadImgUrl = '' - +class Person: def set_avatar(self, img_bytes): if not img_bytes: self.avatar.load(Icon.Default_avatar_path) @@ -44,6 +34,9 @@ class MePC: return if path: save_path = path + if os.path.exists(save_path): + self.avatar_path = save_path + return save_path else: os.makedirs('./data/avatar', exist_ok=True) save_path = os.path.join(f'data/avatar/', self.wxid + '.png') @@ -52,7 +45,19 @@ class MePC: print('保存头像', save_path) -class ContactPC: +@singleton +class MePC(Person): + def __init__(self): + self.avatar = QPixmap(Icon.Default_avatar_path) + self.avatar_path = ':/icons/icons/default_avatar.svg' + self.wxid = '' + self.wx_dir = '' + self.name = '' + self.mobile = '' + self.smallHeadImgUrl = '' + + +class ContactPC(Person): def __init__(self, contact_info: Dict): self.wxid = contact_info.get('UserName') self.remark = contact_info.get('Remark') @@ -68,29 +73,8 @@ class ContactPC: self.avatar_path = Icon.Default_avatar_path self.is_chatroom = self.wxid.__contains__('@chatroom') - def set_avatar(self, img_bytes): - if not img_bytes: - self.avatar.load(Icon.Default_avatar_path) - return - if img_bytes[:4] == b'\x89PNG': - self.avatar.loadFromData(img_bytes, format='PNG') - else: - self.avatar.loadFromData(img_bytes, format='jfif') - self.avatar.scaled(60, 60, Qt.IgnoreAspectRatio, Qt.SmoothTransformation) - def save_avatar(self, path=None): - if not self.avatar: - return - if path: - save_path = path - else: - os.makedirs('./data/avatar', exist_ok=True) - save_path = os.path.join(f'data/avatar/', self.wxid + '.png') - self.avatar_path = save_path - self.avatar.save(save_path) - print('保存头像', save_path) - -class ContactDefault: +class ContactDefault(Person): def __init__(self, wxid=""): self.avatar = QPixmap(Icon.Default_avatar_path) self.avatar_path = ':/icons/icons/default_avatar.svg' @@ -101,28 +85,6 @@ class ContactDefault: self.smallHeadImgUrl = "" self.smallHeadImgBLOG = b'' self.is_chatroom = False - - def set_avatar(self, img_bytes): - if not img_bytes: - self.avatar.load(Icon.Default_avatar_path) - return - if img_bytes[:4] == b'\x89PNG': - self.avatar.loadFromData(img_bytes, format='PNG') - else: - self.avatar.loadFromData(img_bytes, format='jfif') - self.avatar.scaled(60, 60, Qt.IgnoreAspectRatio, Qt.SmoothTransformation) - - def save_avatar(self, path=None): - if not self.avatar: - return - if path: - save_path = path - else: - os.makedirs('./data/avatar', exist_ok=True) - save_path = os.path.join(f'data/avatar/', self.wxid + '.png') - self.avatar_path = save_path - self.avatar.save(save_path) - print('保存头像', save_path) if __name__ == '__main__': diff --git a/app/ui/tool/pc_decrypt/pc_decrypt.py b/app/ui/tool/pc_decrypt/pc_decrypt.py index dee6205..193a35f 100644 --- a/app/ui/tool/pc_decrypt/pc_decrypt.py +++ b/app/ui/tool/pc_decrypt/pc_decrypt.py @@ -133,8 +133,6 @@ class DecryptControl(QWidget, decryptUi.Ui_Dialog, QCursorGif): QMessageBox.critical(self, "错误", "密钥错误\n将软件放在桌面上试试\n如果还不可以的话我也我能为力,您可以等待后续版本解决该问题") close_db() - self.label_tip.setVisible(True) - self.label_tip.setText('点我之后没有反应那就多等儿吧,不要再点了') self.thread2 = DecryptThread(db_dir, self.info['key']) self.thread2.maxNumSignal.connect(self.setProgressBarMaxNum) self.thread2.signal.connect(self.progressBar_view) diff --git a/app/util/compress_content.py b/app/util/compress_content.py index 3177141..6f91dc4 100644 --- a/app/util/compress_content.py +++ b/app/util/compress_content.py @@ -3,7 +3,6 @@ import xml.etree.ElementTree as ET import lz4.block - def decompress_CompressContent(data): """ 解压缩Msg:CompressContent内容 diff --git a/readme.md b/readme.md index f6c3ea4..b001c7b 100644 --- a/readme.md +++ b/readme.md @@ -69,7 +69,7 @@ - 群组年度报告 - 按日期、关键词索引 - 小伙伴们想要其他功能可以留言哦📬 -- 🔥项目正处于并将长期处于发展阶段,你所期望的未来都会实现,可关注文末公众号持续关注项目更新动态 +- 🔥项目正处于并将长期处于发展阶段,给我一些时间♾️,你所期望的未来都会实现,可关注文末公众号持续关注项目更新动态 ## 🥤效果