mirror of
https://github.com/TheNetsky/Microsoft-Rewards-Script.git
synced 2026-01-11 02:46:17 +00:00
1.3.0
This commit is contained in:
@@ -11,6 +11,11 @@ Under development, however mainly for personal use!
|
||||
5. Run `npm run build` to build the script
|
||||
6. Run `npm run start` to start the built script
|
||||
|
||||
## Notes ##
|
||||
- If you end the script without closing the browser window first (only with headless as false), you'll be left with hanging chrome instances using resources. Use taskmanager to kill these or use the included `npm run chrome-kill` script. WINDOWS ONLY
|
||||
- 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.
|
||||
|
||||
|
||||
## Features ##
|
||||
- [x] Multi-Account Support
|
||||
- [x] Session Storing
|
||||
|
||||
13
package.json
13
package.json
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "microsoft-rewards-script",
|
||||
"version": "1.2.5",
|
||||
"version": "1.3.0",
|
||||
"description": "Automatically do tasks for Microsoft Rewards but in TS!",
|
||||
"main": "index.js",
|
||||
"engines": {
|
||||
@@ -10,7 +10,8 @@
|
||||
"build": "tsc",
|
||||
"start": "node ./dist/index.js",
|
||||
"ts-start": "ts-node ./src/index.ts",
|
||||
"dev": "ts-node ./src/index.ts -dev"
|
||||
"dev": "ts-node ./src/index.ts -dev",
|
||||
"kill-chrome-win": "powershell -Command \"Get-Process | Where-Object { $_.MainModule.FileVersionInfo.FileDescription -eq 'Google Chrome for Testing' } | ForEach-Object { Stop-Process -Id $_.Id -Force }\""
|
||||
},
|
||||
"keywords": [
|
||||
"Bing Rewards",
|
||||
@@ -30,11 +31,11 @@
|
||||
"typescript": "^5.2.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"axios": "^1.6.1",
|
||||
"axios": "^1.6.2",
|
||||
"cheerio": "^1.0.0-rc.12",
|
||||
"fingerprint-generator": "^2.1.43",
|
||||
"fingerprint-injector": "^2.1.43",
|
||||
"puppeteer": "^21.2.1",
|
||||
"fingerprint-generator": "^2.1.45",
|
||||
"fingerprint-injector": "^2.1.45",
|
||||
"puppeteer": "^21.5.2",
|
||||
"ts-node": "^10.9.1"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,10 @@ export default class BrowserFunc {
|
||||
try {
|
||||
const dashboardURL = new URL(this.bot.config.baseURL)
|
||||
|
||||
if (page.url() === dashboardURL.href) {
|
||||
return
|
||||
}
|
||||
|
||||
await page.goto(this.bot.config.baseURL)
|
||||
|
||||
const maxIterations = 5 // Maximum iterations set to 5
|
||||
|
||||
@@ -27,6 +27,11 @@ export class Workers {
|
||||
|
||||
await this.solveActivities(page, activitiesUncompleted)
|
||||
|
||||
page = await this.bot.browser.utils.getLatestTab(page)
|
||||
|
||||
// Always return to the homepage if not already
|
||||
await this.bot.browser.func.goHome(page)
|
||||
|
||||
this.bot.log('DAILY-SET', 'All "Daily Set" items have been completed')
|
||||
}
|
||||
|
||||
@@ -41,24 +46,31 @@ export class Workers {
|
||||
}
|
||||
|
||||
for (const punchCard of punchCardsUncompleted) {
|
||||
// Get latest page for each card
|
||||
page = await this.bot.browser.utils.getLatestTab(page)
|
||||
|
||||
const activitiesUncompleted = punchCard.childPromotions.filter(x => !x.complete) // Only return uncompleted activities
|
||||
|
||||
// Solve Activities
|
||||
this.bot.log('PUNCH-CARD', `Started solving "Punch Card" items for punchcard: "${punchCard.parentPromotion.title}"`)
|
||||
|
||||
const browser = page.browser()
|
||||
page = await browser.newPage()
|
||||
|
||||
// Got to punch card index page in a new tab
|
||||
await page.goto(punchCard.parentPromotion.destinationUrl, { referer: this.bot.config.baseURL })
|
||||
|
||||
// Wait for new page to load, max 10 seconds, however try regardless in case of error
|
||||
await page.waitForNetworkIdle({ timeout: 10_000 }).catch(() => { })
|
||||
await page.waitForNetworkIdle({ timeout: 5_000 }).catch(() => { })
|
||||
|
||||
await this.solveActivities(page, activitiesUncompleted, punchCard)
|
||||
|
||||
// Close the punch card index page
|
||||
page = await this.bot.browser.utils.getLatestTab(page)
|
||||
|
||||
const pages = await (page.browser()).pages()
|
||||
|
||||
if (pages.length > 3) {
|
||||
await page.close()
|
||||
} else {
|
||||
await this.bot.browser.func.goHome(page)
|
||||
}
|
||||
|
||||
this.bot.log('PUNCH-CARD', `All items for punchcard: "${punchCard.parentPromotion.title}" have been completed`)
|
||||
}
|
||||
@@ -85,39 +97,55 @@ export class Workers {
|
||||
// Solve Activities
|
||||
this.bot.log('MORE-PROMOTIONS', 'Started solving "More Promotions" item')
|
||||
|
||||
page = await this.bot.browser.utils.getLatestTab(page)
|
||||
|
||||
await this.solveActivities(page, activitiesUncompleted)
|
||||
|
||||
page = await this.bot.browser.utils.getLatestTab(page)
|
||||
|
||||
// Always return to the homepage if not already
|
||||
await this.bot.browser.func.goHome(page)
|
||||
|
||||
this.bot.log('MORE-PROMOTIONS', 'All "More Promotion" items have been completed')
|
||||
}
|
||||
|
||||
// Solve all the different types of activities
|
||||
private async solveActivities(page: Page, activities: PromotionalItem[] | MorePromotion[], punchCard?: PunchCard) {
|
||||
let activityPage = page
|
||||
private async solveActivities(activityPage: Page, activities: PromotionalItem[] | MorePromotion[], punchCard?: PunchCard) {
|
||||
const activityInitial = activityPage.url() // Homepage for Daily/More and Index for promotions
|
||||
|
||||
for (const activity of activities) {
|
||||
try {
|
||||
// Reselect the worker page
|
||||
activityPage = await this.bot.browser.utils.getLatestTab(activityPage)
|
||||
|
||||
const pages = await activityPage.browser().pages()
|
||||
if (pages.length > 3) {
|
||||
await activityPage.close()
|
||||
|
||||
activityPage = await this.bot.browser.utils.getLatestTab(activityPage)
|
||||
}
|
||||
|
||||
await this.bot.utils.wait(1000)
|
||||
|
||||
if (activityPage.url() !== activityInitial) {
|
||||
await activityPage.goto(activityInitial)
|
||||
}
|
||||
|
||||
|
||||
let selector = `[data-bi-id="${activity.offerId}"]`
|
||||
|
||||
if (punchCard) {
|
||||
selector = await this.bot.browser.func.getPunchCardActivity(page, activity)
|
||||
selector = await this.bot.browser.func.getPunchCardActivity(activityPage, activity)
|
||||
|
||||
} else if (activity.name.toLowerCase().includes('membercenter')) {
|
||||
|
||||
// Promotion
|
||||
if (activity.priority === 1) {
|
||||
selector = await page.waitForSelector('#promo-item', { visible: true, timeout: 2000 }).then(() => true).catch(() => false) ?
|
||||
'#promo-item' : activity.name
|
||||
} else {
|
||||
selector = `[data-bi-id="${activity.name}"]`
|
||||
}
|
||||
}
|
||||
|
||||
// Click element, it will be opened in a new tab
|
||||
await page.click(selector)
|
||||
await activityPage.click(selector)
|
||||
|
||||
// Select the new activity page
|
||||
activityPage = await this.bot.browser.utils.getLatestTab(page)
|
||||
activityPage = await this.bot.browser.utils.getLatestTab(activityPage)
|
||||
|
||||
// Wait for the new tab to fully load, ignore error.
|
||||
/*
|
||||
@@ -175,12 +203,8 @@ export class Workers {
|
||||
|
||||
} catch (error) {
|
||||
this.bot.log('ACTIVITY', 'An error occurred:' + error, 'error')
|
||||
const tabs = await (page.browser()).pages()
|
||||
}
|
||||
|
||||
if (tabs.length > 2) {
|
||||
await activityPage.close() // Already assigned to be the "latest tab"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ import axios from 'axios'
|
||||
|
||||
import { Workers } from '../Workers'
|
||||
|
||||
import { DashboardData, DashboardImpression } from '../../interface/DashboardData'
|
||||
import { Counters, DashboardData } from '../../interface/DashboardData'
|
||||
import { GoogleTrends } from '../../interface/GoogleDailyTrends'
|
||||
import { GoogleSearch } from '../../interface/Search'
|
||||
|
||||
@@ -15,21 +15,12 @@ export class Search extends Workers {
|
||||
public async doSearch(page: Page, data: DashboardData) {
|
||||
this.bot.log('SEARCH-BING', 'Starting bing searches')
|
||||
|
||||
let retries = 0
|
||||
while ((!data.userStatus.counters?.pcSearch || data.userStatus.counters.pcSearch.length < 2) && retries < 3) {
|
||||
data = await this.bot.browser.func.getDashboardData()
|
||||
retries++
|
||||
}
|
||||
page = await this.bot.browser.utils.getLatestTab(page)
|
||||
|
||||
const mobileData = data.userStatus.counters?.mobileSearch ? data.userStatus.counters.mobileSearch[0] : null // Mobile searches
|
||||
const edgeData = data.userStatus.counters.pcSearch[1] as DashboardImpression // Edge searches
|
||||
const genericData = data.userStatus.counters.pcSearch[0] as DashboardImpression // Normal searches
|
||||
let searchCounters: Counters = await this.bot.browser.func.getSearchPoints()
|
||||
let missingPoints = this.calculatePoints(searchCounters)
|
||||
|
||||
let missingPoints = (this.bot.isMobile && mobileData) ?
|
||||
(mobileData.pointProgressMax - mobileData.pointProgress) :
|
||||
(edgeData.pointProgressMax - edgeData.pointProgress) + (genericData.pointProgressMax - genericData.pointProgress)
|
||||
|
||||
if (missingPoints == 0) {
|
||||
if (missingPoints === 0) {
|
||||
this.bot.log('SEARCH-BING', `Bing searches for ${this.bot.isMobile ? 'MOBILE' : 'DESKTOP'} have already been completed`)
|
||||
return
|
||||
}
|
||||
@@ -41,7 +32,6 @@ export class Search extends Workers {
|
||||
// Deduplicate the search terms
|
||||
googleSearchQueries = [...new Set(googleSearchQueries)]
|
||||
|
||||
|
||||
// Go to bing
|
||||
await page.goto(this.searchPageURL)
|
||||
|
||||
@@ -57,25 +47,8 @@ export class Search extends Workers {
|
||||
|
||||
this.bot.log('SEARCH-BING', `${missingPoints} Points Remaining | Query: ${query} | Mobile: ${this.bot.isMobile}`)
|
||||
|
||||
let newData = await this.bingSearch(page, page, query)
|
||||
|
||||
let retries = 0
|
||||
while ((!newData?.pcSearch || newData.pcSearch.length < 2) && retries < 3) {
|
||||
newData = await this.bot.browser.func.getSearchPoints()
|
||||
retries++
|
||||
}
|
||||
|
||||
if (!newData?.pcSearch || newData.pcSearch.length < 2) {
|
||||
newData = await this.bot.browser.func.getSearchPoints()
|
||||
}
|
||||
|
||||
const newMobileData = newData.mobileSearch ? newData.mobileSearch[0] : null // Mobile searches
|
||||
const newEdgeData = newData.pcSearch[1] as DashboardImpression // Edge searches
|
||||
const newGenericData = newData.pcSearch[0] as DashboardImpression // Normal searches
|
||||
|
||||
const newMissingPoints = (this.bot.isMobile && newMobileData) ?
|
||||
(newMobileData.pointProgressMax - newMobileData.pointProgress) :
|
||||
(newEdgeData.pointProgressMax - newEdgeData.pointProgress) + (newGenericData.pointProgressMax - newGenericData.pointProgress)
|
||||
searchCounters = await this.bingSearch(page, query)
|
||||
const newMissingPoints = this.calculatePoints(searchCounters)
|
||||
|
||||
// If the new point amount is the same as before
|
||||
if (newMissingPoints == missingPoints) {
|
||||
@@ -86,7 +59,7 @@ export class Search extends Workers {
|
||||
|
||||
missingPoints = newMissingPoints
|
||||
|
||||
if (missingPoints == 0) {
|
||||
if (missingPoints === 0) {
|
||||
break
|
||||
}
|
||||
|
||||
@@ -113,21 +86,8 @@ 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}`)
|
||||
|
||||
let newData = await this.bingSearch(page, page, query.topic)
|
||||
|
||||
let retries = 0
|
||||
while ((!newData?.pcSearch || newData.pcSearch.length < 2) && retries < 3) {
|
||||
newData = await this.bot.browser.func.getSearchPoints()
|
||||
retries++
|
||||
}
|
||||
|
||||
const newMobileData = newData.mobileSearch ? newData.mobileSearch[0] : null // Mobile searches
|
||||
const newEdgeData = newData.pcSearch[1] as DashboardImpression // Edge searches
|
||||
const newGenericData = newData.pcSearch[0] as DashboardImpression // Normal searches
|
||||
|
||||
const newMissingPoints = (this.bot.isMobile && newMobileData) ?
|
||||
(newMobileData.pointProgressMax - newMobileData.pointProgress) :
|
||||
(newEdgeData.pointProgressMax - newEdgeData.pointProgress) + (newGenericData.pointProgressMax - newGenericData.pointProgress)
|
||||
searchCounters = await this.bingSearch(page, query.topic)
|
||||
const newMissingPoints = this.calculatePoints(searchCounters)
|
||||
|
||||
// If the new point amount is the same as before
|
||||
if (newMissingPoints == missingPoints) {
|
||||
@@ -139,7 +99,7 @@ export class Search extends Workers {
|
||||
missingPoints = newMissingPoints
|
||||
|
||||
// If we satisfied the searches
|
||||
if (missingPoints == 0) {
|
||||
if (missingPoints === 0) {
|
||||
break
|
||||
}
|
||||
|
||||
@@ -156,7 +116,7 @@ export class Search extends Workers {
|
||||
this.bot.log('SEARCH-BING', 'Completed searches')
|
||||
}
|
||||
|
||||
private async bingSearch(page: Page, searchPage: Page, query: string) {
|
||||
private async bingSearch(searchPage: Page, query: string) {
|
||||
// Try a max of 5 times
|
||||
for (let i = 0; i < 5; i++) {
|
||||
try {
|
||||
@@ -300,37 +260,18 @@ export class Search extends Workers {
|
||||
// Check if the URL is different from the original one, don't loop more than 5 times.
|
||||
let i = 0
|
||||
while (lastTabURL.href !== searchListingURL.href && i < 5) {
|
||||
// If hostname is still bing, (Bing images/news etc)
|
||||
if (lastTabURL.hostname === searchListingURL.hostname) {
|
||||
await lastTab.goBack()
|
||||
const browser = page.browser()
|
||||
const tabs = await browser.pages()
|
||||
|
||||
// Refresh
|
||||
lastTab = await this.bot.browser.utils.getLatestTab(page)
|
||||
lastTabURL = new URL(lastTab.url())
|
||||
|
||||
// If "goBack" didn't return to search listing (due to redirects)
|
||||
if (lastTabURL.hostname !== searchListingURL.hostname) {
|
||||
await lastTab.goto(this.searchPageURL)
|
||||
}
|
||||
|
||||
} else { // No longer on bing, likely opened a new tab, close this tab
|
||||
const tabs = await (page.browser()).pages()
|
||||
|
||||
// If the browser has more than 3 tabs open, it has opened a new one, we need to close this one.
|
||||
if (tabs.length > 3) {
|
||||
if (tabs.length === 4) {
|
||||
await lastTab.close()
|
||||
|
||||
} else if (lastTabURL.href !== searchListingURL.href) {
|
||||
await lastTab.goBack()
|
||||
// Refresh
|
||||
lastTab = await this.bot.browser.utils.getLatestTab(page)
|
||||
lastTabURL = new URL(lastTab.url())
|
||||
} else if (tabs.length === 2) {
|
||||
const newPage = await browser.newPage()
|
||||
await newPage.goto(searchListingURL.href)
|
||||
|
||||
// If "goBack" didn't return to search listing (due to redirects)
|
||||
if (lastTabURL.hostname !== searchListingURL.hostname) {
|
||||
await lastTab.goto(this.searchPageURL)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
await lastTab.goBack()
|
||||
}
|
||||
|
||||
// End of loop, refresh lastPage
|
||||
@@ -344,4 +285,16 @@ export class Search extends Workers {
|
||||
}
|
||||
}
|
||||
|
||||
private calculatePoints(counters: Counters) {
|
||||
const mobileData = counters.mobileSearch?.[0] // Mobile searches
|
||||
const genericData = counters.pcSearch?.[0] // Normal searches
|
||||
const edgeData = counters.pcSearch?.[1] // Edge searches
|
||||
|
||||
const missingPoints = (this.bot.isMobile && mobileData)
|
||||
? mobileData.pointProgressMax - mobileData.pointProgress
|
||||
: (edgeData ? edgeData.pointProgressMax - edgeData.pointProgress : 0)
|
||||
+ (genericData ? genericData.pointProgressMax - genericData.pointProgress : 0)
|
||||
|
||||
return missingPoints
|
||||
}
|
||||
}
|
||||
@@ -9,7 +9,8 @@ export class UrlReward extends Workers {
|
||||
this.bot.log('URL-REWARD', 'Trying to complete UrlReward')
|
||||
|
||||
try {
|
||||
// After waiting, close the page
|
||||
this.bot.utils.wait(2000)
|
||||
|
||||
await page.close()
|
||||
|
||||
this.bot.log('URL-REWARD', 'Completed the UrlReward successfully')
|
||||
|
||||
14
src/index.ts
14
src/index.ts
@@ -230,6 +230,20 @@ export class MicrosoftRewardsBot {
|
||||
// Do mobile searches
|
||||
if (this.config.workers.doMobileSearch) {
|
||||
await this.activities.doSearch(workerPage, data)
|
||||
|
||||
// Fetch current search points
|
||||
const mobileSearchPoints = (await this.browser.func.getSearchPoints()).mobileSearch?.[0]
|
||||
|
||||
// If the remaining mobile points does not equal 0, restart and assume the generated UA is invalid
|
||||
if (mobileSearchPoints && ((mobileSearchPoints.pointProgressMax - mobileSearchPoints.pointProgress) > 0)) {
|
||||
log('MAIN', 'Unable to complete mobile searches, bad User-Agent?, retrying...')
|
||||
|
||||
// Close mobile browser
|
||||
await browser.close()
|
||||
|
||||
// Retry
|
||||
await this.Mobile(account)
|
||||
}
|
||||
}
|
||||
|
||||
// Fetch new points
|
||||
|
||||
Reference in New Issue
Block a user