You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
core/src/factories/media.js

217 lines
5.5 KiB

const path = require('path')
const fs = require('fs')
const sharp = require('sharp')
const mkdirp = require('mkdirp')
const crypto = require('crypto')
const slugify = require('slugify')
const configStore = require('./../config.js')
/**
* Media
*
* change size, optimize and copy media to assets
*
* @author Björn Hase <me@herr-hase.wtf>
* @license http://opensource.org/licenses/MIT The MIT License
* @link https://gitea.node001.net/HerrHase/siteomat-webpack-plugin.git
*
*/
class Media {
constructor(path = NULL) {
this._path = path
this._DIR_ASSETS = '/assets/'
}
/**
* resolve media
*
* @param {string} src
* @param {object} sizes
* @param {Object} [options={}]
* @return {string}
*
*/
resolve(src, sizes = {}, options = {}) {
let extension = path.extname(src)
let sourcePath
const filename = slugify(path.basename(src, extension))
// check for images in path
if (this._path && fs.existsSync(configStore.get('source') + this._path + '/' + src)) {
sourcePath = configStore.get('source') + this._path + '/' + src
} else {
sourcePath = configStore.get('source') + '/' + src
}
// getting sharp
const process = sharp(sourcePath)
if (extension === '.gif') {
process
.gif({
reoptimise: true
})
} else {
// change extension
extension = '.webp'
process
.webp({
lossless: true
})
}
// destination
const destinationPath = this._getDestinationPath(sourcePath)
// create files to write
const filesToWrite = this._getFilesToWrite(filename, extension, destinationPath, sizes)
// results contains only path as strings
const results = {}
// create path if not exists
if (!fs.existsSync(configStore.get('destination') + destinationPath)) {
mkdirp.sync(configStore.get('destination') + destinationPath)
}
filesToWrite.forEach((file) => {
if (!fs.existsSync(configStore.get('destination') + file.path)) {
this._writeFile(file, process, options)
}
results[file.name] = file.path
})
return this._reduce(results)
}
/**
* if only full is in results, reduce object to string
*
* @param {Object} results
* @return {mixed}
*
*/
_reduce(results) {
if (Object.getOwnPropertyNames(results).length === 1) {
results = results['full']
}
return results
}
/**
* getting files to write
*
* @param {string} src
* @param {string} extension
* @param {Object} sizes
* @return {string}
*/
_getFilesToWrite(filename, extension, destinationPath, sizes) {
const results = []
// add orginal
results.push(this._getFile(filename, destinationPath, extension))
// check for sizes
if (typeof sizes === 'object' && !Array.isArray(sizes)) {
results.push(this._getFile(filename, destinationPath, extension, sizes))
} else if (Array.isArray(sizes)) {
sizes.forEach((size) => {
results.push(this._getFile(filename, destinationPath, extension, size))
})
}
return results
}
/**
* write files to destination
*
* @param {string} file
* @param {object} process
* @param {Object} options
*/
_writeFile(file, process, options) {
// resize without options and with options
if (file.sizes && Object.getOwnPropertyNames(options).length === 0 && Object.getOwnPropertyNames(file.sizes).length > 0) {
process.resize(file.sizes)
} else if (file.sizes && Object.getOwnPropertyNames(options).length > 0 && Object.getOwnPropertyNames(file.sizes).length > 0) {
process.resize(file.sizes, options)
}
process.toFile(configStore.get('destination') + file.path)
}
/**
* generate destination path from hash of file
*
* @param {string}
* @return {string}
*/
_getDestinationPath(sourcePath) {
const hash = crypto.createHash('sha1')
const file = fs.readFileSync(sourcePath)
// getting hash from file
hash.update(file)
return this._DIR_ASSETS + hash.digest('hex').match(new RegExp('.{1,8}', 'g')).join('/')
}
/**
* create file as object, adding path, name with sizes
*
* @param {string} filename
* @param {object} destinationPath
* @param {Object} extension
* @param {sizes} sizes
* @return {object}
*/
_getFile(filename, destinationPath, extension, sizes = undefined) {
let file = {
name: ''
}
let prefix = ''
// check for sizes
if (sizes && sizes.width) {
file.name += sizes.width
}
if (sizes && sizes.height) {
if (sizes.width) {
prefix = 'x'
}
file.name += prefix + sizes.height
}
// create path before name is set to orginal as fallback
file.path = destinationPath + '/' + filename + file.name + extension
if (!file.name) {
file.name = 'full'
}
if (sizes) {
file.sizes = sizes
}
return file
}
}
module.exports = Media