mirror of
https://github.com/TheNetsky/Microsoft-Rewards-Script.git
synced 2026-01-12 03:16:19 +00:00
Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ce2a72ee36 | ||
|
|
755237caa1 | ||
|
|
2b4cd505c0 | ||
|
|
a39a861dab | ||
|
|
8d19129906 |
@@ -28,6 +28,10 @@ module.exports = {
|
||||
'error',
|
||||
'never'
|
||||
],
|
||||
'@typescript-eslint/no-explicit-any':
|
||||
['warn', {
|
||||
fixToUnknown: true // This line is optional and only relevant if you are using TypeScript
|
||||
}],
|
||||
'comma-dangle': 'off',
|
||||
'@typescript-eslint/comma-dangle': 'error',
|
||||
'prefer-arrow-callback': 'error'
|
||||
|
||||
@@ -37,4 +37,4 @@ COPY src/crontab.template /etc/cron.d/microsoft-rewards-cron.template
|
||||
RUN touch /var/log/cron.log
|
||||
|
||||
# Define the command to run your application with cron optionally
|
||||
CMD sh -c 'echo "$TZ" > /etc/timezone && dpkg-reconfigure -f noninteractive tzdata && if [ "$RUN_ON_START" = "true" ]; then npm start; fi && envsubst < /etc/cron.d/microsoft-rewards-cron.template > /etc/cron.d/microsoft-rewards-cron && crontab /etc/cron.d/microsoft-rewards-cron && cron && tail -f /var/log/cron.log'
|
||||
CMD sh -c 'node src/updateConfig.js && echo "$TZ" > /etc/timezone && dpkg-reconfigure -f noninteractive tzdata && if [ "$RUN_ON_START" = "true" ]; then npm start; fi && envsubst < /etc/cron.d/microsoft-rewards-cron.template > /etc/cron.d/microsoft-rewards-cron && crontab /etc/cron.d/microsoft-rewards-cron && cron && tail -f /var/log/cron.log'
|
||||
|
||||
40
README.md
40
README.md
@@ -16,11 +16,14 @@ Under development, however mainly for personal use!
|
||||
- If you automate this script, set it to run at least 2 times a day to make sure it picked up all tasks, set `"runOnZeroPoints": false` so it doesn't run when no points are found.
|
||||
|
||||
## Docker (Experimental) ##
|
||||
**Note:** If you had previously built and run the script locally, remove the `/node_modules` and `/dist` from your Microsoft-Rewards-Script folder.
|
||||
|
||||
1. Download the source code
|
||||
2. Make changes to your `accounts.json`
|
||||
3. **Headless mode must be enabled when using Docker.** You can do this using the `HEADLESS=true` environmental variable in docker run or docker compose.yaml (see below). Environmental variables are always prioritized over the values in config.json.
|
||||
4. The container will run scheduled. Customize your schedule using the `CRON_START_TIME` environmental variable. Use [crontab.guru](crontab.guru) if you're unsure how to create a cron schedule.
|
||||
2. Make changes to your `accounts.json` and `config.json`
|
||||
3. **Headless mode must be enabled.** You can do this in `config.json` or by using the `HEADLESS=true` environmental variable in docker run or docker compose.yaml (see below). Environmental variables are prioritized over the values in config.json.
|
||||
4. The container has in-built scheduling. Customize your schedule using the `CRON_START_TIME` environmental variable. Use [crontab.guru](crontab.guru) if you're unsure how to create a cron schedule.
|
||||
5. **Note:** the container will add between 5 and 50 minutes of randomized variability to your scheduled start times.
|
||||
|
||||
### Option 1: build and run with docker run
|
||||
|
||||
1. Build or re-build the container image with: `docker build -t microsoft-rewards-script-docker .`
|
||||
@@ -31,14 +34,12 @@ Under development, however mainly for personal use!
|
||||
docker run --name netsky -d \
|
||||
-e TZ=America/New_York \
|
||||
-e HEADLESS=true \
|
||||
-e SEARCH_DELAY_MIN=10000 \
|
||||
-e SEARCH_DELAY_MAX=20000 \
|
||||
-e CLUSTERS=1 \
|
||||
-e RUN_ON_START=true \
|
||||
-e CRON_START_TIME="0 5,11 * * *" \
|
||||
microsoft-rewards-script-docker
|
||||
```
|
||||
|
||||
3. Optionally, change any environmental variables other than `HEADLESS`, which must stay `=true`
|
||||
|
||||
3. Optionally, customize your config by adding any other environmental variables from the table below.
|
||||
|
||||
4. You can view logs with `docker logs netsky`.
|
||||
|
||||
@@ -46,9 +47,9 @@ Under development, however mainly for personal use!
|
||||
|
||||
1. A basic docker compose.yaml has been provided.
|
||||
|
||||
2. Optionally, change any environmental variables other than `HEADLESS`, which must stay `=true`
|
||||
2. Optionally, customize your config by adding any other environmental variables from the table below.
|
||||
|
||||
3. Build or rebuild and start the container using `docker compose up -d --build`
|
||||
3. Build and start the container using `docker compose up -d`.
|
||||
|
||||
4. You can view logs with `docker logs netsky`
|
||||
|
||||
@@ -62,17 +63,17 @@ Under development, however mainly for personal use!
|
||||
| runOnZeroPoints | Run the rest of the script if 0 points can be earned | `false` (Will not run on 0 points) | RUN_ON_ZERO_POINTS |
|
||||
| clusters | Amount of instances ran on launch, 1 per account | `1` (Will run 1 account at the time) | CLUSTERS |
|
||||
| saveFingerprint | Re-use the same fingerprint each time | `false` (Will generate a new fingerprint each time) | SAVE_FINGERPRINT |
|
||||
| workers.doDailySet | Complete daily set items | `true` | WORKERS_DO_DAILY_SET |
|
||||
| workers.doMorePromotions | Complete promotional items | `true` | WORKERS_DO_MORE_PROMOTIONS |
|
||||
| workers.doPunchCards | Complete punchcards | `true` | WORKERS_DO_PUNCH_CARDS |
|
||||
| workers.doDesktopSearch | Complete daily desktop searches | `true` | WORKERS_DO_DESKTOP_SEARCH |
|
||||
| workers.doMobileSearch | Complete daily mobile searches | `true` | WORKERS_DO_MOBILE_SEARCH |
|
||||
| workers.doDailySet | Complete daily set items | `true` | DO_DAILY_SET |
|
||||
| workers.doMorePromotions | Complete promotional items | `true` | DO_MORE_PROMOTIONS |
|
||||
| workers.doPunchCards | Complete punchcards | `true` | DO_PUNCH_CARDS |
|
||||
| workers.doDesktopSearch | Complete daily desktop searches | `true` | DO_DESKTOP_SEARCH |
|
||||
| workers.doMobileSearch | Complete daily mobile searches | `true` | DO_MOBILE_SEARCH |
|
||||
| globalTimeout | The length before the action gets timeout | `30000` (30 seconds) | GLOBAL_TIMEOUT |
|
||||
| searchSettings.useGeoLocaleQueries | Generate search queries based on your geo-location | `false` (Uses EN-US generated queries) | SEARCH_SETTINGS_USE_GEO_LOCALE_QUERIES |
|
||||
| scrollRandomResults | Scroll randomly in search results | `true` | SEARCH_SETTINGS_SCROLL_RANDOM_RESULTS |
|
||||
| searchSettings.clickRandomResults | Visit random website from search result| `true` | SEARCH_SETTINGS_CLICK_RANDOM_RESULTS |
|
||||
| searchSettings.useGeoLocaleQueries | Generate search queries based on your geo-location | `false` (Uses EN-US generated queries) | USE_GEO_LOCALE_QUERIES |
|
||||
| scrollRandomResults | Scroll randomly in search results | `true` | SCROLL_RANDOM_RESULTS |
|
||||
| searchSettings.clickRandomResults | Visit random website from search result| `true` | CLICK_RANDOM_RESULTS |
|
||||
| searchSettings.searchDelay | Minimum and maximum time in miliseconds between search queries | `min: 10000` (10 seconds) `max: 20000` (20 seconds) | SEARCH_DELAY_MIN SEARCH_DELAY_MAX |
|
||||
| searchSettings.retryMobileSearch | Keep retrying mobile searches until completed (indefinite)| `false` | SEARCH_SETTINGS_RETRY_MOBILE_SEARCH |
|
||||
| searchSettings.retryMobileSearch | Keep retrying mobile searches until completed (indefinite)| `false` | RETRY_MOBILE_SEARCH |
|
||||
| webhook.enabled | Enable or disable your set webhook | `false` | WEBHOOK_ENABLED |
|
||||
| webhook.url | Your Discord webhook URL | `null` | WEBHOOK_URL="" |
|
||||
| cronStartTime | Scheduled script run-time, *only available for docker implementation* | `0 5,11 * * *` (5:00 am, 11:00 am daily) | CRON_START_TIME="" |
|
||||
@@ -82,6 +83,7 @@ Under development, however mainly for personal use!
|
||||
- [x] Multi-Account Support
|
||||
- [x] Session Storing
|
||||
- [x] 2FA Support
|
||||
- [x] Passwordless Support
|
||||
- [x] Headless Support
|
||||
- [x] Discord Webhook Support
|
||||
- [x] Desktop Searches
|
||||
|
||||
27
compose.yaml
27
compose.yaml
@@ -6,29 +6,8 @@ services:
|
||||
- TZ=America/Toronto #change to your local timezone
|
||||
- NODE_ENV=production
|
||||
- HEADLESS=true #do not change
|
||||
### the following are optional, you only need to include them if you want to enter a custom value, removing them will use the default values
|
||||
- BASE_URL=https://rewards.bing.com
|
||||
- SESSION_PATH=sessions
|
||||
- RUN_ON_ZERO_POINTS=false
|
||||
- CLUSTERS=1
|
||||
- SAVE_FINGERPRINT=false
|
||||
- WORKERS_DO_DAILY_SET=true
|
||||
- WORKERS_DO_MORE_PROMOTIONS=true
|
||||
- WORKERS_DO_PUNCH_CARDS=true
|
||||
- WORKERS_DO_DESKTOP_SEARCH=true
|
||||
- WORKERS_DO_MOBILE_SEARCH=true
|
||||
- SEARCH_SETTINGS_USE_GEO_LOCALE_QUERIES=false
|
||||
- SEARCH_SETTINGS_SCROLL_RANDOM_RESULTS=true
|
||||
- SEARCH_SETTINGS_CLICK_RANDOM_RESULTS=true
|
||||
- SEARCH_SETTINGS_SEARCH_DELAY_MIN=10000 # Set the search delay longer, e.g. MIN=180000 and MAX=270000 if you live in a region where MS enforces a search cooldown
|
||||
- SEARCH_SETTINGS_SEARCH_DELAY_MAX=20000
|
||||
- SEARCH_SETTINGS_RETRY_MOBILE_SEARCH=true
|
||||
- WEBHOOK_ENABLED=false
|
||||
- WEBHOOK_URL=
|
||||
### Customize your run schedule, default 5:00 am and 11:00 am, use crontab.guru if you're not sure
|
||||
### Customize your run schedule, default 5:00 am and 11:00 am, use crontab.guru for formatting
|
||||
- CRON_START_TIME=0 5,11 * * *
|
||||
### Run on start, set as false to only run the script per the cron schedule
|
||||
### Run on start, set to false to only run the script per the cron schedule
|
||||
- RUN_ON_START=true
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
- .:/usr/src/microsoft-rewards-script
|
||||
restart: unless-stopped
|
||||
16
package.json
16
package.json
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "microsoft-rewards-script",
|
||||
"version": "1.4.7",
|
||||
"version": "1.4.8",
|
||||
"description": "Automatically do tasks for Microsoft Rewards but in TS!",
|
||||
"main": "index.js",
|
||||
"engines": {
|
||||
@@ -26,17 +26,17 @@
|
||||
"author": "Netsky",
|
||||
"license": "ISC",
|
||||
"devDependencies": {
|
||||
"@typescript-eslint/eslint-plugin": "^7.11.0",
|
||||
"@typescript-eslint/eslint-plugin": "^7.17.0",
|
||||
"eslint": "^8.57.0",
|
||||
"eslint-plugin-modules-newline": "^0.0.6",
|
||||
"typescript": "^5.4.5"
|
||||
"typescript": "^5.5.4"
|
||||
},
|
||||
"dependencies": {
|
||||
"axios": "^1.7.2",
|
||||
"cheerio": "^1.0.0-rc.12",
|
||||
"fingerprint-generator": "^2.1.51",
|
||||
"fingerprint-injector": "^2.1.51",
|
||||
"playwright": "^1.44.1",
|
||||
"axios": "^1.7.4",
|
||||
"cheerio": "^1.0.0",
|
||||
"fingerprint-generator": "^2.1.54",
|
||||
"fingerprint-injector": "^2.1.54",
|
||||
"playwright": "^1.46.1",
|
||||
"ts-node": "^10.9.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -158,7 +158,7 @@ export default class BrowserFunc {
|
||||
if (data.morePromotions?.length) {
|
||||
data.morePromotions.forEach(x => {
|
||||
// Only count points from supported activities
|
||||
if (['quiz', 'urlreward'].includes(x.promotionType)) {
|
||||
if (['quiz', 'urlreward'].includes(x.promotionType) && !x.attributes.is_unlocked) {
|
||||
totalEarnablePoints += (x.pointProgressMax - x.pointProgress)
|
||||
}
|
||||
})
|
||||
|
||||
@@ -1 +1 @@
|
||||
${CRON_START_TIME} /bin/bash /usr/src/microsoft-rewards-script/src/run_daily.sh >> /var/log/cron.log 2>&1
|
||||
${CRON_START_TIME} TZ=${TZ} /bin/bash /usr/src/microsoft-rewards-script/src/run_daily.sh >> /var/log/cron.log 2>&1
|
||||
|
||||
@@ -56,51 +56,110 @@ export class Login {
|
||||
|
||||
private async execLogin(page: Page, email: string, password: string) {
|
||||
try {
|
||||
// Enter email
|
||||
await page.fill('#i0116', email)
|
||||
await page.click('#idSIButton9')
|
||||
|
||||
this.bot.log('LOGIN', 'Email entered successfully')
|
||||
|
||||
try {
|
||||
// Enter password
|
||||
await page.waitForSelector('#i0118', { state: 'visible', timeout: 2000 })
|
||||
await this.bot.utils.wait(2000)
|
||||
|
||||
await page.fill('#i0118', password)
|
||||
await page.click('#idSIButton9')
|
||||
|
||||
// When erroring at this stage it means a 2FA code is required
|
||||
} catch (error) {
|
||||
this.bot.log('LOGIN', '2FA code required')
|
||||
|
||||
// Wait for user input
|
||||
const code = await new Promise<string>((resolve) => {
|
||||
rl.question('Enter 2FA code:\n', (input) => {
|
||||
rl.close()
|
||||
resolve(input)
|
||||
})
|
||||
})
|
||||
|
||||
await page.fill('input[name="otc"]', code)
|
||||
await page.keyboard.press('Enter')
|
||||
}
|
||||
|
||||
this.bot.log('LOGIN', 'Password entered successfully')
|
||||
|
||||
} catch (error) {
|
||||
this.bot.log('LOGIN', 'An error occurred:' + error, 'error')
|
||||
await this.enterEmail(page, email)
|
||||
await this.enterPassword(page, password)
|
||||
await this.checkLoggedIn(page)
|
||||
} catch (error: any) {
|
||||
this.bot.log('LOGIN', 'An error occurred: ' + error.message, 'error')
|
||||
}
|
||||
}
|
||||
|
||||
const currentURL = new URL(page.url())
|
||||
private async enterEmail(page: Page, email: string) {
|
||||
await page.fill('#i0116', email)
|
||||
await page.click('#idSIButton9')
|
||||
this.bot.log('LOGIN', 'Email entered successfully')
|
||||
}
|
||||
|
||||
while (currentURL.pathname !== '/' || currentURL.hostname !== 'rewards.bing.com') {
|
||||
private async enterPassword(page: Page, password: string) {
|
||||
try {
|
||||
await page.waitForSelector('#i0118', { state: 'visible', timeout: 2000 })
|
||||
await this.bot.utils.wait(2000)
|
||||
await page.fill('#i0118', password)
|
||||
await page.click('#idSIButton9')
|
||||
this.bot.log('LOGIN', 'Password entered successfully')
|
||||
} catch {
|
||||
this.bot.log('LOGIN', 'Password entry failed or 2FA required')
|
||||
await this.handle2FA(page)
|
||||
}
|
||||
}
|
||||
|
||||
private async handle2FA(page: Page) {
|
||||
try {
|
||||
const numberToPress = await this.get2FACode(page)
|
||||
if (numberToPress) {
|
||||
// Authentictor App verification
|
||||
await this.authAppVerification(page, numberToPress)
|
||||
} else {
|
||||
// SMS verification
|
||||
await this.authSMSVerification(page)
|
||||
}
|
||||
} catch (error: any) {
|
||||
this.bot.log('LOGIN', `2FA handling failed: ${error.message}`)
|
||||
}
|
||||
}
|
||||
|
||||
private async get2FACode(page: Page): Promise<string | null> {
|
||||
try {
|
||||
const element = await page.waitForSelector('#displaySign', { state: 'visible', timeout: 2000 })
|
||||
return await element.textContent()
|
||||
} catch {
|
||||
await page.click('button[aria-describedby="confirmSendTitle"]')
|
||||
await this.bot.utils.wait(2000)
|
||||
const element = await page.waitForSelector('#displaySign', { state: 'visible', timeout: 2000 })
|
||||
return await element.textContent()
|
||||
}
|
||||
}
|
||||
|
||||
private async authAppVerification(page: Page, numberToPress: string | null) {
|
||||
// eslint-disable-next-line no-constant-condition
|
||||
while (true) {
|
||||
try {
|
||||
this.bot.log('LOGIN', `Press the number ${numberToPress} on your Authenticator app to approve the login`)
|
||||
this.bot.log('LOGIN', 'If you press the wrong number or the "DENY" button, try again in 60 seconds')
|
||||
|
||||
await page.waitForSelector('#i0281', { state: 'detached', timeout: 60000 })
|
||||
|
||||
this.bot.log('LOGIN', 'Login successfully approved!')
|
||||
break
|
||||
} catch {
|
||||
this.bot.log('LOGIN', 'The code is expired. Trying to get a new code...')
|
||||
await page.click('button[aria-describedby="pushNotificationsTitle errorDescription"]')
|
||||
numberToPress = await this.get2FACode(page)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async authSMSVerification(page: Page) {
|
||||
this.bot.log('LOGIN', 'SMS 2FA code required. Waiting for user input...')
|
||||
|
||||
const code = await new Promise<string>((resolve) => {
|
||||
rl.question('Enter 2FA code:\n', (input) => {
|
||||
rl.close()
|
||||
resolve(input)
|
||||
})
|
||||
})
|
||||
|
||||
await page.fill('input[name="otc"]', code)
|
||||
await page.keyboard.press('Enter')
|
||||
this.bot.log('LOGIN', '2FA code entered successfully')
|
||||
}
|
||||
|
||||
private async checkLoggedIn(page: Page) {
|
||||
const targetHostname = 'rewards.bing.com'
|
||||
const targetPathname = '/'
|
||||
|
||||
// eslint-disable-next-line no-constant-condition
|
||||
while (true) {
|
||||
await this.bot.browser.utils.tryDismissAllMessages(page)
|
||||
currentURL.href = page.url()
|
||||
const currentURL = new URL(page.url())
|
||||
if (currentURL.hostname === targetHostname && currentURL.pathname === targetPathname) {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// Wait for login to complete
|
||||
await page.waitForSelector('html[data-role-name="RewardsPortal"]', { timeout: 10_000 })
|
||||
this.bot.log('LOGIN', 'Successfully logged into the rewards portal')
|
||||
}
|
||||
|
||||
private async checkBingLogin(page: Page): Promise<void> {
|
||||
|
||||
@@ -87,7 +87,7 @@ export class Workers {
|
||||
morePromotions.push(data.promotionalItem as unknown as MorePromotion)
|
||||
}
|
||||
|
||||
const activitiesUncompleted = morePromotions?.filter(x => !x.complete && x.pointProgressMax > 0) ?? []
|
||||
const activitiesUncompleted = morePromotions?.filter(x => !x.complete && x.pointProgressMax > 0 && !x.attributes.is_unlocked) ?? []
|
||||
|
||||
if (!activitiesUncompleted.length) {
|
||||
this.bot.log('MORE-PROMOTIONS', 'All "More Promotion" items have already been completed')
|
||||
@@ -132,13 +132,13 @@ export class Workers {
|
||||
}
|
||||
|
||||
|
||||
let selector = `[data-bi-id="${activity.offerId}"]`
|
||||
let selector = `[data-bi-id^="${activity.offerId}"]`
|
||||
|
||||
if (punchCard) {
|
||||
selector = await this.bot.browser.func.getPunchCardActivity(activityPage, activity)
|
||||
|
||||
} else if (activity.name.toLowerCase().includes('membercenter')) {
|
||||
selector = `[data-bi-id="${activity.name}"]`
|
||||
selector = `[data-bi-id^="${activity.name}"]`
|
||||
}
|
||||
|
||||
// Click element, it will be opened in a new tab
|
||||
@@ -149,7 +149,7 @@ export class Workers {
|
||||
|
||||
// Wait for the new tab to fully load, ignore error.
|
||||
/*
|
||||
Due to common false timeout on this function, we're ignoring the error regardless, if it worked then it's faster,
|
||||
Due to common false timeout on this function, we're ignoring the error regardless, if it worked then it's faster,
|
||||
if it didn't then it gave enough time for the page to load.
|
||||
*/
|
||||
await activityPage.waitForLoadState('networkidle', { timeout: 10_000 }).catch(() => { })
|
||||
|
||||
@@ -42,6 +42,8 @@ export class Search extends Workers {
|
||||
// Mobile search doesn't seem to like related queries?
|
||||
googleSearchQueries.forEach(x => { this.bot.isMobile ? queries.push(x.topic) : queries.push(x.topic, ...x.related) })
|
||||
|
||||
await this.bot.browser.utils.tryDismissBingCookieBanner(page)
|
||||
|
||||
// Loop over Google search queries
|
||||
for (let i = 0; i < queries.length; i++) {
|
||||
const query = queries[i] as string
|
||||
@@ -98,7 +100,7 @@ export class Search extends Workers {
|
||||
for (const term of relatedTerms.slice(1, 3)) {
|
||||
this.bot.log('SEARCH-BING-EXTRA', `${missingPoints} Points Remaining | Query: ${term} | Mobile: ${this.bot.isMobile}`)
|
||||
|
||||
searchCounters = await this.bingSearch(page, query.topic)
|
||||
searchCounters = await this.bingSearch(page, term)
|
||||
const newMissingPoints = this.calculatePoints(searchCounters)
|
||||
|
||||
// If the new point amount is the same as before
|
||||
@@ -334,4 +336,4 @@ export class Search extends Workers {
|
||||
|
||||
return missingPoints
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,9 @@
|
||||
# Set up environment variables
|
||||
export PATH=$PATH:/usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/usr/sbin:/sbin
|
||||
|
||||
# Ensure TZ is set
|
||||
export TZ=${TZ}
|
||||
|
||||
# Change directory to the application directory
|
||||
cd /usr/src/microsoft-rewards-script
|
||||
|
||||
|
||||
41
src/updateConfig.js
Executable file
41
src/updateConfig.js
Executable file
@@ -0,0 +1,41 @@
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const configPath = path.join(__dirname, '../dist/config.json');
|
||||
|
||||
// Read the existing config file
|
||||
const config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
|
||||
|
||||
// Update the config with environment variables if they are set
|
||||
config.baseURL = process.env.BASE_URL || config.baseURL;
|
||||
config.sessionPath = process.env.SESSION_PATH || config.sessionPath;
|
||||
config.headless = process.env.HEADLESS ? process.env.HEADLESS === 'true' : config.headless;
|
||||
config.runOnZeroPoints = process.env.RUN_ON_ZERO_POINTS ? process.env.RUN_ON_ZERO_POINTS === 'true' : config.runOnZeroPoints;
|
||||
config.clusters = process.env.CLUSTERS ? parseInt(process.env.CLUSTERS, 10) : config.clusters;
|
||||
config.saveFingerprint = process.env.SAVE_FINGERPRINT ? process.env.SAVE_FINGERPRINT === 'true' : config.saveFingerprint;
|
||||
config.globalTimeout = process.env.GLOBAL_TIMEOUT ? parseInt(process.env.GLOBAL_TIMEOUT, 10) : config.globalTimeout;
|
||||
|
||||
config.workers.doDailySet = process.env.DO_DAILY_SET ? process.env.DO_DAILY_SET === 'true' : config.workers.doDailySet;
|
||||
config.workers.doMorePromotions = process.env.DO_MORE_PROMOTIONS ? process.env.DO_MORE_PROMOTIONS === 'true' : config.workers.doMorePromotions;
|
||||
config.workers.doPunchCards = process.env.DO_PUNCH_CARDS ? process.env.DO_PUNCH_CARDS === 'true' : config.workers.doPunchCards;
|
||||
config.workers.doDesktopSearch = process.env.DO_DESKTOP_SEARCH ? process.env.DO_DESKTOP_SEARCH === 'true' : config.workers.doDesktopSearch;
|
||||
config.workers.doMobileSearch = process.env.DO_MOBILE_SEARCH ? process.env.DO_MOBILE_SEARCH === 'true' : config.workers.doMobileSearch;
|
||||
|
||||
config.searchSettings.useGeoLocaleQueries = process.env.USE_GEO_LOCALE_QUERIES ? process.env.USE_GEO_LOCALE_QUERIES === 'true' : config.searchSettings.useGeoLocaleQueries;
|
||||
config.searchSettings.scrollRandomResults = process.env.SCROLL_RANDOM_RESULTS ? process.env.SCROLL_RANDOM_RESULTS === 'true' : config.searchSettings.scrollRandomResults;
|
||||
config.searchSettings.clickRandomResults = process.env.CLICK_RANDOM_RESULTS ? process.env.CLICK_RANDOM_RESULTS === 'true' : config.searchSettings.clickRandomResults;
|
||||
config.searchSettings.searchDelay.min = process.env.SEARCH_DELAY_MIN ? parseInt(process.env.SEARCH_DELAY_MIN, 10) : config.searchSettings.searchDelay.min;
|
||||
config.searchSettings.searchDelay.max = process.env.SEARCH_DELAY_MAX ? parseInt(process.env.SEARCH_DELAY_MAX, 10) : config.searchSettings.searchDelay.max;
|
||||
config.searchSettings.retryMobileSearch = process.env.RETRY_MOBILE_SEARCH ? process.env.RETRY_MOBILE_SEARCH === 'true' : config.searchSettings.retryMobileSearch;
|
||||
|
||||
config.webhook.enabled = process.env.WEBHOOK_ENABLED ? process.env.WEBHOOK_ENABLED === 'true' : config.webhook.enabled;
|
||||
config.webhook.url = process.env.WEBHOOK_URL || config.webhook.url;
|
||||
|
||||
// Write the updated config back to the file
|
||||
try {
|
||||
fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
|
||||
console.log('Config file updated with environment variables');
|
||||
} catch (error) {
|
||||
console.error(`Failed to write updated config file to ${configPath}:`, error);
|
||||
process.exit(1);
|
||||
}
|
||||
Reference in New Issue
Block a user