Resolve merge conflicts for video uploads and processing
This commit is contained in:
@@ -76,12 +76,15 @@ const upload = multer({
|
|||||||
},
|
},
|
||||||
fileFilter: (req, file, cb) => {
|
fileFilter: (req, file, cb) => {
|
||||||
// Accept images and common video formats with proper validation
|
// Accept images and common video formats with proper validation
|
||||||
const allowedMimeTypes = ['image/jpeg', 'image/png', 'image/webp', 'video/mp4', 'video/quicktime', 'video/webm'];
|
const allowedMimeTypes = [
|
||||||
|
'image/jpeg', 'image/png', 'image/webp',
|
||||||
|
'video/mp4', 'video/webm', 'video/quicktime', 'video/x-msvideo'
|
||||||
|
];
|
||||||
|
|
||||||
if (validateFileType(file.originalname, file.mimetype, allowedMimeTypes)) {
|
if (validateFileType(file.originalname, file.mimetype, allowedMimeTypes)) {
|
||||||
return cb(null, true);
|
return cb(null, true);
|
||||||
} else {
|
} else {
|
||||||
cb(new Error('Only JPEG, PNG, WebP images or MP4/MOV/WEBM videos are allowed'));
|
cb(new Error('Only JPEG, PNG, WebP images and MP4, WebM, MOV, AVI videos are allowed'));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
// Add abort on limit to stop processing when limits are exceeded
|
// Add abort on limit to stop processing when limits are exceeded
|
||||||
@@ -90,8 +93,12 @@ const upload = multer({
|
|||||||
|
|
||||||
// Create content validator middleware
|
// Create content validator middleware
|
||||||
const validateUploadContent = createFileUploadValidator({
|
const validateUploadContent = createFileUploadValidator({
|
||||||
allowedTypes: ['image/jpeg', 'image/png', 'image/webp', 'video/mp4', 'video/quicktime', 'video/webm'],
|
allowedTypes: [
|
||||||
maxFileSize: 50 * 1024 * 1024,
|
'image/jpeg', 'image/png', 'image/webp',
|
||||||
|
'video/mp4', 'video/webm', 'video/quicktime', 'video/x-msvideo'
|
||||||
|
],
|
||||||
|
// 10GB per file to accommodate large videos; overall limits enforced elsewhere
|
||||||
|
maxFileSize: 10 * 1024 * 1024 * 1024,
|
||||||
validateContent: true
|
validateContent: true
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ const path = require('path');
|
|||||||
const fs = require('fs').promises;
|
const fs = require('fs').promises;
|
||||||
const { db } = require('../database/db');
|
const { db } = require('../database/db');
|
||||||
const { generateThumbnail, generateVideoPlaceholder } = require('./imageProcessor');
|
const { generateThumbnail, generateVideoPlaceholder } = require('./imageProcessor');
|
||||||
|
const { processUploadedVideo } = require('./videoProcessor');
|
||||||
const { generatePhotoFilename } = require('../utils/filenameSanitizer');
|
const { generatePhotoFilename } = require('../utils/filenameSanitizer');
|
||||||
const { isVideoMimeType } = require('../utils/fileSecurityUtils');
|
const { isVideoMimeType } = require('../utils/fileSecurityUtils');
|
||||||
const mime = require('mime-types');
|
const mime = require('mime-types');
|
||||||
@@ -155,10 +156,21 @@ async function processUploadedPhotos(files, eventId, uploadedBy = 'admin', categ
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate thumbnail or placeholder
|
// Generate thumbnail and metadata
|
||||||
let thumbnailPath = null;
|
let thumbnailPath = null;
|
||||||
|
let videoMetadata = null;
|
||||||
if (isVideo) {
|
if (isVideo) {
|
||||||
thumbnailPath = await generateVideoPlaceholder(newFilename);
|
const thumbnailDir = path.join(getStoragePath(), 'thumbnails');
|
||||||
|
await fs.mkdir(thumbnailDir, { recursive: true });
|
||||||
|
const videoThumbnailPath = path.join(thumbnailDir, `thumb_${newFilename.replace(/\.[^.]+$/, '.jpg')}`);
|
||||||
|
try {
|
||||||
|
const result = await processUploadedVideo(newPath, videoThumbnailPath);
|
||||||
|
videoMetadata = result?.metadata || null;
|
||||||
|
thumbnailPath = path.relative(getStoragePath(), videoThumbnailPath);
|
||||||
|
} catch (videoErr) {
|
||||||
|
console.error('Failed to process uploaded video, falling back to placeholder:', videoErr.message);
|
||||||
|
thumbnailPath = await generateVideoPlaceholder(newFilename);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
thumbnailPath = await generateThumbnail(newPath);
|
thumbnailPath = await generateThumbnail(newPath);
|
||||||
}
|
}
|
||||||
@@ -173,32 +185,25 @@ async function processUploadedPhotos(files, eventId, uploadedBy = 'admin', categ
|
|||||||
const clientName = trx?.client?.config?.client;
|
const clientName = trx?.client?.config?.client;
|
||||||
const supportsReturning = ['pg', 'postgres', 'postgresql'].includes(clientName);
|
const supportsReturning = ['pg', 'postgres', 'postgresql'].includes(clientName);
|
||||||
|
|
||||||
|
const photoData = {
|
||||||
|
event_id: eventId,
|
||||||
|
filename: newFilename,
|
||||||
|
path: relativePath,
|
||||||
|
thumbnail_path: relativeThumbPath,
|
||||||
|
type: photoType,
|
||||||
|
size_bytes: file.size,
|
||||||
|
uploaded_by: uploadedBy,
|
||||||
|
source_origin: 'managed',
|
||||||
|
mime_type: resolvedMime,
|
||||||
|
media_type: isVideo ? 'video' : 'photo'
|
||||||
|
};
|
||||||
|
|
||||||
if (supportsReturning) {
|
if (supportsReturning) {
|
||||||
insertResult = await trx('photos')
|
insertResult = await trx('photos')
|
||||||
.insert({
|
.insert(photoData)
|
||||||
event_id: eventId,
|
|
||||||
filename: newFilename,
|
|
||||||
path: relativePath,
|
|
||||||
thumbnail_path: relativeThumbPath,
|
|
||||||
type: photoType,
|
|
||||||
size_bytes: file.size,
|
|
||||||
uploaded_by: uploadedBy,
|
|
||||||
source_origin: 'managed',
|
|
||||||
mime_type: resolvedMime
|
|
||||||
})
|
|
||||||
.returning('id');
|
.returning('id');
|
||||||
} else {
|
} else {
|
||||||
insertResult = await trx('photos').insert({
|
insertResult = await trx('photos').insert(photoData);
|
||||||
event_id: eventId,
|
|
||||||
filename: newFilename,
|
|
||||||
path: relativePath,
|
|
||||||
thumbnail_path: relativeThumbPath,
|
|
||||||
type: photoType,
|
|
||||||
size_bytes: file.size,
|
|
||||||
uploaded_by: uploadedBy,
|
|
||||||
source_origin: 'managed',
|
|
||||||
mime_type: resolvedMime
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const insertedId = Array.isArray(insertResult)
|
const insertedId = Array.isArray(insertResult)
|
||||||
|
|||||||
Reference in New Issue
Block a user