1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889 |
- import fs from 'fs'
- import path from 'path'
- import { createHash } from 'crypto'
-
- /**
- * 下载并本地化图片
- * @param imageUrl 原始图片URL
- * @param basePath 保存图片的基础路径
- * @returns 本地化后的图片路径
- */
- export async function localizeImage(imageUrl: string, basePath = 'public/images/remote'): Promise<string> {
- // 检查URL是否有效
- if (!imageUrl || !imageUrl.startsWith('http')) {
- return imageUrl
- }
-
- try {
- // 创建保存目录
- const fullBasePath = path.resolve(process.cwd(), basePath)
- if (!fs.existsSync(fullBasePath)) {
- fs.mkdirSync(fullBasePath, { recursive: true })
- }
-
- // 生成唯一文件名(使用URL的MD5哈希)
- const urlHash = createHash('md5').update(imageUrl).digest('hex')
- const fileExt = path.extname(new URL(imageUrl).pathname) || '.jpg'
- const fileName = `${urlHash}${fileExt}`
- const filePath = path.join(fullBasePath, fileName)
-
- // 如果文件已存在,直接返回路径
- if (fs.existsSync(filePath)) {
- return `/images/remote/${fileName}`
- }
-
- // 下载图片
- const response = await fetch(imageUrl)
- if (!response.ok) {
- throw new Error(`下载图片失败: ${response.status} ${response.statusText}`)
- }
-
- const buffer = Buffer.from(await response.arrayBuffer())
- fs.writeFileSync(filePath, buffer)
-
- // 返回本地URL(相对于public目录)
- return `/images/remote/${fileName}`
- } catch (error) {
- console.error(`本地化图片失败 ${imageUrl}:`, error)
- return imageUrl // 失败时返回原始URL
- }
- }
-
- /**
- * 递归处理对象中的所有图片URL
- * @param data 需要处理的数据对象或数组
- * @param imageFields 指定哪些字段包含图片URL
- * @returns 处理后的数据
- */
- export async function localizeImages(
- data: any,
- imageFields = ['image', 'imageUrl', 'thumbnail', 'cover', 'avatar', 'photo', 'src']
- ): Promise<any> {
- 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
- }
|