xenforo-dl
Version:
XenForo Forum Downloader
269 lines • 9.89 kB
JavaScript
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
};
var _a, _CommandLineParser_parseArgs;
import commandLineArgs from 'command-line-args';
import commandLineUsage from 'command-line-usage';
import { EOL } from 'os';
import { getPackageInfo } from '../lib/utils/PackageInfo.js';
const COMMAND_LINE_ARGS = {
help: 'help',
url: 'url',
cookie: 'cookie',
outDir: 'out-dir',
dirStructure: 'dir-structure',
overwrite: 'overwrite',
logLevel: 'log-level',
logFile: 'log-file',
maxRetries: 'max-retries',
maxConcurrent: 'max-concurrent',
minTimePage: 'min-time-page',
minTimeAttachment: 'min-time-image',
noPrompt: 'no-prompt',
continue: 'continue'
};
const OPT_DEFS = [
{
name: COMMAND_LINE_ARGS.help,
description: 'Display this usage guide',
alias: 'h',
type: Boolean
},
{
name: COMMAND_LINE_ARGS.url,
description: 'URL of content to download',
type: String,
defaultOption: true
},
{
name: COMMAND_LINE_ARGS.cookie,
description: 'Cookie to set in requests',
alias: 'k',
type: String
},
{
name: COMMAND_LINE_ARGS.outDir,
description: 'Path to directory where content is saved. Default: current working directory',
alias: 'o',
type: String,
typeLabel: '<dir>'
},
{
name: COMMAND_LINE_ARGS.dirStructure,
description: 'Combination of flags controlling the output directory structure of downloaded threads. See "Directory structure flags" section for available flags.',
alias: 'd',
type: String,
typeLabel: '<flags>'
},
{
name: COMMAND_LINE_ARGS.overwrite,
description: 'Overwrite existing attachment files',
alias: 'w',
type: Boolean
},
{
name: COMMAND_LINE_ARGS.logLevel,
description: 'Log level: \'info\', \'debug\', \'warn\' or \'error\'; set to \'none\' to disable logging. Default: info',
alias: 'l',
type: String,
typeLabel: '<level>'
},
{
name: COMMAND_LINE_ARGS.logFile,
description: 'Save logs to <path>',
alias: 's',
type: String,
typeLabel: '<path>'
},
{
name: COMMAND_LINE_ARGS.maxRetries,
description: 'Maximum retry attempts when a download fails. Default: 3',
alias: 'r',
type: Number,
typeLabel: '<number>'
},
{
name: COMMAND_LINE_ARGS.maxConcurrent,
description: 'Maximum number of concurrent downloads for attachments. Default: 10',
alias: 'c',
type: Number,
typeLabel: '<number>'
},
{
name: COMMAND_LINE_ARGS.minTimePage,
description: 'Minimum time to wait between page fetch requests. Default: 500',
alias: 'p',
type: Number,
typeLabel: '<milliseconds>'
},
{
name: COMMAND_LINE_ARGS.minTimeAttachment,
description: 'Minimum time to wait between download requests for attachments. Default: 200',
alias: 'i',
type: Number,
typeLabel: '<milliseconds>'
},
{
name: COMMAND_LINE_ARGS.continue,
description: 'Continue from previous download',
type: Boolean
},
{
name: COMMAND_LINE_ARGS.noPrompt,
description: 'Do not prompt for confirmation to proceed',
alias: 'y',
type: Boolean
}
];
export default class CommandLineParser {
static parse() {
const opts = __classPrivateFieldGet(this, _a, "m", _CommandLineParser_parseArgs).call(this);
const argv = process.argv;
const __getOptNameUsed = (key) => {
const name = `--${key}`;
if (argv.includes(name)) {
return name;
}
const alias = OPT_DEFS.find((def) => def.name === key)?.alias;
if (alias) {
return `-${alias}`;
}
return name;
};
const __getValue = (key) => {
let value = opts[key];
const booleanTypeArgs = [
COMMAND_LINE_ARGS.noPrompt,
COMMAND_LINE_ARGS.overwrite,
COMMAND_LINE_ARGS.continue
];
if (booleanTypeArgs.includes(key) && value !== undefined) {
value = '1';
}
if (value === null) {
throw Error(`Command-line option requires a value for '--${key}'`);
}
if ((typeof value === 'string' && value) || typeof value === 'number') {
return {
key: __getOptNameUsed(key),
value: String(value).trim()
};
}
return undefined;
};
return {
url: __getValue(COMMAND_LINE_ARGS.url),
outDir: __getValue(COMMAND_LINE_ARGS.outDir),
dirStructure: __getValue(COMMAND_LINE_ARGS.dirStructure),
overwrite: __getValue(COMMAND_LINE_ARGS.overwrite),
request: {
maxRetries: __getValue(COMMAND_LINE_ARGS.maxRetries),
maxConcurrent: __getValue(COMMAND_LINE_ARGS.maxConcurrent),
minTime: {
page: __getValue(COMMAND_LINE_ARGS.minTimePage),
attachment: __getValue(COMMAND_LINE_ARGS.minTimeAttachment)
},
cookie: __getValue(COMMAND_LINE_ARGS.cookie)
},
continue: __getValue(COMMAND_LINE_ARGS.continue),
noPrompt: __getValue(COMMAND_LINE_ARGS.noPrompt),
logging: {
level: __getValue(COMMAND_LINE_ARGS.logLevel),
file: __getValue(COMMAND_LINE_ARGS.logFile)
}
};
}
static showUsage() {
let opts;
try {
opts = __classPrivateFieldGet(this, _a, "m", _CommandLineParser_parseArgs).call(this);
}
catch (error) {
return false;
}
if (opts.help) {
const urlContent = [
'Download a single thread (messages and attachments):',
`- <forum_site_url>/threads/<title_slug>.<thread_id>[/page-<num>]${EOL}`,
'Download all threads in a forum (including subforums):',
`- <forum_site_url>/forums/<title_slug>.<forum_id>[/page-<num>]${EOL}`,
`If '/page-<num>' is present in URL, download will begin from the specified page.${EOL}`,
'For URLs not matching the above patterns, xenforo-dl will scrape for forum links and download from them. It is your responsibility to ensure the given URL is a valid XenForo link.'
];
const dirStructureContent = [
{
flag: 's',
desc: 'Include directory for the forum site.'
},
{
flag: 'pl',
desc: 'Include directory for each category or forum leading up to the target thread.'
},
{
flag: 'pi',
desc: 'Include directory for the immediate section or forum containing the target thread.'
},
{
flag: 't',
desc: 'Include directory for the target thread itself.'
},
{
flag: 'a',
desc: 'Include directory for attachments.'
},
{
flag: '-',
desc: 'No directory structure. Everything will be saved directly to --out-dir.'
}
];
const sections = [
{
header: 'Usage',
content: 'xenforo-dl [OPTION]... URL'
},
{
header: 'URL',
content: urlContent.join(EOL)
},
{
header: 'Options',
optionList: OPT_DEFS,
hide: 'url'
},
{
header: 'Directory structure flags (--dir-structure)',
content: 'When downloading a thread, the following flags specify which directory is to be included in the output directory structure:'
},
{
content: dirStructureContent
},
{
content: 'Default: splta'
},
{
header: 'Project home',
content: '{underline https://github.com/patrickkfkan/xenforo-dl}'
}
];
const banner = getPackageInfo().banner;
if (banner) {
sections.unshift({ header: banner, raw: true });
}
const usage = commandLineUsage(sections);
console.log(usage);
return true;
}
return false;
}
}
_a = CommandLineParser, _CommandLineParser_parseArgs = function _CommandLineParser_parseArgs() {
const opts = commandLineArgs(OPT_DEFS, { stopAtFirstUnknown: true });
if (opts['_unknown']) {
const unknownOpt = Object.keys(opts['_unknown'])[0];
throw Error(`Unknown option '${unknownOpt}'`);
}
return opts;
};
//# sourceMappingURL=CommandLineParser.js.map