支持导出txt

This commit is contained in:
shuaikangzhou 2023-12-10 19:36:08 +08:00
parent 4bf1729d20
commit 682e69376e
3 changed files with 134 additions and 95 deletions

View File

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

View File

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

View File

@ -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}%")