mirror of
https://github.com/TheNetsky/Microsoft-Rewards-Script.git
synced 2026-01-20 06:53:59 +00:00
Support new quest to get points (#138)
* support passwordless auth (using Authenticator app) * update readme * feat: added mobile app tasks (daily check in + read to earn) * fix some stuff * make ReadToEarn use the delay config * fix daily reward search per week * reorder mobile tasks * fix message * Search fixes, reformatting and types --------- Co-authored-by: TheNetsky <56271887+TheNetsky@users.noreply.github.com>
This commit is contained in:
48
src/functions/activities/DailyCheckIn.ts
Normal file
48
src/functions/activities/DailyCheckIn.ts
Normal file
@@ -0,0 +1,48 @@
|
||||
import axios from 'axios'
|
||||
import { randomBytes } from 'crypto'
|
||||
|
||||
import { Workers } from '../Workers'
|
||||
|
||||
import { DashboardData } from '../../interface/DashboardData'
|
||||
|
||||
|
||||
export class DailyCheckIn extends Workers {
|
||||
public async doDailyCheckIn(accessToken: string, data: DashboardData) {
|
||||
this.bot.log('DAILY-CHECK-IN', 'Starting Daily Check In')
|
||||
|
||||
try {
|
||||
let geoLocale = data.userProfile.attributes.country
|
||||
geoLocale = (this.bot.config.searchSettings.useGeoLocaleQueries && geoLocale.length === 2) ? geoLocale.toLowerCase() : 'us'
|
||||
|
||||
const jsonData = {
|
||||
amount: 1,
|
||||
country: geoLocale,
|
||||
id: randomBytes(64).toString('hex'),
|
||||
type: 101,
|
||||
attributes: {
|
||||
offerid: 'Gamification_Sapphire_DailyCheckIn'
|
||||
}
|
||||
}
|
||||
|
||||
const claimRequest = {
|
||||
url: 'https://prod.rewardsplatform.microsoft.com/dapi/me/activities',
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Authorization': `Bearer ${accessToken}`,
|
||||
'Content-Type': 'application/json',
|
||||
'X-Rewards-Country': geoLocale,
|
||||
'X-Rewards-Language': 'en'
|
||||
},
|
||||
data: JSON.stringify(jsonData)
|
||||
}
|
||||
|
||||
const claimResponse = await axios(claimRequest)
|
||||
const claimedPoint = parseInt((await claimResponse.data).response.activity.p)
|
||||
|
||||
this.bot.log('DAILY-CHECK-IN', claimedPoint > 0 ? `Claimed ${claimedPoint} points` : 'Already claimed today')
|
||||
} catch (error) {
|
||||
this.bot.log('DAILY-CHECK-IN', 'An error occurred:' + error, 'error')
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
73
src/functions/activities/ReadToEarn.ts
Normal file
73
src/functions/activities/ReadToEarn.ts
Normal file
@@ -0,0 +1,73 @@
|
||||
import axios from 'axios'
|
||||
import { randomBytes } from 'crypto'
|
||||
|
||||
import { Workers } from '../Workers'
|
||||
|
||||
import { DashboardData } from '../../interface/DashboardData'
|
||||
|
||||
|
||||
export class ReadToEarn extends Workers {
|
||||
public async doReadToEarn(accessToken: string, data: DashboardData) {
|
||||
this.bot.log('READ-TO-EARN', 'Starting Read to Earn')
|
||||
|
||||
try {
|
||||
|
||||
let geoLocale = data.userProfile.attributes.country
|
||||
geoLocale = (this.bot.config.searchSettings.useGeoLocaleQueries && geoLocale.length === 2) ? geoLocale.toLowerCase() : 'us'
|
||||
|
||||
const userDataRequest = {
|
||||
url: 'https://prod.rewardsplatform.microsoft.com/dapi/me',
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Authorization': `Bearer ${accessToken}`,
|
||||
'X-Rewards-Country': geoLocale,
|
||||
'X-Rewards-Language': 'en'
|
||||
}
|
||||
}
|
||||
const userDataResponse = await axios(userDataRequest)
|
||||
const userData = (await userDataResponse.data).response
|
||||
let balance: number = userData.balance
|
||||
|
||||
const jsonData = {
|
||||
amount: 1,
|
||||
country: geoLocale,
|
||||
id: '1',
|
||||
type: 101,
|
||||
attributes: {
|
||||
offerid: 'ENUS_readarticle3_30points'
|
||||
}
|
||||
}
|
||||
|
||||
for (let i = 0; i < 10; ++i) {
|
||||
jsonData.id = randomBytes(64).toString('hex')
|
||||
const claimRequest = {
|
||||
url: 'https://prod.rewardsplatform.microsoft.com/dapi/me/activities',
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Authorization': `Bearer ${accessToken}`,
|
||||
'Content-Type': 'application/json',
|
||||
'X-Rewards-Country': geoLocale,
|
||||
'X-Rewards-Language': 'en'
|
||||
},
|
||||
data: JSON.stringify(jsonData)
|
||||
}
|
||||
|
||||
const claimResponse = await axios(claimRequest)
|
||||
const newBalance = (await claimResponse.data).response.balance
|
||||
|
||||
if (newBalance == balance) {
|
||||
this.bot.log('READ-TO-EARN', 'Read all available articles')
|
||||
break
|
||||
} else {
|
||||
balance = newBalance
|
||||
this.bot.log('READ-TO-EARN', `Read article ${i + 1}`)
|
||||
await this.bot.utils.wait(Math.floor(this.bot.utils.randomNumber(this.bot.config.searchSettings.searchDelay.min, this.bot.config.searchSettings.searchDelay.max)))
|
||||
}
|
||||
}
|
||||
|
||||
this.bot.log('READ-TO-EARN', 'Completed Read to Earn')
|
||||
} catch (error) {
|
||||
this.bot.log('READ-TO-EARN', 'An error occurred:' + error, 'error')
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -133,15 +133,19 @@ export class Search extends Workers {
|
||||
private async bingSearch(searchPage: Page, query: string) {
|
||||
const platformControlKey = platform() === 'darwin' ? 'Meta' : 'Control'
|
||||
|
||||
|
||||
|
||||
// Try a max of 5 times
|
||||
for (let i = 0; i < 5; i++) {
|
||||
try {
|
||||
|
||||
// Go to top of the page
|
||||
await searchPage.evaluate(() => {
|
||||
window.scrollTo(0, 0)
|
||||
})
|
||||
|
||||
// Set it since params get added after visiting
|
||||
this.searchPageURL = searchPage.url()
|
||||
|
||||
await this.bot.utils.wait(500)
|
||||
|
||||
const searchBar = '#sb_form_q'
|
||||
@@ -155,14 +159,19 @@ export class Search extends Workers {
|
||||
await searchPage.keyboard.type(query)
|
||||
await searchPage.keyboard.press('Enter')
|
||||
|
||||
await this.bot.utils.wait(1000)
|
||||
|
||||
// Bing.com in Chrome opens a new tab when searching
|
||||
const resultPage = await this.bot.browser.utils.getLatestTab(searchPage)
|
||||
|
||||
if (this.bot.config.searchSettings.scrollRandomResults) {
|
||||
await this.bot.utils.wait(2000)
|
||||
await this.randomScroll(searchPage)
|
||||
await this.randomScroll(resultPage)
|
||||
}
|
||||
|
||||
if (this.bot.config.searchSettings.clickRandomResults) {
|
||||
await this.bot.utils.wait(2000)
|
||||
await this.clickRandomLink(searchPage)
|
||||
await this.clickRandomLink(resultPage)
|
||||
}
|
||||
|
||||
// Delay between searches
|
||||
@@ -181,7 +190,7 @@ export class Search extends Workers {
|
||||
|
||||
// Reset the tabs
|
||||
const lastTab = await this.bot.browser.utils.getLatestTab(searchPage)
|
||||
await this.closeTabs(lastTab, this.searchPageURL)
|
||||
await this.closeTabs(lastTab)
|
||||
|
||||
await this.bot.utils.wait(4000)
|
||||
}
|
||||
@@ -262,11 +271,13 @@ export class Search extends Workers {
|
||||
|
||||
private async randomScroll(page: Page) {
|
||||
try {
|
||||
const scrollAmount = this.bot.utils.randomNumber(5, 5000)
|
||||
const viewportHeight = await page.evaluate(() => window.innerHeight)
|
||||
const totalHeight = await page.evaluate(() => document.body.scrollHeight)
|
||||
const randomScrollPosition = Math.floor(Math.random() * (totalHeight - viewportHeight))
|
||||
|
||||
await page.evaluate((scrollAmount) => {
|
||||
window.scrollBy(0, scrollAmount)
|
||||
}, scrollAmount)
|
||||
await page.evaluate((scrollPos) => {
|
||||
window.scrollTo(0, scrollPos)
|
||||
}, randomScrollPosition)
|
||||
|
||||
} catch (error) {
|
||||
this.bot.log('SEARCH-RANDOM-SCROLL', 'An error occurred:' + error, 'error')
|
||||
@@ -275,23 +286,22 @@ export class Search extends Workers {
|
||||
|
||||
private async clickRandomLink(page: Page) {
|
||||
try {
|
||||
const searchListingURL = new URL(page.url()) // Get searchPage info before clicking
|
||||
|
||||
await page.click('#b_results .b_algo h2').catch(() => { }) // Since we don't really care if it did it or not
|
||||
await page.click('#b_results .b_algo h2', { timeout: 2000 }).catch(() => { }) // Since we don't really care if it did it or not
|
||||
|
||||
// Will get current tab if no new one is created
|
||||
let lastTab = await this.bot.browser.utils.getLatestTab(page)
|
||||
|
||||
// Let website load, if it doesn't load within 5 sec. exit regardless
|
||||
await this.bot.utils.wait(5000)
|
||||
// Stay for 10 seconds
|
||||
await this.bot.utils.wait(10_000)
|
||||
|
||||
let lastTabURL = new URL(lastTab.url()) // Get new tab info
|
||||
|
||||
// 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) {
|
||||
while (lastTabURL.href !== this.searchPageURL && i < 5) {
|
||||
|
||||
await this.closeTabs(lastTab, searchListingURL.href)
|
||||
await this.closeTabs(lastTab)
|
||||
|
||||
// End of loop, refresh lastPage
|
||||
lastTab = await this.bot.browser.utils.getLatestTab(page) // Finally update the lastTab var again
|
||||
@@ -304,26 +314,25 @@ export class Search extends Workers {
|
||||
}
|
||||
}
|
||||
|
||||
private async closeTabs(lastTab: Page, url: string) {
|
||||
private async closeTabs(lastTab: Page) {
|
||||
const browser = lastTab.context()
|
||||
const tabs = browser.pages()
|
||||
|
||||
// If more than 3 tabs are open, close the last tab
|
||||
// If more than 2 tabs are open, close the last tab
|
||||
if (tabs.length > 2) {
|
||||
await lastTab.close()
|
||||
|
||||
// If only 1 tab is open, open a new one to search in
|
||||
} else if (tabs.length === 1) {
|
||||
const newPage = await browser.newPage()
|
||||
await newPage.goto(url)
|
||||
await newPage.goto(this.searchPageURL)
|
||||
|
||||
// Else go back one page
|
||||
// Else go back one page, this means the correct amount is open
|
||||
} else {
|
||||
await lastTab.goBack()
|
||||
await lastTab.goBack().catch(() => { })
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private calculatePoints(counters: Counters) {
|
||||
const mobileData = counters.mobileSearch?.[0] // Mobile searches
|
||||
const genericData = counters.pcSearch?.[0] // Normal searches
|
||||
|
||||
Reference in New Issue
Block a user