mirror of
https://github.com/TheNetsky/Microsoft-Rewards-Script.git
synced 2026-01-19 06:23:58 +00:00
1.2.1
This commit is contained in:
@@ -23,6 +23,7 @@ Under development, however mainly for personal use!
|
|||||||
- [x] Mobile Searches
|
- [x] Mobile Searches
|
||||||
- [x] Emulated Scrolling Support
|
- [x] Emulated Scrolling Support
|
||||||
- [x] Emulated Link Clicking Support
|
- [x] Emulated Link Clicking Support
|
||||||
|
- [x] Geo Locale Search Queries
|
||||||
- [x] Completing Daily Set
|
- [x] Completing Daily Set
|
||||||
- [x] Completing More Promotions
|
- [x] Completing More Promotions
|
||||||
- [x] Solving Quiz (10 point variant)
|
- [x] Solving Quiz (10 point variant)
|
||||||
@@ -36,7 +37,7 @@ Under development, however mainly for personal use!
|
|||||||
- [ ] Completing Shopping Game
|
- [ ] Completing Shopping Game
|
||||||
- [ ] Completing Gaming Tab
|
- [ ] Completing Gaming Tab
|
||||||
- [x] Clustering Support
|
- [x] Clustering Support
|
||||||
- [ ] Proxy Support
|
- [x] Proxy Support
|
||||||
|
|
||||||
## Disclaimer ##
|
## Disclaimer ##
|
||||||
Your account may be at risk of getting banned or suspended using this script, you've been warned!
|
Your account may be at risk of getting banned or suspended using this script, you've been warned!
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "microsoft-rewards-script",
|
"name": "microsoft-rewards-script",
|
||||||
"version": "1.2.0",
|
"version": "1.2.1",
|
||||||
"description": "Automatically do tasks for Microsoft Rewards but in TS!",
|
"description": "Automatically do tasks for Microsoft Rewards but in TS!",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"engines": {
|
"engines": {
|
||||||
|
|||||||
@@ -1,10 +1,22 @@
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
"email": "email_1",
|
"email": "email_1",
|
||||||
"password": "password_1"
|
"password": "password_1",
|
||||||
|
"proxy": {
|
||||||
|
"url": "",
|
||||||
|
"port": 0,
|
||||||
|
"username": "",
|
||||||
|
"password": ""
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"email": "email_2",
|
"email": "email_2",
|
||||||
"password": "password_2"
|
"password": "password_2",
|
||||||
|
"proxy": {
|
||||||
|
"url": "",
|
||||||
|
"port": 0,
|
||||||
|
"username": "",
|
||||||
|
"password": ""
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@@ -1,16 +1,18 @@
|
|||||||
import puppeteer from 'puppeteer-extra'
|
import puppeteer from 'puppeteer-extra'
|
||||||
import StealthPlugin from 'puppeteer-extra-plugin-stealth'
|
import stealthPlugin from 'puppeteer-extra-plugin-stealth'
|
||||||
|
|
||||||
import { getUserAgent } from '../util/UserAgent'
|
import { getUserAgent } from '../util/UserAgent'
|
||||||
import { loadSesion } from './BrowserFunc'
|
import { loadSesion } from './BrowserFunc'
|
||||||
|
|
||||||
|
import { AccountProxy } from '../interface/Account'
|
||||||
|
|
||||||
import { headless } from '../config.json'
|
import { headless } from '../config.json'
|
||||||
|
|
||||||
puppeteer.use(StealthPlugin())
|
puppeteer.use(stealthPlugin())
|
||||||
|
|
||||||
class Browser {
|
class Browser {
|
||||||
|
|
||||||
async createBrowser(email: string, isMobile: boolean) {
|
async createBrowser(email: string, proxy: AccountProxy, isMobile: boolean) {
|
||||||
const userAgent = await getUserAgent(isMobile)
|
const userAgent = await getUserAgent(isMobile)
|
||||||
|
|
||||||
const browser = await puppeteer.launch({
|
const browser = await puppeteer.launch({
|
||||||
@@ -21,7 +23,8 @@ class Browser {
|
|||||||
'--mute-audio',
|
'--mute-audio',
|
||||||
'--disable-setuid-sandbox',
|
'--disable-setuid-sandbox',
|
||||||
`--user-agent=${userAgent.userAgent}`,
|
`--user-agent=${userAgent.userAgent}`,
|
||||||
isMobile ? '--window-size=568,1024' : ''
|
isMobile ? '--window-size=568,1024' : '',
|
||||||
|
proxy.url ? `--proxy-server=${proxy.url}:${proxy.port}` : ''
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { Page } from 'puppeteer'
|
import { Page } from 'puppeteer'
|
||||||
import fs from 'fs'
|
import fs from 'fs'
|
||||||
import path from 'path'
|
import path from 'path'
|
||||||
import { load } from 'cheerio'
|
import { CheerioAPI, load } from 'cheerio'
|
||||||
|
|
||||||
import { tryDismissAllMessages, tryDismissCookieBanner } from './BrowserUtil'
|
import { tryDismissAllMessages, tryDismissCookieBanner } from './BrowserUtil'
|
||||||
import { getFormattedDate, wait } from './../util/Utils'
|
import { getFormattedDate, wait } from './../util/Utils'
|
||||||
@@ -200,7 +200,7 @@ export async function loadSesion(email: string): Promise<string> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function waitForQuizRefresh(page: Page) {
|
export async function waitForQuizRefresh(page: Page): Promise<boolean> {
|
||||||
try {
|
try {
|
||||||
await page.waitForSelector('#rqHeaderCredits', { visible: true, timeout: 5000 })
|
await page.waitForSelector('#rqHeaderCredits', { visible: true, timeout: 5000 })
|
||||||
await wait(2000)
|
await wait(2000)
|
||||||
@@ -212,7 +212,7 @@ export async function waitForQuizRefresh(page: Page) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function checkQuizCompleted(page: Page) {
|
export async function checkQuizCompleted(page: Page): Promise<boolean> {
|
||||||
try {
|
try {
|
||||||
await page.waitForSelector('#quizCompleteContainer', { visible: true, timeout: 1000 })
|
await page.waitForSelector('#quizCompleteContainer', { visible: true, timeout: 1000 })
|
||||||
await wait(2000)
|
await wait(2000)
|
||||||
@@ -223,14 +223,14 @@ export async function checkQuizCompleted(page: Page) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function refreshCheerio(page: Page) {
|
export async function refreshCheerio(page: Page): Promise<CheerioAPI> {
|
||||||
const html = await page.content()
|
const html = await page.content()
|
||||||
const $ = load(html)
|
const $ = load(html)
|
||||||
|
|
||||||
return $
|
return $
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getPunchCardActivity(page: Page, activity: PromotionalItem | MorePromotion) {
|
export async function getPunchCardActivity(page: Page, activity: PromotionalItem | MorePromotion): Promise<string> {
|
||||||
let selector = ''
|
let selector = ''
|
||||||
try {
|
try {
|
||||||
const html = await page.content()
|
const html = await page.content()
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ export async function tryDismissBingCookieBanner(page: Page): Promise<void> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getLatestTab(page: Page) {
|
export async function getLatestTab(page: Page): Promise<Page> {
|
||||||
try {
|
try {
|
||||||
await wait(500)
|
await wait(500)
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
"baseURL": "https://rewards.bing.com",
|
"baseURL": "https://rewards.bing.com",
|
||||||
"sessionPath": "sessions",
|
"sessionPath": "sessions",
|
||||||
"headless": false,
|
"headless": false,
|
||||||
"runOnZeroPoints": false,
|
"runOnZeroPoints": true,
|
||||||
"clusters": 1,
|
"clusters": 1,
|
||||||
"workers": {
|
"workers": {
|
||||||
"doDailySet": true,
|
"doDailySet": true,
|
||||||
@@ -12,6 +12,7 @@
|
|||||||
"doMobileSearch": true
|
"doMobileSearch": true
|
||||||
},
|
},
|
||||||
"searchSettings": {
|
"searchSettings": {
|
||||||
|
"useGeoLocaleQueries": false,
|
||||||
"scrollRandomResults": true,
|
"scrollRandomResults": true,
|
||||||
"clickRandomResults": true
|
"clickRandomResults": true
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -157,13 +157,14 @@ async function solveActivities(page: Page, activities: PromotionalItem[] | MoreP
|
|||||||
await doUrlReward(activityPage)
|
await doUrlReward(activityPage)
|
||||||
break
|
break
|
||||||
|
|
||||||
// Misc
|
// Misc, Usually UrlReward Type
|
||||||
default:
|
default:
|
||||||
log('ACTIVITY', `Found activity type: "Misc" title: "${activity.title}"`)
|
log('ACTIVITY', `Found activity type: "Misc" title: "${activity.title}"`)
|
||||||
await doUrlReward(activityPage)
|
await doUrlReward(activityPage)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Cooldown
|
||||||
await wait(1500)
|
await wait(1500)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
log('ACTIVITY', 'An error occurred:' + error, 'error')
|
log('ACTIVITY', 'An error occurred:' + error, 'error')
|
||||||
|
|||||||
@@ -13,10 +13,6 @@ import { GoogleTrends } from '../../interface/GoogleDailyTrends'
|
|||||||
import { GoogleSearch } from '../../interface/Search'
|
import { GoogleSearch } from '../../interface/Search'
|
||||||
|
|
||||||
export async function doSearch(page: Page, data: DashboardData, mobile: boolean) {
|
export async function doSearch(page: Page, data: DashboardData, mobile: boolean) {
|
||||||
const locale = await page.evaluate(() => {
|
|
||||||
return navigator.language
|
|
||||||
})
|
|
||||||
|
|
||||||
log('SEARCH-BING', 'Starting bing searches')
|
log('SEARCH-BING', 'Starting bing searches')
|
||||||
|
|
||||||
const mobileData = data.userStatus.counters?.mobileSearch ? data.userStatus.counters.mobileSearch[0] : null // Mobile searches
|
const mobileData = data.userStatus.counters?.mobileSearch ? data.userStatus.counters.mobileSearch[0] : null // Mobile searches
|
||||||
@@ -33,7 +29,7 @@ export async function doSearch(page: Page, data: DashboardData, mobile: boolean)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Generate search queries
|
// Generate search queries
|
||||||
let googleSearchQueries = await getGoogleTrends(locale, missingPoints) as GoogleSearch[]
|
let googleSearchQueries = await getGoogleTrends(data.userProfile.attributes.country, missingPoints)
|
||||||
googleSearchQueries = shuffleArray(googleSearchQueries)
|
googleSearchQueries = shuffleArray(googleSearchQueries)
|
||||||
|
|
||||||
// Deduplicate the search terms
|
// Deduplicate the search terms
|
||||||
@@ -185,10 +181,14 @@ async function bingSearch(page: Page, searchPage: Page, query: string) {
|
|||||||
return await getSearchPoints(page)
|
return await getSearchPoints(page)
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getGoogleTrends(locale: string, queryCount: number): Promise<GoogleSearch[]> {
|
async function getGoogleTrends(geoLocale: string, queryCount: number): Promise<GoogleSearch[]> {
|
||||||
const queryTerms: GoogleSearch[] = []
|
const queryTerms: GoogleSearch[] = []
|
||||||
let i = 0
|
let i = 0
|
||||||
|
|
||||||
|
geoLocale = (searchSettings.useGeoLocaleQueries && geoLocale.length === 2) ? geoLocale.toUpperCase() : 'US'
|
||||||
|
|
||||||
|
log('SEARCH-GOOGLE-TRENDS', `Generating search queries, can take a while! | GeoLocale: ${geoLocale}`)
|
||||||
|
|
||||||
while (queryCount > queryTerms.length) {
|
while (queryCount > queryTerms.length) {
|
||||||
i += 1
|
i += 1
|
||||||
const date = new Date()
|
const date = new Date()
|
||||||
@@ -197,7 +197,7 @@ async function getGoogleTrends(locale: string, queryCount: number): Promise<Goog
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const request = {
|
const request = {
|
||||||
url: `https://trends.google.com/trends/api/dailytrends?geo=US&hl=en&ed=${formattedDate}&ns=15`,
|
url: `https://trends.google.com/trends/api/dailytrends?geo=${geoLocale}&hl=en&ed=${formattedDate}&ns=15`,
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json'
|
'Content-Type': 'application/json'
|
||||||
@@ -283,13 +283,11 @@ async function clickRandomLink(page: Page) {
|
|||||||
// Check if the URL is different from the original one, don't loop more than 5 times.
|
// Check if the URL is different from the original one, don't loop more than 5 times.
|
||||||
let i = 0
|
let i = 0
|
||||||
while (lastTabURL.href !== searchListingURL.href && i < 5) {
|
while (lastTabURL.href !== searchListingURL.href && i < 5) {
|
||||||
|
|
||||||
// If hostname is still bing, (Bing images/news etc)
|
// If hostname is still bing, (Bing images/news etc)
|
||||||
if (lastTabURL.hostname == searchListingURL.hostname) {
|
if (lastTabURL.hostname == searchListingURL.hostname) {
|
||||||
await lastTab.goBack()
|
await lastTab.goBack()
|
||||||
|
|
||||||
lastTab = await getLatestTab(page) // Get last opened tab
|
lastTab = await getLatestTab(page) // Get last opened tab
|
||||||
lastTabURL = new URL(lastTab.url())
|
|
||||||
|
|
||||||
// If "goBack" didn't return to search listing (due to redirects)
|
// If "goBack" didn't return to search listing (due to redirects)
|
||||||
if (lastTabURL.hostname !== searchListingURL.hostname) {
|
if (lastTabURL.hostname !== searchListingURL.hostname) {
|
||||||
|
|||||||
@@ -2,9 +2,9 @@ import { Page } from 'puppeteer'
|
|||||||
|
|
||||||
import { wait } from '../../util/Utils'
|
import { wait } from '../../util/Utils'
|
||||||
import { log } from '../../util/Logger'
|
import { log } from '../../util/Logger'
|
||||||
|
import { getQuizData } from '../../browser/BrowserFunc'
|
||||||
|
|
||||||
export async function doThisOrThat(page: Page) {
|
export async function doThisOrThat(page: Page) {
|
||||||
return // Todo
|
|
||||||
log('THIS-OR-THAT', 'Trying to complete ThisOrThat')
|
log('THIS-OR-THAT', 'Trying to complete ThisOrThat')
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -22,6 +22,8 @@ export async function doThisOrThat(page: Page) {
|
|||||||
await wait(2000)
|
await wait(2000)
|
||||||
|
|
||||||
// Solving
|
// Solving
|
||||||
|
const quizData = await getQuizData(page)
|
||||||
|
quizData // correctAnswer property is always null?
|
||||||
|
|
||||||
log('THIS-OR-THAT', 'Completed the ThisOrthat successfully')
|
log('THIS-OR-THAT', 'Completed the ThisOrthat successfully')
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
24
src/index.ts
24
src/index.ts
@@ -2,6 +2,7 @@ import cluster from 'cluster'
|
|||||||
|
|
||||||
import Browser from './browser/Browser'
|
import Browser from './browser/Browser'
|
||||||
import { getDashboardData, getEarnablePoints, goHome } from './browser/BrowserFunc'
|
import { getDashboardData, getEarnablePoints, goHome } from './browser/BrowserFunc'
|
||||||
|
|
||||||
import { log } from './util/Logger'
|
import { log } from './util/Logger'
|
||||||
import { loadAccounts } from './util/Account'
|
import { loadAccounts } from './util/Account'
|
||||||
import { chunkArray } from './util/Utils'
|
import { chunkArray } from './util/Utils'
|
||||||
@@ -102,8 +103,18 @@ class MicrosoftRewardsBot {
|
|||||||
|
|
||||||
// Desktop
|
// Desktop
|
||||||
async Desktop(account: Account) {
|
async Desktop(account: Account) {
|
||||||
const browser = await this.browserFactory.createBrowser(account.email, false)
|
const browser = await this.browserFactory.createBrowser(account.email, account.proxy, false)
|
||||||
const page = await browser.newPage()
|
const page = await browser.newPage()
|
||||||
|
let pages = await browser.pages()
|
||||||
|
|
||||||
|
// If for some reason the browser initializes with more than 2 pages, close these
|
||||||
|
while (pages.length > 2) {
|
||||||
|
await pages[0]?.close()
|
||||||
|
pages = await browser.pages()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Log into proxy
|
||||||
|
await page.authenticate({ username: account.proxy.username, password: account.proxy.password })
|
||||||
|
|
||||||
log('MAIN', 'Starting DESKTOP browser')
|
log('MAIN', 'Starting DESKTOP browser')
|
||||||
|
|
||||||
@@ -156,8 +167,17 @@ class MicrosoftRewardsBot {
|
|||||||
|
|
||||||
// Mobile
|
// Mobile
|
||||||
async Mobile(account: Account) {
|
async Mobile(account: Account) {
|
||||||
const browser = await this.browserFactory.createBrowser(account.email, true)
|
const browser = await this.browserFactory.createBrowser(account.email, account.proxy, true)
|
||||||
const page = await browser.newPage()
|
const page = await browser.newPage()
|
||||||
|
let pages = await browser.pages()
|
||||||
|
|
||||||
|
// If for some reason the browser initializes with more than 2 pages, close these
|
||||||
|
while (pages.length > 2) {
|
||||||
|
await pages[0]?.close()
|
||||||
|
pages = await browser.pages()
|
||||||
|
}
|
||||||
|
// Log into proxy
|
||||||
|
await page.authenticate({ username: account.proxy.username, password: account.proxy.password })
|
||||||
|
|
||||||
log('MAIN', 'Starting MOBILE browser')
|
log('MAIN', 'Starting MOBILE browser')
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,12 @@
|
|||||||
export interface Account {
|
export interface Account {
|
||||||
email: string;
|
email: string;
|
||||||
password: string;
|
password: string;
|
||||||
|
proxy: AccountProxy;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface AccountProxy {
|
||||||
|
url: string;
|
||||||
|
port: number;
|
||||||
|
password: string;
|
||||||
|
username: string;
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,9 @@
|
|||||||
import * as fs from 'fs'
|
import * as fs from 'fs'
|
||||||
import path from 'path'
|
import path from 'path'
|
||||||
|
|
||||||
export async function loadAccounts() {
|
import { Account } from '../interface/Account'
|
||||||
|
|
||||||
|
export async function loadAccounts(): Promise<Account[]> {
|
||||||
try {
|
try {
|
||||||
let file = 'accounts.json'
|
let file = 'accounts.json'
|
||||||
|
|
||||||
|
|||||||
@@ -81,7 +81,7 @@ export async function getEdgeVersions() {
|
|||||||
|
|
||||||
export function getSystemComponents(mobile: boolean): string {
|
export function getSystemComponents(mobile: boolean): string {
|
||||||
const osId: string = mobile ? 'Linux' : 'Windows NT 10.0'
|
const osId: string = mobile ? 'Linux' : 'Windows NT 10.0'
|
||||||
const uaPlatform: string = mobile ? 'Android 10' : 'Win64; x64'
|
const uaPlatform: string = mobile ? 'Android 13' : 'Win64; x64'
|
||||||
|
|
||||||
if (mobile) {
|
if (mobile) {
|
||||||
return `${uaPlatform}; ${osId}; K`
|
return `${uaPlatform}; ${osId}; K`
|
||||||
@@ -90,7 +90,6 @@ export function getSystemComponents(mobile: boolean): string {
|
|||||||
return `${uaPlatform}; ${osId}`
|
return `${uaPlatform}; ${osId}`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export async function getAppComponents(mobile: boolean) {
|
export async function getAppComponents(mobile: boolean) {
|
||||||
const versions = await getEdgeVersions()
|
const versions = await getEdgeVersions()
|
||||||
const edgeVersion = mobile ? versions.android : versions.windows as string
|
const edgeVersion = mobile ? versions.android : versions.windows as string
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ export async function wait(ms: number): Promise<void> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getFormattedDate(ms = Date.now()) {
|
export function getFormattedDate(ms = Date.now()): string {
|
||||||
const today = new Date(ms)
|
const today = new Date(ms)
|
||||||
const month = String(today.getMonth() + 1).padStart(2, '0') // January is 0
|
const month = String(today.getMonth() + 1).padStart(2, '0') // January is 0
|
||||||
const day = String(today.getDate()).padStart(2, '0')
|
const day = String(today.getDate()).padStart(2, '0')
|
||||||
@@ -21,7 +21,7 @@ export function shuffleArray<T>(array: T[]): T[] {
|
|||||||
return shuffledArray
|
return shuffledArray
|
||||||
}
|
}
|
||||||
|
|
||||||
export function randomNumber(min: number, max: number) {
|
export function randomNumber(min: number, max: number): number {
|
||||||
return Math.floor(Math.random() * (max - min + 1)) + min
|
return Math.floor(Math.random() * (max - min + 1)) + min
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user