feat: 完善多账号连接诊断与聊天媒体导出

- 新增微信账号发现、环境诊断和分步数据库连接引导
- 支持按账号安全保存数据库密钥及快速切换账号
- 完善 WCDB 历史消息分片读取和分页状态提示
- 支持导出图片、视频和语音,提供原图优先及缩略图回退
- 更新安装指引、兼容版本说明和相关自动化测试
This commit is contained in:
Wxw-Gu
2026-08-03 10:43:14 +08:00
parent 224308f0e0
commit 08e1294e5d
37 changed files with 2011 additions and 255 deletions
+16
View File
@@ -0,0 +1,16 @@
import type { DatabaseKeyEnvironment } from './database-key'
export function buildSafeDiagnosticSummary(
environment: Omit<DatabaseKeyEnvironment, 'diagnosticSummary'>
): string {
return [
`WechatExplorer: ${environment.appVersion}`,
`操作系统: ${environment.osVersion}`,
`微信客户端: ${environment.wechatVersion}`,
`数据结构: ${environment.dataStructureVersion}`,
`数据目录: ${environment.dataDirectoryDetected ? '已检测到' : '未检测到'}`,
`微信进程: ${environment.wechatRunning ? '运行中' : '未运行'}`,
`数据库连接: ${environment.dbConnected ? '已连接' : '未连接'}`,
`安全存储: ${environment.encryptionAvailable ? '可用' : '不可用'}`
].join('\n')
}
+28
View File
@@ -24,8 +24,36 @@ export interface DatabaseKeyStorageResult {
encryptionAvailable: boolean
}
export type AccountLoginStatus = 'current' | 'other' | 'unknown'
export interface WechatAccountCandidate {
id: string
accountRoot: string
directoryName: string
wxid?: string
nickname?: string
avatar?: string
hasSavedDbKey: boolean
loginStatus: AccountLoginStatus
selectedByInput: boolean
}
export interface AccountDiscoveryResult {
success: boolean
inputKind?: 'root' | 'account'
accounts: WechatAccountCandidate[]
preselectedAccountId?: string
error?: string
}
export interface DatabaseKeyEnvironment {
platform: NodeJS.Platform
osVersion: string
appVersion: string
wechatVersion: string
dataStructureVersion: string
dataDirectoryDetected: boolean
diagnosticSummary: string
autoDetectSupported: boolean
wechatRunning: boolean
accountIdentified: boolean
+22
View File
@@ -0,0 +1,22 @@
import type { ExportRequest } from './export'
export type ImageExportAttempt = {
allowThumbnail: boolean
preferThumbnail: boolean
fallback: boolean
}
export function getImageExportAttempts(
request: Pick<ExportRequest, 'preferOriginal' | 'fallbackThumbnail'>
): ImageExportAttempt[] {
if (request.preferOriginal === false) {
return [{ allowThumbnail: true, preferThumbnail: true, fallback: false }]
}
const attempts: ImageExportAttempt[] = [
{ allowThumbnail: false, preferThumbnail: false, fallback: false }
]
if (request.fallbackThumbnail !== false) {
attempts.push({ allowThumbnail: true, preferThumbnail: true, fallback: true })
}
return attempts
}
+3
View File
@@ -23,6 +23,9 @@ export interface ExportRequest {
endTime?: number
kinds: ExportMessageKind[]
includeMedia: boolean
preferOriginal?: boolean
fallbackThumbnail?: boolean
keepMissing?: boolean
includeAvatars?: boolean
avatarUrls?: Record<string, string>
nameMode?: ExportNameMode