diff --git a/app/DataBase/output_pc.py b/app/DataBase/output_pc.py index 20a6370..55bb67c 100644 --- a/app/DataBase/output_pc.py +++ b/app/DataBase/output_pc.py @@ -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('').rstrip('')) - 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() diff --git a/app/ui_pc/contact/contactInfo.py b/app/ui_pc/contact/contactInfo.py index 2fe26b4..9f4da77 100644 --- a/app/ui_pc/contact/contactInfo.py +++ b/app/ui_pc/contact/contactInfo.py @@ -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) diff --git a/app/ui_pc/contact/export_dialog.py b/app/ui_pc/contact/export_dialog.py index 5365b36..263b9e8 100644 --- a/app/ui_pc/contact/export_dialog.py +++ b/app/ui_pc/contact/export_dialog.py @@ -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}%")