mirror of
https://github.com/opelly27/streetmerchant.git
synced 2026-05-20 13:27:38 +00:00
Compare commits
18 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 381f1f7505 | |||
| ebbdfe3f63 | |||
| 14b1e4cee6 | |||
| 433fa8ca9f | |||
| cf0e959fb4 | |||
| 8c5d7d0c49 | |||
| 393d5f6898 | |||
| d4de1a4638 | |||
| c85658bf82 | |||
| 8aba7ecbdb | |||
| ccc781b8dd | |||
| 6be74a19f3 | |||
| dcda82bd98 | |||
| ea5b7a0918 | |||
| 3b2ba29cf1 | |||
| a21740942b | |||
| 25643c4870 | |||
| ef319d4b20 |
@@ -0,0 +1,5 @@
|
|||||||
|
root = true
|
||||||
|
[*]
|
||||||
|
end_of_line = lf
|
||||||
|
insert_final_newline = true
|
||||||
|
indent_style = tab
|
||||||
@@ -8,4 +8,11 @@ SLACK_TOKEN="slack-token"
|
|||||||
STORES="bestbuy,bandh,nvidia"
|
STORES="bestbuy,bandh,nvidia"
|
||||||
PHONE_NUMBER="1234567890"
|
PHONE_NUMBER="1234567890"
|
||||||
PHONE_CARRIER="tmobile"
|
PHONE_CARRIER="tmobile"
|
||||||
|
PUSHOVER_TOKEN="123pushover-token456"
|
||||||
|
PUSHOVER_USER="123pushover-user-key"
|
||||||
|
OPEN_BROWSER="true"
|
||||||
|
PLAY_SOUND="false"
|
||||||
SCREENSHOT="true"
|
SCREENSHOT="true"
|
||||||
|
TELEGRAM_ACCESS_TOKEN=""
|
||||||
|
TELEGRAM_CHAT_ID="1234"
|
||||||
|
SHOW_ONLY_BRANDS="evga"
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
---
|
---
|
||||||
name: 🐛 Bug report
|
name: 🐛 Bug report
|
||||||
about: Report a bug for this project
|
about: Report a bug for this project
|
||||||
title: 'bug: '
|
title: ''
|
||||||
labels: 'bug'
|
labels: 'bug'
|
||||||
assignees: jef
|
assignees: jef
|
||||||
|
|
||||||
@@ -9,7 +9,9 @@ assignees: jef
|
|||||||
|
|
||||||
### Description
|
### Description
|
||||||
|
|
||||||
<!-- Describe the feature here. -->
|
<!-- Describe the bug here. -->
|
||||||
|
<!-- Please be as detailed as possible. -->
|
||||||
|
<!-- Include OS, screenshots and console outputs. -->
|
||||||
|
|
||||||
### Possible solution
|
### Possible solution
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
---
|
---
|
||||||
name: 🚀 Feature request
|
name: 🚀 Feature request
|
||||||
about: Suggest a feature for this project
|
about: Suggest a feature for this project
|
||||||
title: 'enhancement: '
|
title: ''
|
||||||
labels: 'enhancement'
|
labels: 'enhancement'
|
||||||
assignees: jef
|
assignees: jef
|
||||||
|
|
||||||
|
|||||||
@@ -6,3 +6,7 @@ node_modules/
|
|||||||
|
|
||||||
.env
|
.env
|
||||||
success-*.png
|
success-*.png
|
||||||
|
|
||||||
|
*.wav
|
||||||
|
*.mp3
|
||||||
|
*.flac
|
||||||
@@ -1,5 +1,22 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## [1.4.0](https://www.github.com/jef/nvidia-snatcher/compare/v1.3.0...v1.4.0) (2020-09-19)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **notification:** add mint mobile carrier ([#70](https://www.github.com/jef/nvidia-snatcher/issues/70)) ([8aba7ec](https://www.github.com/jef/nvidia-snatcher/commit/8aba7ecbdb0bfce06257b7b9066e8fccbd82e47e))
|
||||||
|
* **notification:** add pushover ([#55](https://www.github.com/jef/nvidia-snatcher/issues/55)) ([c85658b](https://www.github.com/jef/nvidia-snatcher/commit/c85658bf82fdf360e5e9d8345eaa846f0572e67c))
|
||||||
|
* **notification:** add telegram ([#71](https://www.github.com/jef/nvidia-snatcher/issues/71)) ([393d5f6](https://www.github.com/jef/nvidia-snatcher/commit/393d5f689887bf1d6f30a37eea163b2e6bbd4efa))
|
||||||
|
* **notification:** add telus sms ([6be74a1](https://www.github.com/jef/nvidia-snatcher/commit/6be74a19f3d3f999145d17ac8e91c59db2502071))
|
||||||
|
* **store:** add amazon.ca, fix timeout ([#75](https://www.github.com/jef/nvidia-snatcher/issues/75)) ([d4de1a4](https://www.github.com/jef/nvidia-snatcher/commit/d4de1a4638e903eb9518354ab6fb2f8c4befc347))
|
||||||
|
* webpage toggle, sound notification, fix evga links ([#52](https://www.github.com/jef/nvidia-snatcher/issues/52)) ([a217409](https://www.github.com/jef/nvidia-snatcher/commit/a21740942bbbbe967948062fa06cfc82c31eb755))
|
||||||
|
|
||||||
|
|
||||||
|
### Performance Improvements
|
||||||
|
|
||||||
|
* browser abstraction ([#68](https://www.github.com/jef/nvidia-snatcher/issues/68)) ([#81](https://www.github.com/jef/nvidia-snatcher/issues/81)) ([ebbdfe3](https://www.github.com/jef/nvidia-snatcher/commit/ebbdfe3f6378516112f4b6e004bbd6ccf13af685))
|
||||||
|
|
||||||
## [1.3.0](https://www.github.com/jef/nvidia-snatcher/compare/v1.2.0...v1.3.0) (2020-09-19)
|
## [1.3.0](https://www.github.com/jef/nvidia-snatcher/compare/v1.2.0...v1.3.0) (2020-09-19)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# nvidia-snatcher [](https://github.com/jef/nvidia-snatcher/actions?query=workflow%3Aci)
|
# nvidia-snatcher [](https://github.com/jef/nvidia-snatcher/actions?query=workflow%3Aci) [](https://discord.gg/Cyc7nrz)
|
||||||
|
|
||||||
[FAQ](#FAQ) | [Discord](https://discord.gg/3duFzwk) | [Issues](https://github.com/jef/nvidia-snatcher/issues) | [Wiki](https://github.com/jef/nvidia-snatcher/wiki)
|
[FAQ](#FAQ) | [Issues](https://github.com/jef/nvidia-snatcher/issues) | [Wiki](https://github.com/jef/nvidia-snatcher/wiki)
|
||||||
|
|
||||||
The purpose of this bot is to get an Nvidia card. It tries multiple things to do that.
|
The purpose of this bot is to get an Nvidia card. It tries multiple things to do that.
|
||||||
|
|
||||||
@@ -28,13 +28,11 @@ The purpose of this bot is to get an Nvidia card. It tries multiple things to do
|
|||||||
|
|
||||||
> :point_right: You may get false positives from time to time, so I apologize for that. The library currently waits for all calls to be completed before parsing, but sometimes this can have unknown behavior. Patience is a virtue :)
|
> :point_right: You may get false positives from time to time, so I apologize for that. The library currently waits for all calls to be completed before parsing, but sometimes this can have unknown behavior. Patience is a virtue :)
|
||||||
|
|
||||||
| | **Best Buy** | **B&H** | **Newegg** | **Nvidia** | **EVGA** | **Amazon** |
|
| | **Amazon** | **EVGA** | **Best Buy** | **B&H** | **Micro Center** | **Newegg** | **Nvidia** |
|
||||||
|:---:|:---:|:---:|:---:|:---:|:---:|:---:|
|
|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|
|
||||||
| **3070**| | | | | | |
|
| **3070**| | | | | | | |
|
||||||
| **3080** | `✔` | `✔` | `ℹ` | `✔` | `✔` | `✔` |
|
| **3080** | `✔` | `✔` | `✔` | `✔` | `✔` | `✔` | `✔` |
|
||||||
| **3090** | | | | | | |
|
| **3090** | | | | | | | |
|
||||||
|
|
||||||
> :point_right: (`ℹ`) Work in progress. Catchpa problems are intermittent. Use if you'd like, but expect problems.
|
|
||||||
|
|
||||||
## Installation and prerequisites
|
## Installation and prerequisites
|
||||||
|
|
||||||
@@ -58,31 +56,39 @@ At any point you want the program to stop, use <kbd>Ctrl</kbd> + <kbd>C</kbd>.
|
|||||||
|
|
||||||
### Customization
|
### Customization
|
||||||
|
|
||||||
There is not much to configure (as of now), but there are some options that you can choose to utilize.
|
To customize `nvidia-snatcher`, make a copy of `.env-example` as `.env` and make any changes to your liking.
|
||||||
|
|
||||||
First, you're going to need to copy the `.env.example` to `.env`. The current options are:
|
Here is a list of variables that you can use to customize your newly copied `.env` file:
|
||||||
|
|
||||||
| **Environment variable** | **Description** |
|
| **Environment variable** | **Description** |
|
||||||
|:---:|:---:|
|
|:---:|---|
|
||||||
| `EMAIL_USERNAME` | Gmail address (e.g., `jensen.robbed.us@gmail.com`); optional |
|
| `EMAIL_USERNAME` | Gmail address (e.g., `jensen.robbed.us@gmail.com`); optional |
|
||||||
| `EMAIL_PASSWORD` | Gmail password; see below if you have MFA; optional |
|
| `EMAIL_PASSWORD` | Gmail password; see below if you have MFA; optional |
|
||||||
| `NOTIFICATION_TEST` | Test all the notifications configured; optional, default: `false` |
|
| `NOTIFICATION_TEST` | Test all the notifications configured; optional, default: `false` |
|
||||||
| `PAGE_TIMEOUT` | Navigation Timeout in milliseconds (`0` for infinite); optional, default: `30000` |
|
| `PAGE_TIMEOUT` | Navigation Timeout in milliseconds (`0` for infinite); optional, default: `30000` |
|
||||||
| `PHONE_NUMBER` | 10 digit phone number, only USA, SMS may apply (e.g., `1234567890`); optional, email configuration required |
|
| `PHONE_NUMBER` | 10 digit phone number (e.g., `1234567890`); optional, email configuration required |
|
||||||
| `PHONE_CARRIER` | Service provider for SMS, supports `["sprint", "tmobile", "att", "verizon", "google"]`; optional, email configuration required |
|
| `PHONE_CARRIER` | [Supported carriers](#supported-carriers) for SMS; optional, email configuration required |
|
||||||
| `RATE_LIMIT_TIMEOUT` | Rate limit timeout for each full store cycle; optional, default: `5000` |
|
| `RATE_LIMIT_TIMEOUT` | Rate limit timeout for each full store cycle; optional, default: `5000` |
|
||||||
|
| `SHOW_ONLY_BRANDS` | If set, will only show specified brands, seperated by `,` |
|
||||||
| `SLACK_CHANNEL` | Slack channel for posting (e.g., `update`); optional |
|
| `SLACK_CHANNEL` | Slack channel for posting (e.g., `update`); optional |
|
||||||
| `SLACK_TOKEN` | Slack API token; optional
|
| `SLACK_TOKEN` | Slack API token; optional |
|
||||||
| `STORES` | List of [stores](#Supported-stores) you want to be scraped; optional, default: `nvidia` |
|
| `STORES` | [Supported stores](#supported-stores) you want to be scraped; optional, default: `nvidia` |
|
||||||
|
| `OPEN_BROWSER` | Toggle for whether or not the browser should open when item is found, default: `true` |
|
||||||
|
| `PLAY_SOUND` | Play this sound notification if a card is found.; optional |
|
||||||
| `SCREENSHOT` | Capture screenshot of page on successful hit; optional, default `true` |
|
| `SCREENSHOT` | Capture screenshot of page on successful hit; optional, default `true` |
|
||||||
|
| `TELEGRAM_ACCESS_TOKEN` | Telegram access token; optional |
|
||||||
|
| `TELEGRAM_CHAT_ID` | Telegram chat ID; optional |
|
||||||
|
|
||||||
> :point_right: If you have multi-factor authentication (MFA), you will need to create an [app password](https://myaccount.google.com/apppasswords) and use this instead of your Gmail password.
|
> :point_right: If you have multi-factor authentication (MFA), you will need to create an [app password](https://myaccount.google.com/apppasswords) and use this instead of your Gmail password.
|
||||||
|
|
||||||
|
> :point_right: Free sounds available [here](https://freesound.org/home/). Place sounds into `resources/sounds/`
|
||||||
|
|
||||||
#### Supported stores
|
#### Supported stores
|
||||||
|
|
||||||
| **Store name** | **Store name environment variable** |
|
| **Stores** | **Environment variable** |
|
||||||
|:---:|:---:|
|
|:---:|:---:|
|
||||||
| Best Buy | `bestbuy`|
|
| Best Buy | `bestbuy`|
|
||||||
|
| Amazon.ca | `amazon-ca`|
|
||||||
| Amazon | `amazon`|
|
| Amazon | `amazon`|
|
||||||
| B&H | `bandh`|
|
| B&H | `bandh`|
|
||||||
| EVGA | `evga`|
|
| EVGA | `evga`|
|
||||||
@@ -90,7 +96,17 @@ First, you're going to need to copy the `.env.example` to `.env`. The current op
|
|||||||
| Newegg | `newegg`|
|
| Newegg | `newegg`|
|
||||||
| Nvidia | `nvidia`|
|
| Nvidia | `nvidia`|
|
||||||
|
|
||||||
> :point_right: Look at [`.env.example`](.env.example) for an example for `.env`.
|
#### Supported carriers
|
||||||
|
|
||||||
|
| **Carrier** | **Environment variable** | **Notes** |
|
||||||
|
|:---:|:---:|:---:|
|
||||||
|
| AT&T | `att`| |
|
||||||
|
| Google | `google`| |
|
||||||
|
| Mint | `mint`| |
|
||||||
|
| Sprint | `sprint`| |
|
||||||
|
| Telus | `telus`| |
|
||||||
|
| T-Mobile | `tmobile`| |
|
||||||
|
| Verizon | `verizon`| Works with Visible |
|
||||||
|
|
||||||
## FAQ
|
## FAQ
|
||||||
|
|
||||||
|
|||||||
Generated
+177
-14
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "nvidia-snatcher",
|
"name": "nvidia-snatcher",
|
||||||
"version": "1.3.0",
|
"version": "1.4.0",
|
||||||
"lockfileVersion": 1,
|
"lockfileVersion": 1,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -230,6 +230,11 @@
|
|||||||
"integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==",
|
"integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"@types/debug": {
|
||||||
|
"version": "4.1.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.5.tgz",
|
||||||
|
"integrity": "sha512-Q1y515GcOdTHgagaVFhHnIFQ38ygs/kmxdNpvpou+raI9UO3YZcHDngBSYKQklcKlvA7iuQlmIKbzvmxcOE9CQ=="
|
||||||
|
},
|
||||||
"@types/eslint-visitor-keys": {
|
"@types/eslint-visitor-keys": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz",
|
||||||
@@ -267,6 +272,11 @@
|
|||||||
"integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=",
|
"integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"@types/lodash": {
|
||||||
|
"version": "4.14.161",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.161.tgz",
|
||||||
|
"integrity": "sha512-EP6O3Jkr7bXvZZSZYlsgt5DIjiGr0dXP1/jVEwVLTFgg0d+3lWVQkRavYVQszV7dYUwvg0B8R0MBDpcmXg7XIA=="
|
||||||
|
},
|
||||||
"@types/minimatch": {
|
"@types/minimatch": {
|
||||||
"version": "3.0.3",
|
"version": "3.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz",
|
||||||
@@ -326,6 +336,16 @@
|
|||||||
"integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==",
|
"integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"@types/url-join": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/url-join/-/url-join-4.0.0.tgz",
|
||||||
|
"integrity": "sha512-awrJu8yML4E/xTwr2EMatC+HBnHGoDxc2+ImA9QyeUELI1S7dOCIZcyjki1rkwoA8P2D2NVgLAJLjnclkdLtAw=="
|
||||||
|
},
|
||||||
|
"@types/warning": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/warning/-/warning-3.0.0.tgz",
|
||||||
|
"integrity": "sha1-DSUBJorY+ZYrdA04fEZU9fjiPlI="
|
||||||
|
},
|
||||||
"@types/yauzl": {
|
"@types/yauzl": {
|
||||||
"version": "2.9.1",
|
"version": "2.9.1",
|
||||||
"resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.9.1.tgz",
|
"resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.9.1.tgz",
|
||||||
@@ -649,11 +669,26 @@
|
|||||||
"version": "0.19.2",
|
"version": "0.19.2",
|
||||||
"resolved": "https://registry.npmjs.org/axios/-/axios-0.19.2.tgz",
|
"resolved": "https://registry.npmjs.org/axios/-/axios-0.19.2.tgz",
|
||||||
"integrity": "sha512-fjgm5MvRHLhx+osE2xoekY70AhARk3a6hkN+3Io1jc00jtquGvxYlKlsFUhmUET0V5te6CcZI7lcv2Ym61mjHA==",
|
"integrity": "sha512-fjgm5MvRHLhx+osE2xoekY70AhARk3a6hkN+3Io1jc00jtquGvxYlKlsFUhmUET0V5te6CcZI7lcv2Ym61mjHA==",
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"follow-redirects": "1.5.10"
|
"follow-redirects": "1.5.10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"axios-error": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/axios-error/-/axios-error-1.0.0.tgz",
|
||||||
|
"integrity": "sha512-1JlcEEdTDeadLJ9+ImZd9eQudqqpAStpHzh9/Rb2q2UsWC+dJyQrFMTAHOzSJoFknWZ9IbVvW5gga9lG7CKLqQ==",
|
||||||
|
"requires": {
|
||||||
|
"axios": "^0.19.2",
|
||||||
|
"type-fest": "^0.15.1"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"type-fest": {
|
||||||
|
"version": "0.15.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.15.1.tgz",
|
||||||
|
"integrity": "sha512-n+UXrN8i5ioo7kqT/nF8xsEzLaqFra7k32SEsSPwvXVGyAcRgV/FUQN/sgfptJTR1oRmmq7z4IXMFSM7im7C9A=="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"babel-eslint": {
|
"babel-eslint": {
|
||||||
"version": "10.1.0",
|
"version": "10.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/babel-eslint/-/babel-eslint-10.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/babel-eslint/-/babel-eslint-10.1.0.tgz",
|
||||||
@@ -1043,6 +1078,15 @@
|
|||||||
"integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
|
"integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"camel-case": {
|
||||||
|
"version": "4.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/camel-case/-/camel-case-4.1.1.tgz",
|
||||||
|
"integrity": "sha512-7fa2WcG4fYFkclIvEmxBbTvmibwF2/agfEBc6q3lOpVu0A13ltLsA+Hr/8Hp6kp5f+G7hKi6t8lys6XxP+1K6Q==",
|
||||||
|
"requires": {
|
||||||
|
"pascal-case": "^3.1.1",
|
||||||
|
"tslib": "^1.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"camelcase": {
|
"camelcase": {
|
||||||
"version": "5.3.1",
|
"version": "5.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
|
||||||
@@ -1578,6 +1622,15 @@
|
|||||||
"integrity": "sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==",
|
"integrity": "sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"dot-case": {
|
||||||
|
"version": "3.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.3.tgz",
|
||||||
|
"integrity": "sha512-7hwEmg6RiSQfm/GwPL4AAWXKy3YNNZA3oFv2Pdiey0mwkRCPZ9x6SZbkLcn8Ma5PYeVokzoD4Twv2n7LKp5WeA==",
|
||||||
|
"requires": {
|
||||||
|
"no-case": "^3.0.3",
|
||||||
|
"tslib": "^1.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"dot-prop": {
|
"dot-prop": {
|
||||||
"version": "5.3.0",
|
"version": "5.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz",
|
||||||
@@ -2721,6 +2774,12 @@
|
|||||||
"pkg-dir": "^4.1.0"
|
"pkg-dir": "^4.1.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"find-exec": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/find-exec/-/find-exec-1.0.1.tgz",
|
||||||
|
"integrity": "sha512-4o6QkGkpg3xK5s/47rdK9LDZRsE4JR1mrXnaAOXBngG6UKeIDJXfwtNCAkljgyy6VRh75D3FFaB0tii9vDEtIA==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"find-root": {
|
"find-root": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz",
|
||||||
@@ -2773,7 +2832,6 @@
|
|||||||
"version": "1.5.10",
|
"version": "1.5.10",
|
||||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.10.tgz",
|
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.10.tgz",
|
||||||
"integrity": "sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==",
|
"integrity": "sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==",
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"debug": "=3.1.0"
|
"debug": "=3.1.0"
|
||||||
},
|
},
|
||||||
@@ -2782,7 +2840,6 @@
|
|||||||
"version": "3.1.0",
|
"version": "3.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
|
||||||
"integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
|
"integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"ms": "2.0.0"
|
"ms": "2.0.0"
|
||||||
}
|
}
|
||||||
@@ -2790,8 +2847,7 @@
|
|||||||
"ms": {
|
"ms": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
||||||
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
|
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
|
||||||
"dev": true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -3549,8 +3605,7 @@
|
|||||||
"js-tokens": {
|
"js-tokens": {
|
||||||
"version": "4.0.0",
|
"version": "4.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
|
||||||
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
|
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"js-types": {
|
"js-types": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
@@ -3713,8 +3768,7 @@
|
|||||||
"lodash": {
|
"lodash": {
|
||||||
"version": "4.17.20",
|
"version": "4.17.20",
|
||||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz",
|
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz",
|
||||||
"integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==",
|
"integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA=="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"lodash.get": {
|
"lodash.get": {
|
||||||
"version": "4.4.2",
|
"version": "4.4.2",
|
||||||
@@ -3795,6 +3849,22 @@
|
|||||||
"triple-beam": "^1.3.0"
|
"triple-beam": "^1.3.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"loose-envify": {
|
||||||
|
"version": "1.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
|
||||||
|
"integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
|
||||||
|
"requires": {
|
||||||
|
"js-tokens": "^3.0.0 || ^4.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"lower-case": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.1.tgz",
|
||||||
|
"integrity": "sha512-LiWgfDLLb1dwbFQZsSglpRj+1ctGnayXz3Uv0/WO8n558JycT5fg6zkNcnW0G68Nn0aEldTFeEfmjCfmqry/rQ==",
|
||||||
|
"requires": {
|
||||||
|
"tslib": "^1.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"lowercase-keys": {
|
"lowercase-keys": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz",
|
||||||
@@ -3827,8 +3897,7 @@
|
|||||||
"map-obj": {
|
"map-obj": {
|
||||||
"version": "4.1.0",
|
"version": "4.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/map-obj/-/map-obj-4.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/map-obj/-/map-obj-4.1.0.tgz",
|
||||||
"integrity": "sha512-glc9y00wgtwcDmp7GaE/0b0OnxpNJsVf3ael/An6Fe2Q51LLwN1er6sdomLRzz5h0+yMpiYLhWYF5R7HeqVd4g==",
|
"integrity": "sha512-glc9y00wgtwcDmp7GaE/0b0OnxpNJsVf3ael/An6Fe2Q51LLwN1er6sdomLRzz5h0+yMpiYLhWYF5R7HeqVd4g=="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"map-visit": {
|
"map-visit": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
@@ -3928,6 +3997,39 @@
|
|||||||
"integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
|
"integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"messaging-api-common": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/messaging-api-common/-/messaging-api-common-1.0.0.tgz",
|
||||||
|
"integrity": "sha512-4bHqgnzrR2F97V+WnxVKS6EmjElkURa9jhy0/Tv7B+Xmcl3BDEW2krFpr5LfJDwFFiaDqj8Poel81hTOoWO/Lw==",
|
||||||
|
"requires": {
|
||||||
|
"@types/debug": "^4.1.5",
|
||||||
|
"@types/lodash": "^4.14.156",
|
||||||
|
"@types/url-join": "^4.0.0",
|
||||||
|
"axios": "^0.19.2",
|
||||||
|
"camel-case": "^4.1.1",
|
||||||
|
"debug": "^4.1.1",
|
||||||
|
"lodash": "^4.17.15",
|
||||||
|
"map-obj": "^4.1.0",
|
||||||
|
"pascal-case": "^3.1.1",
|
||||||
|
"snake-case": "^3.0.3",
|
||||||
|
"url-join": "^4.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"messaging-api-telegram": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/messaging-api-telegram/-/messaging-api-telegram-1.0.0.tgz",
|
||||||
|
"integrity": "sha512-hA2LFclQV5sVGGIYosdYvhap0GrPD73GuNjYi/T9rKZhn9qA5wTihrHNXdJHmUI7QOTT3JnA3QRdkwc9wkFZuA==",
|
||||||
|
"requires": {
|
||||||
|
"@types/lodash": "^4.14.156",
|
||||||
|
"@types/warning": "^3.0.0",
|
||||||
|
"axios": "^0.19.2",
|
||||||
|
"axios-error": "^1.0.0",
|
||||||
|
"lodash": "^4.17.15",
|
||||||
|
"messaging-api-common": "^1.0.0",
|
||||||
|
"ts-invariant": "^0.4.4",
|
||||||
|
"warning": "^4.0.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
"micro-spelling-correcter": {
|
"micro-spelling-correcter": {
|
||||||
"version": "1.1.1",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/micro-spelling-correcter/-/micro-spelling-correcter-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/micro-spelling-correcter/-/micro-spelling-correcter-1.1.1.tgz",
|
||||||
@@ -4145,6 +4247,15 @@
|
|||||||
"integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=",
|
"integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"no-case": {
|
||||||
|
"version": "3.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.3.tgz",
|
||||||
|
"integrity": "sha512-ehY/mVQCf9BL0gKfsJBvFJen+1V//U+0HQMPrWct40ixE4jnv0bfvxDbWtAHL9EcaPEOJHVVYKoQn1TlZUB8Tw==",
|
||||||
|
"requires": {
|
||||||
|
"lower-case": "^2.0.1",
|
||||||
|
"tslib": "^1.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node-libs-browser": {
|
"node-libs-browser": {
|
||||||
"version": "2.2.1",
|
"version": "2.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-2.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-2.2.1.tgz",
|
||||||
@@ -4559,6 +4670,15 @@
|
|||||||
"lines-and-columns": "^1.1.6"
|
"lines-and-columns": "^1.1.6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"pascal-case": {
|
||||||
|
"version": "3.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.1.tgz",
|
||||||
|
"integrity": "sha512-XIeHKqIrsquVTQL2crjq3NfJUxmdLasn3TYOU0VBM+UX2a6ztAWBlJQBePLGY7VHW8+2dRadeIPK5+KImwTxQA==",
|
||||||
|
"requires": {
|
||||||
|
"no-case": "^3.0.3",
|
||||||
|
"tslib": "^1.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"pascalcase": {
|
"pascalcase": {
|
||||||
"version": "0.1.1",
|
"version": "0.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz",
|
||||||
@@ -4643,6 +4763,15 @@
|
|||||||
"find-up": "^4.0.0"
|
"find-up": "^4.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"play-sound": {
|
||||||
|
"version": "1.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/play-sound/-/play-sound-1.1.3.tgz",
|
||||||
|
"integrity": "sha512-lqEzgtNAdfg2VUXItOtu5bTyWcqeFmnJmgvc8iHEeEOBEJdurqiGYfmCOzIpSBcwrs7XeSpvHv+Rw9dzRPc4aw==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"find-exec": "1.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"plur": {
|
"plur": {
|
||||||
"version": "4.0.0",
|
"version": "4.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/plur/-/plur-4.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/plur/-/plur-4.0.0.tgz",
|
||||||
@@ -4783,6 +4912,11 @@
|
|||||||
"ws": "^7.2.3"
|
"ws": "^7.2.3"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"pushover-notifications": {
|
||||||
|
"version": "1.2.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/pushover-notifications/-/pushover-notifications-1.2.2.tgz",
|
||||||
|
"integrity": "sha512-+3Xcj+kiMiouZK1Ws8yGBTyl8WMPZZdELgl/iVxYqNwDdlaObBHMhEGPRC6Zb9t0BE27ikOoOqSIO1cKZOtsDA=="
|
||||||
|
},
|
||||||
"querystring": {
|
"querystring": {
|
||||||
"version": "0.2.0",
|
"version": "0.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz",
|
||||||
@@ -5216,6 +5350,15 @@
|
|||||||
"is-fullwidth-code-point": "^2.0.0"
|
"is-fullwidth-code-point": "^2.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"snake-case": {
|
||||||
|
"version": "3.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/snake-case/-/snake-case-3.0.3.tgz",
|
||||||
|
"integrity": "sha512-WM1sIXEO+rsAHBKjGf/6R1HBBcgbncKS08d2Aqec/mrDSpU80SiOU41hO7ny6DToHSyrlwTYzQBIK1FPSx4Y3Q==",
|
||||||
|
"requires": {
|
||||||
|
"dot-case": "^3.0.3",
|
||||||
|
"tslib": "^1.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"snapdragon": {
|
"snapdragon": {
|
||||||
"version": "0.8.2",
|
"version": "0.8.2",
|
||||||
"resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz",
|
"resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz",
|
||||||
@@ -5811,6 +5954,14 @@
|
|||||||
"resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.3.0.tgz",
|
||||||
"integrity": "sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw=="
|
"integrity": "sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw=="
|
||||||
},
|
},
|
||||||
|
"ts-invariant": {
|
||||||
|
"version": "0.4.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/ts-invariant/-/ts-invariant-0.4.4.tgz",
|
||||||
|
"integrity": "sha512-uEtWkFM/sdZvRNNDL3Ehu4WVpwaulhwQszV8mrtcdeE8nN00BV9mAmQ88RkrBhFgl9gMgvjJLAQcZbnPXI9mlA==",
|
||||||
|
"requires": {
|
||||||
|
"tslib": "^1.9.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
"tsconfig-paths": {
|
"tsconfig-paths": {
|
||||||
"version": "3.9.0",
|
"version": "3.9.0",
|
||||||
"resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.9.0.tgz",
|
"resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.9.0.tgz",
|
||||||
@@ -5837,8 +5988,7 @@
|
|||||||
"tslib": {
|
"tslib": {
|
||||||
"version": "1.13.0",
|
"version": "1.13.0",
|
||||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.13.0.tgz",
|
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.13.0.tgz",
|
||||||
"integrity": "sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q==",
|
"integrity": "sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q=="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"tsutils": {
|
"tsutils": {
|
||||||
"version": "3.17.1",
|
"version": "3.17.1",
|
||||||
@@ -6067,6 +6217,11 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"url-join": {
|
||||||
|
"version": "4.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/url-join/-/url-join-4.0.1.tgz",
|
||||||
|
"integrity": "sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA=="
|
||||||
|
},
|
||||||
"url-parse-lax": {
|
"url-parse-lax": {
|
||||||
"version": "3.0.0",
|
"version": "3.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz",
|
||||||
@@ -6126,6 +6281,14 @@
|
|||||||
"integrity": "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==",
|
"integrity": "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"warning": {
|
||||||
|
"version": "4.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz",
|
||||||
|
"integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==",
|
||||||
|
"requires": {
|
||||||
|
"loose-envify": "^1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"which": {
|
"which": {
|
||||||
"version": "2.0.2",
|
"version": "2.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
|
||||||
|
|||||||
+4
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "nvidia-snatcher",
|
"name": "nvidia-snatcher",
|
||||||
"version": "1.3.0",
|
"version": "1.4.0",
|
||||||
"description": "🔮 For all your Nvidia needs",
|
"description": "🔮 For all your Nvidia needs",
|
||||||
"main": "src/index.ts",
|
"main": "src/index.ts",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
@@ -22,9 +22,11 @@
|
|||||||
"homepage": "https://github.com/jef/nvidia-snatcher#readme",
|
"homepage": "https://github.com/jef/nvidia-snatcher#readme",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"dotenv": "^8.2.0",
|
"dotenv": "^8.2.0",
|
||||||
|
"messaging-api-telegram": "^1.0.0",
|
||||||
"nodemailer": "^6.4.11",
|
"nodemailer": "^6.4.11",
|
||||||
"open": "^7.2.1",
|
"open": "^7.2.1",
|
||||||
"puppeteer": "^5.3.0",
|
"puppeteer": "^5.3.0",
|
||||||
|
"pushover-notifications": "^1.2.2",
|
||||||
"winston": "^3.3.3"
|
"winston": "^3.3.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
@@ -32,6 +34,7 @@
|
|||||||
"@types/node": "^14.11.1",
|
"@types/node": "^14.11.1",
|
||||||
"@types/nodemailer": "^6.4.0",
|
"@types/nodemailer": "^6.4.0",
|
||||||
"@types/puppeteer": "^3.0.2",
|
"@types/puppeteer": "^3.0.2",
|
||||||
|
"play-sound": "^1.1.3",
|
||||||
"rimraf": "^3.0.2",
|
"rimraf": "^3.0.2",
|
||||||
"typescript": "^4.0.2",
|
"typescript": "^4.0.2",
|
||||||
"xo": "^0.33.1"
|
"xo": "^0.33.1"
|
||||||
|
|||||||
+26
-6
@@ -9,14 +9,31 @@ const notifications = {
|
|||||||
password: process.env.EMAIL_PASSWORD ?? ''
|
password: process.env.EMAIL_PASSWORD ?? ''
|
||||||
},
|
},
|
||||||
phone: {
|
phone: {
|
||||||
availableCarriers: ['sprint', 'verizon', 'tmobile', 'att', 'google'],
|
availableCarriers: new Map([
|
||||||
carrier: process.env.PHONE_CARRIER,
|
['att', 'txt.att.net'],
|
||||||
number: process.env.PHONE_NUMBER
|
['google', 'msg.fi.google.com'],
|
||||||
|
['mint', 'mailmymobile.net'],
|
||||||
|
['sprint', 'messaging.sprintpcs.com'],
|
||||||
|
['telus', 'msg.telus.com'],
|
||||||
|
['tmobile', 'tmomail.net'],
|
||||||
|
['verizon', 'vtext.com']
|
||||||
|
]),
|
||||||
|
carrier: process.env.PHONE_CARRIER ?? '',
|
||||||
|
number: process.env.PHONE_NUMBER ?? ''
|
||||||
|
},
|
||||||
|
playSound: process.env.PLAY_SOUND ?? 'false',
|
||||||
|
pushover: {
|
||||||
|
token: process.env.PUSHOVER_TOKEN,
|
||||||
|
user: process.env.PUSHOVER_USER
|
||||||
},
|
},
|
||||||
slack: {
|
slack: {
|
||||||
channel: process.env.SLACK_CHANNEL ?? '',
|
channel: process.env.SLACK_CHANNEL ?? '',
|
||||||
token: process.env.SLACK_TOKEN ?? ''
|
token: process.env.SLACK_TOKEN ?? ''
|
||||||
},
|
},
|
||||||
|
telegram: {
|
||||||
|
accessToken: process.env.TELEGRAM_ACCESS_TOKEN ?? '',
|
||||||
|
chatId: process.env.TELEGRAM_CHAT_ID ?? ''
|
||||||
|
},
|
||||||
test: process.env.NOTIFICATION_TEST ?? 'false'
|
test: process.env.NOTIFICATION_TEST ?? 'false'
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -28,13 +45,16 @@ const page = {
|
|||||||
userAgent: 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36'
|
userAgent: 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36'
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const openBrowser = process.env.OPEN_BROWSER ?? 'true';
|
||||||
const rateLimitTimeout = Number(process.env.RATE_LIMIT_TIMEOUT) ?? 5000;
|
const rateLimitTimeout = Number(process.env.RATE_LIMIT_TIMEOUT) ?? 5000;
|
||||||
|
const stores = process.env.STORES ? process.env.STORES.split(',') : ['nvidia'];
|
||||||
const stores = process.env.STORES ?? 'nvidia';
|
const showOnlyBrands = process.env.SHOW_ONLY_BRANDS ? process.env.SHOW_ONLY_BRANDS.split(',') : [];
|
||||||
|
|
||||||
export const Config = {
|
export const Config = {
|
||||||
notifications,
|
notifications,
|
||||||
rateLimitTimeout,
|
rateLimitTimeout,
|
||||||
page,
|
page,
|
||||||
stores
|
stores,
|
||||||
|
openBrowser,
|
||||||
|
showOnlyBrands
|
||||||
};
|
};
|
||||||
|
|||||||
+11
-74
@@ -1,97 +1,34 @@
|
|||||||
import {Config} from './config';
|
import {Config} from './config';
|
||||||
import {Store, Stores} from './store';
|
import {Stores} from './store/model';
|
||||||
import puppeteer from 'puppeteer';
|
|
||||||
import open from 'open';
|
|
||||||
import sendNotification from './notification';
|
|
||||||
import {Logger} from './logger';
|
import {Logger} from './logger';
|
||||||
|
import {sendNotification} from './notification';
|
||||||
/**
|
import {lookup} from './store';
|
||||||
* Send test email.
|
import puppeteer from 'puppeteer';
|
||||||
*/
|
|
||||||
if (Config.notifications.test === 'true') {
|
|
||||||
sendNotification('test');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Starts the bot.
|
* Starts the bot.
|
||||||
*/
|
*/
|
||||||
async function main() {
|
async function main() {
|
||||||
const results = [];
|
const results = [];
|
||||||
|
const browser = await puppeteer.launch();
|
||||||
|
|
||||||
for (const store of Stores) {
|
for (const store of Stores) {
|
||||||
Logger.debug(store.links);
|
Logger.debug(store.links);
|
||||||
results.push(lookup(store));
|
results.push(lookup(browser, store));
|
||||||
}
|
}
|
||||||
|
|
||||||
await Promise.all(results);
|
await Promise.all(results);
|
||||||
|
await browser.close();
|
||||||
|
|
||||||
Logger.info('↗ trying stores again');
|
Logger.info('↗ trying stores again');
|
||||||
setTimeout(main, Config.rateLimitTimeout);
|
setTimeout(main, Config.rateLimitTimeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Responsible for looking up information about a each product within
|
* Send test email.
|
||||||
* 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) {
|
if (Config.notifications.test === 'true') {
|
||||||
/* eslint-disable no-await-in-loop */
|
sendNotification('test');
|
||||||
for (const link of store.links) {
|
|
||||||
const browser = await puppeteer.launch();
|
|
||||||
const page = await browser.newPage();
|
|
||||||
page.setDefaultNavigationTimeout(Config.page.navigationTimeout);
|
|
||||||
await page.setUserAgent(Config.page.userAgent);
|
|
||||||
await page.setViewport({
|
|
||||||
height: Config.page.height,
|
|
||||||
width: Config.page.width
|
|
||||||
});
|
|
||||||
|
|
||||||
const graphicsCard = `${link.brand} ${link.model}`;
|
|
||||||
|
|
||||||
try {
|
|
||||||
await page.goto(link.url, {waitUntil: 'networkidle0'});
|
|
||||||
} catch {
|
|
||||||
Logger.error(`✖ [${store.name}] ${graphicsCard} skipping; timed out`);
|
|
||||||
await browser.close();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const bodyHandle = await page.$('body');
|
|
||||||
const textContent = await page.evaluate(body => body.textContent, bodyHandle);
|
|
||||||
|
|
||||||
Logger.debug(textContent);
|
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
if (Config.page.capture === 'true') {
|
|
||||||
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();
|
|
||||||
return oosLabels.some(label => domTextLowerCase.includes(label));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -3,23 +3,24 @@ import Mail from 'nodemailer/lib/mailer';
|
|||||||
import {Config} from '../config';
|
import {Config} from '../config';
|
||||||
import {Logger} from '../logger';
|
import {Logger} from '../logger';
|
||||||
|
|
||||||
|
const email = Config.notifications.email;
|
||||||
const subject = 'NVIDIA - BUY NOW';
|
const subject = 'NVIDIA - BUY NOW';
|
||||||
|
|
||||||
const transporter = nodemailer.createTransport({
|
const transporter = nodemailer.createTransport({
|
||||||
service: 'gmail',
|
service: 'gmail',
|
||||||
auth: {
|
auth: {
|
||||||
user: Config.notifications.email.username,
|
user: email.username,
|
||||||
pass: Config.notifications.email.password
|
pass: email.password
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const mailOptions: Mail.Options = {
|
const mailOptions: Mail.Options = {
|
||||||
from: Config.notifications.email.username,
|
from: email.username,
|
||||||
to: Config.notifications.email.username,
|
to: email.username,
|
||||||
subject
|
subject
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function sendEmail(text: string) {
|
export function sendEmail(text: string) {
|
||||||
mailOptions.text = text;
|
mailOptions.text = text;
|
||||||
|
|
||||||
transporter.sendMail(mailOptions, (error, info) => {
|
transporter.sendMail(mailOptions, (error, info) => {
|
||||||
|
|||||||
@@ -1,21 +1 @@
|
|||||||
import {Config} from '../config';
|
export * from './notification';
|
||||||
import sendEmail from './email';
|
|
||||||
import sendSlaskMessage from './slack';
|
|
||||||
import sendSMS from './sms';
|
|
||||||
|
|
||||||
export default function sendNotification(cartUrl: string) {
|
|
||||||
if (Config.notifications.email.username && Config.notifications.email.password) {
|
|
||||||
sendEmail(cartUrl);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Config.notifications.slack.channel && Config.notifications.slack.token) {
|
|
||||||
sendSlaskMessage(cartUrl);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Config.notifications.phone.number) {
|
|
||||||
const carrier = Config.notifications.phone.carrier?.toLowerCase();
|
|
||||||
if (carrier && Config.notifications.phone.availableCarriers.includes(carrier)) {
|
|
||||||
sendSMS(cartUrl);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -0,0 +1,38 @@
|
|||||||
|
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';
|
||||||
|
|
||||||
|
const notifications = Config.notifications;
|
||||||
|
|
||||||
|
export function sendNotification(cartUrl: string) {
|
||||||
|
if (notifications.email.username && notifications.email.password) {
|
||||||
|
sendEmail(cartUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (notifications.slack.channel && notifications.slack.token) {
|
||||||
|
sendSlackMessage(cartUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (notifications.telegram.accessToken && notifications.telegram.chatId) {
|
||||||
|
sendTelegramMessage(cartUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (notifications.phone.number) {
|
||||||
|
const carrier = notifications.phone.carrier.toLowerCase();
|
||||||
|
if (carrier && notifications.phone.availableCarriers.has(carrier)) {
|
||||||
|
sendSMS(cartUrl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (notifications.pushover.token && notifications.pushover.user) {
|
||||||
|
sendPushoverNotification(cartUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (notifications.playSound === 'true') {
|
||||||
|
playSound();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
import Push from 'pushover-notifications';
|
||||||
|
import {Config} from '../config';
|
||||||
|
import {Logger} from '../logger';
|
||||||
|
|
||||||
|
const pushover = Config.notifications.pushover;
|
||||||
|
const push = new Push({
|
||||||
|
user: pushover.user,
|
||||||
|
token: pushover.token
|
||||||
|
});
|
||||||
|
|
||||||
|
export function sendPushoverNotification(text: string) {
|
||||||
|
const message = {
|
||||||
|
message: text
|
||||||
|
};
|
||||||
|
|
||||||
|
push.send(message, (err: Error, result: string) => {
|
||||||
|
if (err) {
|
||||||
|
Logger.error(err);
|
||||||
|
} else {
|
||||||
|
Logger.info(`✔ Pushover notification sent: ${result}`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -6,7 +6,7 @@ const channel = Config.notifications.slack.channel;
|
|||||||
const token = Config.notifications.slack.token;
|
const token = Config.notifications.slack.token;
|
||||||
const web = new WebClient(token);
|
const web = new WebClient(token);
|
||||||
|
|
||||||
export default function sendSlackMessage(text: string) {
|
export function sendSlackMessage(text: string) {
|
||||||
(async () => {
|
(async () => {
|
||||||
try {
|
try {
|
||||||
const result = await web.chat.postMessage({text, channel});
|
const result = await web.chat.postMessage({text, channel});
|
||||||
|
|||||||
+7
-15
@@ -4,20 +4,13 @@ import {Config} from '../config';
|
|||||||
import {Logger} from '../logger';
|
import {Logger} from '../logger';
|
||||||
|
|
||||||
const subject = 'NVIDIA - BUY NOW';
|
const subject = 'NVIDIA - BUY NOW';
|
||||||
|
const [email, phone] = [Config.notifications.email, Config.notifications.phone];
|
||||||
enum carrierAddress {
|
|
||||||
sprint = 'messaging.sprintpcs.com',
|
|
||||||
verizon = 'vtext.com',
|
|
||||||
tmobile = 'tmomail.net',
|
|
||||||
att = 'txt.att.net',
|
|
||||||
google = 'msg.fi.google.com'
|
|
||||||
}
|
|
||||||
|
|
||||||
const transporter = nodemailer.createTransport({
|
const transporter = nodemailer.createTransport({
|
||||||
service: 'gmail',
|
service: 'gmail',
|
||||||
auth: {
|
auth: {
|
||||||
user: Config.notifications.email.username,
|
user: email.username,
|
||||||
pass: Config.notifications.email.password
|
pass: email.password
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -27,7 +20,7 @@ const mailOptions: Mail.Options = {
|
|||||||
subject
|
subject
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function sendSMS(text: string) {
|
export function sendSMS(text: string) {
|
||||||
mailOptions.text = text;
|
mailOptions.text = text;
|
||||||
|
|
||||||
transporter.sendMail(mailOptions, (error, info) => {
|
transporter.sendMail(mailOptions, (error, info) => {
|
||||||
@@ -41,9 +34,8 @@ export default function sendSMS(text: string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function generateAddress() {
|
function generateAddress() {
|
||||||
const carrier = Config.notifications.phone.carrier?.toLowerCase();
|
const carrier = phone.carrier.toLowerCase();
|
||||||
if (carrier && Object.keys(carrierAddress).includes(carrier)) {
|
if (carrier && phone.availableCarriers.has(carrier)) {
|
||||||
// @ts-expect-error
|
return [phone.number, phone.availableCarriers.get(carrier)].join('@');
|
||||||
return [Config.notifications.phone.number, carrierAddress[carrier]].join('@');
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
import playerLib = require('play-sound');
|
||||||
|
import {Config} from '../config';
|
||||||
|
import {Logger} from '../logger';
|
||||||
|
import * as fs from 'fs';
|
||||||
|
|
||||||
|
const notificationSound = './resources/sounds/' + Config.notifications.playSound;
|
||||||
|
const player = playerLib();
|
||||||
|
|
||||||
|
export function playSound() {
|
||||||
|
// Check if file exists
|
||||||
|
fs.access(notificationSound, fs.constants.F_OK, err => {
|
||||||
|
if (err) {
|
||||||
|
Logger.error(`error opening sound file: ${err.message}`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
player.play(notificationSound, (err: string) => {
|
||||||
|
Logger.info('✔ playing sound');
|
||||||
|
|
||||||
|
if (err) {
|
||||||
|
Logger.error(`error playing sound: ${err}`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
import {Config} from '../config';
|
||||||
|
import {Logger} from '../logger';
|
||||||
|
import {TelegramClient} from 'messaging-api-telegram';
|
||||||
|
|
||||||
|
const telegram = Config.notifications.telegram;
|
||||||
|
|
||||||
|
const client = new TelegramClient({
|
||||||
|
accessToken: telegram.accessToken
|
||||||
|
});
|
||||||
|
|
||||||
|
export function sendTelegramMessage(text: string) {
|
||||||
|
(async () => {
|
||||||
|
try {
|
||||||
|
await client.sendMessage(telegram.chatId, text);
|
||||||
|
Logger.info(`✔ telegram message sent to '${telegram.chatId}': ${text}`);
|
||||||
|
} catch (error) {
|
||||||
|
Logger.error(error);
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
}
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
import {Store} from './store';
|
|
||||||
|
|
||||||
export const BAndH: Store = {
|
|
||||||
cartUrl: '',
|
|
||||||
links: [
|
|
||||||
{
|
|
||||||
brand: 'gigabyte',
|
|
||||||
model: 'black',
|
|
||||||
url: 'https://www.bhphotovideo.com/c/product/1593333-REG/gigabyte_gv_n3080gaming_oc_10gd_geforce_rtx_3080_gaming.html?SID=s1600391647213ytuua52439',
|
|
||||||
oosLabels: ['notify when available']
|
|
||||||
}
|
|
||||||
],
|
|
||||||
name: 'bandh'
|
|
||||||
};
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
import {Store} from './store';
|
|
||||||
|
|
||||||
export const Evga: Store = {
|
|
||||||
cartUrl: '',
|
|
||||||
links: [
|
|
||||||
{
|
|
||||||
brand: 'evga',
|
|
||||||
model: 'ftw3, xc3 black, xc3 gaming, xc3 ultra gaming',
|
|
||||||
url: 'https://www.evga.com/products/productlist.aspx?type=0&family=GeForce+30+Series+Family&chipset=RTX+3080',
|
|
||||||
oosLabels: ['out of stock']
|
|
||||||
}
|
|
||||||
],
|
|
||||||
name: 'evga'
|
|
||||||
};
|
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
/**
|
||||||
|
* Checks if DOM has any out-of-stock related text.
|
||||||
|
*
|
||||||
|
* @param domText Complete DOM of website.
|
||||||
|
* @param oosLabels Out-of-stock labels.
|
||||||
|
*/
|
||||||
|
export function includesLabels(domText: string, oosLabels: string[]): boolean {
|
||||||
|
const domTextLowerCase = domText.toLowerCase();
|
||||||
|
return oosLabels.some(label => domTextLowerCase.includes(label));
|
||||||
|
}
|
||||||
+2
-30
@@ -1,30 +1,2 @@
|
|||||||
import {BestBuy} from './bestbuy';
|
export * from './lookup';
|
||||||
import {BAndH} from './bandh';
|
export * from './includes-labels';
|
||||||
import {Evga} from './evga';
|
|
||||||
import {NewEgg} from './newegg';
|
|
||||||
import {Nvidia} from './nvidia';
|
|
||||||
import {Amazon} from './amazon';
|
|
||||||
import {MicroCenter} from './microcenter';
|
|
||||||
import {Config} from '../config';
|
|
||||||
|
|
||||||
const masterList = new Map([
|
|
||||||
['amazon', Amazon],
|
|
||||||
['bestbuy', BestBuy],
|
|
||||||
['bandh', BAndH],
|
|
||||||
['evga', Evga],
|
|
||||||
['microcenter', MicroCenter],
|
|
||||||
['newegg', NewEgg],
|
|
||||||
['nvidia', Nvidia]
|
|
||||||
]);
|
|
||||||
|
|
||||||
const list = new Map();
|
|
||||||
|
|
||||||
const storeArray = Config.stores.split(',');
|
|
||||||
|
|
||||||
for (const name of storeArray) {
|
|
||||||
list.set(name, masterList.get(name));
|
|
||||||
}
|
|
||||||
|
|
||||||
export const Stores = Array.from(list.values());
|
|
||||||
|
|
||||||
export * from './store';
|
|
||||||
|
|||||||
@@ -0,0 +1,85 @@
|
|||||||
|
import puppeteer from 'puppeteer';
|
||||||
|
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';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the brand should be checked for stock
|
||||||
|
*
|
||||||
|
* @param brand The brand of the GPU
|
||||||
|
*/
|
||||||
|
function filterBrand(brand: string) {
|
||||||
|
if (Config.showOnlyBrands.length === 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Config.showOnlyBrands.includes(brand);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 browser Current browser in use.
|
||||||
|
* @param store Vendor of graphics cards.
|
||||||
|
*/
|
||||||
|
export async function lookup(browser: puppeteer.Browser, store: Store) {
|
||||||
|
/* eslint-disable no-await-in-loop */
|
||||||
|
for (const link of store.links) {
|
||||||
|
if (!filterBrand(link.brand)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const page = await browser.newPage();
|
||||||
|
page.setDefaultNavigationTimeout(Config.page.navigationTimeout);
|
||||||
|
await page.setUserAgent(Config.page.userAgent);
|
||||||
|
await page.setViewport({
|
||||||
|
height: Config.page.height,
|
||||||
|
width: Config.page.width
|
||||||
|
});
|
||||||
|
|
||||||
|
const graphicsCard = `${link.brand} ${link.model}`;
|
||||||
|
|
||||||
|
try {
|
||||||
|
await page.goto(link.url, {waitUntil: 'networkidle0'});
|
||||||
|
} catch {
|
||||||
|
Logger.error(`✖ [${store.name}] ${graphicsCard} skipping; timed out`);
|
||||||
|
await page.close();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const bodyHandle = await page.$('body');
|
||||||
|
const textContent = await page.evaluate(body => body.textContent, bodyHandle);
|
||||||
|
|
||||||
|
Logger.debug(textContent);
|
||||||
|
|
||||||
|
if (includesLabels(textContent, link.oosLabels)) {
|
||||||
|
Logger.info(`✖ [${store.name}] still out of stock: ${graphicsCard}`);
|
||||||
|
} else if (link.captchaLabels && includesLabels(textContent, link.captchaLabels)) {
|
||||||
|
Logger.warn(`✖ [${store.name}] CAPTCHA from: ${graphicsCard}`);
|
||||||
|
} else {
|
||||||
|
Logger.info(`🚀🚀🚀 [${store.name}] ${graphicsCard} IN STOCK 🚀🚀🚀`);
|
||||||
|
Logger.info(link.url);
|
||||||
|
|
||||||
|
if (Config.page.capture === 'true') {
|
||||||
|
Logger.debug('ℹ saving screenshot');
|
||||||
|
await page.screenshot({path: `success-${Date.now()}.png`});
|
||||||
|
}
|
||||||
|
|
||||||
|
const givenUrl = store.cartUrl ? store.cartUrl : link.url;
|
||||||
|
|
||||||
|
if (Config.openBrowser === 'true') {
|
||||||
|
await open(givenUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
sendNotification(givenUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
await page.close();
|
||||||
|
}
|
||||||
|
/* eslint-enable no-await-in-loop */
|
||||||
|
}
|
||||||
@@ -0,0 +1,84 @@
|
|||||||
|
import {Store} from './store';
|
||||||
|
|
||||||
|
export const AmazonCa: Store = {
|
||||||
|
links: [
|
||||||
|
{
|
||||||
|
brand: 'msi',
|
||||||
|
model: 'gaming trio',
|
||||||
|
url: 'https://www.amazon.ca/MSI-GeForce-RTX-3080-10G/dp/B08HR7SV3M?ref_=ast_sto_dp',
|
||||||
|
oosLabels: ['currently unavailable'],
|
||||||
|
captchaLabels: ['enter the characters you see below']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
brand: 'evga',
|
||||||
|
model: 'ftw3gaming',
|
||||||
|
url: 'https://www.amazon.ca/EVGA-GeForce-Technology-Backplate-10G-P5-3895-KR/dp/B08HR3DPGW?ref_=ast_sto_dp',
|
||||||
|
oosLabels: ['currently unavailable'],
|
||||||
|
captchaLabels: ['enter the characters you see below']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
brand: 'evga',
|
||||||
|
model: 'ftw3ultra',
|
||||||
|
url: 'https://www.amazon.ca/EVGA-GeForce-Technology-Backplate-10G-P5-3897-KR/dp/B08HR3Y5GQ?ref_=ast_sto_dp',
|
||||||
|
oosLabels: ['currently unavailable'],
|
||||||
|
captchaLabels: ['enter the characters you see below']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
brand: 'evga',
|
||||||
|
model: 'xc3ultra',
|
||||||
|
url: 'https://www.amazon.ca/EVGA-GeForce-Cooling-Backplate-10G-P5-3885-KR/dp/B08HR55YB5?ref_=ast_sto_dp',
|
||||||
|
oosLabels: ['currently unavailable'],
|
||||||
|
captchaLabels: ['enter the characters you see below']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
brand: 'evga',
|
||||||
|
model: 'xc3gaming',
|
||||||
|
url: 'https://www.amazon.ca/EVGA-GeForce-Cooling-Backplate-10G-P5-3883-KR/dp/B08HR4RJ3Q?ref_=ast_sto_dp',
|
||||||
|
oosLabels: ['currently unavailable'],
|
||||||
|
captchaLabels: ['enter the characters you see below']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
brand: 'evga',
|
||||||
|
model: 'xc3black',
|
||||||
|
url: 'https://www.amazon.ca/EVGA-GeForce-Gaming-Cooling-10G-P5-3881-KR/dp/B08HR6FMF3?ref_=ast_sto_dp',
|
||||||
|
oosLabels: ['currently unavailable'],
|
||||||
|
captchaLabels: ['enter the characters you see below']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
brand: 'gigabyte',
|
||||||
|
model: 'windforce',
|
||||||
|
url: 'https://www.amazon.ca/GIGABYTE-GeForce-Graphics-WINDFORCE-GV-N3080GAMING/dp/B08HJTH61J?ref_=ast_sto_dp',
|
||||||
|
oosLabels: ['currently unavailable'],
|
||||||
|
captchaLabels: ['enter the characters you see below']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
brand: 'gigabyte',
|
||||||
|
model: 'windforce eagle',
|
||||||
|
url: 'https://www.amazon.ca/GIGABYTE-GeForce-Graphics-WINDFORCE-GV-N3080EAGLE/dp/B08HJS2JLJ?ref_=ast_sto_dp',
|
||||||
|
oosLabels: ['currently unavailable'],
|
||||||
|
captchaLabels: ['enter the characters you see below']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
brand: 'asus',
|
||||||
|
model: 'tuf',
|
||||||
|
url: 'https://www.amazon.ca/Asus-90YV0FB0-M0AM00-TUF-RTX3080-10G-GAMING/dp/B08HHDP9DW?ref_=ast_sto_dp',
|
||||||
|
oosLabels: ['currently unavailable'],
|
||||||
|
captchaLabels: ['enter the characters you see below']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
brand: 'asus',
|
||||||
|
model: 'tufoc',
|
||||||
|
url: 'https://www.amazon.ca/Asus-90YV0FB1-M0AM00-TUF-RTX3080-O10G-GAMING/dp/B08HH5WF97?ref_=ast_sto_dp',
|
||||||
|
oosLabels: ['currently unavailable'],
|
||||||
|
captchaLabels: ['enter the characters you see below']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
brand: 'msi',
|
||||||
|
model: 'ventus',
|
||||||
|
url: 'https://www.amazon.ca/MSI-GeForce-RTX-3080-10G/dp/B08HR5SXPS?ref_=ast_sto_dp',
|
||||||
|
oosLabels: ['currently unavailable'],
|
||||||
|
captchaLabels: ['enter the characters you see below']
|
||||||
|
}
|
||||||
|
],
|
||||||
|
name: 'amazon-ca'
|
||||||
|
};
|
||||||
@@ -1,55 +1,62 @@
|
|||||||
import {Store} from './store';
|
import {Store} from './store';
|
||||||
|
|
||||||
export const Amazon: Store = {
|
export const Amazon: Store = {
|
||||||
cartUrl: '',
|
|
||||||
links: [
|
links: [
|
||||||
{
|
{
|
||||||
brand: 'pny',
|
brand: 'pny',
|
||||||
model: 'xlr8',
|
model: 'xlr8',
|
||||||
url: 'https://www.amazon.com/PNY-GeForce-Gaming-Epic-X-Graphics/dp/B08HBR7QBM?ref_=ast_sto_dp',
|
url: 'https://www.amazon.com/PNY-GeForce-Gaming-Epic-X-Graphics/dp/B08HBR7QBM?ref_=ast_sto_dp',
|
||||||
oosLabels: ['currently unavailable', 'Enter the characters you see below']
|
oosLabels: ['currently unavailable'],
|
||||||
|
captchaLabels: ['enter the characters you see below']
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
brand: 'msi',
|
brand: 'msi',
|
||||||
model: 'gaming trio',
|
model: 'gaming trio',
|
||||||
url: 'https://www.amazon.com/MSI-GeForce-RTX-3080-10G/dp/B08HR7SV3M?ref_=ast_sto_dp',
|
url: 'https://www.amazon.com/MSI-GeForce-RTX-3080-10G/dp/B08HR7SV3M?ref_=ast_sto_dp',
|
||||||
oosLabels: ['currently unavailable', 'Enter the characters you see below']
|
oosLabels: ['currently unavailable'],
|
||||||
|
captchaLabels: ['enter the characters you see below']
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
brand: 'evga',
|
brand: 'evga',
|
||||||
model: 'ftw3',
|
model: 'ftw3',
|
||||||
url: 'https://www.amazon.com/EVGA-10G-P5-3897-KR-GeForce-Technology-Backplate/dp/B08HR3Y5GQ?ref_=ast_sto_dp',
|
url: 'https://www.amazon.com/EVGA-10G-P5-3897-KR-GeForce-Technology-Backplate/dp/B08HR3Y5GQ?ref_=ast_sto_dp',
|
||||||
oosLabels: ['currently unavailable', 'Enter the characters you see below']
|
oosLabels: ['currently unavailable'],
|
||||||
|
captchaLabels: ['enter the characters you see below']
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
brand: 'evga',
|
brand: 'evga',
|
||||||
model: 'xc3',
|
model: 'xc3',
|
||||||
url: 'https://www.amazon.com/EVGA-10G-P5-3885-KR-GeForce-Cooling-Backplate/dp/B08HR55YB5?ref_=ast_sto_dp',
|
url: 'https://www.amazon.com/EVGA-10G-P5-3885-KR-GeForce-Cooling-Backplate/dp/B08HR55YB5?ref_=ast_sto_dp',
|
||||||
oosLabels: ['currently unavailable', 'Enter the characters you see below']
|
oosLabels: ['currently unavailable'],
|
||||||
|
captchaLabels: ['enter the characters you see below']
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
brand: 'gigabyte',
|
brand: 'gigabyte',
|
||||||
model: 'windforce',
|
model: 'windforce',
|
||||||
url: 'https://www.amazon.com/GIGABYTE-GeForce-Graphics-WINDFORCE-GV-N3080GAMING/dp/B08HJTH61J?ref_=ast_sto_dp',
|
url: 'https://www.amazon.com/GIGABYTE-GeForce-Graphics-WINDFORCE-GV-N3080GAMING/dp/B08HJTH61J?ref_=ast_sto_dp',
|
||||||
oosLabels: ['currently unavailable', 'Enter the characters you see below']
|
oosLabels: ['currently unavailable'],
|
||||||
|
captchaLabels: ['enter the characters you see below']
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
brand: 'gigabyte',
|
brand: 'gigabyte',
|
||||||
model: 'windforce eagle',
|
model: 'windforce eagle',
|
||||||
url: 'https://www.amazon.com/GIGABYTE-GeForce-Graphics-WINDFORCE-GV-N3080EAGLE/dp/B08HJS2JLJ?ref_=ast_sto_dp',
|
url: 'https://www.amazon.com/GIGABYTE-GeForce-Graphics-WINDFORCE-GV-N3080EAGLE/dp/B08HJS2JLJ?ref_=ast_sto_dp',
|
||||||
oosLabels: ['currently unavailable', 'Enter the characters you see below']
|
oosLabels: ['currently unavailable'],
|
||||||
|
captchaLabels: ['enter the characters you see below']
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
brand: 'asus',
|
brand: 'asus',
|
||||||
model: 'tuf',
|
model: 'tuf',
|
||||||
url: 'https://www.amazon.com/ASUS-Graphics-DisplayPort-Military-Grade-Certification/dp/B08HH5WF97?ref_=ast_sto_dp',
|
url: 'https://www.amazon.com/ASUS-Graphics-DisplayPort-Military-Grade-Certification/dp/B08HH5WF97?ref_=ast_sto_dp',
|
||||||
oosLabels: ['currently unavailable', 'Enter the characters you see below']
|
oosLabels: ['currently unavailable'],
|
||||||
|
captchaLabels: ['enter the characters you see below']
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
brand: 'msi',
|
brand: 'msi',
|
||||||
model: 'ventus',
|
model: 'ventus',
|
||||||
url: 'https://www.amazon.com/MSI-GeForce-RTX-3080-10G/dp/B08HR5SXPS?ref_=ast_sto_dp',
|
url: 'https://www.amazon.com/MSI-GeForce-RTX-3080-10G/dp/B08HR5SXPS?ref_=ast_sto_dp',
|
||||||
oosLabels: ['currently unavailable', 'Enter the characters you see below']
|
oosLabels: ['currently unavailable'],
|
||||||
|
captchaLabels: ['enter the characters you see below']
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
name: 'amazon'
|
name: 'amazon'
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
import {Store} from './store';
|
||||||
|
|
||||||
|
export const BAndH: Store = {
|
||||||
|
links: [
|
||||||
|
{
|
||||||
|
brand: 'gigabyte',
|
||||||
|
model: 'black',
|
||||||
|
url: 'https://www.bhphotovideo.com/c/product/1593333-REG/gigabyte_gv_n3080gaming_oc_10gd_geforce_rtx_3080_gaming.html?SID=s1600391647213ytuua52439',
|
||||||
|
oosLabels: ['notify when available']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
brand: 'asus',
|
||||||
|
model: 'tuf',
|
||||||
|
url: 'https://www.bhphotovideo.com/c/product/1593649-REG/asus_tuf_rtx3080_10g_gaming_tuf_gaming_geforce_rtx.html',
|
||||||
|
oosLabels: ['notify when available']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
brand: 'gigabyte',
|
||||||
|
model: 'gaming-oc',
|
||||||
|
url: 'https://www.bhphotovideo.com/c/product/1593333-REG/gigabyte_gv_n3080gaming_oc_10gd_geforce_rtx_3080_gaming.html',
|
||||||
|
oosLabels: ['notify when available']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
brand: 'zotac',
|
||||||
|
model: 'trinity',
|
||||||
|
url: 'https://www.bhphotovideo.com/c/product/1592969-REG/zotac_zt_a30800d_10p_gaming_geforce_rtx_3080.html',
|
||||||
|
oosLabels: ['notify when available']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
brand: 'asus',
|
||||||
|
model: 'tuf-oc',
|
||||||
|
url: 'https://www.bhphotovideo.com/c/product/1593650-REG/asus_tuf_rtx3080_o10g_gaming_tuf_gaming_geforce_rtx.html',
|
||||||
|
oosLabels: ['notify when available']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
brand: 'msi',
|
||||||
|
model: 'xtrio',
|
||||||
|
url: 'https://www.bhphotovideo.com/c/product/1593996-REG/msi_g3080gxt10_geforce_rtx_3080_gaming.html',
|
||||||
|
oosLabels: ['notify when available']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
brand: 'msi',
|
||||||
|
model: 'ventus',
|
||||||
|
url: 'https://www.bhphotovideo.com/c/product/1593997-REG/msi_g3080v3x10c_geforce_rtx_3080_ventus.html',
|
||||||
|
oosLabels: ['notify when available']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
brand: 'msi',
|
||||||
|
model: 'TRIO2',
|
||||||
|
url: 'https://www.bhphotovideo.com/c/product/1593645-REG/msi_geforce_rtx_3080_gaming.html',
|
||||||
|
oosLabels: ['notify when available']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
brand: 'msi',
|
||||||
|
model: 'ventus-oc',
|
||||||
|
url: 'https://www.bhphotovideo.com/c/product/1593646-REG/msi_geforce_rtx_3080_ventus.html',
|
||||||
|
oosLabels: ['notify when available']
|
||||||
|
}
|
||||||
|
|
||||||
|
],
|
||||||
|
name: 'bandh'
|
||||||
|
};
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
import {Store} from './store';
|
import {Store} from './store';
|
||||||
|
|
||||||
export const BestBuy: Store = {
|
export const BestBuy: Store = {
|
||||||
cartUrl: '',
|
|
||||||
links: [
|
links: [
|
||||||
{
|
{
|
||||||
brand: 'asus',
|
brand: 'asus',
|
||||||
@@ -33,7 +32,6 @@ export const BestBuy: Store = {
|
|||||||
url: 'https://www.bestbuy.com/site/gigabyte-geforce-rtx-3080-10g-gddr6x-pci-express-4-0-graphics-card-black/6430621.p?skuId=6430621',
|
url: 'https://www.bestbuy.com/site/gigabyte-geforce-rtx-3080-10g-gddr6x-pci-express-4-0-graphics-card-black/6430621.p?skuId=6430621',
|
||||||
oosLabels: ['sold out', 'coming soon']
|
oosLabels: ['sold out', 'coming soon']
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
brand: 'msi',
|
brand: 'msi',
|
||||||
model: 'ventus 3x',
|
model: 'ventus 3x',
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
import {Store} from './store';
|
||||||
|
|
||||||
|
export const Evga: Store = {
|
||||||
|
links: [
|
||||||
|
{
|
||||||
|
brand: 'evga',
|
||||||
|
model: 'xc3 black',
|
||||||
|
url: 'https://www.evga.com/products/product.aspx?pn=10G-P5-3881-KR',
|
||||||
|
oosLabels: ['out of stock']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
brand: 'evga',
|
||||||
|
model: 'ftw3',
|
||||||
|
url: 'https://www.evga.com/products/product.aspx?pn=10G-P5-3897-KR',
|
||||||
|
oosLabels: ['out of stock']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
brand: 'evga',
|
||||||
|
model: 'xc3 gaming',
|
||||||
|
url: 'https://www.evga.com/products/product.aspx?pn=10G-P5-3883-KR',
|
||||||
|
oosLabels: ['out of stock']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
brand: 'evga',
|
||||||
|
model: 'xc3 ultra gaming',
|
||||||
|
url: 'https://www.evga.com/products/product.aspx?pn=10G-P5-3885-KR',
|
||||||
|
oosLabels: ['out of stock']
|
||||||
|
}
|
||||||
|
],
|
||||||
|
name: 'evga'
|
||||||
|
};
|
||||||
|
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
import {BestBuy} from './bestbuy';
|
||||||
|
import {BAndH} from './bandh';
|
||||||
|
import {Evga} from './evga';
|
||||||
|
import {NewEgg} from './newegg';
|
||||||
|
import {Amazon} from './amazon';
|
||||||
|
import {MicroCenter} from './microcenter';
|
||||||
|
import {Config} from '../../config';
|
||||||
|
import {Nvidia} from './nvidia';
|
||||||
|
import {AmazonCa} from './amazon-ca';
|
||||||
|
|
||||||
|
const masterList = new Map([
|
||||||
|
[Amazon.name, Amazon],
|
||||||
|
[AmazonCa.name, AmazonCa],
|
||||||
|
[BestBuy.name, BestBuy],
|
||||||
|
[BAndH.name, BAndH],
|
||||||
|
[Evga.name, Evga],
|
||||||
|
[MicroCenter.name, MicroCenter],
|
||||||
|
[NewEgg.name, NewEgg],
|
||||||
|
[Nvidia.name, Nvidia]
|
||||||
|
]);
|
||||||
|
|
||||||
|
const list = new Map();
|
||||||
|
|
||||||
|
for (const name of Config.stores) {
|
||||||
|
list.set(name, masterList.get(name));
|
||||||
|
}
|
||||||
|
|
||||||
|
export const Stores = Array.from(list.values());
|
||||||
|
|
||||||
|
export * from './store';
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
import {Store} from './store';
|
import {Store} from './store';
|
||||||
|
|
||||||
export const MicroCenter: Store = {
|
export const MicroCenter: Store = {
|
||||||
cartUrl: '',
|
|
||||||
links: [
|
links: [
|
||||||
{
|
{
|
||||||
brand: 'evga',
|
brand: 'evga',
|
||||||
@@ -1,37 +1,41 @@
|
|||||||
import {Store} from './store';
|
import {Store} from './store';
|
||||||
|
|
||||||
export const NewEgg: Store = {
|
export const NewEgg: Store = {
|
||||||
cartUrl: '',
|
|
||||||
links: [
|
links: [
|
||||||
{
|
{
|
||||||
brand: 'asus',
|
brand: 'asus',
|
||||||
model: 'tuf',
|
model: 'tuf',
|
||||||
url: 'https://www.newegg.com/asus-geforce-rtx-3080-tuf-rtx3080-10g-gaming/p/N82E16814126453',
|
url: 'https://www.newegg.com/asus-geforce-rtx-3080-tuf-rtx3080-10g-gaming/p/N82E16814126453',
|
||||||
oosLabels: ['auto notify', 'out of stock']
|
oosLabels: ['auto notify', 'out of stock'],
|
||||||
|
captchaLabels: ['are you a human?']
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
brand: 'evga',
|
brand: 'evga',
|
||||||
model: 'black gaming',
|
model: 'black gaming',
|
||||||
url: 'https://www.newegg.com/evga-geforce-rtx-3080-10g-p5-3881-kr/p/N82E16814487522',
|
url: 'https://www.newegg.com/evga-geforce-rtx-3080-10g-p5-3881-kr/p/N82E16814487522',
|
||||||
oosLabels: ['auto notify', 'out of stock']
|
oosLabels: ['auto notify', 'out of stock'],
|
||||||
|
captchaLabels: ['are you a human?']
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
brand: 'evga',
|
brand: 'evga',
|
||||||
model: 'argb led icx3',
|
model: 'argb led icx3',
|
||||||
url: 'https://www.newegg.com/evga-geforce-rtx-3080-10g-p5-3883-kr/p/N82E16814487521',
|
url: 'https://www.newegg.com/evga-geforce-rtx-3080-10g-p5-3883-kr/p/N82E16814487521',
|
||||||
oosLabels: ['auto notify', 'out of stock']
|
oosLabels: ['auto notify', 'out of stock'],
|
||||||
|
captchaLabels: ['are you a human?']
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
brand: 'evga',
|
brand: 'evga',
|
||||||
model: 'xc3 ultra gaming',
|
model: 'xc3 ultra gaming',
|
||||||
url: 'https://www.newegg.com/evga-geforce-rtx-3080-10g-p5-3885-kr/p/N82E16814487520',
|
url: 'https://www.newegg.com/evga-geforce-rtx-3080-10g-p5-3885-kr/p/N82E16814487520',
|
||||||
oosLabels: ['auto notify', 'out of stock']
|
oosLabels: ['auto notify', 'out of stock'],
|
||||||
|
captchaLabels: ['are you a human?']
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
brand: 'msi',
|
brand: 'msi',
|
||||||
model: 'ventus',
|
model: 'ventus',
|
||||||
url: 'https://www.newegg.com/msi-geforce-rtx-3080-rtx-3080-ventus-3x-10g/p/N82E16814137600',
|
url: 'https://www.newegg.com/msi-geforce-rtx-3080-rtx-3080-ventus-3x-10g/p/N82E16814137600',
|
||||||
oosLabels: ['auto notify', 'out of stock']
|
oosLabels: ['auto notify', 'out of stock'],
|
||||||
|
captchaLabels: ['are you a human?']
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
name: 'newegg'
|
name: 'newegg'
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
import {Store} from './store';
|
import {Store} from './store';
|
||||||
|
|
||||||
export const Nvidia: Store = {
|
export const Nvidia: Store = {
|
||||||
cartUrl: '',
|
|
||||||
links: [
|
links: [
|
||||||
{
|
{
|
||||||
brand: 'nvidia',
|
brand: 'nvidia',
|
||||||
@@ -3,10 +3,11 @@ interface Link {
|
|||||||
model: string;
|
model: string;
|
||||||
url: string;
|
url: string;
|
||||||
oosLabels: string[];
|
oosLabels: string[];
|
||||||
|
captchaLabels?: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Store {
|
export interface Store {
|
||||||
cartUrl: string;
|
cartUrl?: string;
|
||||||
links: Link[];
|
links: Link[];
|
||||||
name: string;
|
name: string;
|
||||||
}
|
}
|
||||||
Vendored
+1
@@ -0,0 +1 @@
|
|||||||
|
declare module 'play-sound';
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
declare module 'pushover-notifications';
|
||||||
Reference in New Issue
Block a user