mirror of
https://wget.la/https://github.com/Wxw-Gu/WechatExplorer
synced 2026-08-17 19:47:08 +08:00
fix: 修复语音文件缺失误报
批量语音读取失败时,并行回退到兼容的单条读取接口,避免批量接口异常导致全部语音被误判为缺失。 增量合并恢复可播放语音或转写后,清理矛盾的媒体及转写错误状态,并补充批量回退与增量合并回归测试。
This commit is contained in:
@@ -275,6 +275,8 @@ const mergeArchiveMessage = (previous: Message, current: Message): Message => {
|
|||||||
if (!current.exportMediaUrl && !current.voiceDataUrl && previous.exportMediaError) {
|
if (!current.exportMediaUrl && !current.voiceDataUrl && previous.exportMediaError) {
|
||||||
merged.exportMediaError = previous.exportMediaError
|
merged.exportMediaError = previous.exportMediaError
|
||||||
}
|
}
|
||||||
|
if (merged.voiceDataUrl) delete merged.exportMediaError
|
||||||
|
if (merged.voiceTranscript) delete merged.voiceTranscriptError
|
||||||
return merged
|
return merged
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -102,11 +102,12 @@ export class VoiceService {
|
|||||||
candidates: this.buildCandidates(reference.sessionId)
|
candidates: this.buildCandidates(reference.sessionId)
|
||||||
}))
|
}))
|
||||||
)
|
)
|
||||||
|
const failed: Array<{ index: number; reference: VoiceReference }> = []
|
||||||
for (const [{ index, reference }, source] of missing.map(
|
for (const [{ index, reference }, source] of missing.map(
|
||||||
(item, sourceIndex) => [item, sources[sourceIndex]] as const
|
(item, sourceIndex) => [item, sources[sourceIndex]] as const
|
||||||
)) {
|
)) {
|
||||||
if (!source?.success || !source.hex) {
|
if (!source?.success || !source.hex) {
|
||||||
results[index] = { success: false, error: source?.error || '获取语音数据失败' }
|
failed.push({ index, reference })
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
const silkData = this.decodeVoiceBlob(source.hex)
|
const silkData = this.decodeVoiceBlob(source.hex)
|
||||||
@@ -137,6 +138,19 @@ export class VoiceService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
const retried = await Promise.all(
|
||||||
|
failed.map(({ reference }) =>
|
||||||
|
this.resolveVoice(
|
||||||
|
reference.sessionId,
|
||||||
|
reference.localId,
|
||||||
|
reference.createTime,
|
||||||
|
reference.svrId
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
failed.forEach(({ index }, retryIndex) => {
|
||||||
|
results[index] = retried[retryIndex]
|
||||||
|
})
|
||||||
return results as Array<{ success: boolean; data?: string; error?: string }>
|
return results as Array<{ success: boolean; data?: string; error?: string }>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -494,6 +494,29 @@ describe('media export flow', () => {
|
|||||||
])
|
])
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('clears stale missing errors when an incremental merge restores playable voice data', async () => {
|
||||||
|
const { mergeHtmlArchiveMessages } = await import('../../src/main/export-service')
|
||||||
|
const previous = message({
|
||||||
|
id: 'voice-incremental',
|
||||||
|
type: '语音',
|
||||||
|
voiceDataUrl: 'voices/existing.wav',
|
||||||
|
voiceTranscript: '已有转写',
|
||||||
|
voiceTranscriptError: '旧转写错误'
|
||||||
|
})
|
||||||
|
const current = message({
|
||||||
|
id: 'voice-incremental',
|
||||||
|
type: '语音',
|
||||||
|
exportMediaError: '语音文件缺失:获取语音数据失败'
|
||||||
|
})
|
||||||
|
|
||||||
|
const [merged] = mergeHtmlArchiveMessages([previous], [current])
|
||||||
|
|
||||||
|
expect(merged.voiceDataUrl).toBe('voices/existing.wav')
|
||||||
|
expect(merged.voiceTranscript).toBe('已有转写')
|
||||||
|
expect(merged.exportMediaError).toBeUndefined()
|
||||||
|
expect(merged.voiceTranscriptError).toBeUndefined()
|
||||||
|
})
|
||||||
|
|
||||||
it('uses the customized file name as the HTML archive title', async () => {
|
it('uses the customized file name as the HTML archive title', async () => {
|
||||||
const { runExport } = await import('../../src/main/export-service')
|
const { runExport } = await import('../../src/main/export-service')
|
||||||
const win = { isDestroyed: () => true, webContents: { send: vi.fn() } }
|
const win = { isDestroyed: () => true, webContents: { send: vi.fn() } }
|
||||||
|
|||||||
@@ -0,0 +1,31 @@
|
|||||||
|
import { describe, expect, it, vi } from 'vitest'
|
||||||
|
import { VoiceService } from '../../src/main/voice-service'
|
||||||
|
|
||||||
|
describe('VoiceService batch lookup', () => {
|
||||||
|
it('retries failed batch entries with the compatible single-item lookup', async () => {
|
||||||
|
const getVoiceDataBatch = vi.fn().mockResolvedValue([
|
||||||
|
{ success: false, error: '获取语音数据失败' },
|
||||||
|
{ success: false, error: '获取语音数据失败' }
|
||||||
|
])
|
||||||
|
const service = new VoiceService({ getVoiceDataBatch } as never)
|
||||||
|
const resolveVoice = vi
|
||||||
|
.spyOn(service, 'resolveVoice')
|
||||||
|
.mockImplementation(async (_sessionId, localId) => ({
|
||||||
|
success: true,
|
||||||
|
data: `voice-${localId}`
|
||||||
|
}))
|
||||||
|
|
||||||
|
const result = await service.resolveVoices([
|
||||||
|
{ sessionId: 'session', localId: 10, createTime: 100, svrId: '1000' },
|
||||||
|
{ sessionId: 'session', localId: 11, createTime: 101, svrId: '1001' }
|
||||||
|
])
|
||||||
|
|
||||||
|
expect(result).toEqual([
|
||||||
|
{ success: true, data: 'voice-10' },
|
||||||
|
{ success: true, data: 'voice-11' }
|
||||||
|
])
|
||||||
|
expect(resolveVoice).toHaveBeenCalledTimes(2)
|
||||||
|
expect(resolveVoice).toHaveBeenNthCalledWith(1, 'session', 10, 100, '1000')
|
||||||
|
expect(resolveVoice).toHaveBeenNthCalledWith(2, 'session', 11, 101, '1001')
|
||||||
|
})
|
||||||
|
})
|
||||||
Reference in New Issue
Block a user