diff --git a/.editorconfig b/.editorconfig index 65f6a0f..cc0e8ba 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,5 +1,12 @@ root = true + [*] -end_of_line = lf -insert_final_newline = true indent_style = tab +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true + +[*.yml] +indent_style = space +indent_size = 2 diff --git a/README.md b/README.md index 3509cbe..f86be7b 100644 --- a/README.md +++ b/README.md @@ -66,7 +66,7 @@ Here is a list of variables that you can use to customize your newly copied `.en | `DISCORD_NOTIFY_GROUP` | Discord group you would like to notify; optional | E.g.: @here | | `DISCORD_WEB_HOOK` | Discord Web Hook URL | | `EMAIL_USERNAME` | Gmail address | E.g.: `jensen.robbed.us@gmail.com` | -| `EMAIL_PASSWORD` | Gmail password | See below if you have MFA | +| `EMAIL_PASSWORD` | Gmail password | See below if you have MFA | | `HEADLESS` | Puppeteer to run headless or not | Debugging related, default: `true` | | `IN_STOCK_WAIT_TIME` | Time to wait between requests to the same store if it has cards in stock | In seconds, default: `0` | | `LOG_LEVEL` | [Logging levels](https://github.com/winstonjs/winston#logging-levels) | Debugging related, default: `info` | diff --git a/package-lock.json b/package-lock.json index a7e6d7f..6520f91 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1460,6 +1460,12 @@ "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", "dev": true }, + "compare-versions": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-3.6.0.tgz", + "integrity": "sha512-W6Af2Iw1z4CB7q4uU4hv646dW9GQuBM+YpC0UvUCWSD8w90SJjp+ujJuXaEMtAXBtSqGfMPuFOVn4/+FlaqfBA==", + "dev": true + }, "component-emitter": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", @@ -3044,6 +3050,15 @@ "path-exists": "^4.0.0" } }, + "find-versions": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/find-versions/-/find-versions-3.2.0.tgz", + "integrity": "sha512-P8WRou2S+oe222TOCHitLy8zj+SIsVJh52VP4lvXkaFVnOFFdoWv1H1Jjvel1aI6NCFOAaeAVm8qrI0odiLcww==", + "dev": true, + "requires": { + "semver-regex": "^2.0.0" + } + }, "flat-cache": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", @@ -3442,6 +3457,70 @@ } } }, + "husky": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/husky/-/husky-4.3.0.tgz", + "integrity": "sha512-tTMeLCLqSBqnflBZnlVDhpaIMucSGaYyX6855jM4AguGeWCeSzNdb1mfyWduTZ3pe3SJVvVWGL0jO1iKZVPfTA==", + "dev": true, + "requires": { + "chalk": "^4.0.0", + "ci-info": "^2.0.0", + "compare-versions": "^3.6.0", + "cosmiconfig": "^7.0.0", + "find-versions": "^3.2.0", + "opencollective-postinstall": "^2.0.2", + "pkg-dir": "^4.2.0", + "please-upgrade-node": "^3.2.0", + "slash": "^3.0.0", + "which-pm-runs": "^1.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", + "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", + "dev": true, + "requires": { + "@types/color-name": "^1.1.1", + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, "ieee754": { "version": "1.1.13", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", @@ -4885,6 +4964,12 @@ } } }, + "opencollective-postinstall": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/opencollective-postinstall/-/opencollective-postinstall-2.0.3.tgz", + "integrity": "sha512-8AV/sCtuzUeTo8gQK5qDZzARrulB3egtLzFgteqB2tcT4Mw7B8Kt7JcDHmltjz6FOAHsvTevk70gZEbhM4ZS9Q==", + "dev": true + }, "optionator": { "version": "0.9.1", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", @@ -5116,6 +5201,15 @@ "find-exec": "1.0.1" } }, + "please-upgrade-node": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/please-upgrade-node/-/please-upgrade-node-3.2.0.tgz", + "integrity": "sha512-gQR3WpIgNIKwBMVLkpMUeR3e1/E1y42bqDQZfql+kDeXd8COYfM8PQA4X6y7a8u9Ua9FHmsrrmirW2vHs45hWg==", + "dev": true, + "requires": { + "semver-compare": "^1.0.0" + } + }, "plur": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/plur/-/plur-4.0.0.tgz", @@ -5701,6 +5795,12 @@ "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==" }, + "semver-compare": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/semver-compare/-/semver-compare-1.0.0.tgz", + "integrity": "sha1-De4hahyUGrN+nvsXiPavxf9VN/w=", + "dev": true + }, "semver-diff": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-3.1.1.tgz", @@ -5718,6 +5818,12 @@ } } }, + "semver-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/semver-regex/-/semver-regex-2.0.0.tgz", + "integrity": "sha512-mUdIBBvdn0PLOeP3TEkMH7HHeUP3GjsXCwKarjv/kGmUFOYg1VqEemKhoQpWMu6X2I8kHeuVdGibLGkVK+/5Qw==", + "dev": true + }, "set-value": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", @@ -6792,6 +6898,12 @@ "isexe": "^2.0.0" } }, + "which-pm-runs": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/which-pm-runs/-/which-pm-runs-1.0.0.tgz", + "integrity": "sha1-Zws6+8VS4LVd9rd4DKdGFfI60cs=", + "dev": true + }, "widest-line": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz", diff --git a/package.json b/package.json index 87aff50..8e341f2 100644 --- a/package.json +++ b/package.json @@ -38,13 +38,26 @@ "@slack/web-api": "^5.12.0", "@types/async": "^3.2.3", "@types/node": "^14.11.2", + "@types/node-notifier": "^8.0.0", "@types/nodemailer": "^6.4.0", "@types/puppeteer": "^3.0.2", - "@types/node-notifier": "^8.0.0", + "discord-webhook-node": "^1.1.8", + "husky": "^4.3.0", "play-sound": "^1.1.3", "rimraf": "^3.0.2", "typescript": "^4.0.2", - "xo": "^0.33.1", - "discord-webhook-node": "^1.1.8" + "xo": "^0.33.1" + }, + "xo": { + "rules": { + "sort-imports": "error", + "sort-keys": "error", + "sort-vars": "error" + } + }, + "husky": { + "hooks": { + "pre-commit": "npm run lint && npm run build" + } } } diff --git a/src/__test__/notification-test.ts b/src/__test__/notification-test.ts index 1435287..c5b25a6 100644 --- a/src/__test__/notification-test.ts +++ b/src/__test__/notification-test.ts @@ -2,10 +2,10 @@ import {Link} from '../store/model'; import {sendNotification} from '../notification'; const link: Link = { - series: 'debug', brand: 'brand', cartUrl: 'http://example.com/', model: 'model', + series: 'debug', url: 'http://example.com/' }; diff --git a/src/config.ts b/src/config.ts index 0125fb4..6dce70d 100644 --- a/src/config.ts +++ b/src/config.ts @@ -1,13 +1,13 @@ -import {resolve} from 'path'; import {config} from 'dotenv'; +import path from 'path'; -config({path: resolve(__dirname, '../.env')}); +config({path: path.resolve(__dirname, '../.env')}); const browser = { isHeadless: process.env.HEADLESS ? process.env.HEADLESS === 'true' : true, - open: process.env.OPEN_BROWSER === 'true', + maxSleep: Number(process.env.PAGE_SLEEP_MAX ?? 10000), minSleep: Number(process.env.PAGE_SLEEP_MIN ?? 5000), - maxSleep: Number(process.env.PAGE_SLEEP_MAX ?? 10000) + open: process.env.OPEN_BROWSER === 'true' }; const logLevel = process.env.LOG_LEVEL ?? 'info'; @@ -19,8 +19,8 @@ const notifications = { webHookUrl: process.env.DISCORD_WEB_HOOK ?? '' }, email: { - username: process.env.EMAIL_USERNAME ?? '', - password: process.env.EMAIL_PASSWORD ?? '' + password: process.env.EMAIL_PASSWORD ?? '', + username: process.env.EMAIL_USERNAME ?? '' }, phone: { availableCarriers: new Map([ @@ -38,7 +38,7 @@ const notifications = { playSound: process.env.PLAY_SOUND ?? '', pushover: { token: process.env.PUSHOVER_TOKEN ?? '', - user: process.env.PUSHOVER_USER ?? '' + username: process.env.PUSHOVER_USER ?? '' }, slack: { channel: process.env.SLACK_CHANNEL ?? '', @@ -53,18 +53,18 @@ const notifications = { const page = { capture: process.env.SCREENSHOT ? process.env.SCREENSHOT === 'true' : 'true', - width: 1920, height: 1080, + inStockWaitTime: Number(process.env.IN_STOCK_WAIT_TIME ?? 0), navigationTimeout: Number(process.env.PAGE_TIMEOUT ?? 30000), userAgent: process.env.USER_AGENT ?? 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36', - inStockWaitTime: Number(process.env.IN_STOCK_WAIT_TIME ?? 0) + width: 1920 }; const store = { - showOnlySeries: process.env.SHOW_ONLY_SERIES ? process.env.SHOW_ONLY_SERIES.split(',') : ['3070', '3080', '3090'], + country: process.env.COUNTRY ?? 'usa', showOnlyBrands: process.env.SHOW_ONLY_BRANDS ? process.env.SHOW_ONLY_BRANDS.split(',') : [], - stores: process.env.STORES ? process.env.STORES.split(',') : ['nvidia'], - country: process.env.COUNTRY ?? 'usa' + showOnlySeries: process.env.SHOW_ONLY_SERIES ? process.env.SHOW_ONLY_SERIES.split(',') : ['3070', '3080', '3090'], + stores: process.env.STORES ? process.env.STORES.split(',') : ['nvidia'] }; export const Config = { diff --git a/src/index.ts b/src/index.ts index 81a981c..fa6b4e1 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,11 +1,11 @@ +import {Config} from './config'; +import {Logger} from './logger'; +import {Stores} from './store/model'; +import {adBlocker} from './adblocker'; +import {getSleepTime} from './util'; import puppeteer from 'puppeteer-extra'; import stealthPlugin from 'puppeteer-extra-plugin-stealth'; -import {Config} from './config'; -import {Stores} from './store/model'; -import {Logger} from './logger'; import {tryLookupAndLoop} from './store'; -import {getSleepTime} from './util'; -import {adBlocker} from './adblocker'; puppeteer.use(stealthPlugin()); puppeteer.use(adBlocker); @@ -15,11 +15,11 @@ puppeteer.use(adBlocker); */ async function main() { const browser = await puppeteer.launch({ - headless: Config.browser.isHeadless, defaultViewport: { height: Config.page.height, width: Config.page.width - } + }, + headless: Config.browser.isHeadless }); for (const store of Stores) { diff --git a/src/logger.ts b/src/logger.ts index 88c1d07..c736ba8 100644 --- a/src/logger.ts +++ b/src/logger.ts @@ -12,7 +12,6 @@ const prettyJson = format.printf(info => { }); export const Logger = winston.createLogger({ - level: Config.logLevel, format: format.combine( format.colorize(), format.prettyPrint(), @@ -20,7 +19,6 @@ export const Logger = winston.createLogger({ format.simple(), prettyJson ), - transports: [ - new winston.transports.Console({}) - ] + level: Config.logLevel, + transports: [new winston.transports.Console({})] }); diff --git a/src/notification/desktop.ts b/src/notification/desktop.ts index f26b88d..efeb174 100644 --- a/src/notification/desktop.ts +++ b/src/notification/desktop.ts @@ -1,5 +1,5 @@ -import notifier from 'node-notifier'; import {Link} from '../store/model'; +import notifier from 'node-notifier'; export function sendDesktopNotification(cartUrl: string, link: Link) { (async () => { @@ -7,8 +7,8 @@ export function sendDesktopNotification(cartUrl: string, link: Link) { const message = cartUrl; notifier.notify({ - title, - message + message, + title }); })(); } diff --git a/src/notification/discord.ts b/src/notification/discord.ts index de537a9..abedf9c 100644 --- a/src/notification/discord.ts +++ b/src/notification/discord.ts @@ -1,7 +1,7 @@ -import {Webhook, MessageBuilder} from 'discord-webhook-node'; +import {MessageBuilder, Webhook} from 'discord-webhook-node'; import {Config} from '../config'; -import {Logger} from '../logger'; import {Link} from '../store/model'; +import {Logger} from '../logger'; const hook = new Webhook(Config.notifications.discord.webHookUrl); const notifyGroup = Config.notifications.discord.notifyGroup; diff --git a/src/notification/email.ts b/src/notification/email.ts index 80e561f..d9245e4 100644 --- a/src/notification/email.ts +++ b/src/notification/email.ts @@ -1,24 +1,24 @@ -import nodemailer from 'nodemailer'; -import Mail from 'nodemailer/lib/mailer'; import {Config} from '../config'; -import {Logger} from '../logger'; import {Link} from '../store/model'; +import {Logger} from '../logger'; +import Mail from 'nodemailer/lib/mailer'; +import nodemailer from 'nodemailer'; const email = Config.notifications.email; const subject = 'NVIDIA - BUY NOW'; const transporter = nodemailer.createTransport({ - service: 'gmail', auth: { - user: email.username, - pass: email.password - } + pass: email.password, + user: email.username + }, + service: 'gmail' }); const mailOptions: Mail.Options = { from: email.username, - to: email.username, - subject + subject, + to: email.username }; export function sendEmail(cartUrl: string, link: Link) { diff --git a/src/notification/notification.ts b/src/notification/notification.ts index 0d7c810..9ca515b 100644 --- a/src/notification/notification.ts +++ b/src/notification/notification.ts @@ -1,14 +1,13 @@ import {Config} from '../config'; -import {sendEmail} from './email'; -import {sendSMS} from './sms'; -import {playSound} from './sound'; -import {sendSlackMessage} from './slack'; -import {sendPushoverNotification} from './pushover'; -import {sendTelegramMessage} from './telegram'; -import {sendDiscordMessage} from './discord'; -import {sendDesktopNotification} from './desktop'; - import {Link} from '../store/model'; +import {playSound} from './sound'; +import {sendDesktopNotification} from './desktop'; +import {sendDiscordMessage} from './discord'; +import {sendEmail} from './email'; +import {sendPushoverNotification} from './pushover'; +import {sendSMS} from './sms'; +import {sendSlackMessage} from './slack'; +import {sendTelegramMessage} from './telegram'; const notifications = Config.notifications; @@ -36,7 +35,7 @@ export function sendNotification(cartUrl: string, link: Link) { } } - if (notifications.pushover.token && notifications.pushover.user) { + if (notifications.pushover.token && notifications.pushover.username) { sendPushoverNotification(cartUrl); } diff --git a/src/notification/pushover.ts b/src/notification/pushover.ts index aa2b299..c7da5b5 100644 --- a/src/notification/pushover.ts +++ b/src/notification/pushover.ts @@ -1,11 +1,11 @@ -import Push from 'pushover-notifications'; import {Config} from '../config'; import {Logger} from '../logger'; +import Push from 'pushover-notifications'; const pushover = Config.notifications.pushover; const push = new Push({ - user: pushover.user, - token: pushover.token + token: pushover.token, + user: pushover.username }); export function sendPushoverNotification(cartUrl: string) { diff --git a/src/notification/slack.ts b/src/notification/slack.ts index 9bd13b6..37918b9 100644 --- a/src/notification/slack.ts +++ b/src/notification/slack.ts @@ -1,6 +1,6 @@ -import {WebClient} from '@slack/web-api'; import {Config} from '../config'; import {Logger} from '../logger'; +import {WebClient} from '@slack/web-api'; const channel = Config.notifications.slack.channel; const token = Config.notifications.slack.token; @@ -9,7 +9,7 @@ const web = new WebClient(token); export function sendSlackMessage(cartUrl: string) { (async () => { try { - const result = await web.chat.postMessage({text: cartUrl, channel}); + const result = await web.chat.postMessage({channel, text: cartUrl}); if (!result.ok) { Logger.error(result.error); return; diff --git a/src/notification/sms.ts b/src/notification/sms.ts index 54b411c..c0c289a 100644 --- a/src/notification/sms.ts +++ b/src/notification/sms.ts @@ -1,24 +1,24 @@ -import nodemailer from 'nodemailer'; -import Mail from 'nodemailer/lib/mailer'; import {Config} from '../config'; -import {Logger} from '../logger'; import {Link} from '../store/model'; +import {Logger} from '../logger'; +import Mail from 'nodemailer/lib/mailer'; +import nodemailer from 'nodemailer'; const subject = 'NVIDIA - BUY NOW'; const [email, phone] = [Config.notifications.email, Config.notifications.phone]; const transporter = nodemailer.createTransport({ - service: 'gmail', auth: { - user: email.username, - pass: email.password - } + pass: email.password, + user: email.username + }, + service: 'gmail' }); const mailOptions: Mail.Options = { from: Config.notifications.email.username, - to: generateAddress(), - subject + subject, + to: generateAddress() }; export function sendSMS(text: string, link: Link) { diff --git a/src/notification/sound.ts b/src/notification/sound.ts index 66226f7..da4a187 100644 --- a/src/notification/sound.ts +++ b/src/notification/sound.ts @@ -1,7 +1,7 @@ -import playerLib from 'play-sound'; import {Config} from '../config'; import {Logger} from '../logger'; import fs from 'fs'; +import playerLib from 'play-sound'; const notificationSound = Config.notifications.playSound; const player = playerLib(); diff --git a/src/store/lookup.ts b/src/store/lookup.ts index 986a721..73bf8af 100644 --- a/src/store/lookup.ts +++ b/src/store/lookup.ts @@ -1,11 +1,11 @@ import {Browser, Response} from 'puppeteer'; +import {closePage, delay, getSleepTime} from '../util'; import {Config} from '../config'; import {Logger} from '../logger'; -import open from 'open'; import {Store} from './model'; -import {sendNotification} from '../notification'; import {includesLabels} from './includes-labels'; -import {closePage, delay, getSleepTime} from '../util'; +import open from 'open'; +import {sendNotification} from '../notification'; const inStock: Record = {}; diff --git a/src/store/model/adorama.ts b/src/store/model/adorama.ts index d2ad13f..f1fab91 100644 --- a/src/store/model/adorama.ts +++ b/src/store/model/adorama.ts @@ -1,6 +1,10 @@ import {Store} from './store'; export const Adorama: Store = { + labels: { + captcha: ['please verify you are a human'], + outOfStock: ['temporarily not available', 'out of stock'] + }, links: [ { brand: 'TEST', @@ -63,9 +67,5 @@ export const Adorama: Store = { url: 'https://www.adorama.com/png30801tfxb.html' } ], - labels: { - captcha: ['please verify you are a human'], - outOfStock: ['temporarily not available', 'out of stock'] - }, name: 'adorama' }; diff --git a/src/store/model/amazon-ca.ts b/src/store/model/amazon-ca.ts index 128945b..9b70e37 100644 --- a/src/store/model/amazon-ca.ts +++ b/src/store/model/amazon-ca.ts @@ -1,6 +1,10 @@ import {Store} from './store'; export const AmazonCa: Store = { + labels: { + captcha: ['enter the characters you see below'], + outOfStock: ['currently unavailable'] + }, links: [ { brand: 'TEST', @@ -75,9 +79,5 @@ export const AmazonCa: Store = { url: 'https://www.amazon.ca/MSI-GeForce-RTX-3080-10G/dp/B08HR5SXPS' } ], - labels: { - captcha: ['enter the characters you see below'], - outOfStock: ['currently unavailable'] - }, name: 'amazon-ca' }; diff --git a/src/store/model/amazon.ts b/src/store/model/amazon.ts index bcaec1a..7f52598 100644 --- a/src/store/model/amazon.ts +++ b/src/store/model/amazon.ts @@ -1,6 +1,11 @@ import {Store} from './store'; export const Amazon: Store = { + labels: { + bannedSeller: ['sports authentics', 'raccoon capitalist', 'gigaparts'], + captcha: ['enter the characters you see below'], + outOfStock: ['currently unavailable', 'available from these sellers'] + }, links: [ { brand: 'TEST', @@ -93,10 +98,5 @@ export const Amazon: Store = { url: 'https://www.amazon.com/ZOTAC-Graphics-IceStorm-Advanced-ZT-A30800D-10P/dp/B08HJNKT3P' } ], - labels: { - captcha: ['enter the characters you see below'], - outOfStock: ['currently unavailable', 'available from these sellers'], - bannedSeller: ['sports authentics', 'raccoon capitalist', 'gigaparts'] - }, name: 'amazon' }; diff --git a/src/store/model/asus.ts b/src/store/model/asus.ts index e7be3f5..5d046c7 100644 --- a/src/store/model/asus.ts +++ b/src/store/model/asus.ts @@ -1,6 +1,9 @@ import {Store} from './store'; export const Asus: Store = { + labels: { + outOfStock: ['coming soon', 'temporarily sold out'] + }, links: [ { brand: 'asus', @@ -15,9 +18,6 @@ export const Asus: Store = { url: 'https://store.asus.com/us/item/202009AM150000004/' } ], - labels: { - outOfStock: ['coming soon', 'temporarily sold out'] - }, name: 'asus' }; diff --git a/src/store/model/bandh.ts b/src/store/model/bandh.ts index cb0204f..8c3b0f0 100644 --- a/src/store/model/bandh.ts +++ b/src/store/model/bandh.ts @@ -1,6 +1,9 @@ import {Store} from './store'; export const BAndH: Store = { + labels: { + outOfStock: ['notify when available', 'try varying your search terms', 'sorry, an unexpected error has occurred'] + }, links: [ { brand: 'TEST', @@ -60,8 +63,5 @@ export const BAndH: Store = { } ], - labels: { - outOfStock: ['notify when available', 'try varying your search terms', 'sorry, an unexpected error has occurred.'] - }, name: 'bandh' }; diff --git a/src/store/model/bestbuy.ts b/src/store/model/bestbuy.ts index 10baceb..9f7b8e4 100644 --- a/src/store/model/bestbuy.ts +++ b/src/store/model/bestbuy.ts @@ -1,6 +1,9 @@ import {Store} from './store'; export const BestBuy: Store = { + labels: { + outOfStock: ['sold out', 'coming soon'] + }, links: [ { brand: 'TEST', @@ -12,54 +15,51 @@ export const BestBuy: Store = { brand: 'nvidia', cartUrl: 'https://api.bestbuy.com/click/-/6429440/cart', model: 'founders edition', - url: 'https://www.bestbuy.com/site/nvidia-geforce-rtx-3080-10gb-gddr6x-pci-express-4-0-graphics-card-titanium-and-black/6429440.p?skuId=6429440&intl=nosplash', - series: '3080' + series: '3080', + url: 'https://www.bestbuy.com/site/nvidia-geforce-rtx-3080-10gb-gddr6x-pci-express-4-0-graphics-card-titanium-and-black/6429440.p?skuId=6429440&intl=nosplash' }, { brand: 'asus', cartUrl: 'https://api.bestbuy.com/click/-/6432445/cart', model: 'rog strix', - url: 'https://www.bestbuy.com/site/asus-geforce-rtx-3080-10gb-gddr6x-pci-express-4-0-strix-graphics-card-black/6432445.p?skuId=6432445&intl=nosplash', - series: '3080' + series: '3080', + url: 'https://www.bestbuy.com/site/asus-geforce-rtx-3080-10gb-gddr6x-pci-express-4-0-strix-graphics-card-black/6432445.p?skuId=6432445&intl=nosplash' }, { brand: 'evga', cartUrl: 'https://api.bestbuy.com/click/-/6432399/cart', model: 'xc3 black', - url: 'https://www.bestbuy.com/site/evga-geforce-rtx-3080-10gb-gddr6x-pci-express-4-0-graphics-card/6432399.p?skuId=6432399&intl=nosplash', - series: '3080' + series: '3080', + url: 'https://www.bestbuy.com/site/evga-geforce-rtx-3080-10gb-gddr6x-pci-express-4-0-graphics-card/6432399.p?skuId=6432399&intl=nosplash' }, { brand: 'evga', cartUrl: 'https://api.bestbuy.com/click/-/6432400/cart', model: 'xc3 ultra', - url: 'https://www.bestbuy.com/site/evga-geforce-rtx-3080-10gb-gddr6x-pci-express-4-0-graphics-card/6432400.p?skuId=6432400&intl=nosplash', - series: '3080' + series: '3080', + url: 'https://www.bestbuy.com/site/evga-geforce-rtx-3080-10gb-gddr6x-pci-express-4-0-graphics-card/6432400.p?skuId=6432400&intl=nosplash' }, { brand: 'gigabyte', cartUrl: 'https://api.bestbuy.com/click/-/6430620/cart', model: 'gaming oc', - url: 'https://www.bestbuy.com/site/gigabyte-geforce-rtx-3080-10g-gddr6x-pci-express-4-0-graphics-card-black/6430620.p?acampID=0&cmp=RMX&loc=Hatch&ref=198&skuId=6430620&intl=nosplash', - series: '3080' + series: '3080', + url: 'https://www.bestbuy.com/site/gigabyte-geforce-rtx-3080-10g-gddr6x-pci-express-4-0-graphics-card-black/6430620.p?acampID=0&cmp=RMX&loc=Hatch&ref=198&skuId=6430620&intl=nosplash' }, { brand: 'gigabyte', cartUrl: 'https://api.bestbuy.com/click/-/6430621/cart', model: 'eagle oc', - url: 'https://www.bestbuy.com/site/gigabyte-geforce-rtx-3080-10g-gddr6x-pci-express-4-0-graphics-card-black/6430621.p?skuId=6430621&intl=nosplash', - series: '3080' + series: '3080', + url: 'https://www.bestbuy.com/site/gigabyte-geforce-rtx-3080-10g-gddr6x-pci-express-4-0-graphics-card-black/6430621.p?skuId=6430621&intl=nosplash' }, { brand: 'msi', cartUrl: 'https://api.bestbuy.com/click/-/6430175/cart', model: 'ventus 3x oc', - url: 'https://www.bestbuy.com/site/msi-geforce-rtx-3080-ventus-3x-10g-oc-bv-gddr6x-pci-express-4-0-graphic-card-black-silver/6430175.p?skuId=6430175&intl=nosplash', - series: '3080' + series: '3080', + url: 'https://www.bestbuy.com/site/msi-geforce-rtx-3080-ventus-3x-10g-oc-bv-gddr6x-pci-express-4-0-graphic-card-black-silver/6430175.p?skuId=6430175&intl=nosplash' } ], - labels: { - outOfStock: ['sold out', 'coming soon'] - }, name: 'bestbuy' }; diff --git a/src/store/model/evga-eu.ts b/src/store/model/evga-eu.ts index a52604d..da3a70c 100644 --- a/src/store/model/evga-eu.ts +++ b/src/store/model/evga-eu.ts @@ -1,6 +1,9 @@ import {Store} from './store'; export const EvgaEu: Store = { + labels: { + outOfStock: ['tbd', 'out of stock', 'error reaching the evga website', 'oops! something broke.'] + }, links: [ { brand: 'evga', @@ -27,8 +30,5 @@ export const EvgaEu: Store = { url: 'https://eu.evga.com/products/product.aspx?pn=10G-P5-3885-KR' } ], - labels: { - outOfStock: ['tbd', 'out of stock', 'error reaching the evga website', 'oops! something broke.'] - }, name: 'evga-eu' }; diff --git a/src/store/model/evga.ts b/src/store/model/evga.ts index 9594a3c..db98eea 100644 --- a/src/store/model/evga.ts +++ b/src/store/model/evga.ts @@ -1,6 +1,9 @@ import {Store} from './store'; export const Evga: Store = { + labels: { + outOfStock: ['out of stock', 'error reaching the evga website', 'oops! something broke.'] + }, links: [ { brand: 'TEST', @@ -39,9 +42,6 @@ export const Evga: Store = { url: 'https://www.evga.com/products/product.aspx?pn=10G-P5-3885-KR' } ], - labels: { - outOfStock: ['out of stock', 'error reaching the evga website', 'oops! something broke.'] - }, name: 'evga' }; diff --git a/src/store/model/helpers/nvidia.ts b/src/store/model/helpers/nvidia.ts index f8c5b25..0a916cf 100644 --- a/src/store/model/helpers/nvidia.ts +++ b/src/store/model/helpers/nvidia.ts @@ -1,17 +1,17 @@ -import {timestampUrlParameter} from '../../timestamp-url-parameter'; import {Browser, Response} from 'puppeteer'; +import {NvidiaRegionInfo, regionInfos} from '../nvidia'; +import {Config} from '../../../config'; +import {Link} from '../store'; import {Logger} from '../../../logger'; import open from 'open'; -import {Link} from '../store'; -import {Config} from '../../../config'; -import {NvidiaRegionInfo, regionInfos} from '../nvidia'; +import {timestampUrlParameter} from '../../timestamp-url-parameter'; const nvidiaApiKey = '9485fa7b159e42edb08a83bde0d83dia'; function getRegionInfo(): NvidiaRegionInfo { const country = Array.from(regionInfos.keys()).includes(Config.store.country) ? Config.store.country : 'usa'; - const defaultRegionInfo: NvidiaRegionInfo = {drLocale: 'en_us', nvidiaLocale: 'en_us', fe3080Id: 5438481700, fe3090Id: null, fe2060SuperId: 5379432500}; + const defaultRegionInfo: NvidiaRegionInfo = {drLocale: 'en_us', fe2060SuperId: 5379432500, fe3080Id: 5438481700, fe3090Id: null, nvidiaLocale: 'en_us'}; return regionInfos.get(country) ?? defaultRegionInfo; } @@ -116,31 +116,31 @@ export function generateLinks(): Link[] { if (fe2060SuperId) { links.push({ - series: 'debug', brand: 'TEST', model: 'CARD', - url: digitalRiverStockUrl(fe2060SuperId, drLocale), - openCartAction: generateOpenCartAction(fe2060SuperId, nvidiaLocale, drLocale, 'TEST CARD debug') + openCartAction: generateOpenCartAction(fe2060SuperId, nvidiaLocale, drLocale, 'TEST CARD debug'), + series: 'debug', + url: digitalRiverStockUrl(fe2060SuperId, drLocale) }); } if (fe3080Id) { links.push({ - series: '3080', brand: 'nvidia', model: 'founders edition', - url: digitalRiverStockUrl(fe3080Id, drLocale), - openCartAction: generateOpenCartAction(fe3080Id, nvidiaLocale, drLocale, 'nvidia founders edition 3080') + openCartAction: generateOpenCartAction(fe3080Id, nvidiaLocale, drLocale, 'nvidia founders edition 3080'), + series: '3080', + url: digitalRiverStockUrl(fe3080Id, drLocale) }); } if (fe3090Id) { links.push({ - series: '3090', brand: 'nvidia', model: 'founders edition', - url: digitalRiverStockUrl(fe3090Id, drLocale), - openCartAction: generateOpenCartAction(fe3090Id, nvidiaLocale, drLocale, 'nvidia founders edition 3090') + openCartAction: generateOpenCartAction(fe3090Id, nvidiaLocale, drLocale, 'nvidia founders edition 3090'), + series: '3090', + url: digitalRiverStockUrl(fe3090Id, drLocale) }); } diff --git a/src/store/model/index.ts b/src/store/model/index.ts index 786673b..ce5b2c1 100644 --- a/src/store/model/index.ts +++ b/src/store/model/index.ts @@ -3,8 +3,8 @@ import {Adorama} from './adorama'; import {Amazon} from './amazon'; import {AmazonCa} from './amazon-ca'; import {Asus} from './asus'; -import {BestBuy} from './bestbuy'; import {BAndH} from './bandh'; +import {BestBuy} from './bestbuy'; import {Config} from '../../config'; import {Evga} from './evga'; import {EvgaEu} from './evga-eu'; @@ -12,8 +12,8 @@ import {MicroCenter} from './microcenter'; import {NewEgg} from './newegg'; import {NewEggCa} from './newegg-ca'; import {Nvidia} from './nvidia'; -import {Store} from './store'; import {OfficeDepot} from './officedepot'; +import {Store} from './store'; import {Zotac} from './zotac'; const masterList = new Map([ @@ -21,8 +21,8 @@ const masterList = new Map([ [Amazon.name, Amazon], [AmazonCa.name, AmazonCa], [Asus.name, Asus], - [BestBuy.name, BestBuy], [BAndH.name, BAndH], + [BestBuy.name, BestBuy], [Evga.name, Evga], [EvgaEu.name, EvgaEu], [MicroCenter.name, MicroCenter], diff --git a/src/store/model/microcenter.ts b/src/store/model/microcenter.ts index 7dae366..91dde35 100644 --- a/src/store/model/microcenter.ts +++ b/src/store/model/microcenter.ts @@ -1,6 +1,9 @@ import {Store} from './store'; export const MicroCenter: Store = { + labels: { + outOfStock: ['sold out'] + }, links: [ { brand: 'TEST', @@ -45,8 +48,5 @@ export const MicroCenter: Store = { url: 'https://www.microcenter.com/product/628607/zotac-geforce-rtx-3080-trinity-overclocked-triple-fan-10gb-gddr6x-pcie-40-graphics-card' } ], - labels: { - outOfStock: ['sold out'] - }, name: 'microcenter' }; diff --git a/src/store/model/newegg-ca.ts b/src/store/model/newegg-ca.ts index 9937200..62c667b 100644 --- a/src/store/model/newegg-ca.ts +++ b/src/store/model/newegg-ca.ts @@ -1,6 +1,10 @@ import {Store} from './store'; export const NewEggCa: Store = { + labels: { + captcha: ['are you a human?'], + outOfStock: ['auto notify', 'item is currently out of stock'] + }, links: [ { brand: 'TEST', @@ -69,9 +73,5 @@ export const NewEggCa: Store = { url: 'https://www.newegg.ca/asus-geforce-rtx-3080-tuf-rtx3080-o10g-gaming/p/N82E16814126452' } ], - labels: { - captcha: ['are you a human?'], - outOfStock: ['auto notify', 'item is currently out of stock'] - }, name: 'newegg-ca' }; diff --git a/src/store/model/newegg.ts b/src/store/model/newegg.ts index 6f32a33..b46e15d 100644 --- a/src/store/model/newegg.ts +++ b/src/store/model/newegg.ts @@ -1,6 +1,10 @@ import {Store} from './store'; export const NewEgg: Store = { + labels: { + captcha: ['are you a human?'], + outOfStock: ['auto notify', 'item is currently out of stock'] + }, links: [ { brand: 'TEST', @@ -100,9 +104,5 @@ export const NewEgg: Store = { url: 'https://www.newegg.com/zotac-geforce-rtx-3080-zt-t30800j-10p/p/N82E16814500504' } ], - labels: { - captcha: ['are you a human?'], - outOfStock: ['auto notify', 'item is currently out of stock'] - }, name: 'newegg' }; diff --git a/src/store/model/nvidia.ts b/src/store/model/nvidia.ts index 66edf73..854c336 100644 --- a/src/store/model/nvidia.ts +++ b/src/store/model/nvidia.ts @@ -1,42 +1,42 @@ -import {Store} from './store'; import {generateLinks, generateSetupAction} from './helpers/nvidia'; +import {Store} from './store'; // Region/country set by config file, silently ignores null / missing values and defaults to usa export interface NvidiaRegionInfo { drLocale: string; - nvidiaLocale: string; fe3080Id: number | null; fe3090Id: number | null; fe2060SuperId: number | null; + nvidiaLocale: string; } export const regionInfos = new Map([ - ['austria', {drLocale: 'de_de', nvidiaLocale: 'de_de', fe3080Id: 5440853700, fe3090Id: null, fe2060SuperId: null}], - ['belgium', {drLocale: 'fr_fr', nvidiaLocale: 'fr_fr', fe3080Id: 5438795700, fe3090Id: null, fe2060SuperId: 5394902700}], - ['canada', {drLocale: 'en_us', nvidiaLocale: 'en_ca', fe3080Id: 5438481700, fe3090Id: null, fe2060SuperId: null}], - ['czechia', {drLocale: 'en_gb', nvidiaLocale: 'en_gb', fe3080Id: 5438793800, fe3090Id: null, fe2060SuperId: null}], - ['denmark', {drLocale: 'en_gb', nvidiaLocale: 'en_gb', fe3080Id: 5438793300, fe3090Id: null, fe2060SuperId: null}], - ['finland', {drLocale: 'en_gb', nvidiaLocale: 'en_gb', fe3080Id: 5438793300, fe3090Id: null, fe2060SuperId: null}], - ['france', {drLocale: 'fr_fr', nvidiaLocale: 'fr_fr', fe3080Id: 5438795200, fe3090Id: null, fe2060SuperId: null}], - ['germany', {drLocale: 'de_de', nvidiaLocale: 'de_de', fe3080Id: 5438792300, fe3090Id: null, fe2060SuperId: null}], - ['great_britain', {drLocale: 'en_gb', nvidiaLocale: 'en_gb', fe3080Id: 5438792800, fe3090Id: null, fe2060SuperId: null}], - ['ireland', {drLocale: 'en_gb', nvidiaLocale: 'en_gb', fe3080Id: 5438792800, fe3090Id: null, fe2060SuperId: null}], - ['italy', {drLocale: 'it_it', nvidiaLocale: 'it_it', fe3080Id: 5438796200, fe3090Id: null, fe2060SuperId: null}], - ['luxembourg', {drLocale: 'fr_fr', nvidiaLocale: 'fr_fr', fe3080Id: 5438795700, fe3090Id: null, fe2060SuperId: 5394902700}], - ['poland', {drLocale: 'pl_pl', nvidiaLocale: 'pl_pl', fe3080Id: 5438797700, fe3090Id: null, fe2060SuperId: null}], - ['portugal', {drLocale: 'en_gb', nvidiaLocale: 'en_gb', fe3080Id: 5438794300, fe3090Id: null, fe2060SuperId: null}], - ['russia', {drLocale: 'ru_ru', nvidiaLocale: 'ru_ru', fe3080Id: null, fe3090Id: null, fe2060SuperId: null}], - ['spain', {drLocale: 'es_es', nvidiaLocale: 'es_es', fe3080Id: 5438794800, fe3090Id: null, fe2060SuperId: null}], - ['sweden', {drLocale: 'sv_SE', nvidiaLocale: 'sv_se', fe3080Id: 5438798100, fe3090Id: null, fe2060SuperId: null}], - ['usa', {drLocale: 'en_us', nvidiaLocale: 'en_us', fe3080Id: 5438481700, fe3090Id: null, fe2060SuperId: 5379432500}] + ['austria', {drLocale: 'de_de', fe2060SuperId: null, fe3080Id: 5440853700, fe3090Id: null, nvidiaLocale: 'de_de'}], + ['belgium', {drLocale: 'fr_fr', fe2060SuperId: 5394902700, fe3080Id: 5438795700, fe3090Id: null, nvidiaLocale: 'fr_fr'}], + ['canada', {drLocale: 'en_us', fe2060SuperId: null, fe3080Id: 5438481700, fe3090Id: null, nvidiaLocale: 'en_ca'}], + ['czechia', {drLocale: 'en_gb', fe2060SuperId: null, fe3080Id: 5438793800, fe3090Id: null, nvidiaLocale: 'en_gb'}], + ['denmark', {drLocale: 'en_gb', fe2060SuperId: null, fe3080Id: 5438793300, fe3090Id: null, nvidiaLocale: 'en_gb'}], + ['finland', {drLocale: 'en_gb', fe2060SuperId: null, fe3080Id: 5438793300, fe3090Id: null, nvidiaLocale: 'en_gb'}], + ['france', {drLocale: 'fr_fr', fe2060SuperId: null, fe3080Id: 5438795200, fe3090Id: null, nvidiaLocale: 'fr_fr'}], + ['germany', {drLocale: 'de_de', fe2060SuperId: null, fe3080Id: 5438792300, fe3090Id: null, nvidiaLocale: 'de_de'}], + ['great_britain', {drLocale: 'en_gb', fe2060SuperId: null, fe3080Id: 5438792800, fe3090Id: null, nvidiaLocale: 'en_gb'}], + ['ireland', {drLocale: 'en_gb', fe2060SuperId: null, fe3080Id: 5438792800, fe3090Id: null, nvidiaLocale: 'en_gb'}], + ['italy', {drLocale: 'it_it', fe2060SuperId: null, fe3080Id: 5438796200, fe3090Id: null, nvidiaLocale: 'it_it'}], + ['luxembourg', {drLocale: 'fr_fr', fe2060SuperId: 5394902700, fe3080Id: 5438795700, fe3090Id: null, nvidiaLocale: 'fr_fr'}], + ['poland', {drLocale: 'pl_pl', fe2060SuperId: null, fe3080Id: 5438797700, fe3090Id: null, nvidiaLocale: 'pl_pSl'}], + ['portugal', {drLocale: 'en_gb', fe2060SuperId: null, fe3080Id: 5438794300, fe3090Id: null, nvidiaLocale: 'en_gb'}], + ['russia', {drLocale: 'ru_ru', fe2060SuperId: null, fe3080Id: null, fe3090Id: null, nvidiaLocale: 'ru_ru'}], + ['spain', {drLocale: 'es_es', fe2060SuperId: null, fe3080Id: 5438794800, fe3090Id: null, nvidiaLocale: 'es_es'}], + ['sweden', {drLocale: 'sv_SE', fe2060SuperId: null, fe3080Id: 5438798100, fe3090Id: null, nvidiaLocale: 'sv_se'}], + ['usa', {drLocale: 'en_us', fe2060SuperId: 5379432500, fe3080Id: 5438481700, fe3090Id: null, nvidiaLocale: 'en_us'}] ]); export const Nvidia: Store = { - links: generateLinks(), labels: { outOfStock: ['product_inventory_out_of_stock', 'rate limit exceeded', 'request timeout'] }, + links: generateLinks(), name: 'nvidia', setupAction: generateSetupAction() }; diff --git a/src/store/model/officedepot.ts b/src/store/model/officedepot.ts index 0ba9f9a..5dd62c6 100644 --- a/src/store/model/officedepot.ts +++ b/src/store/model/officedepot.ts @@ -1,6 +1,10 @@ import {Store} from './store'; export const OfficeDepot: Store = { + labels: { + captcha: ['please verify you are a human'], + outOfStock: ['out of stock for delivery', 'out of stock', 'we are unable to process your last request'] + }, links: [ { brand: 'TEST', @@ -21,9 +25,5 @@ export const OfficeDepot: Store = { url: 'https://www.officedepot.com/a/products/7791294/PNY-GeForce-RTX-3080-10GB-GDDR6X/' } ], - labels: { - captcha: ['please verify you are a human'], - outOfStock: ['out of stock for delivery', 'out of stock', 'we are unable to process your last request'] - }, name: 'officedepot' }; diff --git a/src/store/model/zotac.ts b/src/store/model/zotac.ts index 249a0d1..77542da 100644 --- a/src/store/model/zotac.ts +++ b/src/store/model/zotac.ts @@ -1,6 +1,9 @@ import {Store} from './store'; export const Zotac: Store = { + labels: { + outOfStock: ['out of stock', 'this process is automatic'] + }, links: [ { brand: 'zotac', @@ -15,9 +18,6 @@ export const Zotac: Store = { url: 'https://store.zotac.com/zotac-gaming-geforce-rtx-3080-trinity-oc-zt-a30800j-10p' } ], - labels: { - outOfStock: ['out of stock', 'this process is automatic'] - }, name: 'zotac' }; diff --git a/src/util.ts b/src/util.ts index 440cc6e..0bd824b 100644 --- a/src/util.ts +++ b/src/util.ts @@ -1,5 +1,5 @@ -import {Page} from 'puppeteer'; import {Config} from './config'; +import {Page} from 'puppeteer'; import {disableBlockerInPage} from './adblocker'; export function getSleepTime() {