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.
201 lines
5.0 KiB
201 lines
5.0 KiB
const express = require('express')
|
|
const router = express.Router()
|
|
const async = require('async')
|
|
const path = require('path')
|
|
const multer = require('multer')
|
|
const fs = require('fs-extra')
|
|
const upload = multer({ dest: 'uploads' })
|
|
|
|
const sharp = require('sharp')
|
|
|
|
const TOL = require('../../tools/common')
|
|
const CFG = require('../../config')
|
|
var CTX = null
|
|
|
|
module.exports = function (pCtx) {
|
|
CTX = pCtx
|
|
router.post('/upload', upload.single('media'), handleUploadedMedia)
|
|
|
|
router.get('/get/:id', function (req, res) {
|
|
let mediaId = req.params.id
|
|
CTX.restapi.media.__services.readOne(mediaId, {projection: {path: 1}}, function (pErr, pResult) {
|
|
if (pErr) {
|
|
return res.status(404).send('Media:Media:NotFound')
|
|
}
|
|
let mediaPath = path.join(CFG.media.documents, pResult.data.path)
|
|
fs.access(mediaPath, fs.constants.F_OK, function (pErr) {
|
|
if (pErr) {
|
|
return res.status(404).send('Media:File:NotFound')
|
|
}
|
|
res.sendFile(mediaPath)
|
|
})
|
|
})
|
|
})
|
|
|
|
router.get('/preview/:id', function (req, res) {
|
|
let mediaId = req.params.id
|
|
CTX.restapi.media.__services.readOne(mediaId, {projection: {mimetype: 1, path: 1}}, function (pErr, pResult) {
|
|
if (pErr) {
|
|
return res.sendFile(CFG.media['404'])
|
|
}
|
|
|
|
let media = pResult.data
|
|
let mimetypes = media.mimetype.split('/')
|
|
let type = mimetypes[0]
|
|
let subtype = mimetypes[1]
|
|
|
|
switch (type) {
|
|
case 'image':
|
|
let mediaPath = path.join(CFG.media.documents, media.path)
|
|
getPreviewFromImage(res, mediaPath, req.query)
|
|
break
|
|
default:
|
|
res.sendFile(CFG.media['404'])
|
|
}
|
|
})
|
|
})
|
|
|
|
return router
|
|
}
|
|
|
|
function getPreviewFromImage (res, pPath, pQuery, pMedia) {
|
|
let query = pQuery
|
|
query.width = parseInt(query.width) || null
|
|
query.height = parseInt(query.height) || null
|
|
query.fit = query.fit || 'cover'
|
|
if (!query.width && !query.height) {
|
|
query.width = 1024
|
|
}
|
|
|
|
let outName = TOL.createHash(JSON.stringify(query), 'sha1')
|
|
let outPath = path.join(CFG.media.cache, generatePathFromMediaId(outName))
|
|
let outFull = path.join(outPath, `${outName}.jpg`)
|
|
|
|
let tasks = []
|
|
|
|
tasks.push(function (pCb) {
|
|
fs.ensureDir(outPath, pErr => pCb(pErr))
|
|
})
|
|
|
|
tasks.push(function (pCb) {
|
|
sharp(pPath)
|
|
.resize(query.width, query.height, {fit: query.fit})
|
|
.toFile(outFull, function (pErr) {
|
|
pCb(pErr)
|
|
})
|
|
})
|
|
|
|
async.waterfall(tasks, function (pErr) {
|
|
if (pErr) {
|
|
console.log(pErr)
|
|
res.sendFile(CFG.media['404'])
|
|
} else {
|
|
res.sendFile(outFull)
|
|
}
|
|
})
|
|
}
|
|
|
|
function handleUploadedMedia (req, res) {
|
|
let tasks = []
|
|
let file = req.file
|
|
let fileKey = {
|
|
coll: '__default',
|
|
id: '',
|
|
path: ''
|
|
}
|
|
let ext = getExtensionFromMimetype(file.mimetype)
|
|
let currentDate = new Date()
|
|
|
|
if (req.body.docColl && req.body.docId && req.body.docPath) {
|
|
fileKey = {
|
|
coll: req.body.docColl,
|
|
id: req.body.docId,
|
|
path: req.body.docPath
|
|
}
|
|
}
|
|
|
|
let mediaId = TOL.createHash(JSON.stringify(fileKey.coll === '__default' ? file : fileKey), 'sha1')
|
|
let outPath = path.join(CFG.media.documents, generatePathFromMediaId(mediaId))
|
|
let outName = `media.${ext}`
|
|
let outFull = path.join(outPath, outName)
|
|
let isAlreadyExisting = false
|
|
|
|
file.createdAt = currentDate
|
|
file.fileKey = fileKey
|
|
|
|
tasks.push(function (pCb) {
|
|
fs.ensureDir(outPath, pErr => pCb(pErr))
|
|
})
|
|
|
|
tasks.push(function (pCb) {
|
|
fs.move(file.path, outFull, { overwrite: true }, pErr => pCb(pErr))
|
|
})
|
|
|
|
tasks.push(function (pCb) {
|
|
fs.writeFile(path.join(outPath, 'info'), JSON.stringify(file, null, 2), 'utf8', pErr => pCb(pErr))
|
|
})
|
|
|
|
tasks.push(function (pCb) {
|
|
CTX.restapi.media.__services.readOne(mediaId, {projection: {_id: 1}}, function (pErr, pResult) {
|
|
if (pResult && pResult.ok) {
|
|
isAlreadyExisting = true
|
|
}
|
|
pCb()
|
|
})
|
|
})
|
|
|
|
tasks.push(function (pCb) {
|
|
let doc = {
|
|
_id: mediaId,
|
|
name: outName,
|
|
originalName: file.originalname,
|
|
extension: ext,
|
|
path: path.join(generatePathFromMediaId(mediaId), outName),
|
|
fileKey: fileKey,
|
|
mimetype: file.mimetype,
|
|
size: file.size
|
|
}
|
|
|
|
if (isAlreadyExisting) {
|
|
CTX.restapi.media.__services.update(mediaId, doc, req.user, 'media', function (pErr, pResult) {
|
|
pCb(pErr)
|
|
})
|
|
} else {
|
|
CTX.restapi.media.__services.create(doc, req.user, function (pErr, pResult) {
|
|
pCb(pErr)
|
|
})
|
|
}
|
|
})
|
|
|
|
async.waterfall(tasks, function (pErr) {
|
|
res.done(pErr, {
|
|
ok: pErr ? 0 : 1,
|
|
mediaId: mediaId
|
|
})
|
|
})
|
|
}
|
|
|
|
function generatePathFromMediaId (pMediaId) {
|
|
let outSubf = pMediaId.slice(0, 4)
|
|
return path.join(outSubf, pMediaId)
|
|
}
|
|
|
|
function getExtensionFromMimetype (pMimetype) {
|
|
let ext = 'unknown'
|
|
let mimetypes = pMimetype.split('/')
|
|
let type = mimetypes[0]
|
|
let subtype = mimetypes[1]
|
|
switch (type) {
|
|
case 'audio':
|
|
case 'video':
|
|
case 'image':
|
|
ext = subtype
|
|
break
|
|
case 'application/pdf':
|
|
ext = 'pdf'
|
|
break
|
|
default:
|
|
}
|
|
|
|
return ext
|
|
}
|