UNPKG

google-book-shell

Version:

Search books on Google Books

151 lines (124 loc) 4.8 kB
const vorpal = require('vorpal')(); const opn = require('opn'); const inquirer = require('inquirer-question'); const ora = require('ora'); const chalk = require('chalk'); const d = require('debug')('CommandBuilder'); const BookSearchService = require('../services/BookSearchService'); const Writer = require('../Writer'); class CommandBuilder { constructor() { this.bookSearchService = new BookSearchService(); this.writer = new Writer(); } validateBookNumber(number) { if (number == undefined) return true; // make sure that a user has entered a numeric value. if (!Number.isInteger(number)) { return "Enter a number for <number> argument!"; } // remind user to search for a book first else if (this.books.length === 0) { return "Search for a book first..."; } // check that number falls between the searched book count else if (0 >= parseInt(number) || parseInt(number) > this.books.length) { return `Enter a number between 1 and ${this.books.length}`; } return true; } async getAmazonBookURLByISBN(isbn) { const books = await this.bookSearchService.getAmazonBookAsync(isbn); d("getAmazonBookURLByISBN.books", books); return books[0].DetailPageURL[0]; } async buildAsync() { // "search" command vorpal .command('search <book>', 'search for a book in Google Books') .alias('s') .action(async (args, callback) => { this.books = await this.bookSearchService.getGoogleBooks(args.book); this.writer.printBooks(this.books); callback(); }); // "open" in browser command vorpal .command('open <number>', 'open # in searched book list') // Populate 1-N https://stackoverflow.com/a/34388474/4035 // .autocomplete(Array(10).fill().map((e,i) => (i + 1).toString())) .alias('o') // Get Amazon Book link. .option('-a, --amazon', 'open Amazon link') // If you are uncomfortable with Affiliate links, strip it out .option('-s, --strip-amazon-affiliate', 'strip affiliate query parameter') // later on add options to open preview, info links. .validate(args => this.validateBookNumber(args.number)) .action(async (args, callback) => { const bookIndex = args.number - 1; const book = this.books[bookIndex]; let bookURL = book.volumeInfo.previewLink; d("args", args); if (args.options.amazon) { const spinner = ora(chalk.red('Fetching data from Amazon Product Advertising API...')).start(); try { const isbns = book.volumeInfo.industryIdentifiers; // isbn[0] = ISBN 10, while isbn[1] contains ISBN 13 const isbn = isbns && isbns[0] ? isbns[0].identifier : ""; bookURL = await this.getAmazonBookURLByISBN(isbn); spinner.stop(); // Remove Amazon affiliate link if user choose to do so. if (args.options["strip-amazon-affiliate"]) { bookURL = bookURL.split('?')[0]; } } catch (ex) { spinner.fail('Error while fetching Amazon URL from Product Advertising API...'); } finally { spinner.clear(); } } d("finally bookURL", bookURL); opn(bookURL); callback(); }); // "view" (description) command vorpal .command('view [number]', 'view detailed description of the book') .alias('v') .validate(args => this.validateBookNumber(args.number)) .action(async (args, callback) => { if (args.number) { this.writer.viewBookDescription(this.books[args.number - 1]); } else { vorpal.hide(); // build choices let choices = {}; this.books.forEach((book, i) => { let number = (i + 1).toString().padStart(2, '0'); const choice = `${number}: ${book.volumeInfo.title}`; choices[choice] = i; }); inquirer.prompt({ type: 'list', message: 'Select a book to view the detail', choices: choices }).then((result) => { // console.log(result); //=> 1 or 2 this.writer.viewBookDescription(this.books[result]); vorpal.show(); }); } callback(); }); // "print" searched books vorpal .command("print", "print searched books") .alias('p') .action((args, callback) => { this.writer.printBooks(this.books); callback(); }); return vorpal; } } module.exports = CommandBuilder;