mirror of
https://github.com/hicccc77/WeFlow.git
synced 2026-03-25 15:25:50 +00:00
@@ -142,6 +142,12 @@ class ExportService {
|
|||||||
this.configService = new ConfigService()
|
this.configService = new ConfigService()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private getClampedConcurrency(value: number | undefined, fallback = 2, max = 6): number {
|
||||||
|
if (typeof value !== 'number' || !Number.isFinite(value)) return fallback
|
||||||
|
const raw = Math.floor(value)
|
||||||
|
return Math.max(1, Math.min(raw, max))
|
||||||
|
}
|
||||||
|
|
||||||
private cleanAccountDirName(dirName: string): string {
|
private cleanAccountDirName(dirName: string): string {
|
||||||
const trimmed = dirName.trim()
|
const trimmed = dirName.trim()
|
||||||
if (!trimmed) return trimmed
|
if (!trimmed) return trimmed
|
||||||
@@ -1740,9 +1746,9 @@ class ExportService {
|
|||||||
phase: 'exporting-media'
|
phase: 'exporting-media'
|
||||||
})
|
})
|
||||||
|
|
||||||
// 并行导出媒体,限制 8 个并发
|
// 并行导出媒体,并发数跟随导出设置
|
||||||
const MEDIA_CONCURRENCY = 8
|
const mediaConcurrency = this.getClampedConcurrency(options.exportConcurrency)
|
||||||
await parallelLimit(mediaMessages, MEDIA_CONCURRENCY, async (msg) => {
|
await parallelLimit(mediaMessages, mediaConcurrency, async (msg) => {
|
||||||
const mediaKey = `${msg.localType}_${msg.localId}`
|
const mediaKey = `${msg.localType}_${msg.localId}`
|
||||||
if (!mediaCache.has(mediaKey)) {
|
if (!mediaCache.has(mediaKey)) {
|
||||||
const mediaItem = await this.exportMediaForMessage(msg, sessionId, mediaRootDir, mediaRelativePrefix, {
|
const mediaItem = await this.exportMediaForMessage(msg, sessionId, mediaRootDir, mediaRelativePrefix, {
|
||||||
@@ -1956,8 +1962,8 @@ class ExportService {
|
|||||||
phase: 'exporting-media'
|
phase: 'exporting-media'
|
||||||
})
|
})
|
||||||
|
|
||||||
const MEDIA_CONCURRENCY = 8
|
const mediaConcurrency = this.getClampedConcurrency(options.exportConcurrency)
|
||||||
await parallelLimit(mediaMessages, MEDIA_CONCURRENCY, async (msg) => {
|
await parallelLimit(mediaMessages, mediaConcurrency, async (msg) => {
|
||||||
const mediaKey = `${msg.localType}_${msg.localId}`
|
const mediaKey = `${msg.localType}_${msg.localId}`
|
||||||
if (!mediaCache.has(mediaKey)) {
|
if (!mediaCache.has(mediaKey)) {
|
||||||
const mediaItem = await this.exportMediaForMessage(msg, sessionId, mediaRootDir, mediaRelativePrefix, {
|
const mediaItem = await this.exportMediaForMessage(msg, sessionId, mediaRootDir, mediaRelativePrefix, {
|
||||||
@@ -2348,8 +2354,8 @@ class ExportService {
|
|||||||
phase: 'exporting-media'
|
phase: 'exporting-media'
|
||||||
})
|
})
|
||||||
|
|
||||||
const MEDIA_CONCURRENCY = 8
|
const mediaConcurrency = this.getClampedConcurrency(options.exportConcurrency)
|
||||||
await parallelLimit(mediaMessages, MEDIA_CONCURRENCY, async (msg) => {
|
await parallelLimit(mediaMessages, mediaConcurrency, async (msg) => {
|
||||||
const mediaKey = `${msg.localType}_${msg.localId}`
|
const mediaKey = `${msg.localType}_${msg.localId}`
|
||||||
if (!mediaCache.has(mediaKey)) {
|
if (!mediaCache.has(mediaKey)) {
|
||||||
const mediaItem = await this.exportMediaForMessage(msg, sessionId, mediaRootDir, mediaRelativePrefix, {
|
const mediaItem = await this.exportMediaForMessage(msg, sessionId, mediaRootDir, mediaRelativePrefix, {
|
||||||
@@ -2653,8 +2659,8 @@ class ExportService {
|
|||||||
phase: 'exporting-media'
|
phase: 'exporting-media'
|
||||||
})
|
})
|
||||||
|
|
||||||
const MEDIA_CONCURRENCY = 8
|
const mediaConcurrency = this.getClampedConcurrency(options.exportConcurrency)
|
||||||
await parallelLimit(mediaMessages, MEDIA_CONCURRENCY, async (msg) => {
|
await parallelLimit(mediaMessages, mediaConcurrency, async (msg) => {
|
||||||
const mediaKey = `${msg.localType}_${msg.localId}`
|
const mediaKey = `${msg.localType}_${msg.localId}`
|
||||||
if (!mediaCache.has(mediaKey)) {
|
if (!mediaCache.has(mediaKey)) {
|
||||||
const mediaItem = await this.exportMediaForMessage(msg, sessionId, mediaRootDir, mediaRelativePrefix, {
|
const mediaItem = await this.exportMediaForMessage(msg, sessionId, mediaRootDir, mediaRelativePrefix, {
|
||||||
|
|||||||
@@ -373,7 +373,7 @@ function SettingsPage() {
|
|||||||
|
|
||||||
const applyWxidSelection = async (
|
const applyWxidSelection = async (
|
||||||
selectedWxid: string,
|
selectedWxid: string,
|
||||||
options?: { preferCurrentKeys?: boolean; showToast?: boolean; toastText?: string }
|
options?: { preferCurrentKeys?: boolean; showToast?: boolean; toastText?: string; keysOverride?: WxidKeys }
|
||||||
) => {
|
) => {
|
||||||
if (!selectedWxid) return
|
if (!selectedWxid) return
|
||||||
|
|
||||||
@@ -389,9 +389,9 @@ function SettingsPage() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const preferCurrentKeys = options?.preferCurrentKeys ?? false
|
const preferCurrentKeys = options?.preferCurrentKeys ?? false
|
||||||
const keys = preferCurrentKeys
|
const keys = options?.keysOverride ?? (preferCurrentKeys
|
||||||
? buildKeysFromState()
|
? buildKeysFromState()
|
||||||
: buildKeysFromConfig(await configService.getWxidConfig(selectedWxid))
|
: buildKeysFromConfig(await configService.getWxidConfig(selectedWxid)))
|
||||||
|
|
||||||
setWxid(selectedWxid)
|
setWxid(selectedWxid)
|
||||||
applyKeysToState(keys)
|
applyKeysToState(keys)
|
||||||
@@ -471,7 +471,7 @@ function SettingsPage() {
|
|||||||
|
|
||||||
const handleScanWxid = async (
|
const handleScanWxid = async (
|
||||||
silent = false,
|
silent = false,
|
||||||
options?: { preferCurrentKeys?: boolean; showDialog?: boolean }
|
options?: { preferCurrentKeys?: boolean; showDialog?: boolean; keysOverride?: WxidKeys }
|
||||||
) => {
|
) => {
|
||||||
if (!dbPath) {
|
if (!dbPath) {
|
||||||
if (!silent) showMessage('请先选择数据库目录', false)
|
if (!silent) showMessage('请先选择数据库目录', false)
|
||||||
@@ -485,7 +485,8 @@ function SettingsPage() {
|
|||||||
await applyWxidSelection(wxids[0].wxid, {
|
await applyWxidSelection(wxids[0].wxid, {
|
||||||
preferCurrentKeys: options?.preferCurrentKeys ?? false,
|
preferCurrentKeys: options?.preferCurrentKeys ?? false,
|
||||||
showToast: !silent,
|
showToast: !silent,
|
||||||
toastText: `已检测到账号:${wxids[0].wxid}`
|
toastText: `已检测到账号:${wxids[0].wxid}`,
|
||||||
|
keysOverride: options?.keysOverride
|
||||||
})
|
})
|
||||||
} else if (wxids.length > 1 && allowDialog) {
|
} else if (wxids.length > 1 && allowDialog) {
|
||||||
setShowWxidSelect(true)
|
setShowWxidSelect(true)
|
||||||
@@ -573,7 +574,9 @@ function SettingsPage() {
|
|||||||
setDecryptKey(result.key)
|
setDecryptKey(result.key)
|
||||||
setDbKeyStatus('密钥获取成功')
|
setDbKeyStatus('密钥获取成功')
|
||||||
showMessage('已自动获取解密密钥', true)
|
showMessage('已自动获取解密密钥', true)
|
||||||
await handleScanWxid(true, { preferCurrentKeys: true, showDialog: false })
|
await syncCurrentKeys({ decryptKey: result.key, wxid })
|
||||||
|
const keysOverride = buildKeysFromInputs({ decryptKey: result.key })
|
||||||
|
await handleScanWxid(true, { preferCurrentKeys: true, showDialog: false, keysOverride })
|
||||||
} else {
|
} else {
|
||||||
if (result.error?.includes('未找到微信安装路径') || result.error?.includes('启动微信失败')) {
|
if (result.error?.includes('未找到微信安装路径') || result.error?.includes('启动微信失败')) {
|
||||||
setIsManualStartPrompt(true)
|
setIsManualStartPrompt(true)
|
||||||
@@ -840,7 +843,7 @@ function SettingsPage() {
|
|||||||
const value = e.target.value
|
const value = e.target.value
|
||||||
setDecryptKey(value)
|
setDecryptKey(value)
|
||||||
if (value && value.length === 64) {
|
if (value && value.length === 64) {
|
||||||
scheduleConfigSave('keys', () => syncCurrentKeys({ decryptKey: value }))
|
scheduleConfigSave('keys', () => syncCurrentKeys({ decryptKey: value, wxid }))
|
||||||
// showMessage('解密密钥已保存', true)
|
// showMessage('解密密钥已保存', true)
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
@@ -900,12 +903,40 @@ function SettingsPage() {
|
|||||||
value={wxid}
|
value={wxid}
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
const value = e.target.value
|
const value = e.target.value
|
||||||
|
const previousWxid = wxid
|
||||||
setWxid(value)
|
setWxid(value)
|
||||||
scheduleConfigSave('wxid', async () => {
|
scheduleConfigSave('wxid', async () => {
|
||||||
|
if (previousWxid && previousWxid !== value) {
|
||||||
|
const currentKeys = buildKeysFromState()
|
||||||
|
await configService.setWxidConfig(previousWxid, {
|
||||||
|
decryptKey: currentKeys.decryptKey,
|
||||||
|
imageXorKey: typeof currentKeys.imageXorKey === 'number' ? currentKeys.imageXorKey : 0,
|
||||||
|
imageAesKey: currentKeys.imageAesKey
|
||||||
|
})
|
||||||
|
}
|
||||||
if (value) {
|
if (value) {
|
||||||
await configService.setMyWxid(value)
|
await configService.setMyWxid(value)
|
||||||
await syncCurrentKeys({ wxid: value }) // Sync keys to the new wxid entry
|
await syncCurrentKeys({ wxid: value }) // Sync keys to the new wxid entry
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (value && previousWxid !== value) {
|
||||||
|
if (isDbConnected) {
|
||||||
|
try {
|
||||||
|
await window.electronAPI.chat.close()
|
||||||
|
const result = await window.electronAPI.chat.connect()
|
||||||
|
setDbConnected(result.success, dbPath || undefined)
|
||||||
|
if (!result.success && result.error) {
|
||||||
|
showMessage(result.error, false)
|
||||||
|
}
|
||||||
|
} catch (e: any) {
|
||||||
|
showMessage(`切换账号后重新连接失败: ${e}`, false)
|
||||||
|
setDbConnected(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
clearAnalyticsStoreCache()
|
||||||
|
resetChatStore()
|
||||||
|
window.dispatchEvent(new CustomEvent('wxid-changed', { detail: { wxid: value } }))
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
@@ -925,7 +956,7 @@ function SettingsPage() {
|
|||||||
setImageXorKey(value)
|
setImageXorKey(value)
|
||||||
const parsed = parseImageXorKey(value)
|
const parsed = parseImageXorKey(value)
|
||||||
if (value === '' || parsed !== null) {
|
if (value === '' || parsed !== null) {
|
||||||
scheduleConfigSave('keys', () => syncCurrentKeys({ imageXorKey: value }))
|
scheduleConfigSave('keys', () => syncCurrentKeys({ imageXorKey: value, wxid }))
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
@@ -941,7 +972,7 @@ function SettingsPage() {
|
|||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
const value = e.target.value
|
const value = e.target.value
|
||||||
setImageAesKey(value)
|
setImageAesKey(value)
|
||||||
scheduleConfigSave('keys', () => syncCurrentKeys({ imageAesKey: value }))
|
scheduleConfigSave('keys', () => syncCurrentKeys({ imageAesKey: value, wxid }))
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<button className="btn btn-secondary btn-sm" onClick={handleAutoGetImageKey} disabled={isFetchingImageKey}>
|
<button className="btn btn-secondary btn-sm" onClick={handleAutoGetImageKey} disabled={isFetchingImageKey}>
|
||||||
|
|||||||
Reference in New Issue
Block a user