mirror of
https://github.com/TheNetsky/Microsoft-Rewards-Script.git
synced 2026-01-20 23:13:58 +00:00
v3.1.0 initial
This commit is contained in:
124
src/functions/activities/api/DoubleSearchPoints.ts
Normal file
124
src/functions/activities/api/DoubleSearchPoints.ts
Normal file
@@ -0,0 +1,124 @@
|
||||
import type { AxiosRequestConfig } from 'axios'
|
||||
import { Workers } from '../../Workers'
|
||||
import { PromotionalItem } from '../../../interface/DashboardData'
|
||||
|
||||
export class DoubleSearchPoints extends Workers {
|
||||
private cookieHeader: string = ''
|
||||
|
||||
private fingerprintHeader: { [x: string]: string } = {}
|
||||
|
||||
public async doDoubleSearchPoints(promotion: PromotionalItem) {
|
||||
const offerId = promotion.offerId
|
||||
const activityType = promotion.activityType
|
||||
|
||||
try {
|
||||
if (!this.bot.requestToken) {
|
||||
this.bot.logger.warn(
|
||||
this.bot.isMobile,
|
||||
'DOUBLE-SEARCH-POINTS',
|
||||
'Skipping: Request token not available, this activity requires it!'
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
this.cookieHeader = (this.bot.isMobile ? this.bot.cookies.mobile : this.bot.cookies.desktop)
|
||||
.map((c: { name: string; value: string }) => `${c.name}=${c.value}`)
|
||||
.join('; ')
|
||||
|
||||
const fingerprintHeaders = { ...this.bot.fingerprint.headers }
|
||||
delete fingerprintHeaders['Cookie']
|
||||
delete fingerprintHeaders['cookie']
|
||||
this.fingerprintHeader = fingerprintHeaders
|
||||
|
||||
this.bot.logger.info(
|
||||
this.bot.isMobile,
|
||||
'DOUBLE-SEARCH-POINTS',
|
||||
`Starting Double Search Points | offerId=${offerId}`
|
||||
)
|
||||
|
||||
this.bot.logger.debug(
|
||||
this.bot.isMobile,
|
||||
'DOUBLE-SEARCH-POINTS',
|
||||
`Prepared headers | cookieLength=${this.cookieHeader.length} | fingerprintHeaderKeys=${Object.keys(this.fingerprintHeader).length}`
|
||||
)
|
||||
|
||||
const formData = new URLSearchParams({
|
||||
id: offerId,
|
||||
hash: promotion.hash,
|
||||
timeZone: '60',
|
||||
activityAmount: '1',
|
||||
dbs: '0',
|
||||
form: '',
|
||||
type: activityType,
|
||||
__RequestVerificationToken: this.bot.requestToken
|
||||
})
|
||||
|
||||
this.bot.logger.debug(
|
||||
this.bot.isMobile,
|
||||
'DOUBLE-SEARCH-POINTS',
|
||||
`Prepared Double Search Points form data | offerId=${offerId} | hash=${promotion.hash} | timeZone=60 | activityAmount=1 | type=${activityType}`
|
||||
)
|
||||
|
||||
const request: AxiosRequestConfig = {
|
||||
url: 'https://rewards.bing.com/api/reportactivity?X-Requested-With=XMLHttpRequest',
|
||||
method: 'POST',
|
||||
headers: {
|
||||
...(this.bot.fingerprint?.headers ?? {}),
|
||||
Cookie: this.cookieHeader,
|
||||
Referer: 'https://rewards.bing.com/',
|
||||
Origin: 'https://rewards.bing.com'
|
||||
},
|
||||
data: formData
|
||||
}
|
||||
|
||||
this.bot.logger.debug(
|
||||
this.bot.isMobile,
|
||||
'DOUBLE-SEARCH-POINTS',
|
||||
`Sending Double Search Points request | offerId=${offerId} | url=${request.url}`
|
||||
)
|
||||
|
||||
const response = await this.bot.axios.request(request)
|
||||
|
||||
this.bot.logger.debug(
|
||||
this.bot.isMobile,
|
||||
'DOUBLE-SEARCH-POINTS',
|
||||
`Received Double Search Points response | offerId=${offerId} | status=${response.status}`
|
||||
)
|
||||
|
||||
const data = await this.bot.browser.func.getDashboardData()
|
||||
const promotionalItem = data.promotionalItems.find(item =>
|
||||
item.name.toLowerCase().includes('ww_banner_optin_2x')
|
||||
)
|
||||
|
||||
// If OK, should no longer be presernt in promotionalItems
|
||||
if (promotionalItem) {
|
||||
this.bot.logger.warn(
|
||||
this.bot.isMobile,
|
||||
'DOUBLE-SEARCH-POINTS',
|
||||
`Unable to find or activate Double Search Points | offerId=${offerId} | status=${response.status}`
|
||||
)
|
||||
} else {
|
||||
this.bot.logger.info(
|
||||
this.bot.isMobile,
|
||||
'DOUBLE-SEARCH-POINTS',
|
||||
`Activated Double Search Points | offerId=${offerId} | status=${response.status}`,
|
||||
'green'
|
||||
)
|
||||
}
|
||||
|
||||
this.bot.logger.debug(
|
||||
this.bot.isMobile,
|
||||
'DOUBLE-SEARCH-POINTS',
|
||||
`Waiting after Double Search Points | offerId=${offerId}`
|
||||
)
|
||||
|
||||
await this.bot.utils.wait(this.bot.utils.randomDelay(5000, 10000))
|
||||
} catch (error) {
|
||||
this.bot.logger.error(
|
||||
this.bot.isMobile,
|
||||
'DOUBLE-SEARCH-POINTS',
|
||||
`Error in doDoubleSearchPoints | offerId=${offerId} | message=${error instanceof Error ? error.message : String(error)}`
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -33,38 +33,34 @@ export class Search extends Workers {
|
||||
`Search points remaining | Edge=${missingPoints.edgePoints} | Desktop=${missingPoints.desktopPoints} | Mobile=${missingPoints.mobilePoints}`
|
||||
)
|
||||
|
||||
let queries: string[] = []
|
||||
|
||||
const queryCore = new QueryCore(this.bot)
|
||||
const locale = (this.bot.userData.geoLocale ?? 'US').toUpperCase()
|
||||
const langCode = (this.bot.userData.langCode ?? 'en').toLowerCase()
|
||||
|
||||
const locale = this.bot.userData.geoLocale.toUpperCase()
|
||||
this.bot.logger.debug(
|
||||
isMobile,
|
||||
'SEARCH-BING',
|
||||
`Resolving search queries via QueryCore | locale=${locale} | lang=${langCode} | related=true`
|
||||
)
|
||||
|
||||
this.bot.logger.debug(isMobile, 'SEARCH-BING', `Resolving search queries | locale=${locale}`)
|
||||
let queries = await queryCore.queryManager({
|
||||
shuffle: true,
|
||||
related: true,
|
||||
langCode,
|
||||
geoLocale: locale,
|
||||
sourceOrder: ['google', 'wikipedia', 'reddit', 'local']
|
||||
})
|
||||
|
||||
// Set Google search queries
|
||||
queries = await queryCore.getGoogleTrends(locale)
|
||||
queries = [...new Set(queries.map(q => q.trim()).filter(Boolean))]
|
||||
|
||||
this.bot.logger.debug(isMobile, 'SEARCH-BING', `Fetched base queries | count=${queries.length}`)
|
||||
|
||||
// Deduplicate queries
|
||||
queries = [...new Set(queries)]
|
||||
|
||||
this.bot.logger.debug(isMobile, 'SEARCH-BING', `Deduplicated queries | count=${queries.length}`)
|
||||
|
||||
// Shuffle
|
||||
queries = this.bot.utils.shuffleArray(queries)
|
||||
|
||||
this.bot.logger.debug(isMobile, 'SEARCH-BING', `Shuffled queries | count=${queries.length}`)
|
||||
this.bot.logger.debug(isMobile, 'SEARCH-BING', `Query pool ready | count=${queries.length}`)
|
||||
|
||||
// Go to bing
|
||||
const targetUrl = this.searchPageURL ? this.searchPageURL : this.bingHome
|
||||
this.bot.logger.debug(isMobile, 'SEARCH-BING', `Navigating to search page | url=${targetUrl}`)
|
||||
|
||||
await page.goto(targetUrl)
|
||||
|
||||
// Wait until page loaded
|
||||
await page.waitForLoadState('networkidle', { timeout: 10000 }).catch(() => {})
|
||||
|
||||
await this.bot.browser.utils.tryDismissAllMessages(page)
|
||||
|
||||
let stagnantLoop = 0
|
||||
@@ -77,7 +73,6 @@ export class Search extends Workers {
|
||||
const newMissingPoints = this.bot.browser.func.missingSearchPoints(searchCounters, isMobile)
|
||||
const newMissingPointsTotal = newMissingPoints.totalPoints
|
||||
|
||||
// Points gained for THIS query only
|
||||
const rawGained = missingPointsTotal - newMissingPointsTotal
|
||||
const gainedPoints = Math.max(0, rawGained)
|
||||
|
||||
@@ -91,12 +86,10 @@ export class Search extends Workers {
|
||||
} else {
|
||||
stagnantLoop = 0
|
||||
|
||||
// Update global user data
|
||||
const newBalance = Number(this.bot.userData.currentPoints ?? 0) + gainedPoints
|
||||
this.bot.userData.currentPoints = newBalance
|
||||
this.bot.userData.gainedPoints = (this.bot.userData.gainedPoints ?? 0) + gainedPoints
|
||||
|
||||
// Track for return value
|
||||
totalGainedPoints += gainedPoints
|
||||
|
||||
this.bot.logger.info(
|
||||
@@ -107,10 +100,8 @@ export class Search extends Workers {
|
||||
)
|
||||
}
|
||||
|
||||
// Update loop state
|
||||
missingPointsTotal = newMissingPointsTotal
|
||||
|
||||
// Completed
|
||||
if (missingPointsTotal === 0) {
|
||||
this.bot.logger.info(
|
||||
isMobile,
|
||||
@@ -120,7 +111,6 @@ export class Search extends Workers {
|
||||
break
|
||||
}
|
||||
|
||||
// Stuck
|
||||
if (stagnantLoop > stagnantLoopMax) {
|
||||
this.bot.logger.warn(
|
||||
isMobile,
|
||||
@@ -130,105 +120,123 @@ export class Search extends Workers {
|
||||
stagnantLoop = 0
|
||||
break
|
||||
}
|
||||
|
||||
const remainingQueries = queries.length - (i + 1)
|
||||
const minBuffer = 20
|
||||
if (missingPointsTotal > 0 && remainingQueries < minBuffer) {
|
||||
this.bot.logger.warn(
|
||||
isMobile,
|
||||
'SEARCH-BING',
|
||||
`Low query buffer while still missing points, regenerating | remainingQueries=${remainingQueries} | missing=${missingPointsTotal}`
|
||||
)
|
||||
|
||||
const extra = await queryCore.queryManager({
|
||||
shuffle: true,
|
||||
related: true,
|
||||
langCode,
|
||||
geoLocale: locale,
|
||||
sourceOrder: this.bot.config.searchSettings.queryEngines
|
||||
})
|
||||
|
||||
const merged = [...queries, ...extra].map(q => q.trim()).filter(Boolean)
|
||||
queries = [...new Set(merged)]
|
||||
queries = this.bot.utils.shuffleArray(queries)
|
||||
|
||||
this.bot.logger.debug(isMobile, 'SEARCH-BING', `Query pool regenerated | count=${queries.length}`)
|
||||
}
|
||||
}
|
||||
|
||||
if (missingPointsTotal > 0) {
|
||||
this.bot.logger.info(
|
||||
isMobile,
|
||||
'SEARCH-BING',
|
||||
`Search completed but still missing points, generating extra searches | remaining=${missingPointsTotal}`
|
||||
`Search completed but still missing points, continuing with regenerated queries | remaining=${missingPointsTotal}`
|
||||
)
|
||||
|
||||
let i = 0
|
||||
let stagnantLoop = 0
|
||||
const stagnantLoopMax = 5
|
||||
|
||||
while (missingPointsTotal > 0) {
|
||||
const query = queries[i++] as string
|
||||
const extra = await queryCore.queryManager({
|
||||
shuffle: true,
|
||||
related: true,
|
||||
langCode,
|
||||
geoLocale: locale,
|
||||
sourceOrder: this.bot.config.searchSettings.queryEngines
|
||||
})
|
||||
|
||||
const merged = [...queries, ...extra].map(q => q.trim()).filter(Boolean)
|
||||
const newPool = [...new Set(merged)]
|
||||
queries = this.bot.utils.shuffleArray(newPool)
|
||||
|
||||
this.bot.logger.debug(
|
||||
isMobile,
|
||||
'SEARCH-BING-EXTRA',
|
||||
`Fetching related terms for extra searches | baseQuery="${query}"`
|
||||
`New query pool generated | count=${queries.length}`
|
||||
)
|
||||
|
||||
const relatedTerms = await queryCore.getBingRelatedTerms(query)
|
||||
this.bot.logger.debug(
|
||||
isMobile,
|
||||
'SEARCH-BING-EXTRA',
|
||||
`Related terms resolved | baseQuery="${query}" | count=${relatedTerms.length}`
|
||||
)
|
||||
for (const query of queries) {
|
||||
this.bot.logger.info(
|
||||
isMobile,
|
||||
'SEARCH-BING-EXTRA',
|
||||
`Extra search | remaining=${missingPointsTotal} | query="${query}"`
|
||||
)
|
||||
|
||||
if (relatedTerms.length > 3) {
|
||||
for (const term of relatedTerms.slice(1, 3)) {
|
||||
searchCounters = await this.bingSearch(page, query, isMobile)
|
||||
const newMissingPoints = this.bot.browser.func.missingSearchPoints(searchCounters, isMobile)
|
||||
const newMissingPointsTotal = newMissingPoints.totalPoints
|
||||
|
||||
const rawGained = missingPointsTotal - newMissingPointsTotal
|
||||
const gainedPoints = Math.max(0, rawGained)
|
||||
|
||||
if (gainedPoints === 0) {
|
||||
stagnantLoop++
|
||||
this.bot.logger.info(
|
||||
isMobile,
|
||||
'SEARCH-BING-EXTRA',
|
||||
`Extra search | remaining=${missingPointsTotal} | query="${term}"`
|
||||
`No points gained ${stagnantLoop}/${stagnantLoopMax} | query="${query}" | remaining=${newMissingPointsTotal}`
|
||||
)
|
||||
} else {
|
||||
stagnantLoop = 0
|
||||
|
||||
searchCounters = await this.bingSearch(page, term, isMobile)
|
||||
const newMissingPoints = this.bot.browser.func.missingSearchPoints(searchCounters, isMobile)
|
||||
const newMissingPointsTotal = newMissingPoints.totalPoints
|
||||
const newBalance = Number(this.bot.userData.currentPoints ?? 0) + gainedPoints
|
||||
this.bot.userData.currentPoints = newBalance
|
||||
this.bot.userData.gainedPoints = (this.bot.userData.gainedPoints ?? 0) + gainedPoints
|
||||
|
||||
// Points gained for THIS extra query only
|
||||
const rawGained = missingPointsTotal - newMissingPointsTotal
|
||||
const gainedPoints = Math.max(0, rawGained)
|
||||
totalGainedPoints += gainedPoints
|
||||
|
||||
if (gainedPoints === 0) {
|
||||
stagnantLoop++
|
||||
this.bot.logger.info(
|
||||
isMobile,
|
||||
'SEARCH-BING-EXTRA',
|
||||
`No points gained for extra query ${stagnantLoop}/${stagnantLoopMax} | query="${term}" | remaining=${newMissingPointsTotal}`
|
||||
)
|
||||
} else {
|
||||
stagnantLoop = 0
|
||||
this.bot.logger.info(
|
||||
isMobile,
|
||||
'SEARCH-BING-EXTRA',
|
||||
`gainedPoints=${gainedPoints} points | query="${query}" | remaining=${newMissingPointsTotal}`,
|
||||
'green'
|
||||
)
|
||||
}
|
||||
|
||||
// Update global user data
|
||||
const newBalance = Number(this.bot.userData.currentPoints ?? 0) + gainedPoints
|
||||
this.bot.userData.currentPoints = newBalance
|
||||
this.bot.userData.gainedPoints = (this.bot.userData.gainedPoints ?? 0) + gainedPoints
|
||||
missingPointsTotal = newMissingPointsTotal
|
||||
|
||||
// Track for return value
|
||||
totalGainedPoints += gainedPoints
|
||||
if (missingPointsTotal === 0) {
|
||||
this.bot.logger.info(
|
||||
isMobile,
|
||||
'SEARCH-BING-EXTRA',
|
||||
'All required search points earned during extra searches'
|
||||
)
|
||||
break
|
||||
}
|
||||
|
||||
this.bot.logger.info(
|
||||
isMobile,
|
||||
'SEARCH-BING-EXTRA',
|
||||
`gainedPoints=${gainedPoints} points | query="${term}" | remaining=${newMissingPointsTotal}`,
|
||||
'green'
|
||||
)
|
||||
}
|
||||
|
||||
// Update loop state
|
||||
missingPointsTotal = newMissingPointsTotal
|
||||
|
||||
// Completed
|
||||
if (missingPointsTotal === 0) {
|
||||
this.bot.logger.info(
|
||||
isMobile,
|
||||
'SEARCH-BING-EXTRA',
|
||||
'All required search points earned during extra searches'
|
||||
)
|
||||
break
|
||||
}
|
||||
|
||||
// Stuck again
|
||||
if (stagnantLoop > stagnantLoopMax) {
|
||||
this.bot.logger.warn(
|
||||
isMobile,
|
||||
'SEARCH-BING-EXTRA',
|
||||
`Search did not gain points for ${stagnantLoopMax} extra iterations, aborting extra searches`
|
||||
)
|
||||
const finalBalance = Number(this.bot.userData.currentPoints ?? startBalance)
|
||||
this.bot.logger.info(
|
||||
isMobile,
|
||||
'SEARCH-BING',
|
||||
`Aborted extra searches | startBalance=${startBalance} | finalBalance=${finalBalance}`
|
||||
)
|
||||
return totalGainedPoints
|
||||
}
|
||||
if (stagnantLoop > stagnantLoopMax) {
|
||||
this.bot.logger.warn(
|
||||
isMobile,
|
||||
'SEARCH-BING-EXTRA',
|
||||
`Search did not gain points for ${stagnantLoopMax} iterations, aborting extra searches`
|
||||
)
|
||||
const finalBalance = Number(this.bot.userData.currentPoints ?? startBalance)
|
||||
this.bot.logger.info(
|
||||
isMobile,
|
||||
'SEARCH-BING',
|
||||
`Aborted extra searches | startBalance=${startBalance} | finalBalance=${finalBalance}`
|
||||
)
|
||||
return totalGainedPoints
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -259,7 +267,6 @@ export class Search extends Workers {
|
||||
|
||||
this.searchCount++
|
||||
|
||||
// Page fill seems to get more sluggish over time
|
||||
if (this.searchCount % refreshThreshold === 0) {
|
||||
this.bot.logger.info(
|
||||
isMobile,
|
||||
@@ -271,7 +278,7 @@ export class Search extends Workers {
|
||||
|
||||
await searchPage.goto(this.bingHome)
|
||||
await searchPage.waitForLoadState('networkidle', { timeout: 10000 }).catch(() => {})
|
||||
await this.bot.browser.utils.tryDismissAllMessages(searchPage) // Not always the case but possible for new cookie headers
|
||||
await this.bot.browser.utils.tryDismissAllMessages(searchPage)
|
||||
}
|
||||
|
||||
this.bot.logger.debug(
|
||||
@@ -402,11 +409,9 @@ export class Search extends Workers {
|
||||
await this.bot.utils.wait(this.bot.config.searchSettings.searchResultVisitTime)
|
||||
|
||||
if (isMobile) {
|
||||
// Mobile
|
||||
await page.goto(searchPageUrl)
|
||||
this.bot.logger.debug(isMobile, 'SEARCH-RANDOM-CLICK', 'Navigated back to search page')
|
||||
} else {
|
||||
// Desktop
|
||||
const newTab = await this.bot.browser.utils.getLatestTab(page)
|
||||
const newTabUrl = newTab.url()
|
||||
|
||||
|
||||
@@ -232,7 +232,7 @@ export class SearchOnBing extends Workers {
|
||||
if (this.bot.config.searchOnBingLocalQueries) {
|
||||
this.bot.logger.debug(this.bot.isMobile, 'SEARCH-ON-BING-QUERY', 'Using local queries config file')
|
||||
|
||||
const data = fs.readFileSync(path.join(__dirname, '../queries.json'), 'utf8')
|
||||
const data = fs.readFileSync(path.join(__dirname, '../bing-search-activity-queries.json'), 'utf8')
|
||||
queries = JSON.parse(data)
|
||||
|
||||
this.bot.logger.debug(
|
||||
@@ -250,7 +250,7 @@ export class SearchOnBing extends Workers {
|
||||
// Fetch from the repo directly so the user doesn't need to redownload the script for the new activities
|
||||
const response = await this.bot.axios.request({
|
||||
method: 'GET',
|
||||
url: 'https://raw.githubusercontent.com/TheNetsky/Microsoft-Rewards-Script/refs/heads/v3/src/functions/queries.json'
|
||||
url: 'https://raw.githubusercontent.com/TheNetsky/Microsoft-Rewards-Script/refs/heads/v3/src/functions/bing-search-activity-queries.json'
|
||||
})
|
||||
queries = response.data
|
||||
|
||||
|
||||
Reference in New Issue
Block a user