mirror of
https://github.com/ragestudio/comty.git
synced 2025-06-10 19:14:16 +00:00
improve useCompression
service
This commit is contained in:
parent
a0b6e7bb01
commit
cbee86dfb6
@ -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
|
@ -1,10 +1,8 @@
|
|||||||
import fs from "node:fs"
|
import fs from "node:fs"
|
||||||
import Jimp from "jimp"
|
|
||||||
import mimetypes from "mime-types"
|
import mimetypes from "mime-types"
|
||||||
|
|
||||||
import videoTranscode from "@services/videoTranscode"
|
import processVideo from "./video"
|
||||||
|
import processImage from "./image"
|
||||||
const cachePath = global.cache.constructor.cachePath
|
|
||||||
|
|
||||||
const fileTransformer = {
|
const fileTransformer = {
|
||||||
"video/avi": processVideo,
|
"video/avi": processVideo,
|
||||||
@ -20,82 +18,6 @@ const fileTransformer = {
|
|||||||
"image/jfif": processImage,
|
"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) => {
|
export default async (file) => {
|
||||||
if (!file) {
|
if (!file) {
|
||||||
throw new Error("file is required")
|
throw new Error("file is required")
|
||||||
|
@ -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
|
Loading…
x
Reference in New Issue
Block a user