mirror of
https://github.com/TheNetsky/Microsoft-Rewards-Script.git
synced 2026-01-11 10:56:17 +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] Emulated Scrolling Support
|
||||
- [x] Emulated Link Clicking Support
|
||||
- [x] Geo Locale Search Queries
|
||||
- [x] Completing Daily Set
|
||||
- [x] Completing More Promotions
|
||||
- [x] Solving Quiz (10 point variant)
|
||||
@@ -36,7 +37,7 @@ Under development, however mainly for personal use!
|
||||
- [ ] Completing Shopping Game
|
||||
- [ ] Completing Gaming Tab
|
||||
- [x] Clustering Support
|
||||
- [ ] Proxy Support
|
||||
- [x] Proxy Support
|
||||
|
||||
## Disclaimer ##
|
||||
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",
|
||||
"version": "1.2.0",
|
||||
"version": "1.2.1",
|
||||
"description": "Automatically do tasks for Microsoft Rewards but in TS!",
|
||||
"main": "index.js",
|
||||
"engines": {
|
||||
|
||||
@@ -1,10 +1,22 @@
|
||||
[
|
||||
{
|
||||
"email": "email_1",
|
||||
"password": "password_1"
|
||||
"password": "password_1",
|
||||
"proxy": {
|
||||
"url": "",
|
||||
"port": 0,
|
||||
"username": "",
|
||||
"password": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"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 StealthPlugin from 'puppeteer-extra-plugin-stealth'
|
||||
import stealthPlugin from 'puppeteer-extra-plugin-stealth'
|
||||
|
||||
import { getUserAgent } from '../util/UserAgent'
|
||||
import { loadSesion } from './BrowserFunc'
|
||||
|
||||
import { AccountProxy } from '../interface/Account'
|
||||
|
||||
import { headless } from '../config.json'
|
||||
|
||||
puppeteer.use(StealthPlugin())
|
||||
puppeteer.use(stealthPlugin())
|
||||
|
||||
class Browser {
|
||||
|
||||
async createBrowser(email: string, isMobile: boolean) {
|
||||
async createBrowser(email: string, proxy: AccountProxy, isMobile: boolean) {
|
||||
const userAgent = await getUserAgent(isMobile)
|
||||
|
||||
const browser = await puppeteer.launch({
|
||||
@@ -21,7 +23,8 @@ class Browser {
|
||||
'--mute-audio',
|
||||
'--disable-setuid-sandbox',
|
||||
`--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 fs from 'fs'
|
||||
import path from 'path'
|
||||
import { load } from 'cheerio'
|
||||
import { CheerioAPI, load } from 'cheerio'
|
||||
|
||||
import { tryDismissAllMessages, tryDismissCookieBanner } from './BrowserUtil'
|
||||
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 {
|
||||
await page.waitForSelector('#rqHeaderCredits', { visible: true, timeout: 5000 })
|
||||
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 {
|
||||
await page.waitForSelector('#quizCompleteContainer', { visible: true, timeout: 1000 })
|
||||
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 $ = load(html)
|
||||
|
||||
return $
|
||||
}
|
||||
|
||||
export async function getPunchCardActivity(page: Page, activity: PromotionalItem | MorePromotion) {
|
||||
export async function getPunchCardActivity(page: Page, activity: PromotionalItem | MorePromotion): Promise<string> {
|
||||
let selector = ''
|
||||
try {
|
||||
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 {
|
||||
await wait(500)
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"baseURL": "https://rewards.bing.com",
|
||||
"sessionPath": "sessions",
|
||||
"headless": false,
|
||||
"runOnZeroPoints": false,
|
||||
"runOnZeroPoints": true,
|
||||
"clusters": 1,
|
||||
"workers": {
|
||||
"doDailySet": true,
|
||||
@@ -12,6 +12,7 @@
|
||||
"doMobileSearch": true
|
||||
},
|
||||
"searchSettings": {
|
||||
"useGeoLocaleQueries": false,
|
||||
"scrollRandomResults": true,
|
||||
"clickRandomResults": true
|
||||
},
|
||||
|
||||
@@ -157,13 +157,14 @@ async function solveActivities(page: Page, activities: PromotionalItem[] | MoreP
|
||||
await doUrlReward(activityPage)
|
||||
break
|
||||
|
||||
// Misc
|
||||
// Misc, Usually UrlReward Type
|
||||
default:
|
||||
log('ACTIVITY', `Found activity type: "Misc" title: "${activity.title}"`)
|
||||
await doUrlReward(activityPage)
|
||||
break
|
||||
}
|
||||
|
||||
// Cooldown
|
||||
await wait(1500)
|
||||
} catch (error) {
|
||||
log('ACTIVITY', 'An error occurred:' + error, 'error')
|
||||
|
||||
@@ -13,10 +13,6 @@ import { GoogleTrends } from '../../interface/GoogleDailyTrends'
|
||||
import { GoogleSearch } from '../../interface/Search'
|
||||
|
||||
export async function doSearch(page: Page, data: DashboardData, mobile: boolean) {
|
||||
const locale = await page.evaluate(() => {
|
||||
return navigator.language
|
||||
})
|
||||
|
||||
log('SEARCH-BING', 'Starting bing 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
|
||||
let googleSearchQueries = await getGoogleTrends(locale, missingPoints) as GoogleSearch[]
|
||||
let googleSearchQueries = await getGoogleTrends(data.userProfile.attributes.country, missingPoints)
|
||||
googleSearchQueries = shuffleArray(googleSearchQueries)
|
||||
|
||||
// Deduplicate the search terms
|
||||
@@ -185,10 +181,14 @@ async function bingSearch(page: Page, searchPage: Page, query: string) {
|
||||
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[] = []
|
||||
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) {
|
||||
i += 1
|
||||
const date = new Date()
|
||||
@@ -197,7 +197,7 @@ async function getGoogleTrends(locale: string, queryCount: number): Promise<Goog
|
||||
|
||||
try {
|
||||
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',
|
||||
headers: {
|
||||
'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.
|
||||
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()
|
||||
|
||||
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 (lastTabURL.hostname !== searchListingURL.hostname) {
|
||||
|
||||
@@ -2,9 +2,9 @@ import { Page } from 'puppeteer'
|
||||
|
||||
import { wait } from '../../util/Utils'
|
||||
import { log } from '../../util/Logger'
|
||||
import { getQuizData } from '../../browser/BrowserFunc'
|
||||
|
||||
export async function doThisOrThat(page: Page) {
|
||||
return // Todo
|
||||
log('THIS-OR-THAT', 'Trying to complete ThisOrThat')
|
||||
|
||||
try {
|
||||
@@ -22,6 +22,8 @@ export async function doThisOrThat(page: Page) {
|
||||
await wait(2000)
|
||||
|
||||
// Solving
|
||||
const quizData = await getQuizData(page)
|
||||
quizData // correctAnswer property is always null?
|
||||
|
||||
log('THIS-OR-THAT', 'Completed the ThisOrthat successfully')
|
||||
} catch (error) {
|
||||
|
||||
24
src/index.ts
24
src/index.ts
@@ -2,6 +2,7 @@ import cluster from 'cluster'
|
||||
|
||||
import Browser from './browser/Browser'
|
||||
import { getDashboardData, getEarnablePoints, goHome } from './browser/BrowserFunc'
|
||||
|
||||
import { log } from './util/Logger'
|
||||
import { loadAccounts } from './util/Account'
|
||||
import { chunkArray } from './util/Utils'
|
||||
@@ -102,8 +103,18 @@ class MicrosoftRewardsBot {
|
||||
|
||||
// Desktop
|
||||
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()
|
||||
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')
|
||||
|
||||
@@ -156,8 +167,17 @@ class MicrosoftRewardsBot {
|
||||
|
||||
// Mobile
|
||||
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()
|
||||
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')
|
||||
|
||||
|
||||
@@ -1,4 +1,12 @@
|
||||
export interface Account {
|
||||
email: 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 path from 'path'
|
||||
|
||||
export async function loadAccounts() {
|
||||
import { Account } from '../interface/Account'
|
||||
|
||||
export async function loadAccounts(): Promise<Account[]> {
|
||||
try {
|
||||
let file = 'accounts.json'
|
||||
|
||||
|
||||
@@ -81,7 +81,7 @@ export async function getEdgeVersions() {
|
||||
|
||||
export function getSystemComponents(mobile: boolean): string {
|
||||
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) {
|
||||
return `${uaPlatform}; ${osId}; K`
|
||||
@@ -90,7 +90,6 @@ export function getSystemComponents(mobile: boolean): string {
|
||||
return `${uaPlatform}; ${osId}`
|
||||
}
|
||||
|
||||
|
||||
export async function getAppComponents(mobile: boolean) {
|
||||
const versions = await getEdgeVersions()
|
||||
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 month = String(today.getMonth() + 1).padStart(2, '0') // January is 0
|
||||
const day = String(today.getDate()).padStart(2, '0')
|
||||
@@ -21,7 +21,7 @@ export function shuffleArray<T>(array: T[]): T[] {
|
||||
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
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user