Files
weflow-new/electron/services/export/parsers/quoteParser.ts
T
2026-06-30 00:18:31 +08:00

155 lines
4.5 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { extractXmlValue, normalizeAppMessageContent } from './xmlExtractor'
import { decodeHtmlEntities } from '../utils/htmlEscape'
export function looksLikeWxid(text: string): boolean {
if (!text) return false
const trimmed = text.trim().toLowerCase()
if (trimmed.startsWith('wxid_')) return true
return /^wx[a-z0-9_-]{4,}$/.test(trimmed)
}
export function sanitizeQuotedContent(content: string): string {
if (!content) return ''
let result = content
result = result.replace(/wxid_[A-Za-z0-9_-]{3,}/g, '')
result = result.replace(/^[\s::\-]+/, '')
result = result.replace(/[::]{2,}/g, ':')
result = result.replace(/^[\s::\-]+/, '')
result = result.replace(/\s+/g, ' ').trim()
return result
}
function extractPartialQuotedText(xml: string, fullContent: string): string {
if (!xml || !fullContent) return ''
const startChar = extractXmlValue(xml, 'start')
const endChar = extractXmlValue(xml, 'end')
const startIndexRaw = extractXmlValue(xml, 'startindex')
const endIndexRaw = extractXmlValue(xml, 'endindex')
const startIndex = Number.parseInt(startIndexRaw, 10)
const endIndex = Number.parseInt(endIndexRaw, 10)
if (startChar && endChar) {
const startPos = fullContent.indexOf(startChar)
if (startPos !== -1) {
const endPos = fullContent.indexOf(endChar, startPos + startChar.length - 1)
if (endPos !== -1 && endPos >= startPos) {
const sliced = fullContent.slice(startPos, endPos + endChar.length).trim()
if (sliced) return sliced
}
}
}
if (Number.isFinite(startIndex) && Number.isFinite(endIndex) && endIndex >= startIndex) {
const chars = Array.from(fullContent)
const sliced = chars.slice(startIndex, endIndex + 1).join('').trim()
if (sliced) return sliced
}
return ''
}
function extractPreferredQuotedText(referMsgXml: string): string {
if (!referMsgXml) return ''
const sources = [decodeHtmlEntities(referMsgXml)]
const rawMsgSource = extractXmlValue(referMsgXml, 'msgsource')
if (rawMsgSource) {
const decodedMsgSource = decodeHtmlEntities(rawMsgSource)
if (decodedMsgSource) {
sources.push(decodedMsgSource)
}
}
const fullContent = sanitizeQuotedContent(extractXmlValue(sources[0] || referMsgXml, 'content'))
const partialText = extractPartialQuotedText(sources[0] || referMsgXml, fullContent)
if (partialText) return partialText
const candidateTags = [
'selectedcontent',
'selectedtext',
'selectcontent',
'selecttext',
'quotecontent',
'quotetext',
'partcontent',
'parttext',
'excerpt',
'summary',
'preview'
]
for (const source of sources) {
for (const tag of candidateTags) {
const value = sanitizeQuotedContent(extractXmlValue(source, tag))
if (value) return value
}
}
return fullContent
}
export function parseQuoteMessage(content: string): { content?: string; sender?: string; type?: string; svrid?: string } {
try {
const normalized = normalizeAppMessageContent(content || '')
const referMsgStart = normalized.indexOf('<refermsg>')
const referMsgEnd = normalized.indexOf('</refermsg>')
if (referMsgStart === -1 || referMsgEnd === -1) {
return {}
}
const referMsgXml = normalized.substring(referMsgStart, referMsgEnd + 11)
let sender = extractXmlValue(referMsgXml, 'displayname')
if (sender && looksLikeWxid(sender)) {
sender = ''
}
const referContent = extractXmlValue(referMsgXml, 'content')
const referType = extractXmlValue(referMsgXml, 'type')
const svrid = extractXmlValue(referMsgXml, 'svrid')
let displayContent = referContent
switch (referType) {
case '1':
displayContent = extractPreferredQuotedText(referMsgXml)
break
case '3':
displayContent = '[图片]'
break
case '34':
displayContent = '[语音]'
break
case '43':
displayContent = '[视频]'
break
case '47':
displayContent = '[表情包]'
break
case '49':
displayContent = '[链接]'
break
case '42':
displayContent = '[名片]'
break
case '48':
displayContent = '[位置]'
break
default:
if (!referContent || referContent.includes('wxid_')) {
displayContent = '[消息]'
} else {
displayContent = sanitizeQuotedContent(referContent)
}
}
return {
content: displayContent || undefined,
sender: sender || undefined,
type: referType || undefined,
svrid: svrid || undefined
}
} catch {
return {}
}
}