/** * Phase: upload — OSS 上传 * * 将图片(含首尾帧)和视频上传到 OSS,回写 url / videoUrl */ const path = require('path') const { saveManifest, log, getManifestDir } = require('./pipeline-utils') async function phaseUpload(manifest, manifestPath) { const dir = getManifestDir(manifestPath) const { uploadFile } = require('../oss-upload') // 图片(含首尾帧 first frame) const imageItems = manifest.items.filter(it => it.status === 'done' && it.file && !it.url ) // 视频 const videoItems = manifest.items.filter(it => it.status === 'done' && it.video && !it.videoUrl ) if (imageItems.length === 0 && videoItems.length === 0) { log('upload', '无待上传文件,跳过') return } // 上传图片 if (imageItems.length > 0) { log('upload', `图片: ${imageItems.length} 个`) for (let i = 0; i < imageItems.length; i++) { const item = imageItems[i] const filePath = path.resolve(dir, item.file) try { const { url } = await uploadFile(filePath) item.url = url log('upload', ` [${i + 1}/${imageItems.length}] ${item.file} → OK`) } catch (err) { item.error = `上传失败: ${err.message}` log('upload', ` [${i + 1}/${imageItems.length}] 失败: ${err.message}`) } // 首尾帧模式:上传 lastFrame if (item.url && item.lastFrame && !item.lastFrameUrl) { const lastPath = path.resolve(dir, item.lastFrame) try { const { url } = await uploadFile(lastPath) item.lastFrameUrl = url log('upload', ` [${i + 1}/${imageItems.length}] lastFrame → OK`) } catch (err) { log('upload', ` [${i + 1}/${imageItems.length}] lastFrame 上传失败: ${err.message}`) } } saveManifest(manifestPath, manifest) } } // 上传视频 if (videoItems.length > 0) { log('upload', `视频: ${videoItems.length} 个`) for (let i = 0; i < videoItems.length; i++) { const item = videoItems[i] const videoPath = path.resolve(dir, item.video) try { const { url } = await uploadFile(videoPath) item.videoUrl = url log('upload', ` [${i + 1}/${videoItems.length}] ${item.video} → OK`) } catch (err) { log('upload', ` [${i + 1}/${videoItems.length}] 失败: ${err.message}`) } saveManifest(manifestPath, manifest) } } } module.exports = { phaseUpload }