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' })