improve useCompression service

This commit is contained in:
SrGooglo 2023-06-23 21:27:36 +00:00
parent a0b6e7bb01
commit cbee86dfb6
3 changed files with 106 additions and 80 deletions

View File

@ -0,0 +1,59 @@
import fs from "node:fs"
import path from "node:path"
import Sharp from "sharp"
const imageProcessingConf = {
// TODO: Get image sizeThreshold from DB
sizeThreshold: 10 * 1024 * 1024,
// TODO: Get image quality from DB
imageQuality: 80,
}
const imageTypeToConfig = {
png: {
compressionLevel: Math.floor(imageProcessingConf.imageQuality / 100),
},
default: {
quality: imageProcessingConf.imageQuality
}
}
/**
* Processes an image file and transforms it if it's above a certain size threshold.
*
* @async
* @function
* @param {Object} file - The file to be processed.
* @param {string} file.filepath - The path of the file to be processed.
* @param {string} file.hash - The hash of the file to be processed.
* @param {string} file.cachePath - The cache path of the file to be processed.
* @throws {Error} If the file parameter is not provided.
* @return {Object} The processed file object.
*/
async function processImage(file) {
if (!file) {
throw new Error("file is required")
}
const stat = await fs.promises.stat(file.filepath)
if (stat.size < imageProcessingConf.sizeThreshold) {
return file
}
let image = await Sharp(file.filepath)
const { format } = await image.metadata()
image = await image[format](imageTypeToConfig[format] ?? imageTypeToConfig.default).withMetadata()
const outputFilepath = path.resolve(file.cachePath, `${file.hash}_transformed.${format}`)
await transformResult.toFile(outputFilepath)
file.filepath = outputFilepath
return file
}
export default processImage

View File

@ -1,10 +1,8 @@
import fs from "node:fs"
import Jimp from "jimp"
import mimetypes from "mime-types"
import videoTranscode from "@services/videoTranscode"
const cachePath = global.cache.constructor.cachePath
import processVideo from "./video"
import processImage from "./image"
const fileTransformer = {
"video/avi": processVideo,
@ -20,82 +18,6 @@ const fileTransformer = {
"image/jfif": processImage,
}
const maximuns = {
imageResolution: {
width: 3840,
height: 2160,
},
imageQuality: 80,
}
async function processVideo(file) {
if (!file) {
throw new Error("file is required")
}
const result = await videoTranscode(file.filepath, file.cachePath, {
videoCodec: "libx264",
format: "mp4",
audioBitrate: 128,
videoBitrate: 1024,
})
file.filepath = result.filepath
file.filename = result.filename
return file
}
async function processImage(file) {
if (!file) {
throw new Error("file is required")
}
const { width, height } = await new Promise((resolve, reject) => {
Jimp.read(file.filepath)
.then((image) => {
resolve({
width: image.bitmap.width,
height: image.bitmap.height,
})
})
.catch((err) => {
reject(err)
})
})
if (width > maximuns.imageResolution.width || height > maximuns.imageResolution.height) {
await new Promise((resolve, reject) => {
// calculate max resolution respecting aspect ratio
const resizedResolution = {
width: maximuns.imageResolution.width,
height: maximuns.imageResolution.height,
}
if (width > height) {
resizedResolution.height = Math.floor((height / width) * maximuns.imageResolution.width)
}
if (height > width) {
resizedResolution.width = Math.floor((width / height) * maximuns.imageResolution.height)
}
Jimp.read(file.filepath)
.then((image) => {
image
.resize(resizedResolution.width, resizedResolution.height)
.quality(maximuns.imageQuality)
.write(file.filepath, resolve)
})
.catch((err) => {
reject(err)
})
})
}
return file
}
export default async (file) => {
if (!file) {
throw new Error("file is required")

View File

@ -0,0 +1,45 @@
import videoTranscode from "@services/videoTranscode"
/**
* Processes a video file based on the specified options.
*
* @async
* @param {Object} file - The video file to process.
* @param {Object} [options={}] - The options object to use for processing.
* @param {string} [options.videoCodec="libx264"] - The video codec to use.
* @param {string} [options.format="mp4"] - The format to use.
* @param {number} [options.audioBitrate=128] - The audio bitrate to use.
* @param {number} [options.videoBitrate=1024] - The video bitrate to use.
* @throws {Error} Throws an error if file parameter is not provided.
* @return {Object} The processed video file object.
*/
async function processVideo(
file,
options = {}
) {
if (!file) {
throw new Error("file is required")
}
// TODO: Get values from db
const {
videoCodec = "libx264",
format = "mp4",
audioBitrate = 128,
videoBitrate = 1024,
} = options
const result = await videoTranscode(file.filepath, file.cachePath, {
videoCodec,
format,
audioBitrate,
videoBitrate,
})
file.filepath = result.filepath
file.filename = result.filename
return file
}
export default processVideo