igir
Version:
🕹 A zero-setup ROM collection manager that sorts, filters, extracts or archives, patches, and reports on collections of any size on any OS.
152 lines (151 loc) • 6.54 kB
JavaScript
import { ProgressBarSymbol } from "../../console/progressBar.js";
import FileFactory from "../../factories/fileFactory.js";
import ArchiveEntry from "../../models/files/archives/archiveEntry.js";
import Chd from "../../models/files/archives/chd/chd.js";
import ZeroSizeFile from "../../models/files/zeroSizeFile.js";
import { FixExtension } from "../../models/options.js";
import OutputFactory from "../../modules/candidates/utils/outputFactory.js";
import ArrayUtil from "../../utils/arrayUtil.js";
import IntlUtil from "../../utils/intlUtil.js";
import Module from "../module.js";
class CandidateExtensionCorrector extends Module {
options;
fileFactory;
readerSemaphore;
constructor(options, progressBar, fileFactory, readerSemaphore) {
super(progressBar, CandidateExtensionCorrector.name);
this.options = options;
this.fileFactory = fileFactory;
this.readerSemaphore = readerSemaphore;
}
/**
* Correct the file extensions.
*/
async correct(dat, candidates) {
if (candidates.length === 0) {
this.prefixedLogger.trace(`${dat.getName()}: no candidates to correct extensions for`);
return candidates;
}
const romsThatNeedCorrecting = candidates.flatMap((candidate) => candidate.getRomsWithFiles()).filter((romWithFiles) => this.romNeedsCorrecting(romWithFiles)).length;
if (romsThatNeedCorrecting === 0) {
this.prefixedLogger.trace(`${dat.getName()}: no output files need their extension corrected`);
return candidates;
}
this.prefixedLogger.trace(
`${dat.getName()}: correcting ${IntlUtil.toLocaleString(romsThatNeedCorrecting)} output file extension${romsThatNeedCorrecting === 1 ? "" : "s"}`
);
this.progressBar.setSymbol(ProgressBarSymbol.CANDIDATE_EXTENSION_CORRECTION);
this.progressBar.resetProgress(romsThatNeedCorrecting);
const correctedCandidates = await this.correctExtensions(dat, candidates);
this.prefixedLogger.trace(`${dat.getName()}: done correcting output file extensions`);
return correctedCandidates;
}
romNeedsCorrecting(romWithFiles) {
if (romWithFiles.getInputFile() instanceof ZeroSizeFile) {
return false;
}
if (romWithFiles.getRom().getName().trim() === "") {
return true;
}
const inputFile = romWithFiles.getInputFile();
if (inputFile instanceof ArchiveEntry && inputFile.getArchive() instanceof Chd) {
return false;
}
return this.options.getFixExtension() === FixExtension.ALWAYS || this.options.getFixExtension() === FixExtension.AUTO && (!this.options.usingDats() || romWithFiles.getRom().getName().trim() === "");
}
async correctExtensions(dat, candidates) {
return await Promise.all(
candidates.map(async (candidate) => {
const correctedRoms = (await Promise.all(
candidate.getRomsWithFiles().map(async (romWithFiles) => {
const correctedRom = await this.buildCorrectedRom(dat, candidate, romWithFiles);
return romWithFiles.withRom(correctedRom);
})
)).filter(ArrayUtil.filterUniqueMapped((romWithFiles) => romWithFiles.getRom().hashCode()));
const correctedGame = candidate.getGame().withProps({ roms: correctedRoms.map((romWithFiles) => romWithFiles.getRom()) });
const correctedOutputPaths = correctedRoms.map((romWithFiles) => {
const correctedOutputPath = OutputFactory.getPath(
this.options,
dat,
correctedGame,
romWithFiles.getRom(),
romWithFiles.getInputFile()
);
let correctedOutputFile = romWithFiles.getOutputFile().withFilePath(correctedOutputPath.format());
if (correctedOutputFile instanceof ArchiveEntry) {
correctedOutputFile = correctedOutputFile.withEntryPath(correctedOutputPath.entryPath);
}
return romWithFiles.withOutputFile(correctedOutputFile);
});
return candidate.withGame(correctedGame).withRomsWithFiles(correctedOutputPaths);
})
);
}
async buildCorrectedRom(dat, candidate, romWithFiles) {
let correctedRom = romWithFiles.getRom();
if (correctedRom.getName().trim() === "") {
const romWithFilesIdx = candidate.getRomsWithFiles().indexOf(romWithFiles);
correctedRom = correctedRom.withName(
`${candidate.getGame().getName()}${candidate.getRomsWithFiles().length > 1 ? ` (File ${romWithFilesIdx + 1})` : ""}.rom`
);
}
if (!this.romNeedsCorrecting(romWithFiles)) {
return correctedRom;
}
await this.readerSemaphore.runExclusive(async () => {
this.progressBar.incrementInProgress();
this.prefixedLogger.trace(
`${dat.getName()}: ${candidate.getName()}: correcting ROM extension for: ${romWithFiles.getInputFile().toString()}`
);
const childBar = this.progressBar.addChildBar({
name: romWithFiles.getInputFile().toString()
});
try {
const correctedRomName = await this.correctFromFileSignature(
dat,
correctedRom,
romWithFiles.getInputFile()
);
if (correctedRomName === void 0) {
this.prefixedLogger.trace(
`${dat.getName()}: ${candidate.getName()}: didn't correct ROM extension`
);
} else {
correctedRom = correctedRom.withName(correctedRomName);
this.prefixedLogger.trace(
`${dat.getName()}: ${candidate.getName()}: corrected ROM extension to: ${correctedRomName}`
);
}
} finally {
childBar.delete();
}
this.progressBar.incrementCompleted();
});
return correctedRom;
}
async correctFromFileSignature(dat, correctedRom, inputFile) {
let fileSignature;
try {
fileSignature = await this.fileFactory.signatureFrom(inputFile);
} catch (error) {
this.prefixedLogger.error(
`${dat.getName()}: failed to correct file extension for '${inputFile.toString()}': ${error}`
);
}
if (fileSignature !== void 0) {
return correctedRom.getName().replace(/\.[a-zA-Z0-9]+$/, "") + fileSignature.getExtension();
}
const dotSplit = correctedRom.getName().split(".");
const archiveIndex = dotSplit.findIndex(
(_, idx) => FileFactory.isExtensionArchive(dotSplit.slice(0, idx + 1).join("."))
);
if (archiveIndex !== -1) {
return dotSplit.slice(0, archiveIndex).join(".");
}
return void 0;
}
}
export {
CandidateExtensionCorrector as default
};
//# sourceMappingURL=candidateExtensionCorrector.js.map