feat(cloud): 支持临时文件上传功能

- 使用 crypto 模块替换 md5 模块进行文件哈希计算
- 添加对临时文件上传的支持,当存在 tempFilePath 时使用文件流处理
- 实现临时文件的 MD5 计算和元数据解析功能
- 在上传完成后自动清理临时文件
- 配置服务器端文件上传中间件启用临时文件支持
- 修改上传插件以支持临时文件读取流上传方式
- 增加文件大小获取和验证的兼容性处理
This commit is contained in:
LaoShui 2026-02-18 16:44:19 +08:00
parent 26d55255e0
commit ba7d1a8574
3 changed files with 63 additions and 17 deletions

View File

@ -1,5 +1,6 @@
const uploadPlugin = require('../plugins/songUpload')
const md5 = require('md5')
const crypto = require('crypto')
const fs = require('fs')
const createOption = require('../util/option.js')
const logger = require('../util/logger.js')
let mm
@ -26,17 +27,40 @@ module.exports = async (query, request) => {
},
})
}
if (!query.songFile.md5) {
query.songFile.md5 = md5(query.songFile.data)
query.songFile.size = query.songFile.data.byteLength
const useTempFile = !!query.songFile.tempFilePath
let fileSize = query.songFile.size
let fileMd5 = query.songFile.md5
if (useTempFile) {
const stats = fs.statSync(query.songFile.tempFilePath)
fileSize = stats.size
if (!fileMd5) {
fileMd5 = await new Promise((resolve, reject) => {
const hash = crypto.createHash('md5')
const stream = fs.createReadStream(query.songFile.tempFilePath)
stream.on('data', (chunk) => hash.update(chunk))
stream.on('end', () => resolve(hash.digest('hex')))
stream.on('error', reject)
})
}
} else {
if (!fileMd5) {
fileMd5 = crypto.createHash('md5').update(query.songFile.data).digest('hex')
}
fileSize = query.songFile.data.byteLength
}
query.songFile.md5 = fileMd5
query.songFile.size = fileSize
const res = await request(
`/api/cloud/upload/check`,
{
bitrate: String(bitrate),
ext: '',
length: query.songFile.size,
md5: query.songFile.md5,
length: fileSize,
md5: fileMd5,
songId: '0',
version: 1,
},
@ -46,10 +70,15 @@ module.exports = async (query, request) => {
let album = ''
let songName = ''
try {
const metadata = await mm.parseBuffer(
query.songFile.data,
query.songFile.mimetype,
)
let metadata
if (useTempFile) {
metadata = await mm.parseFile(query.songFile.tempFilePath)
} else {
metadata = await mm.parseBuffer(
query.songFile.data,
query.songFile.mimetype,
)
}
const info = metadata.common
if (info.title) {
@ -73,7 +102,7 @@ module.exports = async (query, request) => {
local: false,
nos_product: 3,
type: 'audio',
md5: query.songFile.md5,
md5: fileMd5,
},
createOption(query),
)
@ -98,15 +127,22 @@ module.exports = async (query, request) => {
} catch (uploadError) {
logger.error('Upload failed:', uploadError)
return Promise.reject(uploadError)
} finally {
if (useTempFile && fs.existsSync(query.songFile.tempFilePath)) {
fs.unlinkSync(query.songFile.tempFilePath)
}
}
} else {
logger.info('File already exists, skip upload')
if (useTempFile && fs.existsSync(query.songFile.tempFilePath)) {
fs.unlinkSync(query.songFile.tempFilePath)
}
}
const res2 = await request(
`/api/upload/cloud/info/v2`,
{
md5: query.songFile.md5,
md5: fileMd5,
songid: res.body.songId,
filename: query.songFile.name,
song: songName || filename,

View File

@ -1,4 +1,5 @@
const { default: axios } = require('axios')
const fs = require('fs')
const createOption = require('../util/option.js')
const logger = require('../util/logger.js')
module.exports = async (query, request) => {
@ -71,6 +72,14 @@ module.exports = async (query, request) => {
}
}
const useTempFile = !!query.songFile.tempFilePath
let uploadData
if (useTempFile) {
uploadData = fs.createReadStream(query.songFile.tempFilePath)
} else {
uploadData = query.songFile.data
}
try {
await axios({
method: 'post',
@ -81,7 +90,7 @@ module.exports = async (query, request) => {
'Content-Type': 'audio/mpeg',
'Content-Length': String(query.songFile.size),
},
data: query.songFile.data,
data: uploadData,
maxContentLength: Infinity,
maxBodyLength: Infinity,
timeout: 300000,

View File

@ -183,11 +183,12 @@ async function consturctServer(moduleDefs) {
app.use(fileUpload({
limits: {
fileSize: 500 * 1024 * 1024 // 500MB
fileSize: 500 * 1024 * 1024
},
useTempFiles: false,
tempFileDir: '/tmp/',
abortOnLimit: true
useTempFiles: true,
tempFileDir: require('os').tmpdir(),
abortOnLimit: true,
parseNested: true
}))
/**