Last active
January 13, 2018 21:36
-
-
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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/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