Skip to content

Instantly share code, notes, and snippets.

@peabnuts123
Last active January 13, 2018 21:36
Show Gist options
  • Save peabnuts123/ce43c131285a6afaab182b280a2da5c5 to your computer and use it in GitHub Desktop.
Save peabnuts123/ce43c131285a6afaab182b280a2da5c5 to your computer and use it in GitHub Desktop.
Rename files in a folder to the format of S01E01, S01E02, etc. so that parsers like Sonarr can correctly identify them.
#!/usr/bin/env node
/* TV Renamer
Purpose: Rename files in a folder to the format of S01E01, S01E02, etc.
So that parsers like Sonarr can correctly identify them. The Episode number
is based on a natural sort of the files in the current directory.
Usage: tv-renamer
No parameters. The user is prompted for Season # and asked to confirm before
any files are renamed.
*/
const fs = require('fs');
const path = require('path');
const rl = require('readline');
const readLine = rl.createInterface({
input: process.stdin,
output: process.stdout
});
let orderedFileNames = fs.readdirSync(process.cwd())
.filter(file => !file.startsWith('.'))
.sort((fileA, fileB) => {
// split file names into alphabetic / numerical chunks
let fileATokens = fileA.split(/(\d+)/g);
let fileBTokens = fileB.split(/(\d+)/g);
let minNumTokens = Math.min(fileATokens.length, fileBTokens.length);
for (let i = 0; i < minNumTokens; i++) {
if (fileATokens[i] != fileBTokens[i]) {
if (isNumerical(fileATokens[i]) && isNumerical(fileBTokens[i])) {
let numA = Number(fileATokens[i]);
let numB = Number(fileBTokens[i]);
return numA - numB;
} else {
return fileATokens[i].localeCompare(fileBTokens[i]);
}
}
}
return fileA.localeCompare(fileB);
});
readLine.question('Season Number: ', (numberString) => {
let seasonNumber = Number(numberString);
let processedFiles = orderedFileNames.map((originalName, index) => {
let seasonString = `S${leftPad(seasonNumber, 2, '0')}E${leftPad(index + 1, 2, '0')}`;
let extension = `${path.extname(originalName)}`;
let newName = `${seasonString} ${path.basename(originalName, extension).replace(/\s*\d+\s*/g, '')}${extension}`;
return {
originalName,
newName,
};
});
console.log(" === RENAME PREVIEW === ");
processedFiles.forEach(file => {
console.log(` - Old: "${file.originalName}"`);
console.log(` + New: "${file.newName}"`);
console.log();
});
readLine.question("Looks good? (y/N): ", (response) => {
response = response.trim();
// if (!response || response.toLowerCase() === 'n')
if (response.toLowerCase() === 'y') {
processedFiles.forEach((file, index, arr) => {
let indexString = leftPad(index+1, arr.length.toString().length, '0');
console.log(`(${indexString}/${arr.length}) Renaming "${file.originalName}" to "${file.newName}"`);
fs.renameSync(file.originalName, file.newName);
});
}
readLine.close();
});
});
// Utility Functions
function isNumerical(s) {
return (/\d+/g).test(s);
}
function isAlphabetical(s) {
return (/\D+/g).test(s);
}
function leftPad(s, len, char) {
s = '' + s;
return new Array((len - s.length + 1) / char.length).join().replace(/,/g, char) + s;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment