159 lines
5.8 KiB
JavaScript
159 lines
5.8 KiB
JavaScript
const path = require('path');
|
|
const fs = require('fs');
|
|
const yargs = require('yargs/yargs');
|
|
const { hideBin } = require('yargs/helpers');
|
|
const argv = yargs(hideBin(process.argv)).options({
|
|
"path": {
|
|
alias: 'p',
|
|
demandOption: true,
|
|
type: 'string',
|
|
describe: 'The path to find the show seasons.'
|
|
},
|
|
"ignore_filename": {
|
|
alias: 'if',
|
|
demandOption: false,
|
|
default: false,
|
|
type: 'boolean',
|
|
describe: 'ignore all information from the filename (useful after failed renaming attempt).'
|
|
},
|
|
"dry_run": {
|
|
alias: 'd',
|
|
demandOption: false,
|
|
default: false,
|
|
type: 'boolean',
|
|
describe: 'dry run, just print the changes to console.'
|
|
}
|
|
}).parseSync();
|
|
|
|
|
|
const EPISODE_PATH = argv.path;
|
|
const IGNORE_FILENAME = argv.ignore_filename;
|
|
const DRY_RUN = argv.dry_run;
|
|
|
|
if (DRY_RUN) {
|
|
console.log("This is just a dry run.");
|
|
}
|
|
|
|
if (!fs.existsSync(EPISODE_PATH)) {
|
|
console.error("no dir: "+EPISODE_PATH);
|
|
throw new Error("no dir: "+EPISODE_PATH);
|
|
}
|
|
|
|
// Get all folders in filepath and filter (should include "Season xxx", exclude "Specials" since they are often missing episodes)
|
|
let folders = fs.readdirSync(EPISODE_PATH);
|
|
folders = folders.filter((folderName) => {
|
|
let folderPath = path.join(EPISODE_PATH, folderName);
|
|
let stat = fs.lstatSync(folderPath);
|
|
if (stat.isDirectory() && (folderName.startsWith("Season ") || folderName === "Specials")) {
|
|
return true;
|
|
}
|
|
});
|
|
|
|
// Enter each season folder and get all files with mp4, mkv, etc. sort by name
|
|
folders.forEach((folderName) => {
|
|
let seasonNum = folderName === "Specials" ? 0 : Number(folderName.substring("Season ".length));
|
|
let folderPath = path.join(EPISODE_PATH, folderName);
|
|
|
|
let files = fs.readdirSync(folderPath);
|
|
files = files.sort();
|
|
|
|
// Rename files to "SxxExx.ext"
|
|
let eps_count = 0;
|
|
files.forEach((fileName) => {
|
|
// Check if file has media extension
|
|
let ext = path.extname(fileName);
|
|
if (ext !== ".mp4" && ext !== ".mkv") {
|
|
return;
|
|
}
|
|
eps_count++;
|
|
|
|
// Figure out if they already have an episode num (to account for missing episodes)
|
|
let episodeNums = [];
|
|
if (!IGNORE_FILENAME) {
|
|
for (m of fileName.matchAll(/(?:[\s,\d,-](?:E|(?:(?:E|e)pisode\s*))(\d+))/g)) { // Matches some digit, whitespace, or '-' then Exx or Episode xx
|
|
if (m?.[1]) {
|
|
episodeNums.push(m[1]);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Make sure that no episodeNum is less than current eps_count, otherwise we would overwrite an existing file!
|
|
episodeNums.forEach((episodeNum) => {
|
|
if (episodeNum < eps_count) {
|
|
throw folderName+"/"+fileName+" has a lesser episode num than current count. Exiting.";
|
|
}
|
|
});
|
|
|
|
// Calculate the episode num to use
|
|
let episodeNum = "";
|
|
if (episodeNums.length === 2) {
|
|
// Check for compound episodes
|
|
episodeNums.forEach((n, i) => {
|
|
episodeNum += i > 0 ? "-E" : "E";
|
|
episodeNum += String(n).padStart(3, "0");
|
|
});
|
|
} else if (episodeNums.length === 1) {
|
|
episodeNum = "E" + String(episodeNums[0]).padStart(3, "0");
|
|
} else {
|
|
// If no episode num, give default by index
|
|
episodeNum = "E" + String(eps_count).padStart(3, "0");
|
|
}
|
|
|
|
if (episodeNums.length === 1 || episodeNums.length ===2) {
|
|
// Make sure to not overwrite a just written episode name that had a episode number in the filename
|
|
// By setting the eps_count to the current episode num + 1 if it was gotten from file name
|
|
eps_count = Number(episodeNums[episodeNums.length-1]);
|
|
}
|
|
|
|
// Calculate the new filepath
|
|
let filePath = path.join(folderPath, fileName);
|
|
let newFileName = "S" + String(seasonNum).padStart(3, "0") + episodeNum;
|
|
let newFilePath = path.join(folderPath, newFileName + ext);
|
|
|
|
// Check if there is a subs file next to video
|
|
let subName = files.find((s) => {
|
|
if (s.startsWith(fileName.slice(0, fileName.length-ext.length)) && s.endsWith(".srt")) {
|
|
return true;
|
|
}
|
|
});
|
|
|
|
// Make sure the filename doesn't already exist (unless it is the name we started with)
|
|
if (filePath !== newFilePath && fs.existsSync(newFilePath)) {
|
|
// Oh no, the new file path already exists, and it isn't this file!
|
|
throw "File Already Exists! "+newFilePath;
|
|
}
|
|
|
|
if (subName) {
|
|
// There is a subtitle file with this episode
|
|
// Determine new sub name
|
|
let newSubName = newFileName + subName.slice(fileName.length-ext.length, subName.length-".srt".length);
|
|
|
|
// Determine if the sub file has a language ext
|
|
subLangExt = path.extname(subName.slice(0, subName.length-'.srt'.length));
|
|
if (!subLangExt) {
|
|
// Sub file does not have lang ext
|
|
// Add .en lang ext
|
|
newSubName += ".en"
|
|
} else if (subLangExt === "eng") {
|
|
// Change eng to en for consistency
|
|
}
|
|
|
|
// Calculate old and new sub paths
|
|
let subPath = path.join(folderPath, subName);
|
|
let newSubPath = path.join(folderPath, newSubName);
|
|
|
|
// Rename the sub file
|
|
if (!DRY_RUN) {
|
|
fs.renameSync(subPath, newSubPath+".srt");
|
|
}
|
|
console.log(subPath+" => "+newSubPath+".srt");
|
|
}
|
|
|
|
// Rename the file
|
|
if (!DRY_RUN) {
|
|
fs.renameSync(filePath, newFilePath);
|
|
}
|
|
console.log(filePath+" => "+newFilePath);
|
|
});
|
|
});
|