Files
CipherTalk/scripts/sync-image-native.cjs
ILoveBingLu bb2e6ef2ff 发布 4.2.0:优化图片解密与聊天滚动体验
本次提交将应用版本更新到 4.2.0,并同步更新 package-lock、README 版本徽标和 CHANGELOG 发布说明。

主要变更:
- 接入 CipherTalk 自研图片 DAT 原生解密模块,替换原先迁移自 WeFlow 的命名与资源落点。
- 新增 Windows x64 与 macOS arm64 的预编译 native addon 资源,并补充 manifest、检查脚本和同步脚本。
- 保留 native 优先、TypeScript 兜底的图片解密链路,兼容 V3/V4 图片、wxgf 后处理、缓存命中、高清图回退和实况照片提取。
- 优化图片解密服务的缓存校验、wxgf/HEVC 白图规避、耗时诊断和默认日志输出,减少线上噪音。
- 聊天消息列表改为动态高度虚拟列表,卸载屏幕外消息 DOM 与图片节点,降低长会话内存和渲染压力。
- 修复虚拟列表初始挂载时滚底与顶部历史预加载互相打架导致界面上下晃动的问题。
- 顶部历史消息改为接近顶部并向上滚动时提前加载,同时加强 prepend 后的滚动位置恢复。
- 解析图片 XML 中的宽高信息,并用于聊天图片骨架屏、未解密占位、已解密图片和图片查看器初始窗口尺寸。
- 打包清理逻辑改为按当前平台保留对应 native addon,避免安装包携带无关平台产物。

验证:
- 已执行 npx tsc --noEmit,通过 TypeScript 类型检查。
- 本地未执行应用构建,发布构建交由 GitHub Actions 的 tag 发布工作流完成。
2026-04-21 04:44:47 +08:00

127 lines
4.1 KiB
JavaScript

const fs = require('node:fs')
const path = require('node:path')
const projectRoot = path.resolve(__dirname, '..')
const crateRoot = path.join(projectRoot, 'native', 'image-decrypt')
const releaseDir = path.join(crateRoot, 'target', 'release')
const addonName = 'ciphertalk-image-native'
function parseArgs(argv) {
const parsed = {}
for (let i = 0; i < argv.length; i += 1) {
const arg = argv[i]
if (!arg.startsWith('--')) continue
const key = arg.slice(2)
const next = argv[i + 1]
if (!next || next.startsWith('--')) {
parsed[key] = '1'
continue
}
parsed[key] = next
i += 1
}
return parsed
}
function resolvePlatformDir(value = process.platform) {
if (value === 'win32') return 'win32'
if (value === 'darwin' || value === 'macos') return 'macos'
if (value === 'linux') return 'linux'
throw new Error(`Unsupported platform: ${value}`)
}
function resolveArchDir(value = process.arch) {
if (value === 'x64') return 'x64'
if (value === 'arm64') return 'arm64'
throw new Error(`Unsupported arch: ${value}`)
}
function resolveBuiltLibrary(platformDir, customLibPath) {
if (customLibPath) {
return path.resolve(projectRoot, customLibPath)
}
if (platformDir === 'win32') {
return path.join(releaseDir, 'ciphertalk_image_native.dll')
}
if (platformDir === 'macos') {
return path.join(releaseDir, 'libciphertalk_image_native.dylib')
}
if (platformDir === 'linux') {
return path.join(releaseDir, 'libciphertalk_image_native.so')
}
throw new Error(`Unsupported platform: ${platformDir}`)
}
function removeLegacyOutput(platformDir, archDir, outputName) {
const legacyDir = path.join(projectRoot, 'resources', 'wedecrypt', platformDir, archDir)
const legacyPath = path.join(legacyDir, outputName)
if (fs.existsSync(legacyPath)) {
fs.rmSync(legacyPath, { force: true })
}
if (fs.existsSync(legacyDir) && fs.readdirSync(legacyDir).length === 0) {
fs.rmSync(legacyDir, { recursive: true, force: true })
}
const platformDirPath = path.join(projectRoot, 'resources', 'wedecrypt', platformDir)
if (fs.existsSync(platformDirPath) && fs.readdirSync(platformDirPath).length === 0) {
fs.rmSync(platformDirPath, { recursive: true, force: true })
}
}
function buildManifest() {
const baseDir = path.join(projectRoot, 'resources', 'wedecrypt')
const matrix = [
['win32', 'x64'],
['win32', 'arm64'],
['macos', 'x64'],
['macos', 'arm64'],
['linux', 'x64'],
['linux', 'arm64']
]
const activeBinaries = {}
const platforms = []
for (const [platformDir, archDir] of matrix) {
const filePath = path.join(baseDir, `${addonName}-${platformDir}-${archDir}.node`)
if (!fs.existsSync(filePath)) continue
const key = `${platformDir}-${archDir}`
activeBinaries[key] = 'self-built-from-repo-source'
platforms.push(key)
}
const manifest = {
name: addonName,
version: 'source-present-selfbuilt',
vendor: 'CipherTalk',
source: 'native/image-decrypt',
activeBinaries,
platforms
}
fs.mkdirSync(baseDir, { recursive: true })
fs.writeFileSync(path.join(baseDir, 'manifest.json'), `${JSON.stringify(manifest, null, 2)}\n`)
}
function main() {
const args = parseArgs(process.argv.slice(2))
const platformDir = resolvePlatformDir(args.platform || process.env.CIPHERTALK_IMAGE_NATIVE_PLATFORM || process.platform)
const archDir = resolveArchDir(args.arch || process.env.CIPHERTALK_IMAGE_NATIVE_ARCH || process.arch)
const builtLibrary = resolveBuiltLibrary(platformDir, args.lib || process.env.CIPHERTALK_IMAGE_NATIVE_LIB)
if (!fs.existsSync(builtLibrary)) {
throw new Error(`Built library not found: ${builtLibrary}`)
}
const outputDir = path.join(projectRoot, 'resources', 'wedecrypt')
const outputName = `${addonName}-${platformDir}-${archDir}.node`
const outputPath = path.join(outputDir, outputName)
fs.mkdirSync(outputDir, { recursive: true })
fs.copyFileSync(builtLibrary, outputPath)
removeLegacyOutput(platformDir, archDir, outputName)
buildManifest()
console.log(`[sync-image-native] synced ${builtLibrary} -> ${outputPath}`)
}
main()