适配微信4.0.3正式版,修复media.db不存在的问题,修复图片、视频、文件路径异常的问题

This commit is contained in:
SiYuan 2025-04-03 13:18:13 +08:00
parent 6dde500e07
commit e4a39135c2
13 changed files with 471 additions and 389 deletions

View File

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

View File

@ -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 = `<img src="${message.smallheadimgurl}" alt="headimg">`
contner.innerHTML = `<img src="${message.small_head_url}" alt="headimg">`
const contner_text = document.createElement("div");
contner_text.className = "text";
if (message.sex == '男') {
@ -4260,7 +4260,7 @@
contner_text.innerHTML = `<div class="nickname">
${message.nickname}</div>`
}
contner_text.innerHTML += `<div class="desc"><img src="${message.open_im_desc_icon}">${message.open_im_desc}</div>`
contner_text.innerHTML += `<div class="desc"><img src="${message.open_im_desc_icon}">${message.open_im_desc_icon}</div>`
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 = `<a href="${message.url}" target="_blank">
<div class="top">
<img src='${message.app_logo}' alt='logo'>
<div class='text'>${message.app_name}</div>
</div>
<div class="title">${message.title}</div>
<div class="cover"><img src='${message.cover_url}' onerror="this.style.display='none';"></div>
<div class="bottom"><div class="text">小程序</div></div>
</a>`;
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 = `
<div class="bottom">
<div class="author">
<div class="logo"><img src='${message.publisher_avatar}' onerror="this.style.display='none';"></div>
<div class="name">${message.publisher_nickname}</div>
<div class="authIcon"><img src='${message.authIconUrl}' onerror="this.style.display='none';"></div>
</div>
</div>`;
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 += `<div class="msg-container">${record.text}</div>`;
} 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 = `<span class="system-msg">${replaceEmoji(message.text.replace('\\"', '"'))}</span>`;
}
function handelAudioMessage(params) {
const { message, side, messageContent, messageElement, avatarTag, record, recordItem } = params;
if (record) {
recordItem.innerHTML += `<div class="msg-container">${record.text}</div>`;
} 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 = `<div class="msg-container-top"><span>${record.display_name}</span>
<span style="font-size: 12px;">${timestampToTime(record.timestamp)}</span></div>
<div class="msg-container">${record.text}</div>`;
} else if (record.type == MessageType.MergedMessages) {
// 嵌套合并消息
recordItem.innerHTML = `<div class="msg-container-top"><span>${record.display_name}</span>
recordItem.innerHTML = `<div class="msg-container-top"><span>${record.display_name}</span>
<span style="font-size: 12px;">${timestampToTime(record.timestamp)}</span></div>`;
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 = `<div class="msg-container-top"><span>${record.display_name}</span>
<span style="font-size: 12px;">${timestampToTime(record.timestamp)}</span></div>
<div class="msg-container"><video src="${record.path}" controls=""></video></div>`;
} else if (record.type == MessageType.Image || record.type == MessageType.Emoji) {
// 文件消息
recordItem.innerHTML = `<div class="msg-container-top"><span>${record.display_name}</span>
<span style="font-size: 12px;">${timestampToTime(record.timestamp)}</span></div>`;
recordItem.appendChild(messageImgBox(record));
} else if (record.type == MessageType.File) {
// 文件消息
record.icon_path = getFileIcon(record.datafmt)
recordItem.innerHTML = `<div class="msg-container-top"><span>${record.display_name}</span>
<span style="font-size: 12px;">${timestampToTime(record.timestamp)}</span></div>`;
recordItem.appendChild(messageFileBox(record));
} else if (record.type == MessageType.Position) {
// 文件消息
recordItem.innerHTML = `<div class="msg-container-top"><span>${record.display_name}</span>
<span style="font-size: 12px;">${timestampToTime(record.timestamp)}</span></div>`;
recordItem.appendChild(messageLocation(record, newMapID));
} else if (record.type == MessageType.LinkMessage) {
// 文件消息
recordItem.innerHTML = `<div class="msg-container-top"><span>${record.display_name}</span>
<span style="font-size: 12px;">${timestampToTime(record.timestamp)}</span></div>`;
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 = `<a href="${message.url}" target="_blank">
<div class="top">
<img src='${message.app_logo}' alt='logo'>
<div class='text'>${message.app_name}</div>
</div>
<div class="title">${message.title}</div>
<div class="cover"><img src='${message.cover_url}' onerror="this.style.display='none';"></div>
<div class="bottom"><div class="text">小程序</div></div>
</a>`;
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 = `
<div class="bottom">
<div class="author">
<div class="logo"><img src='${message.publisher_avatar}' onerror="this.style.display='none';"></div>
<div class="name">${message.publisher_nickname}</div>
<div class="authIcon"><img src='${message.authIconUrl}' onerror="this.style.display='none';"></div>
</div>
</div>`;
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 = `<span class="system-msg">${replaceEmoji(message.text.replace('\\"', '"'))}</span>`;
} 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')

View File

@ -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__':

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -57,6 +57,7 @@ def parser_emoji(xml_content):
}
except:
logger.error(traceback.format_exc())
logger.error(xml_content)
finally:
return result

View File

@ -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;
}

View File

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

View File

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

View File

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