mirror of
https://github.com/LC044/WeChatMsg
synced 2025-02-21 01:52:35 +08:00
支持导出txt
This commit is contained in:
parent
4bf1729d20
commit
682e69376e
@ -57,6 +57,7 @@ class Output(QThread):
|
||||
HTML = 2
|
||||
CSV_ALL = 3
|
||||
CONTACT_CSV = 4
|
||||
TXT = 5
|
||||
|
||||
def __init__(self, contact, type_=DOCX, message_types={}, parent=None):
|
||||
super().__init__(parent)
|
||||
@ -123,7 +124,7 @@ class Output(QThread):
|
||||
elif self.output_type == self.CONTACT_CSV:
|
||||
self.contact_to_csv()
|
||||
else:
|
||||
self.Child = ChildThread(self.contact, type_=self.output_type,message_types=self.message_types)
|
||||
self.Child = ChildThread(self.contact, type_=self.output_type, message_types=self.message_types)
|
||||
self.Child.progressSignal.connect(self.progress)
|
||||
self.Child.rangeSignal.connect(self.rangeSignal)
|
||||
self.Child.okSignal.connect(self.okSignal)
|
||||
@ -154,7 +155,6 @@ class ChildThread(QThread):
|
||||
self.msg_id = 0
|
||||
self.output_type = type_
|
||||
|
||||
|
||||
def is_5_min(self, timestamp):
|
||||
if abs(timestamp - self.last_timestamp) > 300:
|
||||
self.last_timestamp = timestamp
|
||||
@ -168,18 +168,24 @@ class ChildThread(QThread):
|
||||
is_send = message[4]
|
||||
avatar = 'myhead.png' if is_send else 'tahead.png'
|
||||
timestamp = message[5]
|
||||
str_content = escape_js_and_html(str_content)
|
||||
if self.is_5_min(timestamp):
|
||||
if self.output_type == Output.HTML:
|
||||
str_content = escape_js_and_html(str_content)
|
||||
if self.is_5_min(timestamp):
|
||||
doc.write(
|
||||
f'''{{ type:0, text: '{str_time}',is_send:0,avatar_path:''}},'''
|
||||
)
|
||||
emojiText = findall(r"(\[.+?\])", str_content)
|
||||
for emoji_text in emojiText:
|
||||
if emoji_text in emoji:
|
||||
str_content = str_content.replace(emoji_text, emoji[emoji_text])
|
||||
doc.write(
|
||||
f'''{{ type:0, text: '{str_time}',is_send:0,avatar_path:''}},'''
|
||||
f'''{{ type:{type_}, text: '{str_content}',is_send:{is_send},avatar_path:'{avatar}'}},'''
|
||||
)
|
||||
elif self.output_type == Output.TXT:
|
||||
name = '你' if is_send else self.contact.remark
|
||||
doc.write(
|
||||
f'''{str_time} {name}\n{str_content}\n\n'''
|
||||
)
|
||||
emojiText = findall(r"(\[.+?\])", str_content)
|
||||
for emoji_text in emojiText:
|
||||
if emoji_text in emoji:
|
||||
str_content = str_content.replace(emoji_text, emoji[emoji_text])
|
||||
doc.write(
|
||||
f'''{{ type:{type_}, text: '{str_content}',is_send:{is_send},avatar_path:'{avatar}'}},'''
|
||||
)
|
||||
|
||||
def image(self, doc, message):
|
||||
type_ = message[2]
|
||||
@ -189,24 +195,29 @@ class ChildThread(QThread):
|
||||
avatar = 'myhead.png' if is_send else 'tahead.png'
|
||||
timestamp = message[5]
|
||||
BytesExtra = message[10]
|
||||
str_content = escape_js_and_html(str_content)
|
||||
image_path = hard_link_db.get_image(str_content, BytesExtra, thumb=False)
|
||||
image_thumb_path = hard_link_db.get_image(str_content, BytesExtra, thumb=True)
|
||||
if image_path is None and image_thumb_path is not None:
|
||||
image_path = image_thumb_path
|
||||
if image_path is None and image_thumb_path is None:
|
||||
return
|
||||
image_path = path.get_relative_path(image_path, base_path=f'/data/聊天记录/{self.contact.remark}/image')
|
||||
image_path = image_path.replace('\\', '/')
|
||||
# print(f"tohtml:---{image_path}")
|
||||
if self.is_5_min(timestamp):
|
||||
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)
|
||||
image_thumb_path = hard_link_db.get_image(str_content, BytesExtra, thumb=True)
|
||||
if image_path is None and image_thumb_path is not None:
|
||||
image_path = image_thumb_path
|
||||
if image_path is None and image_thumb_path is None:
|
||||
return
|
||||
image_path = path.get_relative_path(image_path, base_path=f'/data/聊天记录/{self.contact.remark}/image')
|
||||
image_path = image_path.replace('\\', '/')
|
||||
# print(f"tohtml:---{image_path}")
|
||||
if self.is_5_min(timestamp):
|
||||
doc.write(
|
||||
f'''{{ type:0, text: '{str_time}',is_send:0,avatar_path:''}},'''
|
||||
)
|
||||
doc.write(
|
||||
f'''{{ type:0, text: '{str_time}',is_send:0,avatar_path:''}},'''
|
||||
f'''{{ type:{type_}, text: '{image_path}',is_send:{is_send},avatar_path:'{avatar}'}},'''
|
||||
)
|
||||
elif self.output_type == Output.TXT:
|
||||
name = '你' if is_send else self.contact.remark
|
||||
doc.write(
|
||||
f'''{str_time} {name}\n[图片]\n\n'''
|
||||
)
|
||||
doc.write(
|
||||
f'''{{ type:{type_}, text: '{image_path}',is_send:{is_send},avatar_path:'{avatar}'}},'''
|
||||
)
|
||||
return
|
||||
|
||||
def emoji(self, doc, message):
|
||||
origin_docx_path = f"{os.path.abspath('.')}/data/聊天记录/{self.contact.remark}"
|
||||
@ -215,16 +226,21 @@ class ChildThread(QThread):
|
||||
is_send = message[4]
|
||||
avatar = 'myhead.png' if is_send else 'tahead.png'
|
||||
timestamp = message[5]
|
||||
emoji_path = get_emoji(str_content, thumb=True, output_path=origin_docx_path + '/emoji')
|
||||
emoji_path = './emoji/' + os.path.basename(emoji_path)
|
||||
if self.is_5_min(timestamp):
|
||||
if self.output_type == Output.HTML:
|
||||
emoji_path = get_emoji(str_content, thumb=True, output_path=origin_docx_path + '/emoji')
|
||||
emoji_path = './emoji/' + os.path.basename(emoji_path)
|
||||
if self.is_5_min(timestamp):
|
||||
doc.write(
|
||||
f'''{{ type:0, text: '{str_time}',is_send:0,avatar_path:''}},'''
|
||||
)
|
||||
doc.write(
|
||||
f'''{{ type:0, text: '{str_time}',is_send:0,avatar_path:''}},'''
|
||||
f'''{{ type:{3}, text: '{emoji_path}',is_send:{is_send},avatar_path:'{avatar}'}},'''
|
||||
)
|
||||
elif self.output_type == Output.TXT:
|
||||
name = '你' if is_send else self.contact.remark
|
||||
doc.write(
|
||||
f'''{str_time} {name}\n[表情包]\n\n'''
|
||||
)
|
||||
doc.write(
|
||||
f'''{{ type:{3}, text: '{emoji_path}',is_send:{is_send},avatar_path:'{avatar}'}},'''
|
||||
)
|
||||
return
|
||||
|
||||
def wx_file(self, doc, isSend, content, status):
|
||||
return
|
||||
@ -238,10 +254,17 @@ class ChildThread(QThread):
|
||||
def system_msg(self, doc, message):
|
||||
str_content = message[7]
|
||||
is_send = message[4]
|
||||
str_time = message[8]
|
||||
str_content = escape_js_and_html(str_content.lstrip('<revokemsg>').rstrip('</revokemsg>'))
|
||||
doc.write(
|
||||
f'''{{ type:0, text: '{str_content}',is_send:{is_send},avatar_path:''}},'''
|
||||
)
|
||||
if self.output_type == Output.HTML:
|
||||
doc.write(
|
||||
f'''{{ type:0, text: '{str_content}',is_send:{is_send},avatar_path:''}},'''
|
||||
)
|
||||
elif self.output_type == Output.TXT:
|
||||
name = '你' if is_send else self.contact.remark
|
||||
doc.write(
|
||||
f'''{str_time} {name}\n{str_content}\n\n'''
|
||||
)
|
||||
|
||||
def video(self, doc, message):
|
||||
origin_docx_path = f"{os.path.abspath('.')}/data/聊天记录/{self.contact.remark}"
|
||||
@ -252,43 +275,49 @@ class ChildThread(QThread):
|
||||
BytesExtra = message[10]
|
||||
avatar = 'myhead.png' if is_send else 'tahead.png'
|
||||
timestamp = message[5]
|
||||
video_path = hard_link_db.get_video(str_content, BytesExtra, thumb=False)
|
||||
image_path = hard_link_db.get_video(str_content, BytesExtra, thumb=True)
|
||||
if video_path is None and image_path is not None:
|
||||
print(video_path, image_path)
|
||||
image_path = path.get_relative_path(image_path, base_path=f'/data/聊天记录/{self.contact.remark}/image')
|
||||
print(image_path)
|
||||
image_path = image_path.replace('\\', '/')
|
||||
# print(f"tohtml:---{image_path}")
|
||||
if self.output_type == Output.HTML:
|
||||
video_path = hard_link_db.get_video(str_content, BytesExtra, thumb=False)
|
||||
image_path = hard_link_db.get_video(str_content, BytesExtra, thumb=True)
|
||||
if video_path is None and image_path is not None:
|
||||
print(video_path, image_path)
|
||||
image_path = path.get_relative_path(image_path, base_path=f'/data/聊天记录/{self.contact.remark}/image')
|
||||
print(image_path)
|
||||
image_path = image_path.replace('\\', '/')
|
||||
# print(f"tohtml:---{image_path}")
|
||||
if self.is_5_min(timestamp):
|
||||
doc.write(
|
||||
f'''{{ type:0, text: '{str_time}',is_send:0,avatar_path:''}},'''
|
||||
)
|
||||
doc.write(
|
||||
f'''{{ type:3, text: '{image_path}',is_send:{is_send},avatar_path:'{avatar}'}},'''
|
||||
)
|
||||
return
|
||||
if video_path is None and image_path is None:
|
||||
return
|
||||
video_path = f'{MePC().wx_dir}/{video_path}'
|
||||
if os.path.exists(video_path):
|
||||
new_path = origin_docx_path + '/video/' + os.path.basename(video_path)
|
||||
if not os.path.exists(new_path):
|
||||
shutil.copy(video_path, os.path.join(origin_docx_path, 'video'))
|
||||
video_path = f'./video/{os.path.basename(video_path)}'
|
||||
video_path = video_path.replace('\\', '/')
|
||||
if self.is_5_min(timestamp):
|
||||
doc.write(
|
||||
f'''{{ type:0, text: '{str_time}',is_send:0,avatar_path:''}},'''
|
||||
)
|
||||
doc.write(
|
||||
f'''{{ type:3, text: '{image_path}',is_send:{is_send},avatar_path:'{avatar}'}},'''
|
||||
f'''{{ type:{type_}, text: '{video_path}',is_send:{is_send},avatar_path:'{avatar}'}},'''
|
||||
)
|
||||
return
|
||||
if video_path is None and image_path is None:
|
||||
return
|
||||
video_path = f'{MePC().wx_dir}/{video_path}'
|
||||
if os.path.exists(video_path):
|
||||
new_path = origin_docx_path + '/video/' + os.path.basename(video_path)
|
||||
if not os.path.exists(new_path):
|
||||
shutil.copy(video_path, os.path.join(origin_docx_path, 'video'))
|
||||
video_path = f'./video/{os.path.basename(video_path)}'
|
||||
video_path = video_path.replace('\\', '/')
|
||||
if self.is_5_min(timestamp):
|
||||
elif self.output_type == Output.TXT:
|
||||
name = '你' if is_send else self.contact.remark
|
||||
doc.write(
|
||||
f'''{{ type:0, text: '{str_time}',is_send:0,avatar_path:''}},'''
|
||||
f'''{str_time} {name}\n[视频]\n\n'''
|
||||
)
|
||||
doc.write(
|
||||
f'''{{ type:{type_}, text: '{video_path}',is_send:{is_send},avatar_path:'{avatar}'}},'''
|
||||
)
|
||||
|
||||
def to_csv(self):
|
||||
origin_docx_path = f"{os.path.abspath('.')}/data/聊天记录/{self.contact.remark}"
|
||||
os.makedirs(origin_docx_path, exist_ok=True)
|
||||
filename = f"{os.path.abspath('.')}/data/聊天记录/{self.contact.remark}/{self.contact.remark}.csv"
|
||||
filename = f"{os.path.abspath('.')}/data/聊天记录/{self.contact.remark}/{self.contact.remark}_utf8.csv"
|
||||
# columns = ["用户名", "消息内容", "发送时间", "发送状态", "消息类型", "isSend", "msgId"]
|
||||
columns = ['localId', 'TalkerId', 'Type', 'SubType',
|
||||
'IsSender', 'CreateTime', 'Status', 'StrContent',
|
||||
@ -300,27 +329,13 @@ class ChildThread(QThread):
|
||||
writer.writerow(columns)
|
||||
# 写入数据
|
||||
writer.writerows(messages)
|
||||
# with open(filename, mode='r', newline='', encoding='utf-8') as file:
|
||||
# content = file.read()
|
||||
# filename = f"{os.path.abspath('.')}/data/聊天记录/{self.contact.remark}/{self.contact.remark}_gbk.csv"
|
||||
# with open(filename, mode='w', newline='', encoding='gbk') as file:
|
||||
# file.write(content.encode('utf-8', errors='ignore').decode('gbk', errors='ignore'))
|
||||
self.okSignal.emit('ok')
|
||||
|
||||
def to_csv_all(self):
|
||||
origin_docx_path = f"{os.path.abspath('.')}/data/聊天记录/"
|
||||
os.makedirs(origin_docx_path, exist_ok=True)
|
||||
filename = f"{os.path.abspath('.')}/data/聊天记录/messages.csv"
|
||||
# columns = ["用户名", "消息内容", "发送时间", "发送状态", "消息类型", "isSend", "msgId"]
|
||||
columns = ['localId', 'TalkerId', 'Type', 'SubType',
|
||||
'IsSender', 'CreateTime', 'Status', 'StrContent',
|
||||
'StrTime', 'Remark', 'NickName', 'Sender']
|
||||
# messages = msg_db.get_messages_all()
|
||||
packagemsg = PackageMsg()
|
||||
messages = packagemsg.get_package_message_all()
|
||||
# 写入CSV文件
|
||||
with open(filename, mode='w', newline='', encoding='utf-8') as file:
|
||||
writer = csv.writer(file)
|
||||
writer.writerow(columns)
|
||||
# 写入数据
|
||||
writer.writerows(messages)
|
||||
self.okSignal.emit(1)
|
||||
|
||||
def to_html_(self):
|
||||
origin_docx_path = f"{os.path.abspath('.')}/data/聊天记录/{self.contact.remark}"
|
||||
makedirs(origin_docx_path)
|
||||
@ -334,7 +349,7 @@ class ChildThread(QThread):
|
||||
total_steps = len(messages)
|
||||
for index, message in enumerate(messages):
|
||||
type_ = message[2]
|
||||
self.progressSignal.emit(int((index+1) / total_steps * 100))
|
||||
self.progressSignal.emit(int((index + 1) / total_steps * 100))
|
||||
if type_ == 1 and self.message_types.get(type_):
|
||||
self.text(f, message)
|
||||
elif type_ == 3 and self.message_types.get(type_):
|
||||
@ -349,6 +364,27 @@ class ChildThread(QThread):
|
||||
f.close()
|
||||
self.okSignal.emit(1)
|
||||
|
||||
def to_txt(self):
|
||||
origin_docx_path = f"{os.path.abspath('.')}/data/聊天记录/{self.contact.remark}"
|
||||
os.makedirs(origin_docx_path, exist_ok=True)
|
||||
filename = f"{os.path.abspath('.')}/data/聊天记录/{self.contact.remark}/{self.contact.remark}.txt"
|
||||
messages = msg_db.get_messages(self.contact.wxid)
|
||||
total_steps = len(messages)
|
||||
with open(filename, mode='w', newline='', encoding='utf-8') as f:
|
||||
for index, message in enumerate(messages):
|
||||
type_ = message[2]
|
||||
self.progressSignal.emit(int((index + 1) / total_steps * 100))
|
||||
if type_ == 1 and self.message_types.get(type_):
|
||||
self.text(f, message)
|
||||
elif type_ == 3 and self.message_types.get(type_):
|
||||
self.image(f, message)
|
||||
elif type_ == 43 and self.message_types.get(type_):
|
||||
self.video(f, message)
|
||||
elif type_ == 47 and self.message_types.get(type_):
|
||||
self.emoji(f, message)
|
||||
elif type_ == 10000 and self.message_types.get(type_):
|
||||
self.system_msg(f, message)
|
||||
self.okSignal.emit(1)
|
||||
def run(self):
|
||||
if self.output_type == Output.DOCX:
|
||||
return
|
||||
@ -358,6 +394,8 @@ class ChildThread(QThread):
|
||||
self.to_html_()
|
||||
elif self.output_type == Output.CSV_ALL:
|
||||
self.to_csv_all()
|
||||
elif self.output_type == Output.TXT:
|
||||
self.to_txt()
|
||||
|
||||
def cancel(self):
|
||||
self.requestInterruption()
|
||||
|
@ -38,17 +38,20 @@ class ContactInfo(QWidget, Ui_Form):
|
||||
self.toDocxAct = QAction(Icon.ToDocx, '导出Docx', self)
|
||||
self.toCSVAct = QAction(Icon.ToCSV, '导出CSV', self)
|
||||
self.toHtmlAct = QAction(Icon.ToHTML, '导出HTML', self)
|
||||
self.toTxtAct = QAction(Icon.ToHTML, '导出TXT', self)
|
||||
self.toolButton_output.setPopupMode(QToolButton.MenuButtonPopup)
|
||||
self.toolButton_output.clicked.connect(self.toolButton_show)
|
||||
menu.addAction(self.toDocxAct)
|
||||
menu.addAction(self.toCSVAct)
|
||||
menu.addAction(self.toHtmlAct)
|
||||
menu.addAction(self.toTxtAct)
|
||||
self.toolButton_output.setMenu(menu)
|
||||
self.toolButton_output.setIcon(Icon.Output)
|
||||
# self.toolButton_output.addSeparator()
|
||||
self.toHtmlAct.triggered.connect(self.output)
|
||||
self.toDocxAct.triggered.connect(self.output)
|
||||
self.toCSVAct.triggered.connect(self.output)
|
||||
self.toTxtAct.triggered.connect(self.output)
|
||||
|
||||
def toolButton_show(self):
|
||||
self.toolButton_output.showMenu()
|
||||
@ -123,16 +126,9 @@ class ContactInfo(QWidget, Ui_Form):
|
||||
elif self.sender() == self.toHtmlAct:
|
||||
dialog = ExportDialog(self.contact,title='选择导出的消息类型', file_type='html', parent=self)
|
||||
result = dialog.exec_() # 使用exec_()获取用户的操作结果
|
||||
# if result == QDialog.Accepted:
|
||||
# self.result_label.setText("用户点击了导出按钮")
|
||||
# else:
|
||||
# self.result_label.setText("用户点击了取消按钮")
|
||||
# self.outputThread = Output(self.contact, type_=Output.HTML)
|
||||
|
||||
# self.outputThread.progressSignal.connect(self.output_progress)
|
||||
# self.outputThread.rangeSignal.connect(self.set_progressBar_range)
|
||||
# self.outputThread.okSignal.connect(self.hide_progress_bar)
|
||||
# self.outputThread.start()
|
||||
elif self.sender() == self.toTxtAct:
|
||||
dialog = ExportDialog(self.contact, title='选择导出的消息类型', file_type='txt', parent=self)
|
||||
result = dialog.exec_() # 使用exec_()获取用户的操作结果
|
||||
|
||||
def hide_progress_bar(self, int):
|
||||
reply = QMessageBox(self)
|
||||
|
@ -24,6 +24,9 @@ class ExportDialog(QDialog):
|
||||
elif file_type == 'csv':
|
||||
self.export_type = Output.CSV
|
||||
self.export_choices = {"文本": True, "图片": True, "视频": True, "表情包": True} # 定义导出的数据类型,默认全部选择
|
||||
elif file_type == 'txt':
|
||||
self.export_type = Output.TXT
|
||||
self.export_choices = {"文本": True, "图片": True, "视频": True, "表情包": True} # 定义导出的数据类型,默认全部选择
|
||||
else:
|
||||
self.export_choices = {"文本": True, "图片": True, "视频": True, "表情包": True} # 定义导出的数据类型,默认全部选择
|
||||
self.setWindowTitle(title)
|
||||
@ -58,11 +61,12 @@ class ExportDialog(QDialog):
|
||||
|
||||
# 在这里根据用户选择的数据类型执行导出操作
|
||||
print("选择的数据类型:", selected_types)
|
||||
self.worker = Output(self.contact, type_=self.export_type,message_types=selected_types)
|
||||
self.worker = Output(self.contact, type_=self.export_type, message_types=selected_types)
|
||||
self.worker.progressSignal.connect(self.update_progress)
|
||||
self.worker.okSignal.connect(self.export_finished)
|
||||
self.worker.start()
|
||||
# self.accept() # 使用accept关闭对话框
|
||||
|
||||
def export_finished(self):
|
||||
self.export_button.setEnabled(True)
|
||||
self.cancel_button.setEnabled(True)
|
||||
@ -74,6 +78,7 @@ class ExportDialog(QDialog):
|
||||
reply.addButton("取消", QMessageBox.RejectRole)
|
||||
api = reply.exec_()
|
||||
self.accept()
|
||||
|
||||
def update_progress(self, progress_percentage):
|
||||
self.progress_bar.setValue(progress_percentage)
|
||||
self.progress_label.setText(f"导出进度: {progress_percentage}%")
|
||||
|
Loading…
Reference in New Issue
Block a user