diff --git a/electron/main.ts b/electron/main.ts index d636dd5..076c16d 100644 --- a/electron/main.ts +++ b/electron/main.ts @@ -1563,6 +1563,10 @@ function registerIpcHandlers() { return chatService.getMessageById(sessionId, localId) }) + ipcMain.handle('chat:searchMessages', async (_, keyword: string, sessionId?: string, limit?: number, offset?: number, beginTimestamp?: number, endTimestamp?: number) => { + return chatService.searchMessages(keyword, sessionId, limit, offset, beginTimestamp, endTimestamp) + }) + ipcMain.handle('chat:execQuery', async (_, kind: string, path: string | null, sql: string) => { return chatService.execQuery(kind, path, sql) }) diff --git a/electron/services/chatService.ts b/electron/services/chatService.ts index 0b81fe2..aa958e6 100644 --- a/electron/services/chatService.ts +++ b/electron/services/chatService.ts @@ -6580,6 +6580,20 @@ class ChatService { } } + async searchMessages(keyword: string, sessionId?: string, limit?: number, offset?: number, beginTimestamp?: number, endTimestamp?: number): Promise<{ success: boolean; messages?: Message[]; error?: string }> { + try { + const result = await wcdbService.searchMessages(keyword, sessionId, limit, offset, beginTimestamp, endTimestamp) + if (!result.success || !result.messages) { + return { success: false, error: result.error || '搜索失败' } + } + const messages = result.messages.map((row: any) => this.parseMessage(row)).filter(Boolean) as Message[] + return { success: true, messages } + } catch (e) { + console.error('ChatService: searchMessages 失败:', e) + return { success: false, error: String(e) } + } + } + private parseMessage(row: any): Message { const rawContent = this.decodeMessageContent( this.getRowField(row, [ diff --git a/electron/services/wcdbCore.ts b/electron/services/wcdbCore.ts index 517fedf..a9b99dd 100644 --- a/electron/services/wcdbCore.ts +++ b/electron/services/wcdbCore.ts @@ -106,6 +106,7 @@ export class WcdbCore { private wcdbGetEmoticonCdnUrl: any = null private wcdbGetDbStatus: any = null private wcdbGetVoiceData: any = null + private wcdbSearchMessages: any = null private wcdbGetSnsTimeline: any = null private wcdbGetSnsAnnualStats: any = null private wcdbInstallSnsBlockDeleteTrigger: any = null @@ -817,6 +818,13 @@ export class WcdbCore { this.wcdbGetVoiceData = null } + // wcdb_status wcdb_search_messages(wcdb_handle handle, const char* session_id, const char* keyword, int32_t limit, int32_t offset, int32_t begin_timestamp, int32_t end_timestamp, char** out_json) + try { + this.wcdbSearchMessages = this.lib.func('int32 wcdb_search_messages(int64 handle, const char* sessionId, const char* keyword, int32 limit, int32 offset, int32 beginTimestamp, int32 endTimestamp, _Out_ void** outJson)') + } catch { + this.wcdbSearchMessages = null + } + // wcdb_status wcdb_get_sns_timeline(wcdb_handle handle, int32_t limit, int32_t offset, const char* username, const char* keyword, int32_t start_time, int32_t end_time, char** out_json) try { this.wcdbGetSnsTimeline = this.lib.func('int32 wcdb_get_sns_timeline(int64 handle, int32 limit, int32 offset, const char* username, const char* keyword, int32 startTime, int32 endTime, _Out_ void** outJson)') @@ -2279,6 +2287,36 @@ export class WcdbCore { }) } + async searchMessages(keyword: string, sessionId?: string, limit?: number, offset?: number, beginTimestamp?: number, endTimestamp?: number): Promise<{ success: boolean; messages?: any[]; error?: string }> { + if (!this.ensureReady()) return { success: false, error: 'WCDB 未连接' } + if (!this.wcdbSearchMessages) return { success: false, error: '当前 DLL 版本不支持搜索消息' } + try { + const handle = this.handle + await new Promise(resolve => setImmediate(resolve)) + if (handle === null || this.handle !== handle) return { success: false, error: '连接已断开' } + const outPtr = [null as any] + const result = this.wcdbSearchMessages( + handle, + sessionId || '', + keyword, + limit || 50, + offset || 0, + beginTimestamp || 0, + endTimestamp || 0, + outPtr + ) + if (result !== 0 || !outPtr[0]) { + return { success: false, error: `搜索消息失败: ${result}` } + } + const jsonStr = this.decodeJsonPtr(outPtr[0]) + if (!jsonStr) return { success: false, error: '解析搜索结果失败' } + const messages = JSON.parse(jsonStr) + return { success: true, messages } + } catch (e) { + return { success: false, error: String(e) } + } + } + async getSnsTimeline(limit: number, offset: number, usernames?: string[], keyword?: string, startTime?: number, endTime?: number): Promise<{ success: boolean; timeline?: any[]; error?: string }> { if (!this.ensureReady()) return { success: false, error: 'WCDB 未连接' } if (!this.wcdbGetSnsTimeline) return { success: false, error: '当前 DLL 版本不支持获取朋友圈' } diff --git a/electron/services/wcdbService.ts b/electron/services/wcdbService.ts index 286ddae..b5fcb24 100644 --- a/electron/services/wcdbService.ts +++ b/electron/services/wcdbService.ts @@ -406,6 +406,10 @@ export class WcdbService { return this.callWorker('getMessageById', { sessionId, localId }) } + async searchMessages(keyword: string, sessionId?: string, limit?: number, offset?: number, beginTimestamp?: number, endTimestamp?: number): Promise<{ success: boolean; messages?: any[]; error?: string }> { + return this.callWorker('searchMessages', { keyword, sessionId, limit, offset, beginTimestamp, endTimestamp }) + } + /** * 获取语音数据 */ diff --git a/electron/wcdbWorker.ts b/electron/wcdbWorker.ts index 8a49cad..5d02904 100644 --- a/electron/wcdbWorker.ts +++ b/electron/wcdbWorker.ts @@ -140,6 +140,9 @@ if (parentPort) { case 'getMessageById': result = await core.getMessageById(payload.sessionId, payload.localId) break + case 'searchMessages': + result = await core.searchMessages(payload.keyword, payload.sessionId, payload.limit, payload.offset, payload.beginTimestamp, payload.endTimestamp) + break case 'getVoiceData': result = await core.getVoiceData(payload.sessionId, payload.createTime, payload.candidates, payload.localId, payload.svrId) if (!result.success) {