Skip to content

Instantly share code, notes, and snippets.

@alexrintt
Last active May 22, 2023 17:46
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 alexrintt/8d95037da70676c5ea0db503ab563ca3 to your computer and use it in GitHub Desktop.
Save alexrintt/8d95037da70676c5ea0db503ab563ca3 to your computer and use it in GitHub Desktop.
Nodejs script to run exiftool recursively in a directory from the windows explorer right-click context menu.
import { execSync } from "node:child_process";
const workdir = process.argv[2] || process.cwd();
import { resolve, basename, dirname } from "path";
import { readdirSync, renameSync } from "fs";
import { join } from "node:path";
import { closeSync, existsSync, openSync, rmSync, watch } from "node:fs";
async function* getFiles(dir) {
const dirents = readdirSync(dir, { withFileTypes: true });
for (const dirent of dirents) {
const res = resolve(dir, dirent.name);
if (dirent.isDirectory()) {
yield* getFiles(res);
} else {
yield res;
}
}
}
async function getKeypress() {
return new Promise((resolve) => {
var stdin = process.stdin;
stdin.setRawMode(true); // so get each keypress
stdin.resume(); // resume stdin in the parent process
stdin.once("data", onData); // like on but removes listener also
function onData(buffer) {
stdin.setRawMode(false);
resolve(buffer.toString());
}
});
}
/**
* Returns a hash code from a string
* @param {String} str The string to hash.
* @return {Number} A 32bit integer
* @see http://werxltd.com/wp/2010/05/13/javascript-implementation-of-javas-string-hashcode-method/
*/
function hashCode(str) {
let hash = 0;
for (let i = 0, len = str.length; i < len; i++) {
let chr = str.charCodeAt(i);
hash = (hash << 5) - hash + chr;
hash |= 0; // Convert to 32bit integer
}
return hash;
}
function isWritable(filePath) {
let fileAccess = false;
try {
closeSync(openSync(filePath, "r+"));
fileAccess = true;
} catch (err) {
console.log({ err });
}
return fileAccess;
}
async function toArray(asyncIterator) {
const arr = [];
for await (const i of asyncIterator) arr.push(i);
return arr;
}
function purifyFile(file) {
try {
if (!isWritable(file)) {
return;
}
const parent = dirname(file);
const hashName = Math.abs(hashCode(file)).toString("16");
const temp = join(parent, hashName);
console.log(`${file} -> ${temp}`);
renameSync(file, temp);
try {
execSync(`exiftool -s -all= "${temp}"`);
} catch (e) {
} finally {
renameSync(temp, file);
try {
rmSync(temp + "_original");
} catch (e) {
// console.log({ e });
return;
}
}
} catch (e) {
console.log({
err: e,
});
}
}
(async () => {
const files = await toArray(getFiles(workdir));
for (const file of files) {
purifyFile(file);
}
})();
{
"name": "exiftool",
"version": "1.0.0",
"description": "",
"main": "index.js",
"type": "module",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC"
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment