From 1930b91a5bff009fe61d51ca29147d5f48330e9f Mon Sep 17 00:00:00 2001 From: xuncha <1658671838@qq.com> Date: Mon, 16 Feb 2026 17:26:06 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- electron/services/config.ts | 2 ++ electron/services/snsService.ts | 34 +++++++++++++---------- src/pages/SettingsPage.tsx | 49 +++++++++++++++++++++++++++++++++ src/pages/SnsPage.tsx | 2 +- src/services/config.ts | 12 ++++++++ 5 files changed, 84 insertions(+), 15 deletions(-) diff --git a/electron/services/config.ts b/electron/services/config.ts index 7db11c2..4eb0f2b 100644 --- a/electron/services/config.ts +++ b/electron/services/config.ts @@ -12,6 +12,7 @@ interface ConfigSchema { // 缓存相关 cachePath: string + weixinDllPath: string lastOpenedDb: string lastSession: string @@ -72,6 +73,7 @@ export class ConfigService { imageAesKey: '', wxidConfigs: {}, cachePath: '', + weixinDllPath: '', lastOpenedDb: '', lastSession: '', theme: 'system', diff --git a/electron/services/snsService.ts b/electron/services/snsService.ts index 7f29f23..299cecc 100644 --- a/electron/services/snsService.ts +++ b/electron/services/snsService.ts @@ -75,6 +75,7 @@ const detectImageMime = (buf: Buffer, fallback: string = 'image/jpeg') => { } class SnsService { + private configService: ConfigService private contactCache: ContactCacheService private imageCache = new Map() @@ -87,8 +88,8 @@ class SnsService { private nativeDecryptFn: any = null constructor() { - const config = new ConfigService() - this.contactCache = new ContactCacheService(config.get('cachePath') as string) + this.configService = new ConfigService() + this.contactCache = new ContactCacheService(this.configService.get('cachePath') as string) } async getTimeline(limit: number = 20, offset: number = 0, usernames?: string[], keyword?: string, startTime?: number, endTime?: number): Promise<{ success: boolean; timeline?: SnsPost[]; error?: string }> { @@ -182,11 +183,14 @@ class SnsService { return null } } - private resolveWeixinDllPath(): string | null { const candidates: string[] = [] + if (process.env.WEFLOW_WEIXIN_DLL) candidates.push(process.env.WEFLOW_WEIXIN_DLL) + const configuredPath = String(this.configService.get('weixinDllPath') || '').trim() + if (configuredPath) candidates.push(configuredPath) + const weixinExe = process.env.WEFLOW_WEIXIN_EXE if (weixinExe) { const dir = weixinExe.replace(/\\Weixin\.exe$/i, '') @@ -195,27 +199,32 @@ class SnsService { const programFiles = process.env.ProgramFiles || 'C:\\Program Files' const localAppData = process.env.LOCALAPPDATA || '' - candidates.push( - join(programFiles, 'Tencent', 'Weixin', 'Weixin.dll'), - 'D:\\weixindata\\Weixin\\Weixin.dll', - 'C:\\Users\\16586\\Desktop\\sns\\Weixin.dll' - ) + candidates.push(join(programFiles, 'Tencent', 'Weixin', 'Weixin.dll')) if (localAppData) candidates.push(join(localAppData, 'Tencent', 'xwechat', 'Weixin.dll')) + const seen = new Set() for (const p of candidates) { - if (p && existsSync(p)) return p + if (!p) continue + const normalized = p.trim() + if (!normalized || seen.has(normalized)) continue + seen.add(normalized) + if (existsSync(normalized)) return normalized } return null } - private ensureNativeDecryptor(): boolean { + const configuredPath = String(this.configService.get('weixinDllPath') || '').trim() + if (this.nativeDecryptInit && !this.nativeDecryptReady && configuredPath && configuredPath !== this.nativeDecryptDllPath) { + this.nativeDecryptInit = false + } + if (this.nativeDecryptInit) return this.nativeDecryptReady this.nativeDecryptInit = true try { const dllPath = this.resolveWeixinDllPath() if (!dllPath) { - this.nativeDecryptError = 'Weixin.dll not found, set WEFLOW_WEIXIN_DLL if needed' + this.nativeDecryptError = 'Weixin.dll not found, please set it in Settings or WEFLOW_WEIXIN_DLL' return false } @@ -349,6 +358,3 @@ class SnsService { } export const snsService = new SnsService() - - - diff --git a/src/pages/SettingsPage.tsx b/src/pages/SettingsPage.tsx index 860b4f7..593e67a 100644 --- a/src/pages/SettingsPage.tsx +++ b/src/pages/SettingsPage.tsx @@ -74,6 +74,7 @@ function SettingsPage() { const exportExcelColumnsDropdownRef = useRef(null) const exportConcurrencyDropdownRef = useRef(null) const [cachePath, setCachePath] = useState('') + const [weixinDllPath, setWeixinDllPath] = useState('') const [logEnabled, setLogEnabled] = useState(false) const [whisperModelName, setWhisperModelName] = useState('base') const [whisperModelDir, setWhisperModelDir] = useState('') @@ -249,6 +250,7 @@ function SettingsPage() { const savedPath = await configService.getDbPath() const savedWxid = await configService.getMyWxid() const savedCachePath = await configService.getCachePath() + const savedWeixinDllPath = await configService.getWeixinDllPath() const savedExportPath = await configService.getExportPath() const savedLogEnabled = await configService.getLogEnabled() const savedImageXorKey = await configService.getImageXorKey() @@ -277,6 +279,7 @@ function SettingsPage() { if (savedPath) setDbPath(savedPath) if (savedWxid) setWxid(savedWxid) if (savedCachePath) setCachePath(savedCachePath) + if (savedWeixinDllPath) setWeixinDllPath(savedWeixinDllPath) const wxidConfig = savedWxid ? await configService.getWxidConfig(savedWxid) : null const decryptKeyToUse = wxidConfig?.decryptKey ?? savedKey ?? '' @@ -613,6 +616,29 @@ function SettingsPage() { await applyWxidSelection(selectedWxid) } + const handleSelectWeixinDllPath = async () => { + try { + const result = await dialog.openFile({ + title: '选择 Weixin.dll 文件', + properties: ['openFile'], + filters: [{ name: 'DLL', extensions: ['dll'] }] + }) + if (!result.canceled && result.filePaths.length > 0) { + const selectedPath = result.filePaths[0] + setWeixinDllPath(selectedPath) + await configService.setWeixinDllPath(selectedPath) + showMessage('已选择 Weixin.dll 路径', true) + } + } catch { + showMessage('选择 Weixin.dll 失败', false) + } + } + + const handleResetWeixinDllPath = async () => { + setWeixinDllPath('') + await configService.setWeixinDllPath('') + showMessage('已清空 Weixin.dll 路径', true) + } const handleSelectCachePath = async () => { try { const result = await dialog.openFile({ title: '选择缓存目录', properties: ['openDirectory'] }) @@ -1306,6 +1332,29 @@ function SettingsPage() { +
+ + 用于朋友圈在线图片原生解密,优先使用这里配置的 DLL + { + const value = e.target.value + setWeixinDllPath(value) + scheduleConfigSave('weixinDllPath', () => configService.setWeixinDllPath(value)) + }} + /> +
+ + +
+
+
微信账号标识 diff --git a/src/pages/SnsPage.tsx b/src/pages/SnsPage.tsx index d3ee527..b925752 100644 --- a/src/pages/SnsPage.tsx +++ b/src/pages/SnsPage.tsx @@ -434,7 +434,7 @@ export default function SnsPage() {
- 由于技术限制,当前无法解密显示部分图片与视频等加密资源文件 + 由于技术限制,当前无法解密显示视频加密资源文件
diff --git a/src/services/config.ts b/src/services/config.ts index 0389636..684bdcf 100644 --- a/src/services/config.ts +++ b/src/services/config.ts @@ -12,6 +12,7 @@ export const CONFIG_KEYS = { LAST_SESSION: 'lastSession', WINDOW_BOUNDS: 'windowBounds', CACHE_PATH: 'cachePath', + WEIXIN_DLL_PATH: 'weixinDllPath', EXPORT_PATH: 'exportPath', AGREEMENT_ACCEPTED: 'agreementAccepted', LOG_ENABLED: 'logEnabled', @@ -162,6 +163,17 @@ export async function setCachePath(path: string): Promise { } +// 获取 Weixin.dll 路径 +export async function getWeixinDllPath(): Promise { + const value = await config.get(CONFIG_KEYS.WEIXIN_DLL_PATH) + return value as string | null +} + +// 设置 Weixin.dll 路径 +export async function setWeixinDllPath(path: string): Promise { + await config.set(CONFIG_KEYS.WEIXIN_DLL_PATH, path) +} + // 获取导出路径 export async function getExportPath(): Promise { const value = await config.get(CONFIG_KEYS.EXPORT_PATH)