sheercms
Version:
Sheer Cliff CMS is a simple and powerful content management system (CMS) for Node JS.
413 lines (375 loc) • 13.6 kB
JavaScript
/*
The media plugin controls how media items (images, files, etc) are saved and retrieved.
For example, there could be a plugin for the file system or one for Amazon S3.
*/
var logger = require('../../lib/logger');
var S = require('string');
var path_mod = require('path');
var fs = require('fs');
var cms = require('../../index');
var utils = require('../../lib/utilities');
var async = require("async");
var config = require("../../lib/config");
var gm = require('gm');
module.exports.init = function(server, done) {
done();
};
/*
callback: ( err, result {path, url} )
*/
module.exports.writeMedia = function(item, group, path, size, callback) {
try {
//make sure the path has the root in it
var root = cms.getRoot();
if (path.indexOf(root) < 0)
path = path_mod.join(root, path);
var contentId = item.contentId.toString();
//get the file extension
var ext = path_mod.extname(path);
if (ext)
ext = ext.toLowerCase();
//figure out the file name
var dirs = [];
//top level media folder
dirs.push(path_mod.join(root, 'media'));
//second level media folder
var type = cms.api.contentTypes.getContentTypeSync(item.typeId);
var typeDir = type.mediaType || 'files';
typeDir = makePlural(typeDir.toLowerCase());
dirs.push(path_mod.join(root, 'media', typeDir));
//letter directory - last letter of the contentId
var letter = contentId.substr(contentId.length - 1, 1).toLowerCase();
dirs.push(path_mod.join(dirs[1], letter));
var url = '/' + path_mod.join('media', typeDir, contentId + ext);
ensureDirectories(dirs, function(err) {
try {
if (err) {
if (callback) callback(err);
}
else {
var newPath = path_mod.join(dirs[2], contentId + ext);
var relPath = '/' + path_mod.join('media', typeDir, letter, contentId + ext);
if (type.mediaType === "Image") {
logger.info("Resizing and renaming '" + path + "' to '" + newPath + "'");
//get the media settings for resizing
var mediaSettings = group.mediaSettings || {};
var imageMaxWidth = mediaSettings.imageWidth || config.settings.image_max_width;
var imageMaxHeight = mediaSettings.imageHeight || config.settings.image_max_height;
var imageQuality = mediaSettings.imageQuality || 100;
var resizeMode = mediaSettings.resizeMode || 'none';
resizeImageAndMove(path, newPath, imageMaxWidth, imageMaxHeight, imageQuality, resizeMode, function(err) {
if (err) {
logger.error(err);
if (callback) callback(err);
}
else {
try {
//create the thumbnail
var tPath = path_mod.join(dirs[2], contentId + '-thumb' + ext);
createThumbnail(newPath, tPath, false, function (err) {
if (err) {
if (callback) callback(err);
}
else {
if (callback) callback(null, {path: relPath, url: url});
}
});
}
catch (e) {
logger.error(e);
if (callback) callback(e);
}
}
});
}
else if (item.branch === 'media') {
fs.rename(path, newPath, function (err) {
if (err) {
logger.error(err);
if (callback) callback(err);
}
else {
if (callback) callback(null, {path: relPath, url: url});
}
});
}
}
}
catch(e) {
logger.error(e);
if (callback) callback(e);
}
});
}
catch(e) {
logger.error(e);
if (callback) callback(e);
}
};
/*
callback: (err)
*/
function resizeImageAndMove(path, newPath, maxWidth, maxHeight, quality, mode, callback) {
//get the image size
gm(path).size(function (err, value) {
try {
if (err) {
callback(err);
}
else {
var resized = false;
//see if we need to resize the image
if (mode === 'max' && (value.width > maxWidth || value.height > maxHeight)) {
//resize down to the max width & height
gm(path)
.resize(maxWidth, maxHeight)
.compress('JPEG')
.quality(quality)
.write(newPath, function (err) {
callback(err);
});
}
else if (mode === 'crop' && (value.width > maxWidth || value.height > maxHeight)) {
//crop to max
gm(path)
.resize(maxWidth, maxHeight, '^')
.gravity('Center')
.crop(maxWidth, maxHeight)
.compress('JPEG')
.quality(quality)
.write(newPath, function (err) {
callback(err);
});
}
else if (mode === 'stretch' && (value.width != maxWidth || value.height != maxHeight)) {
//force resize to exact size
gm(path)
.resize(maxWidth, maxHeight, "!")
.compress('JPEG')
.quality(quality)
.write(newPath, function (err) {
callback(err);
});
}
else {
if (quality == 100) {
//don't change the image, just move it
fs.rename(path, newPath, function (err) {
callback(err);
});
}
else {
//save with new quality
gm(path)
.compress('JPEG')
.quality(quality)
.write(newPath, function (err) {
callback(err);
});
}
}
}
}
catch(e) {
logger.error(e);
if (callback) callback(e);
}
});
}
function makePlural(s) {
if (s === 'image')
return 'images';
else if (s === 'file')
return 'files';
else if (s === 'video')
return 'videos';
else if (s === 'audio')
return 'audio';
else
return s;
}
/*
callback: (err)
*/
function createThumbnail(path, tPath, bDelete, callback) {
try {
gm(path)
.resize(config.settings.thumbnail_width, config.settings.thumbnail_height)
.write(tPath, function (err) {
try {
if (err) {
logger.error(err);
if (callback) callback(err);
}
else {
if (bDelete == true) {
//now delete the temp image
fs.unlink(path, function (err) {
if (err) {
logger.error(err);
if (callback) callback(err);
}
else {
if (callback) callback(null);
}
});
}
else {
if (callback) callback(null);
}
}
}
catch (e) {
logger.error(e);
if (callback) callback(e);
}
});
}
catch(e) {
logger.error(e);
if (callback) callback(e);
}
}
/*
callback: (err)
*/
module.exports.deleteMedia = function(item, callback) {
try {
//get the file path
var path = item.filePath;
if (!path || path.length == 0) {
if (callback) callback(null);
return;
}
path = path_mod.join(cms.getRoot(), path);
var arr = [];
arr.push(path);
var type = cms.api.contentTypes.getContentTypeSync(item.typeId);
if (!type) {
var e = new Error('Content type not found: ' + item.typeId);
logger.error(e);
if (callback) callback(e);
return;
}
if (type.mediaType == "Image") {
//change the path to the thumbnail path
var ext = path_mod.extname(path);
if (ext && ext.length > 0)
arr.push(path.replace(ext, "-thumb" + ext));
}
async.each(arr, function (file, done) {
logger.info("Deleting file: " + file);
fs.exists(file, function (exists) {
try {
if (exists) {
fs.unlink(file, function (err) {
if (err) {
logger.error(err);
done(err);
}
else
done();
});
}
else
done();
}
catch(e) {
logger.error(e);
done(e);
}
});
}, function (err) {
if (callback)
callback(err);
});
}
catch(e) {
logger.error(e);
if (callback) callback(e);
}
};
module.exports.renderMedia = function(req, res, item) {
try {
//get the file path
var path = item.filePath;
if (!path || path.length == 0)
throw new Error("File path not found for media item: " + item.contentId);
path = path_mod.join(cms.getRoot(), path);
var type = cms.api.contentTypes.getContentTypeSync(item.typeId);
if (!type) {
var e = new Error('Content type not found: ' + item.typeId);
logger.error(e);
if (callback) callback(e);
return;
}
if (type.mediaType === "Image" && req.query.thumb) {
//change the path to the thumbnail path
var ext = path_mod.extname(path);
if (ext && ext.length > 0)
path = path.replace(ext, "-thumb" + ext);
}
var age = 0;
if (type.mediaType === "Image" && config.settings.image_max_days)
age = parseInt(config.settings.image_max_days) * 1440000;
if (type.mediaType === 'Image') {
var mime = 'image/';
if (item.filePath.indexOf('.gif') > 0)
mime += 'gif';
else if (item.filePath.indexOf('.png') > 0)
mime += 'png';
else
mime += 'jpg';
res.setHeader('content-type',mime);
}
res.sendfile(path, {maxAge: age});
}
catch(e) {
logger.error(e);
res.send(500, 'Error rendering the media item for this URL.');
}
};
/*
callback: (err, data)
*/
module.exports.readMedia = function(item, callback) {
if (callback) {
try {
//get the file path
var path = item.filePath;
if (!path || path.length == 0)
throw new Error("File path not found for media item: " + item.contentId);
path = path_mod.join(cms.getRoot(), path);
fs.readFile(path, callback);
}
catch (e) {
logger.error(e);
res.send(500, 'Error rendering the media item for this URL.');
}
}
};
/*
callback: (err)
*/
function ensureDirectories(dirs, callback) {
try {
async.eachSeries(dirs, function (dir, done) {
logger.info("Ensuring directory: " + dir);
utils.ensureDirectoryExists(dir, function (err, created) {
done(err);
});
}, function (err) {
if (err) {
logger.error(err);
if (callback) callback(err);
}
else {
if (callback) callback(null);
}
});
}
catch(e) {
logger.error(e);
if (callback) callback(e);
}
};