Skip to content

Commit

Permalink
1.3.0
Browse files Browse the repository at this point in the history
  • Loading branch information
TheNetsky committed Dec 1, 2023
1 parent 28286ff commit a8cb548
Show file tree
Hide file tree
Showing 7 changed files with 113 additions and 111 deletions.
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
13 changes: 7 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
@@ -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": {
Expand All @@ -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",
Expand All @@ -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"
}
}
4 changes: 4 additions & 0 deletions src/browser/BrowserFunc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
72 changes: 48 additions & 24 deletions src/functions/Workers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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')
}

Expand All @@ -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
await page.close()
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`)
}
Expand All @@ -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}"]`
}
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.
/*
Expand Down Expand Up @@ -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"
}
}

}
}

Expand Down
113 changes: 33 additions & 80 deletions src/functions/activities/Search.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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'

Expand All @@ -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++
}

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
page = await this.bot.browser.utils.getLatestTab(page)

let missingPoints = (this.bot.isMobile && mobileData) ?
(mobileData.pointProgressMax - mobileData.pointProgress) :
(edgeData.pointProgressMax - edgeData.pointProgress) + (genericData.pointProgressMax - genericData.pointProgress)
let searchCounters: Counters = await this.bot.browser.func.getSearchPoints()
let missingPoints = this.calculatePoints(searchCounters)

if (missingPoints == 0) {
if (missingPoints === 0) {
this.bot.log('SEARCH-BING', `Bing searches for ${this.bot.isMobile ? 'MOBILE' : 'DESKTOP'} have already been completed`)
return
}
Expand All @@ -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)

Expand All @@ -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) {
Expand All @@ -86,7 +59,7 @@ export class Search extends Workers {

missingPoints = newMissingPoints

if (missingPoints == 0) {
if (missingPoints === 0) {
break
}

Expand All @@ -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) {
Expand All @@ -139,7 +99,7 @@ export class Search extends Workers {
missingPoints = newMissingPoints

// If we satisfied the searches
if (missingPoints == 0) {
if (missingPoints === 0) {
break
}

Expand All @@ -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 {
Expand Down Expand Up @@ -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()

// 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()
const browser = page.browser()
const tabs = await 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) {
await lastTab.close()
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
Expand All @@ -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
}
}
3 changes: 2 additions & 1 deletion src/functions/activities/UrlReward.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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')
Expand Down
Loading

0 comments on commit a8cb548

Please sign in to comment.