import fs from "node:fs/promises"; import os from "node:os"; import path from "node:path"; import util from "node:util"; import { createBrowser } from "./browser"; import { createDatabase } from "./database"; import { createLibrary, type Book } from "./library"; import * as pkg from "./package.json"; import { createPlatform, platforms, type TPlatform } from "./platform"; const options = { db: { type: "string", default: "gadl.db", toString() { return ` (default: ${this.default})`; }, }, "out-dir": { type: "string", default: "dist", toString() { return ` (default: ${this.default})`; }, }, "out-authors-limit": { type: "string", default: "3", toString() { return ` (default: ${this.default})`; }, }, "no-headless": { type: "boolean", default: false, }, login: { type: "string", toString() { return [...Object.keys(platforms)].join("|"); }, async run() { const db = await createDatabase(args.values.db!); const browser = await createBrowser({ db, headless: false }); const platform = createPlatform({ platform: args.values.login as TPlatform, db, browser, }); await platform.login(); await browser.close(); }, }, logout: { type: "string", toString() { return [...Object.keys(platforms)].join("|"); }, async run() { const db = await createDatabase(args.values.db!), headless = !args.values["no-headless"]; const browser = await createBrowser({ db, headless }); const platform = createPlatform({ platform: args.values.logout as TPlatform, db, browser, }); await platform.logout(); await browser.close(); }, }, add: { type: "string", toString() { return ``; }, async run() { const db = await createDatabase(args.values.db!); const library = createLibrary(db); await library.add(args.values.add!); }, }, delete: { type: "string", toString() { return ``; }, async run() { const db = await createDatabase(args.values.db!); const library = createLibrary(db); await library.delete(Number(args.values.delete)); }, }, list: { type: "boolean", short: "l", async run() { const db = await createDatabase(args.values.db!); const library = createLibrary(db); const books = await library.getBooks(); console.dir(books, { depth: null, maxArrayLength: null, maxStringLength: null, }); }, }, view: { type: "string", toString() { return ``; }, async run() { const db = await createDatabase(args.values.db!); const library = createLibrary(db); const book = await library.get(args.values.view!); if (!book) { process.exit(1); } console.dir(book, { depth: null, maxArrayLength: null, maxStringLength: null, }); }, }, pull: { type: "string", toString() { return [...Object.keys(platforms)].join("|"); }, async run() { const db = await createDatabase(args.values.db!), library = createLibrary(db), headless = !args.values["no-headless"]; const browser = await createBrowser({ db, headless }); const platform = createPlatform({ platform: args.values.pull as TPlatform, db, browser, }); for await (const book of platform.pull()) { await library.add(book); } await browser.close(); }, }, download: { type: "string", toString() { return `all|`; }, async run() { const db = await createDatabase(args.values.db!), library = createLibrary(db), headless = !args.values["no-headless"]; const books: Array = []; if (args.values.download === "all") { books.push(...(await library.getBooks())); } else { if (URL.canParse(args.values.download!)) { await library.add(args.values.download!); } const book = await library.get(args.values.download!); if (!book) { process.exit(1); } books.push(book); } for (const book of books) { const browser = await createBrowser({ db, headless }); const platform = createPlatform({ platform: book.platform, db, browser, }); const dir = await fs.mkdtemp( path.join(os.tmpdir(), `gadl-${book.id}-`), ); await platform.download(dir, book); await library.archive(dir, book, { outDir: args.values["out-dir"]!, outAuthorsLimit: Number(args.values["out-authors-limit"]!), }); await browser.close(); } }, }, json: { type: "boolean", }, version: { type: "boolean", short: "v", run() { console.log(pkg.version); }, }, help: { type: "boolean", short: "h", run() { console.log( [ "Usage: gadl [options...]", ` $ npx playwright@${pkg.dependencies.playwright} install --with-deps chromium`, ` $ gadl --login=`, ` $ gadl --download=`, "", "Available options:", ...Object.entries(options).map((option) => [ ` --${option[0]}`, "short" in option[1] && ` -${option[1].short}`, option[1].type === "string" && `=${option[1]}`, ] .filter(Boolean) .join(""), ), ].join("\n"), ); }, }, } as const; const args = util.parseArgs({ options }); if (args.values.json) { console.dir = function dir(arrayOrObject) { for (const obj of [arrayOrObject].flat()) { console.log(JSON.stringify(obj)); } }; } for (const option of Object.keys(options)) { if (args.values[option] && typeof options[option].run === "function") { await options[option].run(); process.exit(); } } options.help.run();