Today I’ll show you how I keep my files organised with my custom script using Node.js. I’ll also link a Youtube link below if you prefer video format.
You can also find the Github link here.
The problem I’m solving
Not sure if it’s just me, but I’m really bad at keeping my files organised. My desktop alone has hundreds of files sometimes but my Downloads folder is no different. Sorting it manually is a pain so I just don’t do it, resulting in a bigger pile.
I came up with this script on a regular afternoon after I looked at my files and I felt overwhelmed by the sheer amount of them. It’s really simple, the only thing it does is it reads every file in the folder you invoke it, gets the extension of each file and sorts each file by their extension/media type. Formats like .png
, .jpg
goes to the Images
folder while .mp3
or .flac
goes to the Audio
folder.
Now with this out of the way, it’s time to get started.
Step 1 — Define the extensions and destination folders
For this I’ll use an object to sort the extensions to a single folder. The object key will represent the destination folder, and the value will be an array of extensions that belong into the given folder. Let’s create it, and if you’d like to modify it to your own needs, add extra folders/extensions, feel free to go ahead. I’ll also import some dependencies we’ll use later and a CURRENT_DIR
directory that we’ll use to decide where we run our script.
const fs = require("fs");
const path = require("path");
const CURRENT_DIR = process.argv[2] || "./";
const FILE_EXTENSIONS = {
Images: [
".jpg",
".jpeg",
".jpe",
".png",
".gif",
".webp",
".bmp",
".svg",
".ico",
],
Videos: [
".webm",
".mpeg",
".ogg",
".mp4",
".avi",
".wmv",
".mov",
".qt",
".flv",
],
Audio: [".flac", ".mp3", ".wav"],
Documents: [
".doc",
".docx",
".pdf",
".xls",
".xlsx",
".ppt",
".pptx",
".txt",
],
};
Step 2 — Function to find the target folder by extension
For this function we’ll use the path.extname
built-in function that can help us giving the extension of a file. Once we have that, we’ll have to loop through our FILE_EXTENSIONS
object, and check every array if it contains the extension of our current file. If it does, we’ll return the name of the folder.
const findExtension = (file) => {
const fileExtension = path.extname(file);
const [folderName] =
Object.entries(FILE_EXTENSIONS).find(([, extensions]) =>
extensions.includes(fileExtension)
) || [];
return folderName;
};
Step 3 — Function to create the target folder
Now, when we sort our files and move them, there is no guarantee the target folder exists. In that case we need to create it otherwise we can’t move the file into the given destination and we’ll also be facing an error. This function will take in a string as an argument that’ll be the name of our new folder. We’ll use the fs.promises.mkdir
function to create a folder for us. This function is identical to the fs.mkdir
function, the only difference is the return value. As the name suggests, fs.promises.mkdir
returns a promise, and I prefer that over handling callbacks.
I also invoked it with { recursive: true }
that’ll mean it creates every folder that doesn’t exist. If you invoke it with foo/bar/baz
, and none of them exist, it’ll create all folders.
const createFolder = async (folder) => {
try {
await fs.promises.mkdir(folder, { recursive: true });
} catch (error) {
console.error("Unable to create directory: ", error);
}
};
Step 4 — Function to move a single file
The key component of this script is to take our file, and move it from A
to B
. This function will handle that by received 2 arguments, destination
- which will be the folder where we move our file, and file
- which will be our file to be moved.
We’ll have to generate 2 constants, sourcePath
will refer to the absolute position of our file and destinationPath
will refer to the final destination of the file. We move our file from sourcePath
to destinationPath
.
Once we have those values, we’ll invoke the fs.promises.rename
function to move our file to it’s new home, also adding a log below it so we’ll get a visual feedback when a file is moved.
const moveFile = async (destination, file) => {
const sourcePath = path.resolve(CURRENT_DIR, file);
const destinationPath = path.join(destination, file);
try {
await fs.promises.rename(sourcePath, destinationPath);
console.log(`${file} moved to ${destinationPath}`);
} catch (error) {
console.error("Unable to move file: ", error);
}
};
Step 5 — Read files in folder and putting it all together
We are heading to the end of this article and the only thing we have to do is read all the files in a folder, and then use the functions we created above to handle the different parts that contribute to moving our files.
First we’ll find all the files in our CURRENT_DIR
using the fs.promises.readdir
method. This returns an array of strings that refer to our filenames.
Once we have the files that need to be sorted, we can loop through them and to the following steps:
- find the extension of the current file
- create a destination folder if it doesn’t exist
- move the file to it’s destination folder.
const readFolder = async () => {
try {
const files = await fs.promises.readdir(CURRENT_DIR);
for (const file of files) {
const destination = findExtension(file);
if (destination) {
const destinationPath = path.resolve(CURRENT_DIR, destination);
await createFolder(destinationPath);
await moveFile(destinationPath, file);
}
}
} catch (error) {
console.error("Unable to scan directory: ", error);
}
};
readFolder();
And that should be it! Please use this at your own risk, if you’d like to test it with some dummy files, you can run this in your terminal to give you a variety of files: touch 1.jpg 2.mp3 3.docx 4.doc 5.qt 6.mp4 6.txt 7.png 8.flac 9.webm
I hope you enjoyed this short article and if you are looking for the full code you can find it here.