From fbe1f666602b0e528bce5e8b49b84e78972f0398 Mon Sep 17 00:00:00 2001
From: STDquantum <405720329@qq.com>
Date: Tue, 12 Dec 2023 01:17:21 +0800
Subject: [PATCH 1/3] =?UTF-8?q?html=E8=AF=AD=E9=9F=B3=E6=B6=88=E6=81=AF?=
=?UTF-8?q?=E6=94=AF=E6=8C=81=E5=AF=BC=E5=87=BA=EF=BC=8C=E5=A6=82=E6=9E=9C?=
=?UTF-8?q?=E7=94=B5=E8=84=91=E8=BD=AC=E8=BF=87=E6=96=87=E5=AD=97=E9=82=A3?=
=?UTF-8?q?=E4=B9=88=E8=BD=AC=E7=9A=84=E6=96=87=E5=AD=97=E4=B9=9F=E5=8F=AF?=
=?UTF-8?q?=E4=BB=A5=E6=98=BE=E7=A4=BA=E5=87=BA=E6=9D=A5?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
app/DataBase/__init__.py | 4 ++-
app/DataBase/media_msg.py | 43 ++++++++++++++++++++++-----
app/DataBase/output_pc.py | 47 ++++++++++++++++++++++++++++--
app/ui_pc/contact/export_dialog.py | 3 +-
app/util/emoji.py | 1 +
requirements_pc.txt | 3 +-
6 files changed, 88 insertions(+), 13 deletions(-)
diff --git a/app/DataBase/__init__.py b/app/DataBase/__init__.py
index d5c33c0..28f97df 100644
--- a/app/DataBase/__init__.py
+++ b/app/DataBase/__init__.py
@@ -9,6 +9,7 @@
"""
from .hard_link import HardLink
from .micro_msg import MicroMsg
+from .media_msg import MediaMsg
# from . import data
# from . import output
from .misc import Misc
@@ -18,4 +19,5 @@ misc_db = Misc()
msg_db = Msg()
micro_msg_db = MicroMsg()
hard_link_db = HardLink()
-__all__ = ["data", 'output', 'misc_db', 'micro_msg_db', 'msg_db', 'hard_link_db','MsgType']
+media_msg_db = MediaMsg()
+__all__ = ["data", 'output', 'misc_db', 'micro_msg_db', 'msg_db', 'hard_link_db','MsgType', "media_msg_db"]
diff --git a/app/DataBase/media_msg.py b/app/DataBase/media_msg.py
index d1a57ad..9b77605 100644
--- a/app/DataBase/media_msg.py
+++ b/app/DataBase/media_msg.py
@@ -1,9 +1,12 @@
import os.path
+from os import system
import sqlite3
import threading
+import xml.etree.ElementTree as ET
+from pilk import decode
lock = threading.Lock()
-db_path = "./app/Database/Msg/MediaMSG3.db"
+db_path = "./app/Database/Msg/MediaMSG.db"
def singleton(cls):
@@ -16,7 +19,6 @@ def singleton(cls):
return inner
-
@singleton
class MediaMsg:
def __init__(self):
@@ -36,7 +38,6 @@ class MediaMsg:
lock.release()
def get_media_buffer(self, reserved0):
- pass
sql = '''
select Buf
from Media
@@ -45,14 +46,40 @@ class MediaMsg:
try:
lock.acquire(True)
self.cursor.execute(sql, [reserved0])
- return self.cursor.fetchone()
+ return self.cursor.fetchone()[0]
finally:
lock.release()
+ def get_audio(self, reserved0, output_path):
+ buf = self.get_media_buffer(reserved0)
+ silk_path = f"{output_path}\\{reserved0}.silk"
+ pcm_path = f"{output_path}\\{reserved0}.pcm"
+ mp3_path = f"{output_path}\\{reserved0}.mp3"
+ slik_path = silk_path.replace("/", "\\")
+ pcm_path = pcm_path.replace("/", "\\")
+ mp3_path = mp3_path.replace("/", "\\")
+ print(mp3_path)
+ if os.path.exists(mp3_path):
+ return mp3_path
+ open(silk_path, "wb").write(buf)
+ decode(silk_path, pcm_path, 44100)
+ system(f'ffmpeg.exe -loglevel quiet -y -f s16le -i "{pcm_path}" -ar 44100 -ac 1 "{mp3_path}"')
+ system(f'del "{silk_path}"')
+ system(f'del "{pcm_path}"')
+ return mp3_path
+
+ def get_audio_text(self, content):
+ try:
+ root = ET.fromstring(content)
+ transtext = root.find(".//voicetrans").get("transtext")
+ return transtext
+ except ET.ParseError:
+ return ""
+
if __name__ == '__main__':
- db_path = './Msg/MediaMSG3.db'
+ db_path = './Msg/MediaMSG.db'
media_msg_db = MediaMsg()
- reserved = '823076859361714342'
- buf = media_msg_db.get_media_buffer(reserved)
- print(buf)
+ reserved = '2865682741418252473'
+ path = media_msg_db.get_audio(reserved, r"D:\gou\message\WeChatMsg")
+ print(path)
diff --git a/app/DataBase/output_pc.py b/app/DataBase/output_pc.py
index 75f0376..795dbbd 100644
--- a/app/DataBase/output_pc.py
+++ b/app/DataBase/output_pc.py
@@ -8,6 +8,7 @@ from PyQt5.QtWidgets import QFileDialog
from . import msg_db, micro_msg_db
from .package_msg import PackageMsg
from ..DataBase import hard_link_db
+from ..DataBase import media_msg_db
from ..person_pc import MePC
from ..util import path
import shutil
@@ -220,6 +221,30 @@ class ChildThread(QThread):
f'''{str_time} {name}\n[图片]\n\n'''
)
+ def audio(self, doc, message):
+ origin_docx_path = f"{os.path.abspath('.')}/data/聊天记录/{self.contact.remark}"
+ str_content = message[7]
+ str_time = message[8]
+ is_send = message[4]
+ avatar = 'myhead.png' if is_send else 'tahead.png'
+ timestamp = message[5]
+ msgSvrId = message[9]
+ if self.output_type == Output.HTML:
+ try:
+ audio_path = media_msg_db.get_audio(msgSvrId, output_path=origin_docx_path + "/voice")
+ audio_path = audio_path.replace('\\', '/')
+ voice_to_text = media_msg_db.get_audio_text(str_content)
+ except:
+ return
+ if self.is_5_min(timestamp):
+ doc.write(
+ f'''{{ type:0, text: '{str_time}',is_send:0,avatar_path:''}},'''
+ )
+ doc.write(
+ f'''{{ type:34, text:'{audio_path}',is_send:{is_send},avatar_path:'{avatar}',voice_to_text:'{voice_to_text}'}},'''
+ )
+
+
def emoji(self, doc, message):
origin_docx_path = f"{os.path.abspath('.')}/data/聊天记录/{self.contact.remark}"
str_content = message[7]
@@ -381,6 +406,8 @@ class ChildThread(QThread):
self.text(f, message)
elif type_ == 3 and self.message_types.get(type_):
self.image(f, message)
+ elif type_ == 34 and self.message_types.get(type_):
+ self.audio(f, message)
elif type_ == 43 and self.message_types.get(type_):
self.video(f, message)
elif type_ == 47 and self.message_types.get(type_):
@@ -694,6 +721,12 @@ body{
margin-left: 18px;
max-width: 350px;
}
+.chat-audio{
+ max-width: 300px;
+}
+audio{
+ right: 25px;
+}
.input-area{
border-top:0.5px solid #e0e0e0;
height: 150px;
@@ -908,8 +941,8 @@ html_end = '''
else if (message.type == 49) {
if (message.sub_type == 57){
if (message.is_send == 1) {
- messageElement.className = "item item-right";
- messageElement.innerHTML = `
${message.text}
`
+ messageElement.className = "item item-right";
+ messageElement.innerHTML = `${message.text}
`
}
else if (message.is_send == 0) {
messageElement.className = "item item-left";
@@ -917,6 +950,16 @@ html_end = '''
}
}
}
+ else if (message.type == 34) {
+ if (message.is_send == 1) {
+ messageElement.className = "item item-right";
+ messageElement.innerHTML = `${message.voice_to_text == "" ? "" : `
${message.voice_to_text}
`}
`
+ }
+ else if (message.is_send == 0) {
+ messageElement.className = "item item-left";
+ messageElement.innerHTML = `${message.voice_to_text == "" ? "" : `
${message.voice_to_text}
`}
`
+ }
+ }
chatContainer.appendChild(messageElement);
}
document.querySelector("#chat-container").scrollTop = 0;
diff --git a/app/ui_pc/contact/export_dialog.py b/app/ui_pc/contact/export_dialog.py
index 70349b3..cf71ec0 100644
--- a/app/ui_pc/contact/export_dialog.py
+++ b/app/ui_pc/contact/export_dialog.py
@@ -6,6 +6,7 @@ from app.DataBase.output_pc import Output
types = {
'文本': 1,
'图片': 3,
+ '语音': 34,
'视频': 43,
'表情包': 47,
'拍一拍等系统消息': 10000
@@ -26,7 +27,7 @@ class ExportDialog(QDialog):
self.contact = contact
if file_type == 'html':
self.export_type = Output.HTML
- self.export_choices = {"文本": True, "图片": True, "视频": True, "表情包": True,
+ self.export_choices = {"文本": True, "图片": True, "语音": True, "视频": True, "表情包": True,
'拍一拍等系统消息': True} # 定义导出的数据类型,默认全部选择
elif file_type == 'csv':
self.export_type = Output.CSV
diff --git a/app/util/emoji.py b/app/util/emoji.py
index 141cf20..d2a4d7f 100644
--- a/app/util/emoji.py
+++ b/app/util/emoji.py
@@ -41,6 +41,7 @@ def get_image_format(header):
@log
def parser_xml(xml_string):
+ assert type(xml_string) == str
# Parse the XML string
root = ET.fromstring(xml_string)
emoji = root.find('./emoji')
diff --git a/requirements_pc.txt b/requirements_pc.txt
index e8b56b0..18c0be7 100644
--- a/requirements_pc.txt
+++ b/requirements_pc.txt
@@ -15,4 +15,5 @@ jieba==0.42.1
google==3.0.0
protobuf==4.25.1
soupsieve==2.5
-lz4==4.3.2
\ No newline at end of file
+lz4==4.3.2
+pilk
\ No newline at end of file
From 41879b2fbc15dff7022e1a62e612b2087b36cbbc Mon Sep 17 00:00:00 2001
From: STDquantum <405720329@qq.com>
Date: Tue, 12 Dec 2023 10:32:16 +0800
Subject: [PATCH 2/3] =?UTF-8?q?=E4=BF=AE=E5=A4=8Dimage=E7=BC=A9=E7=95=A5?=
=?UTF-8?q?=E5=9B=BE=E8=8E=B7=E5=8F=96=E4=B8=8D=E4=BA=86=E7=9A=84=E9=97=AE?=
=?UTF-8?q?=E9=A2=98=EF=BC=9B=E4=BF=AE=E5=A4=8D=E5=A4=A7=E7=BC=A9=E6=94=BE?=
=?UTF-8?q?=E4=B8=8Bhtml=E5=85=83=E7=B4=A0=E8=B6=85=E5=87=BA=E9=A1=B5?=
=?UTF-8?q?=E9=9D=A2=E7=9A=84=E9=97=AE=E9=A2=98?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
app/DataBase/output_pc.py | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/app/DataBase/output_pc.py b/app/DataBase/output_pc.py
index 795dbbd..ed1db8c 100644
--- a/app/DataBase/output_pc.py
+++ b/app/DataBase/output_pc.py
@@ -201,6 +201,10 @@ class ChildThread(QThread):
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 not os.path.exists(os.path.join(MePC().wx_dir, image_path)):
+ image_path = None
+ if not os.path.exists(os.path.join(MePC().wx_dir, image_thumb_path)):
+ image_thumb_path = None
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:
@@ -608,7 +612,7 @@ body{
margin-top: 5%;
}
.container{
- height: 760px;
+ height: 99%;
width: 900px;
border-radius: 4px;
border: 0.5px solid #e0e0e0;
From 0e92c5859988f68c2c6e5223dbfd542ec2a87f48 Mon Sep 17 00:00:00 2001
From: STDquantum <405720329@qq.com>
Date: Tue, 12 Dec 2023 13:46:57 +0800
Subject: [PATCH 3/3] =?UTF-8?q?=E8=BF=9B=E5=85=A5=E7=95=8C=E9=9D=A2?=
=?UTF-8?q?=E5=90=8E=E8=81=94=E7=B3=BB=E4=BA=BA=E6=8C=89=E7=85=A7=E6=9C=80?=
=?UTF-8?q?=E6=96=B0=E8=81=8A=E5=A4=A9=E6=97=B6=E9=97=B4=E6=8E=92=E5=BA=8F?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
app/DataBase/micro_msg.py | 57 ++++++++++++++++++++++++++++++++++++++-
1 file changed, 56 insertions(+), 1 deletion(-)
diff --git a/app/DataBase/micro_msg.py b/app/DataBase/micro_msg.py
index 23e7d7e..7cc2ee2 100644
--- a/app/DataBase/micro_msg.py
+++ b/app/DataBase/micro_msg.py
@@ -22,6 +22,61 @@ def singleton(cls):
def is_database_exist():
return os.path.exists(db_path)
+lockMSG = threading.Lock()
+DBMSG = None
+cursorMSG = None
+db_msg_path = "./app/Database/Msg/MSG.db"
+
+@singleton
+class MicroMSGMsg:
+ def __init__(self):
+ self.DBMSG = None
+ self.cursorMSG = None
+ self.open_flag = False
+ self.init_database()
+
+ def init_database(self):
+ if not self.open_flag:
+ if os.path.exists(db_msg_path):
+ self.DBMSG = sqlite3.connect(db_msg_path, check_same_thread=False)
+ # '''创建游标'''
+ self.cursorMSG = self.DBMSG.cursor()
+ self.open_flag = True
+ if lockMSG.locked():
+ lockMSG.release()
+
+ def get_contact(self, contacts):
+ if not self.open_flag:
+ return None
+ try:
+ lockMSG.acquire(True)
+ sql = '''select StrTalker, MAX(CreateTime) from MSG group by StrTalker'''
+ self.cursorMSG.execute(sql)
+ res = self.cursorMSG.fetchall()
+ res = {StrTalker: CreateTime for StrTalker, CreateTime in res}
+ contacts = [list(cur_contact) for cur_contact in contacts]
+ for i, cur_contact in enumerate(contacts):
+ if cur_contact[0] in res:
+ contacts[i].append(res[cur_contact[0]])
+ else:
+ contacts[i].append(0)
+ contacts.sort(key=lambda cur_contact: cur_contact[-1], reverse=True)
+ finally:
+ lockMSG.release()
+ return contacts
+
+ def close(self):
+ if self.open_flag:
+ try:
+ lockMSG.acquire(True)
+ self.open_flag = False
+ self.DBMSG.close()
+ finally:
+ lockMSG.release()
+
+ def __del__(self):
+ self.close()
+
@singleton
class MicroMsg:
@@ -61,7 +116,7 @@ class MicroMsg:
result = self.cursor.fetchall()
finally:
lock.release()
- return result
+ return MicroMSGMsg().get_contact(result)
def get_contact_by_username(self, username):
if not self.open_flag: