From e4a39135c217b00284e49390f6ae2e1ee22092f0 Mon Sep 17 00:00:00 2001 From: SiYuan <863909694@qq.com> Date: Thu, 3 Apr 2025 13:18:13 +0800 Subject: [PATCH] =?UTF-8?q?=E9=80=82=E9=85=8D=E5=BE=AE=E4=BF=A14.0.3?= =?UTF-8?q?=E6=AD=A3=E5=BC=8F=E7=89=88=EF=BC=8C=E4=BF=AE=E5=A4=8Dmedia.db?= =?UTF-8?q?=E4=B8=8D=E5=AD=98=E5=9C=A8=E7=9A=84=E9=97=AE=E9=A2=98=EF=BC=8C?= =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=9B=BE=E7=89=87=E3=80=81=E8=A7=86=E9=A2=91?= =?UTF-8?q?=E3=80=81=E6=96=87=E4=BB=B6=E8=B7=AF=E5=BE=84=E5=BC=82=E5=B8=B8?= =?UTF-8?q?=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- exporter/exporter_html.py | 2 - exporter/resources/template.html | 683 +++++++++--------- wxManager/db_v4/media.py | 26 +- wxManager/db_v4/message.py | 2 +- wxManager/decrypt/wx_info_v4.py | 5 - wxManager/manager_v3.py | 3 +- wxManager/manager_v4.py | 5 +- wxManager/model/db_model.py | 4 +- wxManager/parser/emoji_parser.py | 1 + .../protocbuf/packed_info_data_img2.proto | 25 + .../protocbuf/packed_info_data_img2_pb2.py | 18 +- .../protocbuf/packed_info_data_merged.proto | 8 +- wxManager/parser/wechat_v4.py | 78 +- 13 files changed, 471 insertions(+), 389 deletions(-) diff --git a/exporter/exporter_html.py b/exporter/exporter_html.py index a142609..fe6d3e2 100644 --- a/exporter/exporter_html.py +++ b/exporter/exporter_html.py @@ -133,7 +133,6 @@ class HtmlExporter(ExporterBase): self.update_progress_callback(index / total_steps) type_ = message.type if not self.is_selected(message): - msg_index -= 1 continue server_id = message.server_id if type_ == MessageType.Image: @@ -201,7 +200,6 @@ class HtmlExporter(ExporterBase): VideoNumberIndex.append(msg_index) elif type_ == MessageType.MergedMessages: parser_merged(message) - msg_index += 1 is_select = True html_json.append(message.to_json()) diff --git a/exporter/resources/template.html b/exporter/resources/template.html index 4964241..013321a 100644 --- a/exporter/resources/template.html +++ b/exporter/resources/template.html @@ -4242,12 +4242,12 @@ personal_card.appendChild(card_bottom); return personal_card; } - function openIMCard(message) { + function OpenIMCard(message) { const OpenIM_card = document.createElement("div"); OpenIM_card.className = "OpenIM-card"; const contner = document.createElement("div"); contner.className = "contner"; - contner.innerHTML = `headimg` + contner.innerHTML = `headimg` const contner_text = document.createElement("div"); contner_text.className = "text"; if (message.sex == '男') { @@ -4260,7 +4260,7 @@ contner_text.innerHTML = `
${message.nickname}
` } - contner_text.innerHTML += `
${message.open_im_desc}
` + contner_text.innerHTML += `
${message.open_im_desc_icon}
` contner.appendChild(contner_text); OpenIM_card.appendChild(contner); const card_bottom = document.createElement("div"); @@ -4391,6 +4391,330 @@ return messageMergeModaltitle; } + function messageMiniProgram(message) { + const message_MiniProgram = document.createElement('div'); + message_MiniProgram.className = `mini-program`; + + message_MiniProgram.innerHTML = ` +
+ logo +
${message.app_name}
+
+
${message.title}
+
+
小程序
+
`; + return message_MiniProgram; + } + + function messageVideoNumber(message) { + const message_VideoNumber = document.createElement('div'); + message_VideoNumber.className = `video-number`; + const message_VideoNumber_title = document.createElement('div'); + message_VideoNumber_title.className = `title`; + const message_VideoNumber_container = document.createElement('div'); + message_VideoNumber_container.className = `container`; + message_VideoNumber_container.style.backgroundImage = `url(${message.cover_url})`; + message_VideoNumber_container.style.backgroundSize = "cover"; + message_VideoNumber_container.style.backgroundRepeat = "no-repeat"; + message_VideoNumber_title.innerHTML = replaceEmoji(message.title); + message_VideoNumber_container.innerHTML = ` +
+
+ +
${message.publisher_nickname}
+
+
+
`; + + message_VideoNumber.appendChild(message_VideoNumber_title); + message_VideoNumber.appendChild(message_VideoNumber_container); + + return message_VideoNumber; + } + + function handleTextMessage(params) { + const { message, side, messageContent, messageElement, avatarTag, record, recordItem } = params; + + if (record) { + recordItem.innerHTML += `
${record.text}
`; + } else { + messageContent.className = `content-wrapper content-wrapper-${side}`; + messageContent.appendChild(messageBubble(message, side)); + messageElement.className = `item item-${side}`; + messageElement.appendChild(message.is_send ? messageContent : avatarTag); + messageElement.appendChild(message.is_send ? avatarTag : messageContent); + } + + } + function handleSystemMessage(params) { + const { message, messageElement } = params; + messageElement.className = "item item-center"; + messageElement.innerHTML = `${replaceEmoji(message.text.replace('\\"', '"'))}`; + } + function handelAudioMessage(params) { + const { message, side, messageContent, messageElement, avatarTag, record, recordItem } = params; + + if (record) { + recordItem.innerHTML += `
${record.text}
`; + } else { + messageContent.className = `content-wrapper content-wrapper-${side}`; + messageContent.appendChild(messageAudioBox(message)); + if (message.voice_to_text) { + messageContent.appendChild(messageVoiceToTextBubble(message, side)); + } + messageElement.className = `item item-${side}`; + messageElement.appendChild(message.is_send ? messageContent : avatarTag); + messageElement.appendChild(message.is_send ? avatarTag : messageContent); + } + } + function handleImageOrEmojiMessage(params) { + const { message, side, messageContent, messageElement, avatarTag, record, recordItem } = params; + + if (record) { + recordItem.appendChild(messageImgBox(record)); + } else { + messageContent.className = `content-wrapper content-wrapper-${side}`; + messageContent.appendChild(messageImgBox(message)); + messageElement.className = `item item-${side}`; + messageElement.appendChild(message.is_send ? messageContent : avatarTag); + messageElement.appendChild(message.is_send ? avatarTag : messageContent); + } + } + + function handleVideoMessage(params) { + const { message, side, messageContent, messageElement, avatarTag, record, recordItem } = params; + + if (record) { + recordItem.appendChild(messageVideoBox(record)); + } else { + messageContent.className = `content-wrapper content-wrapper-${side}`; + messageContent.appendChild(messageVideoBox(message)); + messageElement.className = `item item-${side}`; + messageElement.appendChild(message.is_send ? messageContent : avatarTag); + messageElement.appendChild(message.is_send ? avatarTag : messageContent); + } + } + + function handleFileMessage(params) { + const { message, side, messageContent, messageElement, avatarTag, record, recordItem } = params; + if (record) { + record.icon_path = getFileIcon(record.datafmt) + recordItem.appendChild(messageFileBox(record)); + } + else { + messageContent.className = `content-wrapper content-wrapper-${side}`; + messageContent.appendChild(messageFileBox(message)); + messageElement.className = `item item-${side}`; + messageElement.appendChild(message.is_send ? messageContent : avatarTag); + messageElement.appendChild(message.is_send ? avatarTag : messageContent); + } + } + + function handleTransferMessage(params) { + const { message, side, messageContent, messageElement, avatarTag } = params; + messageContent.className = `content-wrapper content-wrapper-${side}`; + messageContent.appendChild(messageTransfer(message)); + // 整合 + messageElement.className = `item item-${side}`; + messageElement.appendChild(message.is_send ? messageContent : avatarTag); + messageElement.appendChild(message.is_send ? avatarTag : messageContent); + } + + function handleLinkMessage(params) { + const { message, side, messageContent, messageElement, avatarTag, record, recordItem } = params; + if (record) { + recordItem.appendChild(messageCard(record)); + } + else { + messageContent.className = `content-wrapper content-wrapper-${side}`; + messageContent.appendChild(messageCard(message)); + // 整合 + messageElement.className = `item item-${side}`; + messageElement.appendChild(message.is_send ? messageContent : avatarTag); + messageElement.appendChild(message.is_send ? avatarTag : messageContent); + } + } + + function handleMusicMessage(params) { + const { message, side, messageContent, messageElement, avatarTag } = params; + messageContent.className = `content-wrapper content-wrapper-${side}`; + messageContent.appendChild(messageMusicAudioBox(message)); + // 整合 + messageElement.className = `item item-${side}`; + messageElement.appendChild(message.is_send ? messageContent : avatarTag); + messageElement.appendChild(message.is_send ? avatarTag : messageContent); + } + + function handleAppletMessage(params) { + const { message, side, messageContent, messageElement, avatarTag } = params; + messageContent.className = `content-wrapper content-wrapper-${side}`; + messageContent.appendChild(messageMiniProgram(message)); + messageElement.className = `item item-${side}`; + messageElement.appendChild(message.is_send ? messageContent : avatarTag); + messageElement.appendChild(message.is_send ? avatarTag : messageContent); + } + + function handleMergedMessages(params) { + const { message, side, messageContent, messageElement, avatarTag, mergemessageElement, record, recordItem, zindex, i, parent_server_id} = params; + if (record) { + recordItem.appendChild(innermessageMergeCard(record, zindex + 1, i, parent_server_id)); + messageContent.insertBefore(messageMergeModal(record, messageContent, zindex + 1, i, parent_server_id), messageContent.firstChild); + } + else { + messageContent.className = `content-wrapper content-wrapper-${side}`; + + messageContent.appendChild(messageMergeCard(message)); + messageContent.insertBefore(messageMergeModal(message, messageContent, 1), messageContent.firstChild); + messageElement.className = `item item-${side}`; + messageElement.appendChild(message.is_send ? messageContent : avatarTag); + messageElement.appendChild(message.is_send ? avatarTag : messageContent); + } + } + + function handleQuoteMessage(params) { + const { message, side, messageContent, messageElement, avatarTag } = params; + messageContent.className = `content-wrapper content-wrapper-${side}`; + messageContent.appendChild(messageBubble(message)); + if (message.quote_text) { + messageContent.appendChild(messageElementReferText(message, side)); + } + messageElement.className = `item item-${side}`; + messageElement.appendChild(message.is_send ? messageContent : avatarTag); + messageElement.appendChild(message.is_send ? avatarTag : messageContent); + } + + function handleWeChatVideo(params) { + const { message, side, messageContent, messageElement, avatarTag } = params; + messageContent.className = `content-wrapper content-wrapper-${side}`; + messageContent.appendChild(messageVideoNumber(message)); + messageElement.className = `item item-${side}`; + messageElement.appendChild(message.is_send ? messageContent : avatarTag); + messageElement.appendChild(message.is_send ? avatarTag : messageContent); + } + + function handleVideoAudioCall(params) { + const { message, side, messageContent, messageElement, avatarTag } = params; + messageContent.className = `content-wrapper content-wrapper-${side}`; + messageContent.appendChild(messageVideoAudioCall(message)); + messageElement.className = `item item-${side}`; + messageElement.appendChild(message.is_send ? messageContent : avatarTag); + messageElement.appendChild(message.is_send ? avatarTag : messageContent); + } + + function handlePersonalCard(params) { + const { message, side, messageContent, messageElement, avatarTag } = params; + messageContent.className = `content-wrapper content-wrapper-${side}`; + if (message.is_open_im) { + messageContent.appendChild(OpenIMCard(message)); + } + else { + messageContent.appendChild(personalCard(message)); + } + messageElement.className = `item item-${side}`; + messageElement.appendChild(message.is_send ? messageContent : avatarTag); + messageElement.appendChild(message.is_send ? avatarTag : messageContent); + } + + function handleLocationMessage(params) { + const { message, side, messageContent, messageElement, avatarTag, record, recordItem } = params; + if (record) { + recordItem.appendChild(messageLocation(record, MapID)); + } + else { + messageContent.className = `content-wrapper content-wrapper-${side}`; + messageContent.appendChild(messageLocation(message, MapID)); + messageElement.className = `item item-${side}`; + messageElement.appendChild(message.is_send ? messageContent : avatarTag); + messageElement.appendChild(message.is_send ? avatarTag : messageContent); + } + } + + function handleOpenIMCard(params) { + const { message, side, messageContent, messageElement, avatarTag } = params; + messageContent.className = `content-wrapper content-wrapper-${side}`; + messageContent.appendChild(OpenIMCard(message)); + messageElement.className = `item item-${side}`; + messageElement.appendChild(message.is_send ? messageContent : avatarTag); + messageElement.appendChild(message.is_send ? avatarTag : messageContent); + } + + function handleUnkownMessage(params) { + const { message } = params; + console.log("UnkownMessage: ", message); + } + + const messageHandlers = { + [MessageType.Text]: handleTextMessage, + [MessageType.System]: handleSystemMessage, + [MessageType.Audio]: handelAudioMessage, + [MessageType.Image]: handleImageOrEmojiMessage, + [MessageType.Emoji]: handleImageOrEmojiMessage, + [MessageType.Video]: handleVideoMessage, + [MessageType.File]: handleFileMessage, + [MessageType.Transfer]: handleTransferMessage, + [MessageType.LinkMessage]: handleLinkMessage, + [MessageType.LinkMessage2]: handleLinkMessage, + [MessageType.LinkMessage3]: handleLinkMessage, + [MessageType.LinkMessage4]: handleLinkMessage, + [MessageType.LinkMessage5]: handleLinkMessage, + [MessageType.LinkMessage6]: handleLinkMessage, + [MessageType.Music]: handleMusicMessage, + [MessageType.Applet]: handleAppletMessage, + [MessageType.Applet2]: handleAppletMessage, + [MessageType.MergedMessages]: handleMergedMessages, + [MessageType.Quote]: handleQuoteMessage, + [MessageType.WeChatVideo]: handleWeChatVideo, + [MessageType.Voip]: handleVideoAudioCall, + [MessageType.BusinessCard]: handlePersonalCard, + [MessageType.Position]: handleLocationMessage, + [MessageType.OpenIMBCard]: handleOpenIMCard, + [MessageType.Unknown]: handleUnkownMessage, + + }; + + function processMessage(params) { + const { message, record } = params; + if (message){ + const handler = messageHandlers[message.type] || handleUnkownMessage; + if (handler && is_valid_data(message.server_id, message.token)) { + handler(params); // 将参数对象传递给处理函数 + } else { + console.log("Unsupported message type or invalid data"); + console.log("message",message); + } + } + else { + const handler = messageHandlers[record.type] || handleUnkownMessage; + if (handler) { + handler(params); // 将参数对象传递给处理函数 + } else { + console.log("Unsupported message type or invalid data"); + console.log("record",record); + } + } + + } + + function getFileIcon(datafmt) { + icon_files = { + 'DOCX': ['doc', 'docx'], + 'XLS': ['xls', 'xlsx'], + 'CSV': ['csv'], + 'TXT': ['txt'], + 'ZIP': ['zip', '7z', 'rar'], + 'PPT': ['ppt', 'pptx'], + 'PDF': ['pdf'], + } + + for (var key in icon_files) { + if (icon_files[key].includes(datafmt)) { + return key + } + } + return 'Default' + } + function messageMergeModal(message, messageContent, zindex, index=0, parent_server_id=0) { var message_MergeModal = document.createElement('div'); message_MergeModal.className = `merge-msg-modal`; @@ -4399,11 +4723,6 @@ parent_server_id = message.server_id; } message_MergeModal.id = `${parent_server_id}-${zindex}-${index}Modal`; - // if (message.server_id) { - // message_MergeModal.id = `${message.server_id}-${zindex}-${index}Modal`; - // } else { - // message_MergeModal.id = `${message.dataid}Modal`; - // } var ModalContent = document.createElement('div'); ModalContent.className = `merge-msg-modal-content`; @@ -4460,48 +4779,11 @@ } const recordItem = document.createElement('div'); recordItem.className = `msg-block`; - // console.log("type:",record.type); - if (record.type == MessageType.Text || record.type == MessageType.Audio) { - // console.log(record.datadesc) - // 文本消息 - recordItem.innerHTML = `
${record.display_name} - ${timestampToTime(record.timestamp)}
-
${record.text}
`; - } else if (record.type == MessageType.MergedMessages) { - // 嵌套合并消息 - recordItem.innerHTML = `
${record.display_name} + recordItem.innerHTML = `
${record.display_name} ${timestampToTime(record.timestamp)}
`; - recordItem.appendChild(innermessageMergeCard(record, zindex + 1, i, parent_server_id)); - // messageContent.appendChild(messageMergeModal(record, messageContent)); - messageContent.insertBefore(messageMergeModal(record, messageContent, zindex + 1, i, parent_server_id), messageContent.firstChild); - } else if (record.type == MessageType.Video) { - // 视频消息 - recordItem.innerHTML = `
${record.display_name} - ${timestampToTime(record.timestamp)}
-
`; - } else if (record.type == MessageType.Image || record.type == MessageType.Emoji) { - // 文件消息 - recordItem.innerHTML = `
${record.display_name} - ${timestampToTime(record.timestamp)}
`; - recordItem.appendChild(messageImgBox(record)); - } else if (record.type == MessageType.File) { - // 文件消息 - record.icon_path = getFileIcon(record.datafmt) - recordItem.innerHTML = `
${record.display_name} - ${timestampToTime(record.timestamp)}
`; - recordItem.appendChild(messageFileBox(record)); - } else if (record.type == MessageType.Position) { - // 文件消息 - recordItem.innerHTML = `
${record.display_name} - ${timestampToTime(record.timestamp)}
`; - recordItem.appendChild(messageLocation(record, newMapID)); - } else if (record.type == MessageType.LinkMessage) { - // 文件消息 - recordItem.innerHTML = `
${record.display_name} - ${timestampToTime(record.timestamp)}
`; - recordItem.appendChild(messageCard(record)); - } + const record_params = {record, recordItem, messageContent, zindex, i, parent_server_id}; + processMessage(record_params); OnePersonMsgRight.appendChild(recordItem); } @@ -4510,70 +4792,10 @@ ModalContent.appendChild(ModalContainer); message_MergeModal.appendChild(ModalContent); - function getFileIcon(datafmt) { - icon_files = { - 'DOCX': ['doc', 'docx'], - 'XLS': ['xls', 'xlsx'], - 'CSV': ['csv'], - 'TXT': ['txt'], - 'ZIP': ['zip', '7z', 'rar'], - 'PPT': ['ppt', 'pptx'], - 'PDF': ['pdf'], - } - - for (var key in icon_files) { - if (icon_files[key].includes(datafmt)) { - return key - } - } - return 'Default' - } - return message_MergeModal; } - function messageMiniProgram(message) { - const message_MiniProgram = document.createElement('div'); - message_MiniProgram.className = `mini-program`; - - message_MiniProgram.innerHTML = ` -
- logo -
${message.app_name}
-
-
${message.title}
-
-
小程序
-
`; - return message_MiniProgram; - } - - function messageVideoNumber(message) { - const message_VideoNumber = document.createElement('div'); - message_VideoNumber.className = `video-number`; - const message_VideoNumber_title = document.createElement('div'); - message_VideoNumber_title.className = `title`; - const message_VideoNumber_container = document.createElement('div'); - message_VideoNumber_container.className = `container`; - message_VideoNumber_container.style.backgroundImage = `url(${message.cover_url})`; - message_VideoNumber_container.style.backgroundSize = "cover"; - message_VideoNumber_container.style.backgroundRepeat = "no-repeat"; - message_VideoNumber_title.innerHTML = replaceEmoji(message.title); - message_VideoNumber_container.innerHTML = ` -
-
- -
${message.publisher_nickname}
-
-
-
`; - - message_VideoNumber.appendChild(message_VideoNumber_title); - message_VideoNumber.appendChild(message_VideoNumber_container); - - return message_VideoNumber; - } // 从数据列表中取出对应范围的元素并添加到容器中 for (let i = startIndex; i < endIndex && i < ChatMsgIndex.length; i++) { @@ -4589,242 +4811,15 @@ if (isChatroom && !message.is_send) { messageContent.appendChild(displayNameBox(message)); } - if (message.type == MessageType.Text && is_valid_data(message.server_id, message.token)) { - // displayname 和 bubble - messageContent.className = `content-wrapper content-wrapper-${side}`; - messageContent.appendChild(messageBubble(message, side)); - // 整合 - messageElement.className = `item item-${side}`; - messageElement.appendChild(message.is_send ? messageContent : avatarTag); - messageElement.appendChild(message.is_send ? avatarTag : messageContent); - } else if (message.type == MessageType.System) { - messageElement.className = "item item-center"; - messageElement.innerHTML = `${replaceEmoji(message.text.replace('\\"', '"'))}`; - } else if ((message.type == MessageType.Image || message.type == MessageType.Emoji)&& is_valid_data(message.server_id, message.token)) { - // displayname 和 img - messageContent.className = `content-wrapper content-wrapper-${side}`; - - messageContent.appendChild(messageImgBox(message)); - - // 整合 - messageElement.className = `item item-${side}`; - messageElement.appendChild(message.is_send ? messageContent : avatarTag); - messageElement.appendChild(message.is_send ? avatarTag : messageContent); - } else if (message.type == MessageType.Video && is_valid_data(message.server_id, message.token)) { - // displayname 和 video - messageContent.className = `content-wrapper content-wrapper-${side}`; - - messageContent.appendChild(messageVideoBox(message)); - - // 整合 - messageElement.className = `item item-${side}`; - messageElement.appendChild(message.is_send ? messageContent : avatarTag); - messageElement.appendChild(message.is_send ? avatarTag : messageContent); - } else if (message.type == MessageType.File) { - console.log('file'); - // displayname 和 file - messageContent.className = `content-wrapper content-wrapper-${side}`; - messageContent.appendChild(messageFileBox(message)); - // 整合 - messageElement.className = `item item-${side}`; - messageElement.appendChild(message.is_send ? messageContent : avatarTag); - messageElement.appendChild(message.is_send ? avatarTag : messageContent); - } else if (message.type == MessageType.Transfer) { - console.log('Transfer'); - // displayname 和 file - messageContent.className = `content-wrapper content-wrapper-${side}`; - if (message.is_chatroom && !message.is_send) { - messageContent.appendChild(displayNameBox(message)); - } - messageContent.appendChild(messageTransfer(message)); - // 整合 - messageElement.className = `item item-${side}`; - messageElement.appendChild(message.is_send ? messageContent : avatarTag); - messageElement.appendChild(message.is_send ? avatarTag : messageContent); - } else if (message.type == MessageType.LinkMessage) { - console.log('LinkMessage'); - // displayname 和 file - messageContent.className = `content-wrapper content-wrapper-${side}`; - if (message.is_chatroom && !message.is_send) { - messageContent.appendChild(displayNameBox(message)); - } - messageContent.appendChild(messageCard(message)); - // 整合 - messageElement.className = `item item-${side}`; - messageElement.appendChild(message.is_send ? messageContent : avatarTag); - messageElement.appendChild(message.is_send ? avatarTag : messageContent); - } else if (message.type == MessageType.Music) { - console.log('LinkMessage'); - // displayname 和 file - messageContent.className = `content-wrapper content-wrapper-${side}`; - if (message.is_chatroom && !message.is_send) { - messageContent.appendChild(displayNameBox(message)); - } - messageContent.appendChild(messageMusicAudioBox(message)); - // 整合 - messageElement.className = `item item-${side}`; - messageElement.appendChild(message.is_send ? messageContent : avatarTag); - messageElement.appendChild(message.is_send ? avatarTag : messageContent); - } else if (message.type == MessageType.Applet) { - console.log('LinkMessage'); - // displayname 和 file - messageContent.className = `content-wrapper content-wrapper-${side}`; - if (message.is_chatroom && !message.is_send) { - messageContent.appendChild(displayNameBox(message)); - } - messageContent.appendChild(messageMiniProgram(message)); - // 整合 - messageElement.className = `item item-${side}`; - messageElement.appendChild(message.is_send ? messageContent : avatarTag); - messageElement.appendChild(message.is_send ? avatarTag : messageContent); - } else if (message.type == MessageType.MergedMessages) { - console.log('MergedMessages'); - // displayname 和 file - messageContent.className = `content-wrapper content-wrapper-${side}`; - if (message.is_chatroom && !message.is_send) { - messageContent.appendChild(displayNameBox(message)); - } - messageContent.appendChild(messageMergeCard(message)); - // messageContent.appendChild(messageMergeModal(message, messageContent)); - messageContent.insertBefore(messageMergeModal(message, messageContent, 1), messageContent.firstChild); - // 整合 - messageElement.className = `item item-${side}`; - messageElement.appendChild(message.is_send ? messageContent : avatarTag); - messageElement.appendChild(message.is_send ? avatarTag : messageContent); - } else if (message.type == MessageType.Quote) { - console.log('Quote'); - // displayname 和 file - messageContent.className = `content-wrapper content-wrapper-${side}`; - if (message.is_chatroom && !message.is_send) { - messageContent.appendChild(displayNameBox(message)); - } - messageContent.appendChild(messageBubble(message, side)); - if (message.quote_text) { - messageContent.appendChild(messageElementReferText(message, side)); - } - // 整合 - messageElement.className = `item item-${side}`; - messageElement.appendChild(message.is_send ? messageContent : avatarTag); - messageElement.appendChild(message.is_send ? avatarTag : messageContent); - } else if (message.type == MessageType.WeChatVideo) { - console.log('WeChatVideo'); - // displayname 和 file - messageContent.className = `content-wrapper content-wrapper-${side}`; - if (message.is_chatroom && !message.is_send) { - messageContent.appendChild(displayNameBox(message)); - } - messageContent.appendChild(messageVideoNumber(message)); - // 整合 - messageElement.className = `item item-${side}`; - messageElement.appendChild(message.is_send ? messageContent : avatarTag); - messageElement.appendChild(message.is_send ? avatarTag : messageContent); - } else if (message.type == 49 && is_valid_data(message.server_id, message.token)) { - if (message.sub_type == 57) { - // displayname 和 bubble 和 refer - messageContent.className = `content-wrapper content-wrapper-${side}`; - if (message.is_chatroom && !message.is_send) { - messageContent.appendChild(displayNameBox(message)); - } - messageContent.appendChild(messageBubble(message, side)); - if (message.refer_text) { - messageContent.appendChild(messageElementReferText(message, side)); - } - - } else if (message.sub_type == 3 || message.sub_type == 76) { - // music share - messageContent.className = `content-wrapper content-wrapper-${side}`; - if (message.is_chatroom && !message.is_send) { - messageContent.appendChild(displayNameBox(message)); - } - messageContent.appendChild(messageMusicAudioBox(message)); - } else if (message.sub_type == 5) { - // displayname 和 card - messageContent.className = `content-wrapper content-wrapper-${side}`; - if (message.is_chatroom && !message.is_send) { - messageContent.appendChild(displayNameBox(message)); - } - messageContent.appendChild(messageCard(message)); - } else if (message.sub_type == 2000) { - // displayname 和 messageTransfer - messageContent.className = `content-wrapper content-wrapper-${side}`; - if (message.is_chatroom && !message.is_send) { - messageContent.appendChild(displayNameBox(message)); - } - messageContent.appendChild(messageTransfer(message)); - } else if (message.sub_type == 19) { - // displayname 和 messageMergeCard - messageContent.className = `content-wrapper content-wrapper-${side}`; - if (message.is_chatroom && !message.is_send) { - messageContent.appendChild(displayNameBox(message)); - } - messageContent.appendChild(messageMergeCard(message)); - // messageContent.appendChild(messageMergeModal(message, messageContent)); - messageContent.insertBefore(messageMergeModal(message, messageContent, 1), messageContent.firstChild); - - } else if (message.sub_type == 33 || message.sub_type == 36) { - // 小程序 - messageContent.className = `content-wrapper content-wrapper-${side}`; - if (message.is_chatroom && !message.is_send) { - messageContent.appendChild(displayNameBox(message)); - } - messageContent.appendChild(messageMiniProgram(message)); - } else if (message.sub_type == 51) { - // 视频号 - messageContent.className = `content-wrapper content-wrapper-${side}`; - if (message.is_chatroom && !message.is_send) { - messageContent.appendChild(displayNameBox(message)); - } - messageContent.appendChild(messageVideoNumber(message)); - } - // 整合 - messageElement.className = `item item-${side}`; - messageElement.appendChild(message.is_send ? messageContent : avatarTag); - messageElement.appendChild(message.is_send ? avatarTag : messageContent); - } else if (message.type == 34 && is_valid_data(message.server_id, message.token)) { - // displayname 和 转的文字 和 audio - messageContent.className = `content-wrapper content-wrapper-${side}`; - - messageContent.appendChild(messageAudioBox(message)); - if (message.voice_to_text) { - messageContent.appendChild(messageVoiceToTextBubble(message, side)); - } - - // 整合 - messageElement.className = `item item-${side}`; - messageElement.appendChild(message.is_send ? messageContent : avatarTag); - messageElement.appendChild(message.is_send ? avatarTag : messageContent); - } else if (message.type == MessageType.Voip && is_valid_data(message.server_id, message.token)) { - // displayname 和 转的文字 和 audio - messageContent.className = `content-wrapper content-wrapper-${side}`; - - messageContent.appendChild(messageVideoAudioCall(message, side)); - - // 整合 - messageElement.className = `item item-${side}`; - messageElement.appendChild(message.is_send ? messageContent : avatarTag); - messageElement.appendChild(message.is_send ? avatarTag : messageContent); - } else if (message.type == MessageType.BusinessCard) { - // 个人名片 - messageContent.className = `content-wrapper content-wrapper-${side}`; - - messageContent.appendChild(MessageType.is_open_im?openIMCard(message):personalCard(message)); - - // 整合 - messageElement.className = `item item-${side}`; - messageElement.appendChild(message.is_send ? messageContent : avatarTag); - messageElement.appendChild(message.is_send ? avatarTag : messageContent); - } else if (message.type == 48 && is_valid_data(message.server_id, message.token)) { - // 定位 - messageContent.className = `content-wrapper content-wrapper-${side}`; - - messageContent.appendChild(messageLocation(message, newMapID)); - - // 整合 - messageElement.className = `item item-${side}`; - messageElement.appendChild(message.is_send ? messageContent : avatarTag); - messageElement.appendChild(message.is_send ? avatarTag : messageContent); - } + const params = { + message, // 消息对象 + side, // 消息显示位置(左/右) + messageContent, // 消息内容容器 + messageElement, // 消息元素 + avatarTag, // 头像标签 + }; + processMessage(params); OnePageMessage.appendChild(messageElement); } @@ -4949,7 +4944,7 @@ var lastTimeStamp = 0; // search init - + var idx = lunr(function () { this.use(lunr.zh); this.ref('server_id') diff --git a/wxManager/db_v4/media.py b/wxManager/db_v4/media.py index bb93ca4..ebd46ae 100644 --- a/wxManager/db_v4/media.py +++ b/wxManager/db_v4/media.py @@ -9,6 +9,7 @@ @Description : """ import os +import shutil import subprocess import sys import traceback @@ -35,6 +36,8 @@ class MediaDB(DataBaseBase): from VoiceInfo where svr_id = ? ''' + if not self.DB: + return b'' for db in self.DB: cursor = db.cursor() cursor.execute(sql, [server_id]) @@ -100,16 +103,19 @@ class MediaDB(DataBaseBase): if not (os.path.exists(db_path) or os.path.isfile(db_path)): print(f'{db_path} 不存在') return - for db in self.DB: - cursor = db.cursor() - try: - # 获取列名 - increase_data(db_path, cursor, db, 'VoiceInfo', 'svr_id') - increase_data(db_path, cursor, db, 'Name2Id', 'user_name') - increase_update_data(db_path, cursor, db, 'Timestamp', 'timestamp') - except: - print(f"数据库操作错误: {traceback.format_exc()}") - db.rollback() + if not self.DB: + shutil.copy(db_path,os.path.join(self.db_dir,self.db_file_name)) + else: + for db in self.DB: + cursor = db.cursor() + try: + # 获取列名 + increase_data(db_path, cursor, db, 'VoiceInfo', 'svr_id') + increase_data(db_path, cursor, db, 'Name2Id', 'user_name') + increase_update_data(db_path, cursor, db, 'Timestamp', 'timestamp') + except: + print(f"数据库操作错误: {traceback.format_exc()}") + db.rollback() if __name__ == '__main__': diff --git a/wxManager/db_v4/message.py b/wxManager/db_v4/message.py index d1068ff..633ed2d 100644 --- a/wxManager/db_v4/message.py +++ b/wxManager/db_v4/message.py @@ -309,7 +309,7 @@ order by sort_seq task_(db_path, cursor, db) tasks.append([db_path, cursor, db]) else: - shutil.copy(db_path, os.path.join(self.db_dir, 'Multi', file_name)) + shutil.copy(db_path, os.path.join(self.db_dir, 'message', file_name)) # print(tasks) # 使用线程池 (没有加快合并速度) # with ThreadPoolExecutor(max_workers=len(tasks)) as executor: diff --git a/wxManager/decrypt/wx_info_v4.py b/wxManager/decrypt/wx_info_v4.py index 0a0cc0c..2b9a29c 100644 --- a/wxManager/decrypt/wx_info_v4.py +++ b/wxManager/decrypt/wx_info_v4.py @@ -430,11 +430,6 @@ def get_nickname(pid): for string in match.strings: instance = string.instances[0] offset, content = instance.offset, instance.matched_data - # print( - # f"匹配字符串: {identifier} 内容: 偏移: {offset} 在地址: {hex(base_address + offset + 0x10)}") - # print(string) - with open('a.bin','wb') as f: - f.write(target_data) phone_addr = offset + 0x10 phone = read_string(target_data, phone_addr, 11) diff --git a/wxManager/manager_v3.py b/wxManager/manager_v3.py index 5c4b04a..2d36c7c 100644 --- a/wxManager/manager_v3.py +++ b/wxManager/manager_v3.py @@ -210,7 +210,8 @@ class DataBaseV3(DataBaseInterface): flag &= self.open_media_db.init_database(db_dir) flag &= self.open_msg_db.init_database(db_dir) flag &= self.audio2text_db.init_database(db_dir) - self.audio2text_db.create() # 初始化数据转文字数据库 + if flag: + self.audio2text_db.create() # 初始化语音转文字数据库 return flag # self.sns_db.init_database(db_dir) diff --git a/wxManager/manager_v4.py b/wxManager/manager_v4.py index 8aa5214..fed53eb 100644 --- a/wxManager/manager_v4.py +++ b/wxManager/manager_v4.py @@ -96,11 +96,12 @@ class DataBaseV4(DataBaseInterface): flag &= self.session_db.init_database(db_dir) flag &= self.message_db.init_database(db_dir) flag &= self.biz_message_db.init_database(db_dir) - flag &= self.media_db.init_database(db_dir) + self.media_db.init_database(db_dir) flag &= self.hardlink_db.init_database(db_dir) flag &= self.emotion_db.init_database(db_dir) flag &= self.audio2text_db.init_database(db_dir) - self.audio2text_db.create() # 初始化数据转文字数据库 + if flag: + self.audio2text_db.create() # 初始化语音转文字数据库 return flag def close(self): diff --git a/wxManager/model/db_model.py b/wxManager/model/db_model.py index 986b206..4d00d98 100644 --- a/wxManager/model/db_model.py +++ b/wxManager/model/db_model.py @@ -24,12 +24,14 @@ class DataBaseBase: def init_database(self, db_dir=''): self.db_dir = db_dir + if not os.path.exists(db_dir): + return False db_path = os.path.join(db_dir, self.db_file_name) if not os.path.exists(db_path) and self.db_file_name != 'Audio2Text.db': return False db_file_name = self.db_file_name - self.db_file_name = [] if self.is_series: + self.db_file_name = [] self.DB = [] self.cursor = [] for i in range(100): diff --git a/wxManager/parser/emoji_parser.py b/wxManager/parser/emoji_parser.py index a9af038..ff04bed 100644 --- a/wxManager/parser/emoji_parser.py +++ b/wxManager/parser/emoji_parser.py @@ -57,6 +57,7 @@ def parser_emoji(xml_content): } except: logger.error(traceback.format_exc()) + logger.error(xml_content) finally: return result diff --git a/wxManager/parser/util/protocbuf/packed_info_data_img2.proto b/wxManager/parser/util/protocbuf/packed_info_data_img2.proto index 4fd3a1c..e288c54 100644 --- a/wxManager/parser/util/protocbuf/packed_info_data_img2.proto +++ b/wxManager/parser/util/protocbuf/packed_info_data_img2.proto @@ -4,10 +4,35 @@ message PackedInfoDataImg2 { int32 field1 = 1; int32 field2 = 2; ImageInfo imageInfo = 3; + VideoInfo videoInfo = 4; + FileInfo fileInfo = 7; } message ImageInfo { int32 height = 1; int32 width = 2; string filename = 4; +} + +message VideoInfo { + int32 height = 4; + int32 width = 5; + string filename = 8; +} + +message FileInfo { + FileSubMessage1 fileInfo = 1; + FileSubMessage2 field2 = 2; + string field3 = 3; +} + +message FileSubMessage1 { + int32 field1 = 1; + string filename = 2; +} + +message FileSubMessage2 { + string field1 = 1; + string field2 = 2; + string field3 = 3; } \ No newline at end of file diff --git a/wxManager/parser/util/protocbuf/packed_info_data_img2_pb2.py b/wxManager/parser/util/protocbuf/packed_info_data_img2_pb2.py index ea163dc..301f5db 100644 --- a/wxManager/parser/util/protocbuf/packed_info_data_img2_pb2.py +++ b/wxManager/parser/util/protocbuf/packed_info_data_img2_pb2.py @@ -13,15 +13,23 @@ _sym_db = _symbol_database.Default() -DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1bpacked_info_data_img2.proto\"S\n\x12PackedInfoDataImg2\x12\x0e\n\x06\x66ield1\x18\x01 \x01(\x05\x12\x0e\n\x06\x66ield2\x18\x02 \x01(\x05\x12\x1d\n\timageInfo\x18\x03 \x01(\x0b\x32\n.ImageInfo\"<\n\tImageInfo\x12\x0e\n\x06height\x18\x01 \x01(\x05\x12\r\n\x05width\x18\x02 \x01(\x05\x12\x10\n\x08\x66ilename\x18\x04 \x01(\tb\x06proto3') +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1bpacked_info_data_img2.proto\"\x8f\x01\n\x12PackedInfoDataImg2\x12\x0e\n\x06\x66ield1\x18\x01 \x01(\x05\x12\x0e\n\x06\x66ield2\x18\x02 \x01(\x05\x12\x1d\n\timageInfo\x18\x03 \x01(\x0b\x32\n.ImageInfo\x12\x1d\n\tvideoInfo\x18\x04 \x01(\x0b\x32\n.VideoInfo\x12\x1b\n\x08\x66ileInfo\x18\x07 \x01(\x0b\x32\t.FileInfo\"<\n\tImageInfo\x12\x0e\n\x06height\x18\x01 \x01(\x05\x12\r\n\x05width\x18\x02 \x01(\x05\x12\x10\n\x08\x66ilename\x18\x04 \x01(\t\"<\n\tVideoInfo\x12\x0e\n\x06height\x18\x04 \x01(\x05\x12\r\n\x05width\x18\x05 \x01(\x05\x12\x10\n\x08\x66ilename\x18\x08 \x01(\t\"`\n\x08\x46ileInfo\x12\"\n\x08\x66ileInfo\x18\x01 \x01(\x0b\x32\x10.FileSubMessage1\x12 \n\x06\x66ield2\x18\x02 \x01(\x0b\x32\x10.FileSubMessage2\x12\x0e\n\x06\x66ield3\x18\x03 \x01(\t\"3\n\x0f\x46ileSubMessage1\x12\x0e\n\x06\x66ield1\x18\x01 \x01(\x05\x12\x10\n\x08\x66ilename\x18\x02 \x01(\t\"A\n\x0f\x46ileSubMessage2\x12\x0e\n\x06\x66ield1\x18\x01 \x01(\t\x12\x0e\n\x06\x66ield2\x18\x02 \x01(\t\x12\x0e\n\x06\x66ield3\x18\x03 \x01(\tb\x06proto3') _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals()) _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'packed_info_data_img2_pb2', globals()) if _descriptor._USE_C_DESCRIPTORS == False: DESCRIPTOR._options = None - _PACKEDINFODATAIMG2._serialized_start=31 - _PACKEDINFODATAIMG2._serialized_end=114 - _IMAGEINFO._serialized_start=116 - _IMAGEINFO._serialized_end=176 + _PACKEDINFODATAIMG2._serialized_start=32 + _PACKEDINFODATAIMG2._serialized_end=175 + _IMAGEINFO._serialized_start=177 + _IMAGEINFO._serialized_end=237 + _VIDEOINFO._serialized_start=239 + _VIDEOINFO._serialized_end=299 + _FILEINFO._serialized_start=301 + _FILEINFO._serialized_end=397 + _FILESUBMESSAGE1._serialized_start=399 + _FILESUBMESSAGE1._serialized_end=450 + _FILESUBMESSAGE2._serialized_start=452 + _FILESUBMESSAGE2._serialized_end=517 # @@protoc_insertion_point(module_scope) diff --git a/wxManager/parser/util/protocbuf/packed_info_data_merged.proto b/wxManager/parser/util/protocbuf/packed_info_data_merged.proto index 506ec59..18f4a17 100644 --- a/wxManager/parser/util/protocbuf/packed_info_data_merged.proto +++ b/wxManager/parser/util/protocbuf/packed_info_data_merged.proto @@ -3,19 +3,19 @@ syntax = "proto3"; message PackedInfoData { int32 field1 = 1; int32 field2 = 2; - NestedMessage field7 = 7; + FileInfo fileInfo = 7; AnotherNestedMessage info = 9; } -message NestedMessage { - SubMessage1 field1 = 1; +message FileInfo { + SubMessage1 fileInfo = 1; SubMessage2 field2 = 2; string field3 = 3; } message SubMessage1 { int32 field1 = 1; - string field2 = 2; + string filename = 2; } message SubMessage2 { diff --git a/wxManager/parser/wechat_v4.py b/wxManager/parser/wechat_v4.py index 6cb68c2..99bb42e 100644 --- a/wxManager/parser/wechat_v4.py +++ b/wxManager/parser/wechat_v4.py @@ -42,9 +42,12 @@ source,message_content,compress_content" def decompress(data): - dctx = zstd.ZstdDecompressor() # 创建解压对象 - x = dctx.decompress(data).strip(b'\x00').strip() - return x.decode('utf-8').strip() + try: + dctx = zstd.ZstdDecompressor() # 创建解压对象 + x = dctx.decompress(data).strip(b'\x00').strip() + return x.decode('utf-8').strip() + except: + return '' class LimitedDict: @@ -255,8 +258,8 @@ class ImageMessageFactory(MessageFactory, Singleton): # 转换为 JSON 格式 packed_info_data = MessageToDict(packed_info_data_proto) image_info = packed_info_data.get('imageInfo', {}) - width = image_info.get('width',0) - height = image_info.get('height',0) + width = image_info.get('width', 0) + height = image_info.get('height', 0) filename = image_info.get('filename', '').strip().strip('"').strip() except: pass @@ -344,6 +347,19 @@ class AudioMessageFactory(MessageFactory, Singleton): class VideoMessageFactory(MessageFactory, Singleton): def create(self, message, username, manager): is_sender, wxid, message_content = self.common_attribute(message, username, manager) + filename = '' + try: + # 2025年3月微信4.0.3正式版修改了img命名方式才有了这个东西 + packed_info_data_proto = packed_info_data_img2_pb2.PackedInfoDataImg2() + packed_info_data_proto.ParseFromString(message[14]) + # 转换为 JSON 格式 + packed_info_data = MessageToDict(packed_info_data_proto) + image_info = packed_info_data.get('videoInfo', {}) + width = image_info.get('width', 0) + height = image_info.get('height', 0) + filename = image_info.get('filename', '').strip().strip('"').strip() + except: + pass msg = VideoMessage( local_id=message[0], server_id=message[1], @@ -361,7 +377,7 @@ class VideoMessageFactory(MessageFactory, Singleton): md5='', path='', file_size=0, - file_name='', + file_name=filename, file_type='mp4', thumb_path='', duration=0, @@ -372,12 +388,25 @@ class VideoMessageFactory(MessageFactory, Singleton): msg.file_size = video_dic.get('size', 0) msg.md5 = video_dic.get('md5', '') msg.raw_md5 = video_dic.get('rawmd5', '') - msg.path = manager.hardlink_db.get_video(msg.raw_md5, False) - msg.thumb_path = manager.hardlink_db.get_video(msg.raw_md5, True) - if not msg.path: - msg.path = manager.hardlink_db.get_video(msg.md5, False) - msg.thumb_path = manager.hardlink_db.get_video(msg.md5, True) - # logger.error(f'{msg.path} {msg.thumb_path}') + month = msg.str_time[:7] # 2025-01 + if filename: + # 微信4.0.3正式版增加 + video_dir = os.path.join('msg', 'video', month) + video_path = os.path.join(video_dir, f'{filename}_raw.mp4') + if os.path.exists(os.path.join(Me().wx_dir, video_path)): + msg.path = video_path + msg.thumb_path = os.path.join(video_dir, f'{filename}.jpg') + else: + msg.path = os.path.join(video_dir, f'{filename}.mp4') + msg.thumb_path = os.path.join(video_dir, f'{filename}.jpg') + else: + msg.path = manager.hardlink_db.get_video(msg.raw_md5, False) + msg.thumb_path = manager.hardlink_db.get_video(msg.raw_md5, True) + if not msg.path: + msg.path = manager.hardlink_db.get_video(msg.md5, False) + msg.thumb_path = manager.hardlink_db.get_video(msg.md5, True) + # logger.error(f'{msg.path} {msg.thumb_path}') + self.add_message(msg) return msg @@ -847,7 +876,19 @@ class FileMessageFactory(MessageFactory, Singleton): is_sender, wxid, message_content = self.common_attribute(message, username, manager) info = parser_file(message_content) md5 = info.get('md5', '') - file_path = manager.get_file(md5) + filename = info.get('filename','') + if not filename: + try: + # 2025年3月微信4.0.3正式版修改了img命名方式才有了这个东西 + packed_info_data_proto = packed_info_data_img2_pb2.PackedInfoDataImg2() + packed_info_data_proto.ParseFromString(message[14]) + # 转换为 JSON 格式 + packed_info_data = MessageToDict(packed_info_data_proto) + image_info = packed_info_data.get('fileInfo', {}) + file_info = image_info.get('fileInfo', {}) + filename = file_info.get('filename', '').strip() + except: + pass msg = FileMessage( local_id=message[0], server_id=message[1], @@ -862,12 +903,21 @@ class FileMessageFactory(MessageFactory, Singleton): avatar_src=self.contacts[wxid].small_head_img_url, status=message[7], xml_content=message_content, - path=file_path, + path='', md5=md5, file_type=info.get('file_type', ''), file_name=info.get('file_name', ''), file_size=info.get('file_size', 0) ) + # file_path = manager.get_file(md5) + if filename: + month = msg.str_time[:7] # 2025-01 + # 微信4.0.3正式版增加 + video_dir = os.path.join('msg', 'file', month) + file_path = os.path.join(video_dir, f'{filename}') + msg.path = file_path + else: + msg.path = manager.get_file(md5) self.add_message(msg) return msg