Files
video-create/.claude/skills/video-from-script/scripts/oss-upload.js

172 lines
5.2 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env node
/**
* OSS 文件上传工具
*
* 上传图片/视频到阿里云 OSS返回签名 URL。
* 支持单文件和批量上传。
*
* 用法:
* node oss-upload.js ./image.png
* node oss-upload.js ./video.mp4 --dir videos/
* node oss-upload.js batch ./manifest.json
*/
const OSS = require('ali-oss')
const path = require('path')
const fs = require('fs')
// ============================================================================
// 配置
// ============================================================================
function getConfig() {
const configPath = path.join(__dirname, '..', '..', 'config.json')
const config = JSON.parse(fs.readFileSync(configPath, 'utf-8'))
if (!config.ossRegion || !config.ossAccessKeyId || !config.ossAccessKeySecret || !config.ossBucket) {
console.error('config.json 需要填写 ossRegion, ossAccessKeyId, ossAccessKeySecret, ossBucket')
process.exit(1)
}
return config
}
function createClient(config) {
return new OSS({
region: config.ossRegion,
accessKeyId: config.ossAccessKeyId,
accessKeySecret: config.ossAccessKeySecret,
bucket: config.ossBucket,
secure: true,
})
}
// ============================================================================
// 上传
// ============================================================================
async function uploadFile(filePath, options = {}) {
const config = getConfig()
const client = createClient(config)
if (!fs.existsSync(filePath)) {
throw new Error(`文件不存在: ${filePath}`)
}
const folder = options.folder || config.ossFolder || 'tmp/'
const basename = options.name || path.basename(filePath)
const ossPath = `${folder}${basename}`
const buffer = fs.readFileSync(filePath)
await client.put(ossPath, buffer)
const expires = config.ossExpires || 31536000
const url = client.signatureUrl(ossPath, { expires })
return { url, ossPath, size: buffer.length }
}
async function uploadBuffer(buffer, options = {}) {
const config = getConfig()
const client = createClient(config)
const folder = options.folder || config.ossFolder || 'tmp/'
const basename = options.name || `${Date.now()}${options.ext || '.png'}`
const ossPath = `${folder}${basename}`
await client.put(ossPath, buffer)
const expires = config.ossExpires || 31536000
const url = client.signatureUrl(ossPath, { expires })
return { url, ossPath }
}
// ============================================================================
// 批量上传(读 manifest.json 中的 file 列表)
// ============================================================================
async function batchUpload(manifestPath, baseDir) {
const manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf-8'))
const dir = baseDir || path.dirname(manifestPath)
const results = {}
for (const item of manifest.items) {
const filePath = path.join(dir, item.file)
if (!fs.existsSync(filePath)) continue
const name = path.basename(item.file)
try {
const { url } = await uploadFile(filePath, { name })
results[item.file] = url
console.log(` OK: ${name}`)
} catch (err) {
console.error(` FAIL: ${name} - ${err.message}`)
}
}
return results
}
// ============================================================================
// CLI
// ============================================================================
function parseArgs(argv) {
const args = { _: [] }
for (let i = 0; i < argv.length; i++) {
if (argv[i].startsWith('--')) {
const key = argv[i].slice(2)
const val = argv[i + 1]
if (val && !val.startsWith('--')) { args[key] = val; i++ }
else args[key] = true
} else {
args._.push(argv[i])
}
}
return args
}
async function main() {
const args = parseArgs(process.argv.slice(2))
const cmd = args._[0]
if (!cmd) {
console.log('用法: node oss-upload.js <file> [--dir folder] [--name filename]')
console.log(' node oss-upload.js batch <manifest.json> [--dir <baseDir>]')
process.exit(0)
}
if (cmd === 'batch') {
const manifest = args._[1]
if (!manifest) { console.error('指定 manifest.json'); process.exit(1) }
console.log(`批量上传: ${manifest}`)
const results = await batchUpload(manifest, args.dir)
console.log(`\n完成: ${Object.keys(results).length} 个文件`)
// 写回 urls
const urlsPath = path.join(args.dir || path.dirname(manifest), 'urls.json')
const existing = fs.existsSync(urlsPath) ? JSON.parse(fs.readFileSync(urlsPath, 'utf-8')) : {}
Object.assign(existing, results)
fs.writeFileSync(urlsPath, JSON.stringify(existing, null, 2))
console.log(`URLs 已写入: ${urlsPath}`)
} else {
const filePath = path.resolve(cmd)
console.log(`上传: ${filePath}`)
const { url, ossPath, size } = await uploadFile(filePath, {
folder: args.dir,
name: args.name,
})
console.log(`\nOSS 路径: ${ossPath}`)
console.log(`签名 URL: ${url}`)
console.log(`文件大小: ${(size / 1024).toFixed(1)} KB`)
}
}
module.exports = { uploadFile, uploadBuffer, batchUpload }
if (require.main === module) {
main().catch(err => {
console.error(`错误: ${err.message}`)
process.exit(1)
})
}