mirror of
https://github.com/opelly27/streetmerchant.git
synced 2026-05-20 05:17:35 +00:00
Compare commits
213 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 0da1621595 | |||
| 5b3e95acdf | |||
| 601742cf2c | |||
| e62eb72056 | |||
| 6cbe72118e | |||
| bb3509f99b | |||
| 430f3ed220 | |||
| e00dafe8ff | |||
| 137c0efdf0 | |||
| ffa2fdc700 | |||
| a9f452f5a7 | |||
| 1d2a33b1d7 | |||
| 493834b526 | |||
| 1918fda5a2 | |||
| 7038be2944 | |||
| 2fc584bdbd | |||
| 191bf8b2ff | |||
| 3085dbcc7f | |||
| 92bb2ef915 | |||
| 2ec5baa37c | |||
| 0fe3db9c99 | |||
| 317c987b08 | |||
| d7360f71ef | |||
| ab4f779573 | |||
| f04c669143 | |||
| 72d66ab127 | |||
| cc114afd15 | |||
| 7c16f85abc | |||
| 8dd10424b3 | |||
| 13edbf311e | |||
| e5b0d7983b | |||
| 3976b21907 | |||
| 87f1c0191d | |||
| 9e0f767a1d | |||
| 2353ee2ef8 | |||
| 6b9ecaeb3d | |||
| 1d6beb8235 | |||
| bde6a25063 | |||
| 273d058414 | |||
| 8548c07e3b | |||
| fa90afc42c | |||
| ceb049b317 | |||
| 2213c9e140 | |||
| 3b5b2b1182 | |||
| 12dd49c387 | |||
| 0318f33234 | |||
| c1dda4f987 | |||
| 61a23fe978 | |||
| 2f57632479 | |||
| 17555ece11 | |||
| 16adc3efda | |||
| 3c22a458b2 | |||
| 3c111bd3a8 | |||
| 0a633ddcfb | |||
| 0b53cb5e51 | |||
| 5cfb1a62d7 | |||
| 373d1a9738 | |||
| 83f82d66d9 | |||
| 5a3bb437aa | |||
| e8b96eb649 | |||
| a42418f814 | |||
| 699de573f6 | |||
| a2af30b703 | |||
| 2e5db7af04 | |||
| f9c4c25874 | |||
| 503d76f3c7 | |||
| 11ee0bf1a3 | |||
| ac37f87793 | |||
| 4847725d3a | |||
| f6db3489b8 | |||
| 9de2307c64 | |||
| 6203a1c18b | |||
| 699e77d960 | |||
| 1f095ce6ac | |||
| 675f13abb8 | |||
| 58416e1994 | |||
| 062201f092 | |||
| aca6523333 | |||
| 10a81dcbd5 | |||
| 68ff5bf836 | |||
| 4fefe22a90 | |||
| 2b6457e840 | |||
| 5ea7cc4ca4 | |||
| 542b92301a | |||
| 0c8771e3eb | |||
| c82b986aab | |||
| 92c5a02f30 | |||
| d575b8b96a | |||
| 8e7b83a55a | |||
| 3b815a9f24 | |||
| 0263bf8b12 | |||
| 199fac45ea | |||
| dc2fcf5ab4 | |||
| 1aaa102c06 | |||
| 32f114b235 | |||
| 053b22100b | |||
| b319bc1080 | |||
| e0735903b7 | |||
| 586029c92a | |||
| 1f89945c57 | |||
| f24f56549e | |||
| 207bc411ed | |||
| 1efde6b783 | |||
| 51d8b5290a | |||
| 2b0eab656d | |||
| cbc3b0b025 | |||
| 81daa7c559 | |||
| 97357c19b8 | |||
| f7ed86506b | |||
| 0cdf6657bf | |||
| 5c61333df0 | |||
| e5909c532d | |||
| a04a0f34af | |||
| 79b9bfe9a8 | |||
| 4192b7108e | |||
| e7592db963 | |||
| c857985a6d | |||
| e1cae3ed71 | |||
| 92696d4654 | |||
| ed970fc397 | |||
| eac05c610d | |||
| 6b9d8cd006 | |||
| b43f352707 | |||
| 812093455e | |||
| 7274ead169 | |||
| 86bef5a617 | |||
| 8adc07a03e | |||
| 160ae37d7b | |||
| 332b4a8246 | |||
| 85a07dc0dc | |||
| b9b6b55c29 | |||
| ee8cb12156 | |||
| 4157a5d746 | |||
| 4ea417cfc1 | |||
| 5109227e88 | |||
| ae6bc86bcb | |||
| 8098a31092 | |||
| f006a8595b | |||
| 8ef8109830 | |||
| eb9d082d17 | |||
| fd3351c028 | |||
| b7e5941a95 | |||
| 9d5272a0a5 | |||
| 628cab1b60 | |||
| b4d8733d18 | |||
| 0c810d62e2 | |||
| 4085136269 | |||
| fd294d2baa | |||
| 02f9ed5e53 | |||
| 177203a085 | |||
| eee6b8183a | |||
| 313d176848 | |||
| fddc0021d3 | |||
| 7a981e7456 | |||
| 760d57b113 | |||
| 7ce6904887 | |||
| 4b3018345b | |||
| e27ea63674 | |||
| b8d4f2f83e | |||
| d3bb507edc | |||
| 5a5d03b259 | |||
| 4db4f1f9d7 | |||
| f980a0bba0 | |||
| 9e7976df57 | |||
| 7148451b66 | |||
| fdd92f9d65 | |||
| 589fbbcd34 | |||
| f1d22d1684 | |||
| d84a409fc7 | |||
| 1a0753e739 | |||
| b110a5a429 | |||
| 54a9890130 | |||
| e55398e789 | |||
| 3b7487e97a | |||
| 7d8897cd9f | |||
| d2476ddb08 | |||
| 95c28a8d6d | |||
| fdcd787f91 | |||
| 772de900a1 | |||
| 5b8d774b7c | |||
| 5414b249a6 | |||
| f2f8d81498 | |||
| 3b90bbbe5d | |||
| 1bac1b928d | |||
| 3bde805f2c | |||
| 8828dd15cd | |||
| 07bd246e87 | |||
| 24786a443a | |||
| 03755d5eb1 | |||
| 0aa7ab596c | |||
| eda6c85fc0 | |||
| 696b75dfbd | |||
| f6760d3c65 | |||
| 9636572c7d | |||
| 1bead4712b | |||
| a2983eb54c | |||
| 349f55d360 | |||
| 38ee437cc9 | |||
| 8d8e5b587d | |||
| d9dea3d0f2 | |||
| b868d1a483 | |||
| 7ef9d935c6 | |||
| c7a716f981 | |||
| d25a643425 | |||
| d69189f12c | |||
| 2893f76e29 | |||
| e992cf4db8 | |||
| 4c63acc75a | |||
| 21aa700a86 | |||
| 8165033ea4 | |||
| 62172d224a | |||
| 9d3b7d38ab | |||
| f277172191 |
@@ -0,0 +1,6 @@
|
||||
.idea/
|
||||
.git/
|
||||
.vs/
|
||||
.vscode/
|
||||
build/
|
||||
node_modules/
|
||||
+1
-1
@@ -7,6 +7,6 @@ charset = utf-8
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
|
||||
[*.yml]
|
||||
[*.{yml, json.md}]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
|
||||
+69
-35
@@ -2,38 +2,72 @@
|
||||
# Read https://github.com/jef/nvidia-snatcher#customization for help on customizing this file
|
||||
#############################################################################################
|
||||
|
||||
BROWSER_TRUSTED=""
|
||||
DISCORD_NOTIFY_GROUP=""
|
||||
DISCORD_WEB_HOOK=""
|
||||
EMAIL_USERNAME=""
|
||||
EMAIL_PASSWORD=""
|
||||
HEADLESS=""
|
||||
IN_STOCK_WAIT_TIME=""
|
||||
LOG_LEVEL=""
|
||||
MICROCENTER_LOCATION=""
|
||||
OPEN_BROWSER=""
|
||||
PAGE_TIMEOUT=""
|
||||
PHONE_NUMBER=""
|
||||
PHONE_CARRIER=""
|
||||
PLAY_SOUND=""
|
||||
PUSHBULLET=""
|
||||
PUSHOVER_TOKEN=""
|
||||
PUSHOVER_USER=""
|
||||
PAGE_SLEEP_MIN=""
|
||||
PAGE_SLEEP_MAX=""
|
||||
SHOW_ONLY_BRANDS=""
|
||||
SHOW_ONLY_MODELS=""
|
||||
SHOW_ONLY_SERIES=""
|
||||
SLACK_CHANNEL=""
|
||||
SLACK_TOKEN=""
|
||||
STORES=""
|
||||
COUNTRY=""
|
||||
SCREENSHOT="false"
|
||||
TELEGRAM_ACCESS_TOKEN=""
|
||||
TELEGRAM_CHAT_ID=""
|
||||
TWITTER_CONSUMER_KEY=""
|
||||
TWITTER_CONSUMER_SECRET=""
|
||||
TWITTER_ACCESS_TOKEN_KEY=""
|
||||
TWITTER_ACCESS_TOKEN_SECRET=""
|
||||
TWITTER_TWEET_TAGS=""
|
||||
USER_AGENT=""
|
||||
BROWSER_TRUSTED=
|
||||
COUNTRY=
|
||||
DESKTOP_NOTIFICATIONS=
|
||||
DISCORD_NOTIFY_GROUP=
|
||||
DISCORD_WEB_HOOK=
|
||||
EMAIL_PASSWORD=
|
||||
EMAIL_TO=
|
||||
EMAIL_USERNAME=
|
||||
HEADLESS=
|
||||
IN_STOCK_WAIT_TIME=
|
||||
LOG_LEVEL=
|
||||
LOW_BANDWIDTH=
|
||||
MAX_PRICE_SERIES_3070=
|
||||
MAX_PRICE_SERIES_3080=
|
||||
MAX_PRICE_SERIES_3090=
|
||||
MICROCENTER_LOCATION=
|
||||
MQTT_BROKER_ADDRESS=
|
||||
MQTT_BROKER_PORT=
|
||||
MQTT_CLIENT_ID=
|
||||
MQTT_PASSWORD=
|
||||
MQTT_QOS=
|
||||
MQTT_TOPIC=
|
||||
MQTT_USERNAME=
|
||||
NVIDIA_ADD_TO_CART_ATTEMPTS=
|
||||
NVIDIA_SESSION_TTL=
|
||||
OPEN_BROWSER=
|
||||
PAGE_BACKOFF_MIN=
|
||||
PAGE_BACKOFF_MAX=
|
||||
PAGE_SLEEP_MIN=
|
||||
PAGE_SLEEP_MAX=
|
||||
PAGE_TIMEOUT=
|
||||
PAGERDUTY_INTEGRATION_KEY=
|
||||
PAGERDUTY_SEVERITY=
|
||||
PHONE_CARRIER=
|
||||
PHONE_NUMBER=
|
||||
PLAY_SOUND=
|
||||
PROXY_ADDRESS=
|
||||
PROXY_PORT=
|
||||
PUSHBULLET=
|
||||
PUSHOVER_TOKEN=
|
||||
PUSHOVER_USER=
|
||||
PUSHOVER_PRIORITY=
|
||||
SCREENSHOT=
|
||||
SHOW_ONLY_BRANDS=
|
||||
SHOW_ONLY_MODELS=
|
||||
SHOW_ONLY_SERIES=
|
||||
SLACK_CHANNEL=
|
||||
SLACK_TOKEN=
|
||||
SMTP_ADDRESS=
|
||||
SMTP_PORT=
|
||||
STORES=
|
||||
TELEGRAM_ACCESS_TOKEN=
|
||||
TELEGRAM_CHAT_ID=
|
||||
TWILIO_ACCOUNT_SID=
|
||||
TWILIO_AUTH_TOKEN=
|
||||
TWILIO_FROM_NUMBER=
|
||||
TWILIO_TO_NUMBER=
|
||||
TWITCH_ACCESS_TOKEN=
|
||||
TWITCH_CHANNEL=
|
||||
TWITCH_CLIENT_ID=
|
||||
TWITCH_CLIENT_SECRET=
|
||||
TWITCH_REFRESH_TOKEN=
|
||||
TWITTER_ACCESS_TOKEN_KEY=
|
||||
TWITTER_ACCESS_TOKEN_SECRET=
|
||||
TWITTER_CONSUMER_KEY=
|
||||
TWITTER_CONSUMER_SECRET=
|
||||
TWITTER_TWEET_TAGS=
|
||||
USER_AGENT=
|
||||
WEB_PORT=
|
||||
|
||||
@@ -1,3 +1,2 @@
|
||||
github: jef
|
||||
patreon: hijef
|
||||
custom: ["https://www.paypal.me/jxf"]
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
name: 🐛 Bug report
|
||||
about: Report a bug for this project
|
||||
title: ''
|
||||
labels: 'bug'
|
||||
labels: 'type: bug'
|
||||
assignees: jef
|
||||
|
||||
---
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
name: 🚀 Feature request
|
||||
about: Suggest a feature for this project
|
||||
title: ''
|
||||
labels: 'enhancement'
|
||||
labels: 'type: enhancement'
|
||||
assignees: jef
|
||||
|
||||
---
|
||||
|
||||
@@ -7,9 +7,6 @@
|
||||
<!-- Fixes #(issue) -->
|
||||
<!-- Please also include relevant motivation and context. -->
|
||||
|
||||
<!-- Feel free to include your Discord tag here and we'll consider making you a ringer! -->
|
||||
<!-- Continuous improvements may also grant you contributor access. -->
|
||||
|
||||
### Testing
|
||||
|
||||
<!-- Please describe the tests that you ran to verify your changes. -->
|
||||
|
||||
@@ -3,14 +3,38 @@ on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
paths-ignore:
|
||||
- '**.md'
|
||||
jobs:
|
||||
cd:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: GoogleCloudPlatform/release-please-action@v2.4.1
|
||||
- uses: GoogleCloudPlatform/release-please-action@v2.5.7
|
||||
id: release
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
release-type: node
|
||||
release-type: simple
|
||||
package-name: nvidia-snatcher
|
||||
- name: login into github package registry
|
||||
run: echo ${{ secrets.CR_PAT }} | docker login ghcr.io -u $GITHUB_ACTOR --password-stdin
|
||||
- name: build nightly docker image
|
||||
if: ${{ ! steps.release.outputs.release_created }}
|
||||
run: |
|
||||
docker build \
|
||||
-t "ghcr.io/${GITHUB_REPOSITORY}:${GITHUB_SHA:0:7}" \
|
||||
-t "ghcr.io/${GITHUB_REPOSITORY}:nightly" .
|
||||
- name: publish nightly
|
||||
if: ${{ ! steps.release.outputs.release_created }}
|
||||
run: docker push "ghcr.io/${GITHUB_REPOSITORY}"
|
||||
- name: build latest docker image
|
||||
if: ${{ steps.release.outputs.release_created }}
|
||||
run: |
|
||||
docker build \
|
||||
-t "ghcr.io/${GITHUB_REPOSITORY}:${TAG_NAME}" \
|
||||
-t "ghcr.io/${GITHUB_REPOSITORY}:latest" .
|
||||
env:
|
||||
TAG_NAME: ${{ steps.release.outputs.tag_name }}
|
||||
- name: publish latest
|
||||
if: ${{ steps.release.outputs.release_created }}
|
||||
run: docker push "ghcr.io/${GITHUB_REPOSITORY}"
|
||||
|
||||
@@ -3,12 +3,14 @@ on:
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
paths-ignore:
|
||||
- '**.md'
|
||||
jobs:
|
||||
build-lint:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@master
|
||||
- uses: actions/setup-node@v2.1.1
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-node@v2.1.2
|
||||
with:
|
||||
node-version: 14
|
||||
- uses: actions/cache@v2
|
||||
@@ -23,3 +25,16 @@ jobs:
|
||||
npm ci
|
||||
npm run build
|
||||
npm run lint
|
||||
build-docker:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: dorny/paths-filter@v2.5.1
|
||||
id: filter
|
||||
with:
|
||||
filters: |
|
||||
docker:
|
||||
- 'Dockerfile'
|
||||
- name: Build image
|
||||
if: steps.filter.outputs.docker == 'true'
|
||||
run: docker build .
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
name: pr-lint
|
||||
on:
|
||||
pull_request_target:
|
||||
types:
|
||||
- opened
|
||||
- edited
|
||||
- reopened
|
||||
- synchronize
|
||||
jobs:
|
||||
main:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: amannn/action-semantic-pull-request@v2.1.0
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
+7
-1
@@ -4,9 +4,15 @@
|
||||
build/
|
||||
node_modules/
|
||||
|
||||
.env
|
||||
.env*
|
||||
.*env
|
||||
!.env-example
|
||||
success-*.png
|
||||
|
||||
*.wav
|
||||
*.mp3
|
||||
*.flac
|
||||
*.exe
|
||||
desktop.ini
|
||||
|
||||
twitch.json
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
14.11.0
|
||||
15.0.1
|
||||
|
||||
+115
@@ -1,5 +1,120 @@
|
||||
# Changelog
|
||||
|
||||
## [1.7.0](https://www.github.com/jef/nvidia-snatcher/compare/v1.6.0...v1.7.0) (2020-11-03)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* add deprecation notices ([601742c](https://www.github.com/jef/nvidia-snatcher/commit/601742cf2c0b5ccf0131e4c4e904ad4037d80a8d))
|
||||
* newegg realtime api ([#664](https://www.github.com/jef/nvidia-snatcher/issues/664)) ([5b3e95a](https://www.github.com/jef/nvidia-snatcher/commit/5b3e95acdf2f427a6098f15b9fbe65e88354a678))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **banner:** add version to docker image ([#649](https://www.github.com/jef/nvidia-snatcher/issues/649)) ([1d2a33b](https://www.github.com/jef/nvidia-snatcher/commit/1d2a33b1d765fece9d1c9bf7d548818d1f0c8d92))
|
||||
|
||||
## [1.6.0](https://www.github.com/jef/nvidia-snatcher/compare/v1.5.0...v1.6.0) (2020-10-29)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* add series to Discord webhook ([#618](https://www.github.com/jef/nvidia-snatcher/issues/618)) ([273d058](https://www.github.com/jef/nvidia-snatcher/commit/273d05841451ed896f1d505bcd24f2230a143d3a))
|
||||
* **api:** add rudimentary web control panel ([#183](https://www.github.com/jef/nvidia-snatcher/issues/183)) ([373d1a9](https://www.github.com/jef/nvidia-snatcher/commit/373d1a973865b14b5753517aa70eabf85b136d94))
|
||||
* **store:** add founders editions to notebooksbilliger.de ([#593](https://www.github.com/jef/nvidia-snatcher/issues/593)) ([2e5db7a](https://www.github.com/jef/nvidia-snatcher/commit/2e5db7af04e6ce79660477d8deb6636ec2e7845e))
|
||||
* **store:** add max price containers to multiple stores ([#579](https://www.github.com/jef/nvidia-snatcher/issues/579)) ([f9c4c25](https://www.github.com/jef/nvidia-snatcher/commit/f9c4c258748ffd3735f1e7385bde15b6112a1ca7))
|
||||
* **store:** add new cards to german web shops ([#597](https://www.github.com/jef/nvidia-snatcher/issues/597)) ([699de57](https://www.github.com/jef/nvidia-snatcher/commit/699de573f6579b59ba2c65cc2bf4dd6ccba3c863))
|
||||
* **store:** Add PCComponentes and Amazon-ES Stores. ([#558](https://www.github.com/jef/nvidia-snatcher/issues/558)) ([062201f](https://www.github.com/jef/nvidia-snatcher/commit/062201f092c7a271202f27e7297b8eb9d7269c02))
|
||||
* **store:** support for azerty ([#557](https://www.github.com/jef/nvidia-snatcher/issues/557)) ([58416e1](https://www.github.com/jef/nvidia-snatcher/commit/58416e1994006cc2e4055937c675e0f9191f6339))
|
||||
* **store:** support for coolmod ([#605](https://www.github.com/jef/nvidia-snatcher/issues/605)) ([c1dda4f](https://www.github.com/jef/nvidia-snatcher/commit/c1dda4f9871988fad43d79f3bfe65f7c7860b9f7))
|
||||
* add `meta` to logger ([#437](https://www.github.com/jef/nvidia-snatcher/issues/437)) ([ae6bc86](https://www.github.com/jef/nvidia-snatcher/commit/ae6bc86bcb75c154a2a68adda324f34f18281700))
|
||||
* add alternate.nl support ([#552](https://www.github.com/jef/nvidia-snatcher/issues/552)) ([aca6523](https://www.github.com/jef/nvidia-snatcher/commit/aca65233339ddbbcc1dbd06f9011d6d44c6650cf))
|
||||
* add asus-de store and asus 3080 tuf/oc to amazon-de ([#436](https://www.github.com/jef/nvidia-snatcher/issues/436)) ([b4d8733](https://www.github.com/jef/nvidia-snatcher/commit/b4d8733d1823e2fa5d3a1b80d2d4218bfa737cd7))
|
||||
* add caseking and proshop-de store ([#521](https://www.github.com/jef/nvidia-snatcher/issues/521)) ([1aaa102](https://www.github.com/jef/nvidia-snatcher/commit/1aaa102c06281b60da593d04ced01f8b20a37a3b))
|
||||
* add coolblue store ([#482](https://www.github.com/jef/nvidia-snatcher/issues/482)) ([5c61333](https://www.github.com/jef/nvidia-snatcher/commit/5c61333df00c0c30f04e4aced01a498c5816ad58))
|
||||
* add german stores ([#462](https://www.github.com/jef/nvidia-snatcher/issues/462)) ([85a07dc](https://www.github.com/jef/nvidia-snatcher/commit/85a07dc0dc6a8dfe2aba1d4ea3e4cde6ec083086))
|
||||
* add incognito mode ([#534](https://www.github.com/jef/nvidia-snatcher/issues/534)) ([2b6457e](https://www.github.com/jef/nvidia-snatcher/commit/2b6457e8409658b843204fa0aeafb00d48f9e53e))
|
||||
* add link series to error message for better context ([#265](https://www.github.com/jef/nvidia-snatcher/issues/265)) ([332b4a8](https://www.github.com/jef/nvidia-snatcher/commit/332b4a8246320e458729c0b58c310d290df12530))
|
||||
* Add PagerDuty Integration ([#565](https://www.github.com/jef/nvidia-snatcher/issues/565)) ([11ee0bf](https://www.github.com/jef/nvidia-snatcher/commit/11ee0bf1a3e2d0d550d2731f9de9e178c382ea1f))
|
||||
* add proshop-dk ([#524](https://www.github.com/jef/nvidia-snatcher/issues/524)) ([dc2fcf5](https://www.github.com/jef/nvidia-snatcher/commit/dc2fcf5ab4dba8be459bd5aa6a41e3e097205d45))
|
||||
* add support for multiple browser user agents ([#547](https://www.github.com/jef/nvidia-snatcher/issues/547)) ([10a81dc](https://www.github.com/jef/nvidia-snatcher/commit/10a81dcbd54557652537cb641cbbd727d39e34e5))
|
||||
* add uk stores ([#455](https://www.github.com/jef/nvidia-snatcher/issues/455)) ([b9b6b55](https://www.github.com/jef/nvidia-snatcher/commit/b9b6b55c29d11f48b683816e5b8c1cab127ed5fd))
|
||||
* allow filtering per model by a specific series ([#595](https://www.github.com/jef/nvidia-snatcher/issues/595)) ([a42418f](https://www.github.com/jef/nvidia-snatcher/commit/a42418f814dcd91354c136288d4c6a24e03a168d))
|
||||
* optional per store min and max page sleep time ([#576](https://www.github.com/jef/nvidia-snatcher/issues/576)) ([503d76f](https://www.github.com/jef/nvidia-snatcher/commit/503d76f3c7d01368fc978af4ab02924d3d036ac0))
|
||||
* **notification:** add `to` field for email ([#327](https://www.github.com/jef/nvidia-snatcher/issues/327)) ([8828dd1](https://www.github.com/jef/nvidia-snatcher/commit/8828dd15cd08959cd434bd256e8eac474dd17c49))
|
||||
* **store:** add ttl for `scan` ([#555](https://www.github.com/jef/nvidia-snatcher/issues/555)) ([4847725](https://www.github.com/jef/nvidia-snatcher/commit/4847725d3a54d2f4dd0c349ff0ad80eb4bc4e9e3))
|
||||
* add rog strix oc to amazon-de ([#471](https://www.github.com/jef/nvidia-snatcher/issues/471)) ([e5909c5](https://www.github.com/jef/nvidia-snatcher/commit/e5909c532da1c8b731e9835bffd8f31b76550d4d))
|
||||
* add support for specifying smtp server ([#458](https://www.github.com/jef/nvidia-snatcher/issues/458)) ([160ae37](https://www.github.com/jef/nvidia-snatcher/commit/160ae37d7bee4f0323cb939566d586f1300aece6))
|
||||
* allow multiple microcenter locations ([#487](https://www.github.com/jef/nvidia-snatcher/issues/487)) ([2b0eab6](https://www.github.com/jef/nvidia-snatcher/commit/2b0eab656d81314ce7d05064662ec138407550c3))
|
||||
* clear cookies and cache ([#515](https://www.github.com/jef/nvidia-snatcher/issues/515)) ([1f89945](https://www.github.com/jef/nvidia-snatcher/commit/1f89945c5746befb2131381a358efdf8ac530e0c)), closes [#417](https://www.github.com/jef/nvidia-snatcher/issues/417)
|
||||
* max price per series ([#451](https://www.github.com/jef/nvidia-snatcher/issues/451)) ([8adc07a](https://www.github.com/jef/nvidia-snatcher/commit/8adc07a03e411dd536bebfdc7270db4bbf8ddb34))
|
||||
* mqtt alerts ([#538](https://www.github.com/jef/nvidia-snatcher/issues/538)) ([68ff5bf](https://www.github.com/jef/nvidia-snatcher/commit/68ff5bf836c63c8e14d02c06777e02e64a6a0f38))
|
||||
* twitch chat notification, multiple telegram chat ids and german web shop overhaul ([#528](https://www.github.com/jef/nvidia-snatcher/issues/528)) ([675f13a](https://www.github.com/jef/nvidia-snatcher/commit/675f13abb892d1158c92c41e3d57049313a5e0b8))
|
||||
* **docker:** add docker and publish images to ghcr ([#411](https://www.github.com/jef/nvidia-snatcher/issues/411)) ([c857985](https://www.github.com/jef/nvidia-snatcher/commit/c857985a6d3736287976caf5b173f19046306465))
|
||||
* **notification:** add at&t prepaid carrier ([#425](https://www.github.com/jef/nvidia-snatcher/issues/425)) ([eb9d082](https://www.github.com/jef/nvidia-snatcher/commit/eb9d082d178a42e35789ba822cfae7b35c0413c1))
|
||||
* **notification:** add pushover priority setting ([#186](https://www.github.com/jef/nvidia-snatcher/issues/186)) ([f277172](https://www.github.com/jef/nvidia-snatcher/commit/f2771721914a20619833df8ccb2ac44298687b4d))
|
||||
* **notification:** add Twillio notification provider ([#344](https://www.github.com/jef/nvidia-snatcher/issues/344)) ([f2f8d81](https://www.github.com/jef/nvidia-snatcher/commit/f2f8d81498d1acfb9359f4a690962042ec20d166))
|
||||
* **store:** add `pny` ([#295](https://www.github.com/jef/nvidia-snatcher/issues/295)) ([f6760d3](https://www.github.com/jef/nvidia-snatcher/commit/f6760d3c65d60eae9e4b1e0fdba34e814f446a4c))
|
||||
* **store:** add 3090s to amazon-ca ([#274](https://www.github.com/jef/nvidia-snatcher/issues/274)) ([e992cf4](https://www.github.com/jef/nvidia-snatcher/commit/e992cf4db85f045fc8d03c9b93286fb72bad1061))
|
||||
* **store:** add additional cards to all stores ([#286](https://www.github.com/jef/nvidia-snatcher/issues/286)) ([d25a643](https://www.github.com/jef/nvidia-snatcher/commit/d25a643425020fa3f7cd48972360ede17501afeb))
|
||||
* **store:** add amazon cards and `cartUrl`s ([#284](https://www.github.com/jef/nvidia-snatcher/issues/284)) ([d69189f](https://www.github.com/jef/nvidia-snatcher/commit/d69189f12c893fb6d88b198d802ff8e36a69bc88))
|
||||
* **store:** add asus strix oc to asus store ([#385](https://www.github.com/jef/nvidia-snatcher/issues/385)) ([e55398e](https://www.github.com/jef/nvidia-snatcher/commit/e55398e789d52def6e15d1e5e10f56cdf5ea5bea))
|
||||
* **store:** add evga 3090 to newegg canada ([#396](https://www.github.com/jef/nvidia-snatcher/issues/396)) ([313d176](https://www.github.com/jef/nvidia-snatcher/commit/313d176848a25f183334db8926ac0ec445a2c481))
|
||||
* **store:** add ftw3 ultra to microcenter ([#448](https://www.github.com/jef/nvidia-snatcher/issues/448)) ([5109227](https://www.github.com/jef/nvidia-snatcher/commit/5109227e8899f57b828b157309a76c397c872559))
|
||||
* **store:** add gamestop ([#390](https://www.github.com/jef/nvidia-snatcher/issues/390)) ([7148451](https://www.github.com/jef/nvidia-snatcher/commit/7148451b66e97f4f7dcdcc86ce06ba8712211bd5))
|
||||
* **store:** add models to bestbuy ([#421](https://www.github.com/jef/nvidia-snatcher/issues/421)) ([4085136](https://www.github.com/jef/nvidia-snatcher/commit/4085136269b00f6bc5c8414836de8310dfec4166))
|
||||
* **store:** add rog-strix-3080 to newegg-ca ([#489](https://www.github.com/jef/nvidia-snatcher/issues/489)) ([207bc41](https://www.github.com/jef/nvidia-snatcher/commit/207bc411ed240cd9150e018b21e735ba08a4d134))
|
||||
* add `norway` to `nvidia-api` ([#304](https://www.github.com/jef/nvidia-snatcher/issues/304)) ([eda6c85](https://www.github.com/jef/nvidia-snatcher/commit/eda6c85fc03a70c5933308e96c572a480bb6c8a0))
|
||||
* configurable status code behaviours ([#340](https://www.github.com/jef/nvidia-snatcher/issues/340)) ([3b7487e](https://www.github.com/jef/nvidia-snatcher/commit/3b7487e97ac9d93344403f50153f2de6243b1f0d))
|
||||
* enhanced lookup behaviour ([#270](https://www.github.com/jef/nvidia-snatcher/issues/270)) ([b868d1a](https://www.github.com/jef/nvidia-snatcher/commit/b868d1a4833a8ec5ac1c79481530d75cd0c4b01e))
|
||||
* in stock wait time per link now ([c7a716f](https://www.github.com/jef/nvidia-snatcher/commit/c7a716f981976a76afe61a4d985bd6fe4343595b))
|
||||
* low bandwidth mode ([#294](https://www.github.com/jef/nvidia-snatcher/issues/294)) ([0aa7ab5](https://www.github.com/jef/nvidia-snatcher/commit/0aa7ab596c907ce72c188eb4b1acdee088307437))
|
||||
* max price filtering ([#383](https://www.github.com/jef/nvidia-snatcher/issues/383)) ([fd294d2](https://www.github.com/jef/nvidia-snatcher/commit/fd294d2baa06a1c0a68852497889a0412dea492e))
|
||||
* **store:** adds aorus master 3080 to newegg ([#402](https://www.github.com/jef/nvidia-snatcher/issues/402)) ([fddc002](https://www.github.com/jef/nvidia-snatcher/commit/fddc0021d36e4d0a9dacccc546da8260684f0eeb))
|
||||
* retry logic for nvidia session token and adding to cart ([#347](https://www.github.com/jef/nvidia-snatcher/issues/347)) ([1bac1b9](https://www.github.com/jef/nvidia-snatcher/commit/1bac1b928d401a819698848f3367edf54836b26f))
|
||||
* support for proxy server ([#352](https://www.github.com/jef/nvidia-snatcher/issues/352)) ([fdcd787](https://www.github.com/jef/nvidia-snatcher/commit/fdcd787f91f26229db23e2291e8922b947007902))
|
||||
* **store:** nvidia debug card for "product details" page ([#337](https://www.github.com/jef/nvidia-snatcher/issues/337)) ([5b8d774](https://www.github.com/jef/nvidia-snatcher/commit/5b8d774b7c7d31d6ba6fc43be3ea7b16a87d2e49))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* `amazon.{nl,de}` test urls ([#345](https://www.github.com/jef/nvidia-snatcher/issues/345)) ([589fbbc](https://www.github.com/jef/nvidia-snatcher/commit/589fbbcd34393ceb2bd7c0a8ac391c54e14a21be))
|
||||
* `envOrNumber` behavior ([#364](https://www.github.com/jef/nvidia-snatcher/issues/364)) ([7d8897c](https://www.github.com/jef/nvidia-snatcher/commit/7d8897cd9fb9ae0db796fd85da3f2b9d1a9f73af))
|
||||
* `nvidia-api` ([#314](https://www.github.com/jef/nvidia-snatcher/issues/314)) ([8d8e5b5](https://www.github.com/jef/nvidia-snatcher/commit/8d8e5b587d2279a95d3e7837a99bea8c5990a477))
|
||||
* add `amazon-nl`, captcha `amazon-de`, add ftw3 `newegg` ([#293](https://www.github.com/jef/nvidia-snatcher/issues/293)) ([a2983eb](https://www.github.com/jef/nvidia-snatcher/commit/a2983eb54c419ba3a56abf80d316ea136a05e0fa))
|
||||
* add status code `429` to bandh `backOffStatusCodes` ([#404](https://www.github.com/jef/nvidia-snatcher/issues/404)) ([7a981e7](https://www.github.com/jef/nvidia-snatcher/commit/7a981e745673f2b12d48d7eed71fc34a6e4ba5b2))
|
||||
* add support for stores label text to have uppercase letters ([#526](https://www.github.com/jef/nvidia-snatcher/issues/526)) ([5ea7cc4](https://www.github.com/jef/nvidia-snatcher/commit/5ea7cc4ca45c506d2b98d4b643b44ca4ede1d7a9))
|
||||
* asus store links ([#573](https://www.github.com/jef/nvidia-snatcher/issues/573)) ([f6db348](https://www.github.com/jef/nvidia-snatcher/commit/f6db3489b8b8a737dfc425880703928d5bc8916d))
|
||||
* bestbuy label container selector precision ([#491](https://www.github.com/jef/nvidia-snatcher/issues/491)) ([cbc3b0b](https://www.github.com/jef/nvidia-snatcher/commit/cbc3b0b025469e9882ba8267f18f909c08c6c931))
|
||||
* corrected norway locales ([#356](https://www.github.com/jef/nvidia-snatcher/issues/356)) ([d2476dd](https://www.github.com/jef/nvidia-snatcher/commit/d2476ddb08606545b32b9676e2d299d57ec5cb6a))
|
||||
* cyclical dependencies ([ed970fc](https://www.github.com/jef/nvidia-snatcher/commit/ed970fc397210eb6ff684c7e82c79eb685a5d0d9)), closes [#468](https://www.github.com/jef/nvidia-snatcher/issues/468)
|
||||
* denver `microcenter` name ([#296](https://www.github.com/jef/nvidia-snatcher/issues/296)) ([349f55d](https://www.github.com/jef/nvidia-snatcher/commit/349f55d3603517b5741fce6ac42b29141816ea79))
|
||||
* dutch stores components ([#513](https://www.github.com/jef/nvidia-snatcher/issues/513)) ([586029c](https://www.github.com/jef/nvidia-snatcher/commit/586029c92aa19bdddcc85b7a837bb7a16bb1d28d))
|
||||
* gamestop false positives ([#395](https://www.github.com/jef/nvidia-snatcher/issues/395)) ([d3bb507](https://www.github.com/jef/nvidia-snatcher/commit/d3bb507edca112124115ed88fb03cf14440d95ef))
|
||||
* in stock wait time ([#325](https://www.github.com/jef/nvidia-snatcher/issues/325)) ([07bd246](https://www.github.com/jef/nvidia-snatcher/commit/07bd246e876cd27df1b5019af5ee8613bb5368f0)), closes [#315](https://www.github.com/jef/nvidia-snatcher/issues/315)
|
||||
* max price getter updated to match .env ([#516](https://www.github.com/jef/nvidia-snatcher/issues/516)) ([32f114b](https://www.github.com/jef/nvidia-snatcher/commit/32f114b23527ee247c84c081a2cd0264de3b4847)), closes [#514](https://www.github.com/jef/nvidia-snatcher/issues/514) [#510](https://www.github.com/jef/nvidia-snatcher/issues/510)
|
||||
* page sleep ([#586](https://www.github.com/jef/nvidia-snatcher/issues/586)) ([a2af30b](https://www.github.com/jef/nvidia-snatcher/commit/a2af30b70334cdbbfa51140d5de23a2d6b8429c8)), closes [#594](https://www.github.com/jef/nvidia-snatcher/issues/594) [#576](https://www.github.com/jef/nvidia-snatcher/issues/576)
|
||||
* remove 3090 drid for DK/FI regions ([#361](https://www.github.com/jef/nvidia-snatcher/issues/361)) ([f1d22d1](https://www.github.com/jef/nvidia-snatcher/commit/f1d22d1684c8e70f09acd9978e6ea802d7224c8b))
|
||||
* trim strings from comma-separated values ([#472](https://www.github.com/jef/nvidia-snatcher/issues/472)) ([f7ed865](https://www.github.com/jef/nvidia-snatcher/commit/f7ed86506b4e76d5bc20787068be83a44ec485b5))
|
||||
* typo in maxPrice for 3090 ([#496](https://www.github.com/jef/nvidia-snatcher/issues/496)) ([e073590](https://www.github.com/jef/nvidia-snatcher/commit/e0735903b7b4b0d542dbbd76b9a860b1eca24e96))
|
||||
* update gigabyte model `vision oc` ([#550](https://www.github.com/jef/nvidia-snatcher/issues/550)) ([4fefe22](https://www.github.com/jef/nvidia-snatcher/commit/4fefe22a907094fa39af5b4f2e3f8f3fe6897115))
|
||||
* update new additions with web panel and sleep operations ([#606](https://www.github.com/jef/nvidia-snatcher/issues/606)) ([61a23fe](https://www.github.com/jef/nvidia-snatcher/commit/61a23fe9782223dc067dbc8251c3b09adbca0a43))
|
||||
* update pushbullet import to match package ([#637](https://www.github.com/jef/nvidia-snatcher/issues/637)) ([d7360f7](https://www.github.com/jef/nvidia-snatcher/commit/d7360f71ef1a076713246ad2832ca58e7163e492))
|
||||
* **env:** default `LOG_LEVEL` ([9636572](https://www.github.com/jef/nvidia-snatcher/commit/9636572c7de36f7ac6800ba31ac60fcd7bd2fd03))
|
||||
* **notification:** discord false triggers ([#346](https://www.github.com/jef/nvidia-snatcher/issues/346)) ([3b90bbb](https://www.github.com/jef/nvidia-snatcher/commit/3b90bbbe5d751003a39823e9113eaee8cbfcf1a2))
|
||||
* **notification:** sms subject output ([#298](https://www.github.com/jef/nvidia-snatcher/issues/298)) ([03755d5](https://www.github.com/jef/nvidia-snatcher/commit/03755d5eb117ac14797e0180c74f50b401e50cb5))
|
||||
* **notifications:** twilio client creation ([#349](https://www.github.com/jef/nvidia-snatcher/issues/349)) ([5414b24](https://www.github.com/jef/nvidia-snatcher/commit/5414b249a6f938615cfad02ca22c171a5f86e127))
|
||||
* **store:** gamestop `label.inStock` ([9e7976d](https://www.github.com/jef/nvidia-snatcher/commit/9e7976df5778a953c4fb6ca7553773655c1f4127))
|
||||
* **store:** pccomponents model normalization ([#563](https://www.github.com/jef/nvidia-snatcher/issues/563)) ([699e77d](https://www.github.com/jef/nvidia-snatcher/commit/699e77d960b17dcb50378975a1913b0badeabfcc))
|
||||
* updating amazon test model card to an in stock product ([#492](https://www.github.com/jef/nvidia-snatcher/issues/492)) ([81daa7c](https://www.github.com/jef/nvidia-snatcher/commit/81daa7c5596ab23bd9e6aac29fa63ee09e136827))
|
||||
* **config:** `MAX_PRICE` quotations ([#426](https://www.github.com/jef/nvidia-snatcher/issues/426)) ([b7e5941](https://www.github.com/jef/nvidia-snatcher/commit/b7e5941a9598a09afabbb79c5636b768345009a3))
|
||||
* **store:** container names on `nvidia` ([#333](https://www.github.com/jef/nvidia-snatcher/issues/333)) ([772de90](https://www.github.com/jef/nvidia-snatcher/commit/772de900a1386e9635d139e152fe86366404ded4))
|
||||
* **store:** update `inStock` and `maxPrice` for newegg, newegg-ca ([#433](https://www.github.com/jef/nvidia-snatcher/issues/433)) ([628cab1](https://www.github.com/jef/nvidia-snatcher/commit/628cab1b605e4363c8dd5ad43476292ecb12db74)), closes [#400](https://www.github.com/jef/nvidia-snatcher/issues/400)
|
||||
|
||||
|
||||
### Reverts
|
||||
|
||||
* reduce false-positive during ci/cd ([79b9bfe](https://www.github.com/jef/nvidia-snatcher/commit/79b9bfe9a83858117f7a58b4b8b1a1569d80c442))
|
||||
|
||||
## [1.5.0](https://www.github.com/jef/nvidia-snatcher/compare/v1.4.0...v1.5.0) (2020-09-24)
|
||||
|
||||
|
||||
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
# Build the source code
|
||||
FROM node:15.0.1-alpine3.12 AS builder
|
||||
|
||||
ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true
|
||||
|
||||
WORKDIR /build
|
||||
|
||||
COPY package.json package.json
|
||||
COPY package-lock.json package-lock.json
|
||||
COPY tsconfig.json tsconfig.json
|
||||
RUN npm ci
|
||||
|
||||
COPY src/ src/
|
||||
RUN npm run build
|
||||
RUN npm prune --production
|
||||
|
||||
FROM node:15.0.1-alpine3.12
|
||||
|
||||
RUN apk add --no-cache chromium
|
||||
|
||||
ENV PUPPETEER_EXECUTABLE_PATH=/usr/bin/chromium-browser \
|
||||
DOCKER=true
|
||||
|
||||
RUN addgroup -S appuser && adduser -S -g appuser appuser \
|
||||
&& mkdir -p /home/appuser/Downloads /app \
|
||||
&& chown -R appuser:appuser /home/appuser \
|
||||
&& chown -R appuser:appuser /app
|
||||
|
||||
USER appuser
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
COPY --from=builder /build/node_modules/ node_modules/
|
||||
COPY --from=builder /build/build/ build/
|
||||
COPY version.txt version.txt
|
||||
|
||||
CMD [ "node", "./build/index.js" ]
|
||||
@@ -1,6 +1,7 @@
|
||||
# nvidia-snatcher [](https://github.com/jef/nvidia-snatcher/actions?query=workflow%3Aci) [](https://discord.gg/Cyc7nrz)
|
||||
# nvidia-snatcher [](https://github.com/jef/nvidia-snatcher/actions?query=workflow%3Aci) [](https://kiwiirc.com/nextclient/irc.kiwiirc.com/?nick=kiwi_?#streetmerchant)
|
||||
|
||||
[FAQ](#FAQ) | [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)
|
||||
|
||||

|
||||
|
||||
@@ -8,133 +9,288 @@ The purpose of this bot is to get an Nvidia card. It tries multiple things to do
|
||||
|
||||
- Currently, `nvidia-snatcher` is not capable of purchasing a card for you
|
||||
- Scrapes multiple websites for patterns of being stocked
|
||||
- API requests are a work in progress (very soon)
|
||||
- API requests are a work in progress (very soon)
|
||||
- Opens browser when stock is available
|
||||
- Sends an email to you when stock is avaiable (must have Gmail)
|
||||
- Ability to send notifications when stock is available
|
||||
|
||||
<details>
|
||||
<summary>What you may see if you're lucky</summary>
|
||||
|
||||
```sh
|
||||
2020-09-18T07:06:28.535Z info :: ✖ [nvidia] nvidia founders edition is still out of stock
|
||||
2020-09-18T07:06:31.241Z info :: ✖ [nvidia] nvidia founders edition is still out of stock
|
||||
2020-09-18T07:06:34.212Z info :: ✖ [bestbuy] nvidia founder edition is still out of stock
|
||||
2020-09-18T07:06:39.878Z info :: ✖ [bandh] gigabyte black is still out of stock
|
||||
2020-09-18T07:06:43.236Z info :: ✖ [bestbuy] gigabyte black is still out of stock
|
||||
2020-09-18T07:06:43.318Z info :: ↗ trying stores again
|
||||
2020-09-18T07:06:43.318Z info :: 🚀🚀🚀 [nvidia] nvidia founders edition IN STOCK 🚀🚀🚀
|
||||
2020-09-18T07:06:43.318Z info :: https://store.nvidia.com/store/nvidia/en_US/buy/productID.5438481700/clearCart.yes/nextPage.QuickBuyCartPage
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
> :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 :)
|
||||
|
||||
| | **Adorama** | **Amazon** | **Amazon (CA)** | **ASUS** | **B&H** | **Best Buy** | **Best Buy (CA)** | **EVGA** | **Micro Center** | **Newegg** | **Newegg (CA)** | **Nvidia** | **Office Depot** | **Zotac** |
|
||||
|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|
|
||||
| **3070**| | | | | | | | | | | | | | |
|
||||
| **3080** | `✔` | `✔` | `✔` | `✔` | `✔` | `✔` | `✔` | `✔` | `✔` | `✔` | `✔` | `✔` | `✔` | `✔` |
|
||||
| **3090** | | | | | | `✔` | `✔` | | | `✔` | `✔` | `✔` | | |
|
||||
|
||||
## Installation and prerequisites
|
||||
## Installation overview
|
||||
|
||||
Linux, macOS, and Windows are all capable operating systems.
|
||||
|
||||
You do not need any computer skills, smarts, or anything of that nature. You are very capable as you have made it this far. Some basic understanding how a terminal, git, and or Node.js is a bonus, but that does not limit you to getting `nvidia-snatcher` running!
|
||||
You do not need any computer skills, smarts, or anything of that nature. You are very capable as you have made it this
|
||||
far. Some basic understanding how a terminal, git, and or Node.js is a bonus, but that does not limit you to
|
||||
getting `nvidia-snatcher` running!
|
||||
|
||||
### Quick overview
|
||||
### Installation: native
|
||||
|
||||
- [Node.js 14](https://nodejs.org/en/)
|
||||
- [Node.js 15](https://nodejs.org/en/)
|
||||
- [git](https://git-scm.com/)
|
||||
- Clone this project `git clone https://github.com/jef/nvidia-snatcher.git`
|
||||
- Run `npm install`
|
||||
- Copy `.env.example` to a new file `.env` and edit the `.env` file to your liking using your [favorite text editor](https://code.visualstudio.com/)
|
||||
- More on this in [customization](#Customization)
|
||||
- Copy `.env-example` to a new file `.env` and edit the `.env` file to your liking using
|
||||
your [favorite text editor](https://code.visualstudio.com/)
|
||||
- More on this in [customization](#Customization)
|
||||
- Run `npm run start` to start
|
||||
|
||||
At any point you want the program to stop, use <kbd>Ctrl</kbd> + <kbd>C</kbd>.
|
||||
|
||||
> :point_right: Please visit the [wiki](https://github.com/jef/nvidia-snatcher/wiki) if you need more help with installation.
|
||||
|
||||
### Customization
|
||||
### Installation: Docker
|
||||
|
||||
To customize `nvidia-snatcher`, make a copy of `.env-example` as `.env` and make any changes to your liking. _All environment variables are **optional**._
|
||||
Available via GitHub Container Registry.
|
||||
|
||||
Here is a list of variables that you can use to customize your newly copied `.env` file:
|
||||
| Tag | Note |
|
||||
|:---:|---|
|
||||
| `latest` | Latest stable build |
|
||||
| `nightly` | Latest HEAD build, could be unstable |
|
||||
|
||||
| **Environment variable** | **Description** | **Notes** |
|
||||
Use `docker run --cap-add=SYS_ADMIN -it --rm --env-file ./.env ghcr.io/jef/nvidia-snatcher:nightly` to run.
|
||||
|
||||
### Developer notes
|
||||
|
||||
The command `npm run start:dev` can be used instead of `npm run start` to automatically restart the project when
|
||||
filesystem changes are detected in the `src/` folder or `.env` file.
|
||||
|
||||
## Customization
|
||||
|
||||
To customize `nvidia-snatcher`, make a copy of `.env-example` as `.env` and make any changes to your liking. _All
|
||||
environment variables are **optional**._
|
||||
|
||||
<details>
|
||||
<summary>Expand to see all available options</summary>
|
||||
|
||||
### Application
|
||||
|
||||
| Environment variable | Description | Notes |
|
||||
|:---:|---|---|
|
||||
| `BROWSER_TRUSTED` | Skip Chromium Sandbox | Useful for containerized environments, default: `false` |
|
||||
| `DESKTOP_NOTIFICATIONS` | Display desktop notifications using [node-notifier](https://www.npmjs.com/package/node-notifier) | Default: `false` |
|
||||
| `DISCORD_NOTIFY_GROUP` | Discord group you would like to notify | Can be comma separated, use role ID, E.g.: `<@2834729847239842>` |
|
||||
| `DISCORD_WEB_HOOK` | Discord Web Hook URL | Can be comma separated, use whole webhook URL |
|
||||
| `EMAIL_USERNAME` | Gmail address | E.g.: `jensen.robbed.us@gmail.com` |
|
||||
| `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` |
|
||||
| `INCOGNITO` | Puppeteer to run incognito or not | Debugging related, default: `false` |
|
||||
| `IN_STOCK_WAIT_TIME` | Time to wait between requests to the same link if it has that card in stock | In seconds, default: `0` |
|
||||
| `LOG_LEVEL` | [Logging levels](https://github.com/winstonjs/winston#logging-levels) | Debugging related, default: `info` |
|
||||
| `MICROCENTER_LOCATION` | Specific MicroCenter location to search | Default : `web` |
|
||||
| `LOW_BANDWIDTH` | Blocks images/fonts to reduce traffic | Disables ad blocker, default: `false` |
|
||||
| `OPEN_BROWSER` | Toggle for whether or not the browser should open when item is found | Default: `true` |
|
||||
| `PAGE_BACKOFF_MIN` | Minimum backoff time between retrying requests for the same store when a forbidden response is received | Default: `10000` |
|
||||
| `PAGE_BACKOFF_MAX` | Maximum backoff time between retrying requests for the same store when a forbidden response is received | Default: `3600000` |
|
||||
| `PAGE_SLEEP_MIN` | Minimum sleep time between queries of the same product page | In milliseconds, default: `5000` |
|
||||
| `PAGE_SLEEP_MAX` | Maximum sleep time between queries of the same product page | In milliseconds, default: `10000` |
|
||||
| `PAGE_TIMEOUT` | Navigation Timeout in milliseconds | `0` for infinite, default: `30000` |
|
||||
| `PHONE_NUMBER` | 10 digit phone number | E.g.: `1234567890`, email configuration required |
|
||||
| `PHONE_CARRIER` | [Supported carriers](#supported-carriers) for SMS | Email configuration required |
|
||||
| `PLAY_SOUND` | Play this sound notification if a card is found | Relative path accepted, valid formats: wav, mp3, flac, E.g.: `path/to/notification.wav`, [free sounds available](https://notificationsounds.com/) |
|
||||
| `PUSHBULLET` | PushBullet API key | Generate at https://www.pushbullet.com/#settings/account | |
|
||||
| `PUSHOVER_TOKEN` | Pushover access token | Generate at https://pushover.net/apps/build | |
|
||||
| `PUSHOVER_USER` | Pushover username | |
|
||||
| `PAGE_SLEEP_MIN` | Minimum sleep time between queries of the same store | In milliseconds, default: `5000` |
|
||||
| `PAGE_SLEEP_MAX` | Maximum sleep time between queries of the same store | In milliseconds, default: `10000` |
|
||||
| `PROXY_ADDRESS` | IP Address or fqdn of proxy server |
|
||||
| `PROXY_PORT` | TCP Port number on which the proxy is listening for connections | Default: `80` |
|
||||
| `SCREENSHOT` | Capture screenshot of page if a card is found | Default: `true` |
|
||||
| `SHOW_ONLY_BRANDS` | Filter to show specified brands | Comma separated, e.g.: `evga,zotac` |
|
||||
| `SHOW_ONLY_MODELS` | Filter to show specified models | Comma separated, e.g.: `founders edition,rog strix` |
|
||||
| `SHOW_ONLY_SERIES` | Filter to show specified series | Comma separated, e.g.: `3080` |
|
||||
| `SLACK_CHANNEL` | Slack channel for posting | E.g.: `update`, no need for `#` |
|
||||
| `SLACK_TOKEN` | Slack API token | |
|
||||
| `STORES` | [Supported stores](#supported-stores) you want to be scraped | Comma separated, default: `nvidia` |
|
||||
| `COUNTRY` | [Supported country](#supported-countries) you want to be scraped | Currently only used by Nvidia, default: `usa` |
|
||||
| `SCREENSHOT` | Capture screenshot of page if a card is found | Default: `true` |
|
||||
| `TELEGRAM_ACCESS_TOKEN` | Telegram access token | |
|
||||
| `TELEGRAM_CHAT_ID` | Telegram chat ID | |
|
||||
| `USER_AGENT` | Custom User-Agent header for HTTP requests | Default: `Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36` |
|
||||
| `TWITTER_CONSUMER_KEY` | Twitter Consumer Key | Generate all Twitter keys at: https://developer.twitter.com/ |
|
||||
| `TWITTER_CONSUMER_SECRET` | Twitter Consumer Secret | |
|
||||
| `TWITTER_ACCESS_TOKEN_KEY` | Twitter Token Key | |
|
||||
| `TWITTER_ACCESS_TOKEN_SECRET` | Twitter Token Secret | |
|
||||
| `TWITTER_TWEET_TAGS` | Optional list of hashtags to append to the tweet message | E.g.: `#nvidia #nvidiastock` |
|
||||
|
||||
> :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.
|
||||
| `USER_AGENT` | Custom User-Agents headers for HTTP requests | Newline separated, e.g.: `USER_AGENT_STRING1 \n USER_AGENT_STRING2` | | Default: `Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36` |
|
||||
| `WEB_PORT` | Starts a webserver to be able to control the bot while it is running; optional | Default: disabled |
|
||||
|
||||
> :point_right: You can find your computer's user agent by [searching google for "my user agent"](http://google.com/search?q=my+user+agent)
|
||||
|
||||
> :point_right: You can test your notification configuration by running `npm run test:notification`.
|
||||
> :point_right: Data usage is [known to be high](https://github.com/jef/nvidia-snatcher/issues?q=is%3Aissue+sort%3Aupdated-desc+bandwidth). This is expected as the program scrapes many websites in parallel 24/7. To help reduce this, use `LOW_BANDWIDTH="true"`. We are looking into other solutions as well, but is low priority.
|
||||
|
||||
#### Supported stores
|
||||
### Filters
|
||||
|
||||
| **Stores** | **Environment variable** |
|
||||
| Environment variable | Description | Notes |
|
||||
|:---:|---|---|
|
||||
| `COUNTRY` | [Supported country](#supported-countries) you want to be scraped | Currently only used by Nvidia, default: `usa` |
|
||||
| `MAX_PRICE_SERIES_3070` | Maximum price allowed for a match, applies 3070 series cards (does not apply to these sites: Nvidia, Asus, EVGA) | Default: leave empty for no limit, otherwise enter a price (enter whole dollar amounts only, avoid use of: dollar symbols, commas, and periods.) e.g.: `1234` - Cards above `1234` will be skipped. |
|
||||
| `MAX_PRICE_SERIES_3080` | Maximum price allowed for a match, applies 3080 series cards (does not apply to these sites: Nvidia, Asus, EVGA) | Default: leave empty for no limit, otherwise enter a price (enter whole dollar amounts only, avoid use of: dollar symbols, commas, and periods.) e.g.: `1234` - Cards above `1234` will be skipped. |
|
||||
| `MAX_PRICE_SERIES_3090` | Maximum price allowed for a match, applies 3090 series cards (does not apply to these sites: Nvidia, Asus, EVGA) | Default: leave empty for no limit, otherwise enter a price (enter whole dollar amounts only, avoid use of: dollar symbols, commas, and periods.) e.g.: `1234` - Cards above `1234` will be skipped. |
|
||||
| `MICROCENTER_LOCATION` | Specific MicroCenter location(s) to search | Comma separated, e.g.: `marietta,duluth`, default: `web` |
|
||||
| `NVIDIA_ADD_TO_CART_ATTEMPTS` | The maximum number of times the `nvidia-api` add to cart feature will be attempted before failing | Default: `10` |
|
||||
| `NVIDIA_SESSION_TTL` | The time in milliseconds to keep the cart active while using `nvidia-api` | Default: `60000` |
|
||||
| `SHOW_ONLY_BRANDS` | Filter to show specified brands | Comma separated, e.g.: `evga,zotac` |
|
||||
| `SHOW_ONLY_MODELS` | Filter to show specified models | Both supported formats are comma separated <br/><br/>1. Standard E.g.: `founders edition,rog strix` <br/><br/> 2. Advanced E.g: `MODEL:SERIES`, E.g: `founders edition:3090,rog strix` |
|
||||
| `SHOW_ONLY_SERIES` | Filter to show specified series | Comma separated, e.g.: `3080` |
|
||||
| `STORES` | [Supported stores](#supported-stores) you want to be scraped | Both supported formats are comma separated <br/><br/>1. Standard E.g.: `"nvidia"` <br/><br/> 2. Advanced E.g: `STORE:PAGE_SLEEP_MIN:PAGE_SLEEP_MAX`, E.g: `nvidia:10000:30000` <br/><br/>Default: `nvidia` |
|
||||
|
||||
<details>
|
||||
<summary>Supported stores</summary>
|
||||
|
||||
> :point_right: Used with the `STORES` variable.
|
||||
|
||||
| Stores | Environment variable |
|
||||
|:---:|:---:|
|
||||
| Adorama | `adorama`|
|
||||
| Alternate (DE) | `alternate`|
|
||||
| Alternate (NL) | `alternate-nl`|
|
||||
| Amazon | `amazon`|
|
||||
| Amazon (CA) | `amazon-ca`|
|
||||
| Amazon (DE) | `amazon-de`|
|
||||
| Amazon (ES) | `amazon-es`|
|
||||
| Amazon (NL) | `amazon-nl`|
|
||||
| Amazon (UK) | `amazon-uk`|
|
||||
| Aria PC (UK) | `aria`|
|
||||
| ASUS | `asus` |
|
||||
| ASUS (DE) | `asus-de` |
|
||||
| Azerty (NL) | `azerty`|
|
||||
| B&H | `bandh`|
|
||||
| Best Buy | `bestbuy`|
|
||||
| Best Buy (CA) | `bestbuy-ca`|
|
||||
| Box (UK) | `box`|
|
||||
| Caseking (DE) | `caseking`|
|
||||
| CCL (UK) | `ccl`|
|
||||
| Computeruniverse (DE) | `computeruniverse` |
|
||||
| Coolblue (NL) | `coolblue`|
|
||||
| Coolmod (ES) | `coolmod`|
|
||||
| Currys (UK) | `currys`|
|
||||
| Cyberport (DE) | `cyberport` |
|
||||
| eBuyer (UK) | `ebuyer`|
|
||||
| EVGA | `evga`|
|
||||
| EVGA (EU) | `evga-eu`|
|
||||
| Gamestop | `gamestop`|
|
||||
| Mediamarkt (DE) | `mediamarkt`|
|
||||
| Micro Center | `microcenter`|
|
||||
| Mindfactory (DE) | `mindfactory` |
|
||||
| Newegg | `newegg`|
|
||||
| Newegg (CA) | `newegg-ca`|
|
||||
| Notebooksbilliger (DE) |`notebooksbilliger`|
|
||||
| Novatech (UK) | `novatech`|
|
||||
| Nvidia | `nvidia`|
|
||||
| Nvidia (API) | `nvidia-api`|
|
||||
| Office Depot | `officedepot`|
|
||||
| Overclockers (UK) | `overclockers`|
|
||||
| PCComponentes (ES) | `pccomponentes`|
|
||||
| PNY | `pny`|
|
||||
| Proshop (DE) | `proshop-de`|
|
||||
| Proshop (DK) | `proshop-dk`|
|
||||
| Saturn (DE) | `saturn`|
|
||||
| Scan (UK) | `scan`|
|
||||
| Very (UK) | `very`|
|
||||
| Zotac | `zotac`|
|
||||
|
||||
<details>
|
||||
<summary>Micro Center stores</summary>
|
||||
|
||||
> :point_right: Used with the `MICROCENTER_LOCATION` variable.
|
||||
|
||||
> :point_right: Before using `web`, please review [this issue comment](https://github.com/jef/nvidia-snatcher/issues/442#issuecomment-703297393).
|
||||
|
||||
| Store name |
|
||||
|:---:|
|
||||
| `brooklyn` |
|
||||
| `brentwood` |
|
||||
| `cambridge` |
|
||||
| `chicago` |
|
||||
| `columbus` |
|
||||
| `dallas` |
|
||||
| `denver` |
|
||||
| `duluth` |
|
||||
| `fairfax` |
|
||||
| `flushing` |
|
||||
| `houston` |
|
||||
| `madison-heights` |
|
||||
| `marietta` |
|
||||
| `mayfield-heights` |
|
||||
| `north-jersey` |
|
||||
| `overland-park` |
|
||||
| `parkville` |
|
||||
| `rockville` |
|
||||
| `sharonville` |
|
||||
| `st-davids` |
|
||||
| `st-louis-park` |
|
||||
| `tustin` |
|
||||
| `westbury` |
|
||||
| `westmont` |
|
||||
| `yonkers` |
|
||||
|
||||
</details>
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>Supported brands and models</summary>
|
||||
|
||||
> :point_right: Used with the `SHOW_ONLY_BRANDS` and `SHOW_ONLY_MODELS` variables.
|
||||
|
||||
| Brand | Model |
|
||||
|:---:|---|
|
||||
| `asus` | `dual`, `dual oc`, `rog strix`, `rog strix oc`, `tuf`, `tuf oc` |
|
||||
| `evga` | `ftw3`, `ftw3 ultra`, `xc3`, `xc3 black`, `xc3 ultra` |
|
||||
| `gainward` | `phantom gs`, `phoenix`, `phoenix gs`, `phoenix gs oc` |
|
||||
| `gigabyte` | `aorus master`, `aorus xtreme`, `eagle`, `eagle oc`, `gaming`, `gaming oc`, `turbo`, `vision`, `vision oc` |
|
||||
| `inno3d` | `gaming x3`, `ichill x3`, `ichill x4`, `twin x2 oc` |
|
||||
| `kfa2` | `sg oc` |
|
||||
| `msi` | `gaming x trio`, `ventus 2x oc`, `ventus 3x`, `ventus 3x oc` |
|
||||
| `nvidia` | `founders edition` |
|
||||
| `palit` | `gamerock oc`, `gaming pro`, `gaming pro oc` |
|
||||
| `pny` | `dual fan`, `xlr8`, `xlr8 rgb` |
|
||||
| `zotac` | `amp holo`, `amp extreme holo`, `trinity`, `trinity oc`, `twin edge`, `twin edge oc` |
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>Supported countries (used with nvidia and nvidia-api)</summary>
|
||||
|
||||
> :point_right: Used with the `COUNTRY` variable.
|
||||
|
||||
| Country | 3080 FE | 3090 FE | Test Card | Notes |
|
||||
|:---:|:---:|:---:|:---:|:---:|
|
||||
| austria | `✔` | `✔` | `✔` | |
|
||||
| belgium | `✔` | `✔` | `✔` | |
|
||||
| canada | `✔` | `✔` | `✔` | |
|
||||
| czechia | `✔` | `✔` | `✔` | |
|
||||
| denmark | `✔` | | `✔` | Missing RTX 3090 |
|
||||
| finland | `✔` | | `✔` | Missing RTX 3090 |
|
||||
| france | `✔` | `✔` | `✔` | |
|
||||
| germany | `✔` | `✔` | `✔` | |
|
||||
| great_britain | `✔` | `✔` | `✔` | |
|
||||
| ireland | `✔` | `✔` | `✔` | |
|
||||
| italy | `✔` | `✔` | `✔` | |
|
||||
| luxembourg | `✔` | `✔` | `✔` | |
|
||||
| netherlands | `✔` | `✔` | `✔` | |
|
||||
| norway | `✔` | `✔` | `✔` | |
|
||||
| poland | `✔` | `✔` | `✔` | |
|
||||
| portugal | `✔` | | | RTX 3080 only |
|
||||
| spain | `✔` | `✔` | `✔` | |
|
||||
| sweden | `✔` | `✔` | `✔` | |
|
||||
| usa | `✔` | `✔` | `✔` | |
|
||||
|
||||
</details>
|
||||
|
||||
### Notifications
|
||||
|
||||
> :point_right: You can test your notification configuration by running `npm run test:notification`.
|
||||
|
||||
<details>
|
||||
<summary>Desktop</summary>
|
||||
|
||||
| Environment variable | Description | Notes |
|
||||
|:---:|---|---|
|
||||
| `DESKTOP_NOTIFICATIONS` | Display desktop notifications using [node-notifier](https://www.npmjs.com/package/node-notifier) | Default: `false` |
|
||||
| `PLAY_SOUND` | Play this sound notification if a card is found | Relative path accepted, valid formats: wav, mp3, flac, E.g.: `path/to/notification.wav`, [free sounds available](https://notificationsounds.com/) |
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>Discord</summary>
|
||||
|
||||
| Environment variable | Description | Notes |
|
||||
|:---:|---|---|
|
||||
| `DISCORD_NOTIFY_GROUP` | Discord group you would like to notify | Can be comma separated, use role ID, E.g.: `<@2834729847239842>` |
|
||||
| `DISCORD_WEB_HOOK` | Discord Web Hook URL | Can be comma separated, use whole webhook URL |
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>Email and SMS</summary>
|
||||
|
||||
| Environment variable | Description | Notes |
|
||||
|:---:|---|---|
|
||||
| `EMAIL_PASSWORD` | Gmail password | See below if you have MFA |
|
||||
| `EMAIL_TO` | Destination Email | Defaults to username if not set. Can be comma separated |
|
||||
| `EMAIL_USERNAME` | Gmail address | E.g.: `jensen.robbed.us@gmail.com` |
|
||||
| `PHONE_CARRIER` | [Supported carriers](#supported-carriers) for SMS | Email configuration required |
|
||||
| `PHONE_NUMBER` | 10 digit phone number | E.g.: `1234567890`, email configuration required |
|
||||
| `SMTP_ADDRESS` | IP Address or fqdn of smtp server |
|
||||
| `SMTP_PORT` | TCP Port number on which the smtp server is listening for connections | Default: `25` |
|
||||
|
||||
> :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.
|
||||
|
||||
#### Supported carriers
|
||||
|
||||
| **Carrier** | **Environment variable** | **Notes** |
|
||||
| Carrier | Environment variable | Notes |
|
||||
|:---:|:---:|:---:|
|
||||
| AT&T | `att`| |
|
||||
| AT&T | `att` | |
|
||||
| AT&T Prepaid | `attgo` | |
|
||||
| Bell | `bell` | |
|
||||
| Fido | `fido` | |
|
||||
| Google | `google`| |
|
||||
@@ -148,57 +304,144 @@ Here is a list of variables that you can use to customize your newly copied `.en
|
||||
| Virgin | `virgin`| |
|
||||
| Virgin (CA) | `virgin-ca`| |
|
||||
|
||||
#### Supported countries
|
||||
</details>
|
||||
|
||||
| **Country** | **Nvidia.com (3080 FE)** | **Nvidia.com (3090 FE)** | **Notes** |
|
||||
|:---:|:---:|:---:|:---:|
|
||||
| austria | `✔` | | |
|
||||
| belgium | `✔` | | Nvidia supports debug |
|
||||
| canada | `✔` | | |
|
||||
| czechia | `✔` | | |
|
||||
| denmark | `✔` | | |
|
||||
| finland | `✔` | | |
|
||||
| france | `✔` | | |
|
||||
| germany | `✔` | | |
|
||||
| great_britain | `✔` | | |
|
||||
| ireland | `✔` | | |
|
||||
| italy | `✔` | | |
|
||||
| luxembourg | `✔` | | Nvidia supports debug |
|
||||
| netherlands | `✔` | | Nvidia supports debug |
|
||||
| poland | `✔` | | |
|
||||
| portugal | `✔` | | |
|
||||
| russia | | | Missing all IDs |
|
||||
| spain | `✔` | | |
|
||||
| sweden | `✔` | | |
|
||||
| usa | `✔` | | Nvidia supports debug |
|
||||
<details>
|
||||
<summary>MQTT</summary>
|
||||
|
||||
| Environment variable | Description | Notes |
|
||||
|:---:|---|---|
|
||||
| `MQTT_BROKER_ADDRESS` | IP address or URL of MQTT Broker | e.g 192.168.1.xxx or broker.hivemq.com |
|
||||
| `MQTT_BROKER_PORT` | Network port of MQTT Broker | Default: 1883 |
|
||||
| `MQTT_CLIENT_ID` | Unique ClientID (only if required by MQTT Broker), typically not required when only publishing alerts | eg. client-123456 |
|
||||
| `MQTT_PASSWORD` | MQTT password - only use with MQTT brokers on private networks, if required. Will not be sent over public networks for safety. | e.g mysecret |
|
||||
| `MQTT_QOS` | QoS level for published alerts to broker (https://www.npmjs.com/package/mqtt#about-qos) | Default: 0, Can be 0, 1, or 2 |
|
||||
| `MQTT_TOPIC` | Topic to publish alerts to. Can include %store%, %series%, %brand%, %model% for dynamic topics | Default: nvidia-snatcher/alert e.g nv-alert/%store%/%series%/%brand%/%model%/alert |
|
||||
| `MQTT_USERNAME` | MQTT username - (only if required by MQTT Broker) | e.g myusername |
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>PagerDuty</summary>
|
||||
|
||||
| Environment variable | Description | Notes |
|
||||
|:---:|---|---|
|
||||
| `PAGERDUTY_INTEGRATION_KEY` | PagerDuty Events API v2 Integration Key. Obtain one in PagerDuty - <Service you want to use> - Integrations | |
|
||||
| `PAGERDUTY_SEVERITY` | Severity of PagerDuty events | Default: `info` |
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>Pushbullet</summary>
|
||||
|
||||
| Environment variable | Description | Notes |
|
||||
|:---:|---|---|
|
||||
| `PUSHBULLET` | PushBullet API key | Generate at https://www.pushbullet.com/#settings/account | |
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>Pushover</summary>
|
||||
|
||||
| Environment variable | Description | Notes |
|
||||
|:---:|---|---|
|
||||
| `PUSHOVER_TOKEN` | Pushover access token | Generate at https://pushover.net/apps/build | |
|
||||
| `PUSHOVER_USER` | Pushover username | |
|
||||
| `PUSHOVER_PRIORITY` | Pushover message priority |
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>Slack</summary>
|
||||
|
||||
| Environment variable | Description | Notes |
|
||||
|:---:|---|---|
|
||||
| `SLACK_CHANNEL` | Slack channel for posting | E.g.: `update`, no need for `#` |
|
||||
| `SLACK_TOKEN` | Slack API token | |
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>Telegram</summary>
|
||||
|
||||
| Environment variable | Description | Notes |
|
||||
|:---:|---|---|
|
||||
| `TELEGRAM_ACCESS_TOKEN` | Telegram access token | |
|
||||
| `TELEGRAM_CHAT_ID` | Telegram chat ID | Comma seperated, e.g.: `123456789`, `123456789,987654321` |
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>Twilio</summary>
|
||||
|
||||
| Environment variable | Description | Notes |
|
||||
|:---:|---|---|
|
||||
| `TWILIO_ACCOUNT_SID` | Twilio Account SID | Can be found on twilio.com/console |
|
||||
| `TWILIO_AUTH_TOKEN` | Twilio Auth Token | Can be found on twilio.com/console |
|
||||
| `TWILIO_FROM_NUMBER` | Twilio provided phone number to send messages from | Include country code e.g +4401234567890 |
|
||||
| `TWILIO_TO_NUMBER` | Mobile number to send SMS to | Include country code e.g +4401234567890 |
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>Twitter</summary>
|
||||
|
||||
| Environment variable | Description | Notes |
|
||||
|:---:|---|---|
|
||||
| `TWITTER_ACCESS_TOKEN_KEY` | Twitter Token Key | |
|
||||
| `TWITTER_ACCESS_TOKEN_SECRET` | Twitter Token Secret | |
|
||||
| `TWITTER_CONSUMER_KEY` | Twitter Consumer Key | Generate all Twitter keys at: https://developer.twitter.com/ |
|
||||
| `TWITTER_CONSUMER_SECRET` | Twitter Consumer Secret | |
|
||||
| `TWITTER_TWEET_TAGS` | Optional list of hashtags to append to the tweet message | E.g.: `#nvidia #nvidiastock` |
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>Twitch</summary>
|
||||
|
||||
| Environment variable | Description | Notes |
|
||||
|:---:|---|---|
|
||||
| `TWITCH_CLIENT_ID` | Twitch client ID | |
|
||||
| `TWITCH_CLIENT_SECRET`| Twitch client secret | |
|
||||
| `TWITCH_ACCESS_TOKEN` | Twitch access token | |
|
||||
| `TWITCH_REFRESH_TOKEN` | Twitch refresh token | |
|
||||
| `TWITCH_CHANNEL` | Twitch channel | |
|
||||
|
||||
</details>
|
||||
|
||||
</details>
|
||||
|
||||
## FAQ
|
||||
|
||||
**Q: What's Node.js and how do I install it?** Visit [their website](https://nodejs.org/en/) and download and install it. Very straight forward. Otherwise, Google more information related to your system needs.
|
||||
**Q: What's Node.js and how do I install it?** Visit [their website](https://nodejs.org/en/) and download and install
|
||||
it. Very straight forward. Otherwise, Google more information related to your system needs.
|
||||
|
||||
**Q: Will this harm my computer?** No.
|
||||
|
||||
**Q: Have you gotten a card yet?** No. :cry:
|
||||
**Q: Have you gotten a card yet?** YES! :tada: :rocket:
|
||||
|
||||
<details>
|
||||
<summary>Screenshot</summary>
|
||||
|
||||

|
||||
|
||||
</details>
|
||||
|
||||
**Q: Will I get banned from of the stores?** Perhaps, but getting a card is a nice outcome.
|
||||
|
||||
**Q: I got a problem and need help!** File an [issue](https://github.com/jef/nvidia-snatcher/issues/new/choose), I'll do my best to get to you. I work a full time job and this is only a hobby of mine.
|
||||
**Q: I got a problem and need help!** File an [issue](https://github.com/jef/nvidia-snatcher/issues/new/choose). I'll do
|
||||
my best to get to you. I work a full time job and this is only a hobby of mine.
|
||||
|
||||
**Q: How do I get the latest code?** Take look at this [wiki page](https://github.com/jef/nvidia-snatcher/wiki/Troubleshoot:-General:-Getting-the-latest-code)
|
||||
**Q: How do I get the latest code?** Take look at
|
||||
this [wiki page](https://github.com/jef/nvidia-snatcher/wiki/Troubleshoot:-General:-Getting-the-latest-code).
|
||||
|
||||
**Q: Why don't my notifications work?** There are probably an [issue](https://github.com/jef/nvidia-snatcher/issues?q=is%3Aissue+sort%3Aupdated-desc+sound+is%3Aclosed) [that] has [already](https://github.com/jef/nvidia-snatcher/issues/182) [been](https://github.com/jef/nvidia-snatcher/issues/116) [resolved](https://github.com/jef/nvidia-snatcher/issues/155)
|
||||
**Q: Why don't my notifications work?** There is probably
|
||||
an [issue](https://github.com/jef/nvidia-snatcher/issues?q=is%3Aissue+sort%3Aupdated-desc+sound+is%3Aclosed) that
|
||||
has [already](https://github.com/jef/nvidia-snatcher/issues/182) [been](https://github.com/jef/nvidia-snatcher/issues/116) [resolved](https://github.com/jef/nvidia-snatcher/issues/155).
|
||||
|
||||
**Q: I'd love to contribute, how do I do that?** Make a [pull request](https://github.com/jef/nvidia-snatcher/pulls?q=is%3Apr+is%3Aopen+sort%3Aupdated-desc)! All contributions are welcome.
|
||||
**Q: I'd love to contribute, how do I do that?** Make
|
||||
a [pull request](https://github.com/jef/nvidia-snatcher/pulls?q=is%3Apr+is%3Aopen+sort%3Aupdated-desc)! All
|
||||
contributions are welcome.
|
||||
|
||||
**Q: Why do I have to download all this stuff just to get this bot working?** Well, I would rather you didn't either. See [#11](https://github.com/jef/nvidia-snatcher/issues/11).
|
||||
|
||||
### Acknowledgements
|
||||
|
||||
Thanks to the great contributors that make this project possible
|
||||
|
||||
Special shout to initial developers:
|
||||
|
||||
- [@andirew](https://github.com/andirew)
|
||||
- [@fuckingrobot](https://github.com/fuckingrobot)
|
||||
- [@ioncaza](https://github.com/IonCaza)
|
||||
- [@malbert69](https://github.com/malbert69)
|
||||
**Q: Why do I have to download all this stuff just to get this bot working?** Well, I would rather you didn't either.
|
||||
See [#11](https://github.com/jef/nvidia-snatcher/issues/11).
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"exec": "ts-node --files ./src/index",
|
||||
"ext": "ts",
|
||||
"watch": [
|
||||
"src/",
|
||||
".env"
|
||||
]
|
||||
}
|
||||
Generated
+18812
-1110
File diff suppressed because it is too large
Load Diff
+30
-16
@@ -1,13 +1,14 @@
|
||||
{
|
||||
"name": "nvidia-snatcher",
|
||||
"version": "1.5.0",
|
||||
"description": "🔮 For all your Nvidia needs",
|
||||
"main": "src/index.ts",
|
||||
"scripts": {
|
||||
"build": "rimraf ./build && tsc",
|
||||
"all": "npm run build && npm run lint",
|
||||
"build": "tsc",
|
||||
"lint": "xo",
|
||||
"lint:fix": "xo --fix",
|
||||
"start": "npm run build && node build/index.js",
|
||||
"start:dev": "nodemon --config nodemon.json",
|
||||
"test:notification": "npm run build && node build/__test__/notification-test.js"
|
||||
},
|
||||
"repository": {
|
||||
@@ -22,34 +23,47 @@
|
||||
},
|
||||
"homepage": "https://github.com/jef/nvidia-snatcher#readme",
|
||||
"dependencies": {
|
||||
"@jef/pushbullet": "^2.4.3",
|
||||
"@slack/web-api": "^5.13.0",
|
||||
"chalk": "^4.1.0",
|
||||
"cheerio": "^1.0.0-rc.3",
|
||||
"discord-webhook-node": "^1.1.8",
|
||||
"dotenv": "^8.2.0",
|
||||
"messaging-api-telegram": "^1.0.1",
|
||||
"mqtt": "^4.2.4",
|
||||
"node-fetch": "^2.6.1",
|
||||
"node-notifier": "^8.0.0",
|
||||
"nodemailer": "^6.4.11",
|
||||
"open": "^7.2.1",
|
||||
"puppeteer": "^5.3.1",
|
||||
"node-pagerduty": "^1.3.5",
|
||||
"nodemailer": "^6.4.14",
|
||||
"open": "^7.3.0",
|
||||
"play-sound": "^1.1.3",
|
||||
"puppeteer": "^5.4.1",
|
||||
"puppeteer-extra": "^3.1.15",
|
||||
"puppeteer-extra-plugin-adblocker": "^2.11.6",
|
||||
"puppeteer-extra-plugin-stealth": "^2.6.1",
|
||||
"pushbullet": "^2.4.0",
|
||||
"puppeteer-extra-plugin-adblocker": "^2.11.8",
|
||||
"puppeteer-extra-plugin-block-resources": "^2.2.7",
|
||||
"puppeteer-extra-plugin-stealth": "^2.6.5",
|
||||
"pushover-notifications": "^1.2.2",
|
||||
"twilio": "^3.50.0",
|
||||
"twitch": "^4.2.7",
|
||||
"twitch-auth": "^4.2.7",
|
||||
"twitch-chat-client": "^4.2.7",
|
||||
"twitter": "^1.7.1",
|
||||
"winston": "^3.3.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@slack/web-api": "^5.12.0",
|
||||
"@types/async": "^3.2.3",
|
||||
"@types/node": "^14.11.2",
|
||||
"@types/cheerio": "^0.22.22",
|
||||
"@types/node": "^14.14.6",
|
||||
"@types/node-fetch": "^2.5.7",
|
||||
"@types/node-notifier": "^8.0.0",
|
||||
"@types/nodemailer": "^6.4.0",
|
||||
"@types/puppeteer": "^3.0.2",
|
||||
"@types/puppeteer": "^3.0.4",
|
||||
"@types/twitter": "^1.7.0",
|
||||
"discord-webhook-node": "^1.1.8",
|
||||
"husky": "^4.3.0",
|
||||
"play-sound": "^1.1.3",
|
||||
"rimraf": "^3.0.2",
|
||||
"typescript": "^4.0.2",
|
||||
"nodemon": "^2.0.6",
|
||||
"ts-node": "^9.0.0",
|
||||
"typescript": "^4.0.5",
|
||||
"webpack": "^5.3.2",
|
||||
"xo": "^0.33.1"
|
||||
},
|
||||
"xo": {
|
||||
@@ -61,7 +75,7 @@
|
||||
},
|
||||
"husky": {
|
||||
"hooks": {
|
||||
"pre-commit": "npm run lint"
|
||||
"pre-commit": "npm run all"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+3
-1
@@ -7,5 +7,7 @@ export const adBlocker = new PuppeteerExtraPluginAdblocker({
|
||||
|
||||
export async function disableBlockerInPage(page: Page) {
|
||||
const blockerObject = await adBlocker.getBlocker();
|
||||
await blockerObject.disableBlockingInPage(page);
|
||||
if (blockerObject.isBlockingEnabled(page)) {
|
||||
await blockerObject.disableBlockingInPage(page);
|
||||
}
|
||||
}
|
||||
|
||||
+4
-1
@@ -1,4 +1,7 @@
|
||||
import chalk from 'chalk';
|
||||
import {readFileSync} from 'fs';
|
||||
|
||||
const version = readFileSync('version.txt', 'utf8');
|
||||
|
||||
export const banner = chalk.green.bold(`
|
||||
$$\\ $$\\ $$\\ $$\\ $$\\
|
||||
@@ -9,4 +12,4 @@ $$ | $$ |\\$$\\$$ / $$ |$$ / $$ |$$ | $$$$$$$ |\\______|\\$$$$$$\\ $$ | $$
|
||||
$$ | $$ | \\$$$ / $$ |$$ | $$ |$$ |$$ __$$ | \\____$$\\ $$ | $$ |$$ __$$ | $$ |$$\\ $$ | $$ | $$ |$$ ____|$$ |
|
||||
$$ | $$ | \\$ / $$ |\\$$$$$$$ |$$ |\\$$$$$$$ | $$$$$$$ |$$ | $$ |\\$$$$$$$ | \\$$$$ |\\$$$$$$$\\ $$ | $$ |\\$$$$$$$\\ $$ |
|
||||
\\__| \\__| \\_/ \\__| \\_______|\\__| \\_______| \\_______/ \\__| \\__| \\_______| \\____/ \\_______|\\__| \\__| \\_______|\\__|
|
||||
`);
|
||||
${version}`);
|
||||
|
||||
+170
-20
@@ -1,10 +1,11 @@
|
||||
import {banner} from './banner';
|
||||
console.log(banner);
|
||||
|
||||
import {config} from 'dotenv';
|
||||
console.info(banner);
|
||||
|
||||
import {config as config_} from 'dotenv';
|
||||
import path from 'path';
|
||||
|
||||
config({path: path.resolve(__dirname, '../.env')});
|
||||
config_({path: path.resolve(__dirname, '../.env')});
|
||||
|
||||
/**
|
||||
* Returns environment variable, given array, or default array.
|
||||
@@ -13,7 +14,9 @@ config({path: path.resolve(__dirname, '../.env')});
|
||||
* @param array Default array. If not set, is `[]`.
|
||||
*/
|
||||
function envOrArray(environment: string | undefined, array?: string[]): string[] {
|
||||
return environment ? environment.split(',') : (array ?? []);
|
||||
return (environment ? (
|
||||
environment.includes('\n') ? environment.split('\n') : environment.split(',')
|
||||
) : (array ?? [])).map(s => s.trim());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -43,18 +46,84 @@ function envOrString(environment: string | undefined, string?: string): string {
|
||||
* @param number Default number. If not set, is `0`.
|
||||
*/
|
||||
function envOrNumber(environment: string | undefined, number?: number): number {
|
||||
return Number(environment ?? (number ?? 0));
|
||||
return environment ? Number(environment) : (number ?? 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns environment variable, given number, or default number,
|
||||
* while handling .env input errors for a Min/Max pair.
|
||||
* .env errors handled:
|
||||
* - Min/Max swapped (Min larger than Max, Max smaller than Min)
|
||||
* - Min larger than default Max when no Max defined
|
||||
* - Max smaller than default Min when no Min defined
|
||||
*
|
||||
* @param environmentMin Min environment variable of Min/Max pair.
|
||||
* @param environmentMax Max environment variable of Min/Max pair.
|
||||
* @param number Default number. If not set, is `0`.
|
||||
*/
|
||||
function envOrNumberMin(environmentMin: string | undefined, environmentMax: string | undefined, number?: number) {
|
||||
if (environmentMin || environmentMax) {
|
||||
if (environmentMin && environmentMax) {
|
||||
return Number(Number(environmentMin) < Number(environmentMax) ? environmentMin : environmentMax);
|
||||
}
|
||||
|
||||
if (environmentMax) {
|
||||
return Number(environmentMax) < (number ?? 0) ? Number(environmentMax) : (number ?? 0);
|
||||
}
|
||||
|
||||
if (environmentMin) {
|
||||
return Number(environmentMin);
|
||||
}
|
||||
}
|
||||
|
||||
return number ?? 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns environment variable, given number, or default number,
|
||||
* while handling .env input errors for a Min/Max pair.
|
||||
* .env errors handled:
|
||||
* - Min/Max swapped (Min larger than Max, Max smaller than Min)
|
||||
* - Min larger than default Max when no Max defined
|
||||
* - Max smaller than default Min when no Min defined
|
||||
*
|
||||
* @param environmentMin Min environment variable of Min/Max pair.
|
||||
* @param environmentMax Max environment variable of Min/Max pair.
|
||||
* @param number Default number. If not set, is `0`.
|
||||
*/
|
||||
function envOrNumberMax(environmentMin: string | undefined, environmentMax: string | undefined, number?: number) {
|
||||
if (environmentMin || environmentMax) {
|
||||
if (environmentMin && environmentMax) {
|
||||
return Number(Number(environmentMin) < Number(environmentMax) ? environmentMax : environmentMax);
|
||||
}
|
||||
|
||||
if (environmentMin) {
|
||||
return Number(environmentMin) > (number ?? 0) ? Number(environmentMin) : (number ?? 0);
|
||||
}
|
||||
|
||||
if (environmentMax) {
|
||||
return Number(environmentMax);
|
||||
}
|
||||
}
|
||||
|
||||
return number ?? 0;
|
||||
}
|
||||
|
||||
const browser = {
|
||||
isHeadless: envOrBoolean(process.env.HEADLESS),
|
||||
isIncognito: envOrBoolean(process.env.INCOGNITO, false),
|
||||
isTrusted: envOrBoolean(process.env.BROWSER_TRUSTED, false),
|
||||
maxSleep: envOrNumber(process.env.PAGE_SLEEP_MAX, 10000),
|
||||
minSleep: envOrNumber(process.env.PAGE_SLEEP_MIN, 5000),
|
||||
lowBandwidth: envOrBoolean(process.env.LOW_BANDWIDTH, false),
|
||||
maxBackoff: envOrNumberMax(process.env.PAGE_BACKOFF_MIN, process.env.PAGE_BACKOFF_MAX, 3600000),
|
||||
maxSleep: envOrNumberMax(process.env.PAGE_SLEEP_MIN, process.env.PAGE_SLEEP_MAX, 10000),
|
||||
minBackoff: envOrNumberMin(process.env.PAGE_BACKOFF_MIN, process.env.PAGE_BACKOFF_MAX, 10000),
|
||||
minSleep: envOrNumberMin(process.env.PAGE_SLEEP_MIN, process.env.PAGE_SLEEP_MAX, 5000),
|
||||
open: envOrBoolean(process.env.OPEN_BROWSER)
|
||||
};
|
||||
|
||||
const logLevel = process.env.LOG_LEVEL ?? 'info';
|
||||
const docker = envOrBoolean(process.env.DOCKER);
|
||||
|
||||
const logLevel = envOrString(process.env.LOG_LEVEL, 'info');
|
||||
|
||||
const notifications = {
|
||||
desktop: process.env.DESKTOP_NOTIFICATIONS === 'true',
|
||||
@@ -64,11 +133,28 @@ const notifications = {
|
||||
},
|
||||
email: {
|
||||
password: envOrString(process.env.EMAIL_PASSWORD),
|
||||
smtpAddress: envOrString(process.env.SMTP_ADDRESS),
|
||||
smtpPort: envOrNumber(process.env.SMTP_PORT, 25),
|
||||
to: envOrString(process.env.EMAIL_TO, envOrString(process.env.EMAIL_USERNAME)),
|
||||
username: envOrString(process.env.EMAIL_USERNAME)
|
||||
},
|
||||
mqtt: {
|
||||
broker: envOrString(process.env.MQTT_BROKER_ADDRESS),
|
||||
clientId: envOrString(process.env.MQTT_CLIENT_ID),
|
||||
password: envOrString(process.env.MQTT_PASSWORD),
|
||||
port: envOrNumber(process.env.MQTT_BROKER_PORT, 1883),
|
||||
qos: envOrNumber(process.env.MQTT_QOS, 0),
|
||||
topic: envOrString(process.env.MQTT_TOPIC, 'nvidia-snatcher/alert'),
|
||||
username: envOrString(process.env.MQTT_USERNAME)
|
||||
},
|
||||
pagerduty: {
|
||||
integrationKey: envOrString(process.env.PAGERDUTY_INTEGRATION_KEY),
|
||||
severity: envOrString(process.env.PAGERDUTY_SEVERITY, 'info')
|
||||
},
|
||||
phone: {
|
||||
availableCarriers: new Map([
|
||||
['att', 'txt.att.net'],
|
||||
['attgo', 'mms.att.net'],
|
||||
['bell', 'txt.bell.ca'],
|
||||
['fido', 'fido.ca'],
|
||||
['google', 'msg.fi.google.com'],
|
||||
@@ -86,8 +172,9 @@ const notifications = {
|
||||
number: envOrString(process.env.PHONE_NUMBER)
|
||||
},
|
||||
playSound: envOrString(process.env.PLAY_SOUND),
|
||||
pushBulletApiKey: envOrString(process.env.PUSHBULLET),
|
||||
pushbullet: envOrString(process.env.PUSHBULLET),
|
||||
pushover: {
|
||||
priority: envOrNumber(process.env.PUSHOVER_PRIORITY),
|
||||
token: envOrString(process.env.PUSHOVER_TOKEN),
|
||||
username: envOrString(process.env.PUSHOVER_USER)
|
||||
},
|
||||
@@ -97,7 +184,20 @@ const notifications = {
|
||||
},
|
||||
telegram: {
|
||||
accessToken: envOrString(process.env.TELEGRAM_ACCESS_TOKEN),
|
||||
chatId: envOrString(process.env.TELEGRAM_CHAT_ID)
|
||||
chatId: envOrArray(process.env.TELEGRAM_CHAT_ID)
|
||||
},
|
||||
twilio: {
|
||||
accountSid: envOrString(process.env.TWILIO_ACCOUNT_SID),
|
||||
authToken: envOrString(process.env.TWILIO_AUTH_TOKEN),
|
||||
from: envOrString(process.env.TWILIO_FROM_NUMBER),
|
||||
to: envOrString(process.env.TWILIO_TO_NUMBER)
|
||||
},
|
||||
twitch: {
|
||||
accessToken: envOrString(process.env.TWITCH_ACCESS_TOKEN),
|
||||
channel: envOrString(process.env.TWITCH_CHANNEL),
|
||||
clientId: envOrString(process.env.TWITCH_CLIENT_ID),
|
||||
clientSecret: envOrString(process.env.TWITCH_CLIENT_SECRET),
|
||||
refreshToken: envOrString(process.env.TWITCH_REFRESH_TOKEN)
|
||||
},
|
||||
twitter: {
|
||||
accessTokenKey: envOrString(process.env.TWITTER_ACCESS_TOKEN_KEY),
|
||||
@@ -108,28 +208,78 @@ const notifications = {
|
||||
}
|
||||
};
|
||||
|
||||
const nvidia = {
|
||||
addToCardAttempts: envOrNumber(process.env.NVIDIA_ADD_TO_CART_ATTEMPTS, 10),
|
||||
sessionTtl: envOrNumber(process.env.NVIDIA_SESSION_TTL, 60000)
|
||||
};
|
||||
|
||||
const page = {
|
||||
height: 1080,
|
||||
inStockWaitTime: envOrNumber(process.env.IN_STOCK_WAIT_TIME),
|
||||
navigationTimeout: envOrNumber(process.env.PAGE_TIMEOUT, 30000),
|
||||
screenshot: envOrBoolean(process.env.SCREENSHOT),
|
||||
userAgent: envOrString(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'),
|
||||
timeout: envOrNumber(process.env.PAGE_TIMEOUT, 30000),
|
||||
userAgents: envOrArray(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']),
|
||||
width: 1920
|
||||
};
|
||||
|
||||
const store = {
|
||||
country: envOrString(process.env.COUNTRY, 'usa'),
|
||||
microCenterLocation: envOrString(process.env.MICROCENTER_LOCATION, 'web'),
|
||||
showOnlyBrands: envOrArray(process.env.SHOW_ONLY_BRANDS),
|
||||
showOnlyModels: envOrArray(process.env.SHOW_ONLY_MODELS),
|
||||
showOnlySeries: envOrArray(process.env.SHOW_ONLY_SERIES, ['3070', '3080', '3090']),
|
||||
stores: envOrArray(process.env.STORES, ['nvidia'])
|
||||
const proxy = {
|
||||
address: envOrString(process.env.PROXY_ADDRESS),
|
||||
port: envOrNumber(process.env.PROXY_PORT, 80)
|
||||
};
|
||||
|
||||
export const Config = {
|
||||
// Check for deprecated configuration values
|
||||
if (process.env.MAX_PRICE) {
|
||||
console.warn('ℹ MAX_PRICE is deprecated, please use MAX_PRICE_SERIES_{{series}}');
|
||||
}
|
||||
|
||||
const store = {
|
||||
country: envOrString(process.env.COUNTRY, 'usa'),
|
||||
maxPrice: {
|
||||
series: {
|
||||
3070: envOrNumber(process.env.MAX_PRICE_SERIES_3070),
|
||||
3080: envOrNumber(process.env.MAX_PRICE_SERIES_3080),
|
||||
3090: envOrNumber(process.env.MAX_PRICE_SERIES_3090)
|
||||
}
|
||||
},
|
||||
microCenterLocation: envOrArray(process.env.MICROCENTER_LOCATION, ['web']),
|
||||
showOnlyBrands: envOrArray(process.env.SHOW_ONLY_BRANDS),
|
||||
showOnlyModels: envOrArray(process.env.SHOW_ONLY_MODELS).map(entry => {
|
||||
const [name, series] = entry.match(/[^:]+/g) ?? [];
|
||||
return {
|
||||
name: envOrString(name),
|
||||
series: envOrString(series)
|
||||
};
|
||||
}),
|
||||
showOnlySeries: envOrArray(process.env.SHOW_ONLY_SERIES, ['3070', '3080', '3090']),
|
||||
stores: envOrArray(process.env.STORES, ['nvidia']).map(entry => {
|
||||
const [name, minPageSleep, maxPageSleep] = entry.match(/[^:]+/g) ?? [];
|
||||
return {
|
||||
maxPageSleep: envOrNumberMax(minPageSleep, maxPageSleep, browser.maxSleep),
|
||||
minPageSleep: envOrNumberMin(minPageSleep, maxPageSleep, browser.minSleep),
|
||||
name: envOrString(name)
|
||||
};
|
||||
})
|
||||
};
|
||||
|
||||
export const defaultStoreData = {
|
||||
maxPageSleep: browser.maxSleep,
|
||||
minPageSleep: browser.minSleep
|
||||
};
|
||||
|
||||
export const config = {
|
||||
browser,
|
||||
docker,
|
||||
logLevel,
|
||||
notifications,
|
||||
nvidia,
|
||||
page,
|
||||
proxy,
|
||||
store
|
||||
};
|
||||
|
||||
export function setConfig(newConfig: any) {
|
||||
const writeConfig = config as any;
|
||||
for (const key of Object.keys(newConfig)) {
|
||||
writeConfig[key] = newConfig[key];
|
||||
}
|
||||
}
|
||||
|
||||
+67
-22
@@ -1,58 +1,103 @@
|
||||
import {Config} from './config';
|
||||
import {Logger} from './logger';
|
||||
import {Stores} from './store/model';
|
||||
import {startAPIServer, stopAPIServer} from './web';
|
||||
import {Browser} from 'puppeteer';
|
||||
import {adBlocker} from './adblocker';
|
||||
import {config} from './config';
|
||||
import {getSleepTime} from './util';
|
||||
import {logger} from './logger';
|
||||
import puppeteer from 'puppeteer-extra';
|
||||
import resourceBlock from 'puppeteer-extra-plugin-block-resources';
|
||||
import stealthPlugin from 'puppeteer-extra-plugin-stealth';
|
||||
import {storeList} from './store/model';
|
||||
import {tryLookupAndLoop} from './store';
|
||||
|
||||
puppeteer.use(stealthPlugin());
|
||||
puppeteer.use(adBlocker);
|
||||
if (config.browser.lowBandwidth) {
|
||||
puppeteer.use(resourceBlock({
|
||||
blockedTypes: new Set(['image', 'font'] as const)
|
||||
}));
|
||||
} else {
|
||||
puppeteer.use(adBlocker);
|
||||
}
|
||||
|
||||
let browser: Browser | undefined;
|
||||
|
||||
/**
|
||||
* Starts the bot.
|
||||
*/
|
||||
async function main() {
|
||||
if (Stores.length === 0) {
|
||||
Logger.error('✖ no stores selected', Stores);
|
||||
return;
|
||||
}
|
||||
|
||||
const args: string[] = [];
|
||||
|
||||
// Skip Chromium Linux Sandbox
|
||||
// https://github.com/puppeteer/puppeteer/blob/main/docs/troubleshooting.md#setting-up-chrome-linux-sandbox
|
||||
if (Config.browser.isTrusted) {
|
||||
if (config.browser.isTrusted) {
|
||||
args.push('--no-sandbox');
|
||||
args.push('--disable-setuid-sandbox');
|
||||
}
|
||||
|
||||
const browser = await puppeteer.launch({
|
||||
// https://github.com/puppeteer/puppeteer/blob/main/docs/troubleshooting.md#tips
|
||||
if (config.docker) {
|
||||
args.push('--disable-dev-shm-usage');
|
||||
}
|
||||
|
||||
// Add the address of the proxy server if defined
|
||||
if (config.proxy.address) {
|
||||
args.push(`--proxy-server=http://${config.proxy.address}:${config.proxy.port}`);
|
||||
}
|
||||
|
||||
await stop();
|
||||
|
||||
browser = await puppeteer.launch({
|
||||
args,
|
||||
defaultViewport: {
|
||||
height: Config.page.height,
|
||||
width: Config.page.width
|
||||
height: config.page.height,
|
||||
width: config.page.width
|
||||
},
|
||||
headless: Config.browser.isHeadless
|
||||
headless: config.browser.isHeadless
|
||||
});
|
||||
|
||||
for (const store of Stores) {
|
||||
Logger.debug(store.links);
|
||||
for (const store of storeList.values()) {
|
||||
logger.debug('store links', {meta: {links: store.links}});
|
||||
if (store.setupAction !== undefined) {
|
||||
store.setupAction(browser);
|
||||
}
|
||||
|
||||
setTimeout(tryLookupAndLoop, getSleepTime(), browser, store);
|
||||
setTimeout(tryLookupAndLoop, getSleepTime(store), browser, store);
|
||||
}
|
||||
|
||||
await startAPIServer();
|
||||
}
|
||||
|
||||
async function stop() {
|
||||
await stopAPIServer();
|
||||
|
||||
if (browser) {
|
||||
// Use temporary swap variable to avoid any race condition
|
||||
const browserTemporary = browser;
|
||||
browser = undefined;
|
||||
await browserTemporary.close();
|
||||
}
|
||||
}
|
||||
|
||||
async function stopAndExit() {
|
||||
await stop();
|
||||
// eslint-disable-next-line unicorn/no-process-exit
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Will continually run until user interferes.
|
||||
*/
|
||||
try {
|
||||
void main();
|
||||
} catch (error) {
|
||||
Logger.error('✖ something bad happened, resetting nvidia-snatcher', error);
|
||||
void main();
|
||||
async function loopMain() {
|
||||
try {
|
||||
await main();
|
||||
} catch (error) {
|
||||
logger.error('✖ something bad happened, resetting nvidia-snatcher in 5 seconds', error);
|
||||
setTimeout(loopMain, 5000);
|
||||
}
|
||||
}
|
||||
|
||||
void loopMain();
|
||||
|
||||
process.on('SIGINT', stopAndExit);
|
||||
process.on('SIGQUIT', stopAndExit);
|
||||
process.on('SIGTERM', stopAndExit);
|
||||
|
||||
+80
-13
@@ -1,31 +1,56 @@
|
||||
import {Link, Store} from './store/model';
|
||||
import winston, {format} from 'winston';
|
||||
import {Config} from './config';
|
||||
import chalk from 'chalk';
|
||||
import {config} from './config';
|
||||
import winston from 'winston';
|
||||
|
||||
const prettyJson = format.printf(info => {
|
||||
const prettyJson = winston.format.printf(info => {
|
||||
const timestamp = new Date().toLocaleTimeString();
|
||||
|
||||
if (typeof info.message === 'object') {
|
||||
info.message = JSON.stringify(info.message, null, 4);
|
||||
}
|
||||
|
||||
if (info.meta) {
|
||||
return chalk.grey(`[${timestamp}]`) + ` ${info.level} ` + chalk.grey('::') + ` ${info.message} ${chalk.magenta(JSON.stringify(info.meta, null, 2))}`;
|
||||
}
|
||||
|
||||
return chalk.grey(`[${timestamp}]`) + ` ${info.level} ` + chalk.grey('::') + ` ${info.message}`;
|
||||
});
|
||||
|
||||
export const Logger = winston.createLogger({
|
||||
format: format.combine(
|
||||
format.colorize(),
|
||||
format.prettyPrint(),
|
||||
format.splat(),
|
||||
format.simple(),
|
||||
export const logger = winston.createLogger({
|
||||
format: winston.format.combine(
|
||||
winston.format.colorize(),
|
||||
winston.format.prettyPrint(),
|
||||
winston.format.splat(),
|
||||
winston.format.simple(),
|
||||
prettyJson
|
||||
),
|
||||
level: Config.logLevel,
|
||||
level: config.logLevel,
|
||||
transports: [new winston.transports.Console({})]
|
||||
});
|
||||
|
||||
export const Print = {
|
||||
backoff(link: Link, store: Store, parameters: {delay: number; statusCode: number}, color?: boolean): string {
|
||||
if (color) {
|
||||
return '✖ ' + buildProductString(link, store, true) + ' :: ' + chalk.yellow(`BACKOFF DELAY status=${parameters.statusCode} delay=${parameters.delay}`);
|
||||
}
|
||||
|
||||
return `✖ ${buildProductString(link, store)} :: BACKOFF DELAY status=${parameters.statusCode} delay=${parameters.delay}`;
|
||||
},
|
||||
badStatusCode(link: Link, store: Store, statusCode: number, color?: boolean): string {
|
||||
if (color) {
|
||||
return '✖ ' + buildProductString(link, store, true) + ' :: ' + chalk.yellow(`STATUS CODE ERROR ${statusCode}`);
|
||||
}
|
||||
|
||||
return `✖ ${buildProductString(link, store)} :: STATUS CODE ERROR ${statusCode}`;
|
||||
},
|
||||
bannedSeller(link: Link, store: Store, color?: boolean): string {
|
||||
if (color) {
|
||||
return '✖ ' + buildProductString(link, store, true) + ' :: ' + chalk.yellow('BANNED SELLER');
|
||||
}
|
||||
|
||||
return `✖ ${buildProductString(link, store)} :: BANNED SELLER`;
|
||||
},
|
||||
captcha(link: Link, store: Store, color?: boolean): string {
|
||||
if (color) {
|
||||
return '✖ ' + buildProductString(link, store, true) + ' :: ' + chalk.yellow('CAPTCHA');
|
||||
@@ -33,12 +58,46 @@ export const Print = {
|
||||
|
||||
return `✖ ${buildProductString(link, store)} :: CAPTCHA`;
|
||||
},
|
||||
inStock(link: Link, store: Store, color?: boolean): string {
|
||||
inStock(link: Link, store: Store, color?: boolean, sms?: boolean): string {
|
||||
const productString = `${buildProductString(link, store)} :: IN STOCK`;
|
||||
|
||||
if (color) {
|
||||
return chalk.green.bold(`🚀🚨 ${buildProductString(link, store, true)} :: IN STOCK 🚨🚀`);
|
||||
return chalk.bgGreen.white.bold(`🚀🚨 ${productString} 🚨🚀`);
|
||||
}
|
||||
|
||||
return `🚀🚨 ${buildProductString(link, store)} :: IN STOCK 🚨🚀`;
|
||||
if (sms) {
|
||||
return productString;
|
||||
}
|
||||
|
||||
return `🚀🚨 ${productString} 🚨🚀`;
|
||||
},
|
||||
inStockWaiting(link: Link, store: Store, color?: boolean): string {
|
||||
if (color) {
|
||||
return 'ℹ ' + buildProductString(link, store, true) + ' :: ' + chalk.yellow('IN STOCK, WAITING');
|
||||
}
|
||||
|
||||
return `ℹ ${buildProductString(link, store)} :: IN STOCK, WAITING`;
|
||||
},
|
||||
maxPrice(link: Link, store: Store, price: number, maxPrice: number, color?: boolean): string {
|
||||
if (color) {
|
||||
return '✖ ' + buildProductString(link, store, true) + ' :: ' + chalk.yellow(`PRICE ${price} EXCEEDS LIMIT ${maxPrice}`);
|
||||
}
|
||||
|
||||
return `✖ ${buildProductString(link, store)} :: PRICE ${price} EXCEEDS LIMIT ${maxPrice}`;
|
||||
},
|
||||
message(message: string, topic: string, store: Store, color?: boolean): string {
|
||||
if (color) {
|
||||
return '✖ ' + buildSetupString(topic, store, true) + ' :: ' + chalk.yellow(message);
|
||||
}
|
||||
|
||||
return `✖ ${buildSetupString(topic, store)} :: ${message}`;
|
||||
},
|
||||
noResponse(link: Link, store: Store, color?: boolean): string {
|
||||
if (color) {
|
||||
return '✖ ' + buildProductString(link, store, true) + ' :: ' + chalk.yellow('NO RESPONSE');
|
||||
}
|
||||
|
||||
return `✖ ${buildProductString(link, store)} :: NO RESPONSE`;
|
||||
},
|
||||
outOfStock(link: Link, store: Store, color?: boolean): string {
|
||||
if (color) {
|
||||
@@ -56,6 +115,14 @@ export const Print = {
|
||||
}
|
||||
};
|
||||
|
||||
function buildSetupString(topic: string, store: Store, color?: boolean): string {
|
||||
if (color) {
|
||||
return chalk.cyan(`[${store.name}]`) + chalk.grey(` [setup (${topic})]`);
|
||||
}
|
||||
|
||||
return `[${store.name}] [setup (${topic})]`;
|
||||
}
|
||||
|
||||
function buildProductString(link: Link, store: Store, color?: boolean): string {
|
||||
if (color) {
|
||||
return chalk.cyan(`[${store.name}]`) + chalk.grey(` [${link.brand} (${link.series})] ${link.model}`);
|
||||
|
||||
@@ -1,14 +1,20 @@
|
||||
import {Link, Store} from '../store/model';
|
||||
import {Logger, Print} from '../logger';
|
||||
import {Print, logger} from '../logger';
|
||||
import {config} from '../config';
|
||||
import notifier from 'node-notifier';
|
||||
|
||||
export function sendDesktopNotification(link: Link, store: Store) {
|
||||
(async () => {
|
||||
notifier.notify({
|
||||
message: link.cartUrl ? link.cartUrl : link.url,
|
||||
title: Print.inStock(link, store)
|
||||
});
|
||||
const desktop = config.notifications.desktop;
|
||||
|
||||
Logger.info('✔ desktop notification sent');
|
||||
})();
|
||||
export function sendDesktopNotification(link: Link, store: Store) {
|
||||
if (desktop) {
|
||||
logger.debug('↗ sending desktop notification');
|
||||
(async () => {
|
||||
notifier.notify({
|
||||
message: link.cartUrl ? link.cartUrl : link.url,
|
||||
title: Print.inStock(link, store)
|
||||
});
|
||||
|
||||
logger.info('✔ desktop notification sent');
|
||||
})();
|
||||
}
|
||||
}
|
||||
|
||||
+36
-30
@@ -1,38 +1,44 @@
|
||||
import {Link, Store} from '../store/model';
|
||||
import {MessageBuilder, Webhook} from 'discord-webhook-node';
|
||||
import {Config} from '../config';
|
||||
import {Logger} from '../logger';
|
||||
import {config} from '../config';
|
||||
import {logger} from '../logger';
|
||||
|
||||
const hooks = Config.notifications.discord.webHookUrl;
|
||||
const notifyGroup = Config.notifications.discord.notifyGroup;
|
||||
const discord = config.notifications.discord;
|
||||
const hooks = discord.webHookUrl;
|
||||
const notifyGroup = discord.notifyGroup;
|
||||
|
||||
export function sendDiscordMessage(link: Link, store: Store) {
|
||||
(async () => {
|
||||
try {
|
||||
const embed = new MessageBuilder();
|
||||
embed.setTitle('Stock Notification');
|
||||
embed.addField('URL', link.cartUrl ? link.cartUrl : link.url, true);
|
||||
embed.addField('Store', store.name, true);
|
||||
embed.addField('Brand', link.brand, true);
|
||||
embed.addField('Model', link.model, true);
|
||||
if (discord.webHookUrl.length > 0) {
|
||||
logger.debug('↗ sending discord message');
|
||||
|
||||
if (notifyGroup) {
|
||||
embed.setText(notifyGroup.join(' '));
|
||||
(async () => {
|
||||
try {
|
||||
const embed = new MessageBuilder();
|
||||
embed.setTitle('Stock Notification');
|
||||
embed.addField('URL', link.cartUrl ? link.cartUrl : link.url, true);
|
||||
embed.addField('Store', store.name, true);
|
||||
embed.addField('Brand', link.brand, true);
|
||||
embed.addField('Series', link.series, true);
|
||||
embed.addField('Model', link.model, true);
|
||||
|
||||
if (notifyGroup) {
|
||||
embed.setText(notifyGroup.join(' '));
|
||||
}
|
||||
|
||||
embed.setColor(0x76B900);
|
||||
embed.setTimestamp();
|
||||
|
||||
const promises = [];
|
||||
for (const hook of hooks) {
|
||||
promises.push(new Webhook(hook).send(embed));
|
||||
}
|
||||
|
||||
await Promise.all(promises);
|
||||
|
||||
logger.info('✔ discord message sent');
|
||||
} catch (error) {
|
||||
logger.error('✖ couldn\'t send discord message', error);
|
||||
}
|
||||
|
||||
embed.setColor(0x76B900);
|
||||
embed.setTimestamp();
|
||||
|
||||
const promises = [];
|
||||
for (const hook of hooks) {
|
||||
promises.push(new Webhook(hook).send(embed));
|
||||
}
|
||||
|
||||
await Promise.all(promises);
|
||||
|
||||
Logger.info('✔ discord message sent');
|
||||
} catch (error) {
|
||||
Logger.error('✖ couldn\'t send discord message', error);
|
||||
}
|
||||
})();
|
||||
})();
|
||||
}
|
||||
}
|
||||
|
||||
+43
-28
@@ -1,38 +1,53 @@
|
||||
import {Link, Store} from '../store/model';
|
||||
import {Logger, Print} from '../logger';
|
||||
import {Config} from '../config';
|
||||
import {Print, logger} from '../logger';
|
||||
import Mail from 'nodemailer/lib/mailer';
|
||||
import {config} from '../config';
|
||||
import nodemailer from 'nodemailer';
|
||||
|
||||
const email = Config.notifications.email;
|
||||
const email = config.notifications.email;
|
||||
|
||||
const transporter = nodemailer.createTransport({
|
||||
auth: {
|
||||
pass: email.password,
|
||||
user: email.username
|
||||
},
|
||||
service: 'gmail'
|
||||
const transportOptions: any = {};
|
||||
|
||||
if (email.username && (email.password || email.smtpAddress)) {
|
||||
transportOptions.auth = {};
|
||||
transportOptions.auth.user = email.username;
|
||||
transportOptions.auth.pass = email.password;
|
||||
}
|
||||
|
||||
if (email.smtpAddress) {
|
||||
transportOptions.host = email.smtpAddress;
|
||||
transportOptions.port = email.smtpPort;
|
||||
} else {
|
||||
transportOptions.service = 'gmail';
|
||||
}
|
||||
|
||||
export const transporter = nodemailer.createTransport({
|
||||
...transportOptions
|
||||
});
|
||||
|
||||
export function sendEmail(link: Link, store: Store) {
|
||||
const mailOptions: Mail.Options = {
|
||||
attachments: link.screenshot ? [
|
||||
{
|
||||
filename: link.screenshot,
|
||||
path: `./${link.screenshot}`
|
||||
}
|
||||
] : undefined,
|
||||
from: email.username,
|
||||
subject: Print.inStock(link, store),
|
||||
text: link.cartUrl ? link.cartUrl : link.url,
|
||||
to: email.username
|
||||
};
|
||||
if (email.username && (email.password || email.smtpAddress)) {
|
||||
logger.debug('↗ sending email');
|
||||
|
||||
transporter.sendMail(mailOptions, error => {
|
||||
if (error) {
|
||||
Logger.error('✖ couldn\'t send email', error);
|
||||
} else {
|
||||
Logger.info('✔ email sent');
|
||||
}
|
||||
});
|
||||
const mailOptions: Mail.Options = {
|
||||
attachments: link.screenshot ? [
|
||||
{
|
||||
filename: link.screenshot,
|
||||
path: `./${link.screenshot}`
|
||||
}
|
||||
] : undefined,
|
||||
from: email.username,
|
||||
subject: Print.inStock(link, store),
|
||||
text: link.cartUrl ? link.cartUrl : link.url,
|
||||
to: email.to
|
||||
};
|
||||
|
||||
transporter.sendMail(mailOptions, error => {
|
||||
if (error) {
|
||||
logger.error('✖ couldn\'t send email', error);
|
||||
} else {
|
||||
logger.info('✔ email sent');
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,107 @@
|
||||
import {Link, Store} from '../store/model';
|
||||
import MqttClient, {IClientOptions, IClientPublishOptions} from 'mqtt';
|
||||
import {Print, logger} from '../logger';
|
||||
import {config} from '../config';
|
||||
|
||||
const mqtt = config.notifications.mqtt;
|
||||
let client: MqttClient.Client;
|
||||
|
||||
if (mqtt.broker) {
|
||||
if (checkInsecureUsage(mqtt.password, mqtt.broker)) {
|
||||
logger.warn('✖ Insecure transport of password - Only use credentials with MQTT brokers on private networks.');
|
||||
} else {
|
||||
const clientOptions: IClientOptions = {
|
||||
clean: (mqtt.clientId === ''),
|
||||
clientId: mqtt.clientId === '' ? undefined : mqtt.clientId,
|
||||
password: mqtt.password === '' ? undefined : mqtt.password,
|
||||
username: mqtt.username === '' ? undefined : mqtt.username
|
||||
};
|
||||
client = MqttClient.connect(`mqtt://${mqtt.broker}:${mqtt.port}`, clientOptions);
|
||||
}
|
||||
}
|
||||
|
||||
export function sendMqttMessage(link: Link, store: Store) {
|
||||
if (client) {
|
||||
logger.debug('↗ sending mqtt message');
|
||||
|
||||
(async () => {
|
||||
const givenUrl = link.cartUrl ? link.cartUrl : link.url;
|
||||
const message = `{"msg":"${Print.inStock(link, store)}", "url":"${givenUrl}"}`;
|
||||
const topic = generateTopic(link, store, mqtt.topic);
|
||||
const pubOptions: IClientPublishOptions = {
|
||||
qos: mqtt.qos as 0 | 1 | 2,
|
||||
retain: false
|
||||
};
|
||||
|
||||
try {
|
||||
client.publish(
|
||||
topic,
|
||||
message,
|
||||
pubOptions
|
||||
);
|
||||
logger.info('✔ mqtt message sent');
|
||||
} catch (error) {
|
||||
logger.error('✖ couldn\'t send mqtt message', error);
|
||||
}
|
||||
})();
|
||||
}
|
||||
}
|
||||
|
||||
function generateTopic(link: Link, store: Store, topic: string): string {
|
||||
topic.trim();
|
||||
topic = topic.replace(/^\//, '');
|
||||
topic = topic.replace(/%series%/g, link.series)
|
||||
.replace(/%brand%/g, link.brand)
|
||||
.replace(/%model%/g, link.model)
|
||||
.replace(/%store%/g, store.name);
|
||||
|
||||
return topic;
|
||||
}
|
||||
|
||||
/**
|
||||
* Basic protection against sending credentials in the clear over public networks.
|
||||
* - Returns 'true' if password is supplied in .env but address/URL is not part of a private network
|
||||
* - Private networks evaluated: Class A, B, or C private IP's or linklocal URL ("*.local")
|
||||
* - TLS could be implemented, however, the majority of MQTT services on the internet do not require user authentication.
|
||||
* - If you find a 'cloud' MQTT broker requiring authentication for publishing alerts, consider using another MQTT service (for now).
|
||||
*
|
||||
*/
|
||||
function checkInsecureUsage(pass: string, address: string): boolean {
|
||||
if (pass !== '') {
|
||||
if (isClassANet(address) ||
|
||||
isClassBNet(address) ||
|
||||
isClassCNet(address) ||
|
||||
isLinkLocal(address)) {
|
||||
logger.debug(`MQTT using private network broker: ${address}`);
|
||||
} else {
|
||||
logger.debug(`MQTT using public network broker: ${address}`);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function isClassANet(address: string): boolean {
|
||||
const classRegex = /^(10\.(\d|[1-9]\d|[12][0-5]{2})\.(\d|[1-9]\d|[12][0-5]{2})\.(\d|[1-9]\d|[12][0-5]{2}))$/;
|
||||
|
||||
return Boolean(classRegex.exec(address));
|
||||
}
|
||||
|
||||
function isClassBNet(address: string): boolean {
|
||||
const classRegex = /^(172\.(1[6-9]|2\d|3[01])\.(\d|[1-9]\d|[12][0-5]{2})\.(\d|[1-9]\d|[12][0-5]{2}))$/;
|
||||
|
||||
return Boolean(classRegex.exec(address));
|
||||
}
|
||||
|
||||
function isClassCNet(address: string): boolean {
|
||||
const classRegex = /^(192\.168\.(\d|[1-9]\d|[12][0-5]{2})\.(\d|[1-9]\d|[12][0-5]{2}))$/;
|
||||
|
||||
return Boolean(classRegex.exec(address));
|
||||
}
|
||||
|
||||
function isLinkLocal(address: string): boolean {
|
||||
const linkLocal = /.+\.local$/;
|
||||
|
||||
return Boolean(linkLocal.exec(address));
|
||||
}
|
||||
@@ -1,75 +1,34 @@
|
||||
import {Link, Store} from '../store/model';
|
||||
import {Config} from '../config';
|
||||
import {Logger} from '../logger';
|
||||
import {playSound} from './sound';
|
||||
import {sendDesktopNotification} from './desktop';
|
||||
import {sendDiscordMessage} from './discord';
|
||||
import {sendEmail} from './email';
|
||||
import {sendPushBulletNotification} from './pushbullet';
|
||||
import {sendMqttMessage} from './mqtt';
|
||||
import {sendPagerDutyNotification} from './pagerduty';
|
||||
import {sendPushbulletNotification} from './pushbullet';
|
||||
import {sendPushoverNotification} from './pushover';
|
||||
import {sendSMS} from './sms';
|
||||
import {sendSlackMessage} from './slack';
|
||||
import {sendSms} from './sms';
|
||||
import {sendTelegramMessage} from './telegram';
|
||||
import {sendTweet} from './twitter';
|
||||
|
||||
const notifications = Config.notifications;
|
||||
import {sendTwilioMessage} from './twilio';
|
||||
import {sendTwitchMessage} from './twitch';
|
||||
|
||||
export function sendNotification(link: Link, store: Store) {
|
||||
if (notifications.email.username && notifications.email.password) {
|
||||
Logger.debug('↗ sending email');
|
||||
sendEmail(link, store);
|
||||
}
|
||||
|
||||
if (notifications.phone.number) {
|
||||
Logger.debug('↗ sending sms');
|
||||
const carrier = notifications.phone.carrier;
|
||||
if (carrier && notifications.phone.availableCarriers.has(carrier)) {
|
||||
sendSMS(link, store);
|
||||
}
|
||||
}
|
||||
|
||||
if (notifications.playSound) {
|
||||
Logger.debug('↗ playing sound');
|
||||
playSound();
|
||||
}
|
||||
|
||||
if (notifications.desktop) {
|
||||
Logger.debug('↗ sending desktop notification');
|
||||
sendDesktopNotification(link, store);
|
||||
}
|
||||
|
||||
if (notifications.discord.webHookUrl) {
|
||||
Logger.debug('↗ sending discord message');
|
||||
sendDiscordMessage(link, store);
|
||||
}
|
||||
|
||||
if (notifications.slack.channel && notifications.slack.token) {
|
||||
Logger.debug('↗ sending slack message');
|
||||
sendSlackMessage(link, store);
|
||||
}
|
||||
|
||||
if (notifications.telegram.accessToken && notifications.telegram.chatId) {
|
||||
Logger.debug('↗ sending telegram message');
|
||||
sendTelegramMessage(link, store);
|
||||
}
|
||||
|
||||
if (notifications.pushBulletApiKey) {
|
||||
Logger.debug('↗ sending pushbullet message');
|
||||
sendPushBulletNotification(link, store);
|
||||
}
|
||||
|
||||
if (notifications.pushover.token && notifications.pushover.username) {
|
||||
Logger.debug('↗ sending pushover message');
|
||||
sendPushoverNotification(link, store);
|
||||
}
|
||||
|
||||
if (
|
||||
notifications.twitter.accessTokenKey &&
|
||||
notifications.twitter.accessTokenSecret &&
|
||||
notifications.twitter.consumerKey &&
|
||||
notifications.twitter.consumerSecret
|
||||
) {
|
||||
Logger.debug('↗ sending twitter message');
|
||||
sendTweet(link, store);
|
||||
}
|
||||
// Priority
|
||||
playSound();
|
||||
sendEmail(link, store);
|
||||
sendSms(link, store);
|
||||
sendDesktopNotification(link, store);
|
||||
// Non-priority
|
||||
sendDiscordMessage(link, store);
|
||||
sendMqttMessage(link, store);
|
||||
sendPagerDutyNotification(link, store);
|
||||
sendPushbulletNotification(link, store);
|
||||
sendPushoverNotification(link, store);
|
||||
sendSlackMessage(link, store);
|
||||
sendTelegramMessage(link, store);
|
||||
sendTweet(link, store);
|
||||
sendTwilioMessage(link, store);
|
||||
sendTwitchMessage(link, store);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
import {Link, Store} from '../store/model';
|
||||
import {Print, logger} from '../logger';
|
||||
import PDClient from 'node-pagerduty';
|
||||
import {config} from '../config';
|
||||
|
||||
const pd = new PDClient('');
|
||||
|
||||
export function sendPagerDutyNotification(link: Link, store: Store) {
|
||||
if (config.notifications.pagerduty.integrationKey) {
|
||||
logger.debug('↗ sending pagerduty message');
|
||||
const links = [
|
||||
{href: link.url, text: 'Visit Store'}
|
||||
];
|
||||
if (link.cartUrl) {
|
||||
links.push({
|
||||
href: link.cartUrl, text: 'Add to Cart'
|
||||
});
|
||||
}
|
||||
|
||||
pd.events.sendEvent({
|
||||
dedup_key: link.url,
|
||||
event_action: 'trigger',
|
||||
payload: {
|
||||
links,
|
||||
severity: config.notifications.pagerduty.severity,
|
||||
source: store.name,
|
||||
summary: Print.inStock(link, store)
|
||||
},
|
||||
routing_key: config.notifications.pagerduty.integrationKey
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,22 +1,26 @@
|
||||
import {Link, Store} from '../store/model';
|
||||
import {Logger, Print} from '../logger';
|
||||
import {Config} from '../config';
|
||||
import PushBullet from 'pushbullet';
|
||||
import {Print, logger} from '../logger';
|
||||
import PushBullet from '@jef/pushbullet';
|
||||
import {config} from '../config';
|
||||
|
||||
const pushBulletApiKey = Config.notifications.pushBulletApiKey;
|
||||
const pushbullet = config.notifications.pushbullet;
|
||||
|
||||
export function sendPushBulletNotification(link: Link, store: Store) {
|
||||
const pusher = new PushBullet(pushBulletApiKey);
|
||||
export function sendPushbulletNotification(link: Link, store: Store) {
|
||||
if (pushbullet) {
|
||||
logger.debug('↗ sending pushbullet message');
|
||||
|
||||
pusher.note(
|
||||
{},
|
||||
Print.inStock(link, store),
|
||||
link.cartUrl ? link.cartUrl : link.url,
|
||||
(error: Error) => {
|
||||
if (error) {
|
||||
Logger.error('✖ couldn\'t send pushbullet message', error);
|
||||
} else {
|
||||
Logger.info('✔ pushbullet message sent');
|
||||
}
|
||||
});
|
||||
const pusher = new PushBullet(pushbullet);
|
||||
|
||||
pusher.note(
|
||||
{},
|
||||
Print.inStock(link, store),
|
||||
link.cartUrl ? link.cartUrl : link.url,
|
||||
(error: Error) => {
|
||||
if (error) {
|
||||
logger.error('✖ couldn\'t send pushbullet message', error);
|
||||
} else {
|
||||
logger.info('✔ pushbullet message sent');
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,25 +1,30 @@
|
||||
import {Link, Store} from '../store/model';
|
||||
import {Logger, Print} from '../logger';
|
||||
import {Config} from '../config';
|
||||
import Push from 'pushover-notifications';
|
||||
import {Print, logger} from '../logger';
|
||||
import Push, {PushoverMessage} from 'pushover-notifications';
|
||||
import {config} from '../config';
|
||||
|
||||
const pushover = Config.notifications.pushover;
|
||||
const pushover = config.notifications.pushover;
|
||||
const push = new Push({
|
||||
token: pushover.token,
|
||||
user: pushover.username
|
||||
});
|
||||
|
||||
export function sendPushoverNotification(link: Link, store: Store) {
|
||||
const message = {
|
||||
message: link.cartUrl ? link.cartUrl : link.url,
|
||||
title: Print.inStock(link, store)
|
||||
};
|
||||
if (pushover.token && pushover.username) {
|
||||
logger.debug('↗ sending pushover message');
|
||||
|
||||
push.send(message, (error: Error) => {
|
||||
if (error) {
|
||||
Logger.error('✖ couldn\'t send pushover message', error);
|
||||
} else {
|
||||
Logger.info('✔ pushover message sent');
|
||||
}
|
||||
});
|
||||
const message: PushoverMessage = {
|
||||
message: link.cartUrl ? link.cartUrl : link.url,
|
||||
priority: pushover.priority,
|
||||
title: Print.inStock(link, store)
|
||||
};
|
||||
|
||||
push.send(message, (error: Error) => {
|
||||
if (error) {
|
||||
logger.error('✖ couldn\'t send pushover message', error);
|
||||
} else {
|
||||
logger.info('✔ pushover message sent');
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
+25
-20
@@ -1,30 +1,35 @@
|
||||
import {Link, Store} from '../store/model';
|
||||
import {Logger, Print} from '../logger';
|
||||
import {Config} from '../config';
|
||||
import {Print, logger} from '../logger';
|
||||
import {WebClient} from '@slack/web-api';
|
||||
import {config} from '../config';
|
||||
|
||||
const channel = Config.notifications.slack.channel;
|
||||
const token = Config.notifications.slack.token;
|
||||
const slack = config.notifications.slack;
|
||||
const channel = slack.channel;
|
||||
const token = slack.token;
|
||||
const web = new WebClient(token);
|
||||
|
||||
export function sendSlackMessage(link: Link, store: Store) {
|
||||
(async () => {
|
||||
const givenUrl = link.cartUrl ? link.cartUrl : link.url;
|
||||
if (slack.channel && slack.token) {
|
||||
logger.debug('↗ sending slack message');
|
||||
|
||||
try {
|
||||
const result = await web.chat.postMessage({
|
||||
channel,
|
||||
text: `${Print.inStock(link, store)}\n${givenUrl}`
|
||||
});
|
||||
(async () => {
|
||||
const givenUrl = link.cartUrl ? link.cartUrl : link.url;
|
||||
|
||||
if (!result.ok) {
|
||||
Logger.error('✖ couldn\'t send slack message', result);
|
||||
return;
|
||||
try {
|
||||
const result = await web.chat.postMessage({
|
||||
channel,
|
||||
text: `${Print.inStock(link, store)}\n${givenUrl}`
|
||||
});
|
||||
|
||||
if (!result.ok) {
|
||||
logger.error('✖ couldn\'t send slack message', result);
|
||||
return;
|
||||
}
|
||||
|
||||
logger.info('✔ slack message sent');
|
||||
} catch (error) {
|
||||
logger.error('✖ couldn\'t send slack message', error);
|
||||
}
|
||||
|
||||
Logger.info('✔ slack message sent');
|
||||
} catch (error) {
|
||||
Logger.error('✖ couldn\'t send slack message', error);
|
||||
}
|
||||
})();
|
||||
})();
|
||||
}
|
||||
}
|
||||
|
||||
+32
-33
@@ -1,44 +1,43 @@
|
||||
import {Link, Store} from '../store/model';
|
||||
import {Logger, Print} from '../logger';
|
||||
import {Config} from '../config';
|
||||
import {Print, logger} from '../logger';
|
||||
import Mail from 'nodemailer/lib/mailer';
|
||||
import nodemailer from 'nodemailer';
|
||||
import {config} from '../config';
|
||||
import {transporter} from './email';
|
||||
|
||||
if (Config.notifications.phone.number && !Config.notifications.email.username) {
|
||||
Logger.warn('✖ in order to recieve sms alerts, email notifications must also be configured');
|
||||
if (config.notifications.phone.number && !config.notifications.email.username) {
|
||||
logger.warn('✖ in order to receive sms alerts, email notifications must also be configured');
|
||||
}
|
||||
|
||||
const [email, phone] = [Config.notifications.email, Config.notifications.phone];
|
||||
const [email, phone] = [config.notifications.email, config.notifications.phone];
|
||||
|
||||
const transporter = nodemailer.createTransport({
|
||||
auth: {
|
||||
pass: email.password,
|
||||
user: email.username
|
||||
},
|
||||
service: 'gmail'
|
||||
});
|
||||
export function sendSms(link: Link, store: Store) {
|
||||
if (phone.number) {
|
||||
logger.debug('↗ sending sms');
|
||||
const carrier = phone.carrier;
|
||||
|
||||
export function sendSMS(link: Link, store: Store) {
|
||||
const mailOptions: Mail.Options = {
|
||||
attachments: link.screenshot ? [
|
||||
{
|
||||
filename: link.screenshot,
|
||||
path: `./${link.screenshot}`
|
||||
}
|
||||
] : undefined,
|
||||
from: email.username,
|
||||
subject: Print.inStock(link, store),
|
||||
text: link.cartUrl ? link.cartUrl : link.url,
|
||||
to: generateAddress()
|
||||
};
|
||||
if (carrier && phone.availableCarriers.has(carrier)) {
|
||||
const mailOptions: Mail.Options = {
|
||||
attachments: link.screenshot ? [
|
||||
{
|
||||
filename: link.screenshot,
|
||||
path: `./${link.screenshot}`
|
||||
}
|
||||
] : undefined,
|
||||
from: email.username,
|
||||
subject: Print.inStock(link, store, false, true),
|
||||
text: link.cartUrl ? link.cartUrl : link.url,
|
||||
to: generateAddress()
|
||||
};
|
||||
|
||||
transporter.sendMail(mailOptions, error => {
|
||||
if (error) {
|
||||
Logger.error('✖ couldn\'t send sms', error);
|
||||
} else {
|
||||
Logger.info('✔ sms sent');
|
||||
transporter.sendMail(mailOptions, error => {
|
||||
if (error) {
|
||||
logger.error('✖ couldn\'t send sms', error);
|
||||
} else {
|
||||
logger.info('✔ sms sent');
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function generateAddress() {
|
||||
@@ -48,5 +47,5 @@ function generateAddress() {
|
||||
return [phone.number, phone.availableCarriers.get(carrier)].join('@');
|
||||
}
|
||||
|
||||
Logger.error('✖ unknown carrier', carrier);
|
||||
logger.error('✖ unknown carrier', carrier);
|
||||
}
|
||||
|
||||
+16
-14
@@ -1,35 +1,37 @@
|
||||
import {Config} from '../config';
|
||||
import {Logger} from '../logger';
|
||||
import playerLib, {PlaySound} from 'play-sound';
|
||||
import {config} from '../config';
|
||||
import fs from 'fs';
|
||||
import playerLib from 'play-sound';
|
||||
import {logger} from '../logger';
|
||||
|
||||
let player: any;
|
||||
let player: PlaySound;
|
||||
|
||||
if (Config.notifications.playSound) {
|
||||
if (config.notifications.playSound) {
|
||||
player = playerLib();
|
||||
|
||||
if (player.player === null) {
|
||||
Logger.warn('✖ couldn\'t find sound player');
|
||||
logger.warn('✖ couldn\'t find sound player');
|
||||
} else {
|
||||
const playerName: string = player.player;
|
||||
Logger.info(`✔ sound player found: ${playerName}`);
|
||||
const playerName = player.player;
|
||||
logger.info(`✔ sound player found: ${playerName}`);
|
||||
}
|
||||
}
|
||||
|
||||
export function playSound() {
|
||||
if (player.player !== null) {
|
||||
fs.access(Config.notifications.playSound, fs.constants.F_OK, error => {
|
||||
if (config.notifications.playSound && player.player !== null) {
|
||||
logger.debug('↗ playing sound');
|
||||
|
||||
fs.access(config.notifications.playSound, fs.constants.F_OK, error => {
|
||||
if (error) {
|
||||
Logger.error(`✖ error opening sound file: ${error.message}`);
|
||||
logger.error(`✖ error opening sound file: ${error.message}`);
|
||||
return;
|
||||
}
|
||||
|
||||
player.play(Config.notifications.playSound, (error: Error) => {
|
||||
player.play(config.notifications.playSound, (error: Error) => {
|
||||
if (error) {
|
||||
Logger.error('✖ couldn\'t play sound', error);
|
||||
logger.error('✖ couldn\'t play sound', error);
|
||||
}
|
||||
|
||||
Logger.info('✔ played sound');
|
||||
logger.info('✔ played sound');
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,23 +1,32 @@
|
||||
import {Link, Store} from '../store/model';
|
||||
import {Logger, Print} from '../logger';
|
||||
import {Config} from '../config';
|
||||
import {Print, logger} from '../logger';
|
||||
import {TelegramClient} from 'messaging-api-telegram';
|
||||
import {config} from '../config';
|
||||
|
||||
const telegram = Config.notifications.telegram;
|
||||
const telegram = config.notifications.telegram;
|
||||
|
||||
const client = new TelegramClient({
|
||||
accessToken: telegram.accessToken
|
||||
});
|
||||
|
||||
export function sendTelegramMessage(link: Link, store: Store) {
|
||||
(async () => {
|
||||
const givenUrl = link.cartUrl ? link.cartUrl : link.url;
|
||||
if (telegram.accessToken && telegram.chatId) {
|
||||
logger.debug('↗ sending telegram message');
|
||||
|
||||
try {
|
||||
await client.sendMessage(telegram.chatId, `${Print.inStock(link, store)}\n${givenUrl}`);
|
||||
Logger.info('✔ telegram message sent');
|
||||
} catch (error) {
|
||||
Logger.error('✖ couldn\'t send telegram message', error);
|
||||
}
|
||||
})();
|
||||
(async () => {
|
||||
const givenUrl = link.cartUrl ? link.cartUrl : link.url;
|
||||
const results = [];
|
||||
|
||||
for (const chatId of telegram.chatId) {
|
||||
try {
|
||||
results.push(client.sendMessage(chatId, `${Print.inStock(link, store)}\n${givenUrl}`));
|
||||
logger.info('✔ telegram message sent');
|
||||
} catch (error) {
|
||||
logger.error('✖ couldn\'t send telegram message', error);
|
||||
}
|
||||
}
|
||||
|
||||
await Promise.all(results);
|
||||
})();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
import {Link, Store} from '../store/model';
|
||||
import {Print, logger} from '../logger';
|
||||
import {Twilio} from 'twilio';
|
||||
import {config} from '../config';
|
||||
|
||||
const twilio = config.notifications.twilio;
|
||||
let client: Twilio;
|
||||
|
||||
if (twilio.accountSid && twilio.authToken) {
|
||||
client = new Twilio(twilio.accountSid, twilio.authToken);
|
||||
}
|
||||
|
||||
export function sendTwilioMessage(link: Link, store: Store) {
|
||||
if (client) {
|
||||
logger.debug('↗ sending twilio message');
|
||||
|
||||
(async () => {
|
||||
const givenUrl = link.cartUrl ? link.cartUrl : link.url;
|
||||
const message = `${Print.inStock(link, store)}\n${givenUrl}`;
|
||||
|
||||
try {
|
||||
await client.messages.create({
|
||||
body: message,
|
||||
from: twilio.from,
|
||||
to: twilio.to
|
||||
});
|
||||
logger.info('✔ twilio message sent');
|
||||
} catch (error) {
|
||||
logger.error('✖ couldn\'t send twilio message', error);
|
||||
}
|
||||
})();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
import {Link, Store} from '../store/model';
|
||||
import {Print, logger} from '../logger';
|
||||
import {RefreshableAuthProvider, StaticAuthProvider} from 'twitch-auth';
|
||||
import {existsSync, promises, readFileSync} from 'fs';
|
||||
import {ChatClient} from 'twitch-chat-client';
|
||||
import {config} from '../config';
|
||||
|
||||
const twitch = config.notifications.twitch;
|
||||
|
||||
const messages: string[] = [];
|
||||
let alreadySaying = false;
|
||||
|
||||
let tokenData = {
|
||||
accessToken: twitch.accessToken,
|
||||
expiryTimestamp: 0,
|
||||
refreshToken: twitch.refreshToken
|
||||
};
|
||||
|
||||
if (existsSync('./twitch.json')) {
|
||||
tokenData = {...JSON.parse(readFileSync('./twitch.json', 'utf-8')), ...tokenData};
|
||||
}
|
||||
|
||||
const chatClient: ChatClient = new ChatClient(
|
||||
new RefreshableAuthProvider(
|
||||
new StaticAuthProvider(twitch.clientId, tokenData.accessToken),
|
||||
{
|
||||
clientSecret: twitch.clientSecret,
|
||||
expiry: tokenData.expiryTimestamp === null ? null : new Date(tokenData.expiryTimestamp),
|
||||
onRefresh: async ({accessToken, refreshToken, expiryDate}) => {
|
||||
return promises.writeFile('./twitch.json', JSON.stringify({
|
||||
accessToken,
|
||||
expiryTimestamp: expiryDate === null ? null : expiryDate.getTime(),
|
||||
refreshToken
|
||||
}, null, 4), 'utf-8');
|
||||
},
|
||||
refreshToken: tokenData.refreshToken
|
||||
}
|
||||
),
|
||||
{
|
||||
channels: [twitch.channel]
|
||||
}
|
||||
);
|
||||
|
||||
chatClient.onJoin((channel: string, user: string) => {
|
||||
if (channel === `#${twitch.channel}` && user === chatClient.currentNick) {
|
||||
while (messages.length) {
|
||||
const message: string | undefined = messages.shift();
|
||||
|
||||
if (message !== undefined) {
|
||||
try {
|
||||
chatClient.say(channel, message);
|
||||
logger.info('✔ twitch message sent');
|
||||
} catch (error) {
|
||||
logger.error('✖ couldn\'t send twitch message', error);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void chatClient.quit();
|
||||
});
|
||||
|
||||
chatClient.onDisconnect(() => {
|
||||
alreadySaying = false;
|
||||
});
|
||||
|
||||
export function sendTwitchMessage(link: Link, store: Store) {
|
||||
if (tokenData.accessToken && twitch.channel && twitch.clientId && twitch.clientSecret && tokenData.refreshToken) {
|
||||
logger.debug('↗ sending twitch message');
|
||||
|
||||
messages.push(`${Print.inStock(link, store)}\n${link.cartUrl ? link.cartUrl : link.url}`);
|
||||
|
||||
if (!alreadySaying) {
|
||||
alreadySaying = true;
|
||||
void chatClient.connect();
|
||||
}
|
||||
}
|
||||
}
|
||||
+17
-13
@@ -1,9 +1,9 @@
|
||||
import {Link, Store} from '../store/model';
|
||||
import {Logger, Print} from '../logger';
|
||||
import {Config} from '../config';
|
||||
import {Print, logger} from '../logger';
|
||||
import Twitter from 'twitter';
|
||||
import {config} from '../config';
|
||||
|
||||
const twitter = Config.notifications.twitter;
|
||||
const twitter = config.notifications.twitter;
|
||||
|
||||
const client = new Twitter({
|
||||
access_token_key: twitter.accessTokenKey,
|
||||
@@ -13,17 +13,21 @@ const client = new Twitter({
|
||||
});
|
||||
|
||||
export function sendTweet(link: Link, store: Store) {
|
||||
let status = `${Print.inStock(link, store)}\n${link.cartUrl ? link.cartUrl : link.url}`;
|
||||
if (twitter.accessTokenKey && twitter.accessTokenSecret && twitter.consumerKey && twitter.consumerSecret) {
|
||||
logger.debug('↗ sending twitter message');
|
||||
|
||||
if (twitter.tweetTags) {
|
||||
status += `\n\n${twitter.tweetTags}`;
|
||||
}
|
||||
let status = `${Print.inStock(link, store)}\n${link.cartUrl ? link.cartUrl : link.url}`;
|
||||
|
||||
client.post('statuses/update', {status}, error => {
|
||||
if (error) {
|
||||
Logger.error('✖ couldn\'t send twitter notification', error);
|
||||
} else {
|
||||
Logger.info('✔ twitter notification sent');
|
||||
if (twitter.tweetTags) {
|
||||
status += `\n\n${twitter.tweetTags}`;
|
||||
}
|
||||
});
|
||||
|
||||
client.post('statuses/update', {status}, error => {
|
||||
if (error) {
|
||||
logger.error('✖ couldn\'t send twitter notification', error);
|
||||
} else {
|
||||
logger.info('✔ twitter notification sent');
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
import {Link, Series, Store} from './model';
|
||||
import {Print, logger} from '../logger';
|
||||
import {Browser} from 'puppeteer';
|
||||
import cheerio from 'cheerio';
|
||||
import {filterSeries} from './filter';
|
||||
import {usingResponse} from '../util';
|
||||
|
||||
function addNewLinks(store: Store, links: Link[], series: Series) {
|
||||
if (links.length === 0) {
|
||||
logger.debug(Print.message('NO STORE LINKS FOUND', series, store, true));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const existingUrls = new Set(store.links.map(link => link.url));
|
||||
const newLinks = links.filter(link => !existingUrls.has(link.url));
|
||||
|
||||
if (newLinks.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
logger.debug(Print.message(`FOUND ${newLinks.length} STORE LINKS`, series, store, true));
|
||||
logger.debug(JSON.stringify(newLinks, null, 2));
|
||||
|
||||
store.links = store.links.concat(newLinks);
|
||||
}
|
||||
|
||||
export async function fetchLinks(store: Store, browser: Browser) {
|
||||
if (!store.linksBuilder) {
|
||||
return;
|
||||
}
|
||||
|
||||
const promises: Array<Promise<void>> = [];
|
||||
|
||||
for (let {series, url} of store.linksBuilder.urls) {
|
||||
if (!filterSeries(series)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
logger.debug(Print.message('DETECTING STORE LINKS', series, store, true));
|
||||
|
||||
if (!Array.isArray(url)) {
|
||||
url = [url];
|
||||
}
|
||||
|
||||
url.map(x => promises.push(usingResponse(browser, x, async response => {
|
||||
const text = await response?.text();
|
||||
|
||||
if (!text) {
|
||||
logger.error(Print.message('NO RESPONSE', series, store, true));
|
||||
return;
|
||||
}
|
||||
|
||||
const docElement = cheerio.load(text).root();
|
||||
const links = store.linksBuilder!.builder(docElement, series);
|
||||
|
||||
addNewLinks(store, links, series);
|
||||
})));
|
||||
}
|
||||
|
||||
await Promise.all(promises);
|
||||
}
|
||||
+18
-12
@@ -1,5 +1,5 @@
|
||||
import {Config} from '../config';
|
||||
import {Link} from './model';
|
||||
import {config} from '../config';
|
||||
|
||||
/**
|
||||
* Returns true if the brand should be checked for stock
|
||||
@@ -7,27 +7,33 @@ import {Link} from './model';
|
||||
* @param brand The brand of the GPU
|
||||
*/
|
||||
function filterBrand(brand: Link['brand']): boolean {
|
||||
if (Config.store.showOnlyBrands.length === 0) {
|
||||
if (config.store.showOnlyBrands.length === 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return Config.store.showOnlyBrands.includes(brand);
|
||||
return config.store.showOnlyBrands.includes(brand);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the model should be checked for stock
|
||||
*
|
||||
* @param model The model of the GPU
|
||||
* @param series The series of the GPU
|
||||
*/
|
||||
function filterModel(model: Link['model']): boolean {
|
||||
if (Config.store.showOnlyModels.length === 0) {
|
||||
function filterModel(model: Link['model'], series: Link['series']): boolean {
|
||||
if (config.store.showOnlyModels.length === 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const sanitizedModel = model.replace(/\s/g, '');
|
||||
for (const configModel of Config.store.showOnlyModels) {
|
||||
const sanitizedConfigModel = configModel.replace(/\s/g, '');
|
||||
if (sanitizedModel === sanitizedConfigModel) {
|
||||
const sanitizedSeries = series.replace(/\s/g, '');
|
||||
for (const configModelEntry of config.store.showOnlyModels) {
|
||||
const sanitizedConfigModel = configModelEntry.name.replace(/\s/g, '');
|
||||
const sanitizedConfigSeries = configModelEntry.series.replace(/\s/g, '');
|
||||
if (sanitizedConfigSeries ?
|
||||
sanitizedSeries === sanitizedConfigSeries && sanitizedModel === sanitizedConfigModel :
|
||||
sanitizedModel === sanitizedConfigModel
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -40,12 +46,12 @@ function filterModel(model: Link['model']): boolean {
|
||||
*
|
||||
* @param series The series of the GPU
|
||||
*/
|
||||
function filterSeries(series: Link['series']): boolean {
|
||||
if (Config.store.showOnlySeries.length === 0) {
|
||||
export function filterSeries(series: Link['series']): boolean {
|
||||
if (config.store.showOnlySeries.length === 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return Config.store.showOnlySeries.includes(series);
|
||||
return config.store.showOnlySeries.includes(series);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -56,7 +62,7 @@ function filterSeries(series: Link['series']): boolean {
|
||||
export function filterStoreLink(link: Link): boolean {
|
||||
return (
|
||||
filterBrand(link.brand) &&
|
||||
filterModel(link.model) &&
|
||||
filterModel(link.model, link.series) &&
|
||||
filterSeries(link.series)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,3 +1,83 @@
|
||||
import {Element, LabelQuery, Pricing} from './model';
|
||||
import {Page} from 'puppeteer';
|
||||
import {logger} from '../logger';
|
||||
|
||||
export type Selector = {
|
||||
requireVisible: boolean;
|
||||
selector: string;
|
||||
type: 'innerHTML' | 'outerHTML' | 'textContent';
|
||||
};
|
||||
|
||||
function isElementArray(query: LabelQuery): query is Element[] {
|
||||
return Array.isArray(query) && query.length > 0 && typeof query[0] === 'object';
|
||||
}
|
||||
|
||||
function getQueryAsElementArray(query: LabelQuery, defaultContainer: string): Array<Required<Element>> {
|
||||
if (isElementArray(query)) {
|
||||
return query.map(x => ({
|
||||
container: x.container ?? defaultContainer,
|
||||
text: x.text
|
||||
}));
|
||||
}
|
||||
|
||||
if (Array.isArray(query)) {
|
||||
return [{
|
||||
container: defaultContainer,
|
||||
text: query
|
||||
}];
|
||||
}
|
||||
|
||||
return [{
|
||||
container: query.container ?? defaultContainer,
|
||||
text: query.text
|
||||
}];
|
||||
}
|
||||
|
||||
export async function pageIncludesLabels(page: Page, query: LabelQuery, options: Selector) {
|
||||
const elementQueries = getQueryAsElementArray(query, options.selector);
|
||||
|
||||
const resolved = await Promise.all(elementQueries.map(async query => {
|
||||
const selector = {...options, selector: query.container};
|
||||
const contents = await extractPageContents(page, selector) ?? '';
|
||||
|
||||
if (!contents) {
|
||||
return false;
|
||||
}
|
||||
|
||||
logger.debug(contents);
|
||||
|
||||
return includesLabels(contents, query.text);
|
||||
}));
|
||||
|
||||
return resolved.includes(true);
|
||||
}
|
||||
|
||||
export async function extractPageContents(page: Page, selector: Selector): Promise<string | null> {
|
||||
return page.evaluate((options: Selector) => {
|
||||
// eslint-disable-next-line no-undef
|
||||
const element: globalThis.HTMLElement | null = document.querySelector(options.selector);
|
||||
|
||||
if (!element) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (options.requireVisible && !(element.offsetWidth > 0 && element.offsetHeight > 0)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
switch (options.type) {
|
||||
case 'innerHTML':
|
||||
return element.innerHTML;
|
||||
case 'outerHTML':
|
||||
return element.outerHTML;
|
||||
case 'textContent':
|
||||
return element.textContent;
|
||||
default:
|
||||
return 'Error: selector.type is unknown';
|
||||
}
|
||||
}, selector);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if DOM has any related text.
|
||||
*
|
||||
@@ -6,5 +86,24 @@
|
||||
*/
|
||||
export function includesLabels(domText: string, searchLabels: string[]): boolean {
|
||||
const domTextLowerCase = domText.toLowerCase();
|
||||
return searchLabels.some(label => domTextLowerCase.includes(label));
|
||||
return searchLabels.some(label => domTextLowerCase.includes(label.toLowerCase()));
|
||||
}
|
||||
|
||||
export async function cardPrice(page: Page, query: Pricing, max: number, options: Selector) {
|
||||
if (!max) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const selector = {...options, selector: query.container};
|
||||
const cardPrice = await extractPageContents(page, selector);
|
||||
|
||||
if (cardPrice) {
|
||||
const priceSeperator = query.euroFormat ? /\./g : /,/g;
|
||||
const cardpriceNumber = Number.parseFloat(cardPrice.replace(priceSeperator, '').match(/\d+/g)!.join('.'));
|
||||
|
||||
logger.debug(`Raw card price: ${cardPrice} | Limit: ${max}`);
|
||||
return cardpriceNumber > max ? cardpriceNumber : null;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
+165
-67
@@ -1,15 +1,20 @@
|
||||
import {Browser, Page, Response} from 'puppeteer';
|
||||
import {Link, Store} from './model';
|
||||
import {Logger, Print} from '../logger';
|
||||
import {closePage, delay, getSleepTime} from '../util';
|
||||
import {Config} from '../config';
|
||||
import {Link, Store, getStores} from './model';
|
||||
import {Print, logger} from '../logger';
|
||||
import {Selector, cardPrice, pageIncludesLabels} from './includes-labels';
|
||||
import {closePage, delay, getRandomUserAgent, getSleepTime, isStatusCodeInRange} from '../util';
|
||||
import {config} from '../config';
|
||||
import {disableBlockerInPage} from '../adblocker';
|
||||
import {fetchLinks} from './fetch-links';
|
||||
import {filterStoreLink} from './filter';
|
||||
import {includesLabels} from './includes-labels';
|
||||
import open from 'open';
|
||||
import {processBackoffDelay} from './model/helpers/backoff';
|
||||
import {sendNotification} from '../notification';
|
||||
|
||||
const inStock: Record<string, boolean> = {};
|
||||
|
||||
const linkBuilderLastRunTimes: Record<string, number> = {};
|
||||
|
||||
/**
|
||||
* Responsible for looking up information about a each product within
|
||||
* a `Store`. It's important that we ignore `no-await-in-loop` here
|
||||
@@ -19,36 +24,82 @@ const inStock: Record<string, boolean> = {};
|
||||
* @param store Vendor of graphics cards.
|
||||
*/
|
||||
async function lookup(browser: Browser, store: Store) {
|
||||
if (!getStores().has(store.name)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* eslint-disable no-await-in-loop */
|
||||
for (const link of store.links) {
|
||||
if (!filterStoreLink(link)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const page = await browser.newPage();
|
||||
page.setDefaultNavigationTimeout(Config.page.navigationTimeout);
|
||||
await page.setUserAgent(Config.page.userAgent);
|
||||
|
||||
try {
|
||||
await lookupCard(browser, store, page, link);
|
||||
} catch (error) {
|
||||
Logger.error(`✖ [${store.name}] ${link.brand} ${link.model} - ${error.message as string}`);
|
||||
if (config.page.inStockWaitTime && inStock[link.url]) {
|
||||
logger.info(Print.inStockWaiting(link, store, true));
|
||||
continue;
|
||||
}
|
||||
|
||||
const context = (config.browser.isIncognito ? await browser.createIncognitoBrowserContext() : browser.defaultBrowserContext());
|
||||
const page = (config.browser.isIncognito ? await context.newPage() : await browser.newPage());
|
||||
page.setDefaultNavigationTimeout(config.page.timeout);
|
||||
await page.setUserAgent(getRandomUserAgent());
|
||||
|
||||
if (store.disableAdBlocker) {
|
||||
try {
|
||||
await disableBlockerInPage(page);
|
||||
} catch (error) {
|
||||
logger.error(error);
|
||||
}
|
||||
}
|
||||
|
||||
let statusCode = 0;
|
||||
|
||||
try {
|
||||
statusCode = await lookupCard(browser, store, page, link);
|
||||
} catch (error) {
|
||||
logger.error(`✖ [${store.name}] ${link.brand} ${link.series} ${link.model} - ${error.message as string}`);
|
||||
const client = await page.target().createCDPSession();
|
||||
await client.send('Network.clearBrowserCookies');
|
||||
await client.send('Network.clearBrowserCache');
|
||||
}
|
||||
|
||||
// Must apply backoff before closing the page, e.g. if CloudFlare is
|
||||
// used to detect bot traffic, it introduces a 5 second page delay
|
||||
// before redirecting to the next page
|
||||
await processBackoffDelay(store, link, statusCode);
|
||||
await closePage(page);
|
||||
if (config.browser.isIncognito) {
|
||||
await context.close();
|
||||
}
|
||||
}
|
||||
/* eslint-enable no-await-in-loop */
|
||||
}
|
||||
|
||||
async function lookupCard(browser: Browser, store: Store, page: Page, link: Link) {
|
||||
async function lookupCard(browser: Browser, store: Store, page: Page, link: Link): Promise<number> {
|
||||
const givenWaitFor = store.waitUntil ? store.waitUntil : 'networkidle0';
|
||||
const response: Response | null = await page.goto(link.url, {waitUntil: givenWaitFor});
|
||||
|
||||
if (await lookupCardInStock(store, page)) {
|
||||
const givenUrl = link.cartUrl ? link.cartUrl : link.url;
|
||||
Logger.info(`${Print.inStock(link, store, true)}\n${givenUrl}`);
|
||||
if (!response) {
|
||||
logger.debug(Print.noResponse(link, store, true));
|
||||
}
|
||||
|
||||
if (Config.browser.open) {
|
||||
const successStatusCodes = store.successStatusCodes ?? [[0, 399]];
|
||||
const statusCode = response?.status() ?? 0;
|
||||
if (!isStatusCodeInRange(statusCode, successStatusCodes)) {
|
||||
if (statusCode === 429) {
|
||||
logger.warn(Print.rateLimit(link, store, true));
|
||||
} else {
|
||||
logger.warn(Print.badStatusCode(link, store, statusCode, true));
|
||||
}
|
||||
|
||||
return statusCode;
|
||||
}
|
||||
|
||||
if (await lookupCardInStock(store, page, link)) {
|
||||
const givenUrl = link.cartUrl ? link.cartUrl : link.url;
|
||||
logger.info(`${Print.inStock(link, store, true)}\n${givenUrl}`);
|
||||
|
||||
if (config.browser.open) {
|
||||
if (link.openCartAction === undefined) {
|
||||
await open(givenUrl);
|
||||
} else {
|
||||
@@ -58,77 +109,124 @@ async function lookupCard(browser: Browser, store: Store, page: Page, link: Link
|
||||
|
||||
sendNotification(link, store);
|
||||
|
||||
if (Config.page.inStockWaitTime) {
|
||||
inStock[store.name] = true;
|
||||
if (config.page.inStockWaitTime) {
|
||||
inStock[link.url] = true;
|
||||
|
||||
setTimeout(() => {
|
||||
inStock[store.name] = false;
|
||||
}, 1000 * Config.page.inStockWaitTime);
|
||||
inStock[link.url] = false;
|
||||
}, 1000 * config.page.inStockWaitTime);
|
||||
}
|
||||
|
||||
if (Config.page.screenshot) {
|
||||
Logger.debug('ℹ saving screenshot');
|
||||
if (config.page.screenshot) {
|
||||
logger.debug('ℹ saving screenshot');
|
||||
|
||||
link.screenshot = `success-${Date.now()}.png`;
|
||||
await page.screenshot({path: link.screenshot});
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (await lookupPageHasCaptcha(store, page)) {
|
||||
Logger.warn(Print.captcha(link, store, true));
|
||||
await delay(getSleepTime());
|
||||
return;
|
||||
}
|
||||
|
||||
if (response && response.status() === 429) {
|
||||
Logger.warn(Print.rateLimit(link, store, true));
|
||||
return;
|
||||
}
|
||||
|
||||
Logger.info(Print.outOfStock(link, store, true));
|
||||
return statusCode;
|
||||
}
|
||||
|
||||
async function lookupCardInStock(store: Store, page: Page) {
|
||||
const stockHandle = await page.$(store.labels.inStock.container);
|
||||
async function lookupCardInStock(store: Store, page: Page, link: Link) {
|
||||
const baseOptions: Selector = {
|
||||
requireVisible: false,
|
||||
selector: store.labels.container ?? 'body',
|
||||
type: 'textContent'
|
||||
};
|
||||
|
||||
const visible = await page.evaluate(element => element && element.offsetWidth > 0 && element.offsetHeight > 0, stockHandle);
|
||||
if (!visible) {
|
||||
return false;
|
||||
if (store.labels.inStock) {
|
||||
const options = {...baseOptions, requireVisible: true, type: 'outerHTML' as const};
|
||||
|
||||
if (!await pageIncludesLabels(page, store.labels.inStock, options)) {
|
||||
logger.info(Print.outOfStock(link, store, true));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
const stockContent = await page.evaluate(element => element.outerHTML, stockHandle);
|
||||
|
||||
Logger.debug(stockContent);
|
||||
|
||||
return includesLabels(stockContent, store.labels.inStock.text);
|
||||
}
|
||||
|
||||
async function lookupPageHasCaptcha(store: Store, page: Page) {
|
||||
if (!store.labels.captcha) {
|
||||
return false;
|
||||
if (store.labels.outOfStock) {
|
||||
if (await pageIncludesLabels(page, store.labels.outOfStock, baseOptions)) {
|
||||
logger.info(Print.outOfStock(link, store, true));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
const captchaHandle = await page.$(store.labels.captcha.container);
|
||||
const captchaContent = await page.evaluate(element => element.textContent, captchaHandle);
|
||||
if (store.labels.bannedSeller) {
|
||||
if (await pageIncludesLabels(page, store.labels.bannedSeller, baseOptions)) {
|
||||
logger.warn(Print.bannedSeller(link, store, true));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return includesLabels(captchaContent, store.labels.captcha.text);
|
||||
if (store.labels.maxPrice) {
|
||||
let price;
|
||||
let maxPrice = 0;
|
||||
switch (link.series) {
|
||||
case '3070':
|
||||
price = await cardPrice(page, store.labels.maxPrice, config.store.maxPrice.series['3070'], baseOptions);
|
||||
maxPrice = config.store.maxPrice.series['3070'];
|
||||
break;
|
||||
case '3080':
|
||||
price = await cardPrice(page, store.labels.maxPrice, config.store.maxPrice.series['3080'], baseOptions);
|
||||
maxPrice = config.store.maxPrice.series['3080'];
|
||||
break;
|
||||
case '3090':
|
||||
price = await cardPrice(page, store.labels.maxPrice, config.store.maxPrice.series['3090'], baseOptions);
|
||||
maxPrice = config.store.maxPrice.series['3090'];
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (price) {
|
||||
logger.info(Print.maxPrice(link, store, price, maxPrice, true));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (store.labels.captcha) {
|
||||
if (await pageIncludesLabels(page, store.labels.captcha, baseOptions)) {
|
||||
logger.warn(Print.captcha(link, store, true));
|
||||
await delay(getSleepTime(store));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Do API inventory validation in realtime (no cache) if available
|
||||
if (store.realTimeInventoryLookup !== undefined && link.itemNumber !== undefined) {
|
||||
return store.realTimeInventoryLookup(link.itemNumber);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
export async function tryLookupAndLoop(browser: Browser, store: Store) {
|
||||
Logger.debug(`[${store.name}] Starting lookup...`);
|
||||
try {
|
||||
if (Config.page.inStockWaitTime && inStock[store.name]) {
|
||||
Logger.info(`[${store.name}] Has stock, waiting before trying to lookup again...`);
|
||||
} else {
|
||||
await lookup(browser, store);
|
||||
}
|
||||
} catch (error) {
|
||||
Logger.error(error);
|
||||
if (!browser.isConnected()) {
|
||||
logger.debug(`[${store.name}] Ending this loop as browser is disposed...`);
|
||||
return;
|
||||
}
|
||||
|
||||
const sleepTime = getSleepTime();
|
||||
Logger.debug(`[${store.name}] Lookup done, next one in ${sleepTime} ms`);
|
||||
if (store.linksBuilder) {
|
||||
const lastRunTime = linkBuilderLastRunTimes[store.name] ?? -1;
|
||||
const ttl = store.linksBuilder.ttl ?? Number.MAX_SAFE_INTEGER;
|
||||
if (lastRunTime === -1 || (Date.now() - lastRunTime) > ttl) {
|
||||
try {
|
||||
await fetchLinks(store, browser);
|
||||
linkBuilderLastRunTimes[store.name] = Date.now();
|
||||
} catch (error) {
|
||||
logger.error(error.message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
logger.debug(`[${store.name}] Starting lookup...`);
|
||||
try {
|
||||
await lookup(browser, store);
|
||||
} catch (error) {
|
||||
logger.error(error);
|
||||
}
|
||||
|
||||
const sleepTime = getSleepTime(store);
|
||||
logger.debug(`[${store.name}] Lookup done, next one in ${sleepTime} ms`);
|
||||
setTimeout(tryLookupAndLoop, sleepTime, browser, store);
|
||||
}
|
||||
|
||||
@@ -9,6 +9,10 @@ export const Adorama: Store = {
|
||||
inStock: {
|
||||
container: '.buy-section.purchase',
|
||||
text: ['add to cart']
|
||||
},
|
||||
maxPrice: {
|
||||
container: '.your-price',
|
||||
euroFormat: false
|
||||
}
|
||||
},
|
||||
links: [
|
||||
@@ -68,9 +72,57 @@ export const Adorama: Store = {
|
||||
},
|
||||
{
|
||||
brand: 'pny',
|
||||
model: 'xlr8 rbg',
|
||||
model: 'xlr8 rgb',
|
||||
series: '3080',
|
||||
url: 'https://www.adorama.com/png30801tfxb.html'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'rog strix oc',
|
||||
series: '3080',
|
||||
url: 'https://www.adorama.com/asrx3080o10g.html'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'tuf oc',
|
||||
series: '3080',
|
||||
url: 'https://www.adorama.com/astr3080o10g.html'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'tuf',
|
||||
series: '3080',
|
||||
url: 'https://www.adorama.com/astrx308010g.html'
|
||||
},
|
||||
{
|
||||
brand: 'msi',
|
||||
model: 'gaming x trio',
|
||||
series: '3090',
|
||||
url: 'https://www.adorama.com/msig390gxt24.html'
|
||||
},
|
||||
{
|
||||
brand: 'msi',
|
||||
model: 'ventus 3x oc',
|
||||
series: '3090',
|
||||
url: 'https://www.adorama.com/msig39v3x24c.html'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'tuf',
|
||||
series: '3090',
|
||||
url: 'https://www.adorama.com/asrtx309024g.html'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'tuf oc',
|
||||
series: '3090',
|
||||
url: 'https://www.adorama.com/ast3090o24g.html'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'rog strix oc',
|
||||
series: '3090',
|
||||
url: 'https://www.adorama.com/asrx3090o24g.html'
|
||||
}
|
||||
],
|
||||
name: 'adorama'
|
||||
|
||||
@@ -0,0 +1,172 @@
|
||||
import {Store} from './store';
|
||||
|
||||
export const AlternateNL: Store = {
|
||||
labels: {
|
||||
inStock: {
|
||||
container: '.stockStatus',
|
||||
text: ['Direct leverbaar']
|
||||
},
|
||||
maxPrice: {
|
||||
container: 'div.price > span',
|
||||
euroFormat: true
|
||||
},
|
||||
outOfStock: {
|
||||
container: '.stockStatus',
|
||||
text: ['Levertermijn onbekend', 'pre-order']
|
||||
}
|
||||
},
|
||||
links: [
|
||||
{
|
||||
brand: 'test:brand',
|
||||
model: 'test:model',
|
||||
series: 'test:series',
|
||||
url: 'https://www.alternate.nl/product/1516616'
|
||||
},
|
||||
{
|
||||
brand: 'gigabyte',
|
||||
model: 'eagle oc',
|
||||
series: '3080',
|
||||
url: 'https://www.alternate.nl/product/1672756'
|
||||
},
|
||||
{
|
||||
brand: 'msi',
|
||||
model: 'ventus 3x oc',
|
||||
series: '3080',
|
||||
url: 'https://www.alternate.nl/product/1672345'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'tuf gaming',
|
||||
series: '3080',
|
||||
url: 'https://www.alternate.nl/product/1672251'
|
||||
},
|
||||
{
|
||||
brand: 'gigabyte',
|
||||
model: 'gaming oc',
|
||||
series: '3080',
|
||||
url: 'https://www.alternate.nl/product/1672753'
|
||||
},
|
||||
{
|
||||
brand: 'msi',
|
||||
model: 'gaming x trio',
|
||||
series: '3080',
|
||||
url: 'https://www.alternate.nl/product/1672343'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'tuf oc gaming',
|
||||
series: '3080',
|
||||
url: 'https://www.alternate.nl/product/1672634'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'rog strix oc gaming',
|
||||
series: '3080',
|
||||
url: 'https://www.alternate.nl/product/1672867'
|
||||
},
|
||||
{
|
||||
brand: 'evga',
|
||||
model: 'xc3 black gaming',
|
||||
series: '3080',
|
||||
url: 'https://www.alternate.nl/product/1673512'
|
||||
},
|
||||
{
|
||||
brand: 'zotac',
|
||||
model: 'trinity',
|
||||
series: '3080',
|
||||
url: 'https://www.alternate.nl/product/1672612'
|
||||
},
|
||||
{
|
||||
brand: 'evga',
|
||||
model: 'xc3 ultra gaming',
|
||||
series: '3080',
|
||||
url: 'https://www.alternate.nl/product/1674164'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'rog strix gaming',
|
||||
series: '3080',
|
||||
url: 'https://www.alternate.nl/product/1672868'
|
||||
},
|
||||
{
|
||||
brand: 'palit',
|
||||
model: 'gaming pro oc',
|
||||
series: '3080',
|
||||
url: 'https://www.alternate.nl/product/1673431'
|
||||
},
|
||||
{
|
||||
brand: 'zotac',
|
||||
model: 'trinity oc',
|
||||
series: '3080',
|
||||
url: 'https://www.alternate.nl/product/1677989'
|
||||
},
|
||||
{
|
||||
brand: 'gigabyte',
|
||||
model: 'vision oc',
|
||||
series: '3080',
|
||||
url: 'https://www.alternate.nl/product/1681134'
|
||||
},
|
||||
{
|
||||
brand: 'evga',
|
||||
model: 'xc3 gaming',
|
||||
series: '3080',
|
||||
url: 'https://www.alternate.nl/product/1673520'
|
||||
},
|
||||
{
|
||||
brand: 'gainward',
|
||||
model: 'phoenix gs',
|
||||
series: '3080',
|
||||
url: 'https://www.alternate.nl/product/1673442'
|
||||
},
|
||||
{
|
||||
brand: 'inno3d',
|
||||
model: 'ichill x3',
|
||||
series: '3080',
|
||||
url: 'https://www.alternate.nl/product/1673136'
|
||||
},
|
||||
{
|
||||
brand: 'evga',
|
||||
model: 'ftw3 ultra gaming',
|
||||
series: '3080',
|
||||
url: 'https://www.alternate.nl/product/1673524'
|
||||
},
|
||||
{
|
||||
brand: 'gigabyte',
|
||||
model: 'aorus master',
|
||||
series: '3080',
|
||||
url: 'https://www.alternate.nl/product/1680168'
|
||||
},
|
||||
{
|
||||
brand: 'evga',
|
||||
model: 'ftw3 gaming',
|
||||
series: '3080',
|
||||
url: 'https://www.alternate.nl/product/1673517'
|
||||
},
|
||||
{
|
||||
brand: 'zotac',
|
||||
model: 'amp holo',
|
||||
series: '3080',
|
||||
url: 'https://www.alternate.nl/product/1677985'
|
||||
},
|
||||
{
|
||||
brand: 'zotac',
|
||||
model: 'amp extreme holo',
|
||||
series: '3080',
|
||||
url: 'https://www.alternate.nl/product/1677982'
|
||||
},
|
||||
{
|
||||
brand: 'inno3d',
|
||||
model: 'twin x2 oc',
|
||||
series: '3080',
|
||||
url: 'https://www.alternate.nl/product/1673137'
|
||||
},
|
||||
{
|
||||
brand: 'inno3d',
|
||||
model: 'ichill x4',
|
||||
series: '3080',
|
||||
url: 'https://www.alternate.nl/product/1673134'
|
||||
}
|
||||
],
|
||||
name: 'alternate-nl'
|
||||
};
|
||||
|
||||
@@ -0,0 +1,321 @@
|
||||
import {Store} from './store';
|
||||
|
||||
export const Alternate: Store = {
|
||||
labels: {
|
||||
inStock: {
|
||||
container: '.stockStatus',
|
||||
text: ['auf lager', 'ware neu eingetroffen', 'in kürze versandfertig', 'ware im zulauf']
|
||||
},
|
||||
maxPrice: {
|
||||
container: 'div.price > span',
|
||||
euroFormat: true
|
||||
},
|
||||
outOfStock: {
|
||||
container: '.stockStatus',
|
||||
text: ['liefertermin unbekannt']
|
||||
}
|
||||
},
|
||||
links: [
|
||||
{
|
||||
brand: 'test:brand',
|
||||
model: 'test:model',
|
||||
series: 'test:series',
|
||||
url: 'https://www.alternate.de/product/1516616'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'rog strix',
|
||||
series: '3080',
|
||||
url: 'https://www.alternate.de/product/1672868'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'rog strix oc',
|
||||
series: '3080',
|
||||
url: 'https://www.alternate.de/product/1672867'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'tuf',
|
||||
series: '3080',
|
||||
url: 'https://www.alternate.de/product/1672251'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'tuf oc',
|
||||
series: '3080',
|
||||
url: 'https://www.alternate.de/product/1672634'
|
||||
},
|
||||
{
|
||||
brand: 'evga',
|
||||
model: 'ftw3',
|
||||
series: '3080',
|
||||
url: 'https://www.alternate.de/product/1673517'
|
||||
},
|
||||
{
|
||||
brand: 'evga',
|
||||
model: 'ftw3 ultra',
|
||||
series: '3080',
|
||||
url: 'https://www.alternate.de/product/1673524'
|
||||
},
|
||||
{
|
||||
brand: 'evga',
|
||||
model: 'xc3 black',
|
||||
series: '3080',
|
||||
url: 'https://www.alternate.de/product/1673512'
|
||||
},
|
||||
{
|
||||
brand: 'evga',
|
||||
model: 'xc3',
|
||||
series: '3080',
|
||||
url: 'https://www.alternate.de/product/1673520'
|
||||
},
|
||||
{
|
||||
brand: 'evga',
|
||||
model: 'xc3 ultra',
|
||||
series: '3080',
|
||||
url: 'https://www.alternate.de/product/1674164'
|
||||
},
|
||||
{
|
||||
brand: 'gainward',
|
||||
model: 'phantom gs',
|
||||
series: '3080',
|
||||
url: 'https://www.alternate.de/product/1688597'
|
||||
},
|
||||
{
|
||||
brand: 'gainward',
|
||||
model: 'phoenix gs',
|
||||
series: '3080',
|
||||
url: 'https://www.alternate.de/product/1673442'
|
||||
},
|
||||
{
|
||||
brand: 'gigabyte',
|
||||
model: 'aorus master',
|
||||
series: '3080',
|
||||
url: 'https://www.alternate.de/product/1680168'
|
||||
},
|
||||
{
|
||||
brand: 'gigabyte',
|
||||
model: 'aorus xtreme',
|
||||
series: '3080',
|
||||
url: 'https://www.alternate.de/product/1680168'
|
||||
},
|
||||
{
|
||||
brand: 'gigabyte',
|
||||
model: 'eagle oc',
|
||||
series: '3080',
|
||||
url: 'https://www.alternate.de/product/1672756'
|
||||
},
|
||||
{
|
||||
brand: 'gigabyte',
|
||||
model: 'gaming oc',
|
||||
series: '3080',
|
||||
url: 'https://www.alternate.de/product/1672753'
|
||||
},
|
||||
{
|
||||
brand: 'gigabyte',
|
||||
model: 'vision oc',
|
||||
series: '3080',
|
||||
url: 'https://www.alternate.de/product/1681134'
|
||||
},
|
||||
{
|
||||
brand: 'inno3d',
|
||||
model: 'ichill x3',
|
||||
series: '3080',
|
||||
url: 'https://www.alternate.de/product/1673136'
|
||||
},
|
||||
{
|
||||
brand: 'inno3d',
|
||||
model: 'ichill x4',
|
||||
series: '3080',
|
||||
url: 'https://www.alternate.de/product/1673134'
|
||||
},
|
||||
{
|
||||
brand: 'inno3d',
|
||||
model: 'twin x2 oc',
|
||||
series: '3080',
|
||||
url: 'https://www.alternate.de/product/1673137'
|
||||
},
|
||||
{
|
||||
brand: 'msi',
|
||||
model: 'gaming x trio',
|
||||
series: '3080',
|
||||
url: 'https://www.alternate.de/product/1672343'
|
||||
},
|
||||
{
|
||||
brand: 'msi',
|
||||
model: 'ventus 3x oc',
|
||||
series: '3080',
|
||||
url: 'https://www.alternate.de/product/1672345'
|
||||
},
|
||||
{
|
||||
brand: 'palit',
|
||||
model: 'gamerock oc',
|
||||
series: '3080',
|
||||
url: 'https://www.alternate.de/product/1688594'
|
||||
},
|
||||
{
|
||||
brand: 'palit',
|
||||
model: 'gaming pro oc',
|
||||
series: '3080',
|
||||
url: 'https://www.alternate.de/product/1673431'
|
||||
},
|
||||
{
|
||||
brand: 'zotac',
|
||||
model: 'amp extreme holo',
|
||||
series: '3080',
|
||||
url: 'https://www.alternate.de/product/1677982'
|
||||
},
|
||||
{
|
||||
brand: 'zotac',
|
||||
model: 'amp holo',
|
||||
series: '3080',
|
||||
url: 'https://www.alternate.de/product/1677985'
|
||||
},
|
||||
{
|
||||
brand: 'zotac',
|
||||
model: 'trinity oc',
|
||||
series: '3080',
|
||||
url: 'https://www.alternate.de/product/1677989'
|
||||
},
|
||||
{
|
||||
brand: 'zotac',
|
||||
model: 'trinity',
|
||||
series: '3080',
|
||||
url: 'https://www.alternate.de/product/1672612'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'rog strix',
|
||||
series: '3090',
|
||||
url: 'https://www.alternate.de/product/1672870'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'rog strix oc',
|
||||
series: '3090',
|
||||
url: 'https://www.alternate.de/product/1672872'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'tuf',
|
||||
series: '3090',
|
||||
url: 'https://www.alternate.de/product/1672259'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'tuf oc',
|
||||
series: '3090',
|
||||
url: 'https://www.alternate.de/product/1672629'
|
||||
},
|
||||
{
|
||||
brand: 'evga',
|
||||
model: 'ftw3',
|
||||
series: '3090',
|
||||
url: 'https://www.alternate.de/product/1673530'
|
||||
},
|
||||
{
|
||||
brand: 'evga',
|
||||
model: 'ftw3 ultra',
|
||||
series: '3090',
|
||||
url: 'https://www.alternate.de/product/1673531'
|
||||
},
|
||||
{
|
||||
brand: 'evga',
|
||||
model: 'xc3 black',
|
||||
series: '3090',
|
||||
url: 'https://www.alternate.de/product/1673521'
|
||||
},
|
||||
{
|
||||
brand: 'evga',
|
||||
model: 'xc3',
|
||||
series: '3090',
|
||||
url: 'https://www.alternate.de/product/1673525'
|
||||
},
|
||||
{
|
||||
brand: 'evga',
|
||||
model: 'xc3 ultra',
|
||||
series: '3090',
|
||||
url: 'https://www.alternate.de/product/1673529'
|
||||
},
|
||||
{
|
||||
brand: 'gainward',
|
||||
model: 'phoenix gs',
|
||||
series: '3090',
|
||||
url: 'https://www.alternate.de/product/1673440'
|
||||
},
|
||||
{
|
||||
brand: 'gigabyte',
|
||||
model: 'aorus xtreme',
|
||||
series: '3090',
|
||||
url: 'https://www.alternate.de/product/1680670'
|
||||
},
|
||||
{
|
||||
brand: 'gigabyte',
|
||||
model: 'aorus master',
|
||||
series: '3090',
|
||||
url: 'https://www.alternate.de/product/1687793'
|
||||
},
|
||||
{
|
||||
brand: 'gigabyte',
|
||||
model: 'eagle oc',
|
||||
series: '3090',
|
||||
url: 'https://www.alternate.de/product/1672744'
|
||||
},
|
||||
{
|
||||
brand: 'gigabyte',
|
||||
model: 'gaming oc',
|
||||
series: '3090',
|
||||
url: 'https://www.alternate.de/product/1672749'
|
||||
},
|
||||
{
|
||||
brand: 'gigabyte',
|
||||
model: 'turbo',
|
||||
series: '3090',
|
||||
url: 'https://www.alternate.de/product/1687703'
|
||||
},
|
||||
{
|
||||
brand: 'inno3d',
|
||||
model: 'gaming x3',
|
||||
series: '3090',
|
||||
url: 'https://www.alternate.de/product/1673131'
|
||||
},
|
||||
{
|
||||
brand: 'inno3d',
|
||||
model: 'ichill x3',
|
||||
series: '3090',
|
||||
url: 'https://www.alternate.de/product/1673135'
|
||||
},
|
||||
{
|
||||
brand: 'inno3d',
|
||||
model: 'ichill x4',
|
||||
series: '3090',
|
||||
url: 'https://www.alternate.de/product/1673129'
|
||||
},
|
||||
{
|
||||
brand: 'msi',
|
||||
model: 'gaming x trio',
|
||||
series: '3090',
|
||||
url: 'https://www.alternate.de/product/1672341'
|
||||
},
|
||||
{
|
||||
brand: 'msi',
|
||||
model: 'ventus 3x oc',
|
||||
series: '3090',
|
||||
url: 'https://www.alternate.de/product/1672346'
|
||||
},
|
||||
{
|
||||
brand: 'palit',
|
||||
model: 'gaming pro oc',
|
||||
series: '3090',
|
||||
url: 'https://www.alternate.de/product/1673434'
|
||||
},
|
||||
{
|
||||
brand: 'zotac',
|
||||
model: 'trinity',
|
||||
series: '3090',
|
||||
url: 'https://www.alternate.de/product/1672611'
|
||||
}
|
||||
],
|
||||
name: 'alternate'
|
||||
};
|
||||
@@ -9,6 +9,10 @@ export const AmazonCa: Store = {
|
||||
inStock: {
|
||||
container: '#desktop_buybox',
|
||||
text: ['add to cart']
|
||||
},
|
||||
maxPrice: {
|
||||
container: 'span[class*="PriceString"]',
|
||||
euroFormat: false
|
||||
}
|
||||
},
|
||||
links: [
|
||||
@@ -24,6 +28,12 @@ export const AmazonCa: Store = {
|
||||
series: '3080',
|
||||
url: 'https://www.amazon.ca/dp/B08HR7SV3M'
|
||||
},
|
||||
{
|
||||
brand: 'msi',
|
||||
model: 'ventus 3x oc',
|
||||
series: '3080',
|
||||
url: 'https://www.amazon.ca/dp/B08HR5SXPS'
|
||||
},
|
||||
{
|
||||
brand: 'evga',
|
||||
model: 'ftw3',
|
||||
@@ -78,11 +88,47 @@ export const AmazonCa: Store = {
|
||||
series: '3080',
|
||||
url: 'https://www.amazon.ca/dp/B08HH5WF97'
|
||||
},
|
||||
{
|
||||
brand: 'zotac',
|
||||
model: 'trinity',
|
||||
series: '3080',
|
||||
url: 'https://www.amazon.ca/dp/B08HJNKT3P'
|
||||
},
|
||||
{
|
||||
brand: 'zotac',
|
||||
model: 'trinity',
|
||||
series: '3090',
|
||||
url: 'https://www.amazon.ca/dp/B08HJQ182D'
|
||||
},
|
||||
{
|
||||
brand: 'msi',
|
||||
model: 'ventus 3x oc',
|
||||
series: '3080',
|
||||
url: 'https://www.amazon.ca/dp/B08HR5SXPS'
|
||||
series: '3090',
|
||||
url: 'https://www.amazon.ca/dp/B08HR9D2JS'
|
||||
},
|
||||
{
|
||||
brand: 'gigabyte',
|
||||
model: 'gaming oc',
|
||||
series: '3090',
|
||||
url: 'https://www.amazon.ca/dp/B08HJRF2CN'
|
||||
},
|
||||
{
|
||||
brand: 'gigabyte',
|
||||
model: 'eagle oc',
|
||||
series: '3090',
|
||||
url: 'https://www.amazon.ca/dp/B08HJPDJTY'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'tuf',
|
||||
series: '3090',
|
||||
url: 'https://www.amazon.ca/dp/B08HJGNJ81'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'tuf oc',
|
||||
series: '3090',
|
||||
url: 'https://www.amazon.ca/dp/B08HJLLF7G'
|
||||
}
|
||||
],
|
||||
name: 'amazon-ca'
|
||||
|
||||
+283
-26
@@ -1,14 +1,19 @@
|
||||
import {Store} from './store';
|
||||
|
||||
export const AmazonDe: Store = {
|
||||
backoffStatusCodes: [403, 429, 503],
|
||||
labels: {
|
||||
captcha: {
|
||||
container: 'body',
|
||||
text: ['geben sie die unten angezeigten zeichen ein']
|
||||
text: ['geben sie die unten angezeigten zeichen ein', 'geben sie die zeichen unten ein']
|
||||
},
|
||||
inStock: {
|
||||
container: '#desktop_buybox',
|
||||
text: ['in den einkaufswagen']
|
||||
},
|
||||
maxPrice: {
|
||||
container: 'span[class*="PriceString"]',
|
||||
euroFormat: true
|
||||
}
|
||||
},
|
||||
links: [
|
||||
@@ -16,37 +21,31 @@ export const AmazonDe: Store = {
|
||||
brand: 'test:brand',
|
||||
model: 'test:model',
|
||||
series: 'test:series',
|
||||
url: 'https://www.amazon.com/dp/B07MQ36Z6L'
|
||||
url: 'https://www.amazon.de/dp/B083JX52VG/'
|
||||
},
|
||||
{
|
||||
brand: 'pny',
|
||||
model: 'xlr8',
|
||||
brand: 'asus',
|
||||
model: 'rog strix',
|
||||
series: '3080',
|
||||
url: 'https://www.amazon.de/dp/B08HBTJMLJ'
|
||||
url: 'https://www.amazon.de/dp/B08HN7VVLJ'
|
||||
},
|
||||
{
|
||||
brand: 'pny',
|
||||
model: 'xlr8-rgb',
|
||||
brand: 'asus',
|
||||
model: 'rog strix oc',
|
||||
series: '3080',
|
||||
url: 'https://www.amazon.de/dp/B08HBR7QBM'
|
||||
url: 'https://www.amazon.de/dp/B08HN6KYS3'
|
||||
},
|
||||
{
|
||||
brand: 'msi',
|
||||
model: 'gaming x trio',
|
||||
brand: 'asus',
|
||||
model: 'tuf',
|
||||
series: '3080',
|
||||
url: 'https://www.amazon.de/dp/B08HM4V2DH'
|
||||
url: 'https://www.amazon.de/dp/B08HN37VQK'
|
||||
},
|
||||
{
|
||||
brand: 'evga',
|
||||
model: 'ftw3 ultra',
|
||||
brand: 'asus',
|
||||
model: 'tuf oc',
|
||||
series: '3080',
|
||||
url: 'https://www.amazon.de/dp/B08HGYXP4C'
|
||||
},
|
||||
{
|
||||
brand: 'evga',
|
||||
model: 'xc3 ultra',
|
||||
series: '3080',
|
||||
url: 'https://www.amazon.de/dp/B08HJ9XFNM'
|
||||
url: 'https://www.amazon.de/dp/B08HN4DSTC'
|
||||
},
|
||||
{
|
||||
brand: 'evga',
|
||||
@@ -54,6 +53,12 @@ export const AmazonDe: Store = {
|
||||
series: '3080',
|
||||
url: 'https://www.amazon.de/dp/B08HGBYWQ6'
|
||||
},
|
||||
{
|
||||
brand: 'evga',
|
||||
model: 'ftw3 ultra',
|
||||
series: '3080',
|
||||
url: 'https://www.amazon.de/dp/B08HGYXP4C'
|
||||
},
|
||||
{
|
||||
brand: 'evga',
|
||||
model: 'xc3',
|
||||
@@ -67,10 +72,16 @@ export const AmazonDe: Store = {
|
||||
url: 'https://www.amazon.de/dp/B08HH1BMQQ'
|
||||
},
|
||||
{
|
||||
brand: 'gigabyte',
|
||||
model: 'gaming oc',
|
||||
brand: 'evga',
|
||||
model: 'xc3 ultra',
|
||||
series: '3080',
|
||||
url: 'https://www.amazon.de/dp/B08HLZXHZY'
|
||||
url: 'https://www.amazon.de/dp/B08HJ9XFNM'
|
||||
},
|
||||
{
|
||||
brand: 'gigabyte',
|
||||
model: 'aorus master',
|
||||
series: '3080',
|
||||
url: 'https://www.amazon.de/dp/B08KHLDS72'
|
||||
},
|
||||
{
|
||||
brand: 'gigabyte',
|
||||
@@ -79,10 +90,28 @@ export const AmazonDe: Store = {
|
||||
url: 'https://www.amazon.de/dp/B08HHZVZ3N'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'tuf',
|
||||
brand: 'gigabyte',
|
||||
model: 'gaming oc',
|
||||
series: '3080',
|
||||
url: 'https://www.amazon.de/dp/B08HN4DSTC'
|
||||
url: 'https://www.amazon.de/dp/B08HLZXHZY'
|
||||
},
|
||||
{
|
||||
brand: 'gigabyte',
|
||||
model: 'vision oc',
|
||||
series: '3080',
|
||||
url: 'https://www.amazon.de/dp/B08KH7RL89'
|
||||
},
|
||||
{
|
||||
brand: 'inno3d',
|
||||
model: 'twin x2 oc',
|
||||
series: '3080',
|
||||
url: 'https://www.amazon.de/dp/B08JD6QPXD'
|
||||
},
|
||||
{
|
||||
brand: 'msi',
|
||||
model: 'gaming x trio',
|
||||
series: '3080',
|
||||
url: 'https://www.amazon.de/dp/B08HM4V2DH'
|
||||
},
|
||||
{
|
||||
brand: 'msi',
|
||||
@@ -90,11 +119,239 @@ export const AmazonDe: Store = {
|
||||
series: '3080',
|
||||
url: 'https://www.amazon.de/dp/B08HM4M621'
|
||||
},
|
||||
{
|
||||
brand: 'palit',
|
||||
model: 'gaming pro',
|
||||
series: '3080',
|
||||
url: 'https://www.amazon.de/dp/B08JCVWTQY'
|
||||
},
|
||||
{
|
||||
brand: 'palit',
|
||||
model: 'gaming pro oc',
|
||||
series: '3080',
|
||||
url: 'https://www.amazon.de/dp/B08JCKYYL8'
|
||||
},
|
||||
{
|
||||
brand: 'zotac',
|
||||
model: 'trinity',
|
||||
series: '3080',
|
||||
url: 'https://www.amazon.de/dp/B08HR1NPPQ'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'rog strix',
|
||||
series: '3090',
|
||||
url: 'https://www.amazon.de/dp/B08HN642LY'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'rog strix oc',
|
||||
series: '3090',
|
||||
url: 'https://www.amazon.de/dp/B08HN51T8Q'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'tuf',
|
||||
series: '3090',
|
||||
url: 'https://www.amazon.de/dp/B08HN4FLFJ'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'tuf oc',
|
||||
series: '3090',
|
||||
url: 'https://www.amazon.de/dp/B08HN5B8FJ'
|
||||
},
|
||||
{
|
||||
brand: 'evga',
|
||||
model: 'ftw3',
|
||||
series: '3090',
|
||||
url: 'https://www.amazon.de/dp/B08HGFNPJQ'
|
||||
},
|
||||
{
|
||||
brand: 'evga',
|
||||
model: 'ftw3',
|
||||
series: '3090',
|
||||
url: 'https://www.amazon.de/dp/B08J5NMDP7'
|
||||
},
|
||||
{
|
||||
brand: 'evga',
|
||||
model: 'ftw3 ultra',
|
||||
series: '3090',
|
||||
url: 'https://www.amazon.de/dp/B08HGS1SXH'
|
||||
},
|
||||
{
|
||||
brand: 'evga',
|
||||
model: 'xc3',
|
||||
series: '3090',
|
||||
url: 'https://www.amazon.de/dp/B08HGZ4XSZ'
|
||||
},
|
||||
{
|
||||
brand: 'evga',
|
||||
model: 'xc3 black',
|
||||
series: '3090',
|
||||
url: 'https://www.amazon.de/dp/B08HGKQ527'
|
||||
},
|
||||
{
|
||||
brand: 'evga',
|
||||
model: 'xc3 ultra',
|
||||
series: '3090',
|
||||
url: 'https://www.amazon.de/dp/B08HGTNDL4'
|
||||
},
|
||||
{
|
||||
brand: 'gigabyte',
|
||||
model: 'aorus master',
|
||||
series: '3090',
|
||||
url: 'https://www.amazon.de/dp/B08KH7R4FQ'
|
||||
},
|
||||
{
|
||||
brand: 'gigabyte',
|
||||
model: 'eagle oc',
|
||||
series: '3090',
|
||||
url: 'https://www.amazon.de/dp/B08HJPDJTY'
|
||||
},
|
||||
{
|
||||
brand: 'gigabyte',
|
||||
model: 'turbo',
|
||||
series: '3090',
|
||||
url: 'https://www.amazon.de/dp/B08KHKDTSJ'
|
||||
},
|
||||
{
|
||||
brand: 'gigabyte',
|
||||
model: 'gaming oc',
|
||||
series: '3090',
|
||||
url: 'https://www.amazon.de/dp/B08HJRF2CN'
|
||||
},
|
||||
{
|
||||
brand: 'msi',
|
||||
model: 'gaming x trio',
|
||||
series: '3090',
|
||||
url: 'https://www.amazon.de/dp/B08HRBW6VB'
|
||||
},
|
||||
{
|
||||
brand: 'msi',
|
||||
model: 'ventus 3x oc',
|
||||
series: '3090',
|
||||
url: 'https://www.amazon.de/dp/B08HM661YM'
|
||||
},
|
||||
{
|
||||
brand: 'palit',
|
||||
model: 'gaming pro',
|
||||
series: '3090',
|
||||
url: 'https://www.amazon.de/dp/B08JQQ1VD1'
|
||||
},
|
||||
{
|
||||
brand: 'nvidia',
|
||||
model: 'founders edition',
|
||||
series: '3090',
|
||||
url: 'https://www.amazon.de/dp/B08HR6ZBYJ'
|
||||
},
|
||||
{
|
||||
brand: 'zotac',
|
||||
model: 'trinity',
|
||||
series: '3090',
|
||||
url: 'https://www.amazon.de/dp/B08HJQ182D'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'dual',
|
||||
series: '3070',
|
||||
url: 'https://www.amazon.de/dp/B08HSJ1622'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'dual oc',
|
||||
series: '3070',
|
||||
url: 'https://www.amazon.de/dp/B08KHFZN9P'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'rog strix',
|
||||
series: '3070',
|
||||
url: 'https://www.amazon.de/dp/B08HT7PR9Y'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'rog strix oc',
|
||||
series: '3070',
|
||||
url: 'https://www.amazon.de/dp/B08L8JNTXQ'
|
||||
},
|
||||
{
|
||||
brand: 'msi',
|
||||
model: 'ventus 2x oc',
|
||||
series: '3070',
|
||||
url: 'https://www.amazon.de/dp/B08KWPDXJZ'
|
||||
},
|
||||
{
|
||||
brand: 'msi',
|
||||
model: 'ventus 3x oc',
|
||||
series: '3070',
|
||||
url: 'https://www.amazon.de/dp/B08L6PCZTR'
|
||||
},
|
||||
{
|
||||
brand: 'msi',
|
||||
model: 'gaming x trio',
|
||||
series: '3070',
|
||||
url: 'https://www.amazon.de/dp/B08KWN2LZG'
|
||||
},
|
||||
{
|
||||
brand: 'gigabyte',
|
||||
model: 'vision oc',
|
||||
series: '3070',
|
||||
url: 'https://www.amazon.de/dp/B08M13DXSZ'
|
||||
},
|
||||
{
|
||||
brand: 'gigabyte',
|
||||
model: 'gaming oc',
|
||||
series: '3070',
|
||||
url: 'https://www.amazon.de/dp/B08KHL21CV'
|
||||
},
|
||||
{
|
||||
brand: 'gigabyte',
|
||||
model: 'eagle oc',
|
||||
series: '3070',
|
||||
url: 'https://www.amazon.de/dp/B08KHL2J5X'
|
||||
},
|
||||
{
|
||||
brand: 'evga',
|
||||
model: 'xc3 black',
|
||||
series: '3070',
|
||||
url: 'https://www.amazon.de/dp/B08L3QCZKZ'
|
||||
},
|
||||
{
|
||||
brand: 'evga',
|
||||
model: 'xc3',
|
||||
series: '3070',
|
||||
url: 'https://www.amazon.de/dp/B08L3QZP7W'
|
||||
},
|
||||
{
|
||||
brand: 'evga',
|
||||
model: 'xc3 ultra',
|
||||
series: '3070',
|
||||
url: 'https://www.amazon.de/dp/B08L3Q41SM'
|
||||
},
|
||||
{
|
||||
brand: 'zotac',
|
||||
model: 'twin edge',
|
||||
series: '3070',
|
||||
url: 'https://www.amazon.de/dp/B08HRBR7K9'
|
||||
},
|
||||
{
|
||||
brand: 'zotac',
|
||||
model: 'twin edge oc',
|
||||
series: '3070',
|
||||
url: 'https://www.amazon.de/dp/B08LBVNKT1'
|
||||
},
|
||||
{
|
||||
brand: 'pny',
|
||||
model: 'dual fan',
|
||||
series: '3070',
|
||||
url: 'https://www.amazon.de/dp/B08HBF5L3K'
|
||||
},
|
||||
{
|
||||
brand: 'pny',
|
||||
model: 'xlr8 rgb',
|
||||
series: '3070',
|
||||
url: 'https://www.amazon.de/dp/B08HBJB7YD'
|
||||
}
|
||||
],
|
||||
name: 'amazon-de'
|
||||
|
||||
@@ -0,0 +1,105 @@
|
||||
import {Store} from './store';
|
||||
|
||||
export const AmazonEs: Store = {
|
||||
labels: {
|
||||
captcha: {
|
||||
container: 'body',
|
||||
text: ['introduzca los caracteres que ve a continuación']
|
||||
},
|
||||
inStock: {
|
||||
container: '#desktop_buybox',
|
||||
text: ['añadir a la cesta']
|
||||
},
|
||||
maxPrice: {
|
||||
container: 'span[class*="PriceString"]',
|
||||
euroFormat: true
|
||||
}
|
||||
},
|
||||
links: [
|
||||
{
|
||||
brand: 'test:brand',
|
||||
model: 'test:model',
|
||||
series: 'test:series',
|
||||
url: 'https://www.amazon.es/dp/B083JX52VG/'
|
||||
},
|
||||
{
|
||||
brand: 'msi',
|
||||
model: 'gaming x trio',
|
||||
series: '3080',
|
||||
url: 'https://www.amazon.es/dp/B08HM4V2DH'
|
||||
},
|
||||
{
|
||||
brand: 'evga',
|
||||
model: 'ftw3 ultra',
|
||||
series: '3080',
|
||||
url: 'https://www.amazon.es/dp/B08HGYXP4C'
|
||||
},
|
||||
{
|
||||
brand: 'evga',
|
||||
model: 'xc3 ultra',
|
||||
series: '3080',
|
||||
url: 'https://www.amazon.es/dp/B08HJ9XFNM'
|
||||
},
|
||||
{
|
||||
brand: 'evga',
|
||||
model: 'ftw3',
|
||||
series: '3080',
|
||||
url: 'https://www.amazon.es/dp/B08HGBYWQ6'
|
||||
},
|
||||
{
|
||||
brand: 'evga',
|
||||
model: 'xc3',
|
||||
series: '3080',
|
||||
url: 'https://www.amazon.es/dp/B08HGLN78Q'
|
||||
},
|
||||
{
|
||||
brand: 'evga',
|
||||
model: 'xc3 black',
|
||||
series: '3080',
|
||||
url: 'https://www.amazon.es/dp/B08HH1BMQQ'
|
||||
},
|
||||
{
|
||||
brand: 'gigabyte',
|
||||
model: 'gaming oc',
|
||||
series: '3080',
|
||||
url: 'https://www.amazon.es/dp/B08HLZXHZY'
|
||||
},
|
||||
{
|
||||
brand: 'gigabyte',
|
||||
model: 'eagle oc',
|
||||
series: '3080',
|
||||
url: 'https://www.amazon.es/dp/B08HHZVZ3N'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'tuf',
|
||||
series: '3080',
|
||||
url: 'https://www.amazon.es/dp/B08HN37VQK'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'tuf oc',
|
||||
series: '3080',
|
||||
url: 'https://www.amazon.es/dp/B08HN4DSTC'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'rog strix oc',
|
||||
series: '3080',
|
||||
url: 'https://www.amazon.es/dp/B08HN6KYS3'
|
||||
},
|
||||
{
|
||||
brand: 'msi',
|
||||
model: 'ventus 3x oc',
|
||||
series: '3080',
|
||||
url: 'https://www.amazon.es/dp/B08HM4M621'
|
||||
},
|
||||
{
|
||||
brand: 'zotac',
|
||||
model: 'trinity',
|
||||
series: '3080',
|
||||
url: 'https://www.amazon.es/dp/B08HR1NPPQ'
|
||||
}
|
||||
],
|
||||
name: 'amazon-es'
|
||||
};
|
||||
@@ -0,0 +1,67 @@
|
||||
import {Store} from './store';
|
||||
|
||||
export const AmazonNl: Store = {
|
||||
labels: {
|
||||
captcha: {
|
||||
container: 'body',
|
||||
text: ['voer de karakters in die u hieronder ziet']
|
||||
},
|
||||
inStock: {
|
||||
container: '#availability',
|
||||
text: ['op voorraad', 'verkrijgbaar vanaf', 'wordt gewoonlijk verzonden binnen', 'nog slechts']
|
||||
},
|
||||
maxPrice: {
|
||||
container: 'span[class*="PriceString"]',
|
||||
euroFormat: true
|
||||
},
|
||||
outOfStock: [
|
||||
{
|
||||
container: '#availability',
|
||||
text: ['tijdelijk niet']
|
||||
},
|
||||
{
|
||||
container: '#outOfStock',
|
||||
text: ['we weten niet of en wanneer dit item weer op voorraad is']
|
||||
}
|
||||
]
|
||||
},
|
||||
links: [
|
||||
{
|
||||
brand: 'test:brand',
|
||||
model: 'test:model',
|
||||
series: 'test:series',
|
||||
url: 'https://www.amazon.nl/dp/B083GGYNQ6'
|
||||
},
|
||||
{
|
||||
brand: 'msi',
|
||||
model: 'ventus 3x oc',
|
||||
series: '3080',
|
||||
url: 'https://www.amazon.nl/dp/B08HM4M621'
|
||||
},
|
||||
{
|
||||
brand: 'msi',
|
||||
model: 'gaming x trio',
|
||||
series: '3080',
|
||||
url: 'https://www.amazon.nl/dp/B08HM4V2DH'
|
||||
},
|
||||
{
|
||||
brand: 'evga',
|
||||
model: 'xc3 ultra',
|
||||
series: '3080',
|
||||
url: 'https://www.amazon.nl/dp/B08HJ9XFNM'
|
||||
},
|
||||
{
|
||||
brand: 'evga',
|
||||
model: 'xc3 black',
|
||||
series: '3080',
|
||||
url: 'https://www.amazon.nl/dp/B08HH1BMQQ'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'rog strix',
|
||||
series: '3080',
|
||||
url: 'https://www.amazon.nl/dp/B08HN7VVLJ'
|
||||
}
|
||||
],
|
||||
name: 'amazon-nl'
|
||||
};
|
||||
@@ -0,0 +1,95 @@
|
||||
import {Link, Store} from './store';
|
||||
import {logger} from '../../logger';
|
||||
import {parseCard} from './helpers/card';
|
||||
|
||||
export const AmazonUk: Store = {
|
||||
backoffStatusCodes: [403, 429, 503],
|
||||
labels: {
|
||||
captcha: {
|
||||
container: 'body',
|
||||
text: ['enter the characters you see below']
|
||||
},
|
||||
inStock: {
|
||||
container: '#availability',
|
||||
text: ['in stock']
|
||||
},
|
||||
maxPrice: {
|
||||
container: 'span[class*="PriceString"]'
|
||||
},
|
||||
outOfStock: [
|
||||
{
|
||||
container: '#availability',
|
||||
text: ['out of stock', 'unavailable']
|
||||
},
|
||||
{
|
||||
container: '#backInStock',
|
||||
text: ['unavailable']
|
||||
}
|
||||
]
|
||||
},
|
||||
links: [
|
||||
{
|
||||
brand: 'test:brand',
|
||||
cartUrl: 'https://www.amazon.co.uk/gp/aws/cart/add.html?ASIN.1=B081265T5Z&Quantity.1=1',
|
||||
model: 'test:model',
|
||||
series: 'test:series',
|
||||
url: 'https://www.amazon.co.uk/dp/B081265T5Z/'
|
||||
}
|
||||
],
|
||||
linksBuilder: {
|
||||
builder: (docElement, series) => {
|
||||
const productElements = docElement.find('.s-result-list .s-result-item[data-asin]');
|
||||
const links: Link[] = [];
|
||||
for (let i = 0; i < productElements.length; i++) {
|
||||
const productElement = productElements.eq(i);
|
||||
const asin = productElement.attr()['data-asin'];
|
||||
|
||||
if (!asin) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const url = `https://www.amazon.co.uk/dp/${asin}/`;
|
||||
const titleElement = productElement.find('.sg-col-inner h2 a.a-text-normal[href] span').first();
|
||||
const title = titleElement.text().trim();
|
||||
|
||||
if (!title || !new RegExp(`RTX.*${series}`, 'i').exec(title)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const card = parseCard(title);
|
||||
|
||||
if (card) {
|
||||
links.push({
|
||||
brand: card.brand as any,
|
||||
cartUrl: `https://www.amazon.co.uk/gp/aws/cart/add.html?ASIN.1=${asin}&Quantity.1=1`,
|
||||
model: card.model,
|
||||
series,
|
||||
url
|
||||
});
|
||||
} else {
|
||||
logger.error(`Failed to parse card: ${title}`);
|
||||
}
|
||||
}
|
||||
|
||||
return links;
|
||||
},
|
||||
ttl: 300000,
|
||||
urls: [
|
||||
{
|
||||
series: '3080',
|
||||
url: [
|
||||
'https://www.amazon.co.uk/s?k=%2B%22RTX+3080%22+-2080+-GTX&i=computers&rh=n%3A430500031%2Cp_n_availability%3A419162031&s=relevancerank&dc&qid=1601675291',
|
||||
'https://www.amazon.co.uk/s?k=%2B%22RTX+3080%22+-2080+-GTX&i=computers&rh=n%3A430500031%2Cp_n_availability%3A419162031&s=relevancerank&dc&qid=1601675594&page=2'
|
||||
]
|
||||
},
|
||||
{
|
||||
series: '3090',
|
||||
url: [
|
||||
'https://www.amazon.co.uk/s?k=%2B%22RTX+3090%22+-3080+-GTX&i=computers&rh=n%3A430500031%2Cp_n_availability%3A419162031&s=relevancerank&dc&qid=1601675291',
|
||||
'https://www.amazon.co.uk/s?k=%2B%22RTX+3090%22+-3080+-GTX&i=computers&rh=n%3A430500031%2Cp_n_availability%3A419162031&s=relevancerank&dc&qid=1601675594&page=2'
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
name: 'amazon-uk'
|
||||
};
|
||||
@@ -9,104 +9,193 @@ export const Amazon: Store = {
|
||||
inStock: {
|
||||
container: '#desktop_buybox',
|
||||
text: ['add to cart']
|
||||
},
|
||||
maxPrice: {
|
||||
container: 'span[class*="PriceString"]'
|
||||
}
|
||||
},
|
||||
links: [
|
||||
{
|
||||
brand: 'test:brand',
|
||||
cartUrl: 'https://www.amazon.com/gp/aws/cart/add.html?ASIN.1=B07TDN1SC5&Quantity.1=1',
|
||||
model: 'test:model',
|
||||
series: 'test:series',
|
||||
url: 'https://www.amazon.com/dp/B07MQ36Z6L'
|
||||
url: 'https://www.amazon.com/dp/B07TDN1SC5'
|
||||
},
|
||||
{
|
||||
brand: 'pny',
|
||||
cartUrl: 'https://www.amazon.com/gp/aws/cart/add.html?ASIN.1=B08HBR7QBM&Quantity.1=1',
|
||||
model: 'xlr8',
|
||||
series: '3080',
|
||||
url: 'https://www.amazon.com/dp/B08HBR7QBM'
|
||||
},
|
||||
{
|
||||
brand: 'pny',
|
||||
cartUrl: 'https://www.amazon.com/gp/aws/cart/add.html?ASIN.1=B08HBTJMLJ&Quantity.1=1',
|
||||
model: 'xlr8 rgb',
|
||||
series: '3080',
|
||||
url: 'https://www.amazon.com/dp/B08HBTJMLJ'
|
||||
},
|
||||
{
|
||||
brand: 'msi',
|
||||
cartUrl: 'https://www.amazon.com/gp/aws/cart/add.html?ASIN.1=B08HR7SV3M&Quantity.1=1',
|
||||
model: 'gaming x trio',
|
||||
series: '3080',
|
||||
url: 'https://www.amazon.com/dp/B08HR7SV3M'
|
||||
},
|
||||
{
|
||||
brand: 'evga',
|
||||
cartUrl: 'https://www.amazon.com/gp/aws/cart/add.html?ASIN.1=B08HR3Y5GQ&Quantity.1=1',
|
||||
model: 'ftw3 ultra',
|
||||
series: '3080',
|
||||
url: 'https://www.amazon.com/dp/B08HR3Y5GQ'
|
||||
},
|
||||
{
|
||||
brand: 'evga',
|
||||
cartUrl: 'https://www.amazon.com/gp/aws/cart/add.html?ASIN.1=B08HR55YB5&Quantity.1=1',
|
||||
model: 'xc3 ultra',
|
||||
series: '3080',
|
||||
url: 'https://www.amazon.com/dp/B08HR55YB5'
|
||||
},
|
||||
{
|
||||
brand: 'evga',
|
||||
cartUrl: 'https://www.amazon.com/gp/aws/cart/add.html?ASIN.1=B08HR3DPGW&Quantity.1=1',
|
||||
model: 'ftw3',
|
||||
series: '3080',
|
||||
url: 'https://www.amazon.com/dp/B08HR3DPGW'
|
||||
},
|
||||
{
|
||||
brand: 'evga',
|
||||
cartUrl: 'https://www.amazon.com/gp/aws/cart/add.html?ASIN.1=B08HR4RJ3Q&Quantity.1=1',
|
||||
model: 'xc3',
|
||||
series: '3080',
|
||||
url: 'https://www.amazon.com/dp/B08HR4RJ3Q'
|
||||
},
|
||||
{
|
||||
brand: 'evga',
|
||||
cartUrl: 'https://www.amazon.com/gp/aws/cart/add.html?ASIN.1=B08HR6FMF3&Quantity.1=1',
|
||||
model: 'xc3 black',
|
||||
series: '3080',
|
||||
url: 'https://www.amazon.com/dp/B08HR6FMF3'
|
||||
},
|
||||
{
|
||||
brand: 'gigabyte',
|
||||
cartUrl: 'https://www.amazon.com/gp/aws/cart/add.html?ASIN.1=B08HJTH61J&Quantity.1=1',
|
||||
model: 'gaming oc',
|
||||
series: '3080',
|
||||
url: 'https://www.amazon.com/dp/B08HJTH61J'
|
||||
},
|
||||
{
|
||||
brand: 'gigabyte',
|
||||
cartUrl: 'https://www.amazon.com/gp/aws/cart/add.html?ASIN.1=B08HJS2JLJ&Quantity.1=1',
|
||||
model: 'eagle oc',
|
||||
series: '3080',
|
||||
url: 'https://www.amazon.com/dp/B08HJS2JLJ'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
cartUrl: 'https://www.amazon.com/gp/aws/cart/add.html?ASIN.1=B08HH5WF97&Quantity.1=1',
|
||||
model: 'tuf oc',
|
||||
series: '3080',
|
||||
url: 'https://www.amazon.com/dp/B08HH5WF97'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
cartUrl: 'https://www.amazon.com/gp/aws/cart/add.html?ASIN.1=B08HHDP9DW&Quantity.1=1',
|
||||
model: 'tuf',
|
||||
series: '3080',
|
||||
url: 'https://www.amazon.com/dp/B08HHDP9DW'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'strix',
|
||||
cartUrl: 'https://www.amazon.com/gp/aws/cart/add.html?ASIN.1=B08J6F174Z&Quantity.1=1',
|
||||
model: 'rog strix oc',
|
||||
series: '3080',
|
||||
url: 'https://www.amazon.com/dp/B08J6F174Z'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
cartUrl: 'https://www.amazon.com/gp/aws/cart/add.html?ASIN.1=B08J6GMWCQ&Quantity.1=1',
|
||||
model: 'rog strix oc',
|
||||
series: '3090',
|
||||
url: 'https://www.amazon.com/dp/B08J6GMWCQ'
|
||||
},
|
||||
{
|
||||
brand: 'msi',
|
||||
cartUrl: 'https://www.amazon.com/gp/aws/cart/add.html?ASIN.1=B08HR5SXPS&Quantity.1=1',
|
||||
model: 'ventus 3x oc',
|
||||
series: '3080',
|
||||
url: 'https://www.amazon.com/dp/B08HR5SXPS'
|
||||
},
|
||||
{
|
||||
brand: 'zotac',
|
||||
cartUrl: 'https://www.amazon.com/gp/aws/cart/add.html?ASIN.1=B08HJNKT3P&Quantity.1=1',
|
||||
model: 'trinity',
|
||||
series: '3080',
|
||||
url: 'https://www.amazon.com/dp/B08HJNKT3P'
|
||||
},
|
||||
{
|
||||
brand: 'zotac',
|
||||
cartUrl: 'https://www.amazon.com/gp/aws/cart/add.html?ASIN.1=B08HJQ182D&Quantity.1=1',
|
||||
model: 'trinity',
|
||||
series: '3090',
|
||||
url: 'https://www.amazon.com/dp/B08HJQ182D'
|
||||
},
|
||||
{
|
||||
brand: 'pny',
|
||||
cartUrl: 'https://www.amazon.com/gp/aws/cart/add.html?ASIN.1=B08HBQWBHH&Quantity.1=1',
|
||||
model: 'xlr8',
|
||||
series: '3090',
|
||||
url: 'https://www.amazon.com/dp/B08HBQWBHH'
|
||||
},
|
||||
{
|
||||
brand: 'pny',
|
||||
cartUrl: 'https://www.amazon.com/gp/aws/cart/add.html?ASIN.1=B08HBVX53D&Quantity.1=1',
|
||||
model: 'xlr8',
|
||||
series: '3090',
|
||||
url: 'https://www.amazon.com/dp/B08HBVX53D'
|
||||
},
|
||||
{
|
||||
brand: 'msi',
|
||||
cartUrl: 'https://www.amazon.com/gp/aws/cart/add.html?ASIN.1=B08HRBW6VB&Quantity.1=1',
|
||||
model: 'gaming x trio',
|
||||
series: '3090',
|
||||
url: 'https://www.amazon.com/dp/B08HRBW6VB'
|
||||
},
|
||||
{
|
||||
brand: 'msi',
|
||||
cartUrl: 'https://www.amazon.com/gp/aws/cart/add.html?ASIN.1=B08HR9D2JS&Quantity.1=1',
|
||||
model: 'ventus 3x',
|
||||
series: '3090',
|
||||
url: 'https://www.amazon.com/dp/B08HR9D2JS'
|
||||
},
|
||||
{
|
||||
brand: 'gigabyte',
|
||||
cartUrl: 'https://www.amazon.com/gp/aws/cart/add.html?ASIN.1=B08HJRF2CN&Quantity.1=1',
|
||||
model: 'gaming oc',
|
||||
series: '3090',
|
||||
url: 'https://www.amazon.com/dp/B08HJRF2CN'
|
||||
},
|
||||
{
|
||||
brand: 'gigabyte',
|
||||
cartUrl: 'https://www.amazon.com/gp/aws/cart/add.html?ASIN.1=B08HJPDJTY&Quantity.1=1',
|
||||
model: 'eagle oc',
|
||||
series: '3090',
|
||||
url: 'https://www.amazon.com/dp/B08HJPDJTY'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
cartUrl: 'https://www.amazon.com/gp/aws/cart/add.html?ASIN.1=B08HJGNJ81&Quantity.1=1',
|
||||
model: 'tuf oc',
|
||||
series: '3090',
|
||||
url: 'https://www.amazon.com/dp/B08HJGNJ81'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
cartUrl: 'https://www.amazon.com/gp/aws/cart/add.html?ASIN.1=B08HJLLF7G&Quantity.1=1',
|
||||
model: 'tuf oc',
|
||||
series: '3090',
|
||||
url: 'https://www.amazon.com/dp/B08HJLLF7G'
|
||||
}
|
||||
],
|
||||
name: 'amazon'
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
import {Store} from './store';
|
||||
import {getProductLinksBuilder} from './helpers/card';
|
||||
|
||||
export const Aria: Store = {
|
||||
labels: {
|
||||
inStock: {
|
||||
container: '#addQuantity',
|
||||
text: ['add to shopping basket']
|
||||
},
|
||||
maxPrice: {
|
||||
container: '.priceBig',
|
||||
euroFormat: false // Note: Aria uses non-euroFromat as price seperator
|
||||
},
|
||||
outOfStock: {
|
||||
container: '.fBox',
|
||||
text: ['out of stock', 'there is currently no stock of this item']
|
||||
}
|
||||
},
|
||||
links: [
|
||||
{
|
||||
brand: 'test:brand',
|
||||
model: 'test:model',
|
||||
series: 'test:series',
|
||||
url: 'https://www.aria.co.uk/Products/Components/Graphics+Cards/NVIDIA+GeForce/GeForce+RTX+2060+Super/Gigabyte+NVIDIA+GeForce+RTX+2060+SUPER+8GB+WINDFORCE+OC+Turing+Graphics+Card+%2B+RTX+Bundle%21?productId=71541'
|
||||
}
|
||||
],
|
||||
linksBuilder: {
|
||||
builder: getProductLinksBuilder({
|
||||
productsSelector: '#productListingInner .listTable .listTableTr',
|
||||
sitePrefix: 'https://www.aria.co.uk',
|
||||
titleSelector: 'strong > a[href]'
|
||||
}),
|
||||
urls: [
|
||||
{
|
||||
series: '3080',
|
||||
url: 'https://www.aria.co.uk/Products/Components/Graphics+Cards/NVIDIA+GeForce/GeForce+RTX+3080'
|
||||
},
|
||||
{
|
||||
series: '3090',
|
||||
url: 'https://www.aria.co.uk/Products/Components/Graphics+Cards/NVIDIA+GeForce/GeForce+RTX+3090'
|
||||
}
|
||||
]
|
||||
},
|
||||
name: 'aria',
|
||||
waitUntil: 'domcontentloaded'
|
||||
};
|
||||
@@ -0,0 +1,67 @@
|
||||
import {Store} from './store';
|
||||
|
||||
export const AsusDe: Store = {
|
||||
labels: {
|
||||
inStock: {
|
||||
container: '.buybox--button',
|
||||
text: ['in den warenkorb']
|
||||
}
|
||||
},
|
||||
links: [
|
||||
{
|
||||
brand: 'test:brand',
|
||||
model: 'test:model',
|
||||
series: 'test:series',
|
||||
url: 'https://webshop.asus.com/de/komponenten/grafikkarten/nvidia-serie/2766/asus-rog-strix-rtx2060s-o8g-evo-v2-gaming'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'rog strix',
|
||||
series: '3080',
|
||||
url: 'https://webshop.asus.com/de/komponenten/grafikkarten/nvidia-serie/2828/asus-rog-strix-rtx3080-10g-gaming'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'rog strix oc',
|
||||
series: '3080',
|
||||
url: 'https://webshop.asus.com/de/komponenten/grafikkarten/nvidia-serie/2829/asus-rog-strix-rtx3080-o10g-gaming'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'tuf',
|
||||
series: '3080',
|
||||
url: 'https://webshop.asus.com/de/komponenten/grafikkarten/nvidia-serie/2824/asus-tuf-rtx3080-10g-gaming'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'tuf oc',
|
||||
series: '3080',
|
||||
url: 'https://webshop.asus.com/de/komponenten/grafikkarten/nvidia-serie/2825/asus-tuf-rtx3080-o10g-gaming'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'rog strix',
|
||||
series: '3090',
|
||||
url: 'https://webshop.asus.com/de/komponenten/grafikkarten/nvidia-serie/2826/asus-rog-strix-rtx3090-24g-gaming'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'rog strix oc',
|
||||
series: '3090',
|
||||
url: 'https://webshop.asus.com/de/komponenten/grafikkarten/nvidia-serie/2827/asus-rog-strix-rtx3090-o24g-gaming'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'tuf',
|
||||
series: '3090',
|
||||
url: 'https://webshop.asus.com/de/komponenten/grafikkarten/nvidia-serie/2822/asus-tuf-rtx3090-24g-gaming'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'tuf oc',
|
||||
series: '3090',
|
||||
url: 'https://webshop.asus.com/de/komponenten/grafikkarten/nvidia-serie/2823/asus-tuf-rtx3090-o24g-gaming'
|
||||
}
|
||||
],
|
||||
name: 'asus-de'
|
||||
};
|
||||
+23
-5
@@ -12,21 +12,39 @@ export const Asus: Store = {
|
||||
brand: 'test:brand',
|
||||
model: 'test:model',
|
||||
series: 'test:series',
|
||||
url: 'https://store.asus.com/us/item/202003AM280000002/'
|
||||
url: 'https://store.asus.com/us/item/202003AM280000002'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'tuf oc',
|
||||
series: '3080',
|
||||
url: 'https://store.asus.com/us/item/202009AM160000001/'
|
||||
url: 'https://store.asus.com/us/item/202009AM160000001'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'tuf',
|
||||
series: '3080',
|
||||
url: 'https://store.asus.com/us/item/202009AM150000004/'
|
||||
url: 'https://store.asus.com/us/item/202009AM150000004'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'tuf',
|
||||
series: '3090',
|
||||
url: 'https://store.asus.com/us/item/202009AM150000003'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'tuf oc',
|
||||
series: '3090',
|
||||
url: 'https://store.asus.com/us/item/202009AM150000001'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'rog strix oc',
|
||||
series: '3080',
|
||||
url: 'https://store.asus.com/us/item/202009AM290000002'
|
||||
}
|
||||
],
|
||||
name: 'asus'
|
||||
name: 'asus',
|
||||
successStatusCodes: [[0, 399], 404]
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,165 @@
|
||||
import {Store} from './store';
|
||||
|
||||
export const Azerty: Store = {
|
||||
labels: {
|
||||
inStock: {
|
||||
container: '.orderdelay',
|
||||
text: ['Volgende werkdag in huis', '1 werkdag', '2-3 werkdagen']
|
||||
},
|
||||
maxPrice: {
|
||||
container: '.mod_article .price',
|
||||
euroFormat: true
|
||||
},
|
||||
outOfStock: {
|
||||
container: '.orderdelay',
|
||||
text: ['Onbekend', 'meer dan 10 werkdagen', 'Pre-order']
|
||||
}
|
||||
},
|
||||
links: [
|
||||
{
|
||||
brand: 'test:brand',
|
||||
model: 'test:model',
|
||||
series: 'test:series',
|
||||
url: 'https://azerty.nl/product/gigabyte/3756757/geforce-rtx-2060-oc-6g-grafische-kaart-geforce-rtx-2060'
|
||||
},
|
||||
{
|
||||
brand: 'gigabyte',
|
||||
model: 'aorus xtreme',
|
||||
series: '3080',
|
||||
url: 'https://azerty.nl/product/gigabyte/4349658/aorus-geforce-rtx-3080-xtreme-10g-grafische-kaart-gf-rtx-3080'
|
||||
},
|
||||
{
|
||||
brand: 'msi',
|
||||
model: 'ventus 3x oc',
|
||||
series: '3080',
|
||||
url: 'https://azerty.nl/product/msi/4346262/geforce-rtx-3080-ventus-3x-10g-oc-grafische-kaart-rtx-3080'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'tuf',
|
||||
series: '3080',
|
||||
url: 'https://azerty.nl/product/asus/4346679/tuf-gaming-geforce-rtx-3080-grafische-kaart-gf-rtx-3080'
|
||||
},
|
||||
{
|
||||
brand: 'msi',
|
||||
model: 'gaming x trio',
|
||||
series: '3080',
|
||||
url: 'https://azerty.nl/product/msi/4346263/geforce-rtx-3080-gaming-x-trio-10g-grafische-kaart-rtx-3080'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'tuf oc',
|
||||
series: '3080',
|
||||
url: 'https://azerty.nl/product/asus/4348176/tuf-gaming-geforce-rtx-3080-oc-grafische-kaart-gf-rtx-3080'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'rog strix oc',
|
||||
series: '3080',
|
||||
url: 'https://azerty.nl/product/asus/4348174/rog-strix-geforce-rtx-3080-oc-grafische-kaart-gf-rtx-3080'
|
||||
},
|
||||
{
|
||||
brand: 'zotac',
|
||||
model: 'trinity',
|
||||
series: '3080',
|
||||
url: 'https://azerty.nl/product/zotac/4352301/gaming-geforce-rtx-3080-trinity-oc-grafische-kaart-gf-rtx-3080'
|
||||
},
|
||||
{
|
||||
brand: 'gigabyte',
|
||||
model: 'aorus master',
|
||||
series: '3080',
|
||||
url: 'https://azerty.nl/product/gigabyte/4349651/aorus-geforce-rtx-3080-master-10g-grafische-kaart-gf-rtx-3080'
|
||||
},
|
||||
{
|
||||
brand: 'pny',
|
||||
model: 'xlr8 rgb',
|
||||
series: '3080',
|
||||
url: 'https://azerty.nl/product/pny/4342269/geforce-rtx-3080-xlr8-gaming-revel-epic-x-rgb-triple-fan-gaming-edition-grafische-kaart-gf-rtx-3080'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'rog strix oc',
|
||||
series: '3070',
|
||||
url: 'https://azerty.nl/product/asus/4363892/rog-strix-gaming-geforce-rtx-3070-o8g-videokaart-8-gb-gddr6'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'rog strix',
|
||||
series: '3070',
|
||||
url: 'https://azerty.nl/product/asus/4373096/rog-strix-gaming-geforce-rtx-3070-8g-videokaart-8-gb-gddr6'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'tuf oc',
|
||||
series: '3070',
|
||||
url: 'https://azerty.nl/product/asus/4363910/tuf-gaming-geforce-rtx-3070-oc-videokaart-8-gb-gddr6'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'tuf',
|
||||
series: '3070',
|
||||
url: 'https://azerty.nl/product/asus/4373099/tuf-gaming-geforce-rtx-3070-videokaart-8-gb-gddr6'
|
||||
},
|
||||
{
|
||||
brand: 'inno3d',
|
||||
model: 'ichill x4',
|
||||
series: '3070',
|
||||
url: 'https://azerty.nl/product/inno3d/4369725/geforce-rtx-3070-ichill-x4-videokaart-8-gb-ddr6'
|
||||
},
|
||||
{
|
||||
brand: 'inno3d',
|
||||
model: 'ichill x3',
|
||||
series: '3070',
|
||||
url: 'https://azerty.nl/product/inno3d/4369726/geforce-rtx-3070-ichill-x3-videokaart-8-gb-ddr6'
|
||||
},
|
||||
{
|
||||
brand: 'msi',
|
||||
model: 'ventus 3x oc',
|
||||
series: '3070',
|
||||
url: 'https://azerty.nl/product/msi/4374747/geforce-rtx-3070-ventus-3x-oc-videokaart-8-gb-gddr6'
|
||||
},
|
||||
{
|
||||
brand: 'msi',
|
||||
model: 'gaming x trio',
|
||||
series: '3070',
|
||||
url: 'https://azerty.nl/product/msi/4365398/geforce-rtx-3070-gaming-x-trio-videokaart-8-gb-gddr6'
|
||||
},
|
||||
{
|
||||
brand: 'pny',
|
||||
model: 'dual fan',
|
||||
series: '3070',
|
||||
url: 'https://azerty.nl/product/pny/4342270/uprising-dual-fan-geforce-rtx-3070'
|
||||
},
|
||||
{
|
||||
brand: 'pny',
|
||||
model: 'xlr8 rgb',
|
||||
series: '3070',
|
||||
url: 'https://azerty.nl/product/pny/4342271/epic-x-rgb-geforce-rtx-3070-triple-fan-gaming-edition-xlr8--videokaart-8-gb-gddr6x'
|
||||
},
|
||||
{
|
||||
brand: 'evga',
|
||||
model: 'ftw3',
|
||||
series: '3070',
|
||||
url: 'https://azerty.nl/product/evga/4377247/geforce-rtx-3070-ftw3-videokaart-8-gb-gddr6'
|
||||
},
|
||||
{
|
||||
brand: 'evga',
|
||||
model: 'xc3',
|
||||
series: '3070',
|
||||
url: 'https://azerty.nl/product/evga/4377248/xc3-geforce-rtx-3070-xc3-videokaart-8-gb-gddr6'
|
||||
},
|
||||
{
|
||||
brand: 'evga',
|
||||
model: 'ftw3 ultra',
|
||||
series: '3070',
|
||||
url: 'https://azerty.nl/product/evga/4377250/ftw3-ultra-geforce-rtx-3070-videokaart-8-gb-gddr6'
|
||||
},
|
||||
{
|
||||
brand: 'evga',
|
||||
model: 'xc3 black',
|
||||
series: '3070',
|
||||
url: 'https://azerty.nl/product/evga/4377252/xc3-black-geforce-rtx-3070-videokaart-8-gb-gddr6'
|
||||
}
|
||||
],
|
||||
name: 'azerty'
|
||||
};
|
||||
@@ -1,10 +1,15 @@
|
||||
import {Store} from './store';
|
||||
|
||||
export const BAndH: Store = {
|
||||
backoffStatusCodes: [403, 429],
|
||||
labels: {
|
||||
inStock: {
|
||||
container: 'div[data-selenium="addToCartSection"]',
|
||||
text: ['add to cart']
|
||||
},
|
||||
maxPrice: {
|
||||
container: 'div[data-selenium="pricingPrice"]',
|
||||
euroFormat: false
|
||||
}
|
||||
},
|
||||
links: [
|
||||
@@ -54,15 +59,69 @@ export const BAndH: Store = {
|
||||
},
|
||||
{
|
||||
brand: 'msi',
|
||||
model: 'gaming x trio - duplicate',
|
||||
model: 'gaming x trio',
|
||||
series: '3080',
|
||||
url: 'https://www.bhphotovideo.com/c/product/1593645-REG/msi_geforce_rtx_3080_gaming.html'
|
||||
},
|
||||
{
|
||||
brand: 'msi',
|
||||
model: 'ventus 3x oc - duplicate',
|
||||
model: 'ventus 3x oc',
|
||||
series: '3080',
|
||||
url: 'https://www.bhphotovideo.com/c/product/1593646-REG/msi_geforce_rtx_3080_ventus.html'
|
||||
},
|
||||
{
|
||||
brand: 'zotac',
|
||||
model: 'trinity',
|
||||
series: '3090',
|
||||
url: 'https://www.bhphotovideo.com/c/product/1592970-REG/zotac_zt_a30900d_10p_gaming_geforce_rtx_3090.html'
|
||||
},
|
||||
{
|
||||
brand: 'msi',
|
||||
model: 'gaming x trio',
|
||||
series: '3090',
|
||||
url: 'https://www.bhphotovideo.com/c/product/1593647-REG/msi_geforce_rtx_3090_gaming.html'
|
||||
},
|
||||
{
|
||||
brand: 'msi',
|
||||
model: 'gaming x trio',
|
||||
series: '3090',
|
||||
url: 'https://www.bhphotovideo.com/c/product/1593994-REG/msi_g3090gxt24_geforce_rtx_3090_gaming.html'
|
||||
},
|
||||
{
|
||||
brand: 'msi',
|
||||
model: 'ventus 3x oc',
|
||||
series: '3090',
|
||||
url: 'https://www.bhphotovideo.com/c/product/1593648-REG/msi_geforce_rtx_3090_ventus.html'
|
||||
},
|
||||
{
|
||||
brand: 'msi',
|
||||
model: 'ventus 3x oc',
|
||||
series: '3090',
|
||||
url: 'https://www.bhphotovideo.com/c/product/1593995-REG/msi_g3090v3x24c_geforce_rtx_3090_ventus.html'
|
||||
},
|
||||
{
|
||||
brand: 'gigabyte',
|
||||
model: 'eagle oc',
|
||||
series: '3090',
|
||||
url: 'https://www.bhphotovideo.com/c/product/1593334-REG/gigabyte_gv_n3090eagle_oc_24gd_geforce_rtx_3090_eagle.html'
|
||||
},
|
||||
{
|
||||
brand: 'gigabyte',
|
||||
model: 'gaming oc',
|
||||
series: '3090',
|
||||
url: 'https://www.bhphotovideo.com/c/product/1593335-REG/gigabyte_gv_n3090gaming_oc_24gd_geforce_rtx3090_gaming_oc.html'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'tuf',
|
||||
series: '3090',
|
||||
url: 'https://www.bhphotovideo.com/c/product/1594454-REG/asus_90yv0fd0_m0am00_tuf_gaming_geforce_rtx.html'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'tuf oc',
|
||||
series: '3090',
|
||||
url: 'https://www.bhphotovideo.com/c/product/1594451-REG/asus_90yv0fd1_m0am00_tuf_gaming_geforce_rtx.html'
|
||||
}
|
||||
],
|
||||
name: 'bandh'
|
||||
|
||||
@@ -5,6 +5,10 @@ export const BestBuyCa: Store = {
|
||||
inStock: {
|
||||
container: '#root',
|
||||
text: ['available online']
|
||||
},
|
||||
maxPrice: {
|
||||
container: 'div[class^="productPricingContainer"] span[class^="screenReaderOnly_"',
|
||||
euroFormat: false
|
||||
}
|
||||
},
|
||||
links: [
|
||||
@@ -67,6 +71,30 @@ export const BestBuyCa: Store = {
|
||||
model: 'ventus 3x',
|
||||
series: '3090',
|
||||
url: 'https://www.bestbuy.ca/en-ca/product/msi-nvidia-geforce-rtx-3090-ventus-3x-oc-24gb-gddr6x-video-card/14966477?intl=nosplash'
|
||||
},
|
||||
{
|
||||
brand: 'msi',
|
||||
model: 'ventus 3x',
|
||||
series: '3070',
|
||||
url: 'https://www.bestbuy.ca/en-ca/product/msi-nvidia-geforce-rtx-3070-ventus-3x-oc-8gb-gddr6x-video-card/15038016?intl=nosplash'
|
||||
},
|
||||
{
|
||||
brand: 'zotac',
|
||||
model: 'twin edge oc',
|
||||
series: '3070',
|
||||
url: 'https://www.bestbuy.ca/en-ca/product/zotac-nvidia-geforce-rtx-3070-twin-edge-oc-8gb-gddr6x-video-card/15000078?intl=nosplash'
|
||||
},
|
||||
{
|
||||
brand: 'zotac',
|
||||
model: 'twin edge',
|
||||
series: '3070',
|
||||
url: 'https://www.bestbuy.ca/en-ca/product/zotac-nvidia-geforce-rtx-3070-twin-edge-8gb-gddr6x-video-card/15000079?intl=nosplash'
|
||||
},
|
||||
{
|
||||
brand: 'nvidia',
|
||||
model: 'founders edition',
|
||||
series: '3070',
|
||||
url: 'https://www.bestbuy.ca/en-ca/product/nvidia-geforce-rtx-3070-8gb-gddr6-video-card-only-at-best-buy/15078017?intl=nosplash'
|
||||
}
|
||||
],
|
||||
name: 'bestbuy-ca',
|
||||
|
||||
+137
-8
@@ -3,8 +3,12 @@ import {Store} from './store';
|
||||
export const BestBuy: Store = {
|
||||
labels: {
|
||||
inStock: {
|
||||
container: '.v-m-bottom-g',
|
||||
container: '[data-sticky-media-gallery] .fulfillment-add-to-cart-button',
|
||||
text: ['add to cart']
|
||||
},
|
||||
maxPrice: {
|
||||
container: '[data-sticky-media-gallery] .priceView-price .priceView-hero-price span',
|
||||
euroFormat: false
|
||||
}
|
||||
},
|
||||
links: [
|
||||
@@ -12,7 +16,14 @@ export const BestBuy: Store = {
|
||||
brand: 'test:brand',
|
||||
model: 'test:model',
|
||||
series: 'test:series',
|
||||
url: 'https://www.bestbuy.com/site/nvidia-geforce-rtx-2060-super-8gb-gddr6-pci-express-graphics-card-black-silver/6361329.p?skuId=6361329&intl=nosplash'
|
||||
url: 'https://www.bestbuy.com/site/evga-ko-ultra-gaming-nvidia-geforce-rtx-2060-6gb-gddr6-pci-express-3-0-graphics-card-black-gray/6403801.p?skuId=6403801&intl=nosplash'
|
||||
},
|
||||
{
|
||||
brand: 'nvidia',
|
||||
cartUrl: 'https://api.bestbuy.com/click/-/6429442/cart',
|
||||
model: 'founders edition',
|
||||
series: '3070',
|
||||
url: 'https://www.bestbuy.com/site/nvidia-geforce-rtx-3070-8gb-gddr6-pci-express-4-0-graphics-card-dark-platinum-and-black/6429442.p?skuId=6429442&intl=nosplash'
|
||||
},
|
||||
{
|
||||
brand: 'nvidia',
|
||||
@@ -28,6 +39,13 @@ export const BestBuy: Store = {
|
||||
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/-/6439300/cart',
|
||||
model: 'xc3 black',
|
||||
series: '3070',
|
||||
url: 'https://www.bestbuy.com/site/evga-geforce-rtx-3070-xc3-black-gaming-8gb-gddr6x-pci-express-4-0-graphics-card/6439300.p?skuId=6439300&intl=nosplash'
|
||||
},
|
||||
{
|
||||
brand: 'evga',
|
||||
cartUrl: 'https://api.bestbuy.com/click/-/6432399/cart',
|
||||
@@ -35,6 +53,13 @@ export const BestBuy: Store = {
|
||||
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/-/6436194/cart',
|
||||
model: 'xc3',
|
||||
series: '3080',
|
||||
url: 'https://www.bestbuy.com/site/evga-geforce-rtx-3080-10gb-gddr6x-pci-express-4-0-graphics-card/6436194.p?skuId=6436194&intl=nosplash'
|
||||
},
|
||||
{
|
||||
brand: 'evga',
|
||||
cartUrl: 'https://api.bestbuy.com/click/-/6432400/cart',
|
||||
@@ -42,6 +67,34 @@ export const BestBuy: Store = {
|
||||
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: 'evga',
|
||||
cartUrl: 'https://api.bestbuy.com/click/-/6436196/cart',
|
||||
model: 'ftw3 ultra',
|
||||
series: '3080',
|
||||
url: 'https://www.bestbuy.com/site/evga-geforce-rtx-3080-10gb-gddr6x-pci-express-4-0-graphics-card/6436196.p?skuId=6436196&intl=nosplash'
|
||||
},
|
||||
{
|
||||
brand: 'evga',
|
||||
cartUrl: 'https://api.bestbuy.com/click/-/6436191/cart',
|
||||
model: 'ftw3',
|
||||
series: '3080',
|
||||
url: 'https://www.bestbuy.com/site/evga-geforce-rtx-3080-10gb-gddr6x-pci-express-4-0-graphics-card/6436191.p?skuId=6436191&intl=nosplash'
|
||||
},
|
||||
{
|
||||
brand: 'gigabyte',
|
||||
cartUrl: 'https://api.bestbuy.com/click/-/6437912/cart',
|
||||
model: 'eagle',
|
||||
series: '3070',
|
||||
url: 'https://www.bestbuy.com/site/gigabyte-geforce-rtx-3070-8g-gddr6-pci-express-4-0-graphics-card-black/6437912.p?skuId=6437912&intl=nosplash'
|
||||
},
|
||||
{
|
||||
brand: 'gigabyte',
|
||||
cartUrl: 'https://api.bestbuy.com/click/-/6437909/cart',
|
||||
model: 'gaming oc',
|
||||
series: '3070',
|
||||
url: 'https://www.bestbuy.com/site/gigabyte-geforce-rtx-3070-8g-gddr6-pci-express-4-0-graphics-card-black/6437909.p?skuId=6437909&intl=nosplash'
|
||||
},
|
||||
{
|
||||
brand: 'gigabyte',
|
||||
cartUrl: 'https://api.bestbuy.com/click/-/6430620/cart',
|
||||
@@ -56,6 +109,20 @@ export const BestBuy: Store = {
|
||||
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: 'gigabyte',
|
||||
cartUrl: 'https://api.bestbuy.com/click/-/6436219/cart',
|
||||
model: 'vision oc',
|
||||
series: '3080',
|
||||
url: 'https://www.bestbuy.com/site/gigabyte-geforce-rtx-3080-10g-gddr6x-pci-express-4-0-graphics-card-white/6436219.p?skuId=6436219&intl=nosplash'
|
||||
},
|
||||
{
|
||||
brand: 'gigabyte',
|
||||
cartUrl: 'https://api.bestbuy.com/click/-/6436223/cart',
|
||||
model: 'aorus master',
|
||||
series: '3080',
|
||||
url: 'https://www.bestbuy.com/site/gigabyte-geforce-rtx-3080-10g-gddr6x-pci-express-4-0-graphics-card-black/6436223.p?skuId=6436223&intl=nosplash'
|
||||
},
|
||||
{
|
||||
brand: 'msi',
|
||||
cartUrl: 'https://api.bestbuy.com/click/-/6430175/cart',
|
||||
@@ -63,41 +130,103 @@ export const BestBuy: Store = {
|
||||
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'
|
||||
},
|
||||
{
|
||||
brand: 'pny',
|
||||
cartUrl: 'https://api.bestbuy.com/click/-/6432654/cart',
|
||||
model: 'dual fan',
|
||||
series: '3070',
|
||||
url: 'https://www.bestbuy.com/site/pny-geforce-rtx-3070-8gb-dual-fan-graphics-card/6432654.p?skuId=6432654&intl=nosplash'
|
||||
},
|
||||
{
|
||||
brand: 'pny',
|
||||
cartUrl: 'https://api.bestbuy.com/click/-/6432653/cart',
|
||||
model: 'xlr8 rgb',
|
||||
series: '3070',
|
||||
url: 'https://www.bestbuy.com/site/pny-geforce-rtx-3070-8gb-xlr8-gaming-epic-x-rgb-triple-fan-graphics-card/6432653.p?skuId=6432653&intl=nosplash'
|
||||
},
|
||||
{
|
||||
brand: 'pny',
|
||||
cartUrl: 'https://api.bestbuy.com/click/-/6432655/cart',
|
||||
model: 'xlr8 rgb',
|
||||
series: '3080',
|
||||
url: 'https://www.bestbuy.com/site/pny-geforce-rtx-3080-10gb-xlr8-gaming-epic-x-rgb-triple-fan-graphics-card/6432655.p?skuId=6432655&intl=nosplash'
|
||||
},
|
||||
{
|
||||
brand: 'pny',
|
||||
cartUrl: 'https://api.bestbuy.com/click/-/6432658/cart',
|
||||
model: 'xlr8 rgb',
|
||||
series: '3080',
|
||||
url: 'https://www.bestbuy.com/site/pny-geforce-rtx-3080-10gb-xlr8-gaming-epic-x-rgb-triple-fan-graphics-card/6432658.p?skuId=6432658&intl=nosplash'
|
||||
},
|
||||
{
|
||||
brand: 'nvidia',
|
||||
cartUrl: 'https://api.bestbuy.com/click/-/6429434/cart',
|
||||
model: 'founders edition',
|
||||
series: '3090',
|
||||
url: 'https://www.bestbuy.com/site/nvidia-geforce-rtx-3090-24gb-gddr6x-pci-express-4-0-graphics-card-titanium-and-black/6429434.p?skuId=6429434'
|
||||
url: 'https://www.bestbuy.com/site/nvidia-geforce-rtx-3090-24gb-gddr6x-pci-express-4-0-graphics-card-titanium-and-black/6429434.p?skuId=6429434&intl=nosplash'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
cartUrl: 'https://api.bestbuy.com/click/-/6432447/cart',
|
||||
model: 'rog strix',
|
||||
series: '3090',
|
||||
url: 'https://www.bestbuy.com/site/asus-geforce-rtx-3090-24gb-gddr6x-pci-express-4-0-strix-graphics-card-black/6432447.p?skuId=6432447'
|
||||
url: 'https://www.bestbuy.com/site/asus-geforce-rtx-3090-24gb-gddr6x-pci-express-4-0-strix-graphics-card-black/6432447.p?skuId=6432447&intl=nosplash'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
cartUrl: 'https://api.bestbuy.com/click/-/6432446/cart',
|
||||
model: 'tuf',
|
||||
series: '3090',
|
||||
url: 'https://www.bestbuy.com/site/asus-tuf-rtx-3090-24gb-gddr6x-pci-express-4-0-graphics-card-black/6432446.p?skuId=6432446'
|
||||
url: 'https://www.bestbuy.com/site/asus-tuf-rtx-3090-24gb-gddr6x-pci-express-4-0-graphics-card-black/6432446.p?skuId=6432446&intl=nosplash'
|
||||
},
|
||||
{
|
||||
brand: 'msi',
|
||||
cartUrl: 'https://api.bestbuy.com/click/-/6430215/cart',
|
||||
model: 'ventus 3x oc',
|
||||
series: '3090',
|
||||
url: 'https://www.bestbuy.com/site/msi-geforce-rtx-3090-ventus-3x-24g-oc-bv-24gb-gddr6x-pci-express-4-0-graphics-card-black-silver/6430215.p?skuId=6430215'
|
||||
url: 'https://www.bestbuy.com/site/msi-geforce-rtx-3090-ventus-3x-24g-oc-bv-24gb-gddr6x-pci-express-4-0-graphics-card-black-silver/6430215.p?skuId=6430215&intl=nosplash'
|
||||
},
|
||||
{
|
||||
brand: 'gigabyte',
|
||||
cartUrl: 'https://api.bestbuy.com/click/-/6430623/cart',
|
||||
model: 'gaming',
|
||||
series: '3090',
|
||||
url: 'https://www.bestbuy.com/site/gigabyte-geforce-rtx-3090-24g-gddr6x-pci-express-4-0-graphics-card-black/6430623.p?skuId=6430623'
|
||||
url: 'https://www.bestbuy.com/site/gigabyte-geforce-rtx-3090-24g-gddr6x-pci-express-4-0-graphics-card-black/6430623.p?skuId=6430623&intl=nosplash'
|
||||
},
|
||||
{
|
||||
brand: 'gigabyte',
|
||||
cartUrl: 'https://api.bestbuy.com/click/-/6430624/cart',
|
||||
model: 'eagle',
|
||||
series: '3090',
|
||||
url: 'https://www.bestbuy.com/site/gigabyte-geforce-rtx-3090-24g-gddr6x-pci-express-4-0-graphics-card-black/6430624.p?skuId=6430624'
|
||||
url: 'https://www.bestbuy.com/site/gigabyte-geforce-rtx-3090-24g-gddr6x-pci-express-4-0-graphics-card-black/6430624.p?skuId=6430624&intl=nosplash'
|
||||
},
|
||||
{
|
||||
brand: 'evga',
|
||||
cartUrl: 'https://api.bestbuy.com/click/-/6434363/cart',
|
||||
model: 'xc3',
|
||||
series: '3090',
|
||||
url: 'https://www.bestbuy.com/site/evga-geforce-rtx-3090-24gb-gddr6x-pci-express-4-0-graphics-card/6434363.p?skuId=6434363&intl=nosplash'
|
||||
},
|
||||
{
|
||||
brand: 'evga',
|
||||
cartUrl: 'https://api.bestbuy.com/click/-/6436193/cart',
|
||||
model: 'ftw3',
|
||||
series: '3090',
|
||||
url: 'https://www.bestbuy.com/site/evga-geforce-rtx-3090-24gb-gddr6x-pci-express-4-0-graphics-card/6436193.p?skuId=6436193&intl=nosplash'
|
||||
},
|
||||
{
|
||||
brand: 'evga',
|
||||
cartUrl: 'https://api.bestbuy.com/click/-/6436192/cart',
|
||||
model: 'ftw3 ultra',
|
||||
series: '3090',
|
||||
url: 'https://www.bestbuy.com/site/evga-geforce-rtx-3090-24gb-gddr6x-pci-express-4-0-graphics-card/6436192.p?skuId=6436192&intl=nosplash'
|
||||
},
|
||||
{
|
||||
brand: 'pny',
|
||||
cartUrl: 'https://api.bestbuy.com/click/-/6432657/cart',
|
||||
model: 'xlr8 rgb',
|
||||
series: '3090',
|
||||
url: 'https://www.bestbuy.com/site/pny-geforce-rtx-3090-24gb-xlr8-gaming-epic-x-rgb-triple-fan-graphics-card/6432657.p?skuId=6432657&intl=nosplash'
|
||||
}
|
||||
],
|
||||
name: 'bestbuy'
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
import {Store} from './store';
|
||||
import {getProductLinksBuilder} from './helpers/card';
|
||||
|
||||
export const Box: Store = {
|
||||
labels: {
|
||||
inStock: {
|
||||
container: '#divBuyButton',
|
||||
text: ['add to basket']
|
||||
},
|
||||
maxPrice: {
|
||||
container: '.p-right-wrapper .pq-price',
|
||||
euroFormat: false // Note: Box uses non-euroFromat as price seperator
|
||||
},
|
||||
outOfStock: {
|
||||
text: ['request stock alert', 'coming soon']
|
||||
}
|
||||
},
|
||||
links: [
|
||||
{
|
||||
brand: 'test:brand',
|
||||
model: 'test:model',
|
||||
series: 'test:series',
|
||||
url: 'https://www.box.co.uk/Gigabyte-GeForce-RTX-2080-Super-8GB-Wind_2724554.html'
|
||||
}
|
||||
],
|
||||
linksBuilder: {
|
||||
builder: getProductLinksBuilder({
|
||||
productsSelector: '.products-right .p-list',
|
||||
sitePrefix: 'https://www.box.co.uk',
|
||||
titleSelector: '.p-list-section > h3 > a[href]'
|
||||
}),
|
||||
urls: [
|
||||
{
|
||||
series: '3070',
|
||||
url: 'https://www.box.co.uk/rtx-3070-graphics-cards'
|
||||
},
|
||||
{
|
||||
series: '3080',
|
||||
url: 'https://www.box.co.uk/rtx-3080-graphics-cards'
|
||||
},
|
||||
{
|
||||
series: '3090',
|
||||
url: 'https://www.box.co.uk/rtx-3090-graphics-cards'
|
||||
}
|
||||
]
|
||||
},
|
||||
name: 'box',
|
||||
waitUntil: 'domcontentloaded'
|
||||
};
|
||||
@@ -0,0 +1,275 @@
|
||||
import {Store} from './store';
|
||||
|
||||
export const Caseking: Store = {
|
||||
backoffStatusCodes: [403, 429],
|
||||
labels: {
|
||||
inStock: {
|
||||
container: '.delivery_container',
|
||||
text: ['lagernd', 'im zulauf', 'ab']
|
||||
},
|
||||
maxPrice: {
|
||||
container: '#buybox .article_details_price',
|
||||
euroFormat: true
|
||||
},
|
||||
outOfStock: {
|
||||
container: '.delivery_container',
|
||||
text: ['unbekannt']
|
||||
}
|
||||
},
|
||||
links: [
|
||||
{
|
||||
brand: 'test:brand',
|
||||
model: 'test:model',
|
||||
series: 'test:series',
|
||||
url: 'https://www.caseking.de/evga-geforce-rtx-2060-super-xc-ultra-gaming-8192-mb-gddr6-gcev-385.html'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'rog strix',
|
||||
series: '3080',
|
||||
url: 'https://www.caseking.de/asus-geforce-rtx-3080-rog-strix-10g-10240-mb-gddr6x-gcas-400.html'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'rog strix oc',
|
||||
series: '3080',
|
||||
url: 'https://www.caseking.de/asus-geforce-rtx-3080-rog-strix-o10g-10240-mb-gddr6x-gcas-399.html'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'tuf',
|
||||
series: '3080',
|
||||
url: 'https://www.caseking.de/asus-geforce-rtx-3080-tuf-gaming-10g-10240-mb-gddr6x-gcas-394.html'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'tuf oc',
|
||||
series: '3080',
|
||||
url: 'https://www.caseking.de/asus-geforce-rtx-3080-tuf-gaming-o10g-10240-mb-gddr6x-gcas-396.html'
|
||||
},
|
||||
{
|
||||
brand: 'evga',
|
||||
model: 'ftw3',
|
||||
series: '3080',
|
||||
url: 'https://www.caseking.de/evga-geforce-rtx-3080-ftw3-gaming-10240-mb-gddr6x-gcev-416.html'
|
||||
},
|
||||
{
|
||||
brand: 'evga',
|
||||
model: 'ftw3 ultra',
|
||||
series: '3080',
|
||||
url: 'https://www.caseking.de/evga-geforce-rtx-3080-ftw3-ultra-gaming-10240-mb-gddr6x-gcev-417.html'
|
||||
},
|
||||
{
|
||||
brand: 'evga',
|
||||
model: 'xc3',
|
||||
series: '3080',
|
||||
url: 'https://www.caseking.de/evga-geforce-rtx-3080-xc3-gaming-10240-mb-gddr6x-gcev-415.html'
|
||||
},
|
||||
{
|
||||
brand: 'evga',
|
||||
model: 'xc3 black',
|
||||
series: '3080',
|
||||
url: 'https://www.caseking.de/evga-geforce-rtx-3080-xc3-black-gaming-10240-mb-gddr6x-gcev-414.html'
|
||||
},
|
||||
{
|
||||
brand: 'evga',
|
||||
model: 'xc3 ultra',
|
||||
series: '3080',
|
||||
url: 'https://www.caseking.de/evga-geforce-rtx-3080-xc3-ultra-gaming-10240-mb-gddr6x-gcev-423.html'
|
||||
},
|
||||
{
|
||||
brand: 'gigabyte',
|
||||
model: 'aorus master',
|
||||
series: '3080',
|
||||
url: 'https://www.caseking.de/gigabyte-aorus-geforce-rtx-3080-master-10g-10240-mb-gddr6x-gcgb-331.html'
|
||||
},
|
||||
{
|
||||
brand: 'gigabyte',
|
||||
model: 'eagle oc',
|
||||
series: '3080',
|
||||
url: 'https://www.caseking.de/gigabyte-geforce-rtx-3080-eagle-oc-10g-10240-mb-gddr6x-gcgb-326.html'
|
||||
},
|
||||
{
|
||||
brand: 'gigabyte',
|
||||
model: 'gaming oc',
|
||||
series: '3080',
|
||||
url: 'https://www.caseking.de/gigabyte-geforce-rtx-3080-gaming-oc-10g-10240-mb-gddr6x-gcgb-327.html'
|
||||
},
|
||||
{
|
||||
brand: 'gigabyte',
|
||||
model: 'vision oc',
|
||||
series: '3080',
|
||||
url: 'https://www.caseking.de/gigabyte-geforce-rtx-3080-vision-oc-10g-10240-mb-gddr6x-gcgb-332.html'
|
||||
},
|
||||
{
|
||||
brand: 'inno3d',
|
||||
model: 'ichill x3',
|
||||
series: '3080',
|
||||
url: 'https://www.caseking.de/inno3d-geforce-rtx-3080-ichill-x3-10240-mb-gddr6x-gci3-170.html'
|
||||
},
|
||||
{
|
||||
brand: 'inno3d',
|
||||
model: 'ichill x4',
|
||||
series: '3080',
|
||||
url: 'https://www.caseking.de/inno3d-geforce-rtx-3080-ichill-x4-10240-mb-gddr6x-gci3-169.html'
|
||||
},
|
||||
{
|
||||
brand: 'inno3d',
|
||||
model: 'twin x2 oc',
|
||||
series: '3080',
|
||||
url: 'https://www.caseking.de/inno3d-geforce-rtx-3080-twin-x2-oc-10240-mb-gddr6x-gci3-171.html'
|
||||
},
|
||||
{
|
||||
brand: 'msi',
|
||||
model: 'gaming x trio',
|
||||
series: '3080',
|
||||
url: 'https://www.caseking.de/msi-geforce-rtx-3080-gaming-x-trio-10g-10240-mb-gddr6x-gcmc-248.html'
|
||||
},
|
||||
{
|
||||
brand: 'msi',
|
||||
model: 'ventus 3x oc',
|
||||
series: '3080',
|
||||
url: 'https://www.caseking.de/msi-geforce-rtx-3080-ventus-3x-10g-oc-10240-mb-gddr6x-gcmc-247.html'
|
||||
},
|
||||
{
|
||||
brand: 'pny',
|
||||
model: 'xlr8 rgb',
|
||||
series: '3080',
|
||||
url: 'https://www.caseking.de/pny-geforce-rtx-3080-xlr8-gaming-epic-x-rgb-10240-mb-gddr6x-gcpn-075.html'
|
||||
},
|
||||
{
|
||||
brand: 'pny',
|
||||
model: 'xlr8 rgb',
|
||||
series: '3080',
|
||||
url: 'https://www.caseking.de/pny-geforce-rtx-3080-xlr8-gaming-revel-epic-x-rgb-10240-mb-gddr6x-gcpn-076.html'
|
||||
},
|
||||
{
|
||||
brand: 'zotac',
|
||||
model: 'amp holo',
|
||||
series: '3080',
|
||||
url: 'https://www.caseking.de/zotac-gaming-geforce-rtx-3080-amp-holo-10240-mb-gddr6x-gczt-166.html'
|
||||
},
|
||||
{
|
||||
brand: 'zotac',
|
||||
model: 'trinity oc',
|
||||
series: '3080',
|
||||
url: 'https://www.caseking.de/zotac-gaming-geforce-rtx-3080-trinity-oc-10240-mb-gddr6x-gczt-167.html'
|
||||
},
|
||||
{
|
||||
brand: 'zotac',
|
||||
model: 'trinity',
|
||||
series: '3080',
|
||||
url: 'https://www.caseking.de/zotac-gaming-geforce-rtx-3080-trinity-10240-mb-gddr6x-gczt-163.html'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'rog strix',
|
||||
series: '3090',
|
||||
url: 'https://www.caseking.de/asus-geforce-rtx-3090-rog-strix-24g-24576-mb-gddr6x-gcas-397.html'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'rog strix oc',
|
||||
series: '3090',
|
||||
url: 'https://www.caseking.de/asus-geforce-rtx-3090-rog-strix-o24g-24576-mb-gddr6x-gcas-398.html'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'tuf',
|
||||
series: '3090',
|
||||
url: 'https://www.caseking.de/asus-geforce-rtx-3090-tuf-gaming-24g-24576-mb-gddr6x-gcas-393.html'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'tuf oc',
|
||||
series: '3090',
|
||||
url: 'https://www.caseking.de/asus-geforce-rtx-3090-tuf-gaming-o24g-24576-mb-gddr6x-gcas-395.html'
|
||||
},
|
||||
{
|
||||
brand: 'evga',
|
||||
model: 'ftw3',
|
||||
series: '3090',
|
||||
url: 'https://www.caseking.de/evga-geforce-rtx-3090-ftw3-gaming-24576-mb-gddr6x-gcev-421.html'
|
||||
},
|
||||
{
|
||||
brand: 'evga',
|
||||
model: 'ftw3 ultra',
|
||||
series: '3090',
|
||||
url: 'https://www.caseking.de/evga-geforce-rtx-3090-ftw3-ultra-gaming-24576-mb-gddr6x-gcev-422.html'
|
||||
},
|
||||
{
|
||||
brand: 'evga',
|
||||
model: 'xc3',
|
||||
series: '3090',
|
||||
url: 'https://www.caseking.de/evga-geforce-rtx-3090-xc3-gaming-24576-mb-gddr6x-gcev-419.html'
|
||||
},
|
||||
{
|
||||
brand: 'evga',
|
||||
model: 'xc3 black',
|
||||
series: '3090',
|
||||
url: 'https://www.caseking.de/evga-geforce-rtx-3090-xc3-black-gaming-24576-mb-gddr6x-gcev-418.html'
|
||||
},
|
||||
{
|
||||
brand: 'evga',
|
||||
model: 'xc3 ultra',
|
||||
series: '3090',
|
||||
url: 'https://www.caseking.de/evga-geforce-rtx-3090-xc3-ultra-gaming-24576-mb-gddr6x-gcev-420.html'
|
||||
},
|
||||
{
|
||||
brand: 'gigabyte',
|
||||
model: 'eagle oc',
|
||||
series: '3090',
|
||||
url: 'https://www.caseking.de/gigabyte-geforce-rtx-3090-eagle-oc-24g-24576-mb-gddr6x-gcgb-329.html'
|
||||
},
|
||||
{
|
||||
brand: 'gigabyte',
|
||||
model: 'gaming oc',
|
||||
series: '3090',
|
||||
url: 'https://www.caseking.de/gigabyte-geforce-rtx-3090-gaming-oc-24g-24576-mb-gddr6x-gcgb-328.html'
|
||||
},
|
||||
{
|
||||
brand: 'inno3d',
|
||||
model: 'gaming x3',
|
||||
series: '3090',
|
||||
url: 'https://www.caseking.de/inno3d-geforce-rtx-3090-gaming-x3-24576-mb-gddr6x-gci3-172.html'
|
||||
},
|
||||
{
|
||||
brand: 'inno3d',
|
||||
model: 'ichill x3',
|
||||
series: '3090',
|
||||
url: 'https://www.caseking.de/inno3d-geforce-rtx-3090-ichill-x3-24576-mb-gddr6x-gci3-168.html'
|
||||
},
|
||||
{
|
||||
brand: 'inno3d',
|
||||
model: 'ichill x4',
|
||||
series: '3090',
|
||||
url: 'https://www.caseking.de/inno3d-geforce-rtx-3090-ichill-x4-24576-mb-gddr6x-gci3-167.html'
|
||||
},
|
||||
{
|
||||
brand: 'msi',
|
||||
model: 'gaming x trio',
|
||||
series: '3090',
|
||||
url: 'https://www.caseking.de/msi-geforce-rtx-3090-gaming-x-trio-24g-24576-mb-gddr6x-gcmc-244.html'
|
||||
},
|
||||
{
|
||||
brand: 'pny',
|
||||
model: 'xlr8 rgb',
|
||||
series: '3090',
|
||||
url: 'https://www.caseking.de/pny-geforce-rtx-3090-xlr8-gaming-epic-x-rgb-24576-mb-gddr6x-gcpn-073.html'
|
||||
},
|
||||
{
|
||||
brand: 'pny',
|
||||
model: 'xlr8 rgb',
|
||||
series: '3090',
|
||||
url: 'https://www.caseking.de/pny-geforce-rtx-3090-xlr8-gaming-revel-epic-x-rgb-24576-mb-gddr6x-gcpn-074.html'
|
||||
},
|
||||
{
|
||||
brand: 'zotac',
|
||||
model: 'trinity',
|
||||
series: '3090',
|
||||
url: 'https://www.caseking.de/zotac-gaming-geforce-rtx-3090-trinity-24576-mb-gddr6x-gczt-162.html'
|
||||
}
|
||||
],
|
||||
name: 'caseking'
|
||||
};
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
import {Store} from './store';
|
||||
import {getProductLinksBuilder} from './helpers/card';
|
||||
|
||||
export const Ccl: Store = {
|
||||
labels: {
|
||||
inStock: {
|
||||
container: '#pnlAddToBasket',
|
||||
text: ['add to basket']
|
||||
},
|
||||
maxPrice: {
|
||||
container: '#pnlPriceText > p',
|
||||
euroFormat: false // Note: CCL uses non-euroFromat as price seperator
|
||||
},
|
||||
outOfStock: {
|
||||
container: '#pnlSoldOut',
|
||||
text: ['sold out', 'coming soon']
|
||||
}
|
||||
},
|
||||
links: [
|
||||
{
|
||||
brand: 'test:brand',
|
||||
model: 'test:model',
|
||||
series: 'test:series',
|
||||
url: 'https://www.cclonline.com/product/296443/RTX-2060-SUPER-VENTUS-GP-OC/Graphics-Cards/MSI-GeForce-RTX-2060-SUPER-VENTUS-GP-OC-8GB-Overclocked-Graphics-Card/VGA5671/'
|
||||
}
|
||||
],
|
||||
linksBuilder: {
|
||||
builder: getProductLinksBuilder({
|
||||
productsSelector: '.productListingContainerOuter .productList',
|
||||
sitePrefix: 'https://www.cclonline.com',
|
||||
titleAttribute: 'title',
|
||||
titleSelector: '.productList_Detail a[title]'
|
||||
}),
|
||||
urls: [
|
||||
{
|
||||
series: '3070',
|
||||
url: 'https://www.cclonline.com/category/430/PC-Components/Graphics-Cards/GeForce-RTX-3070-Graphics-Cards/'
|
||||
},
|
||||
{
|
||||
series: '3080',
|
||||
url: 'https://www.cclonline.com/category/430/PC-Components/Graphics-Cards/GeForce-RTX-3080-Graphics-Cards/'
|
||||
},
|
||||
{
|
||||
series: '3090',
|
||||
url: 'https://www.cclonline.com/category/430/PC-Components/Graphics-Cards/GeForce-RTX-3090-Graphics-Cards/'
|
||||
}
|
||||
]
|
||||
},
|
||||
name: 'ccl',
|
||||
waitUntil: 'domcontentloaded'
|
||||
};
|
||||
@@ -0,0 +1,455 @@
|
||||
import {Store} from './store';
|
||||
|
||||
export const Computeruniverse: Store = {
|
||||
labels: {
|
||||
inStock: {
|
||||
container: '.availability',
|
||||
text: ['bestellartikel', 'auf lager und sofort lieferbar', 'kurzfristig verfügbar']
|
||||
},
|
||||
maxPrice: {
|
||||
container: '.product-price',
|
||||
euroFormat: true
|
||||
}
|
||||
},
|
||||
links: [
|
||||
{
|
||||
brand: 'test:brand',
|
||||
model: 'test:model',
|
||||
series: 'test:series',
|
||||
url: 'https://www.computeruniverse.net/de/gainward-geforce-gtx-1660-super-ghost-6-gb-high-end-grafikkarte'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'dual',
|
||||
series: '3070',
|
||||
url: 'https://www.computeruniverse.net/de/asus-geforce-rtx3070-dual-rtx3070-8g-8-gb-enthusiast-grafikkarte'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'dual oc',
|
||||
series: '3070',
|
||||
url: 'https://www.computeruniverse.net/de/asus-geforce-rtx3070-dual-oc-dual-rtx3070-o8g-8-gb-oc-enthusiast-grafikkarte'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'rog strix',
|
||||
series: '3070',
|
||||
url: 'https://www.computeruniverse.net/de/asus-rog-strix-geforce-rtx3070-gaming-8-gb-enthusiast-grafikkarte'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'rog strix oc',
|
||||
series: '3070',
|
||||
url: 'https://www.computeruniverse.net/de/asus-rog-strix-geforce-rtx3070-gaming-oc-8-gb-oc-enthusiast-grafikkarte'
|
||||
},
|
||||
{
|
||||
brand: 'evga',
|
||||
model: 'xc3 black',
|
||||
series: '3070',
|
||||
url: 'https://www.computeruniverse.net/de/evga-geforce-rtx3070-xc3-black'
|
||||
},
|
||||
{
|
||||
brand: 'gainward',
|
||||
model: 'phoenix',
|
||||
series: '3070',
|
||||
url: 'https://www.computeruniverse.net/de/gainward-geforce-rtx3070-phoenix-8-gb-enthusiast-grafikkarte'
|
||||
},
|
||||
{
|
||||
brand: 'gainward',
|
||||
model: 'phoenix gs',
|
||||
series: '3070',
|
||||
url: 'https://www.computeruniverse.net/de/gainward-geforce-rtx3070-phoenix-gs-8-gb-enthusiast-grafikkarte'
|
||||
},
|
||||
{
|
||||
brand: 'gigabyte',
|
||||
model: 'eagle',
|
||||
series: '3070',
|
||||
url: 'https://www.computeruniverse.net/de/gigabyte-geforce-rtx3070-eagle-8-gb-enthusiast-grafikkarte'
|
||||
},
|
||||
{
|
||||
brand: 'gigabyte',
|
||||
model: 'eagle oc',
|
||||
series: '3070',
|
||||
url: 'https://www.computeruniverse.net/de/gigabyte-geforce-rtx3070-eagle-oc-8-gb-enthusiast-grafikkarte'
|
||||
},
|
||||
{
|
||||
brand: 'gigabyte',
|
||||
model: 'gaming oc',
|
||||
series: '3070',
|
||||
url: 'https://www.computeruniverse.net/de/gigabyte-geforce-rtx3070-gaming-oc-8-gb-oc-enthusiast-grafikkarte'
|
||||
},
|
||||
{
|
||||
brand: 'inno3d',
|
||||
model: 'ichill x3',
|
||||
series: '3070',
|
||||
url: 'https://www.computeruniverse.net/de/inno3d-geforce-rtx3070-ichill-x3'
|
||||
},
|
||||
{
|
||||
brand: 'inno3d',
|
||||
model: 'ichill x4',
|
||||
series: '3070',
|
||||
url: 'https://www.computeruniverse.net/de/inno3d-geforce-rtx3070-ichill-x4'
|
||||
},
|
||||
{
|
||||
brand: 'msi',
|
||||
model: 'gaming x trio',
|
||||
series: '3070',
|
||||
url: 'https://www.computeruniverse.net/de/msi-geforce-rtx3070-gaming-x-trio-8-gb-enthusiast-grafikkarte'
|
||||
},
|
||||
{
|
||||
brand: 'msi',
|
||||
model: 'ventus 2x oc',
|
||||
series: '3070',
|
||||
url: 'https://www.computeruniverse.net/de/msi-geforce-rtx3070-ventus-2x-oc-8-gb-oc-enthusiast-grafikkarte'
|
||||
},
|
||||
{
|
||||
brand: 'msi',
|
||||
model: 'ventus 3x oc',
|
||||
series: '3070',
|
||||
url: 'https://www.computeruniverse.net/de/msi-geforce-rtx3070-ventus-3x-oc-8-gb-oc-enthusiast-grafikkarte'
|
||||
},
|
||||
{
|
||||
brand: 'palit',
|
||||
model: 'gaming pro',
|
||||
series: '3070',
|
||||
url: 'https://www.computeruniverse.net/de/palit-geforce-rtx3070-gaming-pro-8-gb'
|
||||
},
|
||||
{
|
||||
brand: 'pny',
|
||||
model: 'dual fan',
|
||||
series: '3070',
|
||||
url: 'https://www.computeruniverse.net/de/pny-geforce-rtx3070-m-dual-8-gb'
|
||||
},
|
||||
{
|
||||
brand: 'pny',
|
||||
model: 'xlr8 rgb',
|
||||
series: '3070',
|
||||
url: 'https://www.computeruniverse.net/de/pny-geforce-rtx3070-xlr8-gaming-epic-x-rgb-p-8-gb-enthusiast-grafikkarte'
|
||||
},
|
||||
{
|
||||
brand: 'zotac',
|
||||
model: 'twin edge oc',
|
||||
series: '3070',
|
||||
url: 'https://www.computeruniverse.net/de/zotac-gaming-geforce-rtx3070-twin-edge-oc-8-gb-oc'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'rog strix',
|
||||
series: '3080',
|
||||
url: 'https://www.computeruniverse.net/de/asus-rog-strix-geforce-rtx3080-gaming-10-gb-enthusiast-grafikkarte'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'rog strix oc',
|
||||
series: '3080',
|
||||
url: 'https://www.computeruniverse.net/de/asus-rog-strix-geforce-rtx3080-gaming-oc-10-gb-oc-enthusiast-grafikkarte'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'tuf',
|
||||
series: '3080',
|
||||
url: 'https://www.computeruniverse.net/de/asus-tuf-geforce-rtx3080-gaming-tuf-rtx3080-10g-gaming-10-gb-enthusiast-grafikkarte'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'tuf oc',
|
||||
series: '3080',
|
||||
url: 'https://www.computeruniverse.net/de/asus-tuf-geforce-rtx3080-gaming-oc-tuf-rtx3080-o10g-gaming-10-gb-oc-enthusiast-grafikkarte'
|
||||
},
|
||||
{
|
||||
brand: 'evga',
|
||||
model: 'ftw3',
|
||||
series: '3080',
|
||||
url: 'https://www.computeruniverse.net/de/evga-geforce-rtx3080-ftw3-10-gb-high-end-grafikkarte'
|
||||
},
|
||||
{
|
||||
brand: 'evga',
|
||||
model: 'ftw3 ultra',
|
||||
series: '3080',
|
||||
url: 'https://www.computeruniverse.net/de/evga-geforce-rtx3080-ultra-ftw3-10-gb-oc-enthusiast-grafikkarte'
|
||||
},
|
||||
{
|
||||
brand: 'evga',
|
||||
model: 'xc3',
|
||||
series: '3080',
|
||||
url: 'https://www.computeruniverse.net/de/evga-geforce-rtx3080-xc3-10-gb-enthusiast-grafikkarte'
|
||||
},
|
||||
{
|
||||
brand: 'evga',
|
||||
model: 'xc3 black',
|
||||
series: '3080',
|
||||
url: 'https://www.computeruniverse.net/de/evga-geforce-rtx3080-xc3-black-10-gb-enthusiast-grafikkarte'
|
||||
},
|
||||
{
|
||||
brand: 'evga',
|
||||
model: 'xc3 ultra',
|
||||
series: '3080',
|
||||
url: 'https://www.computeruniverse.net/de/evga-geforce-rtx3080-xc3-ultra-10-gb-enthusiast-grafikkarte'
|
||||
},
|
||||
{
|
||||
brand: 'gainward',
|
||||
model: 'phoenix',
|
||||
series: '3080',
|
||||
url: 'https://www.computeruniverse.net/de/gainward-geforce-rtx3080-phoenix-10-gb-enthusiast-grafikkarte'
|
||||
},
|
||||
{
|
||||
brand: 'gainward',
|
||||
model: 'phoenix gs',
|
||||
series: '3080',
|
||||
url: 'https://www.computeruniverse.net/de/gainward-geforce-rtx3080-phoenix-gs-10-gb-enthusiast-grafikkarte'
|
||||
},
|
||||
{
|
||||
brand: 'gigabyte',
|
||||
model: 'aorus master',
|
||||
series: '3080',
|
||||
url: 'https://www.computeruniverse.net/de/gigabyte-aorus-geforce-rtx3080-master-10-gb-oc-enthusiast-grafikkarte'
|
||||
},
|
||||
{
|
||||
brand: 'gigabyte',
|
||||
model: 'eagle oc',
|
||||
series: '3080',
|
||||
url: 'https://www.computeruniverse.net/de/gigabyte-geforce-rtx3080-eagle-oc-10-gb-oc-enthusiast-grafikkarte'
|
||||
},
|
||||
{
|
||||
brand: 'gigabyte',
|
||||
model: 'gaming oc',
|
||||
series: '3080',
|
||||
url: 'https://www.computeruniverse.net/de/gigabyte-geforce-rtx3080-gaming-oc-10-gb-enthusiast-grafikkarte'
|
||||
},
|
||||
{
|
||||
brand: 'gigabyte',
|
||||
model: 'vision oc',
|
||||
series: '3080',
|
||||
url: 'https://www.computeruniverse.net/de/gigabyte-geforce-rtx3080-vision-oc-10-gb-oc-enthusiast-grafikkarte'
|
||||
},
|
||||
{
|
||||
brand: 'inno3d',
|
||||
model: 'ichill x3',
|
||||
series: '3080',
|
||||
url: 'https://www.computeruniverse.net/de/inno3d-geforce-rtx3080-ichill-x3-10-gb-enthusiast-grafikkarte'
|
||||
},
|
||||
{
|
||||
brand: 'inno3d',
|
||||
model: 'ichill x4',
|
||||
series: '3080',
|
||||
url: 'https://www.computeruniverse.net/de/inno3d-geforce-rtx3080-ichill-x4-10-gb-enthusiast-grafikkarte'
|
||||
},
|
||||
{
|
||||
brand: 'inno3d',
|
||||
model: 'twin x2 oc',
|
||||
series: '3080',
|
||||
url: 'https://www.computeruniverse.net/de/inno3d-geforce-rtx3080-twin-x2-oc-10-gb-enthusiast-grafikkarte'
|
||||
},
|
||||
{
|
||||
brand: 'kfa2',
|
||||
model: 'sg oc',
|
||||
series: '3080',
|
||||
url: 'https://www.computeruniverse.net/de/kfa-geforce-rtx3080-sg-oc-10-gb-oc-enthusiast-grafikkarte'
|
||||
},
|
||||
{
|
||||
brand: 'msi',
|
||||
model: 'gaming x trio',
|
||||
series: '3080',
|
||||
url: 'https://www.computeruniverse.net/de/msi-geforce-rtx3080-gaming-x-trio-10-gb-enthusiast-grafikkarte'
|
||||
},
|
||||
{
|
||||
brand: 'msi',
|
||||
model: 'ventus 3x oc',
|
||||
series: '3080',
|
||||
url: 'https://www.computeruniverse.net/de/msi-geforce-rtx3080-ventus-3x-oc-10-gb-enthusiast-grafikkarte'
|
||||
},
|
||||
{
|
||||
brand: 'palit',
|
||||
model: 'gaming pro',
|
||||
series: '3080',
|
||||
url: 'https://www.computeruniverse.net/de/palit-geforce-rtx3080-gamingpro-10-gb-enthusiast-grafikkarte'
|
||||
},
|
||||
{
|
||||
brand: 'palit',
|
||||
model: 'gaming pro oc',
|
||||
series: '3080',
|
||||
url: 'https://www.computeruniverse.net/de/palit-geforce-rtx3080-gamingpro-oc-10-gb-oc-enthusiast-grafikkarte'
|
||||
},
|
||||
{
|
||||
brand: 'pny',
|
||||
model: 'xlr8 rgb',
|
||||
series: '3080',
|
||||
url: 'https://www.computeruniverse.net/de/pny-geforce-rtx-3080-xlr8-gaming-epic-x-rgb-p-10-gb-enthusiast-grafikkarte'
|
||||
},
|
||||
{
|
||||
brand: 'pny',
|
||||
model: 'xlr8 rgb',
|
||||
series: '3080',
|
||||
url: 'https://www.computeruniverse.net/de/pny-geforce-rtx3080-xlr8-gaming-epic-x-rgb-m-10-gb-enthusiast-grafikkarte'
|
||||
},
|
||||
{
|
||||
brand: 'zotac',
|
||||
model: 'amp holo',
|
||||
series: '3080',
|
||||
url: 'https://www.computeruniverse.net/de/zotac-geforce-rtx3080-amp-holo-10-gb-enthusiast-grafikkarte'
|
||||
},
|
||||
{
|
||||
brand: 'zotac',
|
||||
model: 'amp extreme holo',
|
||||
series: '3080',
|
||||
url: 'https://www.computeruniverse.net/de/zotac-geforce-rtx3080-amp-extreme-holo-10-gb-enthusiast-grafikkarte'
|
||||
},
|
||||
{
|
||||
brand: 'zotac',
|
||||
model: 'trinity',
|
||||
series: '3080',
|
||||
url: 'https://www.computeruniverse.net/de/zotac-gaming-geforce-rtx3080-trinity-10-gb-enthusiast-grafikkarte'
|
||||
},
|
||||
{
|
||||
brand: 'zotac',
|
||||
model: 'trinity oc',
|
||||
series: '3080',
|
||||
url: 'https://www.computeruniverse.net/de/zotac-gaming-geforce-rtx3080-trinity-oc-10-gb-enthusiast-grafikkarte'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'rog strix',
|
||||
series: '3090',
|
||||
url: 'https://www.computeruniverse.net/de/asus-rog-strix-geforce-rtx3090-gaming-24-gb-enthusiast-grafikkarte'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'rog strix oc',
|
||||
series: '3090',
|
||||
url: 'https://www.computeruniverse.net/de/asus-rog-strix-geforce-rtx3090-gaming-oc-24-gb-oc-enthusiast-grafikkarte'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'tuf',
|
||||
series: '3090',
|
||||
url: 'https://www.computeruniverse.net/de/asus-tuf-geforce-rtx3090-gaming-tuf-rtx3090-24g-gaming-24-gb-enthusiast-grafikkarte'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'tuf oc',
|
||||
series: '3090',
|
||||
url: 'https://www.computeruniverse.net/de/asus-tuf-geforce-rtx3090-gaming-oc-tuf-rtx3090-o24g-gaming-24-gb-oc-enthusiast-grafikkarte'
|
||||
},
|
||||
{
|
||||
brand: 'evga',
|
||||
model: 'ftw3',
|
||||
series: '3090',
|
||||
url: 'https://www.computeruniverse.net/de/evga-geforce-rtx3090-ftw3-gaming-24-gb-enthusiast-grafikkarte'
|
||||
},
|
||||
{
|
||||
brand: 'evga',
|
||||
model: 'ftw3 ultra',
|
||||
series: '3090',
|
||||
url: 'https://www.computeruniverse.net/de/evga-geforce-rtx3090-ftw3-ultra-gaming-24-gb-enthusiast-grafikkarte'
|
||||
},
|
||||
{
|
||||
brand: 'evga',
|
||||
model: 'xc3',
|
||||
series: '3090',
|
||||
url: 'https://www.computeruniverse.net/de/evga-geforce-rtx3090-xc3-gaming-24-gb-enthusiast-grafikkarte'
|
||||
},
|
||||
{
|
||||
brand: 'evga',
|
||||
model: 'xc3 black',
|
||||
series: '3090',
|
||||
url: 'https://www.computeruniverse.net/de/evga-geforce-rtx3090-xc3-black-gaming-24-gb-enthusiast-grafikkarte'
|
||||
},
|
||||
{
|
||||
brand: 'evga',
|
||||
model: 'xc3 ultra',
|
||||
series: '3090',
|
||||
url: 'https://www.computeruniverse.net/de/evga-geforce-rtx3090-xc3-ultra-gaming-24-gb-enthusiast-grafikkarte'
|
||||
},
|
||||
{
|
||||
brand: 'gainward',
|
||||
model: 'phoenix',
|
||||
series: '3090',
|
||||
url: 'https://www.computeruniverse.net/de/gainward-geforce-rtx3090-phoenix-24-gb-enthusiast-grafikkarte'
|
||||
},
|
||||
{
|
||||
brand: 'gainward',
|
||||
model: 'phoenix gs oc',
|
||||
series: '3090',
|
||||
url: 'https://www.computeruniverse.net/de/gainward-geforce-rtx3090-phoenix-gs-24-gb-oc-enthusiast-grafikkarte'
|
||||
},
|
||||
{
|
||||
brand: 'gigabyte',
|
||||
model: 'aorus master',
|
||||
series: '3090',
|
||||
url: 'https://www.computeruniverse.net/de/gigabyte-aorus-geforce-rtx3090-master-24gb'
|
||||
},
|
||||
{
|
||||
brand: 'gigabyte',
|
||||
model: 'eagle oc',
|
||||
series: '3090',
|
||||
url: 'https://www.computeruniverse.net/de/gigabyte-geforce-rtx3090-eagle-oc-24-gb-oc-enthusiast-grafikkarte'
|
||||
},
|
||||
{
|
||||
brand: 'gigabyte',
|
||||
model: 'gaming oc',
|
||||
series: '3090',
|
||||
url: 'https://www.computeruniverse.net/de/gigabyte-geforce-rtx3090-gaming-oc-24-gb-oc'
|
||||
},
|
||||
{
|
||||
brand: 'inno3d',
|
||||
model: 'ichill x3',
|
||||
series: '3090',
|
||||
url: 'https://www.computeruniverse.net/de/inno3d-geforce-rtx3090-ichill-x3-24-gb-enthusiast-grafikkarte'
|
||||
},
|
||||
{
|
||||
brand: 'inno3d',
|
||||
model: 'ichill x4',
|
||||
series: '3090',
|
||||
url: 'https://www.computeruniverse.net/de/inno3d-geforce-rtx3090-ichill-x4-24-gb-enthusiast-grafikkarte'
|
||||
},
|
||||
{
|
||||
brand: 'kfa2',
|
||||
model: 'sg oc',
|
||||
series: '3090',
|
||||
url: 'https://www.computeruniverse.net/de/kfa-geforce-rtx3090-sg-oc-24-gb-oc-enthusiast-grafikkarte'
|
||||
},
|
||||
{
|
||||
brand: 'msi',
|
||||
model: 'gaming x trio',
|
||||
series: '3090',
|
||||
url: 'https://www.computeruniverse.net/de/msi-geforce-rtx3090-gaming-x-trio-24-gb-enthusiast-grafikkarte'
|
||||
},
|
||||
{
|
||||
brand: 'msi',
|
||||
model: 'ventus 3x oc',
|
||||
series: '3090',
|
||||
url: 'https://www.computeruniverse.net/de/msi-geforce-rtx3090-ventus-3x-oc-24-gb-oc-enthusiast-grafikkarte'
|
||||
},
|
||||
{
|
||||
brand: 'palit',
|
||||
model: 'gaming pro',
|
||||
series: '3090',
|
||||
url: 'https://www.computeruniverse.net/de/palit-geforce-rtx3090-gamingpro-24-gb-enthusiast-grafikkarte'
|
||||
},
|
||||
{
|
||||
brand: 'palit',
|
||||
model: 'gaming pro oc',
|
||||
series: '3090',
|
||||
url: 'https://www.computeruniverse.net/de/palit-geforce-rtx3090-gamingpro-oc-24-gb-oc-enthusiast-grafikkarte'
|
||||
},
|
||||
{
|
||||
brand: 'pny',
|
||||
model: 'xlr8 rgb',
|
||||
series: '3090',
|
||||
url: 'https://www.computeruniverse.net/de/pny-geforce-rtx3090-xlr8-gaming-epic-x-rgb-m-24-gb-enthusiast-grafikkarte'
|
||||
},
|
||||
{
|
||||
brand: 'pny',
|
||||
model: 'xlr8 rgb',
|
||||
series: '3090',
|
||||
url: 'https://www.computeruniverse.net/de/pny-geforce-rtx3090-xlr8-gaming-epic-x-rgb-p-24-gb-enthusiast-grafikkarte'
|
||||
},
|
||||
{
|
||||
brand: 'zotac',
|
||||
model: 'trinity',
|
||||
series: '3090',
|
||||
url: 'https://www.computeruniverse.net/de/zotac-gaming-geforce-rtx-3090-trinity-24-gb-enthusiast-grafikkarte'
|
||||
}
|
||||
],
|
||||
name: 'computeruniverse'
|
||||
};
|
||||
@@ -0,0 +1,123 @@
|
||||
import {Store} from './store';
|
||||
|
||||
export const Coolblue: Store = {
|
||||
labels: {
|
||||
inStock: {
|
||||
container: '.product-order',
|
||||
text: ['bestel snel', 'morgen in huis']
|
||||
},
|
||||
maxPrice: {
|
||||
container: '.js-order-block .sales-price__current',
|
||||
euroFormat: true
|
||||
},
|
||||
outOfStock: {
|
||||
container: '.product-order',
|
||||
text: ['binnenkort leverbaar', 'tijdelijk uitverkocht']
|
||||
}
|
||||
},
|
||||
links: [
|
||||
{
|
||||
brand: 'test:brand',
|
||||
model: 'test:model',
|
||||
series: 'test:series',
|
||||
url: 'https://www.coolblue.nl/product/826844/'
|
||||
},
|
||||
{
|
||||
brand: 'gigabyte',
|
||||
model: 'eagle oc',
|
||||
series: '3080',
|
||||
url: 'https://www.coolblue.nl/product/868737/'
|
||||
},
|
||||
{
|
||||
brand: 'msi',
|
||||
model: 'ventus 3x oc',
|
||||
series: '3080',
|
||||
url: 'https://www.coolblue.nl/product/868741/'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'tuf',
|
||||
series: '3080',
|
||||
url: 'https://www.coolblue.nl/product/868726/'
|
||||
},
|
||||
{
|
||||
brand: 'gigabyte',
|
||||
model: 'gaming oc',
|
||||
series: '3080',
|
||||
url: 'https://www.coolblue.nl/product/868736/'
|
||||
},
|
||||
{
|
||||
brand: 'msi',
|
||||
model: 'gaming x trio',
|
||||
series: '3080',
|
||||
url: 'https://www.coolblue.nl/product/868740/'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'tuf oc',
|
||||
series: '3080',
|
||||
url: 'https://www.coolblue.nl/product/868733/'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'rog strix oc gaming',
|
||||
series: '3080',
|
||||
url: 'https://www.coolblue.nl/product/868731/'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'rog strix gaming',
|
||||
series: '3080',
|
||||
url: 'https://www.coolblue.nl/product/868732/'
|
||||
},
|
||||
{
|
||||
brand: 'msi',
|
||||
model: 'gaming x trio',
|
||||
series: '3090',
|
||||
url: 'https://www.coolblue.nl/product/868738/'
|
||||
},
|
||||
{
|
||||
brand: 'msi',
|
||||
model: 'ventus 3x oc',
|
||||
series: '3090',
|
||||
url: 'https://www.coolblue.nl/product/868739/'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'tuf oc',
|
||||
series: '3090',
|
||||
url: 'https://www.coolblue.nl/product/868730/'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'tuf',
|
||||
series: '3090',
|
||||
url: 'https://www.coolblue.nl/product/868727/'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'rog strix oc gaming',
|
||||
series: '3090',
|
||||
url: 'https://www.coolblue.nl/product/868728/'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'rog strix gaming',
|
||||
series: '3090',
|
||||
url: 'https://www.coolblue.nl/product/868729/'
|
||||
},
|
||||
{
|
||||
brand: 'gigabyte',
|
||||
model: 'gaming oc',
|
||||
series: '3090',
|
||||
url: 'https://www.coolblue.nl/product/868734/'
|
||||
},
|
||||
{
|
||||
brand: 'gigabyte',
|
||||
model: 'eagle oc',
|
||||
series: '3090',
|
||||
url: 'https://www.coolblue.nl/product/868735/'
|
||||
}
|
||||
],
|
||||
name: 'coolblue'
|
||||
};
|
||||
@@ -0,0 +1,168 @@
|
||||
import {Store} from './store';
|
||||
|
||||
export const Coolmod: Store = {
|
||||
labels: {
|
||||
inStock: {
|
||||
container: '.product-availability',
|
||||
text: ['Envío']
|
||||
},
|
||||
outOfStock: {
|
||||
container: '.product-availability',
|
||||
text: ['Sin Stock']
|
||||
}
|
||||
},
|
||||
links: [
|
||||
{
|
||||
brand: 'test:brand',
|
||||
model: 'test:model',
|
||||
series: 'test:series',
|
||||
url: 'https://www.coolmod.com/kfa2-geforce-rtx-2060-super-1-click-oc-8gb-gddr6-tarjeta-grafica-precio'
|
||||
},
|
||||
{
|
||||
brand: 'gigabyte',
|
||||
model: 'eagle oc',
|
||||
series: '3080',
|
||||
url: 'https://www.coolmod.com/gigabyte-geforce-rtx-3080-eagle-oc-10gb-gddr6x-tarjeta-grafica-precio'
|
||||
},
|
||||
{
|
||||
brand: 'msi',
|
||||
model: 'ventus 3x oc',
|
||||
series: '3080',
|
||||
url: 'https://www.coolmod.com/msi-geforce-rtx-3080-ventus-3x-oc-10gb-gddr6x-tarjeta-grafica-precio'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'tuf',
|
||||
series: '3080',
|
||||
url: 'https://www.coolmod.com/asus-geforce-tuf-rtx-3080-gaming-10gb-gddr6x-tarjeta-grafica-precio'
|
||||
},
|
||||
{
|
||||
brand: 'gigabyte',
|
||||
model: 'gaming oc',
|
||||
series: '3080',
|
||||
url: 'https://www.coolmod.com/gigabyte-geforce-rtx-3080-gaming-oc-10gb-gddr6x-tarjeta-grafica-precio'
|
||||
},
|
||||
{
|
||||
brand: 'msi',
|
||||
model: 'gaming x trio',
|
||||
series: '3080',
|
||||
url: 'https://www.coolmod.com/msi-geforce-rtx-3080-gaming-x-trio-10gb-gddr6x-tarjeta-grafica-precio'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'tuf oc',
|
||||
series: '3080',
|
||||
url: 'https://www.coolmod.com/asus-geforce-tuf-rtx-3080-oc-gaming-10gb-gddr6x-tarjeta-grfica-precio'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'rog strix oc',
|
||||
series: '3080',
|
||||
url: 'https://www.coolmod.com/asus-rog-strix-geforce-rtx-3080-oc-10gb-gddr6x-tarjeta-grafica-precio'
|
||||
},
|
||||
{
|
||||
brand: 'evga',
|
||||
model: 'xc3 black',
|
||||
series: '3080',
|
||||
url: 'https://www.coolmod.com/evga-geforce-rtx-3080-xc3-black-gaming-10gb-gddr6x-tarjeta-grafica-precio'
|
||||
},
|
||||
{
|
||||
brand: 'zotac',
|
||||
model: 'trinity',
|
||||
series: '3080',
|
||||
url: 'https://www.coolmod.com/zotac-gaming-geforce-rtx-3080-trinity-10gb-gddr6x-tarjeta-grafica-precio'
|
||||
},
|
||||
{
|
||||
brand: 'evga',
|
||||
model: 'xc3 ultra',
|
||||
series: '3080',
|
||||
url: 'https://www.coolmod.com/evga-geforce-rtx-3080-xc3-ultra-gaming-10gb-gddr6x-tarjeta-grafica-precio'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'rog strix',
|
||||
series: '3080',
|
||||
url: 'https://www.coolmod.com/asus-rog-strix-geforce-rtx-3080-10gb-gddr6x-tarjeta-grfica-precio'
|
||||
},
|
||||
{
|
||||
brand: 'zotac',
|
||||
model: 'trinity oc',
|
||||
series: '3080',
|
||||
url: 'https://www.coolmod.com/zotac-gaming-geforce-rtx-3080-trinity-oc-10gb-gddr6x-tarjeta-grafica-precio'
|
||||
},
|
||||
{
|
||||
brand: 'gigabyte',
|
||||
model: 'vision oc',
|
||||
series: '3080',
|
||||
url: 'https://www.coolmod.com/gigabyte-geforce-rtx-3080-vision-oc-10gb-gddr6x-tarjeta-grafica-precio'
|
||||
},
|
||||
{
|
||||
brand: 'evga',
|
||||
model: 'xc3',
|
||||
series: '3080',
|
||||
url: 'https://www.coolmod.com/evga-geforce-rtx-3080-xc3-gaming-10gb-gddr6x-tarjeta-grafica-precio'
|
||||
},
|
||||
{
|
||||
brand: 'evga',
|
||||
model: 'ftw3 ultra',
|
||||
series: '3080',
|
||||
url: 'https://www.coolmod.com/evga-geforce-rtx-3080-ftw3-ultra-gaming-10gb-gddr6x-tarjeta-grafica-precio'
|
||||
},
|
||||
{
|
||||
brand: 'gigabyte',
|
||||
model: 'aorus master',
|
||||
series: '3080',
|
||||
url: 'https://www.coolmod.com/gigabyte-aorus-geforce-rtx-3080-master-10gb-gddr6x-tarjeta-grafica-precio'
|
||||
},
|
||||
{
|
||||
brand: 'gigabyte',
|
||||
model: 'aorus xtreme',
|
||||
series: '3080',
|
||||
url: 'https://www.coolmod.com/gigabyte-aorus-geforce-rtx-3080-xtreme-10gb-gddr6x-tarjeta-grafica-precio'
|
||||
},
|
||||
{
|
||||
brand: 'evga',
|
||||
model: 'ftw3',
|
||||
series: '3080',
|
||||
url: 'https://www.coolmod.com/evga-geforce-rtx-3080-ftw3-gaming-10gb-gddr6x-tarjeta-grafica-precio'
|
||||
},
|
||||
{
|
||||
brand: 'pny',
|
||||
model: 'xlr8 rgb',
|
||||
series: '3080',
|
||||
url: 'https://www.coolmod.com/pny-geforce-rtx-3080-10gb-xlr8-gaming-epic-x-rgb-10gb-gddr6x-tarjeta-grafica-precio'
|
||||
},
|
||||
{
|
||||
brand: 'pny',
|
||||
model: 'xlr8',
|
||||
series: '3080',
|
||||
url: 'https://www.coolmod.com/pny-geforce-rtx-3080-xlr8-gaming-epic-x-rgb-10gb-gddr6x-tarjeta-grafica-precio'
|
||||
},
|
||||
{
|
||||
brand: 'kfa2',
|
||||
model: 'sg-oc',
|
||||
series: '3080',
|
||||
url: 'https://www.coolmod.com/kfa2-geforce-rtx-3080-sg-1-click-oc-10gb-gddr6x-tarjeta-grafica-precio'
|
||||
},
|
||||
{
|
||||
brand: 'inno3d',
|
||||
model: 'ichill x4',
|
||||
series: '3080',
|
||||
url: 'https://www.coolmod.com/inno3d-geforce-rtx-3080-ichill-x4-10gb-gddr6x-tarjeta-grafica-precio'
|
||||
},
|
||||
{
|
||||
brand: 'inno3d',
|
||||
model: 'ichill x3',
|
||||
series: '3080',
|
||||
url: 'https://www.coolmod.com/inno3d-geforce-rtx-3080-ichill-x3-10gb-gddr6x-tarjeta-grafica-precio'
|
||||
},
|
||||
{
|
||||
brand: 'inno3d',
|
||||
model: 'twin x2 oc',
|
||||
series: '3080',
|
||||
url: 'https://www.coolmod.com/inno3d-geforce-rtx-3080-twin-x2-oc-10gb-gddr6x-tarjeta-grafica-precio'
|
||||
}
|
||||
],
|
||||
name: 'coolmod'
|
||||
};
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
import {Store} from './store';
|
||||
import {getProductLinksBuilder} from './helpers/card';
|
||||
|
||||
export const Currys: Store = {
|
||||
labels: {
|
||||
inStock: {
|
||||
container: '#product-actions button',
|
||||
text: ['add to basket']
|
||||
},
|
||||
maxPrice: {
|
||||
container: '#product-actions span[class*="ProductPriceBlock__Price"]',
|
||||
euroFormat: false // Note: Currys uses non-euroFromat as price seperator
|
||||
},
|
||||
outOfStock: {
|
||||
container: '#product-actions .unavailable',
|
||||
text: ['not available for delivery']
|
||||
}
|
||||
},
|
||||
links: [
|
||||
{
|
||||
brand: 'test:brand',
|
||||
model: 'test:model',
|
||||
series: 'test:series',
|
||||
url: 'https://www.currys.co.uk/gbuk/computing-accessories/components-upgrades/graphics-cards/msi-geforce-rtx-2060-8-gb-super-ventus-gp-oc-graphics-card-10196803-pdt.html'
|
||||
}
|
||||
],
|
||||
linksBuilder: {
|
||||
builder: getProductLinksBuilder({
|
||||
productsSelector: '.resultList .product',
|
||||
sitePrefix: 'https://www.currys.co.uk',
|
||||
titleSelector: '.productTitle',
|
||||
urlSelector: 'a[href]'
|
||||
}),
|
||||
urls: [
|
||||
{
|
||||
series: '3080',
|
||||
url: 'https://www.currys.co.uk/gbuk/rtx-3080/components-upgrades/graphics-cards/324_3091_30343_xx_ba00013562-bv00313767/xx-criteria.html'
|
||||
},
|
||||
{
|
||||
series: '3090',
|
||||
url: 'https://www.currys.co.uk/gbuk/rtx-3090/components-upgrades/graphics-cards/324_3091_30343_xx_ba00013562-bv00313725/xx-criteria.html'
|
||||
}
|
||||
]
|
||||
},
|
||||
name: 'currys',
|
||||
waitUntil: 'domcontentloaded'
|
||||
};
|
||||
@@ -0,0 +1,99 @@
|
||||
import {Store} from './store';
|
||||
|
||||
export const Cyberport: Store = {
|
||||
labels: {
|
||||
inStock: {
|
||||
container: '.tooltipAvailabilityParent',
|
||||
text: ['sofort verfügbar']
|
||||
},
|
||||
maxPrice: {
|
||||
container: '#productDetailOverview .price',
|
||||
euroFormat: true
|
||||
},
|
||||
outOfStock: {
|
||||
container: '.tooltipAvailabilityParent',
|
||||
text: ['noch nicht verfügbar']
|
||||
}
|
||||
},
|
||||
links: [
|
||||
{
|
||||
brand: 'test:brand',
|
||||
model: 'test:model',
|
||||
series: 'test:series',
|
||||
url: 'https://www.cyberport.de?DEEP=2E12-3KL'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'rog strix',
|
||||
series: '3080',
|
||||
url: 'https://www.cyberport.de?DEEP=2E07-51S'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'rog strix oc',
|
||||
series: '3080',
|
||||
url: 'https://www.cyberport.de?DEEP=2E07-51T'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'tuf',
|
||||
series: '3080',
|
||||
url: 'https://www.cyberport.de?DEEP=2E07-51L'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'tuf oc',
|
||||
series: '3080',
|
||||
url: 'https://www.cyberport.de?DEEP=2E07-51N'
|
||||
},
|
||||
{
|
||||
brand: 'gigabyte',
|
||||
model: 'aorus master',
|
||||
series: '3080',
|
||||
url: 'https://www.cyberport.de?DEEP=2E21-537'
|
||||
},
|
||||
{
|
||||
brand: 'gigabyte',
|
||||
model: 'eagle oc',
|
||||
series: '3080',
|
||||
url: 'https://www.cyberport.de?DEEP=2E21-52Y'
|
||||
},
|
||||
{
|
||||
brand: 'gigabyte',
|
||||
model: 'aorus master',
|
||||
series: '3090',
|
||||
url: 'https://www.cyberport.de?DEEP=2e21-532'
|
||||
},
|
||||
{
|
||||
brand: 'gigabyte',
|
||||
model: 'gaming oc',
|
||||
series: '3080',
|
||||
url: 'https://www.cyberport.de?DEEP=2E21-52Z'
|
||||
},
|
||||
{
|
||||
brand: 'msi',
|
||||
model: 'gaming x trio',
|
||||
series: '3080',
|
||||
url: 'https://www.cyberport.de?DEEP=2E12-3L6'
|
||||
},
|
||||
{
|
||||
brand: 'msi',
|
||||
model: 'ventus 3x oc',
|
||||
series: '3080',
|
||||
url: 'https://www.cyberport.de?DEEP=2E12-3L7c'
|
||||
},
|
||||
{
|
||||
brand: 'zotac',
|
||||
model: 'trinity',
|
||||
series: '3080',
|
||||
url: 'https://www.cyberport.de?DEEP=2E13-1H4'
|
||||
},
|
||||
{
|
||||
brand: 'zotac',
|
||||
model: 'trinity oc',
|
||||
series: '3080',
|
||||
url: 'https://www.cyberport.de?DEEP=2E13-1H7'
|
||||
}
|
||||
],
|
||||
name: 'cyberport'
|
||||
};
|
||||
@@ -0,0 +1,51 @@
|
||||
import {Store} from './store';
|
||||
import {getProductLinksBuilder} from './helpers/card';
|
||||
|
||||
export const Ebuyer: Store = {
|
||||
labels: {
|
||||
inStock: {
|
||||
container: '.purchase-info',
|
||||
text: ['add to basket', 'in stock']
|
||||
},
|
||||
maxPrice: {
|
||||
container: '.purchase-info__price .price',
|
||||
euroFormat: false // Note: ebuyer uses non-euroFromat as price seperator
|
||||
},
|
||||
outOfStock: {
|
||||
container: '.purchase-info',
|
||||
text: ['coming soon', 'we are expecting this item on']
|
||||
}
|
||||
},
|
||||
links: [
|
||||
{
|
||||
brand: 'test:brand',
|
||||
model: 'test:model',
|
||||
series: 'test:series',
|
||||
url: 'https://www.ebuyer.com/874209-gigabyte-geforce-rtx-2060-windforce-6gb-oc-graphics-card-gv-n2060wf2oc-6gd-v2'
|
||||
}
|
||||
],
|
||||
linksBuilder: {
|
||||
builder: getProductLinksBuilder({
|
||||
productsSelector: '#list-view .listing-product',
|
||||
sitePrefix: 'https://www.ebuyer.com',
|
||||
titleSelector: '.listing-product-title',
|
||||
urlSelector: 'a[href]'
|
||||
}),
|
||||
urls: [
|
||||
{
|
||||
series: '3070',
|
||||
url: 'https://www.ebuyer.com/store/Components/cat/Graphics-Cards-Nvidia/subcat/GeForce-RTX-3070'
|
||||
},
|
||||
{
|
||||
series: '3080',
|
||||
url: 'https://www.ebuyer.com/store/Components/cat/Graphics-Cards-Nvidia/subcat/GeForce-RTX-3080'
|
||||
},
|
||||
{
|
||||
series: '3090',
|
||||
url: 'https://www.ebuyer.com/store/Components/cat/Graphics-Cards-Nvidia/subcat/GeForce-RTX-3090'
|
||||
}
|
||||
]
|
||||
},
|
||||
name: 'ebuyer',
|
||||
waitUntil: 'domcontentloaded'
|
||||
};
|
||||
@@ -8,29 +8,65 @@ export const EvgaEu: Store = {
|
||||
}
|
||||
},
|
||||
links: [
|
||||
{
|
||||
brand: 'evga',
|
||||
model: 'xc3 black',
|
||||
series: '3080',
|
||||
url: 'https://eu.evga.com/products/product.aspx?pn=10G-P5-3881-KR'
|
||||
},
|
||||
{
|
||||
brand: 'evga',
|
||||
model: 'ftw3',
|
||||
series: '3080',
|
||||
url: 'https://eu.evga.com/products/product.aspx?pn=10G-P5-3895-KR'
|
||||
},
|
||||
{
|
||||
brand: 'evga',
|
||||
model: 'ftw3 ultra',
|
||||
series: '3080',
|
||||
url: 'https://eu.evga.com/products/product.aspx?pn=10G-P5-3897-KR'
|
||||
},
|
||||
{
|
||||
brand: 'evga',
|
||||
model: 'xc3',
|
||||
series: '3080',
|
||||
url: 'https://eu.evga.com/products/product.aspx?pn=10G-P5-3883-KR'
|
||||
},
|
||||
{
|
||||
brand: 'evga',
|
||||
model: 'xc3 black',
|
||||
series: '3080',
|
||||
url: 'https://eu.evga.com/products/product.aspx?pn=10G-P5-3881-KR'
|
||||
},
|
||||
{
|
||||
brand: 'evga',
|
||||
model: 'xc3 ultra',
|
||||
series: '3080',
|
||||
url: 'https://eu.evga.com/products/product.aspx?pn=10G-P5-3885-KR'
|
||||
},
|
||||
{
|
||||
brand: 'evga',
|
||||
model: 'ftw3',
|
||||
series: '3090',
|
||||
url: 'https://eu.evga.com/products/product.aspx?pn=24G-P5-3985-KR'
|
||||
},
|
||||
{
|
||||
brand: 'evga',
|
||||
model: 'ftw3 ultra',
|
||||
series: '3090',
|
||||
url: 'https://eu.evga.com/products/product.aspx?pn=24G-P5-3987-KR'
|
||||
},
|
||||
{
|
||||
brand: 'evga',
|
||||
model: 'xc3',
|
||||
series: '3090',
|
||||
url: 'https://eu.evga.com/products/product.aspx?pn=24G-P5-3973-KR'
|
||||
},
|
||||
{
|
||||
brand: 'evga',
|
||||
model: 'xc3 black',
|
||||
series: '3090',
|
||||
url: 'https://eu.evga.com/products/product.aspx?pn=24G-P5-3971-KR'
|
||||
},
|
||||
{
|
||||
brand: 'evga',
|
||||
model: 'xc3 ultra',
|
||||
series: '3090',
|
||||
url: 'https://eu.evga.com/products/product.aspx?pn=24G-P5-3975-KR'
|
||||
}
|
||||
],
|
||||
name: 'evga-eu'
|
||||
|
||||
+48
-1
@@ -14,6 +14,24 @@ export const Evga: Store = {
|
||||
series: 'test:series',
|
||||
url: 'https://www.evga.com/products/product.aspx?pn=06G-P4-2065-KR'
|
||||
},
|
||||
{
|
||||
brand: 'evga',
|
||||
model: 'xc3 black',
|
||||
series: '3070',
|
||||
url: 'https://www.evga.com/products/product.aspx?pn=08G-P5-3751-KR'
|
||||
},
|
||||
{
|
||||
brand: 'evga',
|
||||
model: 'xc3 ultra',
|
||||
series: '3070',
|
||||
url: 'https://www.evga.com/products/product.aspx?pn=08G-P5-3755-KR'
|
||||
},
|
||||
{
|
||||
brand: 'evga',
|
||||
model: 'ftw3 ultra',
|
||||
series: '3070',
|
||||
url: 'https://www.evga.com/products/product.aspx?pn=08G-P5-3767-KR'
|
||||
},
|
||||
{
|
||||
brand: 'evga',
|
||||
model: 'xc3 black',
|
||||
@@ -43,8 +61,37 @@ export const Evga: Store = {
|
||||
model: 'xc3 ultra',
|
||||
series: '3080',
|
||||
url: 'https://www.evga.com/products/product.aspx?pn=10G-P5-3885-KR'
|
||||
},
|
||||
{
|
||||
brand: 'evga',
|
||||
model: 'xc3 black',
|
||||
series: '3090',
|
||||
url: 'https://www.evga.com/products/product.aspx?pn=24G-P5-3971-KR'
|
||||
},
|
||||
{
|
||||
brand: 'evga',
|
||||
model: 'ftw3 ultra',
|
||||
series: '3090',
|
||||
url: 'https://www.evga.com/products/product.aspx?pn=24G-P5-3987-KR'
|
||||
},
|
||||
{
|
||||
brand: 'evga',
|
||||
model: 'ftw3',
|
||||
series: '3090',
|
||||
url: 'https://www.evga.com/products/product.aspx?pn=24G-P5-3985-KR'
|
||||
},
|
||||
{
|
||||
brand: 'evga',
|
||||
model: 'xc3',
|
||||
series: '3090',
|
||||
url: 'https://www.evga.com/products/product.aspx?pn=24G-P5-3973-KR'
|
||||
},
|
||||
{
|
||||
brand: 'evga',
|
||||
model: 'xc3 ultra',
|
||||
series: '3090',
|
||||
url: 'https://www.evga.com/products/product.aspx?pn=24G-P5-3975-KR'
|
||||
}
|
||||
],
|
||||
name: 'evga'
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
import {Store} from './store';
|
||||
|
||||
export const Gamestop: Store = {
|
||||
labels: {
|
||||
inStock: {
|
||||
container: '.add-to-cart',
|
||||
text: ['add to cart']
|
||||
},
|
||||
maxPrice: {
|
||||
container: '.primary-details-row .actual-price',
|
||||
euroFormat: false
|
||||
},
|
||||
outOfStock: {
|
||||
container: '.add-to-cart',
|
||||
text: ['not available']
|
||||
}
|
||||
},
|
||||
links: [
|
||||
{
|
||||
brand: 'test:brand',
|
||||
model: 'test:model',
|
||||
series: 'test:series',
|
||||
url: 'https://www.gamestop.com/nav-pc-hardware-desktops/products/clx-set-tgmsetgxe9600bm-gaming-desktop/11096665'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'tuf oc',
|
||||
series: '3080',
|
||||
url: 'https://www.gamestop.com/video-games/pc/components/graphics-cards/products/tuf-gaming-geforce-rtx-3080-graphics-card/11109446.html'
|
||||
}
|
||||
],
|
||||
name: 'gamestop',
|
||||
successStatusCodes: [[0, 399], 404]
|
||||
};
|
||||
@@ -0,0 +1,52 @@
|
||||
import {Link, Store} from '..';
|
||||
import {Print, logger} from '../../../logger';
|
||||
import {delay, isStatusCodeInRange} from '../../../util';
|
||||
import {config} from '../../../config';
|
||||
|
||||
type Backoff = {
|
||||
count: number;
|
||||
time: number;
|
||||
};
|
||||
|
||||
const stores: Record<string, Backoff> = {};
|
||||
|
||||
export async function processBackoffDelay(store: Store, link: Link, statusCode: number): Promise<number> {
|
||||
/**
|
||||
* We treat statusCode 0 as successful as some of the puppeteer plugins
|
||||
* cause side-effects resulting in an empty response object even though
|
||||
* the page renders fine and its content is accessible.
|
||||
*/
|
||||
|
||||
let backoffStatusCodes = store.backoffStatusCodes;
|
||||
|
||||
if (!backoffStatusCodes) {
|
||||
backoffStatusCodes = [403];
|
||||
}
|
||||
|
||||
const isBackoff = isStatusCodeInRange(statusCode, backoffStatusCodes);
|
||||
let backoff = stores[store.name];
|
||||
|
||||
if (!backoff) {
|
||||
backoff = {count: 0, time: config.browser.minBackoff};
|
||||
stores[store.name] = backoff;
|
||||
}
|
||||
|
||||
if (!isBackoff) {
|
||||
if (backoff.count > 0) {
|
||||
backoff.count--;
|
||||
backoff.time = Math.max(backoff.time / 2, config.browser.minBackoff);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
const backoffTime = backoff.time;
|
||||
logger.debug(Print.backoff(link, store, {delay: backoffTime, statusCode}, true));
|
||||
|
||||
await delay(backoff.time);
|
||||
|
||||
backoff.count++;
|
||||
backoff.time = Math.min(backoff.time * 2, config.browser.maxBackoff);
|
||||
|
||||
return backoffTime;
|
||||
}
|
||||
@@ -0,0 +1,130 @@
|
||||
import {Link, Series} from '../store';
|
||||
import {logger} from '../../../logger';
|
||||
|
||||
export interface Card {
|
||||
brand: string;
|
||||
model: string;
|
||||
}
|
||||
|
||||
interface LinksBuilderOptions {
|
||||
productsSelector: string;
|
||||
sitePrefix: string;
|
||||
titleAttribute?: string;
|
||||
titleSelector: string;
|
||||
urlSelector?: string;
|
||||
}
|
||||
|
||||
const isPartialUrlRegExp = /^\/[^/]/i;
|
||||
|
||||
export function getProductLinksBuilder(options: LinksBuilderOptions) {
|
||||
/* eslint-disable unicorn/no-fn-reference-in-iterator */
|
||||
return (docElement: cheerio.Cheerio, series: Series): Link[] => {
|
||||
const productElements = docElement.find(options.productsSelector);
|
||||
const links: Link[] = [];
|
||||
for (let i = 0; i < productElements.length; i++) {
|
||||
const productElement = productElements.eq(i);
|
||||
const titleElement = productElement.find(options.titleSelector).first();
|
||||
let title: string;
|
||||
|
||||
if (options.titleAttribute) {
|
||||
title = titleElement.attr()?.[options.titleAttribute];
|
||||
} else {
|
||||
title = titleElement.text()?.replace(/\n/g, ' ').trim();
|
||||
}
|
||||
|
||||
if (!title) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let urlElement = titleElement;
|
||||
|
||||
if (options.urlSelector) {
|
||||
urlElement = urlElement.find(options.urlSelector).first();
|
||||
}
|
||||
|
||||
let url = urlElement.attr()?.href;
|
||||
|
||||
if (!url) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (isPartialUrlRegExp.exec(url)) {
|
||||
url = options.sitePrefix + url;
|
||||
}
|
||||
|
||||
const card = parseCard(title);
|
||||
|
||||
if (card) {
|
||||
links.push({
|
||||
brand: card.brand as any,
|
||||
model: card.model,
|
||||
series,
|
||||
url
|
||||
});
|
||||
} else {
|
||||
logger.error(`Failed to parse card: ${title}`);
|
||||
}
|
||||
}
|
||||
|
||||
return links;
|
||||
};
|
||||
/* eslint-enable unicorn/no-fn-reference-in-iterator */
|
||||
}
|
||||
|
||||
export function parseCard(name: string): Card | null {
|
||||
name = name.replace(/\w+-\w+-[^ ]+/g, '');
|
||||
name = name.replace(/\([^(]*\)/g, '');
|
||||
name = name.replace(/, .+$/, '');
|
||||
name = name.replace(/ with .+$/, '');
|
||||
|
||||
// Account for incorrect titles, e.g. MSIGeforce
|
||||
name = name.replace(/geforce/i, '');
|
||||
|
||||
name = name.replace(/[^\w ]+/g, '');
|
||||
name = name.replace(/\bgraphics card\b/gi, '');
|
||||
name = name.replace(/\b(?<!founders) edition\b/gi, '');
|
||||
name = name.replace(/\b(series )?bundle\b/gi, '');
|
||||
name = name.replace(/\b\w+ fan\b/gi, '');
|
||||
name = name.replace(/\s{2,}/g, ' ').trim();
|
||||
|
||||
let model = name.split(' ');
|
||||
const brand = model.shift();
|
||||
|
||||
if (!brand) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Split non spaced TitleCase words only after extracting brand
|
||||
model = model.join(' ').replace(/([A-Z][a-z]+)([A-Z][a-z]+)/g, '$1 $2').split(' ');
|
||||
|
||||
// Some vendors have oc at the beginning of the product name,
|
||||
// store whether the card contains the term "oc" and remove
|
||||
// it during filtering, then add it to the end of the name.
|
||||
let isOC = false;
|
||||
|
||||
/* eslint-disable @typescript-eslint/prefer-regexp-exec */
|
||||
model = model.filter(word => {
|
||||
if (word.toLowerCase() === 'oc') {
|
||||
isOC = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
return !word.match(/^(nvidia|geforce|ge|force|rtx|amp[ae]re|graphics|card|gpu|pci-?e(xpress)?|ray-?tracing|ray|tracing|core|boost|epicx)$/i) &&
|
||||
!word.match(/^(\d+(?:gb?|mhz)?|gb|mhz|g?ddr(\d+x?)?)$/i) &&
|
||||
!word.match(/^(display ?port|hdmi|vga)$/i);
|
||||
});
|
||||
/* eslint-enable @typescript-eslint/prefer-regexp-exec */
|
||||
|
||||
if (isOC) {
|
||||
model.push('OC');
|
||||
}
|
||||
|
||||
if (model.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
brand: brand.toLowerCase(),
|
||||
model: model.join(' ').toLowerCase().replace(/ gaming\b/g, '').trim()
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,174 @@
|
||||
import {NvidiaRegionInfo, regionInfos} from '../nvidia-api';
|
||||
import {usingPage, usingResponse} from '../../../util';
|
||||
import {Browser} from 'puppeteer';
|
||||
import {config} from '../../../config';
|
||||
import {logger} from '../../../logger';
|
||||
import open from 'open';
|
||||
|
||||
interface NvidiaSessionTokenJSON {
|
||||
session_token: string;
|
||||
}
|
||||
|
||||
interface NvidiaAddToCardJSON {
|
||||
location: string;
|
||||
}
|
||||
|
||||
export class NvidiaCart {
|
||||
protected readonly browser: Browser;
|
||||
protected isKeepAlive = false;
|
||||
protected sessionToken: string | null = null;
|
||||
|
||||
public constructor(browser: Browser) {
|
||||
this.browser = browser;
|
||||
}
|
||||
|
||||
public keepAlive() {
|
||||
if (this.isKeepAlive) {
|
||||
return;
|
||||
}
|
||||
|
||||
const callback = async () => {
|
||||
if (!this.isKeepAlive) {
|
||||
return;
|
||||
}
|
||||
|
||||
await this.refreshSessionToken();
|
||||
|
||||
setTimeout(callback, config.nvidia.sessionTtl);
|
||||
};
|
||||
|
||||
this.isKeepAlive = true;
|
||||
|
||||
void callback();
|
||||
}
|
||||
|
||||
public get fallbackCartUrl(): string {
|
||||
return `https://www.nvidia.com/${this.regionInfo.siteLocale}/geforce/`;
|
||||
}
|
||||
|
||||
public get regionInfo(): NvidiaRegionInfo {
|
||||
const country = config.store.country.toLowerCase();
|
||||
const regionInfo = regionInfos.get(country);
|
||||
if (!regionInfo) {
|
||||
throw new Error(`Unknown country ${country}`);
|
||||
}
|
||||
|
||||
return regionInfo;
|
||||
}
|
||||
|
||||
public get sessionUrl(): string {
|
||||
return `https://store.nvidia.com/store/nvidia/SessionToken?format=json&locale=${this.regionInfo.drLocale}`;
|
||||
}
|
||||
|
||||
public async addToCard(productId: number, name: string): Promise<string> {
|
||||
let cartUrl: string | undefined;
|
||||
logger.info(`🚀🚀🚀 [nvidia] ${name}, starting auto add to cart 🚀🚀🚀`);
|
||||
try {
|
||||
logger.info(`🚀🚀🚀 [nvidia] ${name}, adding to cart 🚀🚀🚀`);
|
||||
let lastError: Error | string | undefined;
|
||||
|
||||
/* eslint-disable no-await-in-loop */
|
||||
for (let i = 0; i < config.nvidia.addToCardAttempts; i++) {
|
||||
try {
|
||||
cartUrl = await this.addToCartAndGetLocationRedirect(productId);
|
||||
|
||||
break;
|
||||
} catch (error) {
|
||||
logger.error(`✖ [nvidia] ${name} could not automatically add to cart, attempt ${i + 1} of ${config.nvidia.addToCardAttempts}`, error);
|
||||
logger.debug(error);
|
||||
|
||||
lastError = error;
|
||||
}
|
||||
}
|
||||
/* eslint-enable no-await-in-loop */
|
||||
|
||||
if (!cartUrl) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-throw-literal
|
||||
throw lastError;
|
||||
}
|
||||
|
||||
logger.info(`🚀🚀🚀 [nvidia] ${name}, opening checkout page 🚀🚀🚀`);
|
||||
logger.info(cartUrl);
|
||||
|
||||
await open(cartUrl);
|
||||
} catch (error) {
|
||||
logger.error(`✖ [nvidia] ${name} could not automatically add to cart, opening page`);
|
||||
logger.debug(error);
|
||||
|
||||
cartUrl = this.fallbackCartUrl;
|
||||
|
||||
await open(cartUrl);
|
||||
}
|
||||
|
||||
return cartUrl;
|
||||
}
|
||||
|
||||
public async getSessionToken(): Promise<string> {
|
||||
if (!this.sessionToken) {
|
||||
await this.refreshSessionToken();
|
||||
}
|
||||
|
||||
if (!this.sessionToken) {
|
||||
throw new Error('Failed to create the session_token');
|
||||
}
|
||||
|
||||
return this.sessionToken;
|
||||
}
|
||||
|
||||
public async refreshSessionToken(): Promise<void> {
|
||||
logger.debug('ℹ [nvidia] refreshing session token');
|
||||
try {
|
||||
const result = await usingResponse(this.browser, this.sessionUrl, async response => {
|
||||
return response?.json() as NvidiaSessionTokenJSON | undefined;
|
||||
});
|
||||
if (typeof result !== 'object' || result === null || !('session_token' in result)) {
|
||||
throw new Error('malformed response');
|
||||
}
|
||||
|
||||
this.sessionToken = result.session_token;
|
||||
logger.debug(`ℹ [nvidia] session_token=${result.session_token}`);
|
||||
} catch (error) {
|
||||
const message: string = typeof error === 'object' ? error.message : error;
|
||||
logger.error(`✖ [nvidia] ${message}`);
|
||||
}
|
||||
}
|
||||
|
||||
protected async addToCartAndGetLocationRedirect(productId: number): Promise<string> {
|
||||
const url = 'https://api-prod.nvidia.com/direct-sales-shop/DR/add-to-cart';
|
||||
const sessionToken = await this.getSessionToken();
|
||||
|
||||
logger.info(`ℹ [nvidia] session_token=${sessionToken}`);
|
||||
|
||||
const locationData = await usingPage(this.browser, async page => {
|
||||
page.removeAllListeners('request');
|
||||
|
||||
await page.setRequestInterception(true);
|
||||
|
||||
page.on('request', interceptedRequest => {
|
||||
void interceptedRequest.continue({
|
||||
headers: {
|
||||
...interceptedRequest.headers(),
|
||||
'content-type': 'application/json',
|
||||
nvidia_shop_id: sessionToken
|
||||
},
|
||||
method: 'POST',
|
||||
postData: JSON.stringify({
|
||||
products: [
|
||||
{productId, quantity: 1}
|
||||
]
|
||||
})
|
||||
});
|
||||
});
|
||||
|
||||
const response = await page.goto(url, {waitUntil: 'networkidle0'});
|
||||
|
||||
if (response === null) {
|
||||
throw new Error('NvidiaAddToCartUnavailable');
|
||||
}
|
||||
|
||||
return response.json() as Promise<NvidiaAddToCardJSON>;
|
||||
});
|
||||
|
||||
return locationData.location;
|
||||
}
|
||||
}
|
||||
@@ -1,135 +1,51 @@
|
||||
import {Browser, Response} from 'puppeteer';
|
||||
import {NvidiaRegionInfo, regionInfos} from '../nvidia-api';
|
||||
import {Config} from '../../../config';
|
||||
import {Browser} from 'puppeteer';
|
||||
import {Link} from '../store';
|
||||
import {Logger} from '../../../logger';
|
||||
import open from 'open';
|
||||
import {NvidiaCart} from './nvidia-cart';
|
||||
import {config} from '../../../config';
|
||||
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';
|
||||
let country = config.store.country.toLowerCase();
|
||||
if (!regionInfos.has(country)) {
|
||||
country = 'usa';
|
||||
}
|
||||
|
||||
const defaultRegionInfo: NvidiaRegionInfo = {drLocale: 'en_us', fe2060SuperId: 5379432500, fe3080Id: 5438481700, fe3090Id: null, nvidiaLocale: 'en_us'};
|
||||
return regionInfos.get(country) ?? defaultRegionInfo;
|
||||
const regionInfo = regionInfos.get(country);
|
||||
if (!regionInfo) {
|
||||
throw new Error(`LogicException could not retrieve region info for ${country}`);
|
||||
}
|
||||
|
||||
return regionInfo;
|
||||
}
|
||||
|
||||
function digitalRiverStockUrl(id: number, drLocale: string): string {
|
||||
return `https://api.digitalriver.com/v1/shoppers/me/products/${id}/inventory-status?` +
|
||||
`&apiKey=${nvidiaApiKey}` +
|
||||
`&locale=${drLocale}` +
|
||||
timestampUrlParameter();
|
||||
function nvidiaStockUrl(id: number, drLocale: string, currency: string): string {
|
||||
return `https://api-prod.nvidia.com/direct-sales-shop/DR/products/${drLocale}/${currency}/${id}?` +
|
||||
timestampUrlParameter().slice(1);
|
||||
}
|
||||
|
||||
interface NvidiaSessionTokenJSON {
|
||||
access_token: string;
|
||||
}
|
||||
|
||||
function nvidiaSessionUrl(nvidiaLocale: string): string {
|
||||
return `https://store.nvidia.com/store/nvidia/SessionToken?format=json&locale=${nvidiaLocale}` +
|
||||
`&apiKey=${nvidiaApiKey}` +
|
||||
timestampUrlParameter();
|
||||
}
|
||||
|
||||
function addToCartUrl(id: number, drLocale: string, token: string): string {
|
||||
return 'https://api.digitalriver.com/v1/shoppers/me/carts/active/line-items?format=json&method=post' +
|
||||
`&productId=${id}` +
|
||||
`&token=${token}` +
|
||||
'&quantity=1' +
|
||||
`&locale=${drLocale}` +
|
||||
timestampUrlParameter();
|
||||
}
|
||||
|
||||
function checkoutUrl(drLocale: string, token: string): string {
|
||||
return `https://api.digitalriver.com/v1/shoppers/me/carts/active/web-checkout?token=${token}&locale=${drLocale}`;
|
||||
}
|
||||
|
||||
function fallbackCartUrl(nvidiaLocale: string): string {
|
||||
return `https://www.nvidia.com/${nvidiaLocale}/shop/geforce?${timestampUrlParameter()}`;
|
||||
}
|
||||
let cart: NvidiaCart;
|
||||
|
||||
export function generateSetupAction() {
|
||||
return async (browser: Browser) => {
|
||||
const {drLocale, nvidiaLocale} = getRegionInfo();
|
||||
cart = new NvidiaCart(browser);
|
||||
|
||||
const page = await browser.newPage();
|
||||
|
||||
let response: Response | null;
|
||||
try {
|
||||
Logger.debug('creating cart/session token...');
|
||||
|
||||
response = await page.goto(nvidiaSessionUrl(nvidiaLocale), {waitUntil: 'networkidle0'});
|
||||
|
||||
if (response === null) {
|
||||
throw new Error('NvidiaAccessTokenUnavailable');
|
||||
}
|
||||
|
||||
const data = await response.json() as NvidiaSessionTokenJSON;
|
||||
const accessToken = data.access_token;
|
||||
const cartUrl = checkoutUrl(drLocale, accessToken);
|
||||
|
||||
Logger.debug(cartUrl);
|
||||
|
||||
if (Config.browser.open) {
|
||||
Logger.info('ℹ opening browser for user to login');
|
||||
|
||||
await open(cartUrl);
|
||||
}
|
||||
} catch (error) {
|
||||
Logger.error('✖ [nvidia] cannot generate cart/session token, continuing without; auto "add to cart" may not work', error);
|
||||
if (config.browser.open) {
|
||||
cart.keepAlive();
|
||||
}
|
||||
|
||||
await page.close();
|
||||
};
|
||||
}
|
||||
|
||||
export function generateOpenCartAction(id: number, nvidiaLocale: string, drLocale: string, cardName: string) {
|
||||
return async (browser: Browser) => {
|
||||
const page = await browser.newPage();
|
||||
export function generateOpenCartAction(id: number, cardName: string) {
|
||||
return async () => {
|
||||
const url = await cart.addToCard(id, cardName);
|
||||
|
||||
Logger.info(`🚀🚀🚀 [nvidia] ${cardName}, starting auto add to cart 🚀🚀🚀`);
|
||||
|
||||
let response: Response | null;
|
||||
let cartUrl: string;
|
||||
try {
|
||||
Logger.info(`🚀🚀🚀 [nvidia] ${cardName}, getting access token 🚀🚀🚀`);
|
||||
|
||||
response = await page.goto(nvidiaSessionUrl(nvidiaLocale), {waitUntil: 'networkidle0'});
|
||||
if (response === null) {
|
||||
throw new Error('NvidiaAccessTokenUnavailable');
|
||||
}
|
||||
|
||||
const data = await response.json() as NvidiaSessionTokenJSON;
|
||||
const accessToken = data.access_token;
|
||||
|
||||
Logger.info(`🚀🚀🚀 [nvidia] ${cardName}, adding to cart 🚀🚀🚀`);
|
||||
|
||||
response = await page.goto(addToCartUrl(id, drLocale, accessToken), {waitUntil: 'networkidle0'});
|
||||
|
||||
Logger.info(`🚀🚀🚀 [nvidia] ${cardName}, opening checkout page 🚀🚀🚀`);
|
||||
|
||||
cartUrl = checkoutUrl(drLocale, accessToken);
|
||||
|
||||
Logger.info(cartUrl);
|
||||
|
||||
await open(cartUrl);
|
||||
} catch (error) {
|
||||
Logger.debug(error);
|
||||
Logger.error(`✖ [nvidia] ${cardName} could not automatically add to cart, opening page`, error);
|
||||
|
||||
cartUrl = fallbackCartUrl(nvidiaLocale);
|
||||
await open(cartUrl);
|
||||
}
|
||||
|
||||
await page.close();
|
||||
|
||||
return cartUrl;
|
||||
return url;
|
||||
};
|
||||
}
|
||||
|
||||
export function generateLinks(): Link[] {
|
||||
const {drLocale, nvidiaLocale, fe3080Id, fe3090Id, fe2060SuperId} = getRegionInfo();
|
||||
const {drLocale, fe3080Id, fe3090Id, fe2060SuperId, currency} = getRegionInfo();
|
||||
|
||||
const links: Link[] = [];
|
||||
|
||||
@@ -137,9 +53,9 @@ export function generateLinks(): Link[] {
|
||||
links.push({
|
||||
brand: 'test:brand',
|
||||
model: 'test:model',
|
||||
openCartAction: generateOpenCartAction(fe2060SuperId, nvidiaLocale, drLocale, 'TEST CARD debug'),
|
||||
openCartAction: generateOpenCartAction(fe2060SuperId, 'TEST CARD debug'),
|
||||
series: 'test:series',
|
||||
url: digitalRiverStockUrl(fe2060SuperId, drLocale)
|
||||
url: nvidiaStockUrl(fe2060SuperId, drLocale, currency)
|
||||
});
|
||||
}
|
||||
|
||||
@@ -147,9 +63,9 @@ export function generateLinks(): Link[] {
|
||||
links.push({
|
||||
brand: 'nvidia',
|
||||
model: 'founders edition',
|
||||
openCartAction: generateOpenCartAction(fe3080Id, nvidiaLocale, drLocale, 'nvidia founders edition 3080'),
|
||||
openCartAction: generateOpenCartAction(fe3080Id, 'nvidia founders edition 3080'),
|
||||
series: '3080',
|
||||
url: digitalRiverStockUrl(fe3080Id, drLocale)
|
||||
url: nvidiaStockUrl(fe3080Id, drLocale, currency)
|
||||
});
|
||||
}
|
||||
|
||||
@@ -157,9 +73,9 @@ export function generateLinks(): Link[] {
|
||||
links.push({
|
||||
brand: 'nvidia',
|
||||
model: 'founders edition',
|
||||
openCartAction: generateOpenCartAction(fe3090Id, nvidiaLocale, drLocale, 'nvidia founders edition 3090'),
|
||||
openCartAction: generateOpenCartAction(fe3090Id, 'nvidia founders edition 3090'),
|
||||
series: '3090',
|
||||
url: digitalRiverStockUrl(fe3090Id, drLocale)
|
||||
url: nvidiaStockUrl(fe3090Id, drLocale, currency)
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
+149
-18
@@ -1,69 +1,200 @@
|
||||
import {config, defaultStoreData} from '../../config';
|
||||
import {Adorama} from './adorama';
|
||||
import {Alternate} from './alternate';
|
||||
import {AlternateNL} from './alternate-nl';
|
||||
import {Amazon} from './amazon';
|
||||
import {AmazonCa} from './amazon-ca';
|
||||
import {AmazonDe} from './amazon-de';
|
||||
import {AmazonEs} from './amazon-es';
|
||||
import {AmazonNl} from './amazon-nl';
|
||||
import {AmazonUk} from './amazon-uk';
|
||||
import {Aria} from './aria';
|
||||
import {Asus} from './asus';
|
||||
import {AsusDe} from './asus-de';
|
||||
import {Azerty} from './azerty';
|
||||
import {BAndH} from './bandh';
|
||||
import {BestBuy} from './bestbuy';
|
||||
import {BestBuyCa} from './bestbuy-ca';
|
||||
import {Config} from '../../config';
|
||||
import {Box} from './box';
|
||||
import {Caseking} from './caseking';
|
||||
import {Ccl} from './ccl';
|
||||
import {Computeruniverse} from './computeruniverse';
|
||||
import {Coolblue} from './coolblue';
|
||||
import {Coolmod} from './coolmod';
|
||||
import {Currys} from './currys';
|
||||
import {Cyberport} from './cyberport';
|
||||
import {Ebuyer} from './ebuyer';
|
||||
import {Evga} from './evga';
|
||||
import {EvgaEu} from './evga-eu';
|
||||
import {Logger} from '../../logger';
|
||||
import {Gamestop} from './gamestop';
|
||||
import {Mediamarkt} from './mediamarkt';
|
||||
import {MicroCenter} from './microcenter';
|
||||
import {Mindfactory} from './mindfactory';
|
||||
import {Newegg} from './newegg';
|
||||
import {NeweggCa} from './newegg-ca';
|
||||
import {Notebooksbilliger} from './notebooksbilliger';
|
||||
import {Novatech} from './novatech';
|
||||
import {Nvidia} from './nvidia';
|
||||
import {NvidiaApi} from './nvidia-api';
|
||||
import {OfficeDepot} from './officedepot';
|
||||
import {Overclockers} from './overclockers';
|
||||
import {PCComponentes} from './pccomponentes';
|
||||
import {Pny} from './pny';
|
||||
import {ProshopDE} from './proshop-de';
|
||||
import {ProshopDK} from './proshop-dk';
|
||||
import {Saturn} from './saturn';
|
||||
import {Scan} from './scan';
|
||||
import {Store} from './store';
|
||||
import {Very} from './very';
|
||||
import {Zotac} from './zotac';
|
||||
import {logger} from '../../logger';
|
||||
|
||||
const masterList = new Map([
|
||||
export const storeList = new Map([
|
||||
[Adorama.name, Adorama],
|
||||
[Alternate.name, Alternate],
|
||||
[AlternateNL.name, AlternateNL],
|
||||
[Amazon.name, Amazon],
|
||||
[AmazonCa.name, AmazonCa],
|
||||
[AmazonDe.name, AmazonDe],
|
||||
[AmazonEs.name, AmazonEs],
|
||||
[AmazonNl.name, AmazonNl],
|
||||
[AmazonUk.name, AmazonUk],
|
||||
[Aria.name, Aria],
|
||||
[Asus.name, Asus],
|
||||
[AsusDe.name, AsusDe],
|
||||
[Azerty.name, Azerty],
|
||||
[BAndH.name, BAndH],
|
||||
[BestBuy.name, BestBuy],
|
||||
[BestBuyCa.name, BestBuyCa],
|
||||
[Box.name, Box],
|
||||
[Caseking.name, Caseking],
|
||||
[Ccl.name, Ccl],
|
||||
[Computeruniverse.name, Computeruniverse],
|
||||
[Coolblue.name, Coolblue],
|
||||
[Coolmod.name, Coolmod],
|
||||
[Currys.name, Currys],
|
||||
[Cyberport.name, Cyberport],
|
||||
[Ebuyer.name, Ebuyer],
|
||||
[Evga.name, Evga],
|
||||
[EvgaEu.name, EvgaEu],
|
||||
[Gamestop.name, Gamestop],
|
||||
[Mediamarkt.name, Mediamarkt],
|
||||
[MicroCenter.name, MicroCenter],
|
||||
[Mindfactory.name, Mindfactory],
|
||||
[Newegg.name, Newegg],
|
||||
[NeweggCa.name, NeweggCa],
|
||||
[Notebooksbilliger.name, Notebooksbilliger],
|
||||
[Novatech.name, Novatech],
|
||||
[Nvidia.name, Nvidia],
|
||||
[NvidiaApi.name, NvidiaApi],
|
||||
[OfficeDepot.name, OfficeDepot],
|
||||
[Overclockers.name, Overclockers],
|
||||
[PCComponentes.name, PCComponentes],
|
||||
[Pny.name, Pny],
|
||||
[ProshopDE.name, ProshopDE],
|
||||
[ProshopDK.name, ProshopDK],
|
||||
[Saturn.name, Saturn],
|
||||
[Scan.name, Scan],
|
||||
[Very.name, Very],
|
||||
[Zotac.name, Zotac]
|
||||
]);
|
||||
|
||||
const list = new Map();
|
||||
const brands = new Set();
|
||||
const models = new Set();
|
||||
const series = new Set();
|
||||
const stores = new Map();
|
||||
|
||||
for (const name of Config.store.stores) {
|
||||
if (masterList.has(name)) {
|
||||
list.set(name, masterList.get(name));
|
||||
} else {
|
||||
const logString = `No store named ${name}, skipping.`;
|
||||
Logger.warn(logString);
|
||||
function filterBrandsSeriesModels(stores: Map<string, Store>) {
|
||||
brands.clear();
|
||||
series.clear();
|
||||
models.clear();
|
||||
|
||||
for (const store of stores.values()) {
|
||||
for (const link of store.links) {
|
||||
brands.add(link.brand);
|
||||
series.add(link.series);
|
||||
models.add(link.model);
|
||||
}
|
||||
|
||||
if (store.minPageSleep === undefined) {
|
||||
store.minPageSleep = defaultStoreData.minPageSleep;
|
||||
}
|
||||
|
||||
if (store.maxPageSleep === undefined) {
|
||||
store.maxPageSleep = defaultStoreData.maxPageSleep;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Logger.info(`ℹ selected stores: ${Array.from(list.keys()).join(', ')}`);
|
||||
function printConfig() {
|
||||
if (config.store.stores.length > 0) {
|
||||
logger.info(`ℹ selected stores: ${config.store.stores.map(store => store.name).join(', ')}`);
|
||||
}
|
||||
|
||||
if (Config.store.showOnlyBrands.length > 0) {
|
||||
Logger.info(`ℹ selected brands: ${Config.store.showOnlyBrands.join(', ')}`);
|
||||
if (config.store.showOnlyBrands.length > 0) {
|
||||
logger.info(`ℹ selected brands: ${config.store.showOnlyBrands.join(', ')}`);
|
||||
}
|
||||
|
||||
if (config.store.showOnlyModels.length > 0) {
|
||||
logger.info(`ℹ selected models: ${config.store.showOnlyModels.map(entry => {
|
||||
return entry.series ? entry.name + ' (' + entry.series + ')' : entry.name;
|
||||
}).join(', ')}`);
|
||||
}
|
||||
|
||||
if (config.store.showOnlySeries.length > 0) {
|
||||
logger.info(`ℹ selected series: ${config.store.showOnlySeries.join(', ')}`);
|
||||
}
|
||||
}
|
||||
|
||||
if (Config.store.showOnlyModels.length > 0) {
|
||||
Logger.info(`ℹ selected models: ${Config.store.showOnlyModels.join(', ')}`);
|
||||
function warnIfStoreDeprecated(store: Store) {
|
||||
switch (store.name) {
|
||||
case 'nvidia':
|
||||
case 'nvidia-api':
|
||||
logger.warn(`${store.name} is deprecated in favor of bestbuy`);
|
||||
break;
|
||||
case 'evga':
|
||||
logger.warn(`${store.name} is deprecated since they only support queuing`);
|
||||
break;
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
if (Config.store.showOnlySeries.length > 0) {
|
||||
Logger.info(`ℹ selected series: ${Config.store.showOnlySeries.join(', ')}`);
|
||||
export function updateStores() {
|
||||
stores.clear();
|
||||
|
||||
for (const storeData of config.store.stores) {
|
||||
const store = storeList.get(storeData.name);
|
||||
|
||||
if (store) {
|
||||
warnIfStoreDeprecated(store);
|
||||
stores.set(storeData.name, store);
|
||||
store.minPageSleep = storeData.minPageSleep;
|
||||
store.maxPageSleep = storeData.maxPageSleep;
|
||||
} else {
|
||||
logger.warn(`No store named ${storeData.name}, skipping.`);
|
||||
}
|
||||
}
|
||||
|
||||
filterBrandsSeriesModels(stores);
|
||||
printConfig();
|
||||
}
|
||||
|
||||
export const Stores = Array.from(list.values()) as Store[];
|
||||
updateStores();
|
||||
|
||||
export function getAllBrands() {
|
||||
return Array.from(brands);
|
||||
}
|
||||
|
||||
export function getAllSeries() {
|
||||
return Array.from(series);
|
||||
}
|
||||
|
||||
export function getAllModels() {
|
||||
return Array.from(models);
|
||||
}
|
||||
|
||||
export function getStores() {
|
||||
return stores;
|
||||
}
|
||||
|
||||
export * from './store';
|
||||
|
||||
@@ -0,0 +1,237 @@
|
||||
import {Store} from './store';
|
||||
|
||||
export const Mediamarkt: Store = {
|
||||
labels: {
|
||||
maxPrice: {
|
||||
container: 'span[font-family="price"]',
|
||||
euroFormat: false
|
||||
},
|
||||
outOfStock: [{
|
||||
container: '#root',
|
||||
text: ['dieser artikel ist aktuell nicht verfügbar.']
|
||||
},
|
||||
{
|
||||
container: '#root',
|
||||
text: ['leider keine Lieferung möglich']
|
||||
}]
|
||||
},
|
||||
links: [
|
||||
{
|
||||
brand: 'test:brand',
|
||||
model: 'test:model',
|
||||
series: 'test:series',
|
||||
url: 'https://www.mediamarkt.de/de/product/-2592355.html'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'rog strix',
|
||||
series: '3070',
|
||||
url: 'https://www.mediamarkt.de/de/product/-2691243.html'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'rog strix oc',
|
||||
series: '3070',
|
||||
url: 'https://www.mediamarkt.de/de/product/-2691244.html'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'dual',
|
||||
series: '3070',
|
||||
url: 'https://www.mediamarkt.de/de/product/-2691245.html'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'dual oc',
|
||||
series: '3070',
|
||||
url: 'https://www.mediamarkt.de/de/product/-2691246.html'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'tuf oc',
|
||||
series: '3070',
|
||||
url: 'https://www.mediamarkt.de/de/product/-2691247.html'
|
||||
},
|
||||
{
|
||||
brand: 'gigabyte',
|
||||
model: 'gaming oc',
|
||||
series: '3070',
|
||||
url: 'https://www.mediamarkt.de/de/product/-2691439.html'
|
||||
},
|
||||
{
|
||||
brand: 'gigabyte',
|
||||
model: 'eagle oc',
|
||||
series: '3070',
|
||||
url: 'https://www.mediamarkt.de/de/product/-2691444.html'
|
||||
},
|
||||
{
|
||||
brand: 'gigabyte',
|
||||
model: 'aorus master',
|
||||
series: '3070',
|
||||
url: 'https://www.mediamarkt.de/de/product/-2696163.html'
|
||||
},
|
||||
{
|
||||
brand: 'gigabyte',
|
||||
model: 'vision oc',
|
||||
series: '3070',
|
||||
url: 'https://www.mediamarkt.de/de/product/-2696164.html'
|
||||
},
|
||||
{
|
||||
brand: 'msi',
|
||||
model: 'gaming x trio',
|
||||
series: '3070',
|
||||
url: 'https://www.mediamarkt.de/de/product/-2694894.html'
|
||||
},
|
||||
{
|
||||
brand: 'msi',
|
||||
model: 'ventus 3x oc',
|
||||
series: '3070',
|
||||
url: 'https://www.mediamarkt.de/de/product/-2694896.html'
|
||||
},
|
||||
{
|
||||
brand: 'msi',
|
||||
model: 'ventus 2x oc',
|
||||
series: '3070',
|
||||
url: 'https://www.mediamarkt.de/de/product/-2694898.html'
|
||||
},
|
||||
{
|
||||
brand: 'inno3d',
|
||||
model: 'ichill x3',
|
||||
series: '3070',
|
||||
url: 'https://www.mediamarkt.de/de/product/-2695942.html'
|
||||
},
|
||||
{
|
||||
brand: 'inno3d',
|
||||
model: 'ichill x4',
|
||||
series: '3070',
|
||||
url: 'https://www.mediamarkt.de/de/product/-2695941.html'
|
||||
},
|
||||
{
|
||||
brand: 'zotac',
|
||||
model: 'twin edge',
|
||||
series: '3070',
|
||||
url: 'https://www.mediamarkt.de/de/product/-2691365.html'
|
||||
},
|
||||
{
|
||||
brand: 'zotac',
|
||||
model: 'twin edge oc',
|
||||
series: '3070',
|
||||
url: 'https://www.mediamarkt.de/de/product/-2695671.html'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'rog strix',
|
||||
series: '3080',
|
||||
url: 'https://www.mediamarkt.de/de/product/-2681869.html'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'rog strix oc',
|
||||
series: '3080',
|
||||
url: 'https://www.mediamarkt.de/de/product/-2681871.html'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'tuf',
|
||||
series: '3080',
|
||||
url: 'https://www.mediamarkt.de/de/product/-2681859.html'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'tuf oc',
|
||||
series: '3080',
|
||||
url: 'https://www.mediamarkt.de/de/product/-2681861.html'
|
||||
},
|
||||
{
|
||||
brand: 'gigabyte',
|
||||
model: 'eagle oc',
|
||||
series: '3080',
|
||||
url: 'https://www.mediamarkt.de/de/product/-2683942.html'
|
||||
},
|
||||
{
|
||||
brand: 'gigabyte',
|
||||
model: 'gaming oc',
|
||||
series: '3080',
|
||||
url: 'https://www.mediamarkt.de/de/product/-2683937.html'
|
||||
},
|
||||
{
|
||||
brand: 'inno3d',
|
||||
model: 'ichill x3',
|
||||
series: '3080',
|
||||
url: 'https://www.mediamarkt.de/de/product/-2684241.html'
|
||||
},
|
||||
{
|
||||
brand: 'inno3d',
|
||||
model: 'ichill x4',
|
||||
series: '3080',
|
||||
url: 'https://www.mediamarkt.de/de/product/-2684238.html'
|
||||
},
|
||||
{
|
||||
brand: 'msi',
|
||||
model: 'gaming x trio',
|
||||
series: '3080',
|
||||
url: 'https://www.mediamarkt.de/de/product/-2683227.html'
|
||||
},
|
||||
{
|
||||
brand: 'msi',
|
||||
model: 'ventus 3x oc',
|
||||
series: '3080',
|
||||
url: 'https://www.mediamarkt.de/de/product/-2683229.html'
|
||||
},
|
||||
{
|
||||
brand: 'zotac',
|
||||
model: 'trinity',
|
||||
series: '3080',
|
||||
url: 'https://www.mediamarkt.de/de/product/-2683243.html'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'rog strix',
|
||||
series: '3090',
|
||||
url: 'https://www.mediamarkt.de/de/product/-2681863.html'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'rog strix oc',
|
||||
series: '3090',
|
||||
url: 'https://www.mediamarkt.de/de/product/-2681866.html'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'tuf',
|
||||
series: '3090',
|
||||
url: 'https://www.mediamarkt.de/de/product/-2681855.html'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'tuf oc',
|
||||
series: '3090',
|
||||
url: 'https://www.mediamarkt.de/de/product/-2681857.html'
|
||||
},
|
||||
{
|
||||
brand: 'gigabyte',
|
||||
model: 'aorus master',
|
||||
series: '3090',
|
||||
url: 'https://www.mediamarkt.de/de/product/-2691441.html'
|
||||
},
|
||||
{
|
||||
brand: 'gigabyte',
|
||||
model: 'aorus xtreme',
|
||||
series: '3090',
|
||||
url: 'https://www.mediamarkt.de/de/product/-2691440.html'
|
||||
},
|
||||
{
|
||||
brand: 'inno3d',
|
||||
model: 'ichill x4',
|
||||
series: '3090',
|
||||
url: 'https://www.mediamarkt.de/de/product/-2684235.html'
|
||||
},
|
||||
{
|
||||
brand: 'msi',
|
||||
model: 'gaming x trio',
|
||||
series: '3090',
|
||||
url: 'https://www.mediamarkt.de/de/product/-2683226.html'
|
||||
}
|
||||
],
|
||||
name: 'mediamarkt'
|
||||
};
|
||||
@@ -1,7 +1,9 @@
|
||||
import {Config} from '../../config';
|
||||
import {Store} from './store';
|
||||
import {Link, Store} from './store';
|
||||
import {config} from '../../config';
|
||||
import {logger} from '../../logger';
|
||||
|
||||
const microCenterLocations = config.store.microCenterLocation;
|
||||
|
||||
const MicroCenterLocation = Config.store.microCenterLocation;
|
||||
const microCenterLocationToId: Map<string, string> = new Map([
|
||||
['web', '029'],
|
||||
['brooklyn', '115'],
|
||||
@@ -10,14 +12,14 @@ const microCenterLocationToId: Map<string, string> = new Map([
|
||||
['chicago', '151'],
|
||||
['columbus', '141'],
|
||||
['dallas', '131'],
|
||||
['devin', '181'],
|
||||
['denver', '181'],
|
||||
['duluth', '065'],
|
||||
['fairfax', '081'],
|
||||
['flushing', '145'],
|
||||
['houston', '155'],
|
||||
['madison-heights', '055'],
|
||||
['marietta', '041'],
|
||||
['mayfiend-heights', '051'],
|
||||
['mayfield-heights', '051'],
|
||||
['north-jersey', '075'],
|
||||
['overland-park', '191'],
|
||||
['parkville', '125'],
|
||||
@@ -31,11 +33,65 @@ const microCenterLocationToId: Map<string, string> = new Map([
|
||||
['yonkers', '105']
|
||||
]);
|
||||
|
||||
let links: Link[] = [];
|
||||
let storeId: string;
|
||||
if (microCenterLocationToId.get(MicroCenterLocation) === undefined) {
|
||||
storeId = '029';
|
||||
} else {
|
||||
storeId = microCenterLocationToId.get(MicroCenterLocation)!;
|
||||
for (const microCenterLocation of microCenterLocations) {
|
||||
if (microCenterLocationToId.get(microCenterLocation) === undefined) {
|
||||
const logString = `No MicroCenter location named ${microCenterLocation}, skipping.`;
|
||||
logger.warn(logString);
|
||||
} else {
|
||||
storeId = microCenterLocationToId.get(microCenterLocation)!;
|
||||
links = links.concat([
|
||||
{
|
||||
brand: 'test:brand',
|
||||
model: 'test:model',
|
||||
series: 'test:series',
|
||||
url: `https://www.microcenter.com/product/618433/evga-geforce-rtx-2060-ko-ultra-overclocked-dual-fan-6gb-gddr6-pcie-30-graphics-card/?storeid=${storeId}`
|
||||
},
|
||||
{
|
||||
brand: 'evga',
|
||||
model: 'xc3 ultra',
|
||||
series: '3080',
|
||||
url: `https://www.microcenter.com/product/628344/evga-geforce-rtx-3080-xc3-ultra-gaming-triple-fan-10gb-gddr6x-pcie-40-graphics-card/?storeid=${storeId}`
|
||||
},
|
||||
{
|
||||
brand: 'evga',
|
||||
model: 'ftw3 ultra',
|
||||
series: '3080',
|
||||
url: `https://www.microcenter.com/product/628346/evga-geforce-rtx-3080-ftw3-ultra-gaming-triple-fan-10gb-gddr6x-pcie-40-graphics-card/?storeid=${storeId}`
|
||||
},
|
||||
{
|
||||
brand: 'msi',
|
||||
model: 'ventus 3x',
|
||||
series: '3080',
|
||||
url: `https://www.microcenter.com/product/628331/msi-geforce-rtx-3080-ventus-3x-overclocked-triple-fan-10gb-gddr6x-pcie-40-graphics-card/?storeid=${storeId}`
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'tuf',
|
||||
series: '3080',
|
||||
url: `https://www.microcenter.com/product/628303/asus-geforce-rtx-3080-tuf-gaming-triple-fan-10gb-gddr6x-pcie-40-graphics-card/?storeid=${storeId}`
|
||||
},
|
||||
{
|
||||
brand: 'msi',
|
||||
model: 'gaming x trio',
|
||||
series: '3080',
|
||||
url: `https://www.microcenter.com/product/628330/msi-geforce-rtx-3080-gaming-x-trio-triple-fan-10gb-gddr6x-pcie-40-graphics-card/?storeid=${storeId}`
|
||||
},
|
||||
{
|
||||
brand: 'evga',
|
||||
model: 'xc3 black',
|
||||
series: '3080',
|
||||
url: `https://www.microcenter.com/product/628340/evga-geforce-rtx-3080-xc3-black-triple-fan-10gb-gddr6x-pcie-40-graphics-card/?storeid=${storeId}`
|
||||
},
|
||||
{
|
||||
brand: 'zotac',
|
||||
model: 'trinity',
|
||||
series: '3080',
|
||||
url: `https://www.microcenter.com/product/628607/zotac-geforce-rtx-3080-trinity-overclocked-triple-fan-10gb-gddr6x-pcie-40-graphics-card/?storeid=${storeId}`
|
||||
}
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
export const MicroCenter: Store = {
|
||||
@@ -43,51 +99,12 @@ export const MicroCenter: Store = {
|
||||
inStock: {
|
||||
container: '#cart-options',
|
||||
text: ['in stock']
|
||||
},
|
||||
maxPrice: {
|
||||
container: 'span[id="pricing"]',
|
||||
euroFormat: false
|
||||
}
|
||||
},
|
||||
links: [
|
||||
{
|
||||
brand: 'test:brand',
|
||||
model: 'test:model',
|
||||
series: 'test:series',
|
||||
url: `https://www.microcenter.com/product/618433/evga-geforce-rtx-2060-ko-ultra-overclocked-dual-fan-6gb-gddr6-pcie-30-graphics-card/?storeid=${storeId}`
|
||||
},
|
||||
{
|
||||
brand: 'evga',
|
||||
model: 'xc3 ultra',
|
||||
series: '3080',
|
||||
url: `https://www.microcenter.com/product/628344/evga-geforce-rtx-3080-xc3-ultra-gaming-triple-fan-10gb-gddr6x-pcie-40-graphics-card/?storeid=${storeId}`
|
||||
},
|
||||
{
|
||||
brand: 'msi',
|
||||
model: 'ventus 3x',
|
||||
series: '3080',
|
||||
url: `https://www.microcenter.com/product/628331/msi-geforce-rtx-3080-ventus-3x-overclocked-triple-fan-10gb-gddr6x-pcie-40-graphics-card/?storeid=${storeId}`
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'tuf',
|
||||
series: '3080',
|
||||
url: `https://www.microcenter.com/product/628303/asus-geforce-rtx-3080-tuf-gaming-triple-fan-10gb-gddr6x-pcie-40-graphics-card/?storeid=${storeId}`
|
||||
},
|
||||
{
|
||||
brand: 'msi',
|
||||
model: 'gaming x trio',
|
||||
series: '3080',
|
||||
url: `https://www.microcenter.com/product/628330/msi-geforce-rtx-3080-gaming-x-trio-triple-fan-10gb-gddr6x-pcie-40-graphics-card/?storeid=${storeId}`
|
||||
},
|
||||
{
|
||||
brand: 'evga',
|
||||
model: 'xc3 black',
|
||||
series: '3080',
|
||||
url: `https://www.microcenter.com/product/628340/evga-geforce-rtx-3080-xc3-black-triple-fan-10gb-gddr6x-pcie-40-graphics-card/?storeid=${storeId}`
|
||||
},
|
||||
{
|
||||
brand: 'zotac',
|
||||
model: 'trinity',
|
||||
series: '3080',
|
||||
url: `https://www.microcenter.com/product/628607/zotac-geforce-rtx-3080-trinity-overclocked-triple-fan-10gb-gddr6x-pcie-40-graphics-card/?storeid=${storeId}`
|
||||
}
|
||||
],
|
||||
links,
|
||||
name: 'microcenter'
|
||||
};
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
import {Store} from './store';
|
||||
|
||||
export const Mindfactory: Store = {
|
||||
labels: {
|
||||
inStock: {
|
||||
container: '.pshipping',
|
||||
text: ['lagernd', 'verfügbar']
|
||||
},
|
||||
maxPrice: {
|
||||
container: 'div[class="pprice"]',
|
||||
euroFormat: true
|
||||
},
|
||||
outOfStock: {
|
||||
container: '.pshipping',
|
||||
text: ['ohne liefertermin']
|
||||
}
|
||||
},
|
||||
links: [
|
||||
{
|
||||
brand: 'test:brand',
|
||||
model: 'test:model',
|
||||
series: 'test:series',
|
||||
url: 'https://www.mindfactory.de/product_info.php/8GB-MSI-GeForce-RTX2070Super-GAMING-X-DDR6--Retail-_1329683.html'
|
||||
},
|
||||
{
|
||||
brand: 'gigabyte',
|
||||
model: 'aorus master',
|
||||
series: '3080',
|
||||
url: 'https://www.mindfactory.de/product_info.php/10GB-Gigabyte-RTX3080-AORUS-MASTER-GDDR6X-3xHDMI-3xDP--Retail-_1378681.html'
|
||||
},
|
||||
{
|
||||
brand: 'gigabyte',
|
||||
model: 'aorus xtreme',
|
||||
series: '3080',
|
||||
url: 'https://www.mindfactory.de/product_info.php/10GB-Gigabyte-RTX3080-AORUS-XTREME-GDDR6X-3xHDMI-3xDP--Retail-_1380484.html'
|
||||
},
|
||||
{
|
||||
brand: 'gigabyte',
|
||||
model: 'gaming oc',
|
||||
series: '3080',
|
||||
url: 'https://www.mindfactory.de/product_info.php/10GB-Gigabyte-GeForce-RTX-3080-Gaming-OC-3xDP-2x-HDMI--Retail-_1376263.html'
|
||||
},
|
||||
{
|
||||
brand: 'gigabyte',
|
||||
model: 'vision oc',
|
||||
series: '3080',
|
||||
url: 'https://www.mindfactory.de/product_info.php/10GB-Gigabyte-RTX3080-VISION-OC-GDDR6X-2xHDMI-3xDP--Retail-_1378682.html'
|
||||
},
|
||||
{
|
||||
brand: 'msi',
|
||||
model: 'gaming x trio',
|
||||
series: '3080',
|
||||
url: 'https://www.mindfactory.de/product_info.php/10GB-MSI-GeForce-RTX-3080-Gaming-X-TRIO--Retail-_1376481.html'
|
||||
},
|
||||
{
|
||||
brand: 'palit',
|
||||
model: 'gaming pro',
|
||||
series: '3080',
|
||||
url: 'https://www.mindfactory.de/product_info.php/10GB-Palit-GeForce-RTX-3080-GamingPro--Retail-_1376483.html'
|
||||
},
|
||||
{
|
||||
brand: 'zotac',
|
||||
model: 'trinity oc',
|
||||
series: '3080',
|
||||
url: 'https://www.mindfactory.de/product_info.php/10GB-Zotac-GeForce-RTX-3080-TRINITY-OC--GDDR6X-_1377143.html'
|
||||
},
|
||||
{
|
||||
brand: 'gigabyte',
|
||||
model: 'gaming oc',
|
||||
series: '3090',
|
||||
url: 'https://www.mindfactory.de/product_info.php/24GB-Gigabyte-GeForce-3090-Gaming-OC--Retail-_1377265.html'
|
||||
},
|
||||
{
|
||||
brand: 'msi',
|
||||
model: 'ventus 3x',
|
||||
series: '3090',
|
||||
url: 'https://www.mindfactory.de/product_info.php/24GB-MSI-GeForce-RTX-3090-VENTUS-3X-DDR6--Retail-_1377475.html'
|
||||
},
|
||||
{
|
||||
brand: 'palit',
|
||||
model: 'gaming pro',
|
||||
series: '3090',
|
||||
url: 'https://www.mindfactory.de/product_info.php/24GB-Palit-GeForce-RTX-3090-GamingPro-DDR6--Retail-_1377233.html'
|
||||
}
|
||||
],
|
||||
name: 'mindfactory'
|
||||
};
|
||||
@@ -7,8 +7,12 @@ export const NeweggCa: Store = {
|
||||
text: ['are you a human?']
|
||||
},
|
||||
inStock: {
|
||||
container: '#landingpage-cart .btn-primary span',
|
||||
container: 'div#ProductBuy .btn-primary',
|
||||
text: ['add to cart']
|
||||
},
|
||||
maxPrice: {
|
||||
container: 'div#app div.product-price > ul > li.price-current > strong',
|
||||
euroFormat: false
|
||||
}
|
||||
},
|
||||
links: [
|
||||
@@ -78,6 +82,12 @@ export const NeweggCa: Store = {
|
||||
series: '3080',
|
||||
url: 'https://www.newegg.ca/asus-geforce-rtx-3080-tuf-rtx3080-o10g-gaming/p/N82E16814126452'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'rog strix',
|
||||
series: '3080',
|
||||
url: 'https://www.newegg.ca/asus-geforce-rtx-3080-rog-strix-rtx3080-o10g-gaming/p/N82E16814126457'
|
||||
},
|
||||
{
|
||||
brand: 'msi',
|
||||
model: 'gaming x trio',
|
||||
@@ -113,6 +123,168 @@ export const NeweggCa: Store = {
|
||||
model: 'rog strix',
|
||||
series: '3090',
|
||||
url: 'https://www.newegg.ca/asus-geforce-rtx-3090-rog-strix-rtx3090-o24g-gaming/p/N82E16814126456'
|
||||
},
|
||||
{
|
||||
brand: 'evga',
|
||||
model: 'xc3 ultra',
|
||||
series: '3090',
|
||||
url: 'https://www.newegg.ca/evga-geforce-rtx-3090-24g-p5-3975-kr/p/N82E16814487524'
|
||||
},
|
||||
{
|
||||
brand: 'evga',
|
||||
model: 'xc3',
|
||||
series: '3090',
|
||||
url: 'https://www.newegg.ca/evga-geforce-rtx-3090-24g-p5-3973-kr/p/N82E16814487523'
|
||||
},
|
||||
{
|
||||
brand: 'evga',
|
||||
model: 'ftw3 ultra',
|
||||
series: '3090',
|
||||
url: 'https://www.newegg.ca/evga-geforce-rtx-3090-24g-p5-3987-kr/p/N82E16814487526'
|
||||
},
|
||||
{
|
||||
brand: 'evga',
|
||||
model: 'ftw3',
|
||||
series: '3090',
|
||||
url: 'https://www.newegg.ca/evga-geforce-rtx-3090-24g-p5-3985-kr/p/N82E16814487525'
|
||||
},
|
||||
{
|
||||
brand: 'msi',
|
||||
model: 'ventus 2x',
|
||||
series: '3070',
|
||||
url: 'https://www.newegg.ca/msi-geforce-rtx-3070-rtx-3070-ventus-2x-oc/p/N82E16814137602'
|
||||
},
|
||||
{
|
||||
brand: 'msi',
|
||||
model: 'ventus 3x',
|
||||
series: '3070',
|
||||
url: 'https://www.newegg.ca/msi-geforce-rtx-3070-rtx-3070-ventus-3x-oc/p/N82E16814137601'
|
||||
},
|
||||
{
|
||||
brand: 'msi',
|
||||
model: 'gaming x trio',
|
||||
series: '3070',
|
||||
url: 'https://www.newegg.ca/msi-geforce-rtx-3070-rtx-3070-gaming-x-trio/p/N82E16814137603'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'dual',
|
||||
series: '3070',
|
||||
url: 'https://www.newegg.ca/asus-geforce-rtx-3070-dual-rtx3070-8g/p/N82E16814126460'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'dual oc',
|
||||
series: '3070',
|
||||
url: 'https://www.newegg.ca/asus-geforce-rtx-3070-dual-rtx3070-o8g/p/N82E16814126459'
|
||||
},
|
||||
{
|
||||
brand: 'gigabyte',
|
||||
model: 'gaming oc',
|
||||
series: '3070',
|
||||
url: 'https://www.newegg.ca/gigabyte-geforce-rtx-3070-gv-n3070gaming-oc-8gd/p/N82E16814932342'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'rog strix',
|
||||
series: '3070',
|
||||
url: 'https://www.newegg.ca/asus-geforce-rtx-3070-rog-strix-rtx3070-o8g-gaming/p/N82E16814126458'
|
||||
},
|
||||
{
|
||||
brand: 'zotac',
|
||||
model: 'twin edge',
|
||||
series: '3070',
|
||||
url: 'https://www.newegg.ca/zotac-geforce-rtx-3070-zt-a30700e-10p/p/N82E16814500501'
|
||||
},
|
||||
{
|
||||
brand: 'gigabyte',
|
||||
model: 'eagle',
|
||||
series: '3070',
|
||||
url: 'https://www.newegg.ca/gigabyte-geforce-rtx-3070-gv-n3070eagle-8gd/p/N82E16814932344'
|
||||
},
|
||||
{
|
||||
brand: 'evga',
|
||||
model: 'xc3 black gaming',
|
||||
series: '3070',
|
||||
url: 'https://www.newegg.ca/evga-geforce-rtx-3070-08g-p5-3751-kr/p/N82E16814487528'
|
||||
},
|
||||
{
|
||||
brand: 'gigabyte',
|
||||
model: 'vision oc',
|
||||
series: '3070',
|
||||
url: 'https://www.newegg.ca/gigabyte-geforce-rtx-3070-gv-n3070vision-oc-8gd/p/N82E16814932360'
|
||||
},
|
||||
{
|
||||
brand: 'gigabyte',
|
||||
model: 'vision oc',
|
||||
series: '3080',
|
||||
url: 'https://www.newegg.ca/gigabyte-geforce-rtx-3080-gv-n3080vision-oc-10gd/p/N82E16814932337'
|
||||
},
|
||||
{
|
||||
brand: 'zotac',
|
||||
model: 'twin edge oc',
|
||||
series: '3070',
|
||||
url: 'https://www.newegg.ca/zotac-geforce-rtx-3070-zt-a30700h-10p/p/N82E16814500505'
|
||||
},
|
||||
{
|
||||
brand: 'pny',
|
||||
model: 'uprising',
|
||||
series: '3070',
|
||||
url: 'https://www.newegg.ca/pny-geforce-rtx-3070-vcg30708dfmpb/p/N82E16814133812'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'tuf',
|
||||
series: '3070',
|
||||
url: 'https://www.newegg.ca/asus-geforce-rtx-3070-tuf-rtx3070-o8g-gaming/p/N82E16814126461'
|
||||
},
|
||||
{
|
||||
brand: 'evga',
|
||||
model: 'ftw3 gaming',
|
||||
series: '3070',
|
||||
url: 'https://www.newegg.ca/evga-geforce-rtx-3070-08g-p5-3765-kr/p/N82E16814487531'
|
||||
},
|
||||
{
|
||||
brand: 'evga',
|
||||
model: 'ftw3 gaming',
|
||||
series: '3080',
|
||||
url: 'https://www.newegg.ca/evga-geforce-rtx-3080-10g-p5-3895-kr/p/N82E16814487519'
|
||||
},
|
||||
{
|
||||
brand: 'gigabyte',
|
||||
model: 'aorus',
|
||||
series: '3070',
|
||||
url: 'https://www.newegg.ca/gigabyte-geforce-rtx-3070-gv-n3070aorus-m-8gd/p/N82E16814932359'
|
||||
},
|
||||
{
|
||||
brand: 'gigabyte',
|
||||
model: 'eagle oc',
|
||||
series: '3070',
|
||||
url: 'https://www.newegg.ca/gigabyte-geforce-rtx-3070-gv-n3070eagle-oc-8gd/p/N82E16814932343'
|
||||
},
|
||||
{
|
||||
brand: 'evga',
|
||||
model: 'xc3 ultra gaming',
|
||||
series: '3070',
|
||||
url: 'https://www.newegg.ca/evga-geforce-rtx-3070-08g-p5-3755-kr/p/N82E16814487530'
|
||||
},
|
||||
{
|
||||
brand: 'evga',
|
||||
model: 'ftw3 ultra gaming',
|
||||
series: '3070',
|
||||
url: 'https://www.newegg.ca/evga-geforce-rtx-3070-08g-p5-3767-kr/p/N82E16814487532'
|
||||
},
|
||||
{
|
||||
brand: 'pny',
|
||||
model: 'xlr8 rgb',
|
||||
series: '3070',
|
||||
url: 'https://www.newegg.ca/pny-geforce-rtx-3070-vcg30708tfxppb/p/N82E16814133811'
|
||||
},
|
||||
{
|
||||
brand: 'evga',
|
||||
model: 'xc3 gaming',
|
||||
series: '3070',
|
||||
url: 'https://www.newegg.ca/evga-geforce-rtx-3070-08g-p5-3753-kr/p/N82E16814487529'
|
||||
}
|
||||
],
|
||||
name: 'newegg-ca'
|
||||
|
||||
+249
-15
@@ -1,4 +1,5 @@
|
||||
import {Store} from './store';
|
||||
import fetch from 'node-fetch';
|
||||
|
||||
export const Newegg: Store = {
|
||||
labels: {
|
||||
@@ -7,27 +8,50 @@ export const Newegg: Store = {
|
||||
text: ['are you a human?']
|
||||
},
|
||||
inStock: {
|
||||
container: '#landingpage-cart .btn-primary span',
|
||||
container: 'div#ProductBuy .btn-primary',
|
||||
text: ['add to cart']
|
||||
},
|
||||
maxPrice: {
|
||||
container: 'div#app div.product-price > ul > li.price-current > strong',
|
||||
euroFormat: false
|
||||
}
|
||||
},
|
||||
links: [
|
||||
{
|
||||
brand: 'test:brand',
|
||||
itemNumber: '14-500-495',
|
||||
model: 'test:model',
|
||||
series: 'test:series',
|
||||
url: 'https://www.newegg.com/evga-geforce-rtx-2060-06g-p4-2066-kr/p/N82E16814487488'
|
||||
url: 'https://www.newegg.com/zotac-geforce-rtx-2060-zt-t20600k-10m/p/N82E16814500495'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
cartUrl: 'https://secure.newegg.com/Shopping/AddtoCart.aspx?Submit=ADD&ItemList=N82E16814126453',
|
||||
itemNumber: '14-126-453',
|
||||
model: 'tuf',
|
||||
series: '3080',
|
||||
url: 'https://www.newegg.com/asus-geforce-rtx-3080-tuf-rtx3080-10g-gaming/p/N82E16814126453'
|
||||
},
|
||||
{
|
||||
brand: 'evga',
|
||||
cartUrl: 'https://secure.newegg.com/Shopping/AddtoCart.aspx?Submit=ADD&ItemList=N82E16814487518',
|
||||
itemNumber: '14-487-518',
|
||||
model: 'ftw3 ultra',
|
||||
series: '3080',
|
||||
url: 'https://www.newegg.com/evga-geforce-rtx-3080-10g-p5-3897-kr/p/N82E16814487518'
|
||||
},
|
||||
{
|
||||
brand: 'evga',
|
||||
cartUrl: 'https://secure.newegg.com/Shopping/AddtoCart.aspx?Submit=ADD&ItemList=N82E16814487519',
|
||||
itemNumber: '14-487-519',
|
||||
model: 'ftw3',
|
||||
series: '3080',
|
||||
url: 'https://www.newegg.com/evga-geforce-rtx-3080-10g-p5-3895-kr/p/N82E16814487519'
|
||||
},
|
||||
{
|
||||
brand: 'evga',
|
||||
cartUrl: 'https://secure.newegg.com/Shopping/AddtoCart.aspx?Submit=ADD&ItemList=N82E16814487522',
|
||||
itemNumber: '14-487-522',
|
||||
model: 'xc3 black',
|
||||
series: '3080',
|
||||
url: 'https://www.newegg.com/evga-geforce-rtx-3080-10g-p5-3881-kr/p/N82E16814487522'
|
||||
@@ -35,21 +59,15 @@ export const Newegg: Store = {
|
||||
{
|
||||
brand: 'evga',
|
||||
cartUrl: 'https://secure.newegg.com/Shopping/AddtoCart.aspx?Submit=ADD&ItemList=N82E16814487521',
|
||||
itemNumber: '14-487-521',
|
||||
model: 'xc3',
|
||||
series: '3080',
|
||||
url: 'https://www.newegg.com/evga-geforce-rtx-3080-10g-p5-3883-kr/p/N82E16814487521'
|
||||
},
|
||||
// Removed from Newegg currently not available in US
|
||||
// {
|
||||
// brand: 'evga',
|
||||
// cartUrl: 'https://secure.newegg.com/Shopping/AddtoCart.aspx?Submit=ADD&ItemList=N82E16814487520',
|
||||
// model: 'xc3 ultra',
|
||||
// series: '3080',
|
||||
// url: 'https://www.newegg.com/evga-geforce-rtx-3080-10g-p5-3885-kr/p/N82E16814487520'
|
||||
// },
|
||||
{
|
||||
brand: 'msi',
|
||||
cartUrl: 'https://secure.newegg.com/Shopping/AddtoCart.aspx?Submit=ADD&ItemList=N82E16814137600',
|
||||
itemNumber: '14-137-600',
|
||||
model: 'ventus 3x',
|
||||
series: '3080',
|
||||
url: 'https://www.newegg.com/msi-geforce-rtx-3080-rtx-3080-ventus-3x-10g/p/N82E16814137600'
|
||||
@@ -57,6 +75,7 @@ export const Newegg: Store = {
|
||||
{
|
||||
brand: 'msi',
|
||||
cartUrl: 'https://secure.newegg.com/Shopping/AddtoCart.aspx?Submit=ADD&ItemList=N82E16814137598',
|
||||
itemNumber: '14-137-598',
|
||||
model: 'ventus 3x oc',
|
||||
series: '3080',
|
||||
url: 'https://www.newegg.com/msi-geforce-rtx-3080-rtx-3080-ventus-3x-10g-oc/p/N82E16814137598'
|
||||
@@ -64,6 +83,7 @@ export const Newegg: Store = {
|
||||
{
|
||||
brand: 'msi',
|
||||
cartUrl: 'https://secure.newegg.com/Shopping/AddtoCart.aspx?Submit=ADD&ItemList=N82E16814137597',
|
||||
itemNumber: '14-137-597',
|
||||
model: 'gaming x trio',
|
||||
series: '3080',
|
||||
url: 'https://www.newegg.com/msi-geforce-rtx-3080-rtx-3080-gaming-x-trio-10g/p/N82E16814137597'
|
||||
@@ -71,6 +91,7 @@ export const Newegg: Store = {
|
||||
{
|
||||
brand: 'gigabyte',
|
||||
cartUrl: 'https://secure.newegg.com/Shopping/AddtoCart.aspx?Submit=ADD&ItemList=N82E16814932329',
|
||||
itemNumber: '149-32-329',
|
||||
model: 'gaming oc',
|
||||
series: '3080',
|
||||
url: 'https://www.newegg.com/gigabyte-geforce-rtx-3080-gv-n3080gaming-oc-10gd/p/N82E16814932329'
|
||||
@@ -78,13 +99,23 @@ export const Newegg: Store = {
|
||||
{
|
||||
brand: 'gigabyte',
|
||||
cartUrl: 'https://secure.newegg.com/Shopping/AddtoCart.aspx?Submit=ADD&ItemList=N82E16814932330',
|
||||
itemNumber: '149-32-330',
|
||||
model: 'eagle oc',
|
||||
series: '3080',
|
||||
url: 'https://www.newegg.com/gigabyte-geforce-rtx-3080-gv-n3080eagle-oc-10gd/p/N82E16814932330'
|
||||
},
|
||||
{
|
||||
brand: 'gigabyte',
|
||||
cartUrl: 'https://secure.newegg.com/Shopping/AddtoCart.aspx?Submit=ADD&ItemList=N82E16814932336',
|
||||
itemNumber: '14-932-336',
|
||||
model: 'aorus master',
|
||||
series: '3080',
|
||||
url: 'https://www.newegg.com/gigabyte-geforce-rtx-3080-gv-n3080aorus-m-10gd/p/N82E16814932336'
|
||||
},
|
||||
{
|
||||
brand: 'zotac',
|
||||
cartUrl: 'https://secure.newegg.com/Shopping/AddtoCart.aspx?Submit=ADD&ItemList=N82E16814500502',
|
||||
itemNumber: '14-950-502',
|
||||
model: 'trinity',
|
||||
series: '3080',
|
||||
url: 'https://www.newegg.com/zotac-geforce-rtx-3080-zt-a30800d-10p/p/N82E16814500502'
|
||||
@@ -92,6 +123,7 @@ export const Newegg: Store = {
|
||||
{
|
||||
brand: 'asus',
|
||||
cartUrl: 'https://secure.newegg.com/Shopping/AddtoCart.aspx?Submit=ADD&ItemList=N82E16814126457',
|
||||
itemNumber: '14-126-457',
|
||||
model: 'rog strix',
|
||||
series: '3080',
|
||||
url: 'https://www.newegg.com/asus-geforce-rtx-3080-rog-strix-rtx3080-o10g-gaming/p/N82E16814126457'
|
||||
@@ -99,6 +131,7 @@ export const Newegg: Store = {
|
||||
{
|
||||
brand: 'asus',
|
||||
cartUrl: 'https://secure.newegg.com/Shopping/AddtoCart.aspx?Submit=ADD&ItemList=N82E16814126452',
|
||||
itemNumber: '14-126-452',
|
||||
model: 'tuf oc',
|
||||
series: '3080',
|
||||
url: 'https://www.newegg.com/asus-geforce-rtx-3080-tuf-rtx3080-o10g-gaming/p/N82E16814126452'
|
||||
@@ -106,20 +139,39 @@ export const Newegg: Store = {
|
||||
{
|
||||
brand: 'zotac',
|
||||
cartUrl: 'https://secure.newegg.com/Shopping/AddtoCart.aspx?Submit=ADD&ItemList=N82E16814500504',
|
||||
itemNumber: '14-500-504',
|
||||
model: 'trinity oc',
|
||||
series: '3080',
|
||||
url: 'https://www.newegg.com/zotac-geforce-rtx-3080-zt-t30800j-10p/p/N82E16814500504'
|
||||
},
|
||||
{
|
||||
brand: 'pny',
|
||||
cartUrl: 'https://secure.newegg.com/Shopping/AddtoCart.aspx?Submit=ADD&ItemList=N82E16814133809',
|
||||
itemNumber: '14-133-809',
|
||||
model: 'xlr8 rgb',
|
||||
series: '3080',
|
||||
url: 'https://www.newegg.com/pny-geforce-rtx-3080-vcg308010tfxppb/p/N82E16814133809'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
cartUrl: 'https://secure.newegg.com/Shopping/AddtoCart.aspx?Submit=ADD&ItemList=',
|
||||
cartUrl: 'https://secure.newegg.com/Shopping/AddtoCart.aspx?Submit=ADD&ItemList=N82E16814126455',
|
||||
itemNumber: '14-126-455',
|
||||
model: 'tuf',
|
||||
series: '3090',
|
||||
url: 'https://www.newegg.com/asus-geforce-rtx-3090-tuf-rtx3090-24g-gaming/p/N82E16814126455'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
cartUrl: 'https://secure.newegg.com/Shopping/AddtoCart.aspx?Submit=ADD&ItemList=N82E16814126456',
|
||||
itemNumber: '14-126-456',
|
||||
model: 'rog strix',
|
||||
series: '3090',
|
||||
url: 'https://www.newegg.com/asus-geforce-rtx-3090-rog-strix-rtx3090-o24g-gaming/p/N82E16814126456'
|
||||
},
|
||||
{
|
||||
brand: 'msi',
|
||||
cartUrl: 'https://secure.newegg.com/Shopping/AddtoCart.aspx?Submit=ADD&ItemList=N82E16814137595',
|
||||
itemNumber: '14-137-595',
|
||||
model: 'gaming x trio',
|
||||
series: '3090',
|
||||
url: 'https://www.newegg.com/msi-geforce-rtx-3090-rtx-3090-gaming-x-trio-24g/p/N82E16814137595'
|
||||
@@ -127,6 +179,7 @@ export const Newegg: Store = {
|
||||
{
|
||||
brand: 'msi',
|
||||
cartUrl: 'https://secure.newegg.com/Shopping/AddtoCart.aspx?Submit=ADD&ItemList=N82E16814137596',
|
||||
itemNumber: '14-137-596',
|
||||
model: 'ventus 3x oc',
|
||||
series: '3090',
|
||||
url: 'https://www.newegg.com/msi-geforce-rtx-3090-rtx-3090-ventus-3x-24g-oc/p/N82E16814137596'
|
||||
@@ -134,6 +187,7 @@ export const Newegg: Store = {
|
||||
{
|
||||
brand: 'zotac',
|
||||
cartUrl: 'https://secure.newegg.com/Shopping/AddtoCart.aspx?Submit=ADD&ItemList=N82E16814500503',
|
||||
itemNumber: '14-500-503',
|
||||
model: 'trinity',
|
||||
series: '3090',
|
||||
url: 'https://www.newegg.com/zotac-geforce-rtx-3090-zt-a30900d-10p/p/N82E16814500503'
|
||||
@@ -141,6 +195,7 @@ export const Newegg: Store = {
|
||||
{
|
||||
brand: 'msi',
|
||||
cartUrl: 'https://secure.newegg.com/Shopping/AddtoCart.aspx?Submit=ADD&ItemList=N82E16814137599',
|
||||
itemNumber: '14-137-599',
|
||||
model: 'ventus 3x',
|
||||
series: '3090',
|
||||
url: 'https://www.newegg.com/msi-geforce-rtx-3090-rtx-3090-ventus-3x-24g/p/N82E16814137599'
|
||||
@@ -148,27 +203,47 @@ export const Newegg: Store = {
|
||||
{
|
||||
brand: 'evga',
|
||||
cartUrl: 'https://secure.newegg.com/Shopping/AddtoCart.aspx?Submit=ADD&ItemList=N82E16814487525',
|
||||
model: 'ftw3 gaming',
|
||||
itemNumber: '14-487-525',
|
||||
model: 'ftw3',
|
||||
series: '3090',
|
||||
url: 'https://www.newegg.com/evga-geforce-rtx-3090-24g-p5-3985-kr/p/N82E16814487525'
|
||||
},
|
||||
{
|
||||
brand: 'evga',
|
||||
cartUrl: 'https://secure.newegg.com/Shopping/AddtoCart.aspx?Submit=ADD&ItemList=N82E16814487524',
|
||||
model: 'xc3 ultra gaming',
|
||||
itemNumber: '14-487-524',
|
||||
model: 'xc3 ultra',
|
||||
series: '3090',
|
||||
url: 'https://www.newegg.com/evga-geforce-rtx-3090-24g-p5-3975-kr/p/N82E16814487524'
|
||||
},
|
||||
{
|
||||
brand: 'evga',
|
||||
cartUrl: 'https://secure.newegg.com/Shopping/AddtoCart.aspx?Submit=ADD&ItemList=N82E16814487526',
|
||||
model: 'ftw3 ultra gaming',
|
||||
itemNumber: '14-487-526',
|
||||
model: 'ftw3 ultra',
|
||||
series: '3090',
|
||||
url: 'https://www.newegg.com/evga-geforce-rtx-3090-24g-p5-3987-kr/p/N82E16814487526'
|
||||
},
|
||||
{
|
||||
brand: 'evga',
|
||||
cartUrl: 'https://secure.newegg.com/Shopping/AddtoCart.aspx?Submit=ADD&ItemList=N82E16814487527',
|
||||
itemNumber: '14-487-527',
|
||||
model: 'xc3 black',
|
||||
series: '3090',
|
||||
url: 'https://www.newegg.com/evga-geforce-rtx-3090-24g-p5-3971-kr/p/N82E16814487527'
|
||||
},
|
||||
{
|
||||
brand: 'evga',
|
||||
cartUrl: 'https://secure.newegg.com/Shopping/AddtoCart.aspx?Submit=ADD&ItemList=N82E16814487523',
|
||||
itemNumber: '14-487-523',
|
||||
model: 'xc3',
|
||||
series: '3090',
|
||||
url: 'https://www.newegg.com/evga-geforce-rtx-3090-24g-p5-3973-kr/p/N82E16814487523'
|
||||
},
|
||||
{
|
||||
brand: 'gigabyte',
|
||||
cartUrl: 'https://secure.newegg.com/Shopping/AddtoCart.aspx?Submit=ADD&ItemList=N82E16814932327',
|
||||
itemNumber: '14-932-327',
|
||||
model: 'gaming',
|
||||
series: '3090',
|
||||
url: 'https://www.newegg.com/gigabyte-geforce-rtx-3090-gv-n3090gaming-oc-24gd/p/N82E16814932327'
|
||||
@@ -176,10 +251,169 @@ export const Newegg: Store = {
|
||||
{
|
||||
brand: 'gigabyte',
|
||||
cartUrl: 'https://secure.newegg.com/Shopping/AddtoCart.aspx?Submit=ADD&ItemList=N82E16814932328',
|
||||
itemNumber: '14-932-328',
|
||||
model: 'eagle',
|
||||
series: '3090',
|
||||
url: 'https://www.newegg.com/gigabyte-geforce-rtx-3090-gv-n3090eagle-oc-24gd/p/N82E16814932328'
|
||||
},
|
||||
{
|
||||
brand: 'msi',
|
||||
cartUrl: 'https://secure.newegg.com/Shopping/AddtoCart.aspx?Submit=ADD&ItemList=N82E16814137601',
|
||||
itemNumber: '14-137-601',
|
||||
model: 'ventus 3x oc',
|
||||
series: '3070',
|
||||
url: 'https://www.newegg.com/msi-geforce-rtx-3070-rtx-3070-ventus-3x-oc/p/N82E16814137601'
|
||||
},
|
||||
{
|
||||
brand: 'msi',
|
||||
cartUrl: 'https://secure.newegg.com/Shopping/AddtoCart.aspx?Submit=ADD&ItemList=N82E16814137602',
|
||||
itemNumber: '14-137-602',
|
||||
model: 'ventus 2x oc',
|
||||
series: '3070',
|
||||
url: 'https://www.newegg.com/msi-geforce-rtx-3070-rtx-3070-ventus-2x-oc/p/N82E16814137602'
|
||||
},
|
||||
{
|
||||
brand: 'msi',
|
||||
cartUrl: 'https://secure.newegg.com/Shopping/AddtoCart.aspx?Submit=ADD&ItemList=N82E16814137603',
|
||||
itemNumber: '14-137-603',
|
||||
model: 'gaming x trio',
|
||||
series: '3070',
|
||||
url: 'https://www.newegg.com/msi-geforce-rtx-3070-rtx-3070-gaming-x-trio/p/N82E16814137603'
|
||||
},
|
||||
{
|
||||
brand: 'gigabyte',
|
||||
cartUrl: 'https://secure.newegg.com/Shopping/AddtoCart.aspx?Submit=ADD&ItemList=N82E16814932360',
|
||||
itemNumber: '14-932-360',
|
||||
model: 'vision oc',
|
||||
series: '3070',
|
||||
url: 'https://www.newegg.com/gigabyte-geforce-rtx-3070-gv-n3070vision-oc-8gd/p/N82E16814932360'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
cartUrl: 'https://secure.newegg.com/Shopping/AddtoCart.aspx?Submit=ADD&ItemList=N82E16814126459',
|
||||
itemNumber: '14-126-459',
|
||||
model: 'dual oc',
|
||||
series: '3070',
|
||||
url: 'https://www.newegg.com/asus-geforce-rtx-3070-dual-rtx3070-o8g/p/N82E16814126459'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
cartUrl: 'https://secure.newegg.com/Shopping/AddtoCart.aspx?Submit=ADD&ItemList=N82E16814126458',
|
||||
itemNumber: '14-126-458',
|
||||
model: 'rog strix',
|
||||
series: '3070',
|
||||
url: 'https://www.newegg.com/asus-geforce-rtx-3070-rog-strix-rtx3070-o8g-gaming/p/N82E16814126458'
|
||||
},
|
||||
{
|
||||
brand: 'zotac',
|
||||
cartUrl: 'https://secure.newegg.com/Shopping/AddtoCart.aspx?Submit=ADD&ItemList=N82E16814500501',
|
||||
itemNumber: '14-500-501',
|
||||
model: 'twin edge',
|
||||
series: '3070',
|
||||
url: 'https://www.newegg.com/zotac-geforce-rtx-3070-zt-a30700e-10p/p/N82E16814500501'
|
||||
},
|
||||
{
|
||||
brand: 'zotac',
|
||||
cartUrl: 'https://secure.newegg.com/Shopping/AddtoCart.aspx?Submit=ADD&ItemList=N82E16814500505',
|
||||
itemNumber: '14-500-505',
|
||||
model: 'twin edge oc',
|
||||
series: '3070',
|
||||
url: 'https://www.newegg.com/zotac-geforce-rtx-3070-zt-a30700h-10p/p/N82E16814500505'
|
||||
},
|
||||
{
|
||||
brand: 'gigabyte',
|
||||
cartUrl: 'https://secure.newegg.com/Shopping/AddtoCart.aspx?Submit=ADD&ItemList=N82E16814932342',
|
||||
itemNumber: '14-932-342',
|
||||
model: 'gaming oc',
|
||||
series: '3070',
|
||||
url: 'https://www.newegg.com/gigabyte-geforce-rtx-3070-gv-n3070gaming-oc-8gd/p/N82E16814932342'
|
||||
},
|
||||
{
|
||||
brand: 'evga',
|
||||
cartUrl: 'https://secure.newegg.com/Shopping/AddtoCart.aspx?Submit=ADD&ItemList=N82E16814487532',
|
||||
itemNumber: '14-487-532',
|
||||
model: 'ftw3 ultra',
|
||||
series: '3070',
|
||||
url: 'https://www.newegg.com/evga-geforce-rtx-3070-08g-p5-3767-kr/p/N82E16814487532'
|
||||
},
|
||||
{
|
||||
brand: 'evga',
|
||||
cartUrl: 'https://secure.newegg.com/Shopping/AddtoCart.aspx?Submit=ADD&ItemList=N82E16814487530',
|
||||
itemNumber: '14-487-530',
|
||||
model: 'xc3 ultra',
|
||||
series: '3070',
|
||||
url: 'https://www.newegg.com/evga-geforce-rtx-3070-08g-p5-3755-kr/p/N82E16814487530'
|
||||
},
|
||||
{
|
||||
brand: 'evga',
|
||||
cartUrl: 'https://secure.newegg.com/Shopping/AddtoCart.aspx?Submit=ADD&ItemList=N82E16814487528',
|
||||
itemNumber: '14-487-528',
|
||||
model: 'xc3 black',
|
||||
series: '3070',
|
||||
url: 'https://www.newegg.com/evga-geforce-rtx-3070-08g-p5-3751-kr/p/N82E16814487528'
|
||||
},
|
||||
{
|
||||
brand: 'gigabyte',
|
||||
cartUrl: 'https://secure.newegg.com/Shopping/AddtoCart.aspx?Submit=ADD&ItemList=N82E16814932343',
|
||||
itemNumber: '14-932-343',
|
||||
model: 'eagle oc',
|
||||
series: '3070',
|
||||
url: 'https://www.newegg.com/gigabyte-geforce-rtx-3070-gv-n3070eagle-oc-8gd/p/N82E16814932343'
|
||||
},
|
||||
{
|
||||
brand: 'gigabyte',
|
||||
cartUrl: 'https://secure.newegg.com/Shopping/AddtoCart.aspx?Submit=ADD&ItemList=N82E16814932344',
|
||||
itemNumber: '14-932-344',
|
||||
model: 'eagle',
|
||||
series: '3070',
|
||||
url: 'https://www.newegg.com/gigabyte-geforce-rtx-3070-gv-n3070eagle-8gd/p/N82E16814932344'
|
||||
},
|
||||
{
|
||||
brand: 'evga',
|
||||
cartUrl: 'https://secure.newegg.com/Shopping/AddtoCart.aspx?Submit=ADD&ItemList=N82E16814487529',
|
||||
itemNumber: '14-487-529',
|
||||
model: 'xc3',
|
||||
series: '3070',
|
||||
url: 'https://www.newegg.com/evga-geforce-rtx-3070-08g-p5-3753-kr/p/N82E16814487529'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
cartUrl: 'https://secure.newegg.com/Shopping/AddtoCart.aspx?Submit=ADD&ItemList=N82E16814126460',
|
||||
itemNumber: '14-126-460',
|
||||
model: 'dual',
|
||||
series: '3070',
|
||||
url: 'https://www.newegg.com/asus-geforce-rtx-3070-dual-rtx3070-8g/p/N82E16814126460'
|
||||
},
|
||||
{
|
||||
brand: 'gigabyte',
|
||||
cartUrl: 'https://secure.newegg.com/Shopping/AddtoCart.aspx?Submit=ADD&ItemList=N82E16814932359',
|
||||
itemNumber: '14-932-359',
|
||||
model: 'aorus master',
|
||||
series: '3070',
|
||||
url: 'https://www.newegg.com/gigabyte-geforce-rtx-3070-gv-n3070aorus-m-8gd/p/N82E16814932359'
|
||||
},
|
||||
{
|
||||
brand: 'evga',
|
||||
cartUrl: 'https://secure.newegg.com/Shopping/AddtoCart.aspx?Submit=ADD&ItemList=N82E16814487531',
|
||||
itemNumber: '14-487-531',
|
||||
model: 'ftw3',
|
||||
series: '3070',
|
||||
url: 'https://www.newegg.com/evga-geforce-rtx-3070-08g-p5-3765-kr/p/N82E16814487531'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
cartUrl: 'https://secure.newegg.com/Shopping/AddtoCart.aspx?Submit=ADD&ItemList=N82E16814126461',
|
||||
itemNumber: '14-126-461',
|
||||
model: 'tuf oc',
|
||||
series: '3070',
|
||||
url: 'https://www.newegg.com/asus-geforce-rtx-3070-tuf-rtx3070-o8g-gaming/p/N82E16814126461'
|
||||
}
|
||||
],
|
||||
name: 'newegg'
|
||||
name: 'newegg',
|
||||
realTimeInventoryLookup: async (itemNumber: string) => {
|
||||
const request_url = 'https://www.newegg.com/product/api/ProductRealtime?ItemNumber=' + itemNumber;
|
||||
const response = await fetch(request_url);
|
||||
const response_json = await response.json();
|
||||
return response_json.MainItem !== undefined && response_json.MainItem.Instock === true;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -0,0 +1,207 @@
|
||||
import {Store} from './store';
|
||||
|
||||
export const Notebooksbilliger: Store = {
|
||||
labels: {
|
||||
inStock: {
|
||||
container: '.warehouse',
|
||||
text: ['sofort ab lager', 'verfügbarkeit: ca. 2-4 werktage', 'verfügbarkeit: ca. 5-10 werktage']
|
||||
},
|
||||
maxPrice: {
|
||||
container: 'form[name="cart_quantity"] span[class*="product-price__regular"]',
|
||||
euroFormat: true
|
||||
},
|
||||
outOfStock: [{
|
||||
container: '.warehouse',
|
||||
text: ['liefertermin noch unbestimmt']
|
||||
},
|
||||
{
|
||||
container: '.soldOut',
|
||||
text: ['dieses produkt ist leider ausverkauft.']
|
||||
},
|
||||
{
|
||||
container: '.just_inStore',
|
||||
text: ['dieses Produkt kann nur in unseren unten genannten Stores gekauft werden.']
|
||||
},
|
||||
{
|
||||
container: '#product_error_text',
|
||||
text: ['leider ist dieser artikel nicht mehr verfügbar.']
|
||||
}]
|
||||
},
|
||||
links: [
|
||||
{
|
||||
brand: 'test:brand',
|
||||
model: 'test:model',
|
||||
series: 'test:series',
|
||||
url: 'https://www.notebooksbilliger.de/gainward+geforce+rtx+2070+super+phoenix+v1+grafikkarte+656238'
|
||||
},
|
||||
{
|
||||
brand: 'inno3d',
|
||||
model: 'ichill x3',
|
||||
series: '3070',
|
||||
url: 'https://www.notebooksbilliger.de/inno3d+geforce+rtx+3070+ichill+x3+grafikkarte+684162'
|
||||
},
|
||||
{
|
||||
brand: 'inno3d',
|
||||
model: 'twin x2',
|
||||
series: '3070',
|
||||
url: 'https://www.notebooksbilliger.de/inno3d+geforce+rtx+3070+twin+x2+grafikkarte+685496'
|
||||
},
|
||||
{
|
||||
brand: 'inno3d',
|
||||
model: 'twin x2 oc',
|
||||
series: '3070',
|
||||
url: 'https://www.notebooksbilliger.de/inno3d+geforce+rtx+3070+twin+x2+oc+grafikkarte+685500'
|
||||
},
|
||||
{
|
||||
brand: 'nvidia',
|
||||
model: 'founders edition',
|
||||
series: '3070',
|
||||
url: 'https://www.notebooksbilliger.de/nvidia+geforce+rtx+3070+founders+edition+685357'
|
||||
},
|
||||
{
|
||||
brand: 'gainward',
|
||||
model: 'phoenix',
|
||||
series: '3070',
|
||||
url: 'https://www.notebooksbilliger.de/gainward+geforce+rtx+3070+phoenix+8gb+gddr6+grafikkarte+685073'
|
||||
},
|
||||
{
|
||||
brand: 'gainward',
|
||||
model: 'phoenix gs',
|
||||
series: '3070',
|
||||
url: 'https://www.notebooksbilliger.de/gainward+geforce+rtx+3070+phoenix+gs+8gb+gddr6+grafikkarte+681575'
|
||||
},
|
||||
{
|
||||
brand: 'pny',
|
||||
model: 'uprising',
|
||||
series: '3070',
|
||||
url: 'https://www.notebooksbilliger.de/pny+geforce+rtx+3070+8gb+uprising+dual+fan+edition+grafikkarte+685520'
|
||||
},
|
||||
{
|
||||
brand: 'pny',
|
||||
model: 'xlr8 rgb',
|
||||
series: '3070',
|
||||
url: 'https://www.notebooksbilliger.de/pny+geforce+rtx+3070+8gb+xlr8+gaming+revel+epic+x+rgb+685560'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'tuf',
|
||||
series: '3070',
|
||||
url: 'https://www.notebooksbilliger.de/asus+tuf+gaming+geforce+rtx+3070+8gb+grafikkarte+685524'
|
||||
},
|
||||
{
|
||||
brand: 'zotac',
|
||||
model: 'twin edge',
|
||||
series: '3070',
|
||||
url: 'https://www.notebooksbilliger.de/zotac+gaming+geforce+rtx+3070+twin+edge+8gb+gddr6+grafikkarte+677561'
|
||||
},
|
||||
{
|
||||
brand: 'zotac',
|
||||
model: 'twin edge oc',
|
||||
series: '3070',
|
||||
url: 'https://www.notebooksbilliger.de/zotac+gaming+geforce+rtx+3070+twin+edge+oc+8gb+gddr6+grafikkarte+684216'
|
||||
},
|
||||
{
|
||||
brand: 'gainward',
|
||||
model: 'phoenix gs',
|
||||
series: '3080',
|
||||
url: 'https://www.notebooksbilliger.de/gainward+geforce+rtx+3080+phoenix+gs+10gb+gddr6x+grafikkarte+677618'
|
||||
},
|
||||
{
|
||||
brand: 'gigabyte',
|
||||
model: 'eagle oc',
|
||||
series: '3080',
|
||||
url: 'https://www.notebooksbilliger.de/gigabyte+geforce+rtx+3080+eagle+oc+10gb+gddr6x+grafikkarte+677501'
|
||||
},
|
||||
{
|
||||
brand: 'gigabyte',
|
||||
model: 'gaming oc',
|
||||
series: '3080',
|
||||
url: 'https://www.notebooksbilliger.de/gigabyte+geforce+rtx+3080+gaming+oc+10gb+gddr6x+grafikkarte+677499'
|
||||
},
|
||||
{
|
||||
brand: 'inno3d',
|
||||
model: 'ichill x3',
|
||||
series: '3080',
|
||||
url: 'https://www.notebooksbilliger.de/inno3d+geforce+rtx+3080+ichill+x3+grafikkarte+678588'
|
||||
},
|
||||
{
|
||||
brand: 'inno3d',
|
||||
model: 'twin x2 oc',
|
||||
series: '3080',
|
||||
url: 'https://www.notebooksbilliger.de/inno3d+geforce+rtx+3080+twin+x2+oc+grafikkarte+679190'
|
||||
},
|
||||
{
|
||||
brand: 'msi',
|
||||
model: 'gaming x trio',
|
||||
series: '3080',
|
||||
url: 'https://www.notebooksbilliger.de/msi+geforce+rtx+3080+gaming+x+trio+10g+grafikkarte+678527'
|
||||
},
|
||||
{
|
||||
brand: 'nvidia',
|
||||
model: 'founders edition',
|
||||
series: '3080',
|
||||
url: 'https://www.notebooksbilliger.de/nvidia+geforce+rtx+3080+founders+edition+683301'
|
||||
},
|
||||
{
|
||||
brand: 'palit',
|
||||
model: 'gaming pro',
|
||||
series: '3080',
|
||||
url: 'https://www.notebooksbilliger.de/palit+geforce+rtx+3080+gamingpro+10gb+gddr6x+grafikkarte+677609'
|
||||
},
|
||||
{
|
||||
brand: 'palit',
|
||||
model: 'gaming pro oc',
|
||||
series: '3080',
|
||||
url: 'https://www.notebooksbilliger.de/palit+geforce+rtx+3080+gamingpro+oc+10gb+gddr6x+grafikkarte+677606'
|
||||
},
|
||||
{
|
||||
brand: 'pny',
|
||||
model: 'xlr8 rgb',
|
||||
series: '3080',
|
||||
url: 'https://www.notebooksbilliger.de/pny+geforce+rtx+3080+xlr8+gaming+10gb+gddr6x+grafikkarte+677407'
|
||||
},
|
||||
{
|
||||
brand: 'pny',
|
||||
model: 'xlr8 rgb',
|
||||
series: '3080',
|
||||
url: 'https://www.notebooksbilliger.de/pny+geforce+rtx+3080+10gb+xlr8+gaming+revel+epic+x+grafikkarte+677412'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'rog strix',
|
||||
series: '3090',
|
||||
url: 'https://www.notebooksbilliger.de/asus+rog+strix+geforce+rtx+3090+24gb+gddr6x+grafikkarte+677343'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'rog strix oc',
|
||||
series: '3090',
|
||||
url: 'https://www.notebooksbilliger.de/asus+rog+strix+geforce+rtx+3090+oc+24gb+gddr6x+grafikkarte+677308'
|
||||
},
|
||||
{
|
||||
brand: 'gigabyte',
|
||||
model: 'aorus master',
|
||||
series: '3090',
|
||||
url: 'https://www.notebooksbilliger.de/gigabyte+geforce+rtx+3090+master+24gb+gddr6x+grafikkarte+683868'
|
||||
},
|
||||
{
|
||||
brand: 'nvidia',
|
||||
model: 'founders edition',
|
||||
series: '3090',
|
||||
url: 'https://www.notebooksbilliger.de/nvidia+geforce+rtx+3090+founders+edition+683300'
|
||||
},
|
||||
{
|
||||
brand: 'palit',
|
||||
model: 'gaming pro oc',
|
||||
series: '3090',
|
||||
url: 'https://www.notebooksbilliger.de/palit+geforce+rtx+3090+gamingpro+oc+24gb+gddr6x+grafikkarte+677599'
|
||||
},
|
||||
{
|
||||
brand: 'zotac',
|
||||
model: 'trinity',
|
||||
series: '3090',
|
||||
url: 'https://www.notebooksbilliger.de/zotac+gaming+geforce+rtx+3090+trinity+24gb+gddr6x+grafikkarte+677550'
|
||||
}
|
||||
],
|
||||
name: 'notebooksbilliger'
|
||||
};
|
||||
@@ -0,0 +1,52 @@
|
||||
import {Store} from './store';
|
||||
import {getProductLinksBuilder} from './helpers/card';
|
||||
|
||||
export const Novatech: Store = {
|
||||
labels: {
|
||||
inStock: {
|
||||
container: '.newspec-specprice',
|
||||
text: ['add to basket']
|
||||
},
|
||||
maxPrice: {
|
||||
container: 'p[class="newspec-price"]',
|
||||
euroFormat: false // Note: Novatech uses non-euroFromat as price seperator
|
||||
},
|
||||
outOfStock: {
|
||||
container: '.newspec-pricesection',
|
||||
text: [
|
||||
'very short supply, no confirmed date',
|
||||
'this product is only available to buy when in stock',
|
||||
'ordered upon request',
|
||||
'price to be confirmed'
|
||||
]
|
||||
}
|
||||
},
|
||||
links: [
|
||||
{
|
||||
brand: 'test:brand',
|
||||
model: 'test:model',
|
||||
series: 'test:series',
|
||||
url: 'https://www.novatech.co.uk/products/gigabyte-geforce-rtx-2060-oc-v2-6g-graphics-card/gv-n2060oc-6gdv2.html'
|
||||
}
|
||||
],
|
||||
linksBuilder: {
|
||||
builder: getProductLinksBuilder({
|
||||
productsSelector: '.seo-container .search-box-results',
|
||||
sitePrefix: 'https://www.novatech.co.uk',
|
||||
titleSelector: '.search-box-title',
|
||||
urlSelector: 'a[href]'
|
||||
}),
|
||||
urls: [
|
||||
{
|
||||
series: '3080',
|
||||
url: 'https://www.novatech.co.uk/products/components/nvidiageforcegraphicscards/nvidiartxseries/nvidiartx3080/?i=200'
|
||||
},
|
||||
{
|
||||
series: '3090',
|
||||
url: 'https://www.novatech.co.uk/products/components/nvidiageforcegraphicscards/nvidiartxseries/nvidiartx3090/?i=200'
|
||||
}
|
||||
]
|
||||
},
|
||||
name: 'novatech',
|
||||
waitUntil: 'domcontentloaded'
|
||||
};
|
||||
@@ -4,33 +4,36 @@ import {Store} from './store';
|
||||
// Region/country set by config file, silently ignores null / missing values and defaults to usa
|
||||
|
||||
export interface NvidiaRegionInfo {
|
||||
currency: string;
|
||||
drLocale: string;
|
||||
fe3080Id: number | null;
|
||||
fe3090Id: number | null;
|
||||
fe2060SuperId: number | null;
|
||||
nvidiaLocale: string;
|
||||
siteLocale: string;
|
||||
}
|
||||
|
||||
export const regionInfos = new Map<string, NvidiaRegionInfo>([
|
||||
['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'}],
|
||||
['netherlands', {drLocale: 'nl_nl', fe2060SuperId: 5394903500, fe3080Id: 5438796700, fe3090Id: null, nvidiaLocale: 'nl_nl'}],
|
||||
['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'}]
|
||||
['austria', {currency: 'EUR', drLocale: 'de_de', fe2060SuperId: 5394902900, fe3080Id: 5440853700, fe3090Id: 5444941400, siteLocale: 'de-at'}],
|
||||
['belgium', {currency: 'EUR', drLocale: 'fr_fr', fe2060SuperId: 5394902700, fe3080Id: 5438795700, fe3090Id: 5438795600, siteLocale: 'fr-be'}],
|
||||
['canada', {currency: 'CAD', drLocale: 'en_us', fe2060SuperId: 5379432500, fe3080Id: 5438481700, fe3090Id: 5438481600, siteLocale: 'en-us'}],
|
||||
['czechia', {currency: 'CZK', drLocale: 'en_gb', fe2060SuperId: 5394902800, fe3080Id: 5438793800, fe3090Id: 5438793600, siteLocale: 'cs-cz'}],
|
||||
['denmark', {currency: 'DKK', drLocale: 'en_gb', fe2060SuperId: 5394903100, fe3080Id: 5438793300, fe3090Id: null, siteLocale: 'da-dk'}],
|
||||
['finland', {currency: 'EUR', drLocale: 'en_gb', fe2060SuperId: 5394903100, fe3080Id: 5438793300, fe3090Id: null, siteLocale: 'fi-fi'}],
|
||||
['france', {currency: 'EUR', drLocale: 'fr_fr', fe2060SuperId: 5394903200, fe3080Id: 5438795200, fe3090Id: 5438761500, siteLocale: 'fr-fr'}],
|
||||
['germany', {currency: 'EUR', drLocale: 'de_de', fe2060SuperId: 5394902900, fe3080Id: 5438792300, fe3090Id: 5438761400, siteLocale: 'de-de'}],
|
||||
['great_britain', {currency: 'GBP', drLocale: 'en_gb', fe2060SuperId: 5394903300, fe3080Id: 5438792800, fe3090Id: 5438792700, siteLocale: 'en-gb'}],
|
||||
['ireland', {currency: 'GBP', drLocale: 'en_gb', fe2060SuperId: 5394903300, fe3080Id: 5438792800, fe3090Id: 5438792700, siteLocale: 'en-gb'}],
|
||||
['italy', {currency: 'EUR', drLocale: 'it_it', fe2060SuperId: 5394903400, fe3080Id: 5438796200, fe3090Id: 5438796100, siteLocale: 'it-it'}],
|
||||
['luxembourg', {currency: 'EUR', drLocale: 'fr_fr', fe2060SuperId: 5394902700, fe3080Id: 5438795700, fe3090Id: 5438795600, siteLocale: 'fr-be'}],
|
||||
['netherlands', {currency: 'EUR', drLocale: 'nl_nl', fe2060SuperId: 5394903500, fe3080Id: 5438796700, fe3090Id: 5438796600, siteLocale: 'nl-nl'}],
|
||||
['norway', {currency: 'NOK', drLocale: 'no_no', fe2060SuperId: 5394903600, fe3080Id: 5438797200, fe3090Id: 5438797100, siteLocale: 'nb-no'}],
|
||||
['poland', {currency: 'PLN', drLocale: 'pl_pl', fe2060SuperId: 5394903700, fe3080Id: 5438797700, fe3090Id: 5438797600, siteLocale: 'pl-pl'}],
|
||||
['portugal', {currency: 'EUR', drLocale: 'en_gb', fe2060SuperId: null, fe3080Id: 5438794300, fe3090Id: null, siteLocale: 'en-gb'}],
|
||||
['russia', {currency: 'RUB', drLocale: 'ru_ru', fe2060SuperId: null, fe3080Id: null, fe3090Id: null, siteLocale: 'ru-ru'}],
|
||||
['spain', {currency: 'EUR', drLocale: 'es_es', fe2060SuperId: 5394903000, fe3080Id: 5438794800, fe3090Id: 5438794700, siteLocale: 'es-es'}],
|
||||
['sweden', {currency: 'SEK', drLocale: 'sv_se', fe2060SuperId: 5394903900, fe3080Id: 5438798100, fe3090Id: 5438761600, siteLocale: 'sv-se'}],
|
||||
// https://github.com/jef/nvidia-snatcher/issues/407 This fe2080SuperID is for the Shield TV which is out of stock in the US
|
||||
['usa', {currency: 'USD', drLocale: 'en_us', fe2060SuperId: 5355772500, fe3080Id: 5438481700, fe3090Id: 5438481600, siteLocale: 'en-us'}]
|
||||
]);
|
||||
|
||||
export const NvidiaApi: Store = {
|
||||
|
||||
@@ -6,29 +6,65 @@ export const Nvidia: Store = {
|
||||
container: 'body',
|
||||
text: ['are you a human?']
|
||||
},
|
||||
inStock: {
|
||||
container: '.main-container',
|
||||
text: ['add to cart']
|
||||
}
|
||||
inStock: [
|
||||
{
|
||||
container: '.main-container',
|
||||
text: ['add to cart']
|
||||
},
|
||||
{
|
||||
container: '.inner',
|
||||
text: ['add to cart']
|
||||
}
|
||||
]
|
||||
},
|
||||
links: [
|
||||
{
|
||||
brand: 'test:brand',
|
||||
model: 'test:model',
|
||||
series: 'test:series',
|
||||
url: 'https://www.newegg.com/evga-geforce-rtx-2060-06g-p4-2066-kr/p/N82E16814487488'
|
||||
url: 'https://www.nvidia.com/en-us/shop/geforce/gpu/'
|
||||
},
|
||||
{
|
||||
brand: 'test:brand',
|
||||
model: 'test:model',
|
||||
series: 'test:series',
|
||||
url: 'https://www.nvidia.com/en-us/geforce/graphics-cards/rtx-2060-super/'
|
||||
},
|
||||
{
|
||||
brand: 'nvidia',
|
||||
model: 'founders edition',
|
||||
series: '3080',
|
||||
url: 'https://www.nvidia.com/en-us/shop/geforce/gpu/?page=1&limit=9&locale=en-us&gpu=RTX%203080&category=GPU&manufacturer=NVIDIA&gpu_filter=RTX%203090~1,RTX%203080~1,RTX%203070~0,TITAN%20RTX~0,RTX%202080%20Ti~0,RTX%202070%20SUPER~0,RTX%202060%20SUPER~0,RTX%202060~0,GTX%201660%20Ti~0,GTX%201660%20SUPER~0,GTX%201660~0,GTX%201650%20SUPER~0,GTX%201650~0'
|
||||
url: 'https://www.nvidia.com/en-us/shop/geforce/gpu/?page=1&limit=9&locale=en-us&category=GPU&gpu=RTX%203080'
|
||||
},
|
||||
{
|
||||
brand: 'nvidia',
|
||||
model: 'founders edition',
|
||||
series: '3080',
|
||||
url: 'https://www.nvidia.com/en-us/geforce/graphics-cards/30-series/rtx-3080'
|
||||
},
|
||||
{
|
||||
brand: 'nvidia',
|
||||
model: 'founders edition',
|
||||
series: '3090',
|
||||
url: 'https://www.nvidia.com/en-us/shop/geforce/gpu/?page=1&limit=9&locale=en-us&gpu=RTX%203090&category=GPU&manufacturer=NVIDIA&gpu_filter=RTX%203090~1,RTX%203080~1,RTX%203070~0,TITAN%20RTX~0,RTX%202080%20Ti~0,RTX%202070%20SUPER~0,RTX%202060%20SUPER~0,RTX%202060~0,GTX%201660%20Ti~0,GTX%201660%20SUPER~0,GTX%201660~0,GTX%201650%20SUPER~0,GTX%201650~0'
|
||||
url: 'https://www.nvidia.com/en-us/shop/geforce/gpu/?page=1&limit=9&locale=en-us&category=GPU&gpu=RTX%203090'
|
||||
},
|
||||
{
|
||||
brand: 'nvidia',
|
||||
model: 'founders edition',
|
||||
series: '3090',
|
||||
url: 'https://www.nvidia.com/en-us/geforce/graphics-cards/30-series/rtx-3090'
|
||||
},
|
||||
{
|
||||
brand: 'nvidia',
|
||||
model: 'founders edition',
|
||||
series: '3070',
|
||||
url: 'https://www.nvidia.com/en-us/shop/geforce/gpu/?page=1&limit=9&locale=en-us&category=GPU&gpu=RTX%203070'
|
||||
},
|
||||
{
|
||||
brand: 'nvidia',
|
||||
model: 'founders edition',
|
||||
series: '3070',
|
||||
url: 'https://www.nvidia.com/en-us/geforce/graphics-cards/30-series/rtx-3070'
|
||||
}
|
||||
],
|
||||
name: 'nvidia'
|
||||
|
||||
@@ -9,6 +9,10 @@ export const OfficeDepot: Store = {
|
||||
inStock: {
|
||||
container: '#productPurchase',
|
||||
text: ['add to cart']
|
||||
},
|
||||
maxPrice: {
|
||||
container: 'span[class^="price_column right"]',
|
||||
euroFormat: false
|
||||
}
|
||||
},
|
||||
links: [
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
import {Store} from './store';
|
||||
import {getProductLinksBuilder} from './helpers/card';
|
||||
|
||||
export const Overclockers: Store = {
|
||||
labels: {
|
||||
inStock: {
|
||||
container: '#detailbox',
|
||||
text: ['add to basket', 'in stock']
|
||||
},
|
||||
maxPrice: {
|
||||
container: 'div[class="article_details_price"]',
|
||||
euroFormat: false // Note: Overclockers uses non-euroFromat as price seperator
|
||||
},
|
||||
outOfStock: {
|
||||
container: '#detailbox',
|
||||
text: ['out of stock', 'pre order', 'bought to order']
|
||||
}
|
||||
},
|
||||
links: [
|
||||
{
|
||||
brand: 'test:brand',
|
||||
model: 'test:model',
|
||||
series: 'test:series',
|
||||
url: 'https://www.overclockers.co.uk/gigabyte-geforce-rtx-2060-oc-rev2-6144mb-gddr6-pci-express-graphics-card-gx-1bj-gi.html'
|
||||
}
|
||||
],
|
||||
linksBuilder: {
|
||||
builder: getProductLinksBuilder({
|
||||
productsSelector: '.ck_listing .artbox',
|
||||
sitePrefix: 'https://www.overclockers.co.uk',
|
||||
titleAttribute: 'data-description',
|
||||
titleSelector: 'a[href].producttitles'
|
||||
}),
|
||||
urls: [
|
||||
{
|
||||
series: '3070',
|
||||
url: 'https://www.overclockers.co.uk/pc-components/graphics-cards/nvidia/geforce-rtx-3070'
|
||||
},
|
||||
{
|
||||
series: '3080',
|
||||
// Need to add support to detect pagination so this can be dynamically detected
|
||||
url: [
|
||||
'https://www.overclockers.co.uk/pc-components/graphics-cards/nvidia/geforce-rtx-3080',
|
||||
'https://www.overclockers.co.uk/pc-components/graphics-cards/nvidia/geforce-rtx-3080?p=2'
|
||||
]
|
||||
},
|
||||
{
|
||||
series: '3090',
|
||||
url: 'https://www.overclockers.co.uk/pc-components/graphics-cards/nvidia/geforce-rtx-3090'
|
||||
}
|
||||
]
|
||||
},
|
||||
name: 'overclockers',
|
||||
waitUntil: 'domcontentloaded'
|
||||
};
|
||||
@@ -0,0 +1,148 @@
|
||||
import {Store} from './store';
|
||||
|
||||
export const PCComponentes: Store = {
|
||||
labels: {
|
||||
inStock: {
|
||||
container: '#btnsWishAddBuy',
|
||||
text: ['Comprar']
|
||||
},
|
||||
maxPrice: {
|
||||
container: '#precio-main',
|
||||
euroFormat: true
|
||||
},
|
||||
outOfStock: {
|
||||
container: '#btnsWishAddBuy',
|
||||
text: ['Avísame']
|
||||
}
|
||||
},
|
||||
links: [
|
||||
{
|
||||
brand: 'test:brand',
|
||||
model: 'test:model',
|
||||
series: 'test:series',
|
||||
url: 'https://www.pccomponentes.com/gigabyte-geforce-gtx-1660-super-oc-6gb-gddr6'
|
||||
},
|
||||
{
|
||||
brand: 'gigabyte',
|
||||
model: 'eagle oc',
|
||||
series: '3080',
|
||||
url: 'https://www.pccomponentes.com/gigabyte-geforce-rtx-3080-eagle-oc-10g-10gb-gddr6x'
|
||||
},
|
||||
{
|
||||
brand: 'msi',
|
||||
model: 'ventus 3x oc',
|
||||
series: '3080',
|
||||
url: 'https://www.pccomponentes.com/msi-geforce-rtx-3080-ventus-3x-oc-10gb-gddr6x'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'tuf',
|
||||
series: '3080',
|
||||
url: 'https://www.pccomponentes.com/asus-tuf-geforce-rtx-3080-10gb-gddr6x'
|
||||
},
|
||||
{
|
||||
brand: 'gigabyte',
|
||||
model: 'gaming oc',
|
||||
series: '3080',
|
||||
url: 'https://www.pccomponentes.com/gigabyte-geforce-rtx-3080-gaming-oc-10g-10gb-gddr6x'
|
||||
},
|
||||
{
|
||||
brand: 'msi',
|
||||
model: 'gaming x trio',
|
||||
series: '3080',
|
||||
url: 'https://www.pccomponentes.com/msi-geforce-rtx-3080-gaming-x-trio-10gb-gddr6x'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'tuf oc',
|
||||
series: '3080',
|
||||
url: 'https://www.pccomponentes.com/asus-tuf-geforce-rtx-3080-oc-10gb-gddr6x'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'rog strix oc',
|
||||
series: '3080',
|
||||
url: 'https://www.pccomponentes.com/asus-rog-strix-geforce-rtx-3080-10g-gaming-oc-10gb-gddr6x'
|
||||
},
|
||||
{
|
||||
brand: 'evga',
|
||||
model: 'xc3 black',
|
||||
series: '3080',
|
||||
url: 'https://www.pccomponentes.com/evga-geforce-rtx-3080-xc3-black-gaming-10gb-gddr6x'
|
||||
},
|
||||
{
|
||||
brand: 'zotac',
|
||||
model: 'trinity',
|
||||
series: '3080',
|
||||
url: 'https://www.pccomponentes.com/zotac-gaming-geforce-rtx-3080-trinity-10gb-gddr6x'
|
||||
},
|
||||
{
|
||||
brand: 'evga',
|
||||
model: 'xc3 ultra',
|
||||
series: '3080',
|
||||
url: 'https://www.pccomponentes.com/evga-geforce-rtx-3080-xc3-ultra-gaming-10gb-gddr6x'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'rog strix',
|
||||
series: '3080',
|
||||
url: 'https://www.pccomponentes.com/asus-rog-strix-geforce-rtx-3080-gaming-10gb-gddr6x'
|
||||
},
|
||||
{
|
||||
brand: 'zotac',
|
||||
model: 'trinity oc',
|
||||
series: '3080',
|
||||
url: 'https://www.pccomponentes.com/zotac-gaming-geforce-rtx-3080-trinity-oc-10gb-gddr6x'
|
||||
},
|
||||
{
|
||||
brand: 'gigabyte',
|
||||
model: 'vision oc',
|
||||
series: '3080',
|
||||
url: 'https://www.pccomponentes.com/gigabyte-geforce-rtx-3080-vision-oc-10gb-gddr6x'
|
||||
},
|
||||
{
|
||||
brand: 'evga',
|
||||
model: 'xc3',
|
||||
series: '3080',
|
||||
url: 'https://www.pccomponentes.com/evga-geforce-rtx-3080-xc3-gaming-10gb-gddr6x'
|
||||
},
|
||||
{
|
||||
brand: 'evga',
|
||||
model: 'ftw3 ultra',
|
||||
series: '3080',
|
||||
url: 'https://www.pccomponentes.com/evga-geforce-rtx-3080-ftw3-ultra-gaming-10gb-gddr6x'
|
||||
},
|
||||
{
|
||||
brand: 'gigabyte',
|
||||
model: 'aorus master',
|
||||
series: '3080',
|
||||
url: 'https://www.pccomponentes.com/gigabyte-aorus-geforce-rtx-3080-master-10gb-gddr6x'
|
||||
},
|
||||
{
|
||||
brand: 'gigabyte',
|
||||
model: 'aorus xtreme',
|
||||
series: '3080',
|
||||
url: 'https://www.pccomponentes.com/gigabyte-aorus-geforce-rtx-3080-xtreme-10gb-gddr6x'
|
||||
},
|
||||
{
|
||||
brand: 'evga',
|
||||
model: 'ftw3',
|
||||
series: '3080',
|
||||
url: 'https://www.pccomponentes.com/evga-geforce-rtx-3080-ftw3-gaming-10gb-gddr6x'
|
||||
},
|
||||
{
|
||||
brand: 'pny',
|
||||
model: 'xlr8 rgb',
|
||||
series: '3080',
|
||||
url: 'https://www.pccomponentes.com/pny-geforce-rtx-3080-xlr8-gaming-epic-x-rgb-10gb-gddr6x'
|
||||
},
|
||||
{
|
||||
brand: 'pny',
|
||||
model: 'xlr8',
|
||||
series: '3080',
|
||||
url: 'https://www.pccomponentes.com/pny-geforce-rtx-3080-epic-x-rgb-triple-fan-xlr8-gaming-edition-10gb-gddr6x'
|
||||
}
|
||||
],
|
||||
name: 'pccomponentes'
|
||||
};
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
import {Store} from './store';
|
||||
|
||||
export const Pny: Store = {
|
||||
labels: {
|
||||
inStock: {
|
||||
container: '#ctl01_lbtnAddToCart',
|
||||
text: ['add to cart']
|
||||
},
|
||||
maxPrice: {
|
||||
container: 'span[itemprop="price"]',
|
||||
euroFormat: false
|
||||
}
|
||||
|
||||
},
|
||||
links: [
|
||||
{
|
||||
brand: 'test:brand',
|
||||
model: 'test:model',
|
||||
series: 'test:series',
|
||||
url: 'https://www.pny.com/pny-geforce-gtx-1660-super-gaming-oc-sf'
|
||||
},
|
||||
{
|
||||
brand: 'pny',
|
||||
model: 'dual fan',
|
||||
series: '3070',
|
||||
url: 'https://www.pny.com/pny-geforce-rtx-3070-8gb-df'
|
||||
},
|
||||
{
|
||||
brand: 'pny',
|
||||
model: 'xlr8 rgb',
|
||||
series: '3070',
|
||||
url: 'https://www.pny.com/geforce-rtx-3070-xlr8-gaming-epic-x-rgb-triple-fan'
|
||||
},
|
||||
{
|
||||
brand: 'pny',
|
||||
model: 'xlr8 rgb',
|
||||
series: '3080',
|
||||
url: 'https://www.pny.com/geforce-rtx-3080-xlr8-gaming-epic-x-rgb-triple-fan-m'
|
||||
},
|
||||
{
|
||||
brand: 'pny',
|
||||
model: 'xlr8 rgb',
|
||||
series: '3080',
|
||||
url: 'https://www.pny.com/geforce-rtx-3080-xlr8-gaming-epic-x-rgb-triple-fan-p'
|
||||
},
|
||||
{
|
||||
brand: 'pny',
|
||||
model: 'xlr8 rgb',
|
||||
series: '3090',
|
||||
url: 'https://www.pny.com/geforce-rtx-3090-xlr8-gaming-epic-x-rgb-triple-fan-m'
|
||||
},
|
||||
{
|
||||
brand: 'pny',
|
||||
model: 'xlr8 rgb',
|
||||
series: '3090',
|
||||
url: 'https://www.pny.com/geforce-rtx-3090-xlr8-gaming-epic-x-rgb-triple-fan-p'
|
||||
}
|
||||
],
|
||||
name: 'pny'
|
||||
};
|
||||
|
||||
@@ -0,0 +1,258 @@
|
||||
import {Store} from './store';
|
||||
|
||||
export const ProshopDE: Store = {
|
||||
labels: {
|
||||
maxPrice: {
|
||||
container: '.site-currency-wrapper > span[class="site-currency-attention"]',
|
||||
euroFormat: true
|
||||
},
|
||||
outOfStock: {
|
||||
container: '.site-currency-attention',
|
||||
text: ['die ware ist leider nicht mehr verfügbar.']
|
||||
}
|
||||
},
|
||||
links: [
|
||||
{
|
||||
brand: 'test:brand',
|
||||
model: 'test:model',
|
||||
series: 'test:series',
|
||||
url: 'https://www.proshop.de/2797958'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'rog strix',
|
||||
series: '3070',
|
||||
url: 'https://www.proshop.de/2876843'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: ' rog strix oc',
|
||||
series: '3070',
|
||||
url: 'https://www.proshop.de/2876845'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'dual',
|
||||
series: '3070',
|
||||
url: 'https://www.proshop.de/2876851'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'dual oc',
|
||||
series: '3070',
|
||||
url: 'https://www.proshop.de/2876853'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'tuf',
|
||||
series: '3070',
|
||||
url: 'https://www.proshop.de/2876854'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'tuf oc',
|
||||
series: '3070',
|
||||
url: 'https://www.proshop.de/2876856'
|
||||
},
|
||||
{
|
||||
brand: 'gigabyte',
|
||||
model: 'eagle',
|
||||
series: '3070',
|
||||
url: 'https://www.proshop.de/2878385'
|
||||
},
|
||||
{
|
||||
brand: 'gigabyte',
|
||||
model: 'eagle oc',
|
||||
series: '3070',
|
||||
url: 'https://www.proshop.de/2878386'
|
||||
},
|
||||
{
|
||||
brand: 'gigabyte',
|
||||
model: 'gaming oc',
|
||||
series: '3070',
|
||||
url: 'https://www.proshop.de/2878390'
|
||||
},
|
||||
{
|
||||
brand: 'gigabyte',
|
||||
model: 'vision oc',
|
||||
series: '3070',
|
||||
url: 'https://www.proshop.de/2878390'
|
||||
},
|
||||
{
|
||||
brand: 'inno3d',
|
||||
model: 'ichill x2',
|
||||
series: '3070',
|
||||
url: 'https://www.proshop.de/2883916'
|
||||
},
|
||||
{
|
||||
brand: 'inno3d',
|
||||
model: 'twin x2 oc',
|
||||
series: '3070',
|
||||
url: 'https://www.proshop.de/2883917'
|
||||
},
|
||||
{
|
||||
brand: 'inno3d',
|
||||
model: 'ichill x3',
|
||||
series: '3070',
|
||||
url: 'https://www.proshop.de/2883918'
|
||||
},
|
||||
{
|
||||
brand: 'inno3d',
|
||||
model: 'ichill x4',
|
||||
series: '3070',
|
||||
url: 'https://www.proshop.de/2883919'
|
||||
},
|
||||
{
|
||||
brand: 'msi',
|
||||
model: 'gaming x trio',
|
||||
series: '3070',
|
||||
url: 'https://www.proshop.de/2876871'
|
||||
},
|
||||
{
|
||||
brand: 'msi',
|
||||
model: 'ventus 2x oc',
|
||||
series: '3070',
|
||||
url: 'https://www.proshop.de/2876873'
|
||||
},
|
||||
{
|
||||
brand: 'msi',
|
||||
model: 'ventus 3x oc',
|
||||
series: '3070',
|
||||
url: 'https://www.proshop.de/2876875'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'rog strix',
|
||||
series: '3080',
|
||||
url: 'https://www.proshop.de/2876857'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: ' rog strix oc',
|
||||
series: '3080',
|
||||
url: 'https://www.proshop.de/2876859'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'tuf',
|
||||
series: '3080',
|
||||
url: 'https://www.proshop.de/2876763'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'tuf oc',
|
||||
series: '3080',
|
||||
url: 'https://www.proshop.de/2876861'
|
||||
},
|
||||
{
|
||||
brand: 'gigabyte',
|
||||
model: 'aorus master',
|
||||
series: '3080',
|
||||
url: 'https://www.proshop.de/2876835'
|
||||
},
|
||||
{
|
||||
brand: 'gigabyte',
|
||||
model: 'eagle oc',
|
||||
series: '3080',
|
||||
url: 'https://www.proshop.de/2876837'
|
||||
},
|
||||
{
|
||||
brand: 'gigabyte',
|
||||
model: 'gaming oc',
|
||||
series: '3080',
|
||||
url: 'https://www.proshop.de/2876838'
|
||||
},
|
||||
{
|
||||
brand: 'gigabyte',
|
||||
model: 'vision oc',
|
||||
series: '3080',
|
||||
url: 'https://www.proshop.de/2878401'
|
||||
},
|
||||
{
|
||||
brand: 'inno3d',
|
||||
model: 'ichill x3',
|
||||
series: '3080',
|
||||
url: 'https://www.proshop.de/2878969'
|
||||
},
|
||||
{
|
||||
brand: 'inno3d',
|
||||
model: 'ichill x4',
|
||||
series: '3080',
|
||||
url: 'https://www.proshop.de/2878971'
|
||||
},
|
||||
{
|
||||
brand: 'inno3d',
|
||||
model: 'twin x2 oc',
|
||||
series: '3080',
|
||||
url: 'https://www.proshop.de/2878968'
|
||||
},
|
||||
{
|
||||
brand: 'msi',
|
||||
model: 'gaming x trio',
|
||||
series: '3080',
|
||||
url: 'https://www.proshop.de/2876877'
|
||||
},
|
||||
{
|
||||
brand: 'msi',
|
||||
model: 'ventus 3x',
|
||||
series: '3080',
|
||||
url: 'https://www.proshop.de/2876878'
|
||||
},
|
||||
{
|
||||
brand: 'msi',
|
||||
model: 'ventus 3x oc',
|
||||
series: '3080',
|
||||
url: 'https://www.proshop.de/2876879'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'rog strix',
|
||||
series: '3090',
|
||||
url: 'https://www.proshop.de/2876865'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'rog strix oc',
|
||||
series: '3090',
|
||||
url: 'https://www.proshop.de/2876867'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'tuf',
|
||||
series: '3090',
|
||||
url: 'https://www.proshop.de/2876764'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'tuf oc',
|
||||
series: '3090',
|
||||
url: 'https://www.proshop.de/2876869'
|
||||
},
|
||||
{
|
||||
brand: 'gigabyte',
|
||||
model: 'aorus master',
|
||||
series: '3090',
|
||||
url: 'https://www.proshop.de/2876840'
|
||||
},
|
||||
{
|
||||
brand: 'gigabyte',
|
||||
model: 'aorus xtreme',
|
||||
series: '3090',
|
||||
url: 'https://www.proshop.de/2876839'
|
||||
},
|
||||
{
|
||||
brand: 'gigabyte',
|
||||
model: 'turbo',
|
||||
series: '3090',
|
||||
url: 'https://www.proshop.de/2878410'
|
||||
},
|
||||
{
|
||||
brand: 'msi',
|
||||
model: 'gaming x trio',
|
||||
series: '3090',
|
||||
url: 'https://www.proshop.de/2876881'
|
||||
}
|
||||
],
|
||||
name: 'proshop-de'
|
||||
};
|
||||
|
||||
@@ -0,0 +1,154 @@
|
||||
import {Store} from './store';
|
||||
|
||||
export const ProshopDK: Store = {
|
||||
labels: {
|
||||
inStock: {
|
||||
container: '.site-stock',
|
||||
text: ['1-2 dages levering', 'fjernlager']
|
||||
},
|
||||
maxPrice: {
|
||||
container: '.site-currency-wrapper > span[class="site-currency-attention"]',
|
||||
euroFormat: true
|
||||
},
|
||||
outOfStock: {
|
||||
container: '.site-stock',
|
||||
text: ['bestilt']
|
||||
}
|
||||
},
|
||||
links: [
|
||||
{
|
||||
brand: 'test:brand',
|
||||
model: 'test:model',
|
||||
series: 'test:series',
|
||||
url: 'https://www.proshop.dk/Grafikkort/ASUS-GeForce-RTX-2060-TUF-OC-6GB-GDDR6-RAM-Grafikkort/2694767'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'tuf gaming',
|
||||
series: '3080',
|
||||
url: 'https://www.proshop.dk/Grafikkort/ASUS-GeForce-RTX-3080-TUF-10GB-GDDR6X-RAM-Grafikkort/2876763'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'tuf gaming oc',
|
||||
series: '3080',
|
||||
url: 'https://www.proshop.dk/Grafikkort/ASUS-GeForce-RTX-3080-TUF-OC-10GB-GDDR6X-RAM-Grafikkort/2876861'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'strix gaming',
|
||||
series: '3080',
|
||||
url: 'https://www.proshop.dk/Grafikkort/ASUS-GeForce-RTX-3080-ROG-STRIX-10GB-GDDR6X-RAM-Grafikkort/2876857'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'strix gaming oc',
|
||||
series: '3080',
|
||||
url: 'https://www.proshop.dk/Grafikkort/ASUS-GeForce-RTX-3080-ROG-STRIX-OC-10GB-GDDR6X-RAM-Grafikkort/2876859'
|
||||
},
|
||||
{
|
||||
brand: 'msi',
|
||||
model: 'gaming x trio',
|
||||
series: '3080',
|
||||
url: 'https://www.proshop.dk/Grafikkort/MSI-GeForce-RTX-3080-GAMING-X-TRIO-10GB-GDDR6X-RAM-Grafikkort/2876877'
|
||||
},
|
||||
{
|
||||
brand: 'msi',
|
||||
model: 'ventus 3x',
|
||||
series: '3080',
|
||||
url: 'https://www.proshop.dk/Grafikkort/MSI-GeForce-RTX-3080-Ventus-3X-10GB-GDDR6X-RAM-Grafikkort/2876878'
|
||||
},
|
||||
{
|
||||
brand: 'msi',
|
||||
model: 'ventus 3x oc',
|
||||
series: '3080',
|
||||
url: 'https://www.proshop.dk/Grafikkort/MSI-GeForce-RTX-3080-Ventus-3X-OC-10GB-GDDR6X-RAM-Grafikkort/2876879'
|
||||
},
|
||||
{
|
||||
brand: 'inno3d',
|
||||
model: 'ichill 4x',
|
||||
series: '3080',
|
||||
url: 'https://www.proshop.dk/Grafikkort/Inno3D-GeForce-RTX-3080-iCHILL-X4-10GB-GDDR6X-SDRAM-Grafikkort/2878971'
|
||||
},
|
||||
{
|
||||
brand: 'inno3d',
|
||||
model: 'ichill 3x',
|
||||
series: '3080',
|
||||
url: 'https://www.proshop.dk/Grafikkort/Inno3D-GeForce-RTX-3080-iCHILL-X3-10GB-GDDR6X-SDRAM-Grafikkort/2878969'
|
||||
},
|
||||
{
|
||||
brand: 'gigabyte',
|
||||
model: 'gaming oc',
|
||||
series: '3080',
|
||||
url: 'https://www.proshop.dk/Grafikkort/GIGABYTE-GeForce-RTX-3080-GAMING-OC-10GB-GDDR6X-RAM-Grafikkort/2876838'
|
||||
},
|
||||
{
|
||||
brand: 'gigabyte',
|
||||
model: 'eagle oc',
|
||||
series: '3080',
|
||||
url: 'https://www.proshop.dk/Grafikkort/GIGABYTE-GeForce-RTX-3080-Eagle-OC-10GB-GDDR6X-RAM-Grafikkort/2876837'
|
||||
},
|
||||
{
|
||||
brand: 'inno3d',
|
||||
model: 'twin x2 oc',
|
||||
series: '3080',
|
||||
url: 'https://www.proshop.dk/Grafikkort/Inno3D-GeForce-RTX-3080-Twin-X2-OC-10GB-GDDR6X-SDRAM-Grafikkort/2878968'
|
||||
},
|
||||
{
|
||||
brand: 'gigabyte',
|
||||
model: 'vision oc',
|
||||
series: '3080',
|
||||
url: 'https://www.proshop.dk/Grafikkort/GIGABYTE-GeForce-RTX-3080-Vision-OC-10GB-GDDR6X-RAM-Grafikkort/2878401'
|
||||
},
|
||||
{
|
||||
brand: 'gigabyte',
|
||||
model: 'aorus master',
|
||||
series: '3080',
|
||||
url: 'https://www.proshop.dk/Grafikkort/GIGABYTE-GeForce-RTX-3080-AORUS-Master-10GB-GDDR6X-RAM-Grafikkort/2876835'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'tuf gaming',
|
||||
series: '3090',
|
||||
url: 'https://www.proshop.dk/Grafikkort/ASUS-GeForce-RTX-3090-TUF-24GB-GDDR6X-RAM-Grafikkort/2876764'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'tuf gaming oc',
|
||||
series: '3090',
|
||||
url: 'https://www.proshop.dk/Grafikkort/ASUS-GeForce-RTX-3090-TUF-OC-24GB-GDDR6X-RAM-Grafikkort/2876869'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'strix gaming',
|
||||
series: '3090',
|
||||
url: 'https://www.proshop.dk/Grafikkort/ASUS-GeForce-RTX-3090-ROG-STRIX-24GB-GDDR6X-RAM-Grafikkort/2876865'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'strix gaming oc',
|
||||
series: '3090',
|
||||
url: 'https://www.proshop.dk/Grafikkort/ASUS-GeForce-RTX-3090-ROG-STRIX-OC-24GB-GDDR6X-RAM-Grafikkort/2876867'
|
||||
},
|
||||
{
|
||||
brand: 'msi',
|
||||
model: 'gaming x trio',
|
||||
series: '3090',
|
||||
url: 'https://www.proshop.dk/Grafikkort/MSI-GeForce-RTX-3090-GAMING-X-TRIO-24GB-GDDR6X-RAM-Grafikkort/2876881'
|
||||
},
|
||||
{
|
||||
brand: 'gigabyte',
|
||||
model: 'aorus master',
|
||||
series: '3090',
|
||||
url: 'https://www.proshop.dk/Grafikkort/GIGABYTE-GeForce-RTX-3090-AORUS-Master-24GB-GDDR6X-RAM-Grafikkort/2876840'
|
||||
},
|
||||
{
|
||||
brand: 'gigabyte',
|
||||
model: 'aorus xtreme',
|
||||
series: '3090',
|
||||
url: 'https://www.proshop.dk/Grafikkort/GIGABYTE-GeForce-RTX-3090-AORUS-Xtreme-24GB-GDDR6X-RAM-Grafikkort/2876839'
|
||||
}
|
||||
],
|
||||
name: 'proshop-dk'
|
||||
};
|
||||
|
||||
@@ -0,0 +1,161 @@
|
||||
import {Store} from './store';
|
||||
|
||||
export const Saturn: Store = {
|
||||
labels: {
|
||||
maxPrice: {
|
||||
container: 'span[font-family="price"]',
|
||||
euroFormat: false // Note: Saturn uses non-euroFromat as price seperator
|
||||
},
|
||||
outOfStock: {
|
||||
container: '#root',
|
||||
text: ['dieser artikel ist aktuell nicht verfügbar.']
|
||||
}
|
||||
},
|
||||
links: [
|
||||
{
|
||||
brand: 'test:brand',
|
||||
model: 'test:model',
|
||||
series: 'test:series',
|
||||
url: 'https://www.saturn.de/de/product/-2592355.html'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'rog strix oc',
|
||||
series: '3070',
|
||||
url: 'https://www.saturn.de/de/product/-2691244.html'
|
||||
},
|
||||
{
|
||||
brand: 'gigabyte',
|
||||
model: 'gaming oc',
|
||||
series: '3070',
|
||||
url: 'https://www.saturn.de/de/product/-2691439.html'
|
||||
},
|
||||
{
|
||||
brand: 'inno3d',
|
||||
model: 'ichill x3',
|
||||
series: '3070',
|
||||
url: 'https://www.saturn.de/de/product/-2695942.html'
|
||||
},
|
||||
{
|
||||
brand: 'zotac',
|
||||
model: 'twin edge',
|
||||
series: '3070',
|
||||
url: 'https://www.saturn.de/de/product/-2691365.html'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'rog strix',
|
||||
series: '3080',
|
||||
url: 'https://www.saturn.de/de/product/-2681869.html'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'rog strix oc',
|
||||
series: '3080',
|
||||
url: 'https://www.saturn.de/de/product/-2681871.html'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'tuf',
|
||||
series: '3080',
|
||||
url: 'https://www.saturn.de/de/product/-2681859.html'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'tuf oc',
|
||||
series: '3080',
|
||||
url: 'https://www.saturn.de/de/product/-2681861.html'
|
||||
},
|
||||
{
|
||||
brand: 'gigabyte',
|
||||
model: 'eagle oc',
|
||||
series: '3080',
|
||||
url: 'https://www.saturn.de/de/product/-2683942.html'
|
||||
},
|
||||
{
|
||||
brand: 'gigabyte',
|
||||
model: 'gaming oc',
|
||||
series: '3080',
|
||||
url: 'https://www.saturn.de/de/product/-2683937.html'
|
||||
},
|
||||
{
|
||||
brand: 'inno3d',
|
||||
model: 'ichill x3',
|
||||
series: '3080',
|
||||
url: 'https://www.saturn.de/de/product/-2684241.html'
|
||||
},
|
||||
{
|
||||
brand: 'inno3d',
|
||||
model: 'ichill x4',
|
||||
series: '3080',
|
||||
url: 'https://www.saturn.de/de/product/-2684238.html'
|
||||
},
|
||||
{
|
||||
brand: 'msi',
|
||||
model: 'gaming x trio',
|
||||
series: '3080',
|
||||
url: 'https://www.saturn.de/de/product/-2683227.html'
|
||||
},
|
||||
{
|
||||
brand: 'msi',
|
||||
model: 'ventus 3x oc',
|
||||
series: '3080',
|
||||
url: 'https://www.saturn.de/de/product/-2683229.html'
|
||||
},
|
||||
{
|
||||
brand: 'zotac',
|
||||
model: 'trinity',
|
||||
series: '3080',
|
||||
url: 'https://www.saturn.de/de/product/-2683243.html'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'rog strix',
|
||||
series: '3090',
|
||||
url: 'https://www.saturn.de/de/product/-2681863.html'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'rog strix oc',
|
||||
series: '3090',
|
||||
url: 'https://www.saturn.de/de/product/-2681866.html'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'tuf',
|
||||
series: '3090',
|
||||
url: 'https://www.saturn.de/de/product/-2681855.html'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
model: 'tuf oc',
|
||||
series: '3090',
|
||||
url: 'https://www.saturn.de/de/product/-2681857.html'
|
||||
},
|
||||
{
|
||||
brand: 'gigabyte',
|
||||
model: 'aorus master',
|
||||
series: '3090',
|
||||
url: 'https://www.saturn.de/de/product/-2691441.html'
|
||||
},
|
||||
{
|
||||
brand: 'gigabyte',
|
||||
model: 'aorus xtreme',
|
||||
series: '3090',
|
||||
url: 'https://www.saturn.de/de/product/-2691440.html'
|
||||
},
|
||||
{
|
||||
brand: 'inno3d',
|
||||
model: 'ichill x4',
|
||||
series: '3090',
|
||||
url: 'https://www.saturn.de/de/product/-2684235.html'
|
||||
},
|
||||
{
|
||||
brand: 'msi',
|
||||
model: 'gaming x trio',
|
||||
series: '3090',
|
||||
url: 'https://www.saturn.de/de/product/-2683226.html'
|
||||
}
|
||||
],
|
||||
name: 'saturn'
|
||||
};
|
||||
@@ -0,0 +1,57 @@
|
||||
import {Store} from './store';
|
||||
import {getProductLinksBuilder} from './helpers/card';
|
||||
|
||||
export const Scan: Store = {
|
||||
disableAdBlocker: true,
|
||||
labels: {
|
||||
captcha: [{
|
||||
container: '#challenge-form',
|
||||
text: ['hcaptcha_submit']
|
||||
}],
|
||||
inStock: {
|
||||
container: '.buyPanel .priceAvailability',
|
||||
text: ['add to basket', 'in stock']
|
||||
},
|
||||
maxPrice: {
|
||||
container: '.buyPanel .price',
|
||||
euroFormat: false // Note: Scan uses non-euroFromat as price seperator
|
||||
},
|
||||
outOfStock: {
|
||||
container: '.buyPanel .priceAvailability',
|
||||
text: ['pre order']
|
||||
}
|
||||
},
|
||||
links: [
|
||||
{
|
||||
brand: 'test:brand',
|
||||
model: 'test:model',
|
||||
series: 'test:series',
|
||||
url: 'https://www.scan.co.uk/products/msi-geforce-rtx-2060-ventus-xs-oc-6gb-gddr6-vr-ready-graphics-card-1920-core-1710mhz-boost'
|
||||
}
|
||||
],
|
||||
linksBuilder: {
|
||||
builder: getProductLinksBuilder({
|
||||
productsSelector: 'ul.productColumns li.product',
|
||||
sitePrefix: 'https://www.scan.co.uk',
|
||||
titleSelector: '.details .description',
|
||||
urlSelector: 'a[href]'
|
||||
}),
|
||||
ttl: 300000,
|
||||
urls: [
|
||||
{
|
||||
series: '3070',
|
||||
url: 'https://www.scan.co.uk/shop/computer-hardware/gpu-nvidia/nvidia-geforce-rtx-3070-graphics-cards'
|
||||
},
|
||||
{
|
||||
series: '3080',
|
||||
url: 'https://www.scan.co.uk/shop/computer-hardware/gpu-nvidia/nvidia-geforce-rtx-3080-graphics-cards'
|
||||
},
|
||||
{
|
||||
series: '3090',
|
||||
url: 'https://www.scan.co.uk/shop/computer-hardware/gpu-nvidia/nvidia-geforce-rtx-3090-graphics-cards'
|
||||
}
|
||||
]
|
||||
},
|
||||
name: 'scan',
|
||||
waitUntil: 'domcontentloaded'
|
||||
};
|
||||
@@ -1,13 +1,21 @@
|
||||
import {Browser, LoadEvent} from 'puppeteer';
|
||||
|
||||
export type Element = {
|
||||
container: string;
|
||||
container?: string;
|
||||
text: string[];
|
||||
};
|
||||
|
||||
export type Pricing = {
|
||||
container: string;
|
||||
euroFormat?: boolean;
|
||||
};
|
||||
|
||||
export type Series = 'test:series' | '3070' | '3080' | '3090';
|
||||
|
||||
export type Link = {
|
||||
brand: 'test:brand' | 'asus' | 'evga' | 'gigabyte' | 'pny' | 'msi' | 'nvidia' | 'zotac';
|
||||
series: 'test:series' | '3070' | '3080' | '3090';
|
||||
brand: 'test:brand' | 'asus' | 'evga' | 'gainward' | 'gigabyte' | 'inno3d' | 'kfa2' | 'msi' | 'nvidia' | 'palit' | 'pny' | 'zotac';
|
||||
itemNumber?: string;
|
||||
series: Series;
|
||||
model: string;
|
||||
url: string;
|
||||
cartUrl?: string;
|
||||
@@ -15,15 +23,45 @@ export type Link = {
|
||||
screenshot?: string;
|
||||
};
|
||||
|
||||
export type LabelQuery = Element[] | Element | string[];
|
||||
|
||||
export type Labels = {
|
||||
captcha?: Element;
|
||||
inStock: Element;
|
||||
bannedSeller?: LabelQuery;
|
||||
captcha?: LabelQuery;
|
||||
container?: string;
|
||||
inStock?: LabelQuery;
|
||||
outOfStock?: LabelQuery;
|
||||
maxPrice?: Pricing;
|
||||
};
|
||||
|
||||
export type StatusCodeRangeArray = Array<(number | [number, number])>;
|
||||
|
||||
export type Store = {
|
||||
realTimeInventoryLookup?: (itemNumber: string) => Promise<boolean>;
|
||||
/**
|
||||
* The range of status codes which will trigger backoff, i.e. an increasing
|
||||
* delay between requests. Setting an empty array will disable the feature.
|
||||
* If not defined, the default range will be used: 403.
|
||||
*/
|
||||
backoffStatusCodes?: StatusCodeRangeArray;
|
||||
disableAdBlocker?: boolean;
|
||||
links: Link[];
|
||||
linksBuilder?: {
|
||||
builder: (docElement: cheerio.Cheerio, series: Series) => Link[];
|
||||
ttl?: number;
|
||||
urls: Array<{series: Series; url: string | string[]}>;
|
||||
};
|
||||
labels: Labels;
|
||||
name: string;
|
||||
setupAction?: (browser: Browser) => void;
|
||||
/**
|
||||
* The range of status codes which considered successful, i.e. without error
|
||||
* allowing request parsing to continue. Setting an empty array will cause
|
||||
* all requests to fail. If not defined, the default range will be used:
|
||||
* 0 -> 399 inclusive.
|
||||
*/
|
||||
successStatusCodes?: StatusCodeRangeArray;
|
||||
waitUntil?: LoadEvent;
|
||||
minPageSleep?: number;
|
||||
maxPageSleep?: number;
|
||||
};
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
import {Link, Store} from './store';
|
||||
import {logger} from '../../logger';
|
||||
import {parseCard} from './helpers/card';
|
||||
|
||||
export const Very: Store = {
|
||||
labels: {
|
||||
inStock: {
|
||||
container: '.stockMessaging .indicator',
|
||||
text: ['available', 'low stock']
|
||||
},
|
||||
maxPrice: {
|
||||
container: '.priceNow',
|
||||
euroFormat: false // Note: Very uses non-euroFromat as price seperator
|
||||
},
|
||||
outOfStock: {
|
||||
container: '.stockMessaging .indicator',
|
||||
text: ['pre-order']
|
||||
}
|
||||
},
|
||||
links: [
|
||||
{
|
||||
brand: 'test:brand',
|
||||
model: 'test:model',
|
||||
series: 'test:series',
|
||||
url: 'https://www.very.co.uk/msi-geforce-gtx-1660-ti-gaming-x-6g-graphics-card/1600350984.prd'
|
||||
}
|
||||
],
|
||||
linksBuilder: {
|
||||
builder: (docElement, series) => {
|
||||
const productElements = docElement.find('.productList .product');
|
||||
const links: Link[] = [];
|
||||
for (let i = 0; i < productElements.length; i++) {
|
||||
const productElement = productElements.eq(i);
|
||||
const titleElement = productElement.find('.productTitle').first();
|
||||
const title = titleElement.text()?.replace(/\n/g, ' ').trim();
|
||||
|
||||
if (!title || ['RTX', series]
|
||||
.map(x => title.toLowerCase().includes(x.toLowerCase()))
|
||||
.filter(x => !x).length > 0
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const url = titleElement.attr()?.href;
|
||||
|
||||
if (!url) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const card = parseCard(title);
|
||||
|
||||
if (card) {
|
||||
links.push({
|
||||
brand: card.brand as any,
|
||||
model: card.model,
|
||||
series,
|
||||
url
|
||||
});
|
||||
} else {
|
||||
logger.error(`Failed to parse card: ${title}`);
|
||||
}
|
||||
}
|
||||
|
||||
return links;
|
||||
},
|
||||
ttl: 300000,
|
||||
urls: [
|
||||
{
|
||||
series: '3070',
|
||||
url: 'https://www.very.co.uk/electricals/pc-components/graphics-cards/e/b/118786.end?sort=newin,0&numProducts=100'
|
||||
},
|
||||
{
|
||||
series: '3080',
|
||||
url: 'https://www.very.co.uk/electricals/pc-components/graphics-cards/e/b/118786.end?sort=newin,0&numProducts=100'
|
||||
},
|
||||
{
|
||||
series: '3090',
|
||||
url: 'https://www.very.co.uk/electricals/pc-components/graphics-cards/e/b/118786.end?sort=newin,0&numProducts=100'
|
||||
}
|
||||
]
|
||||
},
|
||||
name: 'very'
|
||||
};
|
||||
@@ -1,10 +1,15 @@
|
||||
import {Store} from './store';
|
||||
|
||||
export const Zotac: Store = {
|
||||
backoffStatusCodes: [403, 503],
|
||||
labels: {
|
||||
inStock: {
|
||||
container: '.add-to-cart-wrapper',
|
||||
text: ['add to cart']
|
||||
},
|
||||
maxPrice: {
|
||||
container: 'div[class="product-shop"] span[class="price"]',
|
||||
euroFormat: false
|
||||
}
|
||||
},
|
||||
links: [
|
||||
@@ -22,9 +27,15 @@ export const Zotac: Store = {
|
||||
},
|
||||
{
|
||||
brand: 'zotac',
|
||||
model: 'trinity OC',
|
||||
model: 'trinity oc',
|
||||
series: '3080',
|
||||
url: 'https://store.zotac.com/zotac-gaming-geforce-rtx-3080-trinity-oc-zt-a30800j-10p'
|
||||
},
|
||||
{
|
||||
brand: 'zotac',
|
||||
model: 'trinity',
|
||||
series: '3090',
|
||||
url: 'https://store.zotac.com/zotac-gaming-geforce-rtx-3090-trinity-zt-a30900d-10p'
|
||||
}
|
||||
],
|
||||
name: 'zotac'
|
||||
|
||||
Vendored
+1
@@ -0,0 +1 @@
|
||||
declare module 'node-pagerduty';
|
||||
Vendored
+22
-1
@@ -1 +1,22 @@
|
||||
declare module 'play-sound';
|
||||
declare module 'play-sound' {
|
||||
export interface Options {
|
||||
players?: string[];
|
||||
player?: string;
|
||||
}
|
||||
|
||||
export interface PlayOptions {
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
export interface PlaySound {
|
||||
player: string;
|
||||
|
||||
play: ((file: string, callback: (error: Error) => void) => PlayerProcess) & ((file: string, options: PlayOptions, callback: (error: Error) => void) => PlayerProcess);
|
||||
}
|
||||
|
||||
export interface PlayerProcess {
|
||||
kill: () => void;
|
||||
}
|
||||
|
||||
export default function (options?: Options): PlaySound;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
declare module 'puppeteer-extra-plugin-block-resources' {
|
||||
import {PuppeteerExtraPlugin} from 'puppeteer-extra';
|
||||
|
||||
export type ResourceType =
|
||||
'document' |
|
||||
'eventsource' |
|
||||
'fetch' |
|
||||
'font' |
|
||||
'image' |
|
||||
'manifest' |
|
||||
'media' |
|
||||
'other' |
|
||||
'script' |
|
||||
'stylesheet' |
|
||||
'texttrack' |
|
||||
'websocket' |
|
||||
'xhr';
|
||||
|
||||
export interface Options {
|
||||
availableTypes?: Set<ResourceType>;
|
||||
blockedTypes?: Set<ResourceType>;
|
||||
}
|
||||
|
||||
export default function (options?: Options): PuppeteerExtraPlugin;
|
||||
}
|
||||
Vendored
+59
-1
@@ -1 +1,59 @@
|
||||
declare module 'pushbullet';
|
||||
declare module '@jef/pushbullet' {
|
||||
export type DeviceParams = string | number | Record<string, any>;
|
||||
|
||||
export type PushBulletCallback = ((error: Error) => void) | ((error?: null, response: any) => void);
|
||||
|
||||
export interface ListOptions {
|
||||
active?: boolean;
|
||||
cursor?: string;
|
||||
limit?: number;
|
||||
}
|
||||
|
||||
export interface HistoryOptions extends ListOptions {
|
||||
modified_after?: number;
|
||||
}
|
||||
|
||||
export interface PushBulletStream {
|
||||
connect: () => void;
|
||||
close: () => void;
|
||||
on: ((event: 'connect' | 'close' | 'nop', callback: () => void) => void) & ((event: 'error', callback: (error: any) => void) => void) & ((event: 'message', callback: (message: any) => void) => void) & ((event: 'tickle', callback: (tickle: any) => void) => void) & ((event: 'push', callback: (push: any) => void) => void);
|
||||
}
|
||||
|
||||
export class PushBullet {
|
||||
constructor(apiKey: string, options?: {fullResponses: boolean}): this;
|
||||
me(callback: PushBulletCallback);
|
||||
devices(options: ListOptions, callback: PushBulletCallback);
|
||||
devices(callback: PushBulletCallback);
|
||||
createDevice(options: Record<string, any>, callback: PushBulletCallback);
|
||||
updateDevice(deviceIden: string, deviceOptions: Record<string, any>, callback: PushBulletCallback);
|
||||
deleteDevice(deviceIden: string, callback: PushBulletCallback);
|
||||
note(deviceParams: DeviceParams, title: string, body: string, callback: PushBulletCallback);
|
||||
link(deviceParams: DeviceParams, name: string, url: string, body: string, callback: PushBulletCallback);
|
||||
file(deviceParams: DeviceParams, filePath: string, message: string, callback: PushBulletCallback);
|
||||
dismissPush(pushIden: DeviceParams, callback: PushBulletCallback);
|
||||
deletePush(pushIden: DeviceParams, callback: PushBulletCallback);
|
||||
deleteAllPushes(callback: PushBulletCallback);
|
||||
history(options: HistoryOptions, callback: PushBulletCallback);
|
||||
history(callback: PushBulletCallback);
|
||||
subscriptions(options: ListOptions, callback: PushBulletCallback);
|
||||
subscriptions(callback: PushBulletCallback);
|
||||
subscribe(channelTag: string, callback: PushBulletCallback);
|
||||
unsubscribe(subscriptionIden: string, callback: PushBulletCallback);
|
||||
muteSubscription(subscriptionIden: string, callback: PushBulletCallback);
|
||||
unmuteSubscription(subscriptionIden: string, callback: PushBulletCallback);
|
||||
channelInfo(channelTag: string, callback: PushBulletCallback);
|
||||
chats(options: ListOptions, callback: PushBulletCallback);
|
||||
chats(callback: PushBulletCallback);
|
||||
createChat(email: string, callback: PushBulletCallback);
|
||||
deleteChat(chatIden: string, callback: PushBulletCallback);
|
||||
muteChat(chatIden: string, callback: PushBulletCallback);
|
||||
unmuteChat(chatIden: string, callback: PushBulletCallback);
|
||||
sendSMS(options: Record<string, any>, callback: PushBulletCallback);
|
||||
sendClipboard(options: Record<string, any>, callback: PushBulletCallback);
|
||||
dismissEphemeral(options: Record<string, any>, callback: PushBulletCallback);
|
||||
stream(): PushBulletStream;
|
||||
enableEncryption(encryptionPassword: string, userIden: string): PushBulletStream;
|
||||
}
|
||||
|
||||
export default PushBullet;
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user