mirror of
https://github.com/LC044/WeChatMsg
synced 2024-11-12 20:21:21 +08:00
pyqt支持群聊显示,合并群聊和非群聊的获取
This commit is contained in:
parent
1209caa378
commit
cc281fb352
@ -14,11 +14,7 @@ class CSVExporter(ExporterBase):
|
|||||||
columns = ['localId', 'TalkerId', 'Type', 'SubType',
|
columns = ['localId', 'TalkerId', 'Type', 'SubType',
|
||||||
'IsSender', 'CreateTime', 'Status', 'StrContent',
|
'IsSender', 'CreateTime', 'Status', 'StrContent',
|
||||||
'StrTime', 'Remark', 'NickName', 'Sender']
|
'StrTime', 'Remark', 'NickName', 'Sender']
|
||||||
if self.contact.is_chatroom:
|
messages = msg_db.get_messages(self.contact.wxid)
|
||||||
packagemsg = PackageMsg()
|
|
||||||
messages = packagemsg.get_package_message_by_wxid(self.contact.wxid)
|
|
||||||
else:
|
|
||||||
messages = msg_db.get_messages(self.contact.wxid)
|
|
||||||
# 写入CSV文件
|
# 写入CSV文件
|
||||||
with open(filename, mode='w', newline='', encoding='utf-8-sig') as file:
|
with open(filename, mode='w', newline='', encoding='utf-8-sig') as file:
|
||||||
writer = csv.writer(file)
|
writer = csv.writer(file)
|
||||||
|
@ -1,27 +1,20 @@
|
|||||||
import os
|
import os
|
||||||
import shutil
|
import shutil
|
||||||
import sys
|
|
||||||
import time
|
import time
|
||||||
import traceback
|
|
||||||
from re import findall
|
from re import findall
|
||||||
|
|
||||||
import docx
|
import docx
|
||||||
from PyQt5.QtCore import pyqtSignal, QThread
|
|
||||||
from docx import shared
|
from docx import shared
|
||||||
from docx.enum.table import WD_ALIGN_VERTICAL
|
from docx.enum.table import WD_ALIGN_VERTICAL
|
||||||
from docx.enum.text import WD_COLOR_INDEX, WD_PARAGRAPH_ALIGNMENT
|
from docx.enum.text import WD_COLOR_INDEX, WD_PARAGRAPH_ALIGNMENT
|
||||||
from docx.oxml.ns import qn
|
from docx.oxml.ns import qn
|
||||||
|
|
||||||
from app.DataBase import msg_db, hard_link_db, media_msg_db
|
from app.DataBase import msg_db, hard_link_db
|
||||||
from app.DataBase.output import ExporterBase, escape_js_and_html
|
from app.DataBase.output import ExporterBase, escape_js_and_html
|
||||||
from app.DataBase.package_msg import PackageMsg
|
from app.DataBase.package_msg import PackageMsg
|
||||||
from app.log import logger
|
|
||||||
from app.person import Me
|
from app.person import Me
|
||||||
from app.util import path
|
|
||||||
from app.util.compress_content import parser_reply, share_card, music_share
|
from app.util.compress_content import parser_reply, share_card, music_share
|
||||||
from app.util.emoji import get_emoji_url
|
from app.util.image import get_image_abs_path
|
||||||
from app.util.file import get_file
|
|
||||||
from app.util.image import get_image_path, get_image, get_image_abs_path
|
|
||||||
from app.util.music import get_music_path
|
from app.util.music import get_music_path
|
||||||
|
|
||||||
|
|
||||||
@ -296,11 +289,7 @@ class DocxExporter(ExporterBase):
|
|||||||
doc = docx.Document()
|
doc = docx.Document()
|
||||||
doc.styles['Normal'].font.name = u'Cambria'
|
doc.styles['Normal'].font.name = u'Cambria'
|
||||||
doc.styles['Normal']._element.rPr.rFonts.set(qn('w:eastAsia'), u'宋体')
|
doc.styles['Normal']._element.rPr.rFonts.set(qn('w:eastAsia'), u'宋体')
|
||||||
if self.contact.is_chatroom:
|
messages = msg_db.get_messages(self.contact.wxid)
|
||||||
packagemsg = PackageMsg()
|
|
||||||
messages = packagemsg.get_package_message_by_wxid(self.contact.wxid)
|
|
||||||
else:
|
|
||||||
messages = msg_db.get_messages(self.contact.wxid)
|
|
||||||
Me().save_avatar(os.path.join(f"{origin_docx_path}/avatar/{Me().wxid}.png"))
|
Me().save_avatar(os.path.join(f"{origin_docx_path}/avatar/{Me().wxid}.png"))
|
||||||
if self.contact.is_chatroom:
|
if self.contact.is_chatroom:
|
||||||
for message in messages:
|
for message in messages:
|
||||||
|
@ -276,11 +276,7 @@ class HtmlExporter(ExporterBase):
|
|||||||
)
|
)
|
||||||
|
|
||||||
def export(self):
|
def export(self):
|
||||||
if self.contact.is_chatroom:
|
messages = msg_db.get_messages(self.contact.wxid)
|
||||||
packagemsg = PackageMsg()
|
|
||||||
messages = packagemsg.get_package_message_by_wxid(self.contact.wxid)
|
|
||||||
else:
|
|
||||||
messages = msg_db.get_messages(self.contact.wxid)
|
|
||||||
filename = f"{os.path.abspath('.')}/data/聊天记录/{self.contact.remark}/{self.contact.remark}.html"
|
filename = f"{os.path.abspath('.')}/data/聊天记录/{self.contact.remark}/{self.contact.remark}.html"
|
||||||
file_path = './app/resources/data/template.html'
|
file_path = './app/resources/data/template.html'
|
||||||
if not os.path.exists(file_path):
|
if not os.path.exists(file_path):
|
||||||
|
@ -114,11 +114,7 @@ class TxtExporter(ExporterBase):
|
|||||||
origin_docx_path = f"{os.path.abspath('.')}/data/聊天记录/{self.contact.remark}"
|
origin_docx_path = f"{os.path.abspath('.')}/data/聊天记录/{self.contact.remark}"
|
||||||
os.makedirs(origin_docx_path, exist_ok=True)
|
os.makedirs(origin_docx_path, exist_ok=True)
|
||||||
filename = f"{os.path.abspath('.')}/data/聊天记录/{self.contact.remark}/{self.contact.remark}.txt"
|
filename = f"{os.path.abspath('.')}/data/聊天记录/{self.contact.remark}/{self.contact.remark}.txt"
|
||||||
if self.contact.is_chatroom:
|
messages = msg_db.get_messages(self.contact.wxid)
|
||||||
packagemsg = PackageMsg()
|
|
||||||
messages = packagemsg.get_package_message_by_wxid(self.contact.wxid)
|
|
||||||
else:
|
|
||||||
messages = msg_db.get_messages(self.contact.wxid)
|
|
||||||
total_steps = len(messages)
|
total_steps = len(messages)
|
||||||
with open(filename, mode='w', newline='', encoding='utf-8') as f:
|
with open(filename, mode='w', newline='', encoding='utf-8') as f:
|
||||||
for index, message in enumerate(messages):
|
for index, message in enumerate(messages):
|
||||||
|
@ -93,6 +93,7 @@ class MicroMsg:
|
|||||||
self.cursor.execute(sql, [username])
|
self.cursor.execute(sql, [username])
|
||||||
result = self.cursor.fetchone()
|
result = self.cursor.fetchone()
|
||||||
except sqlite3.OperationalError:
|
except sqlite3.OperationalError:
|
||||||
|
# 解决ContactLabel表不存在的问题
|
||||||
# lock.acquire(True)
|
# lock.acquire(True)
|
||||||
sql = '''
|
sql = '''
|
||||||
SELECT UserName, Alias, Type, Remark, NickName, PYInitial, RemarkPYInitial, ContactHeadImgUrl.smallHeadImgUrl, ContactHeadImgUrl.bigHeadImgUrl,ExTraBuf,"None"
|
SELECT UserName, Alias, Type, Remark, NickName, PYInitial, RemarkPYInitial, ContactHeadImgUrl.smallHeadImgUrl, ContactHeadImgUrl.bigHeadImgUrl,ExTraBuf,"None"
|
||||||
|
@ -16,6 +16,70 @@ def is_database_exist():
|
|||||||
return os.path.exists(db_path)
|
return os.path.exists(db_path)
|
||||||
|
|
||||||
|
|
||||||
|
def parser_chatroom_message(messages):
|
||||||
|
from app.DataBase import micro_msg_db, misc_db
|
||||||
|
from app.util.protocbuf.msg_pb2 import MessageBytesExtra
|
||||||
|
from app.person import Contact, Me, ContactDefault
|
||||||
|
'''
|
||||||
|
获取一个群聊的聊天记录
|
||||||
|
return list
|
||||||
|
a[0]: localId,
|
||||||
|
a[1]: talkerId, (和strtalker对应的,不是群聊信息发送人)
|
||||||
|
a[2]: type,
|
||||||
|
a[3]: subType,
|
||||||
|
a[4]: is_sender,
|
||||||
|
a[5]: timestamp,
|
||||||
|
a[6]: status, (没啥用)
|
||||||
|
a[7]: str_content,
|
||||||
|
a[8]: str_time, (格式化的时间)
|
||||||
|
a[9]: msgSvrId,
|
||||||
|
a[10]: BytesExtra,
|
||||||
|
a[11]: CompressContent,
|
||||||
|
a[12]: msg_sender, (ContactPC 或 ContactDefault 类型,这个才是群聊里的信息发送人,不是群聊或者自己是发送者没有这个字段)
|
||||||
|
'''
|
||||||
|
updated_messages = [] # 用于存储修改后的消息列表
|
||||||
|
for row in messages:
|
||||||
|
message = list(row)
|
||||||
|
if message[4] == 1: # 自己发送的就没必要解析了
|
||||||
|
message.append(Me())
|
||||||
|
updated_messages.append(tuple(message))
|
||||||
|
continue
|
||||||
|
if message[10] is None: # BytesExtra是空的跳过
|
||||||
|
message.append(ContactDefault(wxid))
|
||||||
|
updated_messages.append(tuple(message))
|
||||||
|
continue
|
||||||
|
msgbytes = MessageBytesExtra()
|
||||||
|
msgbytes.ParseFromString(message[10])
|
||||||
|
wxid = ''
|
||||||
|
for tmp in msgbytes.message2:
|
||||||
|
if tmp.field1 != 1:
|
||||||
|
continue
|
||||||
|
wxid = tmp.field2
|
||||||
|
if wxid == "": # 系统消息里面 wxid 不存在
|
||||||
|
message.append(ContactDefault(wxid))
|
||||||
|
updated_messages.append(tuple(message))
|
||||||
|
continue
|
||||||
|
contact_info_list = micro_msg_db.get_contact_by_username(wxid)
|
||||||
|
if contact_info_list is None: # 群聊中已退群的联系人不会保存在数据库里
|
||||||
|
message.append(ContactDefault(wxid))
|
||||||
|
updated_messages.append(tuple(message))
|
||||||
|
continue
|
||||||
|
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 = Contact(contact_info)
|
||||||
|
contact.smallHeadImgBLOG = misc_db.get_avatar_buffer(contact.wxid)
|
||||||
|
contact.set_avatar(contact.smallHeadImgBLOG)
|
||||||
|
message.append(contact)
|
||||||
|
updated_messages.append(tuple(message))
|
||||||
|
return updated_messages
|
||||||
|
|
||||||
|
|
||||||
def singleton(cls):
|
def singleton(cls):
|
||||||
_instance = {}
|
_instance = {}
|
||||||
|
|
||||||
@ -105,7 +169,7 @@ class Msg:
|
|||||||
result = self.cursor.fetchall()
|
result = self.cursor.fetchall()
|
||||||
finally:
|
finally:
|
||||||
lock.release()
|
lock.release()
|
||||||
return result
|
return parser_chatroom_message(result) if username_.__contains__('@chatroom') else result
|
||||||
# result.sort(key=lambda x: x[5])
|
# result.sort(key=lambda x: x[5])
|
||||||
# return self.add_sender(result)
|
# return self.add_sender(result)
|
||||||
|
|
||||||
@ -164,7 +228,7 @@ class Msg:
|
|||||||
finally:
|
finally:
|
||||||
lock.release()
|
lock.release()
|
||||||
# result.sort(key=lambda x: x[5])
|
# result.sort(key=lambda x: x[5])
|
||||||
return result
|
return parser_chatroom_message(result) if username_.__contains__('@chatroom') else result
|
||||||
|
|
||||||
def get_messages_by_type(self, username_, type_, year_='all'):
|
def get_messages_by_type(self, username_, type_, year_='all'):
|
||||||
if not self.open_flag:
|
if not self.open_flag:
|
||||||
@ -629,14 +693,15 @@ if __name__ == '__main__':
|
|||||||
msg.init_database()
|
msg.init_database()
|
||||||
wxid = 'wxid_0o18ef858vnu22'
|
wxid = 'wxid_0o18ef858vnu22'
|
||||||
wxid = '24521163022@chatroom'
|
wxid = '24521163022@chatroom'
|
||||||
wxid = 'wxid_vtz9jk9ulzjt22' # si
|
wxid = 'wxid_vtz9jk9ulzjt22' # si
|
||||||
print()
|
print()
|
||||||
from app.util import compress_content
|
from app.util import compress_content
|
||||||
import xml.etree.ElementTree as ET
|
import xml.etree.ElementTree as ET
|
||||||
|
|
||||||
msgs = msg.get_messages(wxid)
|
msgs = msg.get_messages(wxid)
|
||||||
|
|
||||||
for msg in msgs:
|
for msg in msgs:
|
||||||
if msg[2]==49 and msg[3]==5:
|
if msg[2] == 49 and msg[3] == 5:
|
||||||
xml = compress_content.decompress_CompressContent(msg[11])
|
xml = compress_content.decompress_CompressContent(msg[11])
|
||||||
root = ET.XML(xml)
|
root = ET.XML(xml)
|
||||||
appmsg = root.find('appmsg')
|
appmsg = root.find('appmsg')
|
||||||
@ -658,4 +723,4 @@ if __name__ == '__main__':
|
|||||||
print(thumb)
|
print(thumb)
|
||||||
if tmp.field2 == 4:
|
if tmp.field2 == 4:
|
||||||
app_logo = tmp.field2
|
app_logo = tmp.field2
|
||||||
print('logo',app_logo)
|
print('logo', app_logo)
|
||||||
|
@ -110,7 +110,6 @@ class PackageMsg:
|
|||||||
a[12]: msg_sender, (ContactPC 或 ContactDefault 类型,这个才是群聊里的信息发送人,不是群聊或者自己是发送者没有这个字段)
|
a[12]: msg_sender, (ContactPC 或 ContactDefault 类型,这个才是群聊里的信息发送人,不是群聊或者自己是发送者没有这个字段)
|
||||||
'''
|
'''
|
||||||
updated_messages = [] # 用于存储修改后的消息列表
|
updated_messages = [] # 用于存储修改后的消息列表
|
||||||
chatroom_members = self.get_chatroom_member_list(chatroom_wxid)
|
|
||||||
messages = msg_db.get_messages(chatroom_wxid)
|
messages = msg_db.get_messages(chatroom_wxid)
|
||||||
for row in messages:
|
for row in messages:
|
||||||
message = list(row)
|
message = list(row)
|
||||||
@ -150,7 +149,7 @@ class PackageMsg:
|
|||||||
contact.smallHeadImgBLOG = misc_db.get_avatar_buffer(contact.wxid)
|
contact.smallHeadImgBLOG = misc_db.get_avatar_buffer(contact.wxid)
|
||||||
contact.set_avatar(contact.smallHeadImgBLOG)
|
contact.set_avatar(contact.smallHeadImgBLOG)
|
||||||
message.append(contact)
|
message.append(contact)
|
||||||
updated_messages.append(message)
|
updated_messages.append(tuple(message))
|
||||||
return updated_messages
|
return updated_messages
|
||||||
|
|
||||||
def get_chatroom_member_list(self, strtalker):
|
def get_chatroom_member_list(self, strtalker):
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
import os.path
|
import os.path
|
||||||
|
import subprocess
|
||||||
|
import platform
|
||||||
|
|
||||||
from PIL import Image
|
|
||||||
from PyQt5 import QtGui
|
from PyQt5 import QtGui
|
||||||
from PyQt5.QtCore import QSize, pyqtSignal, Qt, QThread
|
from PyQt5.QtCore import QSize, pyqtSignal, Qt, QThread
|
||||||
from PyQt5.QtGui import QPainter, QFont, QColor, QPixmap, QPolygon, QFontMetrics
|
from PyQt5.QtGui import QPainter, QFont, QColor, QPixmap, QPolygon, QFontMetrics
|
||||||
from PyQt5.QtWidgets import QWidget, QLabel, QHBoxLayout, QSizePolicy, QVBoxLayout, QSpacerItem, \
|
from PyQt5.QtWidgets import QWidget, QLabel, QHBoxLayout, QSizePolicy, QVBoxLayout, QSpacerItem, \
|
||||||
QScrollArea, QScrollBar
|
QScrollArea
|
||||||
|
|
||||||
from app.components.scroll_bar import ScrollBar
|
from app.components.scroll_bar import ScrollBar
|
||||||
|
|
||||||
@ -83,7 +84,7 @@ class Notice(QLabel):
|
|||||||
def __init__(self, text, type_=3, parent=None):
|
def __init__(self, text, type_=3, parent=None):
|
||||||
super().__init__(text, parent)
|
super().__init__(text, parent)
|
||||||
self.type_ = type_
|
self.type_ = type_
|
||||||
self.setFont(QFont('微软雅黑', 12))
|
self.setFont(QFont('微软雅黑', 10))
|
||||||
self.setWordWrap(True)
|
self.setWordWrap(True)
|
||||||
self.setTextInteractionFlags(Qt.TextSelectableByMouse)
|
self.setTextInteractionFlags(Qt.TextSelectableByMouse)
|
||||||
self.setAlignment(Qt.AlignCenter)
|
self.setAlignment(Qt.AlignCenter)
|
||||||
@ -100,6 +101,19 @@ class Avatar(QLabel):
|
|||||||
self.setFixedSize(QSize(45, 45))
|
self.setFixedSize(QSize(45, 45))
|
||||||
|
|
||||||
|
|
||||||
|
def open_image_viewer(file_path):
|
||||||
|
system_platform = platform.system()
|
||||||
|
|
||||||
|
if system_platform == "Darwin": # macOS
|
||||||
|
subprocess.run(["open", file_path])
|
||||||
|
elif system_platform == "Windows":
|
||||||
|
subprocess.run(["start", " ", file_path], shell=True)
|
||||||
|
elif system_platform == "Linux":
|
||||||
|
subprocess.run(["xdg-open", file_path])
|
||||||
|
else:
|
||||||
|
print("Unsupported platform")
|
||||||
|
|
||||||
|
|
||||||
class OpenImageThread(QThread):
|
class OpenImageThread(QThread):
|
||||||
def __init__(self, image_path):
|
def __init__(self, image_path):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
@ -107,8 +121,7 @@ class OpenImageThread(QThread):
|
|||||||
|
|
||||||
def run(self) -> None:
|
def run(self) -> None:
|
||||||
if os.path.exists(self.image_path):
|
if os.path.exists(self.image_path):
|
||||||
image = Image.open(self.image_path)
|
open_image_viewer(self.image_path)
|
||||||
image.show()
|
|
||||||
|
|
||||||
|
|
||||||
class ImageMessage(QLabel):
|
class ImageMessage(QLabel):
|
||||||
@ -121,6 +134,9 @@ class ImageMessage(QLabel):
|
|||||||
self.image = QLabel(self)
|
self.image = QLabel(self)
|
||||||
self.max_width = max_width
|
self.max_width = max_width
|
||||||
self.max_height = max_height
|
self.max_height = max_height
|
||||||
|
# self.setFixedSize(self.max_width,self.max_height)
|
||||||
|
self.setMaximumWidth(self.max_width)
|
||||||
|
self.setMaximumHeight(self.max_height)
|
||||||
if isinstance(image, str):
|
if isinstance(image, str):
|
||||||
pixmap = QPixmap(image)
|
pixmap = QPixmap(image)
|
||||||
self.image_path = image
|
self.image_path = image
|
||||||
@ -129,8 +145,7 @@ class ImageMessage(QLabel):
|
|||||||
self.set_image(pixmap)
|
self.set_image(pixmap)
|
||||||
if image_link:
|
if image_link:
|
||||||
self.image_path = image_link
|
self.image_path = image_link
|
||||||
self.setMaximumWidth(self.max_width)
|
|
||||||
self.setMaximumHeight(self.max_height)
|
|
||||||
if is_send:
|
if is_send:
|
||||||
self.setAlignment(Qt.AlignCenter | Qt.AlignRight)
|
self.setAlignment(Qt.AlignCenter | Qt.AlignRight)
|
||||||
# self.setScaledContents(True)
|
# self.setScaledContents(True)
|
||||||
@ -151,7 +166,7 @@ class ImageMessage(QLabel):
|
|||||||
|
|
||||||
|
|
||||||
class BubbleMessage(QWidget):
|
class BubbleMessage(QWidget):
|
||||||
def __init__(self, str_content, avatar, Type, is_send=False, parent=None):
|
def __init__(self, str_content, avatar, Type,is_send=False, display_name=None, parent=None):
|
||||||
super().__init__(parent)
|
super().__init__(parent)
|
||||||
self.isSend = is_send
|
self.isSend = is_send
|
||||||
# self.set
|
# self.set
|
||||||
@ -173,17 +188,30 @@ class BubbleMessage(QWidget):
|
|||||||
self.message = ImageMessage(str_content, is_send)
|
self.message = ImageMessage(str_content, is_send)
|
||||||
else:
|
else:
|
||||||
raise ValueError("未知的消息类型")
|
raise ValueError("未知的消息类型")
|
||||||
|
if display_name:
|
||||||
|
label_name = QLabel(display_name,self)
|
||||||
|
if is_send:
|
||||||
|
label_name.setAlignment(Qt.AlignRight)
|
||||||
|
vlayout = QVBoxLayout()
|
||||||
|
vlayout.setSpacing(0)
|
||||||
|
vlayout.addWidget(label_name)
|
||||||
|
vlayout.addWidget(self.message)
|
||||||
self.spacerItem = QSpacerItem(45 + 6, 45, QSizePolicy.Expanding, QSizePolicy.Minimum)
|
self.spacerItem = QSpacerItem(45 + 6, 45, QSizePolicy.Expanding, QSizePolicy.Minimum)
|
||||||
if is_send:
|
if is_send:
|
||||||
layout.addItem(self.spacerItem)
|
layout.addItem(self.spacerItem)
|
||||||
layout.addWidget(self.message, 1)
|
if display_name:
|
||||||
|
layout.addLayout(vlayout,1)
|
||||||
|
else:
|
||||||
|
layout.addWidget(self.message, 1)
|
||||||
layout.addWidget(triangle, 0, Qt.AlignTop | Qt.AlignLeft)
|
layout.addWidget(triangle, 0, Qt.AlignTop | Qt.AlignLeft)
|
||||||
layout.addWidget(self.avatar, 0, Qt.AlignTop | Qt.AlignLeft)
|
layout.addWidget(self.avatar, 0, Qt.AlignTop | Qt.AlignLeft)
|
||||||
else:
|
else:
|
||||||
layout.addWidget(self.avatar, 0, Qt.AlignTop | Qt.AlignRight)
|
layout.addWidget(self.avatar, 0, Qt.AlignTop | Qt.AlignRight)
|
||||||
layout.addWidget(triangle, 0, Qt.AlignTop | Qt.AlignRight)
|
layout.addWidget(triangle, 0, Qt.AlignTop | Qt.AlignRight)
|
||||||
layout.addWidget(self.message, 1)
|
if display_name:
|
||||||
|
layout.addLayout(vlayout,1)
|
||||||
|
else:
|
||||||
|
layout.addWidget(self.message, 1)
|
||||||
layout.addItem(self.spacerItem)
|
layout.addItem(self.spacerItem)
|
||||||
self.setLayout(layout)
|
self.setLayout(layout)
|
||||||
|
|
||||||
@ -206,8 +234,6 @@ class ScrollArea(QScrollArea):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class ChatWidget(QWidget):
|
class ChatWidget(QWidget):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
|
@ -47,8 +47,9 @@ class Person:
|
|||||||
os.makedirs('./data/avatar', exist_ok=True)
|
os.makedirs('./data/avatar', exist_ok=True)
|
||||||
save_path = os.path.join(f'data/avatar/', self.wxid + '.png')
|
save_path = os.path.join(f'data/avatar/', self.wxid + '.png')
|
||||||
self.avatar_path = save_path
|
self.avatar_path = save_path
|
||||||
self.avatar.save(save_path)
|
if not os.path.exists(save_path):
|
||||||
print('保存头像', save_path)
|
self.avatar.save(save_path)
|
||||||
|
print('保存头像', save_path)
|
||||||
|
|
||||||
|
|
||||||
@singleton
|
@singleton
|
||||||
|
@ -36,6 +36,8 @@ class ChatInfo(QWidget):
|
|||||||
self.setLayout(self.vBoxLayout)
|
self.setLayout(self.vBoxLayout)
|
||||||
|
|
||||||
def show_chats(self):
|
def show_chats(self):
|
||||||
|
# Me().save_avatar()
|
||||||
|
# self.contact.save_avatar()
|
||||||
self.show_chat_thread = ShowChatThread(self.contact)
|
self.show_chat_thread = ShowChatThread(self.contact)
|
||||||
self.show_chat_thread.showSingal.connect(self.add_message)
|
self.show_chat_thread.showSingal.connect(self.add_message)
|
||||||
self.show_chat_thread.finishSingal.connect(self.show_finish)
|
self.show_chat_thread.finishSingal.connect(self.show_finish)
|
||||||
@ -79,6 +81,29 @@ class ChatInfo(QWidget):
|
|||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def get_avatar_path(self, is_send, message, is_absolute_path=False) -> str:
|
||||||
|
if self.contact.is_chatroom:
|
||||||
|
avatar = message[12].smallHeadImgUrl
|
||||||
|
else:
|
||||||
|
avatar = Me().smallHeadImgUrl if is_send else self.contact.smallHeadImgUrl
|
||||||
|
if is_absolute_path:
|
||||||
|
if self.contact.is_chatroom:
|
||||||
|
# message[12].save_avatar()
|
||||||
|
avatar = message[12].avatar
|
||||||
|
else:
|
||||||
|
avatar = Me().avatar if is_send else self.contact.avatar
|
||||||
|
return avatar
|
||||||
|
|
||||||
|
def get_display_name(self, is_send, message) -> str:
|
||||||
|
if self.contact.is_chatroom:
|
||||||
|
if is_send:
|
||||||
|
display_name = Me().name
|
||||||
|
else:
|
||||||
|
display_name = message[12].remark
|
||||||
|
else:
|
||||||
|
display_name = None
|
||||||
|
return display_name
|
||||||
|
|
||||||
def add_message(self, message):
|
def add_message(self, message):
|
||||||
try:
|
try:
|
||||||
type_ = message[2]
|
type_ = message[2]
|
||||||
@ -86,7 +111,8 @@ class ChatInfo(QWidget):
|
|||||||
str_time = message[8]
|
str_time = message[8]
|
||||||
# print(type_, type(type_))
|
# print(type_, type(type_))
|
||||||
is_send = message[4]
|
is_send = message[4]
|
||||||
avatar = Me().avatar if is_send else self.contact.avatar
|
avatar = self.get_avatar_path(is_send, message,True)
|
||||||
|
display_name = self.get_display_name(is_send, message)
|
||||||
timestamp = message[5]
|
timestamp = message[5]
|
||||||
BytesExtra = message[10]
|
BytesExtra = message[10]
|
||||||
if type_ == 1:
|
if type_ == 1:
|
||||||
@ -98,7 +124,8 @@ class ChatInfo(QWidget):
|
|||||||
str_content,
|
str_content,
|
||||||
avatar,
|
avatar,
|
||||||
type_,
|
type_,
|
||||||
is_send
|
is_send,
|
||||||
|
display_name=display_name
|
||||||
)
|
)
|
||||||
self.chat_window.add_message_item(bubble_message, 0)
|
self.chat_window.add_message_item(bubble_message, 0)
|
||||||
elif type_ == 3:
|
elif type_ == 3:
|
||||||
@ -107,7 +134,7 @@ class ChatInfo(QWidget):
|
|||||||
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
|
||||||
self.chat_window.add_message_item(time_message, 0)
|
self.chat_window.add_message_item(time_message, 0)
|
||||||
image_path = hard_link_db.get_image(content=str_content,bytesExtra=BytesExtra, thumb=False)
|
image_path = hard_link_db.get_image(content=str_content, bytesExtra=BytesExtra, thumb=False)
|
||||||
image_path = get_abs_path(image_path)
|
image_path = get_abs_path(image_path)
|
||||||
bubble_message = BubbleMessage(
|
bubble_message = BubbleMessage(
|
||||||
image_path,
|
image_path,
|
||||||
@ -132,7 +159,7 @@ class ChatInfo(QWidget):
|
|||||||
self.chat_window.add_message_item(bubble_message, 0)
|
self.chat_window.add_message_item(bubble_message, 0)
|
||||||
elif type_ == 10000:
|
elif type_ == 10000:
|
||||||
str_content = str_content.lstrip('<revokemsg>').rstrip('</revokemsg>')
|
str_content = str_content.lstrip('<revokemsg>').rstrip('</revokemsg>')
|
||||||
message = Notice(str_content )
|
message = Notice(str_content)
|
||||||
self.chat_window.add_message_item(message, 0)
|
self.chat_window.add_message_item(message, 0)
|
||||||
except:
|
except:
|
||||||
print(message)
|
print(message)
|
||||||
|
@ -79,10 +79,7 @@ class MainWinController(QMainWindow, mainwindow.Ui_MainWindow,QCursorGif):
|
|||||||
self.outputThread0 = None
|
self.outputThread0 = None
|
||||||
self.outputThread = None
|
self.outputThread = None
|
||||||
self.setupUi(self)
|
self.setupUi(self)
|
||||||
# 设置忙碌光标图片数组
|
|
||||||
self.initCursor([':/icons/icons/Cursors/%d.png' %
|
|
||||||
i for i in range(8)])
|
|
||||||
self.setCursorTimeout(100)
|
|
||||||
# self.setWindowIcon(Icon.MainWindow_Icon)
|
# self.setWindowIcon(Icon.MainWindow_Icon)
|
||||||
pixmap = QPixmap(Icon.logo_ico_path)
|
pixmap = QPixmap(Icon.logo_ico_path)
|
||||||
icon = QIcon(pixmap)
|
icon = QIcon(pixmap)
|
||||||
@ -97,6 +94,14 @@ class MainWinController(QMainWindow, mainwindow.Ui_MainWindow,QCursorGif):
|
|||||||
self.label = QLabel(self)
|
self.label = QLabel(self)
|
||||||
self.label.setGeometry((self.width() - 300) // 2, (self.height() - 100) // 2, 300, 100)
|
self.label.setGeometry((self.width() - 300) // 2, (self.height() - 100) // 2, 300, 100)
|
||||||
self.label.setPixmap(QPixmap(':/icons/icons/loading.svg'))
|
self.label.setPixmap(QPixmap(':/icons/icons/loading.svg'))
|
||||||
|
self.menu_output.setIcon(Icon.Output)
|
||||||
|
self.action_output_CSV.setIcon(Icon.ToCSV)
|
||||||
|
self.action_output_CSV.triggered.connect(self.output)
|
||||||
|
self.action_output_contacts.setIcon(Icon.Output)
|
||||||
|
self.action_output_contacts.triggered.connect(self.output)
|
||||||
|
self.action_batch_export.setIcon(Icon.Output)
|
||||||
|
self.action_batch_export.triggered.connect(self.output)
|
||||||
|
self.action_desc.setIcon(Icon.Help_Icon)
|
||||||
|
|
||||||
def load_data(self, flag=True):
|
def load_data(self, flag=True):
|
||||||
if os.path.exists('./app/data/info.json'):
|
if os.path.exists('./app/data/info.json'):
|
||||||
@ -119,15 +124,15 @@ class MainWinController(QMainWindow, mainwindow.Ui_MainWindow,QCursorGif):
|
|||||||
)
|
)
|
||||||
|
|
||||||
def init_ui(self):
|
def init_ui(self):
|
||||||
|
|
||||||
|
# 设置忙碌光标图片数组
|
||||||
|
self.initCursor([':/icons/icons/Cursors/%d.png' %
|
||||||
|
i for i in range(8)])
|
||||||
|
self.setCursorTimeout(100)
|
||||||
|
|
||||||
self.startBusy()
|
self.startBusy()
|
||||||
self.menu_output.setIcon(Icon.Output)
|
|
||||||
self.action_output_CSV.setIcon(Icon.ToCSV)
|
|
||||||
self.action_output_CSV.triggered.connect(self.output)
|
|
||||||
self.action_output_contacts.setIcon(Icon.Output)
|
|
||||||
self.action_output_contacts.triggered.connect(self.output)
|
|
||||||
self.action_batch_export.setIcon(Icon.Output)
|
|
||||||
self.action_batch_export.triggered.connect(self.output)
|
|
||||||
self.action_desc.setIcon(Icon.Help_Icon)
|
|
||||||
self.action_help_contact.triggered.connect(
|
self.action_help_contact.triggered.connect(
|
||||||
lambda: QDesktopServices.openUrl(QUrl("https://blog.lc044.love/post/5")))
|
lambda: QDesktopServices.openUrl(QUrl("https://blog.lc044.love/post/5")))
|
||||||
self.action_help_chat.triggered.connect(
|
self.action_help_chat.triggered.connect(
|
||||||
|
@ -130,7 +130,7 @@ class DecryptControl(QWidget, decryptUi.Ui_Dialog, QCursorGif):
|
|||||||
return
|
return
|
||||||
if self.info.get('key') == 'None':
|
if self.info.get('key') == 'None':
|
||||||
QMessageBox.critical(self, "错误",
|
QMessageBox.critical(self, "错误",
|
||||||
"密钥错误\n将软件放在桌面上试试\n如果还不可以的话我也我能为力,您可以等待后续版本解决该问题")
|
"密钥错误\n请查看教程解决相关问题")
|
||||||
close_db()
|
close_db()
|
||||||
self.thread2 = DecryptThread(db_dir, self.info['key'])
|
self.thread2 = DecryptThread(db_dir, self.info['key'])
|
||||||
self.thread2.maxNumSignal.connect(self.setProgressBarMaxNum)
|
self.thread2.maxNumSignal.connect(self.setProgressBarMaxNum)
|
||||||
@ -232,11 +232,13 @@ class DecryptThread(QThread):
|
|||||||
try:
|
try:
|
||||||
shutil.copy2("app/DataBase/Msg/MSG0.db", target_database) # 使用一个数据库文件作为模板
|
shutil.copy2("app/DataBase/Msg/MSG0.db", target_database) # 使用一个数据库文件作为模板
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
|
logger.error(traceback.format_exc())
|
||||||
self.errorSignal.emit(True)
|
self.errorSignal.emit(True)
|
||||||
# 合并数据库
|
# 合并数据库
|
||||||
try:
|
try:
|
||||||
merge_databases(source_databases, target_database)
|
merge_databases(source_databases, target_database)
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
|
logger.error(traceback.format_exc())
|
||||||
QMessageBox.critical("错误", "数据库不存在\n请检查微信版本是否为最新")
|
QMessageBox.critical("错误", "数据库不存在\n请检查微信版本是否为最新")
|
||||||
|
|
||||||
# 音频数据库文件
|
# 音频数据库文件
|
||||||
@ -248,11 +250,13 @@ class DecryptThread(QThread):
|
|||||||
try:
|
try:
|
||||||
shutil.copy2("app/DataBase/Msg/MediaMSG0.db", target_database) # 使用一个数据库文件作为模板
|
shutil.copy2("app/DataBase/Msg/MediaMSG0.db", target_database) # 使用一个数据库文件作为模板
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
|
logger.error(traceback.format_exc())
|
||||||
self.errorSignal.emit(True)
|
self.errorSignal.emit(True)
|
||||||
# 合并数据库
|
# 合并数据库
|
||||||
try:
|
try:
|
||||||
merge_MediaMSG_databases(source_databases, target_database)
|
merge_MediaMSG_databases(source_databases, target_database)
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
|
logger.error(traceback.format_exc())
|
||||||
QMessageBox.critical("错误", "数据库不存在\n请检查微信版本是否为最新")
|
QMessageBox.critical("错误", "数据库不存在\n请检查微信版本是否为最新")
|
||||||
self.okSignal.emit('ok')
|
self.okSignal.emit('ok')
|
||||||
# self.signal.emit('100')
|
# self.signal.emit('100')
|
||||||
|
26
main.py
26
main.py
@ -3,19 +3,6 @@ import sys
|
|||||||
import time
|
import time
|
||||||
import traceback
|
import traceback
|
||||||
|
|
||||||
from PyQt5.QtGui import QFont
|
|
||||||
from PyQt5.QtWidgets import *
|
|
||||||
from PyQt5.QtCore import Qt
|
|
||||||
|
|
||||||
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
|
|
||||||
from app.config import version
|
|
||||||
|
|
||||||
ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID("WeChatReport")
|
|
||||||
QApplication.setAttribute(Qt.AA_EnableHighDpiScaling, True)
|
|
||||||
QApplication.setAttribute(Qt.AA_UseHighDpiPixmaps, True)
|
|
||||||
widget = None
|
widget = None
|
||||||
|
|
||||||
|
|
||||||
@ -35,6 +22,19 @@ def excepthook(exc_type, exc_value, traceback_):
|
|||||||
|
|
||||||
# 设置 excepthook
|
# 设置 excepthook
|
||||||
sys.excepthook = excepthook
|
sys.excepthook = excepthook
|
||||||
|
from PyQt5.QtGui import QFont
|
||||||
|
from PyQt5.QtWidgets import *
|
||||||
|
from PyQt5.QtCore import Qt
|
||||||
|
|
||||||
|
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
|
||||||
|
from app.config import version
|
||||||
|
|
||||||
|
ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID("WeChatReport")
|
||||||
|
QApplication.setAttribute(Qt.AA_EnableHighDpiScaling, True)
|
||||||
|
QApplication.setAttribute(Qt.AA_UseHighDpiPixmaps, True)
|
||||||
|
|
||||||
|
|
||||||
class ViewController(QWidget):
|
class ViewController(QWidget):
|
||||||
|
@ -272,6 +272,7 @@ python main.py
|
|||||||
|
|
||||||
- [STDquantum](https://github.com/STDquantum)
|
- [STDquantum](https://github.com/STDquantum)
|
||||||
- [xuanli](https://github.com/xuanli)
|
- [xuanli](https://github.com/xuanli)
|
||||||
|
- [无名路人](https://github.com/wumingluren)
|
||||||
|
|
||||||
如果您提供赞助并希望出现在赞助者名单中,请在提交赞助时提供您的 GitHub 用户名或其他相关信息。
|
如果您提供赞助并希望出现在赞助者名单中,请在提交赞助时提供您的 GitHub 用户名或其他相关信息。
|
||||||
|
|
||||||
|
@ -7,7 +7,6 @@ silk-python
|
|||||||
pyaudio
|
pyaudio
|
||||||
fuzzywuzzy
|
fuzzywuzzy
|
||||||
python-Levenshtein
|
python-Levenshtein
|
||||||
Pillow==10.1.0
|
|
||||||
requests
|
requests
|
||||||
flask==3.0.0
|
flask==3.0.0
|
||||||
pyecharts==2.0.1
|
pyecharts==2.0.1
|
||||||
|
Loading…
Reference in New Issue
Block a user