itch-dl
Version:
Bulk download games from itch.io - TypeScript implementation
185 lines (184 loc) • 6.6 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.DEFAULT_SETTINGS = void 0;
exports.processPlatformTraits = processPlatformTraits;
exports.createAndGetConfigPath = createAndGetConfigPath;
exports.cleanConfig = cleanConfig;
exports.loadConfig = loadConfig;
const node_path_1 = __importDefault(require("node:path"));
const node_fs_1 = __importDefault(require("node:fs"));
const node_os_1 = __importDefault(require("node:os"));
const package_json_1 = __importDefault(require("axios/package.json"));
const package_json_2 = __importDefault(require("./package.json"));
function processPlatformTraits(platforms) {
if (!platforms || platforms.length === 0) {
return undefined;
}
const traitMapping = {
win: 'p_windows',
lin: 'p_linux',
mac: 'p_osx',
osx: 'p_osx',
darwin: 'p_osx',
and: 'p_android',
};
const traits = new Set();
for (let p of platforms) {
let platformTrait;
p = p.trim().toLowerCase().replace(/^p_/, '');
if (p.startsWith('native')) {
const sys = process.platform;
p = sys.toLowerCase();
if (p.endsWith('bsd')) {
console.warn('Note: Native downloads for *BSDs are not available - Linux binaries will be used.');
p = 'linux';
}
}
for (const [key, trait] of Object.entries(traitMapping)) {
if (p.startsWith(key)) {
platformTrait = trait;
break;
}
}
if (!platformTrait) {
throw new Error(`Platform ${p} not known!`);
}
traits.add(platformTrait);
}
return Array.from(traits);
}
// Default settings used when generating a Settings object
exports.DEFAULT_SETTINGS = {
apiKey: undefined,
userAgent: `axios/${package_json_1.default.version} itch-dl/${package_json_2.default.version}`,
downloadTo: undefined,
mirrorWeb: false,
urlsOnly: false,
parallel: 1,
filterFilesPlatform: undefined,
filterFilesType: undefined,
filterFilesGlob: undefined,
filterFilesRegex: undefined,
filterUrlsGlob: undefined,
filterUrlsRegex: undefined,
verbose: false,
};
/**
* Returns the path to the itch-dl configuration directory for the
* current operating system. The directory may not exist.
*/
function createAndGetConfigPath() {
const sys = process.platform;
let basePath;
if (sys === 'linux') {
basePath = process.env.XDG_CONFIG_HOME || node_path_1.default.join(node_os_1.default.homedir(), '.config');
}
else if (sys === 'darwin') {
basePath = node_path_1.default.join(node_os_1.default.homedir(), 'Library', 'Application Support');
}
else if (sys === 'win32') {
basePath = process.env.APPDATA || node_path_1.default.join(node_os_1.default.homedir(), 'AppData', 'Roaming');
}
else {
throw new Error(`Unknown platform: ${sys}`);
}
return node_path_1.default.join(basePath, 'itch-dl');
}
const TYPE_CHECKS = {
apiKey: v => typeof v === 'string',
userAgent: v => typeof v === 'string',
downloadTo: v => typeof v === 'string',
mirrorWeb: v => typeof v === 'boolean',
urlsOnly: v => typeof v === 'boolean',
parallel: v => typeof v === 'number',
filterFilesPlatform: v => Array.isArray(v),
filterFilesType: v => Array.isArray(v),
filterFilesGlob: v => typeof v === 'string',
filterFilesRegex: v => typeof v === 'string',
filterUrlsGlob: v => typeof v === 'string',
filterUrlsRegex: v => typeof v === 'string',
verbose: v => typeof v === 'boolean',
};
const EXPECTED_TYPES = {
apiKey: 'string',
userAgent: 'string',
downloadTo: 'string',
mirrorWeb: 'boolean',
urlsOnly: 'boolean',
parallel: 'number',
filterFilesPlatform: 'array',
filterFilesType: 'array',
filterFilesGlob: 'string',
filterFilesRegex: 'string',
filterUrlsGlob: 'string',
filterUrlsRegex: 'string',
verbose: 'boolean',
};
/**
* Validates config data loaded from JSON, discarding unknown keys and
* ensuring value types are correct. Exits the process on fatal errors.
*/
function cleanConfig(configData) {
const cleaned = {};
let invalid = false;
for (const [key, value] of Object.entries(configData)) {
if (!(key in TYPE_CHECKS)) {
console.warn(`Settings contain an unknown item, ignoring: '${key}'`);
continue;
}
if (value !== null && value !== undefined && !TYPE_CHECKS[key](value)) {
console.error(`Settings.${key} has invalid type '${typeof value}', expected '${EXPECTED_TYPES[key]}'`);
invalid = true;
continue;
}
cleaned[key] = value;
}
if (invalid) {
console.error('Settings invalid, bailing out!');
process.exit(1);
}
return cleaned;
}
/**
* Loads configuration from disk and applies command-line overrides.
* CLI values replace file values when they evaluate to true.
*/
function loadConfig(cli = {}, profile) {
const configPath = createAndGetConfigPath();
const configFilePath = node_path_1.default.join(configPath, 'config.json');
const profileFilePath = profile ? node_path_1.default.join(configPath, 'profiles', profile) : '';
let configData = {};
if (node_fs_1.default.existsSync(configFilePath)) {
console.debug(`Found config file: ${configFilePath}`);
try {
configData = JSON.parse(node_fs_1.default.readFileSync(configFilePath, 'utf-8'));
}
catch {
configData = {};
}
}
if (profile && node_fs_1.default.existsSync(profileFilePath)) {
console.debug(`Found profile: ${profileFilePath}`);
try {
const profileData = JSON.parse(node_fs_1.default.readFileSync(profileFilePath, 'utf-8'));
Object.assign(configData, profileData);
}
catch { }
}
const settings = { ...exports.DEFAULT_SETTINGS, ...cleanConfig(configData) };
for (const key of Object.keys(exports.DEFAULT_SETTINGS)) {
const value = cli[key];
if (value) {
settings[key] = value;
}
}
const envKey = process.env.ITCH_API_KEY;
if (!settings.apiKey && envKey) {
settings.apiKey = envKey;
}
settings.filterFilesPlatform = processPlatformTraits(settings.filterFilesPlatform);
return settings;
}