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
189 lines (163 loc) • 5.29 kB
JavaScript
import os from "os";
import { createRequire } from "module";
import { Logger } from "./logger.js";
import fs from "fs";
import path from "path";
import { fileURLToPath } from "url";
import { execSync } from "child_process";
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
/**
* Native optical drive utilities for Windows using C++ DeviceIoControl API
* Requires administrator privileges on Windows
*/
class NativeOpticalDrive {
static #nativeAddon = null;
/**
* Check if running as administrator on Windows
*/
static #isWindowsAdmin() {
if (os.platform() !== "win32") return true;
try {
// Try to run a command that requires admin privileges
execSync("net session >nul 2>&1", { stdio: "ignore" });
return true;
} catch {
return false;
}
}
/**
* Initialize the native addon (lazy loading)
*/
static #initNativeAddon() {
if (this.#nativeAddon === null && os.platform() === "win32") {
try {
// Create require function for ES modules
const require = createRequire(import.meta.url);
// Check if pre-built addon exists
const addonPath = path.join(
__dirname,
"../../build/Release/optical_drive_native.node"
);
if (!fs.existsSync(addonPath)) {
throw new Error(
`Pre-built native addon not found at ${addonPath}. This may be a corrupted installation.`
);
}
// Try to load the native addon
this.#nativeAddon = require("../../build/Release/optical_drive_native.node");
Logger.info("Native optical drive addon loaded successfully");
// Warn if not running as admin (only once when loading)
if (!this.#isWindowsAdmin()) {
Logger.warning(
"Not running as administrator - optical drive operations may fail"
);
Logger.info("For best results, run terminal as administrator");
}
} catch (error) {
Logger.error(`Failed to load native addon: ${error.message}`);
this.#nativeAddon = false;
throw new Error(
`Native optical drive addon is required but failed to load: ${error.message}`
);
}
}
}
/**
* Check if native addon is available
*/
static get isNativeAvailable() {
if (os.platform() !== "win32") {
return false;
}
this.#initNativeAddon();
return (
this.#nativeAddon && typeof this.#nativeAddon.ejectDrive === "function"
);
}
/**
* Eject optical drive using native Windows API
* @param {string} driveLetter - Drive letter (e.g., "D:")
* @returns {Promise<boolean>} Success status
*/
static async ejectDrive(driveLetter) {
if (os.platform() !== "win32") {
throw new Error("Native drive operations only supported on Windows");
}
this.#initNativeAddon();
if (this.isNativeAvailable) {
try {
// Ensure proper format: remove any extra colons and normalize
const normalizedDriveLetter =
driveLetter.replace(/::+/g, ":").replace(/:$/, "") + ":";
const success = this.#nativeAddon.ejectDrive(normalizedDriveLetter);
if (!success) {
throw new Error(`Eject failed - try running as administrator`);
}
return success;
} catch (error) {
throw error;
}
} else {
throw new Error("Native addon not available");
}
}
/**
* Load/close optical drive using native Windows API
* @param {string} driveLetter - Drive letter (e.g., "D:")
* @returns {Promise<boolean>} Success status
*/
static async loadDrive(driveLetter) {
if (os.platform() !== "win32") {
throw new Error("Native drive operations only supported on Windows");
}
this.#initNativeAddon();
if (this.isNativeAvailable) {
try {
// Ensure proper format: remove any extra colons and normalize
const normalizedDriveLetter =
driveLetter.replace(/::+/g, ":").replace(/:$/, "") + ":";
const success = this.#nativeAddon.loadDrive(normalizedDriveLetter);
if (!success) {
throw new Error(`Load failed - try running as administrator`);
}
return success;
} catch (error) {
throw error;
}
} else {
throw new Error("Native addon not available");
}
}
/**
* Eject all optical drives
* @param {Array} drives - Array of drive objects with 'id' property
* @returns {Promise<void>}
*/
static async ejectAllDrives(drives) {
for (const drive of drives) {
try {
await this.ejectDrive(drive.id);
} catch (error) {
Logger.error(`Failed to eject drive ${drive.id}: ${error.message}`);
// Continue with other drives
}
}
}
/**
* Load all optical drives
* @param {Array} drives - Array of drive objects with 'id' property
* @returns {Promise<void>}
*/
static async loadAllDrives(drives) {
for (const drive of drives) {
try {
await this.loadDrive(drive.id);
} catch (error) {
Logger.error(`Failed to load drive ${drive.id}: ${error.message}`);
// Continue with other drives
}
}
}
}
export { NativeOpticalDrive };