(options: ParseOptions)
| 224 | // ==================== 解析器实现 ==================== |
| 225 | |
| 226 | async function* parseInstagram(options: ParseOptions): AsyncGenerator<ParseEvent, void, unknown> { |
| 227 | const { filePath, batchSize = 5000, onProgress, onLog } = options |
| 228 | |
| 229 | const totalBytes = getFileSize(filePath) |
| 230 | let messagesProcessed = 0 |
| 231 | |
| 232 | // 发送初始进度 |
| 233 | const initialProgress = createProgress('parsing', 0, totalBytes, 0, '正在解析 Instagram 聊天记录...') |
| 234 | yield { type: 'progress', data: initialProgress } |
| 235 | onProgress?.(initialProgress) |
| 236 | |
| 237 | onLog?.('info', `开始解析 Instagram 聊天记录,大小: ${(totalBytes / 1024 / 1024).toFixed(2)} MB`) |
| 238 | |
| 239 | // 读取并解析 JSON 文件 |
| 240 | let data: InstagramData |
| 241 | try { |
| 242 | const content = fs.readFileSync(filePath, 'utf-8') |
| 243 | data = JSON.parse(content) |
| 244 | } catch (error) { |
| 245 | const err = new Error(`无法解析 Instagram JSON 文件: ${error}`) |
| 246 | yield { type: 'error', data: err } |
| 247 | return |
| 248 | } |
| 249 | |
| 250 | // 判断聊天类型 |
| 251 | const isGroup = data.participants.length > 2 || !!data.joinable_mode |
| 252 | const chatType = isGroup ? ChatType.GROUP : ChatType.PRIVATE |
| 253 | |
| 254 | // 判断 Owner |
| 255 | let ownerId: string | undefined |
| 256 | if (chatType === ChatType.PRIVATE) { |
| 257 | // 私聊:title 是对方名字,另一个参与者是 owner |
| 258 | const owner = data.participants.find((p) => decodeInstagramText(p.name) !== decodeInstagramText(data.title)) |
| 259 | ownerId = owner ? decodeInstagramText(owner.name) : undefined |
| 260 | } else { |
| 261 | // 群聊:找 "You created the group." 消息的发送者 |
| 262 | const createMsg = data.messages.find((m) => m.content === 'You created the group.') |
| 263 | ownerId = createMsg ? decodeInstagramText(createMsg.sender_name) : undefined |
| 264 | } |
| 265 | |
| 266 | // 发送 meta |
| 267 | const meta: ParsedMeta = { |
| 268 | name: decodeInstagramText(data.title) || extractNameFromFilePath(filePath), |
| 269 | platform: KNOWN_PLATFORMS.INSTAGRAM, |
| 270 | type: chatType, |
| 271 | ownerId, |
| 272 | } |
| 273 | yield { type: 'meta', data: meta } |
| 274 | |
| 275 | // 收集成员信息 |
| 276 | const memberMap = new Map<string, ParsedMember>() |
| 277 | for (const participant of data.participants) { |
| 278 | const name = decodeInstagramText(participant.name) |
| 279 | memberMap.set(name, { |
| 280 | platformId: name, |
| 281 | accountName: name, |
| 282 | }) |
| 283 | } |
nothing calls this directly
no test coverage detected