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.
114 lines (113 loc) • 5.28 kB
JavaScript
import { ProgressBarSymbol } from '../../console/progressBar.js';
import FsPoly from '../../polyfill/fsPoly.js';
import Module from '../module.js';
/**
* Apply any specified filter options to the {@link Game}s in a {@link DAT}.
*/
export default class DATFilter extends Module {
options;
constructor(options, progressBar) {
super(progressBar, DATFilter.name);
this.options = options;
}
/**
* Create a new DAT after filtering.
*/
filter(dat) {
// Return early if there aren't any games
if (dat.getGames().length === 0) {
this.progressBar.logTrace(`${dat.getName()}: no games to filter`);
return dat;
}
this.progressBar.logTrace(`${dat.getName()}: filtering DAT`);
this.progressBar.setSymbol(ProgressBarSymbol.DAT_FILTERING);
this.progressBar.resetProgress(dat.getGames().length);
const filteredGames = dat.getParents().flatMap((parent) => {
const games = parent.getGames().filter((game) => this.filterGame(game));
if (games.length === parent.getGames().length) {
// Nothing was filtered, return
return games;
}
// Elect a new parent in case it was filtered out
if (games.some((game) => game.getName() === parent.getName())) {
// Parent is still present, return
return games;
}
const newParent = games.at(0)?.getName();
return games.map((game) => game.withProps({
cloneOf: game.getName() === newParent ? undefined : newParent,
}));
});
const filteredDat = dat.withGames(filteredGames);
// TODO(cemmer): warning if every game was filtered out?
const size = filteredDat
.getGames()
.flatMap((game) => game.getRoms())
.reduce((sum, rom) => sum + rom.getSize(), 0);
this.progressBar.logTrace(`${filteredDat.getName()}: filtered to ${filteredGames.length.toLocaleString()}/${dat.getGames().length.toLocaleString()} game${filteredGames.length === 1 ? '' : 's'} (${FsPoly.sizeReadable(size)})`);
this.progressBar.logTrace(`${filteredDat.getName()}: done filtering DAT`);
return filteredDat;
}
/**
******************
*
* Filter *
*
******************
*/
filterGame(game) {
// If any condition evaluates to 'true', then the candidate will be excluded
return ([
this.options.getFilterRegex() &&
!this.options.getFilterRegex()?.some((regex) => regex.test(game.getName())),
this.options.getFilterRegexExclude()?.some((regex) => regex.test(game.getName())),
this.noLanguageAllowed(game),
this.regionNotAllowed(game),
this.options.getFilterCategoryRegex() &&
!this.options
.getFilterCategoryRegex()
?.some((regex) => game.getCategories().some((category) => regex.test(category))),
this.options.getNoBios() && game.getIsBios(),
this.options.getOnlyBios() && !game.getIsBios(),
this.options.getNoDevice() && game.getIsDevice(),
this.options.getOnlyDevice() && !game.getIsDevice(),
this.options.getOnlyRetail() && !game.isRetail(),
this.options.getNoUnlicensed() && game.isUnlicensed(),
this.options.getOnlyUnlicensed() && !game.isUnlicensed(),
this.options.getNoDebug() && game.isDebug(),
this.options.getOnlyDebug() && !game.isDebug(),
this.options.getNoDemo() && game.isDemo(),
this.options.getOnlyDemo() && !game.isDemo(),
this.options.getNoBeta() && game.isBeta(),
this.options.getOnlyBeta() && !game.isBeta(),
this.options.getNoSample() && game.isSample(),
this.options.getOnlySample() && !game.isSample(),
this.options.getNoPrototype() && game.isPrototype(),
this.options.getOnlyPrototype() && !game.isPrototype(),
this.options.getNoProgram() && game.isProgram(),
this.options.getOnlyProgram() && !game.isProgram(),
this.options.getNoAftermarket() && game.isAftermarket(),
this.options.getOnlyAftermarket() && !game.isAftermarket(),
this.options.getNoHomebrew() && game.isHomebrew(),
this.options.getOnlyHomebrew() && !game.isHomebrew(),
this.options.getNoUnverified() && !game.isVerified(),
this.options.getOnlyUnverified() && game.isVerified(),
this.options.getNoBad() && game.isBad(),
this.options.getOnlyBad() && !game.isBad(),
].filter((val) => val === true).length === 0);
}
noLanguageAllowed(game) {
const langs = this.options.getFilterLanguage();
if (langs.size === 0) {
return false;
}
return !game.getLanguages().some((lang) => langs.has(lang));
}
regionNotAllowed(game) {
const regions = this.options.getFilterRegion();
if (regions.size === 0) {
return false;
}
return !game.getRegions().some((region) => regions.has(region));
}
}