fix: restore cross-message text search
| @@ -353,7 +353,7 @@ async function checkChatIntegrity(filePath, integritySlug) { | |||
| 353 | * @param {ChatMatchFunction|null} matcher - Optional function to match messages | 353 | * @param {ChatMatchFunction|null} matcher - Optional function to match messages |
| 354 | * @returns {Promise<ChatInfo>} | 354 | * @returns {Promise<ChatInfo>} |
| 355 | * | 355 | * |
| 356 | * @typedef {(text: string) => boolean} ChatMatchFunction | 356 | * @typedef {(textArray: string[]) => boolean} ChatMatchFunction |
| 357 | */ | 357 | */ |
| 358 | export async function getChatInfo(pathToFile, additionalData = {}, withMetadata = false, matcher = null) { | 358 | export async function getChatInfo(pathToFile, additionalData = {}, withMetadata = false, matcher = null) { |
| 359 | return new Promise(async (res) => { | 359 | return new Promise(async (res) => { |
| @@ -386,6 +386,7 @@ export async function getChatInfo(pathToFile, additionalData = {}, withMetadata | |||
| 386 | let lastLine; | 386 | let lastLine; |
| 387 | let itemCounter = 0; | 387 | let itemCounter = 0; |
| 388 | let hasAnyMatch = false; | 388 | let hasAnyMatch = false; |
| 389 | let matchBuffer = []; | ||
| 389 | rl.on('line', (line) => { | 390 | rl.on('line', (line) => { |
| 390 | if (withMetadata && itemCounter === 0) { | 391 | if (withMetadata && itemCounter === 0) { |
| 391 | const jsonData = tryParse(line); | 392 | const jsonData = tryParse(line); |
| @@ -396,8 +397,12 @@ export async function getChatInfo(pathToFile, additionalData = {}, withMetadata | |||
| 396 | // Skip matching if any match was already found | 397 | // Skip matching if any match was already found |
| 397 | if (hasMatcher && !hasAnyMatch && itemCounter > 0) { | 398 | if (hasMatcher && !hasAnyMatch && itemCounter > 0) { |
| 398 | const jsonData = tryParse(line); | 399 | const jsonData = tryParse(line); |
| 399 | if (jsonData && matcher(jsonData.mes || '')) { | 400 | if (jsonData) { |
| 400 | hasAnyMatch = true; | 401 | matchBuffer.push(jsonData.mes || ''); |
| 402 | if (matcher(matchBuffer)) { | ||
| 403 | hasAnyMatch = true; | ||
| 404 | matchBuffer = []; | ||
| 405 | } | ||
| 401 | } | 406 | } |
| 402 | } | 407 | } |
| 403 | itemCounter++; | 408 | itemCounter++; |
| @@ -910,18 +915,17 @@ router.post('/search', validateAvatarUrlMiddleware, async function (request, res | |||
| 910 | const fragments = query ? query.trim().toLowerCase().split(/\s+/).filter(x => x) : []; | 915 | const fragments = query ? query.trim().toLowerCase().split(/\s+/).filter(x => x) : []; |
| 911 | 916 | ||
| 912 | /** @type {ChatMatchFunction} */ | 917 | /** @type {ChatMatchFunction} */ |
| 913 | const hasTextMatch = (text) => { | 918 | const hasTextMatch = (textArray) => { |
| 914 | if (fragments.length === 0) { | 919 | if (fragments.length === 0) { |
| 915 | return true; | 920 | return true; |
| 916 | } | 921 | } |
| 917 | const loweredText = String(text).toLowerCase(); | 922 | return fragments.every(fragment => textArray.some(text => String(text ?? '').toLowerCase().includes(fragment))); |
| 918 | return fragments.every(fragment => loweredText.includes(fragment)); | ||
| 919 | }; | 923 | }; |
| 920 | 924 | ||
| 921 | for (const chatFile of chatFiles) { | 925 | for (const chatFile of chatFiles) { |
| 922 | const matcher = query ? hasTextMatch : null; | 926 | const matcher = query ? hasTextMatch : null; |
| 923 | const chatInfo = await getChatInfo(chatFile, {}, false, matcher); | 927 | const chatInfo = await getChatInfo(chatFile, {}, false, matcher); |
| 924 | const hasMatch = hasTextMatch(chatInfo.file_id ?? '') || chatInfo.match; | 928 | const hasMatch = chatInfo.match || hasTextMatch([chatInfo.file_id ?? '']); |
| 925 | 929 | ||
| 926 | // Skip corrupted or invalid chat files | 930 | // Skip corrupted or invalid chat files |
| 927 | if (!chatInfo.file_name) { | 931 | if (!chatInfo.file_name) { |