UNPKG

audible-api

Version:

A Node.js API for searching the audible website

238 lines (196 loc) 9.61 kB
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) { symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); } keys.push.apply(keys, symbols); } return keys; } function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; } function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } } function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; } import { load as loadPage } from "cheerio"; import fetch from "node-fetch"; import { URL, URLSearchParams } from "url"; import { abridged, audibleOriginal, audiobookFormat, pageSizes, plusCatalog, releaseTimes, searchCategories, searchDurations, searchLanguages, siteCountries, unabridged, whispersync } from "./data/audible-search-fields"; import getAudibleBook from "./get-audible-book"; import { parseLanguage } from "./utils/language"; import { cleanNarratorUrl, cleanTitle, cleanUrl } from "./utils/string"; import { getDurationFromStr } from "./utils/time"; /** * A set of parameters used to search the Audible website */ /** * Search the Audible website for a list of books matching your search criteria * * @param options - An object containing your search criteria * @returns A promise returning an array of book objects from the search results, along with total results */ export default function searchAudible() { return _searchAudible.apply(this, arguments); } function _searchAudible() { _searchAudible = _asyncToGenerator(function* () { var { keywords, title, author, narrator, publisher, category, isAudibleOriginal = false, isPlusCatalog = false, releaseTime, durations = [], languages = [], isWhisperSync = false, isAbridged, pageNum = 1, pageSize = 20, getFull = false, site = "us" } = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; var { url: baseUrl } = siteCountries[site] || siteCountries.us; var baseSearchUrl = "".concat(baseUrl, "/search"); var realPageSize = pageSizes.includes(pageSize) ? pageSize : pageSizes[0]; var paramsObj = _objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread({}, title && { title }), keywords && { keywords }), author && { searchAuthor: author }), narrator && { narrator }), publisher && { publisher }), isAbridged === true && abridged), isAbridged === false && unabridged), isAudibleOriginal && audibleOriginal), isPlusCatalog && plusCatalog), isWhisperSync && whispersync), {}, { page: pageNum.toString(), pageSize: realPageSize.toString(), ipRedirectOverride: "true" }, audiobookFormat); var params = new URLSearchParams(paramsObj); if (releaseTime && releaseTimes[releaseTime]) { params.append("publication_date", releaseTimes[releaseTime]); } if (category && searchCategories[category]) { params.append("node", searchCategories[category]); } durations.forEach(duration => { if (searchDurations[duration]) { params.append("feature_seven_browse-bin", searchDurations[duration]); } }); languages.forEach(lang => { var langCode = searchLanguages[lang.toLowerCase()]; if (langCode) { params.append("feature_six_browse-bin", langCode); } }); var searchUrl = "".concat(baseSearchUrl, "?").concat(params.toString()); var res = yield fetch(searchUrl); var body = yield res.text(); var page = loadPage(body); var audibleItems = []; var resultsStr = page(".resultsSummarySubheading").eq(0).text().trim(); var totalResultsMatch = resultsStr.match(/([0-9,]+) results$/); var totalResults = totalResultsMatch ? Number(totalResultsMatch[1]) : 0; page(".productListItem").each((i, elSel) => { var _newBook$url; var newBook = { title: page("h3", elSel).text().trim(), coverUrl: page("img", elSel).attr("data-lazy"), authors: [], narrators: [] }; // Get book's language var newLanguage = parseLanguage(page(".languageLabel", elSel).text().replace("Language:", "").trim()); if (newLanguage) { newBook.language = newLanguage; } // Get book's url var urlStr = page("h3 a", elSel).attr("href"); if (urlStr) { newBook.url = cleanUrl(new URL(urlStr, baseUrl).href); } // Get book's clean title if (newBook.title) { newBook.cleanTitle = cleanTitle(newBook.title); } // Get the book's duration var runtimeStr = page(".runtimeLabel", elSel).text().trim(); if (runtimeStr) { newBook.duration = getDurationFromStr(runtimeStr); } // Get the book's ASIN var asinMatch = (_newBook$url = newBook.url) === null || _newBook$url === void 0 ? void 0 : _newBook$url.match(/\/([A-Z0-9]+)$/); if (asinMatch) { newBook.asin = asinMatch[1]; } // Get the aggregate rating var ratingValueStr = page(".ratingsLabel .bc-pub-offscreen", elSel).text().trim(); var ratingsValueMatch = ratingValueStr.match(/[0-9.]+/); var ratingValue = Number((ratingsValueMatch === null || ratingsValueMatch === void 0 ? void 0 : ratingsValueMatch[0]) || 0); var ratingCountStr = page(".ratingsLabel .bc-color-secondary", elSel).text().trim(); var ratingCountMatch = ratingCountStr.match(/[0-9,]+/); var ratingCount = Number((ratingCountMatch === null || ratingCountMatch === void 0 ? void 0 : ratingCountMatch[0].replace(/,/g, "")) || 0); newBook.rating = { value: ratingValue, count: ratingCount }; page(".authorLabel a", elSel).each((ii, authorSel) => { var authorEl = page(authorSel); var newAuthor = { name: authorEl.text().trim() }; var authorUrlPath = authorEl.attr("href"); if (authorUrlPath) { newAuthor.url = cleanUrl(new URL(authorUrlPath, baseUrl).href); } newBook.authors.push(newAuthor); }); page(".authorLabel a", elSel).each((ii, narratorSel) => { var narratorEl = page(narratorSel); var newNarrator = { name: narratorEl.text().trim() }; var narratorUrlPath = narratorEl.attr("href"); if (narratorUrlPath) { newNarrator.url = cleanNarratorUrl(new URL(narratorUrlPath, baseUrl).href); } newBook.narrators.push(newNarrator); }); // Get series and series part try { var series = []; page(".seriesLabel a", elSel).each((iii, seriesSel) => { var el = page(seriesSel); var newSeries = { name: el.text().trim() }; var seriesUrlPath = el.attr("href"); if (seriesUrlPath) { newSeries.url = cleanUrl(new URL(seriesUrlPath, baseUrl).href); } series.push(newSeries); }); var seriesArr = page(".seriesLabel", elSel).text().replace(/\n/g, "").trim() // remove the beginning text from the series .replace("Series: ", "").split(", ").map(item => item.trim()); seriesArr.forEach((seriesStr, seriesI) => { if (seriesStr.includes("Book")) { var seriesPart = Number(seriesStr.replace("Book ", "")); if (seriesPart) { var matchingBookIndex = series.findIndex(item => item.name === seriesArr[seriesI - 1]); if (matchingBookIndex > -1) { series[matchingBookIndex].part = seriesPart; } } } }); newBook.series = series; } catch (err) {// console.warn(`ERROR PARSING AUDIBLE SERIES'\n${err.stack}`); } audibleItems.push(newBook); }); if (getFull) { audibleItems = yield Promise.all(audibleItems.map(book => book.asin ? getAudibleBook(book.asin, { site }) : book)); } // console.log(JSON.stringify(audibleItems, null, 2)); var searchResults = { totalResults, results: audibleItems }; return searchResults; }); return _searchAudible.apply(this, arguments); } //# sourceMappingURL=search-audible.js.map