From 74490eae3ab30de7d7a708d5dd970e070f27f2ea Mon Sep 17 00:00:00 2001 From: fuckingrobot Date: Wed, 23 Sep 2020 10:45:04 -0400 Subject: [PATCH] feat(notification): add pushbullet, add url with notifications (#226) Co-authored-by: Jef LeCompte --- .env-example | 1 + README.md | 1 + package-lock.json | 61 +++++++++++++++++++++++++++++++ package.json | 1 + src/config.ts | 1 + src/notification/notification.ts | 5 +++ src/notification/pushbullet.ts | 19 ++++++++++ src/store/lookup.ts | 4 +- src/store/model/helpers/nvidia.ts | 18 ++++++--- src/store/model/store.ts | 2 +- src/types/pushbullet.d.ts | 1 + 11 files changed, 106 insertions(+), 8 deletions(-) create mode 100644 src/notification/pushbullet.ts create mode 100644 src/types/pushbullet.d.ts diff --git a/.env-example b/.env-example index 1ddac0765f..eb4996b963 100644 --- a/.env-example +++ b/.env-example @@ -11,6 +11,7 @@ PAGE_TIMEOUT="30000" PHONE_NUMBER="1234567890" PHONE_CARRIER="tmobile" PLAY_SOUND="notification.mp3" +PUSHBULLET="o.pushbulletTokendbjVjvJHVhcg" PUSHOVER_TOKEN="123pushover-token456" PUSHOVER_USER="123pushover-user-key" PAGE_SLEEP_MIN="5000" diff --git a/README.md b/README.md index af50648dc2..aeaaade2d0 100644 --- a/README.md +++ b/README.md @@ -76,6 +76,7 @@ Here is a list of variables that you can use to customize your newly copied `.en | `PHONE_NUMBER` | 10 digit phone number | E.g.: `1234567890`, email configuration required | | `PHONE_CARRIER` | [Supported carriers](#supported-carriers) for SMS | Email configuration required | | `PLAY_SOUND` | Play this sound notification if a card is found | E.g.: `path/to/notification.wav`, relative path accepted, valid formats: wav, mp3, flac, [free sounds available](https://notificationsounds.com/) | +| `PUSHBULLET` | PushBullet API key | Get at https://www.pushbullet.com/#settings/account | | `PUSHOVER_TOKEN` | Pushover access token | Generate at https://pushover.net/apps/build | | `PUSHOVER_USER` | Pushover username | | `PAGE_SLEEP_MIN` | Minimum sleep time between queries of the same store | Default: `5000` | diff --git a/package-lock.json b/package-lock.json index c6cfd3d848..975b5d7e84 100644 --- a/package-lock.json +++ b/package-lock.json @@ -879,6 +879,11 @@ "resolved": "https://registry.npmjs.org/async/-/async-3.2.0.tgz", "integrity": "sha512-TR2mEZFVOj2pLStYxLht7TyfuRzaydfpxr3k9RpHIzMgw7A64dzsdqCxH1WJyQdoe8T10nDXd9wnEigmiuHIZw==" }, + "async-limiter": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", + "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==" + }, "asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", @@ -1427,6 +1432,11 @@ "integrity": "sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==", "dev": true }, + "clone": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", + "integrity": "sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=" + }, "clone-deep": { "version": "0.2.4", "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-0.2.4.tgz", @@ -4821,6 +4831,11 @@ "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz", "integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==" }, + "node-forge": { + "version": "0.7.6", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.7.6.tgz", + "integrity": "sha512-sol30LUpz1jQFBjOKwbjxijiE3b6pjd74YwfD0fJOKPjF+fONKb2Yg8rYgS6+bK6VDl+/wfr4IYpC7jDzLUIfw==" + }, "node-libs-browser": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-2.2.1.tgz", @@ -5636,6 +5651,29 @@ } } }, + "pushbullet": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/pushbullet/-/pushbullet-2.4.0.tgz", + "integrity": "sha512-9CkgzAmBOv/ekxI4oqlFXdFIdKEMQgv1NBUbQYYxo/OsGYdnM2D9xEtWLQLkMAkpZUwbNr9lHq7a27082+eQMw==", + "requires": { + "clone": "^2.1.2", + "mime": "^2.4.0", + "node-forge": "^0.7.6", + "request": "^2.88.0", + "request-promise-native": "^1.0.5", + "ws": "^6.1.2" + }, + "dependencies": { + "ws": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.1.tgz", + "integrity": "sha512-GIyAXC2cB7LjvpgMt9EKS2ldqr0MTrORaleiOno6TweZ6r3TKtoFQWay/2PceJ3RuBasOHzXNn5Lrw1X0bEjqA==", + "requires": { + "async-limiter": "~1.0.0" + } + } + } + }, "pushover-notifications": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/pushover-notifications/-/pushover-notifications-1.2.2.tgz", @@ -5913,6 +5951,24 @@ } } }, + "request-promise-core": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.4.tgz", + "integrity": "sha512-TTbAfBBRdWD7aNNOoVOBH4pN/KigV6LyapYNNlAPA8JwbovRti1E88m3sYAwsLi5ryhPKsE9APwnjFTgdUjTpw==", + "requires": { + "lodash": "^4.17.19" + } + }, + "request-promise-native": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/request-promise-native/-/request-promise-native-1.0.9.tgz", + "integrity": "sha512-wcW+sIUiWnKgNY0dqCpOZkUbF/I+YPi+f09JZIDa39Ec+q82CpSYniDp+ISgTTbKmnpJWASeJBPZmoxH84wt3g==", + "requires": { + "request-promise-core": "1.1.4", + "stealthy-require": "^1.1.1", + "tough-cookie": "^2.3.3" + } + }, "reserved-words": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/reserved-words/-/reserved-words-0.1.2.tgz", @@ -6396,6 +6452,11 @@ } } }, + "stealthy-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz", + "integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=" + }, "stream-browserify": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.2.tgz", diff --git a/package.json b/package.json index 7ed288250b..184f64071d 100644 --- a/package.json +++ b/package.json @@ -31,6 +31,7 @@ "puppeteer-extra": "^3.1.15", "puppeteer-extra-plugin-adblocker": "^2.11.6", "puppeteer-extra-plugin-stealth": "^2.6.1", + "pushbullet": "^2.4.0", "pushover-notifications": "^1.2.2", "twitter": "^1.7.1", "winston": "^3.3.3" diff --git a/src/config.ts b/src/config.ts index 46b0300987..46ef22db80 100644 --- a/src/config.ts +++ b/src/config.ts @@ -37,6 +37,7 @@ const notifications = { number: process.env.PHONE_NUMBER ?? '' }, playSound: process.env.PLAY_SOUND ?? '', + pushBulletApiKey: process.env.PUSHBULLET ?? '', pushover: { token: process.env.PUSHOVER_TOKEN ?? '', username: process.env.PUSHOVER_USER ?? '' diff --git a/src/notification/notification.ts b/src/notification/notification.ts index 8fb924c181..68715a6f9d 100644 --- a/src/notification/notification.ts +++ b/src/notification/notification.ts @@ -4,6 +4,7 @@ import {playSound} from './sound'; import {sendDesktopNotification} from './desktop'; import {sendDiscordMessage} from './discord'; import {sendEmail} from './email'; +import {sendPushBulletNotification} from './pushbullet'; import {sendPushoverNotification} from './pushover'; import {sendSMS} from './sms'; import {sendSlackMessage} from './slack'; @@ -36,6 +37,10 @@ export function sendNotification(cartUrl: string, link: Link) { } } + if (notifications.pushBulletApiKey) { + sendPushBulletNotification(cartUrl, link); + } + if (notifications.pushover.token && notifications.pushover.username) { sendPushoverNotification(cartUrl); } diff --git a/src/notification/pushbullet.ts b/src/notification/pushbullet.ts new file mode 100644 index 0000000000..f882748654 --- /dev/null +++ b/src/notification/pushbullet.ts @@ -0,0 +1,19 @@ +import {Config} from '../config'; +import {Link} from '../store/model'; +import {Logger} from '../logger'; +import PushBullet from 'pushbullet'; + +const pushBulletApiKey = Config.notifications.pushBulletApiKey; + +export function sendPushBulletNotification(cartUrl: string, link: Link) { + const pusher = new PushBullet(pushBulletApiKey); + const title = `🚨 ${link.brand} ${link.model} ${link.series} 👀`; + + pusher.note({}, title, cartUrl, (err: Error, result: string) => { + if (err) { + Logger.error(err); + } else { + Logger.info(`↗ pushbullet notification sent: ${result}`); + } + }); +} diff --git a/src/store/lookup.ts b/src/store/lookup.ts index 9cddb10f4c..cd0ec00b21 100644 --- a/src/store/lookup.ts +++ b/src/store/lookup.ts @@ -88,13 +88,13 @@ async function lookupCard(browser: Browser, store: Store, page: Page, link: Link await page.screenshot({path: link.screenshot}); } - const givenUrl = link.cartUrl ? link.cartUrl : link.url; + let givenUrl = link.cartUrl ? link.cartUrl : link.url; if (Config.browser.open) { if (link.openCartAction === undefined) { await open(givenUrl); } else { - link.openCartAction(browser); + givenUrl = await link.openCartAction(browser); } } diff --git a/src/store/model/helpers/nvidia.ts b/src/store/model/helpers/nvidia.ts index 0a916cf9f5..1c123608f4 100644 --- a/src/store/model/helpers/nvidia.ts +++ b/src/store/model/helpers/nvidia.ts @@ -67,8 +67,11 @@ export function generateSetupAction() { const accessToken = data.access_token; Logger.info('[nvidia] you can log into your cart now...'); - Logger.info(checkoutUrl(drLocale, accessToken)); - await open(checkoutUrl(drLocale, accessToken)); + const cartUrl = checkoutUrl(drLocale, accessToken); + Logger.info(cartUrl); + if (Config.browser.open) { + await open(cartUrl); + } } catch (error) { Logger.debug(error); Logger.error('✖ [nvidia] cannot generate cart/session token, continuing without, auto-"add to cart" may not work...'); @@ -83,6 +86,7 @@ export function generateOpenCartAction(id: number, nvidiaLocale: string, drLocal const page = await browser.newPage(); Logger.info(`🚀🚀🚀 [nvidia] ${cardName}, starting auto add to cart... 🚀🚀🚀`); let response: Response | null; + let cartUrl: string; try { Logger.info(`🚀🚀🚀 [nvidia] ${cardName}, getting access token... 🚀🚀🚀`); response = await page.goto(nvidiaSessionUrl(nvidiaLocale), {waitUntil: 'networkidle0'}); @@ -97,15 +101,19 @@ export function generateOpenCartAction(id: number, nvidiaLocale: string, drLocal response = await page.goto(addToCartUrl(id, drLocale, accessToken), {waitUntil: 'networkidle0'}); Logger.info(`🚀🚀🚀 [nvidia] ${cardName}, opening checkout page... 🚀🚀🚀`); - Logger.info(checkoutUrl(drLocale, accessToken)); - await open(checkoutUrl(drLocale, accessToken)); + cartUrl = checkoutUrl(drLocale, accessToken); + Logger.info(cartUrl); + await open(cartUrl); } catch (error) { Logger.debug(error); Logger.error(`✖ [nvidia] ${cardName} could not automatically add to cart, opening page`); - await open(fallbackCartUrl(nvidiaLocale)); + cartUrl = fallbackCartUrl(nvidiaLocale); + await open(cartUrl); } await page.close(); + + return cartUrl; }; } diff --git a/src/store/model/store.ts b/src/store/model/store.ts index 1c25921775..8b235ec098 100644 --- a/src/store/model/store.ts +++ b/src/store/model/store.ts @@ -11,7 +11,7 @@ export interface Link { model: string; url: string; cartUrl?: string; - openCartAction?: (browser: Browser) => void; + openCartAction?: (browser: Browser) => Promise; screenshot?: string; } diff --git a/src/types/pushbullet.d.ts b/src/types/pushbullet.d.ts new file mode 100644 index 0000000000..c7126e8a8e --- /dev/null +++ b/src/types/pushbullet.d.ts @@ -0,0 +1 @@ +declare module 'pushbullet';