nomid2 commited on
Commit
0b04ef0
·
verified ·
1 Parent(s): 0b715ff

Upload 2 files

Browse files
Files changed (2) hide show
  1. src/lib/imageProcessor.js +2 -2
  2. src/lib/uploader.js +91 -71
src/lib/imageProcessor.js CHANGED
@@ -6,8 +6,8 @@ const sharp = require('sharp')
6
  */
7
  class ImageProcessor {
8
  constructor() {
9
- // 长图阈值:高度超过宽度*3倍(更合理的阈值)
10
- this.LONG_IMAGE_RATIO = 3
11
  // 重叠像素范围
12
  this.OVERLAP_MIN = 50
13
  this.OVERLAP_MAX = 100
 
6
  */
7
  class ImageProcessor {
8
  constructor() {
9
+ // 长图阈值:高度超过宽度*2.5倍(更合理的阈值,确保1080x4000等图片能被识别)
10
+ this.LONG_IMAGE_RATIO = 2.5
11
  // 重叠像素范围
12
  this.OVERLAP_MIN = 50
13
  this.OVERLAP_MAX = 100
src/lib/uploader.js CHANGED
@@ -16,7 +16,7 @@ class ImageUploader {
16
  return crypto.createHash('sha256').update(buffer).digest('hex')
17
  }
18
 
19
- async uploadImage(imageBuffer, imageName, forceUpload = false) {
20
  // 确保参数有效
21
  if (!imageBuffer || !Buffer.isBuffer(imageBuffer)) {
22
  throw new Error('无效的图片数据')
@@ -29,15 +29,13 @@ class ImageUploader {
29
  // 生成图片数据的哈希值作为缓存key
30
  const imageHash = this.generateHash(imageBuffer)
31
 
32
- // 检查缓存中是否已存在该图片的上传结果(除非强制上传)
33
- if (!forceUpload && this.imageCache.has(imageHash)) {
34
- console.log(`[缓存命中] 图片哈希: ${imageHash.substring(0, 8)}...`)
35
- const cachedUrl = this.imageCache.get(imageHash)
36
- console.log(`[缓存返回] URL: ${cachedUrl}`)
37
- return cachedUrl
38
  }
39
 
40
- console.log(`[开始上传] 图片哈希: ${imageHash.substring(0, 8)}... ${forceUpload ? '(强制上传)' : '(缓存未命中)'}`)
41
 
42
  // 获取一个可用的cookie
43
  const cookieValue = accountManager.getNextAvailableCookie()
@@ -71,7 +69,7 @@ class ImageUploader {
71
 
72
  // 将结果保存到缓存
73
  this.imageCache.set(imageHash, imageUrl)
74
- console.log(`[上传成功] 图片哈希: ${imageHash.substring(0, 8)}... -> ${imageUrl}`)
75
 
76
  return imageUrl
77
  } else {
@@ -82,7 +80,7 @@ class ImageUploader {
82
  if (error.response && error.response.status === 403) {
83
  accountManager.markAsUnavailable(cookieValue)
84
  // 递归尝试使用新账号
85
- return this.uploadImage(imageBuffer, imageName, forceUpload)
86
  }
87
 
88
  throw new Error(`图片上传失败: ${error.message}`)
@@ -158,13 +156,10 @@ class ImageUploader {
158
  * @param {string} imageName - 图片名称
159
  * @param {string} requestId - 请求ID(用于日志)
160
  * @param {number} imageIndex - 图片索引(用于日志)
161
- * @param {boolean} preserveOrder - 是否保持顺序(禁用缓存优化)
162
  * @returns {Promise<Array<string>>} 上传后的URL数组
163
  */
164
- async uploadImageSmart(imageBuffer, imageName, requestId = null, imageIndex = 0, preserveOrder = false) {
165
  try {
166
- console.log(`[智能上传] 开始处理图片${imageIndex + 1},保持顺序: ${preserveOrder}`)
167
-
168
  // 检测是否为长图
169
  const detection = await imageProcessor.detectLongImage(imageBuffer)
170
 
@@ -174,85 +169,110 @@ class ImageUploader {
174
 
175
  if (!detection.isLongImage) {
176
  // 不是长图,使用原有方式上传
177
- console.log(`[智能上传] 图片${imageIndex + 1}为普通图片,开始上传`)
178
-
179
- // 如果需要保持顺序,则禁用缓存优化
180
- const url = await this.uploadImage(imageBuffer, imageName, preserveOrder)
181
 
182
  if (requestId) {
183
  logger.logImageUpload(requestId, imageIndex, 0, true, url)
184
  }
185
 
186
- console.log(`[智能上传] 图片${imageIndex + 1}上传完成: ${url}`)
187
  return [url]
188
  }
189
 
190
  // 是长图,进行切割处理
191
  console.log(`检测到长图 ${detection.width}x${detection.height},开始切割处理`)
192
 
193
- const segments = await imageProcessor.cropLongImage(imageBuffer)
194
- const uploadedUrls = []
195
-
196
- if (requestId) {
197
- logger.logImageCropping(requestId, imageIndex, {
198
- segments,
199
- stats: imageProcessor.getProcessingStats(segments)
200
- })
201
- }
202
 
203
- // 并行上传切割后的片段
204
- const uploadPromises = segments.map(async (segment) => {
205
- const segmentName = imageProcessor.generateSegmentName(
206
- imageName,
207
- segment.metadata.segmentIndex,
208
- segment.metadata.totalSegments
209
- )
210
 
211
- try {
212
- const url = await this.uploadImage(segment.buffer, segmentName)
 
 
 
 
213
 
214
- if (requestId) {
215
- logger.logImageUpload(requestId, imageIndex, segment.metadata.segmentIndex, true, url)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
216
  }
 
217
 
218
- console.log(`片段 ${segment.metadata.segmentIndex + 1}/${segment.metadata.totalSegments} 上传成功: ${url}`)
219
- return {
220
- url,
221
- segmentIndex: segment.metadata.segmentIndex,
222
- success: true
223
- }
224
- } catch (error) {
225
- if (requestId) {
226
- logger.logImageUpload(requestId, imageIndex, segment.metadata.segmentIndex, false, null, error.message)
227
- }
228
 
229
- console.error(`片段 ${segment.metadata.segmentIndex + 1} 上传失败: ${error.message}`)
230
- return {
231
- error: error.message,
232
- segmentIndex: segment.metadata.segmentIndex,
233
- success: false
234
- }
235
  }
236
- })
237
 
238
- // 等待所有上传完成
239
- const uploadResults = await Promise.all(uploadPromises)
 
 
 
240
 
241
- // 检查是否有失败的上传
242
- const failedUploads = uploadResults.filter(result => !result.success)
243
- if (failedUploads.length > 0) {
244
- const failedIndexes = failedUploads.map(result => result.segmentIndex + 1).join(', ')
245
- throw new Error(`片段 ${failedIndexes} 上传失败`)
246
- }
 
 
 
 
 
 
 
247
 
248
- // 按照片段顺序排序并提取URL
249
- const sortedResults = uploadResults
250
- .filter(result => result.success)
251
- .sort((a, b) => a.segmentIndex - b.segmentIndex)
252
- .map(result => result.url)
253
 
254
- console.log(`长图切割并行上传完成,共 ${sortedResults.length} 个片段`)
255
- return sortedResults
 
 
 
 
 
 
 
 
256
 
257
  } catch (error) {
258
  if (requestId) {
 
16
  return crypto.createHash('sha256').update(buffer).digest('hex')
17
  }
18
 
19
+ async uploadImage(imageBuffer, imageName) {
20
  // 确保参数有效
21
  if (!imageBuffer || !Buffer.isBuffer(imageBuffer)) {
22
  throw new Error('无效的图片数据')
 
29
  // 生成图片数据的哈希值作为缓存key
30
  const imageHash = this.generateHash(imageBuffer)
31
 
32
+ // 检查缓存中是否已存在该图片的上传结果
33
+ if (this.imageCache.has(imageHash)) {
34
+ console.log(`图片缓存命中: ${imageHash.substring(0, 8)}...`)
35
+ return this.imageCache.get(imageHash)
 
 
36
  }
37
 
38
+ console.log(`图片缓存未命中,开始上传: ${imageHash.substring(0, 8)}...`)
39
 
40
  // 获取一个可用的cookie
41
  const cookieValue = accountManager.getNextAvailableCookie()
 
69
 
70
  // 将结果保存到缓存
71
  this.imageCache.set(imageHash, imageUrl)
72
+ console.log(`图片上传成功并缓存: ${imageHash.substring(0, 8)}... -> ${imageUrl}`)
73
 
74
  return imageUrl
75
  } else {
 
80
  if (error.response && error.response.status === 403) {
81
  accountManager.markAsUnavailable(cookieValue)
82
  // 递归尝试使用新账号
83
+ return this.uploadImage(imageBuffer, imageName)
84
  }
85
 
86
  throw new Error(`图片上传失败: ${error.message}`)
 
156
  * @param {string} imageName - 图片名称
157
  * @param {string} requestId - 请求ID(用于日志)
158
  * @param {number} imageIndex - 图片索引(用于日志)
 
159
  * @returns {Promise<Array<string>>} 上传后的URL数组
160
  */
161
+ async uploadImageSmart(imageBuffer, imageName, requestId = null, imageIndex = 0) {
162
  try {
 
 
163
  // 检测是否为长图
164
  const detection = await imageProcessor.detectLongImage(imageBuffer)
165
 
 
169
 
170
  if (!detection.isLongImage) {
171
  // 不是长图,使用原有方式上传
172
+ const url = await this.uploadImage(imageBuffer, imageName)
 
 
 
173
 
174
  if (requestId) {
175
  logger.logImageUpload(requestId, imageIndex, 0, true, url)
176
  }
177
 
 
178
  return [url]
179
  }
180
 
181
  // 是长图,进行切割处理
182
  console.log(`检测到长图 ${detection.width}x${detection.height},开始切割处理`)
183
 
184
+ try {
185
+ const segments = await imageProcessor.cropLongImage(imageBuffer)
 
 
 
 
 
 
 
186
 
187
+ if (!segments || segments.length === 0) {
188
+ throw new Error('长图切割失败:未生成任何片段')
189
+ }
 
 
 
 
190
 
191
+ if (requestId) {
192
+ logger.logImageCropping(requestId, imageIndex, {
193
+ segments,
194
+ stats: imageProcessor.getProcessingStats(segments)
195
+ })
196
+ }
197
 
198
+ // 并行上传切割后的片段
199
+ const uploadPromises = segments.map(async (segment) => {
200
+ const segmentName = imageProcessor.generateSegmentName(
201
+ imageName,
202
+ segment.metadata.segmentIndex,
203
+ segment.metadata.totalSegments
204
+ )
205
+
206
+ try {
207
+ const url = await this.uploadImage(segment.buffer, segmentName)
208
+
209
+ if (requestId) {
210
+ logger.logImageUpload(requestId, imageIndex, segment.metadata.segmentIndex, true, url)
211
+ }
212
+
213
+ console.log(`片段 ${segment.metadata.segmentIndex + 1}/${segment.metadata.totalSegments} 上传成功: ${url}`)
214
+ return {
215
+ url,
216
+ segmentIndex: segment.metadata.segmentIndex,
217
+ success: true
218
+ }
219
+ } catch (error) {
220
+ if (requestId) {
221
+ logger.logImageUpload(requestId, imageIndex, segment.metadata.segmentIndex, false, null, error.message)
222
+ }
223
+
224
+ console.error(`片段 ${segment.metadata.segmentIndex + 1} 上传失败: ${error.message}`)
225
+ return {
226
+ error: error.message,
227
+ segmentIndex: segment.metadata.segmentIndex,
228
+ success: false
229
+ }
230
  }
231
+ })
232
 
233
+ // 等待所有上传完成
234
+ const uploadResults = await Promise.all(uploadPromises)
 
 
 
 
 
 
 
 
235
 
236
+ // 检查是否有失败的上传
237
+ const failedUploads = uploadResults.filter(result => !result.success)
238
+ if (failedUploads.length > 0) {
239
+ const failedIndexes = failedUploads.map(result => result.segmentIndex + 1).join(', ')
240
+ throw new Error(`片段 ${failedIndexes} 上传失败`)
 
241
  }
 
242
 
243
+ // 按照片段顺序排序并提取URL
244
+ const sortedResults = uploadResults
245
+ .filter(result => result.success)
246
+ .sort((a, b) => a.segmentIndex - b.segmentIndex)
247
+ .map(result => result.url)
248
 
249
+ console.log(`长图切割并行上传完成,共 ${sortedResults.length} 个片段`)
250
+ return sortedResults
251
+
252
+ } catch (longImageError) {
253
+ // 长图处理失败,回退到原图上传
254
+ console.warn(`长图处理失败: ${longImageError.message},回退到原图上传`)
255
+
256
+ if (requestId) {
257
+ logger.logError(requestId, 'LONG_IMAGE_FALLBACK', `长图处理失败,回退到原图: ${longImageError.message}`, {
258
+ imageIndex,
259
+ originalSize: `${detection.width}x${detection.height}`
260
+ })
261
+ }
262
 
263
+ try {
264
+ const fallbackUrl = await this.uploadImage(imageBuffer, imageName)
 
 
 
265
 
266
+ if (requestId) {
267
+ logger.logImageUpload(requestId, imageIndex, 0, true, fallbackUrl, '长图回退上传')
268
+ }
269
+
270
+ console.log(`长图回退上传成功: ${fallbackUrl}`)
271
+ return [fallbackUrl]
272
+ } catch (fallbackError) {
273
+ throw new Error(`长图处理和回退上传均失败: ${longImageError.message} | ${fallbackError.message}`)
274
+ }
275
+ }
276
 
277
  } catch (error) {
278
  if (requestId) {