feat: use ts, update cd, update README (#12)

Signed-off-by: Jef LeCompte <jeffreylec@gmail.com>
This commit is contained in:
Jef LeCompte
2020-09-18 04:27:23 -04:00
committed by GitHub
parent dcbaa6bb2e
commit e9fc0bf5f7
25 changed files with 6632 additions and 228 deletions
+95
View File
@@ -0,0 +1,95 @@
import {Config} from './config';
import {Store, Stores} from './store';
import puppeteer from 'puppeteer';
import open from 'open';
import sendNotification from './notification';
import {Logger} from './logger';
/**
* Starts the bot.
*/
async function main() {
const results = [];
for (const store of Stores) {
Logger.debug(store.links);
results.push(lookup(store));
}
await Promise.all(results);
Logger.info('↗ trying stores again');
setTimeout(main, Config.rateLimitTimeout);
}
/**
* Responsible for looking up information about a each product within
* a `Store`. It's important that we ignore `no-await-in-loop` here
* because we don't want to get rate limited within the same store.
*
* @param store Vendor of graphics cards.
*/
async function lookup(store: Store) {
/* eslint-disable no-await-in-loop */
for (const link of store.links) {
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.setUserAgent(Config.page.userAgent);
await page.setViewport({
height: Config.page.height,
width: Config.page.width
});
await page.goto(link.url, {waitUntil: 'networkidle0'});
const bodyHandle = await page.$('body');
const textContent = await page.evaluate(body => body.textContent, bodyHandle);
Logger.debug(textContent);
const graphicsCard = `${link.brand} ${link.model}`;
if (isOutOfStock(textContent, link.oosLabels)) {
Logger.info(`✖ [${store.name}] ${graphicsCard} is still out of stock`);
} else {
Logger.info(`🚀🚀🚀 [${store.name}] ${graphicsCard} IN STOCK 🚀🚀🚀`);
Logger.info(link.url);
Logger.debug(' saving screenshot');
await page.screenshot({path: `success-${Date.now()}.png`});
const givenUrl = store.cartUrl ? store.cartUrl : link.url;
await open(givenUrl);
sendNotification(givenUrl);
}
await browser.close();
}
/* eslint-enable no-await-in-loop */
}
/**
* Checks if DOM has any out-of-stock related text.
*
* @param domText Complete DOM of website.
* @param oosLabels Out-of-stock labels.
*/
function isOutOfStock(domText: string, oosLabels: string[]) {
const domTextLowerCase = domText.toLowerCase();
let result = false;
for (const oosLabel of oosLabels) {
result = domTextLowerCase.includes(oosLabel.toLowerCase());
}
return result;
}
/**
* Will continually run until user interferes.
*/
try {
void main();
} catch (error) {
// Ignoring errors; more than likely due to rate limits
Logger.error(error);
void main();
}