Skip to content

Instantly share code, notes, and snippets.

@o-az
Last active February 15, 2023 22:56
Show Gist options
  • Save o-az/d2b707b96b2729edeedc0abe194db4a0 to your computer and use it in GitHub Desktop.
Save o-az/d2b707b96b2729edeedc0abe194db4a0 to your computer and use it in GitHub Desktop.
#!/usr/bin/env ts-node
import fs from "node:fs/promises";
import tinify from "tinify";
/**
* This script will travel through the public folder and its subdirectories and
* compress all images with tinify. It will also convert all images to webp.
* then it will delete the original images.
*
* You can run this with ts-node:
*
* TINIFY_API_KEY="APT_KEY_HERE" node_modules/.bin/ts-node tinify.mts
*/
const API_KEY = process.env.TINIFY_API_KEY;
if (!API_KEY) throw new Error("TINIFY_API_KEY is not set");
// set tinify key
Object.assign(tinify, { key: API_KEY });
// supported extensions
const extensions = ["jpg", "jpeg", "png"];
// path to images
const imagesPath = "./public";
processPath(imagesPath)
.then(() => {
console.log("done");
process.exit(0);
})
.catch((error) => {
console.error(error);
process.exit(1);
});
async function processPath(path: string) {
const paths = await fs.readdir(path);
for (let item of paths) {
item = `${path}/${item}`;
const pathType = await getPathType(item);
if (pathType === "skip") continue;
if (pathType === "directory") await processPath(item);
if (pathType === "image") {
const { extension } = await fileInfo(item);
await processImage(item);
await fs.rename(`${item}.webp`, item.replace(extension, "webp"));
await fs.unlink(item);
}
}
}
async function fileInfo(path: string) {
const [, name, extension] = path.split(".");
return { name, extension };
}
async function getPathType(
path: string
): Promise<"image" | "directory" | "skip"> {
return (await fs.stat(path)).isDirectory()
? "directory"
: extensions.includes((await fileInfo(path)).extension)
? "image"
: "skip";
}
async function compress(image: string) {
return await tinify.fromFile(image).toFile(`${image}`);
}
async function convert(image: string, to: "webp" | "jpg" | "png") {
const source = tinify.fromFile(image);
const converted = source.convert({ type: `image/${to}` });
const extension = await converted.result().extension();
await converted.toFile(`${image}.${extension}`);
}
async function processImage(filename: string) {
console.log(`Compressing ${filename}...`);
await convert(filename, "webp");
await compress(filename);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment