diff --git a/src/main/export-html-template.ts b/src/main/export-html-template.ts index ff91e10..d489142 100644 --- a/src/main/export-html-template.ts +++ b/src/main/export-html-template.ts @@ -995,6 +995,19 @@ const renderExportScript = (name: string): string => ` message.contentData && forwardedSearchText(message.contentData.items), message.exportMediaName ].filter(Boolean).join(' ').toLowerCase() + const exportedImageOrVideoFileStem = (message) => { + const mediaType = message.exportMediaType || (message.contentData && message.contentData.type) + if (mediaType !== 'image' && mediaType !== 'video') return '' + const mediaUrl = String(message.exportMediaUrl || '').split(/[?#]/, 1)[0] + const fileName = mediaUrl.slice(mediaUrl.lastIndexOf('/') + 1) + if (!fileName) return '' + let decodedFileName = fileName + try { + decodedFileName = decodeURIComponent(fileName) + } catch {} + const extensionIndex = decodedFileName.lastIndexOf('.') + return (extensionIndex > 0 ? decodedFileName.slice(0, extensionIndex) : decodedFileName).toLowerCase() + } const shareLabel = (typeVal) => { if (String(typeVal) === '5') return '公众号链接' @@ -1516,7 +1529,9 @@ const renderExportScript = (name: string): string => ` return allMessages.filter((message) => (activeConversation === 'all' || message.exportConversationId === activeConversation) && (activeKind === 'all' || kindOf(message) === activeKind) && - (!term || searchText(message).includes(term)) + (!term || + searchText(message).includes(term) || + exportedImageOrVideoFileStem(message) === term) ) } const applyFilters = (restorePosition = false) => { @@ -1779,7 +1794,7 @@ export function renderExportPage(name: string): string {
- +
diff --git a/tests/unit/export-media.test.ts b/tests/unit/export-media.test.ts index 7e0f810..876bf43 100644 --- a/tests/unit/export-media.test.ts +++ b/tests/unit/export-media.test.ts @@ -33,7 +33,7 @@ describe('export media', () => { expect(html).toContain('aria-expanded="') expect(html).toContain('setExpandedTimelineYear') expect(html).toContain('data-kind="media"') - expect(html).toContain('placeholder="搜索发送者或消息内容…"') + expect(html).toContain('placeholder="搜索发送者、消息内容或媒体文件名(不含后缀)…"') expect(html).toContain('font-size: 16px;') expect(html).toContain('filtered.slice(windowStart, windowEnd)') expect(html).toContain('windowStart = Math.max(0, windowEnd - PAGE_SIZE)') @@ -156,6 +156,61 @@ describe('export media', () => { dom.window.close() }) + it('matches exported image and video filenames exactly without their extension', () => { + const html = renderExportPage('媒体文件名搜索') + const dom = new JSDOM(html, { runScripts: 'outside-only' }) + const imageFileName = 'image_0123456789abcdef.jpg' + const videoFileName = 'video_fedcba9876543210.mp4' + const messages: Message[] = [ + { + ...messageForArchive('image-name', 'fixture', '媒体文件名搜索', '', 1), + type: '图片', + exportMediaType: 'image', + exportMediaUrl: `media/${imageFileName}`, + contentData: { type: 'image' } + }, + { + ...messageForArchive('video-name', 'fixture', '媒体文件名搜索', '', 2), + type: '视频', + exportMediaType: 'video', + exportMediaUrl: `media/${videoFileName}`, + contentData: { type: 'video' } + } + ] + Object.assign(dom.window, { + __WECHAT_EXPORT__: { + version: 1, + sourceId: 'fixture', + name: '媒体文件名搜索', + messages + } + }) + + dom.window.eval(inlineScriptOf(html)) + const search = dom.window.document.querySelector('#query') as HTMLInputElement + + search.value = 'IMAGE_0123456789ABCDEF' + search.dispatchEvent(new dom.window.Event('input')) + expect(dom.window.document.querySelectorAll('.message')).toHaveLength(1) + expect(dom.window.document.querySelectorAll('img.media-image')).toHaveLength(1) + expect(dom.window.document.querySelectorAll('video.media-image')).toHaveLength(0) + + search.value = '0123456789abcdef' + search.dispatchEvent(new dom.window.Event('input')) + expect(dom.window.document.querySelectorAll('.message')).toHaveLength(0) + + search.value = 'video_fedcba9876543210' + search.dispatchEvent(new dom.window.Event('input')) + expect(dom.window.document.querySelectorAll('.message')).toHaveLength(1) + expect(dom.window.document.querySelectorAll('img.media-image')).toHaveLength(0) + expect(dom.window.document.querySelectorAll('video.media-image')).toHaveLength(1) + + search.value = videoFileName + search.dispatchEvent(new dom.window.Event('input')) + expect(dom.window.document.querySelectorAll('.message')).toHaveLength(0) + dom.window.close() + }) + it('filters a v2 merged archive by conversation before search and month counts', () => { const html = renderExportPage('合并档案') const dom = new JSDOM(html, { runScripts: 'outside-only' })