import multer from 'multer'; import path from 'path'; import { v4 as uuidv4 } from 'uuid'; import { config } from '../config/index.js'; import { AppError } from './error.js'; import { ERROR_CODES, HTTP_STATUS } from '@media-manager/shared'; import fs from 'fs'; // 确保上传目录存在 const uploadDirs = ['videos', 'images', 'covers']; uploadDirs.forEach(dir => { const fullPath = path.join(config.upload.path, dir); if (!fs.existsSync(fullPath)) { try { fs.mkdirSync(fullPath, { recursive: true }); } catch (err) { console.error(`[upload] Failed to create upload dir ${fullPath}:`, err); } } }); // 视频存储配置 const videoStorage = multer.diskStorage({ destination: (_req, _file, cb) => { cb(null, path.join(config.upload.path, 'videos')); }, filename: (_req, file, cb) => { const ext = path.extname(file.originalname); cb(null, `${uuidv4()}${ext}`); }, }); // 图片存储配置 const imageStorage = multer.diskStorage({ destination: (_req, _file, cb) => { cb(null, path.join(config.upload.path, 'images')); }, filename: (_req, file, cb) => { const ext = path.extname(file.originalname); cb(null, `${uuidv4()}${ext}`); }, }); // 视频文件过滤 const videoFilter = (_req: Express.Request, file: Express.Multer.File, cb: multer.FileFilterCallback) => { if (config.upload.allowedVideoTypes.includes(file.mimetype)) { cb(null, true); } else { cb(new AppError( '不支持的视频格式', HTTP_STATUS.BAD_REQUEST, ERROR_CODES.VIDEO_FORMAT_UNSUPPORTED )); } }; // 图片文件过滤 const imageFilter = (_req: Express.Request, file: Express.Multer.File, cb: multer.FileFilterCallback) => { if (config.upload.allowedImageTypes.includes(file.mimetype)) { cb(null, true); } else { cb(new AppError( '不支持的图片格式', HTTP_STATUS.BAD_REQUEST, ERROR_CODES.VALIDATION )); } }; // 视频上传中间件 export const uploadVideo = multer({ storage: videoStorage, limits: { fileSize: config.upload.maxVideoSize, }, fileFilter: videoFilter, }).single('video'); // 图片上传中间件 export const uploadImage = multer({ storage: imageStorage, limits: { fileSize: config.upload.maxImageSize, }, fileFilter: imageFilter, }).single('image'); // 封面上传中间件 export const uploadCover = multer({ storage: multer.diskStorage({ destination: (_req, _file, cb) => { cb(null, path.join(config.upload.path, 'covers')); }, filename: (_req, file, cb) => { const ext = path.extname(file.originalname); cb(null, `${uuidv4()}${ext}`); }, }), limits: { fileSize: config.upload.maxImageSize, }, fileFilter: imageFilter, }).single('cover');