Compare commits

..

1 Commits

Author SHA1 Message Date
dependabot[bot]
d172114c09 chore(deps-dev): bump sass from 1.98.0 to 1.99.0
Bumps [sass](https://github.com/sass/dart-sass) from 1.98.0 to 1.99.0.
- [Release notes](https://github.com/sass/dart-sass/releases)
- [Changelog](https://github.com/sass/dart-sass/blob/main/CHANGELOG.md)
- [Commits](https://github.com/sass/dart-sass/compare/1.98.0...1.99.0)

---
updated-dependencies:
- dependency-name: sass
  dependency-version: 1.99.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-04-03 23:16:12 +00:00
13 changed files with 63 additions and 367 deletions

1
.gitignore vendored
View File

@@ -72,4 +72,3 @@ pnpm-lock.yaml
/pnpm-workspace.yaml /pnpm-workspace.yaml
wechat-research-site wechat-research-site
.codex .codex
weflow-web-offical

View File

@@ -136,7 +136,6 @@ const shouldOfferUpdateForTrack = (latestVersion: string, currentVersion: string
} }
let lastAppliedUpdaterChannel: string | null = null let lastAppliedUpdaterChannel: string | null = null
let lastAppliedUpdaterFeedUrl: string | null = null
const resetUpdaterProviderCache = () => { const resetUpdaterProviderCache = () => {
const updater = autoUpdater as any const updater = autoUpdater as any
// electron-updater 会缓存 provider切换 channel 后需清理缓存,避免仍请求旧通道 // electron-updater 会缓存 provider切换 channel 后需清理缓存,避免仍请求旧通道
@@ -147,41 +146,23 @@ const resetUpdaterProviderCache = () => {
} }
} }
const getUpdaterFeedUrlByTrack = (track: 'stable' | 'preview' | 'dev'): string => {
const repoBase = 'https://github.com/hicccc77/WeFlow/releases'
if (track === 'stable') return `${repoBase}/latest/download`
if (track === 'preview') return `${repoBase}/download/nightly-preview`
return `${repoBase}/download/nightly-dev`
}
const applyAutoUpdateChannel = (reason: 'startup' | 'settings' = 'startup') => { const applyAutoUpdateChannel = (reason: 'startup' | 'settings' = 'startup') => {
const track = getEffectiveUpdateTrack() const track = getEffectiveUpdateTrack()
const currentTrack = inferUpdateTrackFromVersion(appVersion) const currentTrack = inferUpdateTrackFromVersion(appVersion)
const baseUpdateChannel = track === 'stable' ? 'latest' : track const baseUpdateChannel = track === 'stable' ? 'latest' : track
const nextFeedUrl = getUpdaterFeedUrlByTrack(track)
const nextUpdaterChannel = const nextUpdaterChannel =
process.platform === 'win32' && process.arch === 'arm64' process.platform === 'win32' && process.arch === 'arm64'
? `${baseUpdateChannel}-arm64` ? `${baseUpdateChannel}-arm64`
: baseUpdateChannel : baseUpdateChannel
if ( if (lastAppliedUpdaterChannel && lastAppliedUpdaterChannel !== nextUpdaterChannel) {
(lastAppliedUpdaterChannel && lastAppliedUpdaterChannel !== nextUpdaterChannel) ||
(lastAppliedUpdaterFeedUrl && lastAppliedUpdaterFeedUrl !== nextFeedUrl)
) {
resetUpdaterProviderCache() resetUpdaterProviderCache()
} }
autoUpdater.allowPrerelease = track !== 'stable' autoUpdater.allowPrerelease = track !== 'stable'
// 只要用户当前选择的目标通道与当前安装版本所属通道不同,就允许跨通道更新(含降级) // 只要用户当前选择的目标通道与当前安装版本所属通道不同,就允许跨通道更新(含降级)
autoUpdater.allowDowngrade = track !== currentTrack autoUpdater.allowDowngrade = track !== currentTrack
// 统一走 generic feed确保 preview/dev 命中各自固定发布页,不受 GitHub provider 的 prerelease 选择影响。
autoUpdater.setFeedURL({
provider: 'generic',
url: nextFeedUrl,
channel: nextUpdaterChannel
})
autoUpdater.channel = nextUpdaterChannel autoUpdater.channel = nextUpdaterChannel
lastAppliedUpdaterChannel = nextUpdaterChannel lastAppliedUpdaterChannel = nextUpdaterChannel
lastAppliedUpdaterFeedUrl = nextFeedUrl console.log(`[Update](${reason}) 当前版本 ${appVersion},当前轨道: ${currentTrack},渠道偏好: ${track},更新通道: ${autoUpdater.channel}allowDowngrade=${autoUpdater.allowDowngrade}`)
console.log(`[Update](${reason}) 当前版本 ${appVersion},当前轨道: ${currentTrack},渠道偏好: ${track},更新通道: ${autoUpdater.channel}feed=${nextFeedUrl}allowDowngrade=${autoUpdater.allowDowngrade}`)
} }
applyAutoUpdateChannel('startup') applyAutoUpdateChannel('startup')

View File

@@ -75,7 +75,6 @@ export interface Message {
fileName?: string // 文件名 fileName?: string // 文件名
fileSize?: number // 文件大小 fileSize?: number // 文件大小
fileExt?: string // 文件扩展名 fileExt?: string // 文件扩展名
fileMd5?: string // 文件 MD5
xmlType?: string // XML 中的 type 字段 xmlType?: string // XML 中的 type 字段
appMsgKind?: string // 归一化 appmsg 类型 appMsgKind?: string // 归一化 appmsg 类型
appMsgDesc?: string appMsgDesc?: string
@@ -3797,7 +3796,6 @@ class ChatService {
let fileName: string | undefined let fileName: string | undefined
let fileSize: number | undefined let fileSize: number | undefined
let fileExt: string | undefined let fileExt: string | undefined
let fileMd5: string | undefined
let xmlType: string | undefined let xmlType: string | undefined
let appMsgKind: string | undefined let appMsgKind: string | undefined
let appMsgDesc: string | undefined let appMsgDesc: string | undefined
@@ -3902,7 +3900,6 @@ class ChatService {
fileName = type49Info.fileName fileName = type49Info.fileName
fileSize = type49Info.fileSize fileSize = type49Info.fileSize
fileExt = type49Info.fileExt fileExt = type49Info.fileExt
fileMd5 = type49Info.fileMd5
chatRecordTitle = type49Info.chatRecordTitle chatRecordTitle = type49Info.chatRecordTitle
chatRecordList = type49Info.chatRecordList chatRecordList = type49Info.chatRecordList
transferPayerUsername = type49Info.transferPayerUsername transferPayerUsername = type49Info.transferPayerUsername
@@ -3926,7 +3923,6 @@ class ChatService {
fileName = fileName || type49Info.fileName fileName = fileName || type49Info.fileName
fileSize = fileSize ?? type49Info.fileSize fileSize = fileSize ?? type49Info.fileSize
fileExt = fileExt || type49Info.fileExt fileExt = fileExt || type49Info.fileExt
fileMd5 = fileMd5 || type49Info.fileMd5
appMsgKind = appMsgKind || type49Info.appMsgKind appMsgKind = appMsgKind || type49Info.appMsgKind
appMsgDesc = appMsgDesc || type49Info.appMsgDesc appMsgDesc = appMsgDesc || type49Info.appMsgDesc
appMsgAppName = appMsgAppName || type49Info.appMsgAppName appMsgAppName = appMsgAppName || type49Info.appMsgAppName
@@ -4000,7 +3996,6 @@ class ChatService {
fileName, fileName,
fileSize, fileSize,
fileExt, fileExt,
fileMd5,
xmlType, xmlType,
appMsgKind, appMsgKind,
appMsgDesc, appMsgDesc,
@@ -4604,7 +4599,6 @@ class ChatService {
fileName?: string fileName?: string
fileSize?: number fileSize?: number
fileExt?: string fileExt?: string
fileMd5?: string
transferPayerUsername?: string transferPayerUsername?: string
transferReceiverUsername?: string transferReceiverUsername?: string
chatRecordTitle?: string chatRecordTitle?: string
@@ -4801,7 +4795,6 @@ class ChatService {
// 提取文件扩展名 // 提取文件扩展名
const fileExt = this.extractXmlValue(content, 'fileext') const fileExt = this.extractXmlValue(content, 'fileext')
const fileMd5 = this.extractXmlValue(content, 'md5') || this.extractXmlValue(content, 'filemd5')
if (fileExt) { if (fileExt) {
result.fileExt = fileExt result.fileExt = fileExt
} else if (result.fileName) { } else if (result.fileName) {
@@ -4811,9 +4804,6 @@ class ChatService {
result.fileExt = match[1] result.fileExt = match[1]
} }
} }
if (fileMd5) {
result.fileMd5 = fileMd5.toLowerCase()
}
break break
} }

View File

@@ -98,8 +98,6 @@ export interface ExportOptions {
exportVoices?: boolean exportVoices?: boolean
exportVideos?: boolean exportVideos?: boolean
exportEmojis?: boolean exportEmojis?: boolean
exportFiles?: boolean
maxFileSizeMb?: number
exportVoiceAsText?: boolean exportVoiceAsText?: boolean
excelCompactColumns?: boolean excelCompactColumns?: boolean
txtColumns?: string[] txtColumns?: string[]
@@ -123,7 +121,7 @@ const TXT_COLUMN_DEFINITIONS: Array<{ id: string; label: string }> = [
interface MediaExportItem { interface MediaExportItem {
relativePath: string relativePath: string
kind: 'image' | 'voice' | 'emoji' | 'video' | 'file' kind: 'image' | 'voice' | 'emoji' | 'video'
posterDataUrl?: string posterDataUrl?: string
} }
@@ -138,11 +136,6 @@ interface ExportDisplayProfile {
type MessageCollectMode = 'full' | 'text-fast' | 'media-fast' type MessageCollectMode = 'full' | 'text-fast' | 'media-fast'
type MediaContentType = 'voice' | 'image' | 'video' | 'emoji' type MediaContentType = 'voice' | 'image' | 'video' | 'emoji'
interface FileExportCandidate {
sourcePath: string
matchedBy: 'md5' | 'name'
yearMonth?: string
}
export interface ExportProgress { export interface ExportProgress {
current: number current: number
@@ -849,7 +842,7 @@ class ExportService {
private isMediaExportEnabled(options: ExportOptions): boolean { private isMediaExportEnabled(options: ExportOptions): boolean {
return options.exportMedia === true && return options.exportMedia === true &&
Boolean(options.exportImages || options.exportVoices || options.exportVideos || options.exportEmojis || options.exportFiles) Boolean(options.exportImages || options.exportVoices || options.exportVideos || options.exportEmojis)
} }
private isUnboundedDateRange(dateRange?: { start: number; end: number } | null): boolean { private isUnboundedDateRange(dateRange?: { start: number; end: number } | null): boolean {
@@ -887,7 +880,7 @@ class ExportService {
if (options.exportImages) selected.add(3) if (options.exportImages) selected.add(3)
if (options.exportVoices) selected.add(34) if (options.exportVoices) selected.add(34)
if (options.exportVideos) selected.add(43) if (options.exportVideos) selected.add(43)
if (options.exportFiles) selected.add(49) if (options.exportEmojis) selected.add(47)
return selected return selected
} }
@@ -3423,8 +3416,6 @@ class ExportService {
exportVoices?: boolean exportVoices?: boolean
exportVideos?: boolean exportVideos?: boolean
exportEmojis?: boolean exportEmojis?: boolean
exportFiles?: boolean
maxFileSizeMb?: number
exportVoiceAsText?: boolean exportVoiceAsText?: boolean
includeVideoPoster?: boolean includeVideoPoster?: boolean
includeVoiceWithTranscript?: boolean includeVoiceWithTranscript?: boolean
@@ -3478,16 +3469,6 @@ class ExportService {
) )
} }
if ((localType === 49 || localType === 8589934592049) && options.exportFiles && String(msg?.xmlType || '') === '6') {
return this.exportFileAttachment(
msg,
mediaRootDir,
mediaRelativePrefix,
options.maxFileSizeMb,
options.dirCache
)
}
return null return null
} }
@@ -3958,165 +3939,6 @@ class ExportService {
return tagMatch?.[1]?.toLowerCase() return tagMatch?.[1]?.toLowerCase()
} }
private resolveFileAttachmentRoots(): string[] {
const dbPath = String(this.configService.get('dbPath') || '').trim()
const rawWxid = String(this.configService.get('myWxid') || '').trim()
const cleanedWxid = this.cleanAccountDirName(rawWxid)
if (!dbPath) return []
const normalized = dbPath.replace(/[\\/]+$/, '')
const roots = new Set<string>()
const tryAddRoot = (candidate: string) => {
const fileRoot = path.join(candidate, 'msg', 'file')
if (fs.existsSync(fileRoot)) {
roots.add(fileRoot)
}
}
tryAddRoot(normalized)
if (rawWxid) tryAddRoot(path.join(normalized, rawWxid))
if (cleanedWxid && cleanedWxid !== rawWxid) tryAddRoot(path.join(normalized, cleanedWxid))
const dbStoragePath =
this.resolveDbStoragePathForExport(normalized, cleanedWxid) ||
this.resolveDbStoragePathForExport(normalized, rawWxid)
if (dbStoragePath) {
tryAddRoot(path.dirname(dbStoragePath))
}
return Array.from(roots)
}
private buildPreferredFileYearMonths(createTime?: unknown): string[] {
const raw = Number(createTime)
if (!Number.isFinite(raw) || raw <= 0) return []
const ts = raw > 1e12 ? raw : raw * 1000
const date = new Date(ts)
if (Number.isNaN(date.getTime())) return []
const y = date.getFullYear()
const m = String(date.getMonth() + 1).padStart(2, '0')
return [`${y}-${m}`]
}
private async verifyFileHash(sourcePath: string, expectedMd5?: string): Promise<boolean> {
const normalizedExpected = String(expectedMd5 || '').trim().toLowerCase()
if (!normalizedExpected) return true
if (!/^[a-f0-9]{32}$/i.test(normalizedExpected)) return true
try {
const hash = crypto.createHash('md5')
await new Promise<void>((resolve, reject) => {
const stream = fs.createReadStream(sourcePath)
stream.on('data', chunk => hash.update(chunk))
stream.on('end', () => resolve())
stream.on('error', reject)
})
return hash.digest('hex').toLowerCase() === normalizedExpected
} catch {
return false
}
}
private async resolveFileAttachmentCandidates(msg: any): Promise<FileExportCandidate[]> {
const fileName = String(msg?.fileName || '').trim()
if (!fileName) return []
const roots = this.resolveFileAttachmentRoots()
if (roots.length === 0) return []
const normalizedMd5 = String(msg?.fileMd5 || '').trim().toLowerCase()
const preferredMonths = this.buildPreferredFileYearMonths(msg?.createTime)
const candidates: FileExportCandidate[] = []
const seen = new Set<string>()
for (const root of roots) {
let monthDirs: string[] = []
try {
monthDirs = fs.readdirSync(root)
.filter(entry => /^\d{4}-\d{2}$/.test(entry) && fs.existsSync(path.join(root, entry)))
.sort()
} catch {
continue
}
const orderedMonths = Array.from(new Set([
...preferredMonths,
...monthDirs.slice().reverse()
]))
for (const month of orderedMonths) {
const sourcePath = path.join(root, month, fileName)
if (!fs.existsSync(sourcePath)) continue
const resolvedPath = path.resolve(sourcePath)
if (seen.has(resolvedPath)) continue
seen.add(resolvedPath)
if (normalizedMd5) {
const ok = await this.verifyFileHash(resolvedPath, normalizedMd5)
if (ok) {
candidates.unshift({ sourcePath: resolvedPath, matchedBy: 'md5', yearMonth: month })
continue
}
}
candidates.push({ sourcePath: resolvedPath, matchedBy: 'name', yearMonth: month })
}
}
return candidates
}
private async exportFileAttachment(
msg: any,
mediaRootDir: string,
mediaRelativePrefix: string,
maxFileSizeMb?: number,
dirCache?: Set<string>
): Promise<MediaExportItem | null> {
try {
const fileNameRaw = String(msg?.fileName || '').trim()
if (!fileNameRaw) return null
const filesDir = path.join(mediaRootDir, mediaRelativePrefix, 'files')
if (!dirCache?.has(filesDir)) {
await fs.promises.mkdir(filesDir, { recursive: true })
dirCache?.add(filesDir)
}
const candidates = await this.resolveFileAttachmentCandidates(msg)
if (candidates.length === 0) return null
const maxBytes = Number.isFinite(maxFileSizeMb)
? Math.max(0, Math.floor(Number(maxFileSizeMb) * 1024 * 1024))
: 0
const selected = candidates[0]
const stat = await fs.promises.stat(selected.sourcePath)
if (!stat.isFile()) return null
if (maxBytes > 0 && stat.size > maxBytes) return null
const normalizedMd5 = String(msg?.fileMd5 || '').trim().toLowerCase()
if (normalizedMd5 && selected.matchedBy !== 'md5') {
const verified = await this.verifyFileHash(selected.sourcePath, normalizedMd5)
if (!verified) return null
}
const safeBaseName = path.basename(fileNameRaw).replace(/[\\/:*?"<>|]/g, '_') || 'file'
const messageId = String(msg?.localId || Date.now())
const destFileName = `${messageId}_${safeBaseName}`
const destPath = path.join(filesDir, destFileName)
const copied = await this.copyFileOptimized(selected.sourcePath, destPath)
if (!copied.success) return null
this.noteMediaTelemetry({ doneFiles: 1, bytesWritten: stat.size })
return {
relativePath: path.posix.join(mediaRelativePrefix, 'files', destFileName),
kind: 'file'
}
} catch {
return null
}
}
private extractLocationMeta(content: string, localType: number): { private extractLocationMeta(content: string, localType: number): {
locationLat?: number locationLat?: number
locationLng?: number locationLng?: number
@@ -4173,7 +3995,7 @@ class ExportService {
mediaRelativePrefix: string mediaRelativePrefix: string
} { } {
const exportMediaEnabled = options.exportMedia === true && const exportMediaEnabled = options.exportMedia === true &&
Boolean(options.exportImages || options.exportVoices || options.exportVideos || options.exportEmojis || options.exportFiles) Boolean(options.exportImages || options.exportVoices || options.exportVideos || options.exportEmojis)
const outputDir = path.dirname(outputPath) const outputDir = path.dirname(outputPath)
const rawWriteLayout = this.configService.get('exportWriteLayout') const rawWriteLayout = this.configService.get('exportWriteLayout')
const writeLayout = rawWriteLayout === 'A' || rawWriteLayout === 'B' || rawWriteLayout === 'C' const writeLayout = rawWriteLayout === 'A' || rawWriteLayout === 'B' || rawWriteLayout === 'C'
@@ -5110,8 +4932,7 @@ class ExportService {
return (t === 3 && options.exportImages) || // 图片 return (t === 3 && options.exportImages) || // 图片
(t === 47 && options.exportEmojis) || // 表情 (t === 47 && options.exportEmojis) || // 表情
(t === 43 && options.exportVideos) || // 视频 (t === 43 && options.exportVideos) || // 视频
(t === 34 && options.exportVoices) || // 语音文件 (t === 34 && options.exportVoices) // 语音文件
((t === 49 || t === 8589934592049) && options.exportFiles && String(msg?.xmlType || '') === '6')
}) })
: [] : []
@@ -5152,8 +4973,6 @@ class ExportService {
exportVoices: options.exportVoices, exportVoices: options.exportVoices,
exportVideos: options.exportVideos, exportVideos: options.exportVideos,
exportEmojis: options.exportEmojis, exportEmojis: options.exportEmojis,
exportFiles: options.exportFiles,
maxFileSizeMb: options.maxFileSizeMb,
exportVoiceAsText: options.exportVoiceAsText, exportVoiceAsText: options.exportVoiceAsText,
includeVideoPoster: options.format === 'html', includeVideoPoster: options.format === 'html',
imageDeepSearchOnMiss: options.imageDeepSearchOnMiss, imageDeepSearchOnMiss: options.imageDeepSearchOnMiss,
@@ -5622,8 +5441,7 @@ class ExportService {
return (t === 3 && options.exportImages) || return (t === 3 && options.exportImages) ||
(t === 47 && options.exportEmojis) || (t === 47 && options.exportEmojis) ||
(t === 43 && options.exportVideos) || (t === 43 && options.exportVideos) ||
(t === 34 && options.exportVoices) || (t === 34 && options.exportVoices)
((t === 49 || t === 8589934592049) && options.exportFiles && String(msg?.xmlType || '') === '6')
}) })
: [] : []
@@ -5663,8 +5481,6 @@ class ExportService {
exportVoices: options.exportVoices, exportVoices: options.exportVoices,
exportVideos: options.exportVideos, exportVideos: options.exportVideos,
exportEmojis: options.exportEmojis, exportEmojis: options.exportEmojis,
exportFiles: options.exportFiles,
maxFileSizeMb: options.maxFileSizeMb,
exportVoiceAsText: options.exportVoiceAsText, exportVoiceAsText: options.exportVoiceAsText,
includeVideoPoster: options.format === 'html', includeVideoPoster: options.format === 'html',
imageDeepSearchOnMiss: options.imageDeepSearchOnMiss, imageDeepSearchOnMiss: options.imageDeepSearchOnMiss,
@@ -6485,8 +6301,7 @@ class ExportService {
return (t === 3 && options.exportImages) || return (t === 3 && options.exportImages) ||
(t === 47 && options.exportEmojis) || (t === 47 && options.exportEmojis) ||
(t === 43 && options.exportVideos) || (t === 43 && options.exportVideos) ||
(t === 34 && options.exportVoices) || (t === 34 && options.exportVoices)
((t === 49 || t === 8589934592049) && options.exportFiles && String(msg?.xmlType || '') === '6')
}) })
: [] : []
@@ -6526,8 +6341,6 @@ class ExportService {
exportVoices: options.exportVoices, exportVoices: options.exportVoices,
exportVideos: options.exportVideos, exportVideos: options.exportVideos,
exportEmojis: options.exportEmojis, exportEmojis: options.exportEmojis,
exportFiles: options.exportFiles,
maxFileSizeMb: options.maxFileSizeMb,
exportVoiceAsText: options.exportVoiceAsText, exportVoiceAsText: options.exportVoiceAsText,
includeVideoPoster: options.format === 'html', includeVideoPoster: options.format === 'html',
imageDeepSearchOnMiss: options.imageDeepSearchOnMiss, imageDeepSearchOnMiss: options.imageDeepSearchOnMiss,
@@ -7201,8 +7014,7 @@ class ExportService {
return (t === 3 && options.exportImages) || return (t === 3 && options.exportImages) ||
(t === 47 && options.exportEmojis) || (t === 47 && options.exportEmojis) ||
(t === 43 && options.exportVideos) || (t === 43 && options.exportVideos) ||
(t === 34 && options.exportVoices) || (t === 34 && options.exportVoices)
((t === 49 || t === 8589934592049) && options.exportFiles && String(msg?.xmlType || '') === '6')
}) })
: [] : []
@@ -7242,8 +7054,6 @@ class ExportService {
exportVoices: options.exportVoices, exportVoices: options.exportVoices,
exportVideos: options.exportVideos, exportVideos: options.exportVideos,
exportEmojis: options.exportEmojis, exportEmojis: options.exportEmojis,
exportFiles: options.exportFiles,
maxFileSizeMb: options.maxFileSizeMb,
exportVoiceAsText: options.exportVoiceAsText, exportVoiceAsText: options.exportVoiceAsText,
includeVideoPoster: options.format === 'html', includeVideoPoster: options.format === 'html',
imageDeepSearchOnMiss: options.imageDeepSearchOnMiss, imageDeepSearchOnMiss: options.imageDeepSearchOnMiss,
@@ -7581,8 +7391,7 @@ class ExportService {
return (t === 3 && options.exportImages) || return (t === 3 && options.exportImages) ||
(t === 47 && options.exportEmojis) || (t === 47 && options.exportEmojis) ||
(t === 43 && options.exportVideos) || (t === 43 && options.exportVideos) ||
(t === 34 && options.exportVoices) || (t === 34 && options.exportVoices)
((t === 49 || t === 8589934592049) && options.exportFiles && String(msg?.xmlType || '') === '6')
}) })
: [] : []
@@ -7622,8 +7431,6 @@ class ExportService {
exportVoices: options.exportVoices, exportVoices: options.exportVoices,
exportVideos: options.exportVideos, exportVideos: options.exportVideos,
exportEmojis: options.exportEmojis, exportEmojis: options.exportEmojis,
exportFiles: options.exportFiles,
maxFileSizeMb: options.maxFileSizeMb,
exportVoiceAsText: options.exportVoiceAsText, exportVoiceAsText: options.exportVoiceAsText,
includeVideoPoster: options.format === 'html', includeVideoPoster: options.format === 'html',
imageDeepSearchOnMiss: options.imageDeepSearchOnMiss, imageDeepSearchOnMiss: options.imageDeepSearchOnMiss,
@@ -8044,8 +7851,6 @@ class ExportService {
exportImages: options.exportImages, exportImages: options.exportImages,
exportVoices: options.exportVoices, exportVoices: options.exportVoices,
exportEmojis: options.exportEmojis, exportEmojis: options.exportEmojis,
exportFiles: options.exportFiles,
maxFileSizeMb: options.maxFileSizeMb,
exportVoiceAsText: options.exportVoiceAsText, exportVoiceAsText: options.exportVoiceAsText,
includeVideoPoster: options.format === 'html', includeVideoPoster: options.format === 'html',
includeVoiceWithTranscript: true, includeVoiceWithTranscript: true,

8
package-lock.json generated
View File

@@ -40,7 +40,7 @@
"@vitejs/plugin-react": "^4.3.4", "@vitejs/plugin-react": "^4.3.4",
"electron": "^41.1.1", "electron": "^41.1.1",
"electron-builder": "^26.8.1", "electron-builder": "^26.8.1",
"sass": "^1.98.0", "sass": "^1.99.0",
"sharp": "^0.34.5", "sharp": "^0.34.5",
"typescript": "^6.0.2", "typescript": "^6.0.2",
"vite": "^7.0.0", "vite": "^7.0.0",
@@ -8908,9 +8908,9 @@
} }
}, },
"node_modules/sass": { "node_modules/sass": {
"version": "1.98.0", "version": "1.99.0",
"resolved": "https://registry.npmjs.org/sass/-/sass-1.98.0.tgz", "resolved": "https://registry.npmjs.org/sass/-/sass-1.99.0.tgz",
"integrity": "sha512-+4N/u9dZ4PrgzGgPlKnaaRQx64RO0JBKs9sDhQ2pLgN6JQZ25uPQZKQYaBJU48Kd5BxgXoJ4e09Dq7nMcOUW3A==", "integrity": "sha512-kgW13M54DUB7IsIRM5LvJkNlpH+WhMpooUcaWGFARkF1Tc82v9mIWkCbCYf+MBvpIUBSeSOTilpZjEPr2VYE6Q==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {

View File

@@ -54,7 +54,7 @@
"@vitejs/plugin-react": "^4.3.4", "@vitejs/plugin-react": "^4.3.4",
"electron": "^41.1.1", "electron": "^41.1.1",
"electron-builder": "^26.8.1", "electron-builder": "^26.8.1",
"sass": "^1.98.0", "sass": "^1.99.0",
"sharp": "^0.34.5", "sharp": "^0.34.5",
"typescript": "^6.0.2", "typescript": "^6.0.2",
"vite": "^7.0.0", "vite": "^7.0.0",

View File

@@ -591,13 +591,9 @@ function App() {
<div className="agreement-notice"> <div className="agreement-notice">
<strong></strong> <strong></strong>
<span className="agreement-notice-link"> <span className="agreement-notice-link">
<a href="https://weflow.top" target="_blank" rel="noreferrer">
https://weflow.top
</a>
&nbsp;·&nbsp;
<a href="https://github.com/hicccc77/WeFlow" target="_blank" rel="noreferrer"> <a href="https://github.com/hicccc77/WeFlow" target="_blank" rel="noreferrer">
GitHub https://github.com/hicccc77/WeFlow
</a> </a>
</span> </span>
</div> </div>
@@ -612,7 +608,7 @@ function App() {
<p>使使</p> <p>使使</p>
<h4>4. </h4> <h4>4. </h4>
<p></p> <p></p>
</div> </div>
</div> </div>
<div className="agreement-footer"> <div className="agreement-footer">
@@ -670,30 +666,30 @@ function App() {
)} )}
{showWaylandWarning && ( {showWaylandWarning && (
<div className="agreement-overlay"> <div className="agreement-overlay">
<div className="agreement-modal"> <div className="agreement-modal">
<div className="agreement-header"> <div className="agreement-header">
<Shield size={32} /> <Shield size={32} />
<h2> (Wayland)</h2> <h2> (Wayland)</h2>
</div>
<div className="agreement-content">
<div className="agreement-text">
<p>使 <strong>Wayland</strong> </p>
<p> Wayland <strong></strong></p>
<p></p>
<br />
<p>使</p>
<p>1. <strong>X11 (Xorg)</strong> </p>
<p>2. (WM/DE) </p>
</div> </div>
</div> <div className="agreement-content">
<div className="agreement-footer"> <div className="agreement-text">
<div className="agreement-actions"> <p>使 <strong>Wayland</strong> </p>
<button className="btn btn-primary" onClick={handleDismissWaylandWarning}></button> <p> Wayland <strong></strong></p>
<p></p>
<br />
<p>使</p>
<p>1. <strong>X11 (Xorg)</strong> </p>
<p>2. (WM/DE) </p>
</div>
</div>
<div className="agreement-footer">
<div className="agreement-actions">
<button className="btn btn-primary" onClick={handleDismissWaylandWarning}></button>
</div>
</div> </div>
</div> </div>
</div> </div>
</div>
)} )}
{/* 更新提示对话框 */} {/* 更新提示对话框 */}

View File

@@ -66,8 +66,7 @@ export function ExportDefaultsSettingsForm({
images: true, images: true,
videos: true, videos: true,
voices: true, voices: true,
emojis: true, emojis: true
files: true
}) })
const [exportDefaultVoiceAsText, setExportDefaultVoiceAsText] = useState(false) const [exportDefaultVoiceAsText, setExportDefaultVoiceAsText] = useState(false)
const [exportDefaultExcelCompactColumns, setExportDefaultExcelCompactColumns] = useState(true) const [exportDefaultExcelCompactColumns, setExportDefaultExcelCompactColumns] = useState(true)
@@ -95,8 +94,7 @@ export function ExportDefaultsSettingsForm({
images: true, images: true,
videos: true, videos: true,
voices: true, voices: true,
emojis: true, emojis: true
files: true
}) })
setExportDefaultVoiceAsText(savedVoiceAsText ?? false) setExportDefaultVoiceAsText(savedVoiceAsText ?? false)
setExportDefaultExcelCompactColumns(savedExcelCompactColumns ?? true) setExportDefaultExcelCompactColumns(savedExcelCompactColumns ?? true)
@@ -294,7 +292,7 @@ export function ExportDefaultsSettingsForm({
<div className="form-group media-setting-group"> <div className="form-group media-setting-group">
<div className="form-copy"> <div className="form-copy">
<label></label> <label></label>
<span className="form-hint"></span> <span className="form-hint"></span>
</div> </div>
<div className="form-control"> <div className="form-control">
<div className="media-default-grid"> <div className="media-default-grid">
@@ -354,20 +352,6 @@ export function ExportDefaultsSettingsForm({
/> />
</label> </label>
<label>
<input
type="checkbox"
checked={exportDefaultMedia.files}
onChange={async (e) => {
const next = { ...exportDefaultMedia, files: e.target.checked }
setExportDefaultMedia(next)
await configService.setExportDefaultMedia(next)
onDefaultsChanged?.({ media: next })
notify(`${e.target.checked ? '开启' : '关闭'}默认导出文件`, true)
}}
/>
</label>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -67,7 +67,7 @@ import './ExportPage.scss'
type ConversationTab = 'private' | 'group' | 'official' | 'former_friend' type ConversationTab = 'private' | 'group' | 'official' | 'former_friend'
type TaskStatus = 'queued' | 'running' | 'success' | 'error' type TaskStatus = 'queued' | 'running' | 'success' | 'error'
type TaskScope = 'single' | 'multi' | 'content' | 'sns' type TaskScope = 'single' | 'multi' | 'content' | 'sns'
type ContentType = 'text' | 'voice' | 'image' | 'video' | 'emoji' | 'file' type ContentType = 'text' | 'voice' | 'image' | 'video' | 'emoji'
type ContentCardType = ContentType | 'sns' type ContentCardType = ContentType | 'sns'
type SnsRankMode = 'likes' | 'comments' type SnsRankMode = 'likes' | 'comments'
@@ -88,8 +88,6 @@ interface ExportOptions {
exportVoices: boolean exportVoices: boolean
exportVideos: boolean exportVideos: boolean
exportEmojis: boolean exportEmojis: boolean
exportFiles: boolean
maxFileSizeMb: number
exportVoiceAsText: boolean exportVoiceAsText: boolean
excelCompactColumns: boolean excelCompactColumns: boolean
txtColumns: string[] txtColumns: string[]
@@ -197,8 +195,7 @@ const contentTypeLabels: Record<ContentType, string> = {
voice: '语音', voice: '语音',
image: '图片', image: '图片',
video: '视频', video: '视频',
emoji: '表情包', emoji: '表情包'
file: '文件'
} }
const backgroundTaskSourceLabels: Record<string, string> = { const backgroundTaskSourceLabels: Record<string, string> = {
@@ -1601,8 +1598,7 @@ function ExportPage() {
images: true, images: true,
videos: true, videos: true,
voices: true, voices: true,
emojis: true, emojis: true
files: true
}) })
const [exportDefaultVoiceAsText, setExportDefaultVoiceAsText] = useState(false) const [exportDefaultVoiceAsText, setExportDefaultVoiceAsText] = useState(false)
const [exportDefaultExcelCompactColumns, setExportDefaultExcelCompactColumns] = useState(true) const [exportDefaultExcelCompactColumns, setExportDefaultExcelCompactColumns] = useState(true)
@@ -1621,9 +1617,7 @@ function ExportPage() {
exportImages: true, exportImages: true,
exportVoices: true, exportVoices: true,
exportVideos: true, exportVideos: true,
exportEmojis: true, exportEmojis: true,
exportFiles: true,
maxFileSizeMb: 200,
exportVoiceAsText: false, exportVoiceAsText: false,
excelCompactColumns: true, excelCompactColumns: true,
txtColumns: defaultTxtColumns, txtColumns: defaultTxtColumns,
@@ -2287,8 +2281,7 @@ function ExportPage() {
images: true, images: true,
videos: true, videos: true,
voices: true, voices: true,
emojis: true, emojis: true
files: true
}) })
setExportDefaultVoiceAsText(savedVoiceAsText ?? false) setExportDefaultVoiceAsText(savedVoiceAsText ?? false)
setExportDefaultExcelCompactColumns(savedExcelCompactColumns ?? true) setExportDefaultExcelCompactColumns(savedExcelCompactColumns ?? true)
@@ -2317,14 +2310,12 @@ function ExportPage() {
(savedMedia?.images ?? prev.exportImages) || (savedMedia?.images ?? prev.exportImages) ||
(savedMedia?.voices ?? prev.exportVoices) || (savedMedia?.voices ?? prev.exportVoices) ||
(savedMedia?.videos ?? prev.exportVideos) || (savedMedia?.videos ?? prev.exportVideos) ||
(savedMedia?.emojis ?? prev.exportEmojis) || (savedMedia?.emojis ?? prev.exportEmojis)
(savedMedia?.files ?? prev.exportFiles)
), ),
exportImages: savedMedia?.images ?? prev.exportImages, exportImages: savedMedia?.images ?? prev.exportImages,
exportVoices: savedMedia?.voices ?? prev.exportVoices, exportVoices: savedMedia?.voices ?? prev.exportVoices,
exportVideos: savedMedia?.videos ?? prev.exportVideos, exportVideos: savedMedia?.videos ?? prev.exportVideos,
exportEmojis: savedMedia?.emojis ?? prev.exportEmojis, exportEmojis: savedMedia?.emojis ?? prev.exportEmojis,
exportFiles: savedMedia?.files ?? prev.exportFiles,
exportVoiceAsText: savedVoiceAsText ?? prev.exportVoiceAsText, exportVoiceAsText: savedVoiceAsText ?? prev.exportVoiceAsText,
excelCompactColumns: savedExcelCompactColumns ?? prev.excelCompactColumns, excelCompactColumns: savedExcelCompactColumns ?? prev.excelCompactColumns,
txtColumns, txtColumns,
@@ -4097,15 +4088,12 @@ function ExportPage() {
exportDefaultMedia.images || exportDefaultMedia.images ||
exportDefaultMedia.voices || exportDefaultMedia.voices ||
exportDefaultMedia.videos || exportDefaultMedia.videos ||
exportDefaultMedia.emojis || exportDefaultMedia.emojis
exportDefaultMedia.files
), ),
exportImages: exportDefaultMedia.images, exportImages: exportDefaultMedia.images,
exportVoices: exportDefaultMedia.voices, exportVoices: exportDefaultMedia.voices,
exportVideos: exportDefaultMedia.videos, exportVideos: exportDefaultMedia.videos,
exportEmojis: exportDefaultMedia.emojis, exportEmojis: exportDefaultMedia.emojis,
exportFiles: exportDefaultMedia.files,
maxFileSizeMb: prev.maxFileSizeMb,
exportVoiceAsText: exportDefaultVoiceAsText, exportVoiceAsText: exportDefaultVoiceAsText,
excelCompactColumns: exportDefaultExcelCompactColumns, excelCompactColumns: exportDefaultExcelCompactColumns,
exportConcurrency: exportDefaultConcurrency, exportConcurrency: exportDefaultConcurrency,
@@ -4123,14 +4111,12 @@ function ExportPage() {
next.exportVoices = false next.exportVoices = false
next.exportVideos = false next.exportVideos = false
next.exportEmojis = false next.exportEmojis = false
next.exportFiles = false
} else { } else {
next.exportMedia = true next.exportMedia = true
next.exportImages = payload.contentType === 'image' next.exportImages = payload.contentType === 'image'
next.exportVoices = payload.contentType === 'voice' next.exportVoices = payload.contentType === 'voice'
next.exportVideos = payload.contentType === 'video' next.exportVideos = payload.contentType === 'video'
next.exportEmojis = payload.contentType === 'emoji' next.exportEmojis = payload.contentType === 'emoji'
next.exportFiles = payload.contentType === 'file'
next.exportVoiceAsText = false next.exportVoiceAsText = false
} }
} }
@@ -4349,13 +4335,7 @@ function ExportPage() {
const buildExportOptions = (scope: TaskScope, contentType?: ContentType): ElectronExportOptions => { const buildExportOptions = (scope: TaskScope, contentType?: ContentType): ElectronExportOptions => {
const sessionLayout: SessionLayout = writeLayout === 'C' ? 'per-session' : 'shared' const sessionLayout: SessionLayout = writeLayout === 'C' ? 'per-session' : 'shared'
const exportMediaEnabled = Boolean( const exportMediaEnabled = Boolean(options.exportImages || options.exportVoices || options.exportVideos || options.exportEmojis)
options.exportImages ||
options.exportVoices ||
options.exportVideos ||
options.exportEmojis ||
options.exportFiles
)
const base: ElectronExportOptions = { const base: ElectronExportOptions = {
format: options.format, format: options.format,
@@ -4365,8 +4345,6 @@ function ExportPage() {
exportVoices: options.exportVoices, exportVoices: options.exportVoices,
exportVideos: options.exportVideos, exportVideos: options.exportVideos,
exportEmojis: options.exportEmojis, exportEmojis: options.exportEmojis,
exportFiles: options.exportFiles,
maxFileSizeMb: options.maxFileSizeMb,
exportVoiceAsText: options.exportVoiceAsText, exportVoiceAsText: options.exportVoiceAsText,
excelCompactColumns: options.excelCompactColumns, excelCompactColumns: options.excelCompactColumns,
txtColumns: options.txtColumns, txtColumns: options.txtColumns,
@@ -4397,8 +4375,7 @@ function ExportPage() {
exportImages: false, exportImages: false,
exportVoices: false, exportVoices: false,
exportVideos: false, exportVideos: false,
exportEmojis: false, exportEmojis: false
exportFiles: false
} }
} }
@@ -4410,7 +4387,6 @@ function ExportPage() {
exportVoices: contentType === 'voice', exportVoices: contentType === 'voice',
exportVideos: contentType === 'video', exportVideos: contentType === 'video',
exportEmojis: contentType === 'emoji', exportEmojis: contentType === 'emoji',
exportFiles: contentType === 'file',
exportVoiceAsText: false exportVoiceAsText: false
} }
} }
@@ -4476,7 +4452,6 @@ function ExportPage() {
if (opts.exportVoices) labels.push('语音') if (opts.exportVoices) labels.push('语音')
if (opts.exportVideos) labels.push('视频') if (opts.exportVideos) labels.push('视频')
if (opts.exportEmojis) labels.push('表情包') if (opts.exportEmojis) labels.push('表情包')
if (opts.exportFiles) labels.push('文件')
} }
return Array.from(new Set(labels)).join('、') return Array.from(new Set(labels)).join('、')
}, []) }, [])
@@ -4532,7 +4507,6 @@ function ExportPage() {
if (opts.exportImages) types.push('image') if (opts.exportImages) types.push('image')
if (opts.exportVideos) types.push('video') if (opts.exportVideos) types.push('video')
if (opts.exportEmojis) types.push('emoji') if (opts.exportEmojis) types.push('emoji')
if (opts.exportFiles) types.push('file')
} }
return types return types
} }
@@ -4963,8 +4937,7 @@ function ExportPage() {
images: options.exportImages, images: options.exportImages,
voices: options.exportVoices, voices: options.exportVoices,
videos: options.exportVideos, videos: options.exportVideos,
emojis: options.exportEmojis, emojis: options.exportEmojis
files: options.exportFiles
}) })
await configService.setExportDefaultVoiceAsText(options.exportVoiceAsText) await configService.setExportDefaultVoiceAsText(options.exportVoiceAsText)
await configService.setExportDefaultExcelCompactColumns(options.excelCompactColumns) await configService.setExportDefaultExcelCompactColumns(options.excelCompactColumns)
@@ -6982,12 +6955,11 @@ function ExportPage() {
setExportDefaultMedia(mediaPatch) setExportDefaultMedia(mediaPatch)
setOptions(prev => ({ setOptions(prev => ({
...prev, ...prev,
exportMedia: Boolean(mediaPatch.images || mediaPatch.voices || mediaPatch.videos || mediaPatch.emojis || mediaPatch.files), exportMedia: Boolean(mediaPatch.images || mediaPatch.voices || mediaPatch.videos || mediaPatch.emojis),
exportImages: mediaPatch.images, exportImages: mediaPatch.images,
exportVoices: mediaPatch.voices, exportVoices: mediaPatch.voices,
exportVideos: mediaPatch.videos, exportVideos: mediaPatch.videos,
exportEmojis: mediaPatch.emojis, exportEmojis: mediaPatch.emojis
exportFiles: mediaPatch.files
})) }))
} }
if (typeof patch.voiceAsText === 'boolean') { if (typeof patch.voiceAsText === 'boolean') {
@@ -8187,36 +8159,15 @@ function ExportPage() {
<label><input type="checkbox" checked={options.exportVoices} onChange={event => setOptions(prev => ({ ...prev, exportVoices: event.target.checked }))} /> </label> <label><input type="checkbox" checked={options.exportVoices} onChange={event => setOptions(prev => ({ ...prev, exportVoices: event.target.checked }))} /> </label>
<label><input type="checkbox" checked={options.exportVideos} onChange={event => setOptions(prev => ({ ...prev, exportVideos: event.target.checked }))} /> </label> <label><input type="checkbox" checked={options.exportVideos} onChange={event => setOptions(prev => ({ ...prev, exportVideos: event.target.checked }))} /> </label>
<label><input type="checkbox" checked={options.exportEmojis} onChange={event => setOptions(prev => ({ ...prev, exportEmojis: event.target.checked }))} /> </label> <label><input type="checkbox" checked={options.exportEmojis} onChange={event => setOptions(prev => ({ ...prev, exportEmojis: event.target.checked }))} /> </label>
<label><input type="checkbox" checked={options.exportFiles} onChange={event => setOptions(prev => ({ ...prev, exportFiles: event.target.checked }))} /> </label>
</> </>
)} )}
</div> </div>
{exportDialog.scope !== 'sns' && options.exportFiles && ( {exportDialog.scope === 'sns' && (
<div className="format-note">使 MD5 </div> <div className="format-note"></div>
)} )}
</div> </div>
)} )}
{shouldShowMediaSection && exportDialog.scope !== 'sns' && options.exportFiles && (
<div className="dialog-section">
<h4></h4>
<div className="format-note">0 </div>
<div className="dialog-input-row">
<input
type="number"
min={0}
step={10}
value={options.maxFileSizeMb}
onChange={event => {
const raw = Number(event.target.value)
setOptions(prev => ({ ...prev, maxFileSizeMb: Number.isFinite(raw) ? Math.max(0, Math.floor(raw)) : 0 }))
}}
/>
<span>MB</span>
</div>
</div>
)}
{shouldShowImageDeepSearchToggle && ( {shouldShowImageDeepSearchToggle && (
<div className="dialog-section"> <div className="dialog-section">
<div className="dialog-switch-row"> <div className="dialog-switch-row">

View File

@@ -2508,9 +2508,7 @@ function SettingsPage({ onClose }: SettingsPageProps = {}) {
<div className="about-footer"> <div className="about-footer">
<p className="about-desc"></p> <p className="about-desc"></p>
<div className="about-links"> <div className="about-links">
<a href="#" onClick={(e) => { e.preventDefault(); window.electronAPI.shell.openExternal('https://weflow.top') }}></a> <a href="#" onClick={(e) => { e.preventDefault(); window.electronAPI.shell.openExternal('https://github.com/hicccc77/WeFlow') }}></a>
<span>·</span>
<a href="#" onClick={(e) => { e.preventDefault(); window.electronAPI.shell.openExternal('https://github.com/hicccc77/WeFlow') }}>GitHub </a>
<span>·</span> <span>·</span>
<a href="#" onClick={(e) => { e.preventDefault(); window.electronAPI.shell.openExternal('https://chatlab.fun') }}>ChatLab</a> <a href="#" onClick={(e) => { e.preventDefault(); window.electronAPI.shell.openExternal('https://chatlab.fun') }}>ChatLab</a>
<span>·</span> <span>·</span>

View File

@@ -94,7 +94,6 @@ export interface ExportDefaultMediaConfig {
videos: boolean videos: boolean
voices: boolean voices: boolean
emojis: boolean emojis: boolean
files: boolean
} }
export type WindowCloseBehavior = 'ask' | 'tray' | 'quit' export type WindowCloseBehavior = 'ask' | 'tray' | 'quit'
@@ -105,8 +104,7 @@ const DEFAULT_EXPORT_MEDIA_CONFIG: ExportDefaultMediaConfig = {
images: true, images: true,
videos: true, videos: true,
voices: true, voices: true,
emojis: true, emojis: true
files: true
} }
// 获取解密密钥 // 获取解密密钥
@@ -425,8 +423,7 @@ export async function getExportDefaultMedia(): Promise<ExportDefaultMediaConfig
images: value, images: value,
videos: value, videos: value,
voices: value, voices: value,
emojis: value, emojis: value
files: value
} }
} }
if (value && typeof value === 'object') { if (value && typeof value === 'object') {
@@ -435,8 +432,7 @@ export async function getExportDefaultMedia(): Promise<ExportDefaultMediaConfig
images: typeof raw.images === 'boolean' ? raw.images : DEFAULT_EXPORT_MEDIA_CONFIG.images, images: typeof raw.images === 'boolean' ? raw.images : DEFAULT_EXPORT_MEDIA_CONFIG.images,
videos: typeof raw.videos === 'boolean' ? raw.videos : DEFAULT_EXPORT_MEDIA_CONFIG.videos, videos: typeof raw.videos === 'boolean' ? raw.videos : DEFAULT_EXPORT_MEDIA_CONFIG.videos,
voices: typeof raw.voices === 'boolean' ? raw.voices : DEFAULT_EXPORT_MEDIA_CONFIG.voices, voices: typeof raw.voices === 'boolean' ? raw.voices : DEFAULT_EXPORT_MEDIA_CONFIG.voices,
emojis: typeof raw.emojis === 'boolean' ? raw.emojis : DEFAULT_EXPORT_MEDIA_CONFIG.emojis, emojis: typeof raw.emojis === 'boolean' ? raw.emojis : DEFAULT_EXPORT_MEDIA_CONFIG.emojis
files: typeof raw.files === 'boolean' ? raw.files : DEFAULT_EXPORT_MEDIA_CONFIG.files
} }
} }
return null return null
@@ -448,8 +444,7 @@ export async function setExportDefaultMedia(media: ExportDefaultMediaConfig): Pr
images: media.images, images: media.images,
videos: media.videos, videos: media.videos,
voices: media.voices, voices: media.voices,
emojis: media.emojis, emojis: media.emojis
files: media.files
}) })
} }

View File

@@ -881,7 +881,7 @@ export interface ElectronAPI {
export interface ExportOptions { export interface ExportOptions {
format: 'chatlab' | 'chatlab-jsonl' | 'json' | 'arkme-json' | 'html' | 'txt' | 'excel' | 'weclone' | 'sql' format: 'chatlab' | 'chatlab-jsonl' | 'json' | 'arkme-json' | 'html' | 'txt' | 'excel' | 'weclone' | 'sql'
contentType?: 'text' | 'voice' | 'image' | 'video' | 'emoji' | 'file' contentType?: 'text' | 'voice' | 'image' | 'video' | 'emoji'
dateRange?: { start: number; end: number } | null dateRange?: { start: number; end: number } | null
senderUsername?: string senderUsername?: string
fileNameSuffix?: string fileNameSuffix?: string
@@ -891,8 +891,6 @@ export interface ExportOptions {
exportVoices?: boolean exportVoices?: boolean
exportVideos?: boolean exportVideos?: boolean
exportEmojis?: boolean exportEmojis?: boolean
exportFiles?: boolean
maxFileSizeMb?: number
exportVoiceAsText?: boolean exportVoiceAsText?: boolean
excelCompactColumns?: boolean excelCompactColumns?: boolean
txtColumns?: string[] txtColumns?: string[]

View File

@@ -75,7 +75,6 @@ export interface Message {
fileName?: string // 文件名 fileName?: string // 文件名
fileSize?: number // 文件大小 fileSize?: number // 文件大小
fileExt?: string // 文件扩展名 fileExt?: string // 文件扩展名
fileMd5?: string // 文件 MD5
xmlType?: string // XML 中的 type 字段 xmlType?: string // XML 中的 type 字段
appMsgKind?: string // 归一化 appmsg 类型 appMsgKind?: string // 归一化 appmsg 类型
appMsgDesc?: string appMsgDesc?: string