Implement video region support
This commit is contained in:
@@ -1,3 +1,6 @@
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
module.exports = function registerAdminContentRoutes(app, deps) {
|
||||
const pool = deps.pool;
|
||||
const common = deps.common;
|
||||
@@ -23,6 +26,8 @@ module.exports = function registerAdminContentRoutes(app, deps) {
|
||||
const { buildPagination } = require('../../lib/pagination');
|
||||
|
||||
const LIST_PAGE_SIZE = 10;
|
||||
const IMAGE_UPLOAD_MAX_BYTES = 100 * 1024 * 1024;
|
||||
const VIDEO_UPLOAD_MAX_BYTES = 1024 * 1024 * 1024;
|
||||
|
||||
if (!pool || !common || !pages || !upload || typeof fetchScreensBySlideId !== 'function' || typeof fetchScreensByTemplateId !== 'function' || typeof collectUploadReferencesFromSlide !== 'function' || typeof collectUploadReferencesFromTemplate !== 'function' || typeof collectUploadReferencesFromPayload !== 'function' || typeof removeUnusedUploadFiles !== 'function' || typeof syncPlaylistUploadsOnChange !== 'function' || typeof getAuditUserId !== 'function' || typeof redirectAfterSave !== 'function' || typeof notifyPlayerScreens !== 'function' || typeof broadcastDashboardState !== 'function' || typeof getSlideDeleteBlockMessage !== 'function' || typeof getTemplateDeleteBlockMessage !== 'function' || typeof getCanvasSizeDeleteBlockMessage !== 'function' || typeof hasAnyPermission !== 'function') {
|
||||
throw new Error('registerAdminContentRoutes requires the content route dependencies.');
|
||||
@@ -43,6 +48,62 @@ module.exports = function registerAdminContentRoutes(app, deps) {
|
||||
next(error);
|
||||
}
|
||||
|
||||
function getUploadedFileMediaType(file) {
|
||||
const mimeType = String(file && file.mimetype || '').trim().toLowerCase();
|
||||
const extension = path.extname(String(file && file.originalname || '')).toLowerCase();
|
||||
if (mimeType.indexOf('video/') === 0 || ['.mp4', '.webm', '.ogg', '.ogv', '.mov', '.avi', '.mkv'].indexOf(extension) !== -1) {
|
||||
return 'video';
|
||||
}
|
||||
if (mimeType.indexOf('image/') === 0 || ['.png', '.jpg', '.jpeg', '.gif', '.webp', '.bmp', '.avif', '.tif', '.tiff'].indexOf(extension) !== -1) {
|
||||
return 'image';
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function getUploadedFileLimitBytes(file) {
|
||||
return getUploadedFileMediaType(file) === 'video' ? VIDEO_UPLOAD_MAX_BYTES : IMAGE_UPLOAD_MAX_BYTES;
|
||||
}
|
||||
|
||||
function getUploadedFileLimitLabel(file) {
|
||||
return getUploadedFileMediaType(file) === 'video' ? '1 GB' : '100 MB';
|
||||
}
|
||||
|
||||
async function removeUploadedFile(file) {
|
||||
if (!file || !file.filename || !deps.uploadDir) {
|
||||
return;
|
||||
}
|
||||
|
||||
const filePath = path.join(deps.uploadDir, file.filename);
|
||||
try {
|
||||
await fs.promises.unlink(filePath);
|
||||
} catch (_error) {
|
||||
// Ignore cleanup failures.
|
||||
}
|
||||
}
|
||||
|
||||
async function validateUploadedFiles(files) {
|
||||
const list = Array.isArray(files) ? files.filter(Boolean) : [];
|
||||
for (let i = 0; i < list.length; i += 1) {
|
||||
const file = list[i];
|
||||
const mediaType = getUploadedFileMediaType(file);
|
||||
if (!mediaType) {
|
||||
await removeUploadedFile(file);
|
||||
const error = new Error('Unsupported upload type.');
|
||||
error.statusCode = 400;
|
||||
error.expose = true;
|
||||
throw error;
|
||||
}
|
||||
|
||||
if (Number(file.size || 0) > getUploadedFileLimitBytes(file)) {
|
||||
await removeUploadedFile(file);
|
||||
const error = new Error('File must be ' + getUploadedFileLimitLabel(file) + ' or smaller.');
|
||||
error.statusCode = 400;
|
||||
error.expose = true;
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function queueSlideThumbnailRefresh(slideId, previousThumbnailPath) {
|
||||
if (!backgroundTaskQueue || typeof backgroundTaskQueue.enqueueTask !== 'function') {
|
||||
return Promise.resolve(null);
|
||||
@@ -168,6 +229,8 @@ module.exports = function registerAdminContentRoutes(app, deps) {
|
||||
return res.status(400).json({ error: 'No file was uploaded.' });
|
||||
}
|
||||
|
||||
await validateUploadedFiles([req.file]);
|
||||
|
||||
res.json({
|
||||
path: '/media/uploads/' + req.file.filename,
|
||||
filename: req.file.filename,
|
||||
@@ -195,6 +258,7 @@ module.exports = function registerAdminContentRoutes(app, deps) {
|
||||
|
||||
app.post('/slides', requirePermission('slides.create'), upload.any(), async function (req, res, next) {
|
||||
try {
|
||||
await validateUploadedFiles(req.files || []);
|
||||
const payload = await common.buildSlidePayload(pool, req, null);
|
||||
if (await common.fetchDuplicateName(pool, 'slides', payload.title, null, 'title')) {
|
||||
return res.status(400).send('A slide with that title already exists.');
|
||||
@@ -225,6 +289,7 @@ module.exports = function registerAdminContentRoutes(app, deps) {
|
||||
|
||||
app.post('/slides/:id', requirePermission('slides.update'), upload.any(), async function (req, res, next) {
|
||||
try {
|
||||
await validateUploadedFiles(req.files || []);
|
||||
const slide = await common.fetchSlideById(pool, Number(req.params.id));
|
||||
if (!slide) {
|
||||
return res.status(404).send('Slide not found');
|
||||
|
||||
Reference in New Issue
Block a user