UNPKG

tidyup

Version:

A simple CLI tool to organize files in a directory into categorized subfolders based on file types.

145 lines (141 loc) 5.55 kB
#!/usr/bin/env node "use strict"; var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); // src/index.ts var import_commander = require("commander"); var import_fs = __toESM(require("fs")); var import_path = __toESM(require("path")); var import_util = require("util"); // package.json var version = "0.0.7"; // src/index.ts var readdir = (0, import_util.promisify)(import_fs.default.readdir); var mkdir = (0, import_util.promisify)(import_fs.default.mkdir); var rename = (0, import_util.promisify)(import_fs.default.rename); var stat = (0, import_util.promisify)(import_fs.default.stat); var FILE_TYPE_MAP = { ".png": "images-png", ".jpg": "images-jpg", ".jpeg": "images-jpeg", ".mp4": "videos-mp4", ".avi": "videos-avi", ".pdf": "documents-pdf" }; var program = new import_commander.Command(); program.version(version).argument("[directory]", "Directory to tidy up", ".").description("Organize files in a directory based on their extensions").option("--ext", "Use the file extetions as folder names").option("--name", "Group files by starting name").action(async (inputDir, option) => { const dirPath = import_path.default.resolve(inputDir); try { if (option.ext && option.name) { console.error("Only one of --ext or --name can be used at a time"); process.exit(1); } const dirStat = await stat(dirPath); if (!dirStat.isDirectory()) { console.error(`The provided path is not a directory: ${dirPath}`); process.exit(1); } await organizeFiles(dirPath, option); } catch (error) { console.error("An error occurred:", error.message); process.exit(1); } }); program.parse(process.argv); async function getFileTypes(dirPath) { const files = await readdir(dirPath); const fileTypes = {}; for (const file of files) { const filePath = import_path.default.join(dirPath, file); const fileStat = await stat(filePath); if (fileStat.isFile()) { const ext = import_path.default.extname(file).toLowerCase(); if (!fileTypes[ext]) { fileTypes[ext] = []; } fileTypes[ext].push(filePath); } } return fileTypes; } async function getFileNameGroups(dirPath) { const files = await readdir(dirPath); const nameGroups = {}; for (const file of files) { const filePath = import_path.default.join(dirPath, file); const fileStat = await stat(filePath); if (fileStat.isFile()) { const baseName = import_path.default.parse(file).name.slice(0, 10); if (!nameGroups[baseName]) { nameGroups[baseName] = []; } nameGroups[baseName].push(filePath); } } return nameGroups; } async function organizeFiles(dirPath, options) { let fileTypes; if (options.name) { fileTypes = await getFileNameGroups(dirPath); } else { fileTypes = await getFileTypes(dirPath); } const summary = []; for (const [ext, filePaths] of Object.entries(fileTypes)) { const newFolder = ext.split(".")[1]; const folderName = options.ext ? newFolder : FILE_TYPE_MAP[ext] || `others-${ext.replace(".", "")}`; const folderPath = import_path.default.join(dirPath, folderName); let folderCreated = false; if (!import_fs.default.existsSync(folderPath)) { await mkdir(folderPath); folderCreated = true; } let filesAdded = 0; for (const filePath of filePaths) { const fileName = import_path.default.basename(filePath); let newFilePath = import_path.default.join(folderPath, fileName); if (import_fs.default.existsSync(newFilePath)) { const fileBase = import_path.default.parse(fileName).name; const fileExt = import_path.default.extname(fileName); let counter = 1; while (import_fs.default.existsSync(newFilePath)) { const newFileName = `${fileBase}(${counter})${fileExt}`; newFilePath = import_path.default.join(folderPath, newFileName); counter++; } } await rename(filePath, newFilePath); filesAdded++; } summary.push({ folder: folderName, created: folderCreated, filesAdded }); } const lastPath = dirPath.split("/"); const lastDir = lastPath[lastPath.length - 1]; console.log(`Organization Summary for '${lastDir}':`); for (const { folder, created, filesAdded } of summary) { console.log(`- Folder: ${folder}`); console.log(` - ${created ? "Created" : "Already existed"}`); console.log(` - Files added: ${filesAdded}`); } }