Skip to content

Instantly share code, notes, and snippets.

@Miigon
Last active August 12, 2022 06:51
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 Miigon/0d5d0267a7581502f4c3b4dc361936ef to your computer and use it in GitHub Desktop.
Save Miigon/0d5d0267a7581502f4c3b4dc361936ef to your computer and use it in GitHub Desktop.
A bodged up tool to categorize videos and images into different folders easily.
<!-- NOTE: open this page in browser locally *without serving* (Author: miigon) -->
<body><div id="display" style="width: 100%; height: 75%; margin: 2px; border: solid;">
<video id="video" style="width: 100%; height: 100%;" controls autoplay></video>
<image id="image" style="width: 100%; height: 100%; object-fit: contain;"/>
</div>
<div id="text" style="width: 100%; height: 20%; margin: 2px; padding: 10px; border: solid;"></div>
<script>
di=document.getElementById("display");
vi=document.getElementById("video");
im=document.getElementById("image");
tx=document.getElementById("text");
next = async() => {
r=await(await fetch("http://localhost:8080/queryprogress")).json();
if(r.current == r.total) {
alert("all done! no file left.");
return;
}
console.log(r)
if(r.type=="video") {
vi.hidden = false; im.hidden = true;
vi.src = r.res;
vi.play();
} else {
im.hidden = false; vi.hidden = true;
im.src = r.res;
}
btns = r.dests.map((v,i) => `<button style="height: 2em;" onclick="clk(${i});">${v}</button>`).join(" ")
tx.innerHTML = `FILE ${(r.current+1)}/${r.total}<br>FILENAME: ${r.next}<br>TYPE: ${r.type}<br> OPERATION: ${btns}`;
}
clk = function(i) {
console.log(i)
tx.innerHTML = "moving file to " + r.dests[i];
vi.src = "";
setTimeout(async ()=>{
var res = await (await fetch("http://localhost:8080/move/"+r.next+"?dest="+i)).text()
if(res == "success") {
next();
} else {
alert("failed! check console for more.\n"+res);
}
},100); // wait 100ms, for video to unload
}
document.onkeypress = function (e) {
e = e || window.event;
key = e.keyCode - 49;
if(key >= 0 && key < r.dests.length) {
clk(key);
}
}
next();
</script>
</body>
// NOTE: run this script under Node.js (Author: miigon)
const ROOT_FOLDER = "./data"; // source
// destinations
const DESTS = ["./folder1", "./folder2", "./folder3", "./folder4", "./folder5", "./folder6"];
// images and videos extension names
const EXTNAMES_IMG = [".jpg", ".png"];
const EXTNAMES_VIDEO = [".mp4"];
// note: this tool only scans for files on startup
// if any file name changed, please restart the tool
const HOST = "localhost"; // use localhost for safety
const PORT = 8080;
const fs = require('fs');
const http = require('http');
const url = require('url');
const path = require('path');
function gettype(v) {
let ext = path.extname(v);
if(EXTNAMES_IMG.indexOf(ext) != -1) return "img";
if(EXTNAMES_VIDEO.indexOf(ext) != -1) return "video";
return "unknown";
}
console.log("reading directory...");
console.log("matching extensions: video:", EXTNAMES_VIDEO);
console.log("matching extensions: image:", EXTNAMES_IMG);
dir = fs.readdirSync(ROOT_FOLDER)
.sort() // could also sort by modified date using fs.statSync
.filter(v => gettype(v) != "unknown")
console.log("found files with matching extension: ", dir.length);
let current = 0;
http.createServer(async function (req, res) {
u = url.parse(req.url, true);
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept');
res.setHeader('Access-Control-Allow-Methods', 'POST, GET, PUT, DELETE, OPTIONS');
if(u.pathname.substr(0,6) == "/move/") {
let file = decodeURIComponent(u.pathname.substr(6))
let fullpath = path.join(ROOT_FOLDER, file);
let dest = Number(u.query["dest"]);
if(dir.indexOf(file) == -1) {
res.writeHead(400);
res.end("bad request: invalid file name");
} else if (Number.isNaN(dest) || dest < 0 || dest > DESTS.length) {
res.writeHead(400);
res.end("bad request: invalid dest");
} else {
res.writeHead(200);
console.log("move",fullpath,"to",DESTS[dest]);
fs.renameSync(fullpath,path.join(DESTS[dest], file));
current++;
res.end("success");
}
} else if(u.pathname == "/queryprogress") {
let next = dir[current] || "";
res.writeHead(200);
res.end(JSON.stringify({
total: dir.length, current, next, dests: DESTS,
//res: "file:///" + path.join(path.resolve(ROOT_FOLDER), next),
res: "file://" + path.join("/D:/projects/bodgeimagesort/data", next),
type: gettype(next),
}));
} else if(u.pathname == "/") {
res.writeHead(200);
res.end("just open bodgeimagesort.html locally in browser.");
} else {
await next();
}
}).listen(PORT, HOST);
console.log(`listening on ${HOST}:${PORT}... please open ./bodgeimagesort.html in browser (by double clicking the file)`);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment