Hanye官网
您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

image-downloader.ts 4.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. import fs from 'fs'
  2. import path from 'path'
  3. import { localizeImage } from './image-localizer'
  4. /**
  5. * 从JSON文件提取图片URL并下载到本地
  6. * @param jsonFilePath JSON文件路径
  7. * @param imageFields 包含图片URL的字段名称数组
  8. */
  9. async function extractAndDownloadImages(
  10. jsonFilePath: string,
  11. imageFields = ['image', 'imageUrl', 'thumbnail', 'cover', 'avatar', 'photo', 'src']
  12. ) {
  13. // 检查文件是否存在
  14. if (!fs.existsSync(jsonFilePath)) {
  15. console.error(`文件不存在: ${jsonFilePath}`)
  16. return
  17. }
  18. try {
  19. // 读取JSON文件
  20. const jsonData = JSON.parse(fs.readFileSync(jsonFilePath, 'utf-8'))
  21. // 递归查找所有图片URL
  22. const imageUrls = new Set<string>()
  23. // 递归函数查找所有图片URL
  24. function findImageUrls(obj: any) {
  25. if (!obj) return
  26. if (Array.isArray(obj)) {
  27. obj.forEach(item => findImageUrls(item))
  28. return
  29. }
  30. if (typeof obj === 'object') {
  31. for (const [key, value] of Object.entries(obj)) {
  32. if (imageFields.includes(key) && typeof value === 'string' && value.startsWith('http')) {
  33. imageUrls.add(value)
  34. } else if (typeof value === 'object' && value !== null) {
  35. findImageUrls(value)
  36. }
  37. }
  38. }
  39. }
  40. findImageUrls(jsonData)
  41. // 下载所有图片
  42. console.log(`在 ${jsonFilePath} 中找到 ${imageUrls.size} 个图片URL`)
  43. let downloadedCount = 0
  44. for (const url of imageUrls) {
  45. try {
  46. const localUrl = await localizeImage(url)
  47. if (localUrl !== url) {
  48. downloadedCount++
  49. console.log(`已下载: ${url} -> ${localUrl}`)
  50. }
  51. } catch (error) {
  52. console.error(`下载失败 ${url}:`, error)
  53. }
  54. }
  55. console.log(`成功下载 ${downloadedCount}/${imageUrls.size} 个图片`)
  56. // 将本地化的图片URL写回到JSON文件
  57. try {
  58. const localizedData = await localizeImages(jsonData)
  59. fs.writeFileSync(jsonFilePath, JSON.stringify(localizedData, null, 2))
  60. console.log(`已更新图片URL至本地路径: ${jsonFilePath}`)
  61. } catch (error) {
  62. console.error(`无法更新JSON文件 ${jsonFilePath}:`, error)
  63. }
  64. } catch (error) {
  65. console.error(`处理文件 ${jsonFilePath} 时出错:`, error)
  66. }
  67. }
  68. /**
  69. * 递归处理对象中的所有图片URL
  70. * 此函数是image-localizer.ts中同名函数的复制,以避免在命令行运行时的循环依赖问题
  71. */
  72. async function localizeImages(
  73. data: any,
  74. imageFields = ['image', 'imageUrl', 'thumbnail', 'cover', 'avatar', 'photo', 'src']
  75. ): Promise<any> {
  76. if (!data) return data
  77. // 处理数组
  78. if (Array.isArray(data)) {
  79. return Promise.all(data.map(item => localizeImages(item, imageFields)))
  80. }
  81. // 处理对象
  82. if (typeof data === 'object') {
  83. const result = { ...data }
  84. // 处理所有键
  85. for (const [key, value] of Object.entries(result)) {
  86. // 如果是图片字段且值是字符串,本地化图片
  87. if (imageFields.includes(key) && typeof value === 'string') {
  88. result[key] = await localizeImage(value)
  89. }
  90. // 递归处理嵌套对象或数组
  91. else if (typeof value === 'object' && value !== null) {
  92. result[key] = await localizeImages(value, imageFields)
  93. }
  94. }
  95. return result
  96. }
  97. return data
  98. }
  99. /**
  100. * 处理API响应文件中的图片
  101. * @param outputDir 输出目录路径(通常是.output目录)
  102. */
  103. export async function processApiResponseImages(outputDir = '.output') {
  104. console.log('开始处理API响应文件中的图片...')
  105. // 检查输出目录是否存在
  106. if (!fs.existsSync(outputDir)) {
  107. console.error(`输出目录不存在: ${outputDir}`)
  108. return
  109. }
  110. const serverDir = path.join(outputDir, 'server/api')
  111. if (!fs.existsSync(serverDir)) {
  112. console.error(`服务器API目录不存在: ${serverDir}`)
  113. return
  114. }
  115. console.log(`扫描API响应文件: ${serverDir}`)
  116. // 递归函数查找所有JSON文件
  117. async function processDirectory(dir: string) {
  118. const entries = fs.readdirSync(dir, { withFileTypes: true })
  119. for (const entry of entries) {
  120. const fullPath = path.join(dir, entry.name)
  121. if (entry.isDirectory()) {
  122. await processDirectory(fullPath)
  123. } else if (entry.name.endsWith('.json')) {
  124. console.log(`处理JSON文件: ${fullPath}`)
  125. await extractAndDownloadImages(fullPath)
  126. }
  127. }
  128. }
  129. await processDirectory(serverDir)
  130. console.log('所有API响应文件处理完成')
  131. }
  132. // 允许通过命令行直接运行
  133. // 兼容 ESM 和 CommonJS
  134. if (typeof require !== 'undefined' && require.main === module) {
  135. const outputDir = process.argv[2] || '.output'
  136. processApiResponseImages(outputDir)
  137. .then(() => console.log('图片本地化处理完成'))
  138. .catch(error => console.error('图片本地化处理失败:', error))
  139. }
  140. // 导出主函数,供脚本调用
  141. export default processApiResponseImages