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.
163 lines (162 loc) • 6.15 kB
JavaScript
import { ProgressBarSymbol } from "../../console/progressBar.js";
import ROM from "../../models/dats/rom.js";
import { MergeMode } from "../../models/options.js";
import ArrayUtil from "../../utils/arrayUtil.js";
import IntlUtil from "../../utils/intlUtil.js";
import Module from "../module.js";
class DATMergerSplitter extends Module {
options;
constructor(options, progressBar) {
super(progressBar, DATMergerSplitter.name);
this.options = options;
}
/**
* Un-merge, split, or merge the {@link Game}s within a {@link DAT}.
*/
merge(dat) {
if (this.options.getMergeRoms() === void 0) {
this.prefixedLogger.trace(`${dat.getName()}: no ROM merge option provided, doing nothing`);
return dat;
}
if (!dat.hasParentCloneInfo()) {
this.prefixedLogger.trace(
`${dat.getName()}: DAT doesn't have parent/clone info, doing nothing`
);
return dat;
}
const gameNamesToGames = dat.getGames().reduce((map, game) => {
map.set(game.getName(), game);
return map;
}, /* @__PURE__ */ new Map());
this.prefixedLogger.trace(
`${dat.getName()}: merging & splitting ${IntlUtil.toLocaleString(dat.getGames().length)} game${dat.getGames().length === 1 ? "" : "s"}`
);
this.progressBar.setSymbol(ProgressBarSymbol.DAT_MERGE_SPLIT);
this.progressBar.resetProgress(dat.getGames().length);
const newGames = dat.getParents().flatMap((parent) => this.mergeParent(dat, parent, gameNamesToGames));
const newDat = dat.withGames(newGames);
this.prefixedLogger.trace(
`${newDat.getName()}: merged/split to ${IntlUtil.toLocaleString(newDat.getGames().length)} game${newDat.getGames().length === 1 ? "" : "s"}`
);
this.prefixedLogger.trace(`${newDat.getName()}: done merging & splitting`);
return newDat;
}
mergeParent(dat, parent, gameNamesToGames) {
let games = parent.getGames();
games = games.map(
(game) => game.withProps({
roms: game.getRoms().filter((rom) => rom.getStatus() !== "nodump").filter(ArrayUtil.filterUniqueMapped((rom) => rom.getName())),
disks: game.getDisks().filter((disk) => disk.getStatus() !== "nodump")
})
);
if (this.options.getMergeRoms() === MergeMode.FULLNONMERGED) {
games = games.map(
(game) => game.withProps({
roms: [
...game.getDeviceRefs().map((deviceRef) => deviceRef.getName()).reduce(ArrayUtil.reduceUnique(), []).map((deviceRefName) => gameNamesToGames.get(deviceRefName)).filter((deviceGame) => deviceGame !== void 0).flatMap(
(deviceGame) => deviceGame.getRoms().filter((rom) => rom.getStatus() !== "nodump")
),
...game.getRoms()
]
})
);
}
if (this.options.getMergeRoms() !== MergeMode.FULLNONMERGED) {
games = games.map((game) => {
if (game.getRomOf() === void 0) {
return game;
}
let biosGame;
let romOf = game.getRomOf();
while (romOf !== void 0) {
const romOfGame = gameNamesToGames.get(romOf);
if (romOfGame === void 0) {
this.prefixedLogger.trace(`${dat.getName()}: invalid romOf: ${romOf}`);
return game;
}
biosGame = romOfGame;
romOf = biosGame.getRomOf();
}
if (biosGame === void 0) {
return game;
}
if (!biosGame.getIsBios()) {
biosGame = biosGame.withProps({
roms: biosGame.getRoms().filter((rom) => rom.getBios() !== void 0)
});
}
return game.withProps({
roms: DATMergerSplitter.diffGameRoms(biosGame.getRoms(), game.getRoms())
});
});
}
if (this.options.getMergeRoms() === MergeMode.SPLIT || this.options.getMergeRoms() === MergeMode.MERGED) {
games = games.map((game) => {
const cloneOf = game.getCloneOf();
if (!cloneOf) {
return game;
}
const parentGame = gameNamesToGames.get(cloneOf);
if (!parentGame) {
this.prefixedLogger.trace(
`${dat.getName()}: ${game.getName()} references an invalid parent: ${cloneOf}`
);
return game;
}
return game.withProps({
roms: DATMergerSplitter.diffGameRoms(parentGame.getRoms(), game.getRoms()),
disks: DATMergerSplitter.diffGameRoms(parentGame.getDisks(), game.getDisks())
});
});
}
const parentGames = games.filter((game) => game.isParent());
const cloneGames = games.filter((game) => game.isClone());
if (this.options.getMergeRoms() !== MergeMode.MERGED) {
if (parentGames.length > 0) {
return [...parentGames, ...cloneGames];
}
return cloneGames;
}
const cloneRoms = cloneGames.flatMap(
(game) => game.getRoms().map(
(rom) => new ROM({
...rom,
name: `${game.getName()}\\${rom.getName()}`
})
)
);
const allRomsDeduplicated = [
...cloneRoms,
...parentGames.flatMap((parentGame) => parentGame.getRoms())
].filter(ArrayUtil.filterUniqueMapped((rom) => rom.hashCode()));
const cloneDisks = cloneGames.flatMap((game) => game.getDisks());
const allDisksDeduplicated = [
...cloneDisks,
...parentGames.flatMap((parentGame) => parentGame.getDisks())
].filter(ArrayUtil.filterUniqueMapped((disk) => disk.getName()));
return [
parentGames[0].withProps({
roms: allRomsDeduplicated,
disks: allDisksDeduplicated
})
];
}
static diffGameRoms(parentRoms, childRoms) {
const parentRomNamesToHashCodes = parentRoms.reduce((map, rom) => {
map.set(rom.getName(), rom.hashCode());
return map;
}, /* @__PURE__ */ new Map());
return childRoms.filter((rom) => {
const parentName = rom.getMerge() ?? rom.getName();
const parentHashCode = parentRomNamesToHashCodes.get(parentName);
if (!parentHashCode) {
return true;
}
return parentHashCode !== rom.hashCode();
});
}
}
export {
DATMergerSplitter as default
};
//# sourceMappingURL=datMergerSplitter.js.map