Skip to content

Instantly share code, notes, and snippets.

@sawaYch
Last active September 6, 2023 00:37
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sawaYch/dec742791404e87ed2932325fe41484a to your computer and use it in GitHub Desktop.
Save sawaYch/dec742791404e87ed2932325fe41484a to your computer and use it in GitHub Desktop.
batch convert webp to webm, maybe useful for converting Whatsapp sticker to Telegram.
/**
require webp & libwebp, see https://developers.google.com/speed/webp/download
run:
cd working_dir # suppose working dir contains all webp that u want to convert
node ./convert.js # wait for it until done
*/
const child = require("child_process");
const fs = require("fs");
const path = require("path");
const util = require("util");
const readdir = util.promisify(fs.readdir);
const exec = util.promisify(child.exec);
const terminateWithError = (error = "[fatal] error") => {
console.log(error);
process.exit(1);
};
const converter = (filenames) => {
const filename = filenames.shift();
const nameWithoutExt = filename.replace(".webp", "");
const frames = path.resolve(process.cwd(), "frames");
if (fs.existsSync(frames)) fs.rmdirSync(frames, { recursive: true });
fs.mkdirSync(frames);
process.chdir("frames");
console.log("[info]", process.cwd());
console.log("[info]", `anim_dump ../${filename}`);
exec(`anim_dump ../${filename}`)
.then(() => {
process.chdir("..");
console.log("[info]", process.cwd());
const command = `webpmux -info ./${filename}`;
console.log("[info]", command);
return exec(command);
})
.then(({ stdout, stderr }) => {
if (stderr) return Promise.reject(stderr);
const isAnimation = stdout.match(/Features present: animation/) !== null;
if (!isAnimation)
return Promise.reject("This is not an animated webp file");
const firstLine = stdout.match(/1:.+[\r]?\n/g);
if (!firstLine) return;
const frameLength = firstLine[0].split(/\s+/g)[6];
console.log('frame length', frameLength)
const framerate = 11;//Math.round(1000 / frameLength); // frames/second
const dump = path.resolve(frames, "dump_%04d.png");
const command = `ffmpeg -framerate ${framerate} -i "${dump}" -crf 0 -b:v 0.8M -b:a 124K "${nameWithoutExt}.webm" -y`;
console.log("[info]", command);
return exec(command);
})
.then(({ stdout, stderr }) => {
if (/error/gm.test(stderr)) return Promise.reject(stderr);
fs.rmdirSync(frames, { recursive: true });
if (filenames.length != 0) converter(filenames);
console.log("[info] Success!\n");
})
.catch((err) => {
terminateWithError(`[fatal] ${err}`);
fs.rmdirSync(frames, { recursive: true });
});
};
const getWebFiles = async () => {
let fileName;
try {
fileName = await readdir("./");
} catch (err) {
console.log(err);
}
return fileName.filter((it) => it.endsWith(".webp"));
};
getWebFiles().then((filenames) => {
converter(filenames);
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment