From ba7d1a8574e56a437aa1dc43dbe1ed001e578317 Mon Sep 17 00:00:00 2001 From: LaoShui <79132480+laoshuikaixue@users.noreply.github.com> Date: Wed, 18 Feb 2026 16:44:19 +0800 Subject: [PATCH] =?UTF-8?q?feat(cloud):=20=E6=94=AF=E6=8C=81=E4=B8=B4?= =?UTF-8?q?=E6=97=B6=E6=96=87=E4=BB=B6=E4=B8=8A=E4=BC=A0=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 使用 crypto 模块替换 md5 模块进行文件哈希计算 - 添加对临时文件上传的支持,当存在 tempFilePath 时使用文件流处理 - 实现临时文件的 MD5 计算和元数据解析功能 - 在上传完成后自动清理临时文件 - 配置服务器端文件上传中间件启用临时文件支持 - 修改上传插件以支持临时文件读取流上传方式 - 增加文件大小获取和验证的兼容性处理 --- module/cloud.js | 60 ++++++++++++++++++++++++++++++++++--------- plugins/songUpload.js | 11 +++++++- server.js | 9 ++++--- 3 files changed, 63 insertions(+), 17 deletions(-) diff --git a/module/cloud.js b/module/cloud.js index 4fd6172..0b79917 100644 --- a/module/cloud.js +++ b/module/cloud.js @@ -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, diff --git a/plugins/songUpload.js b/plugins/songUpload.js index 09c7745..642d863 100644 --- a/plugins/songUpload.js +++ b/plugins/songUpload.js @@ -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, diff --git a/server.js b/server.js index 3736761..a02d4d8 100644 --- a/server.js +++ b/server.js @@ -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 })) /**