makemkv-auto-rip
Version:
Automatically rips DVDs & Blu-rays using the MakeMKV console, then saves them to unique folders. It can be used from the command line or via a web interface, and is cross-platform. It is also containerized, so it can be run on any system with Docker insta
168 lines (149 loc) • 4.85 kB
JavaScript
import fs from "fs";
import { join } from "path";
import { Logger } from "./logger.js";
import { PLATFORM_DEFAULTS } from "../constants/index.js";
import { access } from "fs/promises";
import os from "os";
/**
* Filesystem utilities for file and folder operations
*/
export class FileSystemUtils {
/**
* Make a title valid for use as a folder path by removing invalid characters
* @param {string} title - The title to sanitize
* @returns {string} - Sanitized title safe for filesystem use
*/
static makeTitleValidFolderPath(title) {
return title
.replace(/\\/g, "")
.replace(/\//g, "")
.replace(/:/g, "")
.replace(/\*/g, "")
.replace(/\?/g, "")
.replace(/</g, "")
.replace(/>/g, "")
.replace(/\|/g, "")
.replace(/['"]+/g, "");
}
/**
* Create a unique folder by appending a number if the folder already exists
* @param {string} outputPath - The base path where to create the folder
* @param {string} folderName - The desired folder name
* @returns {string} - The full path of the created folder
*/
static createUniqueFolder(outputPath, folderName) {
let dir = join(outputPath, folderName);
let folderCounter = 1;
if (fs.existsSync(dir)) {
while (fs.existsSync(`${dir}-${folderCounter}`)) {
folderCounter++;
}
dir += `-${folderCounter}`;
}
fs.mkdirSync(dir);
return dir;
}
/**
* Create a unique log file name by appending a number if the file already exists
* @param {string} logDir - The directory where to create the log file
* @param {string} fileName - The base file name
* @returns {string} - The full path of the unique log file
*/
static createUniqueLogFile(logDir, fileName) {
let dir = join(logDir, `Log-${fileName}`);
let fileCounter = 1;
if (fs.existsSync(`${dir}.txt`)) {
while (fs.existsSync(`${dir}-${fileCounter}.txt`)) {
fileCounter++;
}
dir += `-${fileCounter}`;
}
return `${dir}.txt`;
}
/**
* Write content to a log file
* @param {string} filePath - The full path to the log file
* @param {string} content - The content to write
* @param {string} titleName - The title name for logging purposes
* @returns {Promise<void>}
*/
static async writeLogFile(filePath, content, titleName) {
return new Promise((resolve, reject) => {
fs.writeFile(filePath, content, "utf8", (err) => {
if (err) {
Logger.error("Directory for logs does not exist. Please create it.");
reject(err);
} else {
Logger.info(
`Full log file for ${titleName} has been written to file`
);
resolve();
}
});
});
}
/**
* Check if a directory exists, create it if it doesn't
* @param {string} dirPath - The directory path to check/create
*/
static ensureDirectoryExists(dirPath) {
if (!fs.existsSync(dirPath)) {
fs.mkdirSync(dirPath, { recursive: true });
}
}
/**
* Detect MakeMKV installation path for the current platform
* @returns {Promise<string|null>} - Path to MakeMKV directory or null if not found
*/
static async detectMakeMKVInstallation() {
const platform = os.platform();
const platformPaths = PLATFORM_DEFAULTS.MAKEMKV_PATHS[platform];
if (!platformPaths) {
Logger.warning(`Unsupported platform: ${platform}`);
return null;
}
for (const basePath of platformPaths) {
try {
// Check if the directory exists
await access(basePath);
// Check if makemkvcon executable exists in this path
const executableName =
platform === "win32" ? "makemkvcon.exe" : "makemkvcon";
const executablePath = join(basePath, executableName);
try {
await access(executablePath);
Logger.info(`Found MakeMKV installation at: ${basePath}`);
return basePath;
} catch {
// Executable not found in this directory, try next
continue;
}
} catch {
// Directory doesn't exist, try next
continue;
}
}
Logger.warning(
`MakeMKV installation not found in default locations for ${platform}`
);
return null;
}
/**
* Validate that MakeMKV executable exists at given path
* @param {string} mkvDir - Path to MakeMKV directory
* @returns {Promise<boolean>} - True if executable exists
*/
static async validateMakeMKVInstallation(mkvDir) {
if (!mkvDir) return false;
try {
const platform = os.platform();
const executableName =
platform === "win32" ? "makemkvcon.exe" : "makemkvcon";
const executablePath = join(mkvDir, executableName);
await access(executablePath);
return true;
} catch {
return false;
}
}
}