MCPcopy Create free account
hub / github.com/ChatLab/ChatLab / preprocessQQJson

Function preprocessQQJson

packages/parser/src/formats/shuakami-qq-preprocessor.ts:211–351  ·  view source on GitHub ↗

* 预处理 QQ JSON 文件

(inputPath: string, onProgress?: (progress: ParseProgress) => void)

Source from the content-addressed store, hash-verified

209 * 预处理 QQ JSON 文件
210 */
211async function preprocessQQJson(inputPath: string, onProgress?: (progress: ParseProgress) => void): Promise<string> {
212 const totalBytes = getFileSize(inputPath)
213 let bytesRead = 0
214 let messagesProcessed = 0
215
216 const tempDir = getTempDir()
217 ensureDir(tempDir)
218 const outputFilename = `slim_${Date.now()}_${path.basename(inputPath)}`
219 const outputPath = path.join(tempDir, outputFilename)
220
221 onProgress?.(createProgress('parsing', 0, totalBytes, 0, ''))
222
223 // 先从原文件读取 avatars(因为它在文件末尾,消息处理时可能无法访问)
224 const avatarsStr = readAvatarsFromFile(inputPath)
225
226 return new Promise((resolve, reject) => {
227 const headChunks: string[] = []
228 let headSize = 0
229 const maxHeadSize = 100000
230
231 const headStream = fs.createReadStream(inputPath, { encoding: 'utf-8' })
232 let chatInfo: Record<string, unknown> = { name: '未知群聊', type: 'group' }
233 let metadata: Record<string, unknown> | undefined
234 let statistics: Record<string, unknown> | undefined
235
236 headStream.on('data', (chunk: string | Buffer) => {
237 const str = typeof chunk === 'string' ? chunk : chunk.toString('utf-8')
238 if (headSize < maxHeadSize) {
239 headChunks.push(str)
240 headSize += str.length
241 } else {
242 headStream.destroy()
243 }
244 })
245
246 headStream.on('close', () => {
247 const headContent = headChunks.join('')
248
249 try {
250 const chatInfoMatch = headContent.match(/"chatInfo"\s*:\s*(\{[^}]+\})/)
251 if (chatInfoMatch) {
252 chatInfo = JSON.parse(chatInfoMatch[1])
253 }
254 } catch {
255 // 使用默认值
256 }
257
258 try {
259 const metadataMatch = headContent.match(/"metadata"\s*:\s*(\{[^}]+\})/)
260 if (metadataMatch) {
261 metadata = JSON.parse(metadataMatch[1])
262 }
263 } catch {
264 // 忽略
265 }
266
267 try {
268 const statisticsMatch = headContent.match(/"statistics"\s*:\s*(\{[\s\S]*?\})\s*,\s*"messages"/)

Callers

nothing calls this directly

Calls 14

getFileSizeFunction · 0.90
createProgressFunction · 0.90
readAvatarsFromFileFunction · 0.85
slimMessageFunction · 0.85
resolveFunction · 0.85
onMethod · 0.80
destroyMethod · 0.80
parseMethod · 0.80
endMethod · 0.80
getTempDirFunction · 0.70
ensureDirFunction · 0.70
writeMethod · 0.65

Tested by

no test coverage detected