// Created by AI on 2025-10-11. import UIKit import Foundation class EPImageUploader { init() {} func performBatchUpload( _ images: [UIImage], bucket: String, customDomain: String, progress: @escaping (Int, Int) -> Void, success: @escaping ([[String: Any]]) -> Void, failure: @escaping (String) -> Void ) { let total = images.count let queue = DispatchQueue(label: "com.yumi.imageupload", attributes: .concurrent) let semaphore = DispatchSemaphore(value: 3) var uploadedCount = 0 var resultList: [[String: Any]] = [] var hasError = false let lock = NSLock() for (_, image) in images.enumerated() { queue.async { semaphore.wait() lock.lock() if hasError { lock.unlock() semaphore.signal() return } lock.unlock() guard let imageData = image.jpegData(compressionQuality: 0.5) else { lock.lock() hasError = true lock.unlock() semaphore.signal() DispatchQueue.main.async { failure(YMLocalizedString("error.image_compress_failed")) } return } let format = UIImage.getImageType(withImageData: imageData) ?? "jpeg" let uuid = NSString.createUUID() let fileName = "image/\(uuid).\(format)" let request = QCloudCOSXMLUploadObjectRequest() request.bucket = bucket request.object = fileName request.body = imageData as NSData request.sendProcessBlock = { bytesSent, totalBytesSent, totalBytesExpectedToSend in } request.finishBlock = { [weak self] result, error in guard let self = self else { semaphore.signal() return } if let error = error { lock.lock() if !hasError { hasError = true lock.unlock() semaphore.signal() DispatchQueue.main.async { failure(error.localizedDescription) } } else { lock.unlock() semaphore.signal() } } else if let result = result as? QCloudUploadObjectResult { lock.lock() if !hasError { uploadedCount += 1 let uploadedURL = self.parseUploadURL(result.location, customDomain: customDomain) let imageInfo: [String: Any] = [ "resUrl": uploadedURL, "width": image.size.width, "height": image.size.height, "format": format ] resultList.append(imageInfo) let currentUploaded = uploadedCount lock.unlock() DispatchQueue.main.async { progress(currentUploaded, total) } if currentUploaded == total { DispatchQueue.main.async { success(resultList) } } } else { lock.unlock() } semaphore.signal() } else { semaphore.signal() } } QCloudCOSTransferMangerService.defaultCOSTransferManager().uploadObject(request) } } } private func parseUploadURL(_ location: String, customDomain: String) -> String { let components = location.components(separatedBy: ".com/") if components.count == 2 { return "\(customDomain)/\(components[1])" } return location } }