import fs from 'fs' import path from 'path' import { localizeImage } from './image-localizer' /** * 从JSON文件提取图片URL并下载到本地 * @param jsonFilePath JSON文件路径 * @param imageFields 包含图片URL的字段名称数组 */ async function extractAndDownloadImages( jsonFilePath: string, imageFields = ['image', 'imageUrl', 'thumbnail', 'cover', 'avatar', 'photo', 'src'] ) { // 检查文件是否存在 if (!fs.existsSync(jsonFilePath)) { console.error(`文件不存在: ${jsonFilePath}`) return } try { // 读取JSON文件 const jsonData = JSON.parse(fs.readFileSync(jsonFilePath, 'utf-8')) // 递归查找所有图片URL const imageUrls = new Set() // 递归函数查找所有图片URL function findImageUrls(obj: any) { if (!obj) return if (Array.isArray(obj)) { obj.forEach(item => findImageUrls(item)) return } if (typeof obj === 'object') { for (const [key, value] of Object.entries(obj)) { if (imageFields.includes(key) && typeof value === 'string' && value.startsWith('http')) { imageUrls.add(value) } else if (typeof value === 'object' && value !== null) { findImageUrls(value) } } } } findImageUrls(jsonData) // 下载所有图片 console.log(`在 ${jsonFilePath} 中找到 ${imageUrls.size} 个图片URL`) let downloadedCount = 0 for (const url of imageUrls) { try { const localUrl = await localizeImage(url) if (localUrl !== url) { downloadedCount++ console.log(`已下载: ${url} -> ${localUrl}`) } } catch (error) { console.error(`下载失败 ${url}:`, error) } } console.log(`成功下载 ${downloadedCount}/${imageUrls.size} 个图片`) // 将本地化的图片URL写回到JSON文件 try { const localizedData = await localizeImages(jsonData) fs.writeFileSync(jsonFilePath, JSON.stringify(localizedData, null, 2)) console.log(`已更新图片URL至本地路径: ${jsonFilePath}`) } catch (error) { console.error(`无法更新JSON文件 ${jsonFilePath}:`, error) } } catch (error) { console.error(`处理文件 ${jsonFilePath} 时出错:`, error) } } /** * 递归处理对象中的所有图片URL * 此函数是image-localizer.ts中同名函数的复制,以避免在命令行运行时的循环依赖问题 */ async function localizeImages( data: any, imageFields = ['image', 'imageUrl', 'thumbnail', 'cover', 'avatar', 'photo', 'src'] ): Promise { if (!data) return data // 处理数组 if (Array.isArray(data)) { return Promise.all(data.map(item => localizeImages(item, imageFields))) } // 处理对象 if (typeof data === 'object') { const result = { ...data } // 处理所有键 for (const [key, value] of Object.entries(result)) { // 如果是图片字段且值是字符串,本地化图片 if (imageFields.includes(key) && typeof value === 'string') { result[key] = await localizeImage(value) } // 递归处理嵌套对象或数组 else if (typeof value === 'object' && value !== null) { result[key] = await localizeImages(value, imageFields) } } return result } return data } /** * 处理API响应文件中的图片 * @param outputDir 输出目录路径(通常是.output目录) */ export async function processApiResponseImages(outputDir = '.output') { console.log('开始处理API响应文件中的图片...') // 检查输出目录是否存在 if (!fs.existsSync(outputDir)) { console.error(`输出目录不存在: ${outputDir}`) return } const serverDir = path.join(outputDir, 'server/api') if (!fs.existsSync(serverDir)) { console.error(`服务器API目录不存在: ${serverDir}`) return } console.log(`扫描API响应文件: ${serverDir}`) // 递归函数查找所有JSON文件 async function processDirectory(dir: string) { const entries = fs.readdirSync(dir, { withFileTypes: true }) for (const entry of entries) { const fullPath = path.join(dir, entry.name) if (entry.isDirectory()) { await processDirectory(fullPath) } else if (entry.name.endsWith('.json')) { console.log(`处理JSON文件: ${fullPath}`) await extractAndDownloadImages(fullPath) } } } await processDirectory(serverDir) console.log('所有API响应文件处理完成') } // 允许通过命令行直接运行 // 兼容 ESM 和 CommonJS if (typeof require !== 'undefined' && require.main === module) { const outputDir = process.argv[2] || '.output' processApiResponseImages(outputDir) .then(() => console.log('图片本地化处理完成')) .catch(error => console.error('图片本地化处理失败:', error)) } // 导出主函数,供脚本调用 export default processApiResponseImages