UNPKG

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.

173 lines (172 loc) • 6.73 kB
import { ProgressBarSymbol } from '../../console/progressBar.js'; import FsPoly from '../../polyfill/fsPoly.js'; import { PreferRevision } from '../../types/options.js'; import Module from '../module.js'; /** * Apply any specified preference options to the {@link Game}s within each {@link DAT}. */ export default class DATPreferer extends Module { options; constructor(options, progressBar) { super(progressBar, DATPreferer.name); this.options = options; } /** * Prefer some {@link Game}s. */ prefer(dat) { if (!this.options.getSingle()) { this.progressBar.logTrace(`${dat.getName()}: not running in single/1G1R mode, not preferring games`); return dat; } // Return early if there aren't any games if (dat.getGames().length === 0) { this.progressBar.logTrace(`${dat.getName()}: no games to prefer`); return dat; } // Return early if there aren't any games if (dat.getGames().length === 0) { this.progressBar.logTrace(`${dat.getName()}: no parent has games, not preferring games`); return dat; } this.progressBar.logTrace(`${dat.getName()}: preferring DAT games`); this.progressBar.setSymbol(ProgressBarSymbol.DAT_PREFERRING); this.progressBar.resetProgress(dat.getParents().length); const preferredGames = dat .getParents() .map((parent) => { this.progressBar.incrementInProgress(); if (parent.getGames().length === 0) { return undefined; } this.progressBar.logTrace(`${dat.getName()}: ${parent.getName()} (parent): ${parent.getGames().length.toLocaleString()} game${parent.getGames().length === 1 ? '' : 's'} before preferring`); const preferredGame = parent .getGames() .map((game, idx) => [game, idx]) .sort((one, two) => this.sort(one, two)) .at(0); if (preferredGame === undefined) { return undefined; } return preferredGame[0].withProps({ cloneOf: undefined }); }) .filter((game) => game !== undefined); const preferredDat = dat.withGames(preferredGames); const size = preferredDat .getGames() .flatMap((game) => game.getRoms()) .reduce((sum, rom) => sum + rom.getSize(), 0); this.progressBar.logTrace(`${preferredDat.getName()}: preferred to ${preferredGames.length.toLocaleString()}/${dat.getGames().length.toLocaleString()} game${preferredGames.length === 1 ? '' : 's'} (${FsPoly.sizeReadable(size)})`); this.progressBar.logTrace(`${preferredDat.getName()}: done preferring DAT games`); return preferredDat; } /** ******************* * * Sorting * * ******************* */ sort(one, two) { return (this.preferGameRegexSort(one[0], two[0]) || this.preferRomRegexSort(one[0], two[0]) || this.preferVerifiedSort(one[0], two[0]) || this.preferGoodSort(one[0], two[0]) || this.preferLanguagesSort(one[0], two[0]) || this.preferRegionsSort(one[0], two[0]) || this.preferRevisionSort(one[0], two[0]) || this.preferRetailSort(one[0], two[0]) || this.preferParentSort(one[0], two[0]) || // If there's truly no preference, then sort by the original index one[1] - two[1]); } preferGameRegexSort(a, b) { const gameRegex = this.options.getPreferGameRegex(); if (gameRegex === undefined || gameRegex.length === 0) { return 0; } const aMatched = gameRegex.some((regex) => regex.test(a.getName())) ? 0 : 1; const bMatched = gameRegex.some((regex) => regex.test(b.getName())) ? 0 : 1; return aMatched - bMatched; } preferRomRegexSort(a, b) { const romRegex = this.options.getPreferRomRegex(); if (romRegex === undefined || romRegex.length === 0) { return 0; } const aMatched = romRegex.some((regex) => a.getRoms().some((rom) => regex.test(rom.getName()))) ? 0 : 1; const bMatched = romRegex.some((regex) => b.getRoms().some((rom) => regex.test(rom.getName()))) ? 0 : 1; return aMatched - bMatched; } preferVerifiedSort(a, b) { if (!this.options.getPreferVerified()) { return 0; } return (a.isVerified() ? 0 : 1) - (b.isVerified() ? 0 : 1); } preferGoodSort(a, b) { if (!this.options.getPreferGood()) { return 0; } return (b.isBad() ? 0 : 1) - (a.isBad() ? 0 : 1); } preferLanguagesSort(a, b) { const preferLanguages = this.options.getPreferLanguages(); if (preferLanguages.length === 0) { return 0; } const aLangs = new Set(a.getLanguages()); const bLangs = new Set(b.getLanguages()); for (const preferredLang of preferLanguages) { if (aLangs.has(preferredLang) && !bLangs.has(preferredLang)) { return -1; } if (!aLangs.has(preferredLang) && bLangs.has(preferredLang)) { return 1; } } return 0; } preferRegionsSort(a, b) { const preferRegions = this.options.getPreferRegions(); if (preferRegions.length === 0) { return 0; } const aRegions = new Set(a.getRegions()); const bRegions = new Set(b.getRegions()); for (const preferredRegion of preferRegions) { if (aRegions.has(preferredRegion) && !bRegions.has(preferredRegion)) { return -1; } if (!aRegions.has(preferredRegion) && bRegions.has(preferredRegion)) { return 1; } } return 0; } preferRevisionSort(a, b) { if (this.options.getPreferRevision() === PreferRevision.NEWER) { return b.getRevision() - a.getRevision(); } if (this.options.getPreferRevision() === PreferRevision.OLDER) { return a.getRevision() - b.getRevision(); } return 0; } preferRetailSort(a, b) { if (!this.options.getPreferRetail()) { return 0; } return (a.isRetail() ? 0 : 1) - (b.isRetail() ? 0 : 1); } preferParentSort(a, b) { if (!this.options.getPreferParent()) { return 0; } return (a.isParent() ? 0 : 1) - (b.isParent() ? 0 : 1); } }