UNPKG

chdman

Version:

💿 chdman binaries and wrapper for Node.js.

95 lines • 4.31 kB
import util from 'node:util'; import fs from 'node:fs'; import ChdmanBin from './chdmanBin.js'; import { CHDType, CHDCompressionAlgorithm } from './common.js'; export default { /** * Return info about a CHD file. */ async info(options, attempt = 1) { try { await util.promisify(fs.stat)(options.inputFilename); } catch { throw new Error(`input file doesn't exist: ${options.inputFilename}`); } const output = await ChdmanBin.run([ 'info', '--input', options.inputFilename, '--verbose', ], options); // Try to detect failures, and then retry them automatically if (!output.trim() && attempt <= 3) { await new Promise((resolve) => { setTimeout(resolve, Math.random() * (2 ** (attempt - 1) * 20)); }); return this.info(options, attempt + 1); } const parsedKeys = new Map(); for (const line of output.split(/\r?\n/)) { const split = line.split(/^([^ ][^:]+): +(.+)$/); if (split.length === 4) { parsedKeys.set(split[1].toUpperCase(), split[2]); } } const metadata = [...output.matchAll(/metadata: +(.+)\r?\n +(.+)/gi)] .map((match, index_) => { const tag = match[1].match(/tag='([\d a-z]+)'/i)?.at(1)?.trim() ?? ''; const index = Number.parseInt(match[1].match(/index=(\d+)/i)?.at(1) ?? String(index_), 10); const length = Number.parseInt(match[1].match(/length=([\d,]+)/i)?.at(1)?.replace(/,/g, '') ?? '0', 10); return { tag, index, length, data: match[2], }; }); const metadataTags = new Set(metadata.map((m) => m.tag)); let type = CHDType.RAW; if (metadataTags.has('GDDD')) { type = CHDType.HARD_DISK; } else if (metadataTags.has('CHCD') || metadataTags.has('CHTR') || metadataTags.has('CHT2')) { type = CHDType.CD_ROM; } else if (metadataTags.has('CHGT') || metadataTags.has('CHGD')) { type = CHDType.GD_ROM; } else if (metadataTags.has('DVD')) { type = CHDType.DVD_ROM; } const chdInfo = { inputFile: parsedKeys.get('INPUT FILE') ?? options.inputFilename, fileVersion: Number.parseInt(parsedKeys.get('FILE VERSION') ?? '0', 10), logicalSize: Number.parseInt(parsedKeys.get('LOGICAL SIZE')?.replace(/\D+/g, '') ?? '0', 10), hunkSize: Number.parseInt(parsedKeys.get('HUNK SIZE')?.replace(/\D+/g, '') ?? '0', 10), totalHunks: Number.parseInt(parsedKeys.get('TOTAL HUNKS')?.replace(/\D+/g, '') ?? '0', 10), unitSize: Number.parseInt(parsedKeys.get('UNIT SIZE')?.replace(/\D+/g, '') ?? '0', 10), totalUnits: Number.parseInt(parsedKeys.get('TOTAL UNITS')?.replace(/\D+/g, '') ?? '0', 10), compression: [...(parsedKeys.get('COMPRESSION') ?? '').matchAll(/([a-z]{4})( \([^(]+\))?/g)] .map((match) => match[1]) .map((compressionType) => Object.keys(CHDCompressionAlgorithm) .map((enumKey) => { const compressionAlgo = enumKey; return CHDCompressionAlgorithm[compressionAlgo]; }) .find((enumValue) => enumValue === compressionType)) .filter((enumValue) => enumValue !== undefined), chdSize: Number.parseInt(parsedKeys.get('CHD SIZE')?.replace(/\D+/g, '') ?? '0', 10), ratio: Number.parseFloat(parsedKeys.get('RATIO')?.replace(/[^\d.]+/g, '') ?? '0'), sha1: parsedKeys.get('SHA1') ?? '', dataSha1: parsedKeys.get('DATA SHA1') ?? '', metadata, type, }; // Try to detect failures, and then retry them automatically if (chdInfo.fileVersion === 0 && attempt <= 3) { await new Promise((resolve) => { setTimeout(resolve, Math.random() * (2 ** (attempt - 1) * 20)); }); return this.info(options, attempt + 1); } return chdInfo; }, }; //# sourceMappingURL=chdmanInfo.js.map