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.
67 lines (66 loc) • 2.88 kB
JavaScript
import path from 'node:path';
import { ProgressBarSymbol } from '../../console/progressBar.js';
import GameGrouper from '../../gameGrouper.js';
import Game from '../../types/dats/game.js';
import Module from '../module.js';
/**
* Merge multi-disc {@link Game}s in a {@link DAT} into one game.
*/
export default class DATDiscMerger extends Module {
options;
constructor(options, progressBar) {
super(progressBar, DATDiscMerger.name);
this.options = options;
}
/**
* Merge {@link Game}s.
*/
merge(dat) {
if (!this.options.getMergeDiscs()) {
this.progressBar.logTrace(`${dat.getName()}: not merging discs`);
return dat;
}
if (dat.getGames().length === 0) {
this.progressBar.logTrace(`${dat.getName()}: no games to merge`);
return dat;
}
this.progressBar.logTrace(`${dat.getName()}: merging ${dat.getGames().length.toLocaleString()} game${dat.getGames().length === 1 ? '' : 's'}`);
this.progressBar.setSymbol(ProgressBarSymbol.DAT_MERGE_SPLIT);
this.progressBar.resetProgress(dat.getGames().length);
const groupedGames = this.groupGames(dat.getGames());
const newDat = dat.withGames(groupedGames);
this.progressBar.logTrace(`${newDat.getName()}: merged to ${newDat.getGames().length.toLocaleString()} game${newDat.getGames().length === 1 ? '' : 's'}`);
this.progressBar.logTrace(`${newDat.getName()}: done merging`);
return newDat;
}
groupGames(games) {
const gameNamesToGames = GameGrouper.groupMultiDiscGames(games, (game) => game.getName());
return [...gameNamesToGames.entries()].flatMap(([gameName, games]) => {
if (games.length === 1) {
return games[0];
}
const roms = games.flatMap((game) => game.getRoms());
// Detect conflicting ROM names
const romNamesToCount = roms.reduce((map, rom) => {
map.set(rom.getName(), (map.get(rom.getName()) ?? 0) + 1);
return map;
}, new Map());
const duplicateRomNames = [...romNamesToCount.entries()]
.filter(([, count]) => count > 1)
.map(([romName]) => romName)
.sort();
if (duplicateRomNames.length > 1) {
// De-conflict the filenames by adding a subfolder of the original game's name
const deconflictedRoms = games.flatMap((game) => game.getRoms().map((rom) => rom.withName(path.join(game.getName(), rom.getName()))));
return new Game({
name: gameName,
roms: deconflictedRoms,
});
}
return new Game({
name: gameName,
roms: roms,
});
});
}
}