├── .github
├── scripts
│ ├── cat_logs.sh
│ ├── common.py
│ ├── eligible_accounts.py
│ └── illegal_tries.py
└── workflows
│ └── display_logs.yml
├── .gitignore
├── LICENSE
├── README.md
├── clean_mem.sh
├── cron.tab
├── install.sh
├── logs
├── init
├── log_1
├── log_10
├── log_11
├── log_12
├── log_13
├── log_14
├── log_15
├── log_16
├── log_17
├── log_18
├── log_2
├── log_3
├── log_4
├── log_5
├── log_6
├── log_7
├── log_8
└── log_9
├── ms_rewards.log
├── ms_rewards_farmer.py
├── requirements.txt
├── scripts
└── upgrade_browser.sh
├── ss.sh
└── upload_log.sh
/.github/scripts/cat_logs.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | PROJECT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && cd ../.. && pwd)"
3 |
4 | for file in ${PROJECT_DIR}/logs/log*
5 | do
6 | echo $file
7 | cat $file
8 | done
--------------------------------------------------------------------------------
/.github/scripts/common.py:
--------------------------------------------------------------------------------
1 | import json
2 | import os
3 |
4 | LOG_PREFIX = "log_"
5 |
6 | LOG_TO_INSTANCE = {
7 | "1": "o-ubuntu",
8 | "2": "o-opc",
9 | "3": "msr001",
10 | "4": "us2",
11 | "5": "us3",
12 | "6": "us32",
13 | "7": "us4",
14 | "8": "us42",
15 | "9": "us43",
16 | "10": "us5",
17 | "11": "us41",
18 | "12": "us51",
19 | "13": "us52",
20 | "14": "us53",
21 | "15": "us6",
22 | "16": "us61",
23 | "17": "msr_free",
24 | "18": "salt.li_free"
25 | }
26 |
27 | MACHINE_TO_ACCOUNT = {
28 | #template
29 | "": {
30 | "edge":"",
31 | "chrome":"",
32 | "firefox":"",
33 | "yandex":"",
34 | "opera":"",
35 | "vivaldi":"",
36 | "comodo_icedragon":"",
37 | "slimbrowser":"",
38 | "maxthon":"",
39 | "waterfox":"",
40 | "brave":"",
41 | "seamonkey":"",
42 | "lunascape":"",
43 | "midori":"",
44 | "ur":"",
45 | "pale_moon":"",
46 | "srware_iron":"",
47 | "slimjet":"",
48 | "avg":"",
49 | "liebao":"",
50 | "cent":"",
51 | "theworld":"",
52 | },
53 | "macP_win1022H2": {
54 | "edge":"lysdgrmr@outlook.com",
55 | "chrome":"ktlftboh@outlook.com",
56 | "firefox":"smcinqjj@outlook.com",
57 | "yandex":"bncpiwkk@outlook.com",
58 | "opera":"glggvmgc@outlook.com",
59 | "vivaldi":"gcxdrwqd@outlook.com",
60 | "comodo_icedragon":"qcumuyjj@outlook.com",
61 | "slimbrowser":"gimfumsk@outlook.com",
62 | "maxthon":"ookknadg@outlook.com",
63 | "waterfox":"pmceuitf@outlook.com",
64 | "brave":"tpsgjuvw@outlook.com",
65 | "seamonkey":"ynhudhwm@outlook.com",
66 | "lunascape":"ztbsqsft@outlook.com",
67 | "midori":"unfdhqgm@outlook.com",
68 | "ur":"vckoyirs@outlook.com",
69 | "pale_moon":"mlfyfjgw@outlook.com",
70 | "srware_iron":"tlwesqjg@outlook.com ",
71 | "slimjet":"oxutorhw@outlook.com",
72 | "avg":"dcpnzssa@outlook.com",
73 | "liebao":"ardjjelo@outlook.com",
74 | "cent":"elftxvvs@outlook.com",
75 | "theworld":"",
76 | },
77 | "miHyper_win1022H2": {
78 | "edge":"",
79 | "chrome":"fvevijqg@outlook.com",
80 | "firefox":"",
81 | "yandex":"huqafhdp@outlook.com",
82 | "opera":"rjkiwmjl@outlook.com",
83 | "vivaldi":"ejvkbmpr@outlook.com",
84 | "comodo_icedragon":"wdkdqndc@outlook.com",
85 | "slimbrowser":"bnhrqspr@outlook.com",
86 | "maxthon":"coprnbbt@outlook.com",
87 | "waterfox":"qnxwkvcs@outlook.com",
88 | "brave":"joothsto@outlook.com",
89 | "seamonkey":"wgdzzlnm@outlook.com",
90 | "lunascape":"dicxdycq@outlook.com",
91 | "midori":"pjysssqw@outlook.com",
92 | "ur":"vqkufecw@outlook.com",
93 | "pale_moon":"",
94 | "srware_iron":"",
95 | "slimjet":"spxbtglt@outlook.com",
96 | "avg":"lfsqfgnp@outlook.com",
97 | "liebao":"",
98 | "cent":"nipexfsj@outlook.com",
99 | "theworld":"nhywkmfn@outlook.com",
100 | },
101 | "miHyper_win7": {
102 | "edge":"fcbsqnjg@outlook.com",
103 | "chrome":"cthinvmh@outlook.com",
104 | "firefox":"",
105 | "yandex":"jboqcenv@outlook.com",
106 | "opera":"fxfyxblj@outlook.com",
107 | "vivaldi":"wcpxwrcn@outlook.com",
108 | "comodo_icedragon":"wigpbsoy@outlook.com",
109 | "slimbrowser":"rvyujeks@outlook.com",
110 | "maxthon":"iebtfdkf@outlook.com",
111 | "waterfox":"emqovroe@outlook.com",
112 | "brave":"iejvease@outlook.com",
113 | "seamonkey":"",
114 | "lunascape":"",
115 | "midori":"",
116 | "ur":"",
117 | "pale_moon":"",
118 | "srware_iron":"",
119 | "slimjet":"",
120 | "avg":"",
121 | "liebao":"",
122 | "cent":"",
123 | "theworld":"",
124 | },
125 | "mac_origin": {
126 | "chrome":"ymizpwly@outlook.com",
127 | "chrome2":"wotfvcat@outlook.com",
128 | "safari":"jmbltatj@outlook.com",
129 | "brave":"",
130 | },
131 | }
132 |
133 | MACHINE_PRIORITY = {
134 | "macP_win1022H2": 1,
135 | "miHyper_win1022H2": 2,
136 | "miHyper_win7":3,
137 | "mac_origin": 4,
138 | }
139 |
140 | ACCOUNT_TO_MACHINE = {}
141 |
142 | def init_account_to_machine_for_once():
143 | if len(ACCOUNT_TO_MACHINE) != 0:
144 | return
145 | for machine, browser_to_account in MACHINE_TO_ACCOUNT.items():
146 | if len(machine) == 0:
147 | continue
148 | for browser, account in browser_to_account.items():
149 | ACCOUNT_TO_MACHINE[account] = {
150 | "browser": browser,
151 | "machine": machine,
152 | }
153 |
154 |
155 |
156 | ACCOUNT_REGION = {
157 | }
158 |
159 | class LogFile:
160 | def __init__(self, name, content):
161 | self.file_name = name
162 | self.json_obj = content
163 |
164 | def get_log_location(file_name):
165 | start = len(LOG_PREFIX)
166 | file_index = file_name[start:]
167 | if file_index in LOG_TO_INSTANCE:
168 | return f'instance: {LOG_TO_INSTANCE[file_index]}'
169 | return f'log: {file_name}'
170 |
171 | def get_account_region(account):
172 | if account in ACCOUNT_REGION:
173 | return ACCOUNT_REGION[account]
174 | return "us"
175 |
176 | def get_account_machine(account):
177 | init_account_to_machine_for_once()
178 | if account not in ACCOUNT_TO_MACHINE:
179 | return ""
180 | account_info = ACCOUNT_TO_MACHINE[account]
181 | return f'[{account_info["machine"]}][{account_info["browser"]}]'
182 |
183 | def get_account_priority(account):
184 | init_account_to_machine_for_once()
185 | if account not in ACCOUNT_TO_MACHINE:
186 | return 0
187 | machine = ACCOUNT_TO_MACHINE[account]["machine"]
188 | if len(machine) == 0:
189 | print("[ERROR]", "account:", account, "has invalid 'machine' field configured in ACCOUNT_TO_MACHINE")
190 | return 0
191 |
192 | if machine not in MACHINE_PRIORITY:
193 | print("[ERROR]", "machine:", machine, "is not configured in MACHINE_PRIORITY")
194 | return 0
195 | return MACHINE_PRIORITY[machine]
196 |
197 | def read_logs_to(func):
198 | '''
199 | call the internal func with LogFile
200 | '''
201 | log_dir = os.path.abspath(os.path.join(os.path.abspath(__file__), "../../../logs"))
202 | files= os.listdir(log_dir)
203 | for file in files:
204 | if os.path.isdir(file) or not file.startswith(LOG_PREFIX):
205 | continue
206 | with open(log_dir+"/"+file) as input:
207 | json_obj = json.load(input)
208 | func(LogFile(file, json_obj))
--------------------------------------------------------------------------------
/.github/scripts/eligible_accounts.py:
--------------------------------------------------------------------------------
1 | from common import read_logs_to, get_log_location, get_account_region, get_account_priority, get_account_machine
2 |
3 | REGION_POINT_BAR = {
4 | "sg": 9100,
5 | "us": 13000,
6 | }
7 |
8 | priority_print = {}
9 |
10 | def append_ele_to_dict_of_list(map, key, value):
11 | to_set_list = []
12 | if key in map:
13 | to_set_list = map[key]
14 | to_set_list.append(value)
15 | map[key] = to_set_list
16 |
17 |
18 | def get_eligible_accounts(obj):
19 | '''
20 | :input: LogFile
21 | '''
22 | filename = obj.file_name
23 | json_obj = obj.json_obj
24 | location = get_log_location(filename)
25 | for key, val in json_obj.items():
26 | region = get_account_region(key)
27 | if isinstance(val["Points"], int) and val["Points"] > REGION_POINT_BAR[region]:
28 | priority = get_account_priority(key)
29 | # Region logic isn't used for now
30 | if priority == 0:
31 | append_ele_to_dict_of_list(priority_print, priority,
32 | f'[need verify] account: {key} -> points:{val["Points"]} from {location}|{region}')
33 | continue
34 | machine = get_account_machine(key)
35 | append_ele_to_dict_of_list(priority_print, priority,
36 | f'{machine} account: {key} -> points:{val["Points"]} from {location}| {region}')
37 |
38 | def print_logs_in_priority():
39 | for priority in sorted(priority_print.keys()):
40 | logs = priority_print[priority]
41 | for log in logs:
42 | print(log)
43 |
44 | read_logs_to(get_eligible_accounts)
45 | print_logs_in_priority()
46 |
--------------------------------------------------------------------------------
/.github/scripts/illegal_tries.py:
--------------------------------------------------------------------------------
1 | from common import read_logs_to, get_log_location
2 | from datetime import date, timedelta
3 |
4 | def get_illegal_tries(obj):
5 | '''
6 | :input: LogFile
7 | '''
8 | filename = obj.file_name
9 | json_obj = obj.json_obj
10 | today = str((date.today()))
11 | yesterday = str((date.today() - timedelta(days = 1)))
12 | location = get_log_location(filename)
13 | for key, val in json_obj.items():
14 | check_situation = val["Last check"]
15 | if len(check_situation) != 10 or check_situation[0] != "2":
16 | print(f'abnormal operation: account: {key} -> check:{check_situation} of {filename} in {location}')
17 | continue
18 | if check_situation != yesterday and check_situation != today:
19 | print(f'outdated log: account: {key} -> last time updated:{check_situation} of {filename} in {location}')
20 | continue
21 |
22 | read_logs_to(get_illegal_tries)
--------------------------------------------------------------------------------
/.github/workflows/display_logs.yml:
--------------------------------------------------------------------------------
1 | name: Display all the logs
2 | on: [push]
3 | jobs:
4 | Display-All-The-Logs:
5 | runs-on: ubuntu-latest
6 | steps:
7 | - name: Check out repository code
8 | uses: actions/checkout@v3
9 | - uses: actions/setup-python@v4
10 | with:
11 | python-version: '3.7'
12 | - name: Display all the logs
13 | run: |
14 | cd ${{ github.workspace }}
15 | bash .github/scripts/cat_logs.sh
16 | - name: Display illegal tries
17 | run: |
18 | cd ${{ github.workspace }}
19 | python3 .github/scripts/illegal_tries.py
20 | - name: Display eligible accounts
21 | run: |
22 | cd ${{ github.workspace }}
23 | python3 .github/scripts/eligible_accounts.py
24 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.json
2 | *.txt
3 | .vscode
4 | chromedriver.exe
5 | env
6 | *.deb
7 | __pycache__
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 Farshad Zargari
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | ███╗ ███╗███████╗ ███████╗ █████╗ ██████╗ ███╗ ███╗███████╗██████╗
10 | ████╗ ████║██╔════╝ ██╔════╝██╔══██╗██╔══██╗████╗ ████║██╔════╝██╔══██╗
11 | ██╔████╔██║███████╗ █████╗ ███████║██████╔╝██╔████╔██║█████╗ ██████╔╝
12 | ██║╚██╔╝██║╚════██║ ██╔══╝ ██╔══██║██╔══██╗██║╚██╔╝██║██╔══╝ ██╔══██╗
13 | ██║ ╚═╝ ██║███████║ ██║ ██║ ██║██║ ██║██║ ╚═╝ ██║███████╗██║ ██║
14 | ╚═╝ ╚═╝╚══════╝ ╚═╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝
15 | built by @charlesbel upgraded by @farshadz1997 version 2.0
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 | 👋 Welcome to the future of automation
24 | A simple bot that uses selenium to farm Microsoft Rewards written in Python.
25 |
26 | Installation
27 | You can also find this repository on Gitlab.
28 |
29 |
30 | - Install requirements with the following command :
pip install -r requirements.txt
31 | - Make sure you have Chrome installed
32 | - Install ChromeDriver :
33 | - Windows :
34 | - Download Chrome WebDriver as same as your Google Chrome version : https://chromedriver.chromium.org/downloads
35 | - Place the file in X:\Windows (X as your Windows disk letter)
36 |
37 | - MacOS or Linux :
41 |
42 | - Edit the accounts.json.sample with your accounts credentials and rename it by removing .sample at the end
43 | If you want to add more than one account, the syntax is the following (mobile_user_agent
is optional): [{
44 | "username": "Your Email",
45 | "password": "Your Password",
46 | "mobile_user_agent": "your preferred mobile user agent"
47 | },
48 | {
49 | "username": "Your Email 2",
50 | "password": "Your Password 2",
51 | "mobile_user_agent": "your preferred mobile user agent"
52 | }]
53 | - Due to limits of Ipapi sometimes it returns error and it causes bot stops. So you can define default language and location to prevent it from
54 | here.
55 | - Run the script
56 |
57 | - Use optinal arguments
58 |
59 | --headless
You can use this argument to run the script in headless mode.
60 | --session
Use this argument to create session for each account.
61 | --everyday TIME
This argument takes time in 24h format (HH:MM) to run it everyday at the given time by leaving the program open.
62 | --fast
This argument reduces delays of script and make it faster (use this if you have high speed connection).
63 | --error
When you use this argument, app displays crash error in terminal when it fails.
64 | - For example type in your terminal
python ms_rewards_farmer.py --everyday 14:30 --fast --session
You don't need to use all of arguments.
65 |
66 | - Run the script normally that session and headless disabled and it asks you to input a time if you want to run it at a specific time.
67 |
68 |
69 |
70 |
71 | Features
72 |
73 |
74 | - Bing searches (Desktop, Mobile and Edge) with User-Agents
75 | - Complete automatically the daily set
76 | - Complete automatically punch cards
77 | - Complete automatically the others promotions
78 | - Headless Mode
79 | - Multi-Account Management
80 | - Modified to be undetectable as bot
81 | - If it faces to an unexpected error then try the account from first
82 | - Save progress of bot in a log file and use it to pass completed account on the next start at the same day
83 | - Detect suspended accounts
84 | - Detect locked accounts
85 | - Detect unusual activites
86 | - Uses time out to prevent infinite loop
87 | - You can assign custom user-agent for mobile like above example
88 | - Set clock to start it at specific time
89 | - For Bing search it uses random word at first try and if api failed then it uses google trends
90 |
91 |
92 | ⚠️CAUTION!⚠️
93 |
94 |
Do not use headless mode, it can cause your account to be suspended from Microsoft Rewards.
95 |
--------------------------------------------------------------------------------
/clean_mem.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | pkill -9 python
3 | pkill -9 Xvfb
4 | pkill -9 chrome
--------------------------------------------------------------------------------
/cron.tab:
--------------------------------------------------------------------------------
1 | 10 8 * * * /usr/bin/sh /home/saltleemsr/src/Microsoft-Rewards-bot/clean_mem.sh
2 | 11 8 * * * /usr/bin/python3 /home/saltleemsr/src/Microsoft-Rewards-bot/ms_rewards_farmer.py >> /home/saltleemsr/src/Microsoft-Rewards-bot/cron.log
3 | 0 1 * * * bash /home/saltleemsr/src/Microsoft-Rewards-bot/upload_log.sh 0
4 |
5 | sudo apt-get --only-upgrade install google-chrome-stable
--------------------------------------------------------------------------------
/install.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | sudo apt-get update -y
3 | sudo apt-get install -y xvfb
4 | wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb
5 | sudo apt install -y ./google-chrome-stable_current_amd64.deb
6 | sudo apt install -y chromium-chromedriver
7 | sudo apt-get -y install python3-pip
8 | sudo pip3 install -r requirements.txt
9 | # incompatible lib fix
10 | sudo pip3 uninstall --yes chardet
11 | sudo pip3 uninstall --yes urllib3
12 | sudo pip3 install --upgrade requests --no-input
13 | # sys log storage up-limit
14 | sudo journalctl --vacuum-size=100M
15 | sudo touch accounts.json
--------------------------------------------------------------------------------
/logs/init:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/macrosalt/Microsoft-Rewards-bot/bf851e5761f583fff48a1bef481638ae57df6c8f/logs/init
--------------------------------------------------------------------------------
/logs/log_1:
--------------------------------------------------------------------------------
1 | {
2 | "gimfumsk@outlook.com": {
3 | "Last check": "Unknown error: Microsoft account notice !",
4 | "Today's points": 320,
5 | "Points": 25715,
6 | "Daily": false,
7 | "Punch cards": false,
8 | "More promotions": false,
9 | "PC searches": false
10 | },
11 | "ookknadg@outlook.com": {
12 | "Last check": "Unknown error: Microsoft account notice !",
13 | "Today's points": 340,
14 | "Points": 12381,
15 | "Daily": false,
16 | "Punch cards": false,
17 | "More promotions": false,
18 | "PC searches": false
19 | },
20 | "wotfvcat@outlook.com": {
21 | "Last check": "Unknown error: Microsoft account notice !",
22 | "Today's points": 275,
23 | "Points": 15066,
24 | "Daily": false,
25 | "Punch cards": false,
26 | "More promotions": false,
27 | "PC searches": false
28 | },
29 | "bocpsbvb@outlook.com": {
30 | "Last check": "2024-07-23",
31 | "Today's points": 330,
32 | "Points": 8718,
33 | "Daily": false,
34 | "Punch cards": false,
35 | "More promotions": false,
36 | "PC searches": false
37 | }
38 | }
--------------------------------------------------------------------------------
/logs/log_10:
--------------------------------------------------------------------------------
1 | {
2 | "joothsto@outlook.com": {
3 | "Last check": "Your account has been locked !",
4 | "Today's points": 5976,
5 | "Points": 30202
6 | },
7 | "nipexfsj@outlook.com": {
8 | "Last check": "Unknown error: Sign in to your Microsoft account !",
9 | "Today's points": 335,
10 | "Points": 19383,
11 | "Daily": false,
12 | "Punch cards": false,
13 | "More promotions": false,
14 | "PC searches": false
15 | },
16 | "jboqcenv@outlook.com": {
17 | "Last check": "Unknown error: Sign in to your Microsoft account !",
18 | "Today's points": 365,
19 | "Points": 8867
20 | },
21 | "rvyujeks@outlook.com": {
22 | "Last check": "Unknown error: Sign in to your Microsoft account !",
23 | "Today's points": 19260,
24 | "Points": 28127
25 | }
26 | }
--------------------------------------------------------------------------------
/logs/log_11:
--------------------------------------------------------------------------------
1 | {
2 | "ymizpwly@outlook.com": {
3 | "Last check": "Unknown error: Microsoft account privacy notice !",
4 | "Today's points": 33363,
5 | "Points": 33363
6 | },
7 | "qnxwkvcs@outlook.com": {
8 | "Last check": "Unknown error: Microsoft account privacy notice !",
9 | "Today's points": 305,
10 | "Points": 31803
11 | },
12 | "rmslyruy@outlook.com": {
13 | "Last check": "Unknown error: Microsoft account privacy notice !",
14 | "Today's points": 350,
15 | "Points": 35107,
16 | "Daily": false,
17 | "Punch cards": false,
18 | "More promotions": false,
19 | "PC searches": false
20 | },
21 | "lejhdeey@outlook.com": {
22 | "Last check": "Unknown error: Microsoft account privacy notice !",
23 | "Today's points": 355,
24 | "Points": 20664
25 | }
26 | }
--------------------------------------------------------------------------------
/logs/log_12:
--------------------------------------------------------------------------------
1 | {
2 | "tlwesqjg@outlook.com": {
3 | "Last check": "2023-06-13",
4 | "Today's points": 375,
5 | "Points": 51783,
6 | "Daily": false,
7 | "Punch cards": false,
8 | "More promotions": false,
9 | "PC searches": false
10 | },
11 | "dicxdycq@outlook.com": {
12 | "Last check": "Your account has been locked !",
13 | "Today's points": -14720,
14 | "Points": 13362,
15 | "Daily": false,
16 | "Punch cards": false,
17 | "More promotions": false,
18 | "PC searches": false
19 | },
20 | "cthinvmh@outlook.com": {
21 | "Last check": "Unknown error: Microsoft account privacy notice !",
22 | "Today's points": -19795,
23 | "Points": 31613,
24 | "Daily": false,
25 | "Punch cards": false,
26 | "More promotions": false,
27 | "PC searches": false
28 | },
29 | "vhldgkyv@outlook.com": {
30 | "Last check": "2023-05-30",
31 | "Today's points": -16300,
32 | "Points": 35483,
33 | "Daily": false,
34 | "Punch cards": false,
35 | "More promotions": false,
36 | "PC searches": false
37 | }
38 | }
--------------------------------------------------------------------------------
/logs/log_13:
--------------------------------------------------------------------------------
1 | {
2 | "wgdzzlnm@outlook.com": {
3 | "Last check": "Unknown error: Microsoft account privacy notice !",
4 | "Today's points": 16708,
5 | "Points": 16708
6 | },
7 | "mthoklgd@outlook.com": {
8 | "Last check": "Unknown error: Microsoft account privacy notice !",
9 | "Today's points": 25334,
10 | "Points": 47563,
11 | "Daily": false,
12 | "Punch cards": false,
13 | "More promotions": false,
14 | "PC searches": false
15 | },
16 | "cloaveoc@outlook.com": {
17 | "Last check": "Unknown error: Microsoft account privacy notice !",
18 | "Today's points": 23199,
19 | "Points": 23199
20 | },
21 | "pzkxscig@outlook.com": {
22 | "Last check": "Your account has been suspended",
23 | "Today's points": "N/A",
24 | "Points": "N/A"
25 | }
26 | }
--------------------------------------------------------------------------------
/logs/log_14:
--------------------------------------------------------------------------------
1 | {
2 | "fvevijqg@outlook.com": {
3 | "Last check": "2023-05-30",
4 | "Today's points": -24707,
5 | "Points": 14313,
6 | "Daily": false,
7 | "Punch cards": false,
8 | "More promotions": false,
9 | "PC searches": false
10 | },
11 | "nhywkmfn@outlook.com": {
12 | "Last check": "Unknown error: Microsoft account privacy notice !",
13 | "Today's points": 395,
14 | "Points": 14378,
15 | "Daily": false,
16 | "Punch cards": false,
17 | "More promotions": false,
18 | "PC searches": false
19 | },
20 | "bnhrqspr@outlook.com": {
21 | "Last check": "2023-05-30",
22 | "Today's points": 330,
23 | "Points": 40843,
24 | "Daily": false,
25 | "Punch cards": false,
26 | "More promotions": false,
27 | "PC searches": false
28 | },
29 | "jbfqipsb@outlook.com": {
30 | "Last check": "2023-06-13",
31 | "Today's points": 385,
32 | "Points": 39020,
33 | "Daily": false,
34 | "Punch cards": false,
35 | "More promotions": false,
36 | "PC searches": false
37 | }
38 | }
--------------------------------------------------------------------------------
/logs/log_15:
--------------------------------------------------------------------------------
1 | {
2 | "dcpnzssa@outlook.com": {
3 | "Last check": "2023-05-30",
4 | "Today's points": -12989,
5 | "Points": 18420,
6 | "Daily": false,
7 | "Punch cards": false,
8 | "More promotions": false,
9 | "PC searches": false
10 | },
11 | "ardjjelo@outlook.com": {
12 | "Last check": "2023-05-30",
13 | "Today's points": 390,
14 | "Points": 20520,
15 | "Daily": false,
16 | "Punch cards": false,
17 | "More promotions": false,
18 | "PC searches": false
19 | },
20 | "chlsnyec@outlook.com": {
21 | "Last check": "2023-05-30",
22 | "Today's points": 330,
23 | "Points": 31409,
24 | "Daily": false,
25 | "Punch cards": false,
26 | "More promotions": false,
27 | "PC searches": false
28 | },
29 | "titicbpv@outlook.com": {
30 | "Last check": "2023-06-13",
31 | "Today's points": 315,
32 | "Points": 8713,
33 | "Daily": false,
34 | "Punch cards": false,
35 | "More promotions": false,
36 | "PC searches": false
37 | }
38 | }
--------------------------------------------------------------------------------
/logs/log_16:
--------------------------------------------------------------------------------
1 | {
2 | "coprnbbt@outlook.com": {
3 | "Last check": "2023-06-13",
4 | "Today's points": 330,
5 | "Points": 27468,
6 | "Daily": false,
7 | "Punch cards": false,
8 | "More promotions": false,
9 | "PC searches": false
10 | },
11 | "vckoyirs@outlook.com": {
12 | "Last check": "Unknown error: Microsoft account privacy notice !",
13 | "Today's points": 860,
14 | "Points": 27723,
15 | "Daily": false,
16 | "Punch cards": false,
17 | "More promotions": false,
18 | "PC searches": false
19 | },
20 | "smcinqjj@outlook.com": {
21 | "Last check": "Your account has been suspended",
22 | "Today's points": "N/A",
23 | "Points": "N/A"
24 | },
25 | "bncpiwkk@outlook.com": {
26 | "Last check": "Unknown error: Microsoft account privacy notice !",
27 | "Today's points": 375,
28 | "Points": 27048,
29 | "Daily": false,
30 | "Punch cards": false,
31 | "More promotions": false,
32 | "PC searches": false
33 | }
34 | }
--------------------------------------------------------------------------------
/logs/log_17:
--------------------------------------------------------------------------------
1 | {
2 | "jmbltatj@outlook.com": {
3 | "Last check": "2025-03-05",
4 | "Today's points": 24370,
5 | "Points": 24370,
6 | "Daily": false,
7 | "Punch cards": false,
8 | "More promotions": false,
9 | "PC searches": false
10 | },
11 | "pmceuitf@outlook.com": {
12 | "Last check": "Unknown error: Microsoft account notice !",
13 | "Today's points": -4860,
14 | "Points": 18825,
15 | "Daily": false,
16 | "Punch cards": false,
17 | "More promotions": false,
18 | "PC searches": false
19 | },
20 | "ztbsqsft@outlook.com": {
21 | "Last check": "Unknown error: Microsoft account notice !",
22 | "Today's points": 12320,
23 | "Points": 31145,
24 | "Daily": false,
25 | "Punch cards": false,
26 | "More promotions": false,
27 | "PC searches": false
28 | },
29 | "hotlhswh@outlook.com": {
30 | "Last check": "Unknown error: Microsoft account notice !",
31 | "Today's points": 510,
32 | "Points": 25187,
33 | "Daily": false,
34 | "Punch cards": false,
35 | "More promotions": false,
36 | "PC searches": false
37 | }
38 | }
--------------------------------------------------------------------------------
/logs/log_18:
--------------------------------------------------------------------------------
1 | {
2 | "emqovroe@outlook.com": {
3 | "Last check": "2023-07-07",
4 | "Today's points": 330,
5 | "Points": 38887,
6 | "Daily": false,
7 | "Punch cards": false,
8 | "More promotions": false,
9 | "PC searches": false
10 | },
11 | "iejvease@outlook.com": {
12 | "Last check": "Unknown error: Microsoft account privacy notice !",
13 | "Today's points": 375,
14 | "Points": 36742,
15 | "Daily": false,
16 | "Punch cards": false,
17 | "More promotions": false,
18 | "PC searches": false
19 | },
20 | "nyuhrcrx@outlook.com": {
21 | "Last check": "2023-05-30",
22 | "Today's points": 335,
23 | "Points": 65072,
24 | "Daily": false,
25 | "Punch cards": false,
26 | "More promotions": false,
27 | "PC searches": false
28 | },
29 | "cjubtkgo@outlook.com": {
30 | "Last check": "2023-05-30",
31 | "Today's points": 385,
32 | "Points": 56557,
33 | "Daily": false,
34 | "Punch cards": false,
35 | "More promotions": false,
36 | "PC searches": false
37 | }
38 | }
--------------------------------------------------------------------------------
/logs/log_2:
--------------------------------------------------------------------------------
1 | {
2 | "spxbtglt@outlook.com": {
3 | "Last check": "Unknown error: Microsoft account notice !",
4 | "Today's points": 365,
5 | "Points": 36898,
6 | "Daily": false,
7 | "Punch cards": false,
8 | "More promotions": false,
9 | "PC searches": false
10 | },
11 | "elftxvvs@outlook.com": {
12 | "Last check": "Unknown error: Microsoft account notice !",
13 | "Today's points": 410,
14 | "Points": 15238,
15 | "Daily": false,
16 | "Punch cards": false,
17 | "More promotions": false,
18 | "PC searches": false
19 | },
20 | "wigpbsoy@outlook.com": {
21 | "Last check": "2025-06-08",
22 | "Today's points": 450,
23 | "Points": 10677,
24 | "Daily": false,
25 | "Punch cards": false,
26 | "More promotions": false,
27 | "PC searches": false
28 | },
29 | "yisjuold@outlook.com": {
30 | "Last check": "Unknown error: Microsoft account notice !",
31 | "Today's points": 345,
32 | "Points": 11258,
33 | "Daily": false,
34 | "Punch cards": false,
35 | "More promotions": false,
36 | "PC searches": false
37 | }
38 | }
--------------------------------------------------------------------------------
/logs/log_3:
--------------------------------------------------------------------------------
1 | {
2 | "gcxdrwqd@outlook.com": {
3 | "Last check": "Unknown error: Sign in to your Microsoft account !",
4 | "Today's points": 330,
5 | "Points": 21995
6 | },
7 | "qcumuyjj@outlook.com": {
8 | "Last check": "Unknown error: Microsoft account privacy notice !",
9 | "Today's points": 416,
10 | "Points": 20545
11 | },
12 | "wcpxwrcn@outlook.com": {
13 | "Last check": "Unknown error: Microsoft account privacy notice !",
14 | "Today's points": 280,
15 | "Points": 14092
16 | },
17 | "iebtfdkf@outlook.com": {
18 | "Last check": "Unknown error: Microsoft account privacy notice !",
19 | "Today's points": 270,
20 | "Points": 14149,
21 | "Daily": false,
22 | "Punch cards": false,
23 | "More promotions": false,
24 | "PC searches": false
25 | }
26 | }
--------------------------------------------------------------------------------
/logs/log_4:
--------------------------------------------------------------------------------
1 | {
2 | "ktlftboh@outlook.com": {
3 | "Last check": "2023-06-13",
4 | "Today's points": 380,
5 | "Points": 16503,
6 | "Daily": false,
7 | "Punch cards": false,
8 | "More promotions": false,
9 | "PC searches": false
10 | },
11 | "oxutorhw@outlook.com": {
12 | "Last check": "Unknown error: Microsoft account privacy notice !",
13 | "Today's points": 13080,
14 | "Points": 29583,
15 | "Daily": false,
16 | "Punch cards": false,
17 | "More promotions": false,
18 | "PC searches": false
19 | },
20 | "unfdhqgm@outlook.com": {
21 | "Last check": "Unknown error: Microsoft account privacy notice !",
22 | "Today's points": -18840,
23 | "Points": 10368,
24 | "Daily": false,
25 | "Punch cards": false,
26 | "More promotions": false,
27 | "PC searches": false
28 | },
29 | "wgmulkec@outlook.com": {
30 | "Last check": "Your account has been suspended",
31 | "Today's points": "N/A",
32 | "Points": "N/A"
33 | }
34 | }
--------------------------------------------------------------------------------
/logs/log_5:
--------------------------------------------------------------------------------
1 | {
2 | "wdkdqndc@outlook.com": {
3 | "Last check": "2023-06-01",
4 | "Today's points": 375,
5 | "Points": 19868,
6 | "Daily": false,
7 | "Punch cards": false,
8 | "More promotions": false,
9 | "PC searches": false
10 | },
11 | "ynhudhwm@outlook.com": {
12 | "Last check": "2023-05-30",
13 | "Today's points": 370,
14 | "Points": 32843,
15 | "Daily": false,
16 | "Punch cards": false,
17 | "More promotions": false,
18 | "PC searches": false
19 | },
20 | "huqafhdp@outlook.com": {
21 | "Last check": "2023-05-30",
22 | "Today's points": -14275,
23 | "Points": 18568,
24 | "Daily": false,
25 | "Punch cards": false,
26 | "More promotions": false,
27 | "PC searches": false
28 | },
29 | "vmtgmjti@outlook.com": {
30 | "Last check": "Your account has been suspended",
31 | "Today's points": "N/A",
32 | "Points": "N/A"
33 | }
34 | }
--------------------------------------------------------------------------------
/logs/log_6:
--------------------------------------------------------------------------------
1 | {
2 | "rjkiwmjl@outlook.com": {
3 | "Last check": "2023-06-13",
4 | "Today's points": 415,
5 | "Points": 18823,
6 | "Daily": false,
7 | "Punch cards": false,
8 | "More promotions": false,
9 | "PC searches": false
10 | },
11 | "fcbsqnjg@outlook.com": {
12 | "Last check": "2023-05-30",
13 | "Today's points": 20924,
14 | "Points": 39747,
15 | "Daily": false,
16 | "Punch cards": false,
17 | "More promotions": false,
18 | "PC searches": false
19 | },
20 | "fxfyxblj@outlook.com": {
21 | "Last check": "2023-05-30",
22 | "Today's points": 13110,
23 | "Points": 52857,
24 | "Daily": false,
25 | "Punch cards": false,
26 | "More promotions": false,
27 | "PC searches": false
28 | },
29 | "ygbxznxy@outlook.com": {
30 | "Last check": "Unknown error: Microsoft account privacy notice !",
31 | "Today's points": -4062,
32 | "Points": 48005,
33 | "Daily": false,
34 | "Punch cards": false,
35 | "More promotions": false,
36 | "PC searches": false
37 | }
38 | }
--------------------------------------------------------------------------------
/logs/log_7:
--------------------------------------------------------------------------------
1 | {
2 | "ejvkbmpr@outlook.com": {
3 | "Last check": "Unknown error: Microsoft account privacy notice !",
4 | "Today's points": 385,
5 | "Points": 7850,
6 | "Daily": false,
7 | "Punch cards": false,
8 | "More promotions": false,
9 | "PC searches": false
10 | },
11 | "lfsqfgnp@outlook.com": {
12 | "Last check": "2023-05-30",
13 | "Today's points": 415,
14 | "Points": 36690,
15 | "Daily": false,
16 | "Punch cards": false,
17 | "More promotions": false,
18 | "PC searches": false
19 | },
20 | "vuorgvuj@outlook.com": {
21 | "Last check": "2023-06-13",
22 | "Today's points": 355,
23 | "Points": 37019,
24 | "Daily": false,
25 | "Punch cards": false,
26 | "More promotions": false,
27 | "PC searches": false
28 | },
29 | "rxqinlhb@outlook.com": {
30 | "Last check": "Your account has been suspended",
31 | "Today's points": "N/A",
32 | "Points": "N/A"
33 | }
34 | }
--------------------------------------------------------------------------------
/logs/log_8:
--------------------------------------------------------------------------------
1 | {
2 | "pjysssqw@outlook.com": {
3 | "Last check": "2023-06-13",
4 | "Today's points": 380,
5 | "Points": 29588,
6 | "Daily": false,
7 | "Punch cards": false,
8 | "More promotions": false,
9 | "PC searches": false
10 | },
11 | "wfaobymr@outlook.com": {
12 | "Last check": "2023-05-30",
13 | "Today's points": 54810,
14 | "Points": 54810,
15 | "Daily": false,
16 | "Punch cards": false,
17 | "More promotions": false,
18 | "PC searches": false
19 | },
20 | "csdmuvrk@outlook.com": {
21 | "Last check": "2023-05-30",
22 | "Today's points": -1875,
23 | "Points": 52935,
24 | "Daily": false,
25 | "Punch cards": false,
26 | "More promotions": false,
27 | "PC searches": false
28 | },
29 | "jsgxncdc@outlook.com": {
30 | "Last check": "Your account has been suspended",
31 | "Today's points": "N/A",
32 | "Points": "N/A"
33 | }
34 | }
--------------------------------------------------------------------------------
/logs/log_9:
--------------------------------------------------------------------------------
1 | {
2 | "tpsgjuvw@outlook.com": {
3 | "Last check": "2023-06-13",
4 | "Today's points": 415,
5 | "Points": 31858,
6 | "Daily": false,
7 | "Punch cards": false,
8 | "More promotions": false,
9 | "PC searches": false
10 | },
11 | "mlfyfjgw@outlook.com": {
12 | "Last check": "Unknown error: Microsoft account privacy notice !",
13 | "Today's points": 355,
14 | "Points": 25078,
15 | "Daily": false,
16 | "Punch cards": false,
17 | "More promotions": false,
18 | "PC searches": false
19 | },
20 | "qnxfhcwo@outlook.com": {
21 | "Last check": "2023-05-31",
22 | "Today's points": 330,
23 | "Points": 40758,
24 | "Daily": false,
25 | "Punch cards": false,
26 | "More promotions": false,
27 | "PC searches": false
28 | },
29 | "okihqbow@outlook.com": {
30 | "Last check": "2023-05-30",
31 | "Today's points": 24317,
32 | "Points": 56175,
33 | "Daily": false,
34 | "Punch cards": false,
35 | "More promotions": false,
36 | "PC searches": false
37 | }
38 | }
--------------------------------------------------------------------------------
/ms_rewards.log:
--------------------------------------------------------------------------------
1 | nohup: ignoring input
2 | sh: 1: color: not found
3 |
--------------------------------------------------------------------------------
/ms_rewards_farmer.py:
--------------------------------------------------------------------------------
1 | import time
2 | import json
3 | from datetime import date, timedelta, datetime
4 | import requests
5 | import random
6 | import urllib.parse
7 | import ipapi
8 | import os
9 | from random_word import RandomWords
10 | from func_timeout import func_set_timeout, FunctionTimedOut
11 | import subprocess
12 | import platform
13 | from argparse import ArgumentParser
14 | import sys
15 |
16 | from pyvirtualdisplay import Display
17 | from selenium import webdriver
18 | from selenium.webdriver.chrome.webdriver import WebDriver
19 | from selenium.webdriver.support.ui import WebDriverWait
20 | from selenium.webdriver.support import expected_conditions as ec
21 | from selenium.webdriver.common.by import By
22 | from selenium.common.exceptions import (NoSuchElementException, TimeoutException, ElementNotInteractableException,
23 | UnexpectedAlertPresentException, NoAlertPresentException, SessionNotCreatedException)
24 |
25 | # Define user-agents
26 | PC_USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.5195.102 Safari/537.36 Edg/105.0.1343.33'
27 | MOBILE_USER_AGENT = 'Mozilla/5.0 (Linux; Android 12; SM-N9750) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.5195.102 Mobile Safari/537.36'
28 |
29 | POINTS_COUNTER = 0
30 |
31 | # Global variables
32 | FINISHED_ACCOUNTS = [] # added accounts when finished or those have same date as today date in LOGS at beginning.
33 | ERROR = True # A flag for when error occurred.
34 | MOBILE = True # A flag for when the account has mobile bing search, it is useful for accounts level 1 to pass mobile.
35 | CURRENT_ACCOUNT = None # save current account into this variable when farming.
36 | LOGS = {} # Dictionary of accounts to write in 'logs_accounts.txt'.
37 | FAST = False # When this variable set True then all possible delays reduced.
38 |
39 | # Define browser setup function
40 | def browserSetup(isMobile: bool, user_agent: str = PC_USER_AGENT) -> WebDriver:
41 | # Create Chrome browser
42 | from selenium.webdriver.chrome.options import Options
43 | options = Options()
44 | if ARGS.session:
45 | if not isMobile:
46 | options.add_argument(rf'--user-data-dir={os.path.join(os.getcwd()+"/Profiles/" + CURRENT_ACCOUNT, "PC")}')
47 | else:
48 | options.add_argument(rf'--user-data-dir={os.path.join(os.getcwd()+"/Profiles/" + CURRENT_ACCOUNT, "Mobile")}')
49 | options.add_argument("user-agent=" + user_agent)
50 | options.add_argument('lang=' + LANG.split("-")[0])
51 | options.add_argument('--disable-blink-features=AutomationControlled')
52 | prefs = {"profile.default_content_setting_values.geolocation" :2,
53 | "credentials_enable_service": False,
54 | "profile.password_manager_enabled": False,
55 | "webrtc.ip_handling_policy": "disable_non_proxied_udp",
56 | "webrtc.multiple_routes_enabled": False,
57 | "webrtc.nonproxied_udp_enabled" : False}
58 | options.add_experimental_option("prefs",prefs)
59 | options.add_experimental_option("useAutomationExtension", False)
60 | options.add_experimental_option("excludeSwitches", ["enable-automation"])
61 | if ARGS.headless:
62 | options.add_argument("--headless")
63 | options.add_argument('log-level=3')
64 | options.add_argument("--start-maximized")
65 | if platform.system() == 'Linux':
66 | options.add_argument("--no-sandbox")
67 | options.add_argument("--disable-dev-shm-usage")
68 | chrome_browser_obj = webdriver.Chrome(options=options)
69 | return chrome_browser_obj
70 |
71 | # Define login function
72 | def login(browser: WebDriver, email: str, pwd: str, isMobile: bool = False):
73 | # Close welcome tab for new sessions
74 | if ARGS.session:
75 | time.sleep(2)
76 | if len(browser.window_handles) > 1:
77 | current_window = browser.current_window_handle
78 | for handler in browser.window_handles:
79 | if handler != current_window:
80 | browser.switch_to.window(handler)
81 | time.sleep(0.5)
82 | browser.close()
83 | browser.switch_to.window(current_window)
84 | # Access to bing.com
85 | browser.get('https://login.live.com/')
86 | # Check if account is already logged in
87 | if ARGS.session:
88 | if browser.title == "We're updating our terms" or isElementExists(browser, By.ID, 'iAccrualForm'):
89 | time.sleep(2)
90 | browser.find_element(By.ID, 'iNext').click()
91 | time.sleep(5)
92 | if browser.title == 'Microsoft account | Home' or isElementExists(browser, By.ID, 'navs_container'):
93 | prGreen('[LOGIN] Account already logged in !')
94 | RewardsLogin(browser)
95 | print('[LOGIN]', 'Ensuring login on Bing...')
96 | checkBingLogin(browser, isMobile)
97 | return
98 | elif browser.title == 'Your account has been temporarily suspended':
99 | LOGS[CURRENT_ACCOUNT]['Last check'] = 'Your account has been locked !'
100 | FINISHED_ACCOUNTS.append(CURRENT_ACCOUNT)
101 | updateLogs()
102 | cleanLogs()
103 | raise Exception(prRed('[ERROR] Your account has been locked !'))
104 | # Wait complete loading
105 | waitUntilVisible(browser, By.ID, 'loginHeader', 10)
106 | # Enter email
107 | print('[LOGIN]', 'Writing email...')
108 | browser.find_element(By.NAME, "loginfmt").send_keys(email)
109 | # Click next
110 | browser.find_element(By.ID, 'idSIButton9').click()
111 | # Wait 2 seconds
112 | time.sleep(5 if not FAST else 2)
113 | # Wait complete loading
114 | waitUntilVisible(browser, By.ID, 'loginHeader', 10)
115 | # Enter password
116 | browser.find_element(By.ID, "i0118").send_keys(pwd)
117 | # browser.execute_script("document.getElementById('i0118').value = '" + pwd + "';")
118 | print('[LOGIN]', 'Writing password...')
119 | # Click next
120 | browser.find_element(By.ID, 'idSIButton9').click()
121 | # Wait 5 seconds
122 | time.sleep(5)
123 | try:
124 | if browser.title == "We're updating our terms" or isElementExists(browser, By.ID, 'iAccrualForm'):
125 | time.sleep(2)
126 | browser.find_element(By.ID, 'iNext').click()
127 | time.sleep(5)
128 | if ARGS.session:
129 | # Click Yes to stay signed in.
130 | browser.find_element(By.ID, 'idSIButton9').click()
131 | else:
132 | # Click No.
133 | browser.find_element(By.ID, 'idBtn_Back').click()
134 | except NoSuchElementException:
135 | # Check for if account has been locked.
136 | if browser.title == "Your account has been temporarily suspended" or isElementExists(browser, By.CLASS_NAME, "serviceAbusePageContainer PageContainer"):
137 | LOGS[CURRENT_ACCOUNT]['Last check'] = 'Your account has been locked !'
138 | FINISHED_ACCOUNTS.append(CURRENT_ACCOUNT)
139 | updateLogs()
140 | cleanLogs()
141 | raise Exception(prRed('[ERROR] Your account has been locked !'))
142 | elif browser.title == "Help us protect your account":
143 | prRed('[ERROR] Unusual activity detected !')
144 | LOGS[CURRENT_ACCOUNT]['Last check'] = 'Unusual activity detected !'
145 | FINISHED_ACCOUNTS.append(CURRENT_ACCOUNT)
146 | updateLogs()
147 | cleanLogs()
148 | input('Press any key to close...')
149 | os._exit(0)
150 | else:
151 | unknown_err_msg = f'Unknown error: {browser.title} !'
152 | LOGS[CURRENT_ACCOUNT]['Last check'] = unknown_err_msg
153 | FINISHED_ACCOUNTS.append(CURRENT_ACCOUNT)
154 | updateLogs()
155 | cleanLogs()
156 | raise Exception(prRed(unknown_err_msg))
157 | # Wait 5 seconds
158 | time.sleep(5)
159 | # Click Security Check
160 | print('[LOGIN]', 'Passing security checks...')
161 | try:
162 | browser.find_element(By.ID, 'iLandingViewAction').click()
163 | except (NoSuchElementException, ElementNotInteractableException) as e:
164 | pass
165 | # Wait complete loading
166 | try:
167 | waitUntilVisible(browser, By.ID, 'KmsiCheckboxField', 10)
168 | except (TimeoutException) as e:
169 | pass
170 | # Click next
171 | try:
172 | browser.find_element(By.ID, 'idSIButton9').click()
173 | # Wait 5 seconds
174 | time.sleep(5)
175 | except (NoSuchElementException, ElementNotInteractableException) as e:
176 | pass
177 | print('[LOGIN]', 'Logged-in !')
178 | # Check Microsoft Rewards
179 | print('[LOGIN] Logging into Microsoft Rewards...')
180 | RewardsLogin(browser)
181 | # Check Login
182 | print('[LOGIN]', 'Ensuring login on Bing...')
183 | checkBingLogin(browser, isMobile)
184 |
185 | def RewardsLogin(browser: WebDriver):
186 | #Login into Rewards
187 | browser.get('https://rewards.microsoft.com/dashboard')
188 | try:
189 | time.sleep(10 if not FAST else 5)
190 | browser.find_element(By.ID, 'raf-signin-link-id').click()
191 | except:
192 | pass
193 | time.sleep(10 if not FAST else 5)
194 | # Check for ErrorMessage
195 | try:
196 | browser.find_element(By.ID, 'error').is_displayed()
197 | # Check wheter account suspended or not
198 | if browser.find_element(By.XPATH, '//*[@id="error"]/h1').get_attribute('innerHTML') == ' Uh oh, it appears your Microsoft Rewards account has been suspended.':
199 | LOGS[CURRENT_ACCOUNT]['Last check'] = 'Your account has been suspended'
200 | LOGS[CURRENT_ACCOUNT]["Today's points"] = 'N/A'
201 | LOGS[CURRENT_ACCOUNT]["Points"] = 'N/A'
202 | cleanLogs()
203 | updateLogs()
204 | FINISHED_ACCOUNTS.append(CURRENT_ACCOUNT)
205 | raise Exception(prRed('[ERROR] Your Microsoft Rewards account has been suspended !'))
206 | # Check whether Rewards is available in your region or not
207 | elif browser.find_element(By.XPATH, '//*[@id="error"]/h1').get_attribute('innerHTML') == 'Microsoft Rewards is not available in this country or region.':
208 | prRed('[ERROR] Microsoft Rewards is not available in this country or region !')
209 | input('[ERROR] Press any key to close...')
210 | os._exit()
211 | except NoSuchElementException:
212 | pass
213 |
214 | @func_set_timeout(300)
215 | def checkBingLogin(browser: WebDriver, isMobile: bool = False):
216 | global POINTS_COUNTER
217 | #Access Bing.com
218 | browser.get('https://bing.com/')
219 | # Wait 15 seconds
220 | time.sleep(15 if not FAST else 5)
221 | # try to get points at first if account already logged in
222 | if ARGS.session:
223 | try:
224 | if not isMobile:
225 | POINTS_COUNTER = int(browser.find_element(By.ID, 'id_rc').get_attribute('innerHTML'))
226 | else:
227 | browser.find_element(By.ID, 'mHamburger').click()
228 | time.sleep(1)
229 | POINTS_COUNTER = int(browser.find_element(By.ID, 'fly_id_rc').get_attribute('innerHTML'))
230 | except:
231 | pass
232 | else:
233 | return None
234 | #Accept Cookies
235 | try:
236 | browser.find_element(By.ID, 'bnp_btn_accept').click()
237 | except:
238 | pass
239 | if isMobile:
240 | try:
241 | time.sleep(1)
242 | browser.find_element(By.ID, 'mHamburger').click()
243 | except:
244 | try:
245 | browser.find_element(By.ID, 'bnp_btn_accept').click()
246 | except:
247 | pass
248 | time.sleep(1)
249 | if isElementExists(browser, By.XPATH, '//*[@id="bnp_ttc_div"]/div[1]/div[2]/span'):
250 | browser.execute_script("""var element = document.evaluate('/html/body/div[1]', document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
251 | element.remove();""")
252 | time.sleep(5)
253 | time.sleep(1)
254 | try:
255 | browser.find_element(By.ID, 'mHamburger').click()
256 | except:
257 | pass
258 | try:
259 | time.sleep(1)
260 | browser.find_element(By.ID, 'HBSignIn').click()
261 | except:
262 | pass
263 | try:
264 | time.sleep(2)
265 | browser.find_element(By.ID, 'iShowSkip').click()
266 | time.sleep(3)
267 | except:
268 | if str(browser.current_url).split('?')[0] == "https://account.live.com/proofs/Add":
269 | prRed('[LOGIN] Please complete the Security Check on ' + CURRENT_ACCOUNT)
270 | FINISHED_ACCOUNTS.append(CURRENT_ACCOUNT)
271 | LOGS[CURRENT_ACCOUNT]['Last check'] = 'Requires manual check!'
272 | updateLogs()
273 | exit()
274 | #Wait 5 seconds
275 | time.sleep(5)
276 | # Refresh page
277 | browser.get('https://bing.com/')
278 | # Wait 15 seconds
279 | time.sleep(15 if not FAST else 5)
280 | #Update Counter
281 | try:
282 | if not isMobile:
283 | try:
284 | POINTS_COUNTER = int(browser.find_element(By.ID, 'id_rc').get_attribute('innerHTML'))
285 | except:
286 | browser.find_element(By.ID, 'id_s').click()
287 | time.sleep(15 if not FAST else 7)
288 | checkBingLogin(browser, isMobile)
289 | else:
290 | try:
291 | browser.find_element(By.ID, 'mHamburger').click()
292 | except:
293 | try:
294 | browser.find_element(By.ID, 'bnp_close_link').click()
295 | time.sleep(4)
296 | browser.find_element(By.ID, 'bnp_btn_accept').click()
297 | except:
298 | pass
299 | time.sleep(1)
300 | browser.find_element(By.ID, 'mHamburger').click()
301 | time.sleep(1)
302 | POINTS_COUNTER = int(browser.find_element(By.ID, 'fly_id_rc').get_attribute('innerHTML'))
303 | except:
304 | print("[WARN]", "Failure to load point counter")
305 | return
306 | checkBingLogin(browser, isMobile)
307 |
308 | def waitUntilVisible(browser: WebDriver, by_: By, selector: str, time_to_wait: int = 10):
309 | WebDriverWait(browser, time_to_wait).until(ec.visibility_of_element_located((by_, selector)))
310 |
311 | def waitUntilClickable(browser: WebDriver, by_: By, selector: str, time_to_wait: int = 10):
312 | WebDriverWait(browser, time_to_wait).until(ec.element_to_be_clickable((by_, selector)))
313 |
314 | def waitUntilQuestionRefresh(browser: WebDriver):
315 | tries = 0
316 | refreshCount = 0
317 | while True:
318 | try:
319 | browser.find_elements(By.CLASS_NAME, 'rqECredits')[0]
320 | return True
321 | except:
322 | if tries < 10:
323 | tries += 1
324 | time.sleep(0.5)
325 | else:
326 | if refreshCount < 5:
327 | browser.refresh()
328 | refreshCount += 1
329 | tries = 0
330 | time.sleep(5)
331 | else:
332 | return False
333 |
334 | def waitUntilQuizLoads(browser: WebDriver):
335 | tries = 0
336 | refreshCount = 0
337 | while True:
338 | try:
339 | browser.find_element(By.XPATH, '//*[@id="currentQuestionContainer"]')
340 | return True
341 | except:
342 | if tries < 10:
343 | tries += 1
344 | time.sleep(0.5)
345 | else:
346 | if refreshCount < 5:
347 | browser.refresh()
348 | refreshCount += 1
349 | tries = 0
350 | time.sleep(5)
351 | else:
352 | return False
353 |
354 | def findBetween(s: str, first: str, last: str) -> str:
355 | try:
356 | start = s.index(first) + len(first)
357 | end = s.index(last, start)
358 | return s[start:end]
359 | except ValueError:
360 | return ""
361 |
362 | def getCCodeLangAndOffset() -> tuple:
363 | try:
364 | nfo = ipapi.location()
365 | lang = nfo['languages'].split(',')[0]
366 | geo = nfo['country']
367 | tz = str(round(int(nfo['utc_offset']) / 100 * 60))
368 | return(lang, geo, tz)
369 | # Due to limits that ipapi has some times it returns error so I put US and English as default, you may change it at whatever you need.
370 | except:
371 | return('en-US', 'US', '-480')
372 |
373 | def getGoogleTrends(numberOfwords: int) -> list:
374 | search_terms = []
375 | i = 0
376 | while len(search_terms) < numberOfwords :
377 | i += 1
378 | r = requests.get('https://trends.google.com/trends/api/dailytrends?hl=' + LANG + '&ed=' + str((date.today() - timedelta(days = i)).strftime('%Y%m%d')) + '&geo=' + GEO + '&ns=15')
379 | google_trends = json.loads(r.text[6:])
380 | for topic in google_trends['default']['trendingSearchesDays'][0]['trendingSearches']:
381 | search_terms.append(topic['title']['query'].lower())
382 | for related_topic in topic['relatedQueries']:
383 | search_terms.append(related_topic['query'].lower())
384 | search_terms = list(set(search_terms))
385 | del search_terms[numberOfwords:(len(search_terms)+1)]
386 | return search_terms
387 |
388 | def getRelatedTerms(word: str) -> list:
389 | try:
390 | r = requests.get('https://api.bing.com/osjson.aspx?query=' + word, headers = {'User-agent': PC_USER_AGENT})
391 | return r.json()[1]
392 | except:
393 | return []
394 |
395 | def resetTabs(browser: WebDriver):
396 | try:
397 | curr = browser.current_window_handle
398 |
399 | for handle in browser.window_handles:
400 | if handle != curr:
401 | browser.switch_to.window(handle)
402 | time.sleep(0.5)
403 | browser.close()
404 | time.sleep(0.5)
405 |
406 | browser.switch_to.window(curr)
407 | time.sleep(0.5)
408 | browser.get('https://rewards.microsoft.com/')
409 | except:
410 | browser.get('https://rewards.microsoft.com/')
411 |
412 | def getAnswerCode(key: str, string: str) -> str:
413 | t = 0
414 | for i in range(len(string)):
415 | t += ord(string[i])
416 | t += int(key[-2:], 16)
417 | return str(t)
418 |
419 | def bingSearches(browser: WebDriver, numberOfSearches: int, isMobile: bool = False):
420 | global POINTS_COUNTER
421 | i = 0
422 | R = RandomWords()
423 | search_terms = R.get_random_words(limit = numberOfSearches)
424 | if search_terms == None:
425 | search_terms = getGoogleTrends(numberOfSearches)
426 | for word in search_terms:
427 | i += 1
428 | print('[BING]', str(i) + "/" + str(numberOfSearches))
429 | points = bingSearch(browser, word, isMobile)
430 | if points <= POINTS_COUNTER :
431 | relatedTerms = getRelatedTerms(word)
432 | for term in relatedTerms :
433 | points = bingSearch(browser, term, isMobile)
434 | if points >= POINTS_COUNTER:
435 | break
436 | if points > 0:
437 | POINTS_COUNTER = points
438 | else:
439 | break
440 |
441 | def bingSearch(browser: WebDriver, word: str, isMobile: bool):
442 | try:
443 | if not isMobile:
444 | browser.find_element(By.ID, 'sb_form_q').clear()
445 | time.sleep(1)
446 | else:
447 | browser.get('https://bing.com')
448 | except:
449 | browser.get('https://bing.com')
450 | time.sleep(2)
451 | searchbar = browser.find_element(By.ID, 'sb_form_q')
452 | if FAST:
453 | searchbar.send_keys(word)
454 | time.sleep(1)
455 | else:
456 | for char in word:
457 | searchbar.send_keys(char)
458 | time.sleep(0.33)
459 | searchbar.submit()
460 | time.sleep(random.randint(12, 24) if not FAST else random.randint(6, 9))
461 | points = 0
462 | try:
463 | if not isMobile:
464 | points = int(browser.find_element(By.ID, 'id_rc').get_attribute('innerHTML'))
465 | else:
466 | try :
467 | browser.find_element(By.ID, 'mHamburger').click()
468 | except UnexpectedAlertPresentException:
469 | try :
470 | browser.switch_to.alert.accept()
471 | time.sleep(1)
472 | browser.find_element(By.ID, 'mHamburger').click()
473 | except NoAlertPresentException :
474 | pass
475 | time.sleep(1)
476 | points = int(browser.find_element(By.ID, 'fly_id_rc').get_attribute('innerHTML'))
477 | except:
478 | pass
479 | return points
480 |
481 | def completePromotionalItems(browser: WebDriver):
482 | try:
483 | item = getDashboardData(browser)["promotionalItem"]
484 | if (item["pointProgressMax"] == 100 or item["pointProgressMax"] == 200) and item["complete"] == False and item["destinationUrl"] == "https://rewards.microsoft.com/":
485 | browser.find_element(By.XPATH, '//*[@id="promo-item"]/section/div/div/div/a').click()
486 | time.sleep(1)
487 | browser.switch_to.window(window_name = browser.window_handles[1])
488 | time.sleep(8)
489 | browser.close()
490 | time.sleep(2)
491 | browser.switch_to.window(window_name = browser.window_handles[0])
492 | time.sleep(2)
493 | except:
494 | pass
495 |
496 | def completeDailySetSearch(browser: WebDriver, cardNumber: int):
497 | time.sleep(5)
498 | browser.find_element(By.XPATH, f'//*[@id="app-host"]/ui-view/mee-rewards-dashboard/main/div/mee-rewards-daily-set-section/div/mee-card-group/div/mee-card[{str(cardNumber)}]/div/card-content/mee-rewards-daily-set-item-content/div/a/div/span').click()
499 | time.sleep(1)
500 | browser.switch_to.window(window_name = browser.window_handles[1])
501 | time.sleep(random.randint(13, 17) if not FAST else random.randint(6, 9))
502 | browser.close()
503 | time.sleep(2)
504 | browser.switch_to.window(window_name = browser.window_handles[0])
505 | time.sleep(2)
506 |
507 | def completeDailySetSurvey(browser: WebDriver, cardNumber: int):
508 | time.sleep(5)
509 | browser.find_element(By.XPATH, f'//*[@id="app-host"]/ui-view/mee-rewards-dashboard/main/div/mee-rewards-daily-set-section/div/mee-card-group/div/mee-card[{str(cardNumber)}]/div/card-content/mee-rewards-daily-set-item-content/div/a/div/span').click()
510 | time.sleep(1)
511 | browser.switch_to.window(window_name = browser.window_handles[1])
512 | time.sleep(8 if not FAST else 5)
513 | # Accept cookie popup
514 | if isElementExists(browser, By.ID, 'bnp_container'):
515 | browser.find_element(By.ID, 'bnp_btn_accept').click()
516 | time.sleep(2)
517 | # Click on later on Bing wallpaper app popup
518 | if isElementExists(browser, By.ID, 'b_notificationContainer_bop'):
519 | browser.find_element(By.ID, 'bnp_hfly_cta2').click()
520 | time.sleep(2)
521 | browser.find_element(By.ID, "btoption" + str(random.randint(0, 1))).click()
522 | time.sleep(random.randint(10, 15) if not FAST else 7)
523 | browser.close()
524 | time.sleep(2)
525 | browser.switch_to.window(window_name = browser.window_handles[0])
526 | time.sleep(2)
527 |
528 | def completeDailySetQuiz(browser: WebDriver, cardNumber: int):
529 | time.sleep(5)
530 | browser.find_element(By.XPATH, f'//*[@id="app-host"]/ui-view/mee-rewards-dashboard/main/div/mee-rewards-daily-set-section[1]/div/mee-card-group[1]/div[1]/mee-card[{str(cardNumber)}]/div[1]/card-content[1]/mee-rewards-daily-set-item-content[1]/div[1]/a[1]/div[3]/span[1]').click()
531 | time.sleep(3)
532 | browser.switch_to.window(window_name = browser.window_handles[1])
533 | time.sleep(12 if not FAST else random.randint(5, 8))
534 | if not waitUntilQuizLoads(browser):
535 | resetTabs(browser)
536 | return
537 | # Accept cookie popup
538 | if isElementExists(browser, By.ID, 'bnp_container'):
539 | browser.find_element(By.ID, 'bnp_btn_accept').click()
540 | time.sleep(2)
541 | browser.find_element(By.XPATH, '//*[@id="rqStartQuiz"]').click()
542 | waitUntilVisible(browser, By.XPATH, '//*[@id="currentQuestionContainer"]/div/div[1]', 10)
543 | time.sleep(3)
544 | numberOfQuestions = browser.execute_script("return _w.rewardsQuizRenderInfo.maxQuestions")
545 | numberOfOptions = browser.execute_script("return _w.rewardsQuizRenderInfo.numberOfOptions")
546 | for question in range(numberOfQuestions):
547 | if numberOfOptions == 8:
548 | answers = []
549 | for i in range(8):
550 | if browser.find_element(By.ID, "rqAnswerOption" + str(i)).get_attribute("iscorrectoption").lower() == "true":
551 | answers.append("rqAnswerOption" + str(i))
552 | for answer in answers:
553 | # Click on later on Bing wallpaper app popup
554 | if isElementExists(browser, By.ID, 'b_notificationContainer_bop'):
555 | browser.find_element(By.ID, 'bnp_hfly_cta2').click()
556 | time.sleep(2)
557 | browser.find_element(By.ID, answer).click()
558 | time.sleep(5)
559 | if not waitUntilQuestionRefresh(browser):
560 | return
561 | time.sleep(5)
562 | elif numberOfOptions == 4:
563 | correctOption = browser.execute_script("return _w.rewardsQuizRenderInfo.correctAnswer")
564 | for i in range(4):
565 | if browser.find_element(By.ID, "rqAnswerOption" + str(i)).get_attribute("data-option") == correctOption:
566 | # Click on later on Bing wallpaper app popup
567 | if isElementExists(browser, By.ID, 'b_notificationContainer_bop'):
568 | browser.find_element(By.ID, 'bnp_hfly_cta2').click()
569 | time.sleep(2)
570 | browser.find_element(By.ID, "rqAnswerOption" + str(i)).click()
571 | time.sleep(5)
572 | if not waitUntilQuestionRefresh(browser):
573 | return
574 | break
575 | time.sleep(5)
576 | time.sleep(5)
577 | browser.close()
578 | time.sleep(2)
579 | browser.switch_to.window(window_name = browser.window_handles[0])
580 | time.sleep(2)
581 |
582 | def completeDailySetVariableActivity(browser: WebDriver, cardNumber: int):
583 | time.sleep(2)
584 | browser.find_element(By.XPATH, f'//*[@id="app-host"]/ui-view/mee-rewards-dashboard/main/div/mee-rewards-daily-set-section/div/mee-card-group/div/mee-card[{str(cardNumber)}]/div/card-content/mee-rewards-daily-set-item-content/div/a/div/span').click()
585 | time.sleep(1)
586 | browser.switch_to.window(window_name = browser.window_handles[1])
587 | time.sleep(8)
588 | # Accept cookie popup
589 | if isElementExists(browser, By.ID, 'bnp_container'):
590 | browser.find_element(By.ID, 'bnp_btn_accept').click()
591 | time.sleep(2)
592 | try :
593 | browser.find_element(By.XPATH, '//*[@id="rqStartQuiz"]').click()
594 | waitUntilVisible(browser, By.XPATH, '//*[@id="currentQuestionContainer"]/div/div[1]', 3)
595 | except (NoSuchElementException, TimeoutException):
596 | try:
597 | counter = str(browser.find_element(By.XPATH, '//*[@id="QuestionPane0"]/div[2]').get_attribute('innerHTML'))[:-1][1:]
598 | numberOfQuestions = max([int(s) for s in counter.split() if s.isdigit()])
599 | for question in range(numberOfQuestions):
600 | # Click on later on Bing wallpaper app popup
601 | if isElementExists(browser, By.ID, 'b_notificationContainer_bop'):
602 | browser.find_element(By.ID, 'bnp_hfly_cta2').click()
603 | time.sleep(2)
604 |
605 | browser.execute_script(f'document.evaluate("//*[@id=\'QuestionPane{str(question)}\']/div[1]/div[2]/a[{str(random.randint(1, 3))}]/div", document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue.click()')
606 | time.sleep(8)
607 | time.sleep(5)
608 | browser.close()
609 | time.sleep(2)
610 | browser.switch_to.window(window_name=browser.window_handles[0])
611 | time.sleep(2)
612 | return
613 | except NoSuchElementException:
614 | time.sleep(random.randint(5, 9))
615 | browser.close()
616 | time.sleep(2)
617 | browser.switch_to.window(window_name = browser.window_handles[0])
618 | time.sleep(2)
619 | return
620 | time.sleep(3)
621 | correctAnswer = browser.execute_script("return _w.rewardsQuizRenderInfo.correctAnswer")
622 | if browser.find_element(By.ID, "rqAnswerOption0").get_attribute("data-option") == correctAnswer:
623 | browser.find_element(By.ID, "rqAnswerOption0").click()
624 | else :
625 | browser.find_element(By.ID, "rqAnswerOption1").click()
626 | time.sleep(10)
627 | browser.close()
628 | time.sleep(2)
629 | browser.switch_to.window(window_name = browser.window_handles[0])
630 | time.sleep(2)
631 |
632 | def completeDailySetThisOrThat(browser: WebDriver, cardNumber: int):
633 | time.sleep(2)
634 | browser.find_element(By.XPATH, f'//*[@id="app-host"]/ui-view/mee-rewards-dashboard/main/div/mee-rewards-daily-set-section/div/mee-card-group/div/mee-card[{str(cardNumber)}]/div/card-content/mee-rewards-daily-set-item-content/div/a/div/span').click()
635 | time.sleep(1)
636 | browser.switch_to.window(window_name=browser.window_handles[1])
637 | time.sleep(15 if not FAST else random.randint(5, 8))
638 | # Accept cookie popup
639 | if isElementExists(browser, By.ID, 'bnp_container'):
640 | browser.find_element(By.ID, 'bnp_btn_accept').click()
641 | time.sleep(2)
642 | if not waitUntilQuizLoads(browser):
643 | resetTabs(browser)
644 | return
645 | browser.find_element(By.XPATH, '//*[@id="rqStartQuiz"]').click()
646 | waitUntilVisible(browser, By.XPATH, '//*[@id="currentQuestionContainer"]/div/div[1]', 10)
647 | time.sleep(5)
648 | for question in range(10):
649 | # Click on later on Bing wallpaper app popup
650 | if isElementExists(browser, By.ID, 'b_notificationContainer_bop'):
651 | browser.find_element(By.ID, 'bnp_hfly_cta2').click()
652 | time.sleep(2)
653 |
654 | answerEncodeKey = browser.execute_script("return _G.IG")
655 |
656 | answer1 = browser.find_element(By.ID, "rqAnswerOption0")
657 | answer1Title = answer1.get_attribute('data-option')
658 | answer1Code = getAnswerCode(answerEncodeKey, answer1Title)
659 |
660 | answer2 = browser.find_element(By.ID, "rqAnswerOption1")
661 | answer2Title = answer2.get_attribute('data-option')
662 | answer2Code = getAnswerCode(answerEncodeKey, answer2Title)
663 |
664 | correctAnswerCode = browser.execute_script("return _w.rewardsQuizRenderInfo.correctAnswer")
665 |
666 | if (answer1Code == correctAnswerCode):
667 | answer1.click()
668 | time.sleep(15 if not FAST else 7)
669 | elif (answer2Code == correctAnswerCode):
670 | answer2.click()
671 | time.sleep(15 if not FAST else 7)
672 |
673 | time.sleep(5)
674 | browser.close()
675 | time.sleep(2)
676 | browser.switch_to.window(window_name=browser.window_handles[0])
677 | time.sleep(2)
678 |
679 | def getDashboardData(browser: WebDriver) -> dict:
680 | dashboard = findBetween(browser.find_element(By.XPATH, '/html/body').get_attribute('innerHTML'), "var dashboard = ", ";\n appDataModule.constant(\"prefetchedDashboard\", dashboard);")
681 | dashboard = json.loads(dashboard)
682 | return dashboard
683 |
684 | def completeDailySet(browser: WebDriver):
685 | d = getDashboardData(browser)['dailySetPromotions']
686 | todayDate = datetime.today().strftime('%m/%d/%Y')
687 | todayPack = []
688 | for date, data in d.items():
689 | if date == todayDate:
690 | todayPack = data
691 | for activity in todayPack:
692 | try:
693 | if activity['complete'] == False:
694 | cardNumber = int(activity['offerId'][-1:])
695 | if activity['promotionType'] == "urlreward":
696 | print('[DAILY SET]', 'Completing search of card ' + str(cardNumber))
697 | completeDailySetSearch(browser, cardNumber)
698 | if activity['promotionType'] == "quiz":
699 | if activity['pointProgressMax'] == 50 and activity['pointProgress'] == 0:
700 | print('[DAILY SET]', 'Completing This or That of card ' + str(cardNumber))
701 | completeDailySetThisOrThat(browser, cardNumber)
702 | elif (activity['pointProgressMax'] == 40 or activity['pointProgressMax'] == 30) and activity['pointProgress'] == 0:
703 | print('[DAILY SET]', 'Completing quiz of card ' + str(cardNumber))
704 | completeDailySetQuiz(browser, cardNumber)
705 | elif activity['pointProgressMax'] == 10 and activity['pointProgress'] == 0:
706 | searchUrl = urllib.parse.unquote(urllib.parse.parse_qs(urllib.parse.urlparse(activity['destinationUrl']).query)['ru'][0])
707 | searchUrlQueries = urllib.parse.parse_qs(urllib.parse.urlparse(searchUrl).query)
708 | filters = {}
709 | for filter in searchUrlQueries['filters'][0].split(" "):
710 | filter = filter.split(':', 1)
711 | filters[filter[0]] = filter[1]
712 | if "PollScenarioId" in filters:
713 | print('[DAILY SET]', 'Completing poll of card ' + str(cardNumber))
714 | completeDailySetSurvey(browser, cardNumber)
715 | else:
716 | print('[DAILY SET]', 'Completing quiz of card ' + str(cardNumber))
717 | completeDailySetVariableActivity(browser, cardNumber)
718 | except:
719 | resetTabs(browser)
720 |
721 | def getAccountPoints(browser: WebDriver) -> int:
722 | return getDashboardData(browser)['userStatus']['availablePoints']
723 |
724 | def completePunchCard(browser: WebDriver, url: str, childPromotions: dict):
725 | browser.get(url)
726 | for child in childPromotions:
727 | if child['complete'] == False:
728 | if child['promotionType'] == "urlreward":
729 | browser.execute_script("document.getElementsByClassName('offer-cta')[0].click()")
730 | time.sleep(1)
731 | browser.switch_to.window(window_name = browser.window_handles[1])
732 | time.sleep(random.randint(13, 17))
733 | browser.close()
734 | time.sleep(2)
735 | browser.switch_to.window(window_name = browser.window_handles[0])
736 | time.sleep(2)
737 | if child['promotionType'] == "quiz" and child['pointProgressMax'] >= 50 :
738 | browser.find_element(By.XPATH, '//*[@id="rewards-dashboard-punchcard-details"]/div[2]/div[2]/div[7]/div[3]/div[1]/a').click()
739 | time.sleep(1)
740 | browser.switch_to.window(window_name = browser.window_handles[1])
741 | time.sleep(15)
742 | try:
743 | browser.find_element(By.XPATH, '//*[@id="rqStartQuiz"]').click()
744 | except:
745 | pass
746 | time.sleep(5)
747 | waitUntilVisible(browser, By.XPATH, '//*[@id="currentQuestionContainer"]', 10)
748 | numberOfQuestions = browser.execute_script("return _w.rewardsQuizRenderInfo.maxQuestions")
749 | AnswerdQuestions = browser.execute_script("return _w.rewardsQuizRenderInfo.CorrectlyAnsweredQuestionCount")
750 | numberOfQuestions -= AnswerdQuestions
751 | for question in range(numberOfQuestions):
752 | answer = browser.execute_script("return _w.rewardsQuizRenderInfo.correctAnswer")
753 | browser.find_element(By.XPATH, f'//input[@value="{answer}"]').click()
754 | time.sleep(15)
755 | time.sleep(5)
756 | browser.close()
757 | time.sleep(2)
758 | browser.switch_to.window(window_name=browser.window_handles[0])
759 | time.sleep(2)
760 | browser.refresh()
761 | break
762 | elif child['promotionType'] == "quiz" and child['pointProgressMax'] < 50:
763 | browser.execute_script("document.getElementsByClassName('offer-cta')[0].click()")
764 | time.sleep(1)
765 | browser.switch_to.window(window_name = browser.window_handles[1])
766 | time.sleep(8)
767 | counter = str(browser.find_element(By.XPATH, '//*[@id="QuestionPane0"]/div[2]').get_attribute('innerHTML'))[:-1][1:]
768 | numberOfQuestions = max([int(s) for s in counter.split() if s.isdigit()])
769 | for question in range(numberOfQuestions):
770 | browser.execute_script('document.evaluate("//*[@id=\'QuestionPane' + str(question) + '\']/div[1]/div[2]/a[' + str(random.randint(1, 3)) + ']/div", document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue.click()')
771 | time.sleep(10)
772 | time.sleep(5)
773 | browser.close()
774 | time.sleep(2)
775 | browser.switch_to.window(window_name = browser.window_handles[0])
776 | time.sleep(2)
777 | browser.refresh()
778 | break
779 |
780 | def completePunchCards(browser: WebDriver):
781 | punchCards = getDashboardData(browser)['punchCards']
782 | for punchCard in punchCards:
783 | try:
784 | if punchCard['parentPromotion'] != None and punchCard['childPromotions'] != None and punchCard['parentPromotion']['complete'] == False and punchCard['parentPromotion']['pointProgressMax'] != 0:
785 | url = punchCard['parentPromotion']['attributes']['destination']
786 | if browser.current_url.startswith('https://rewards.'):
787 | path = url.replace('https://rewards.microsoft.com', '')
788 | new_url = 'https://rewards.microsoft.com/dashboard/'
789 | userCode = path[11:15]
790 | dest = new_url + userCode + path.split(userCode)[1]
791 | else:
792 | path = url.replace('https://account.microsoft.com/rewards/dashboard/','')
793 | new_url = 'https://account.microsoft.com/rewards/dashboard/'
794 | userCode = path[:4]
795 | dest = new_url + userCode + path.split(userCode)[1]
796 | completePunchCard(browser, dest, punchCard['childPromotions'])
797 | except:
798 | resetTabs(browser)
799 | time.sleep(2)
800 | browser.get('https://rewards.microsoft.com/dashboard/')
801 | time.sleep(2)
802 |
803 | def completeMorePromotionSearch(browser: WebDriver, cardNumber: int):
804 | browser.find_element(By.XPATH, f'//*[@id="app-host"]/ui-view/mee-rewards-dashboard/main/div/mee-rewards-more-activities-card/mee-card-group/div/mee-card[{str(cardNumber)}]/div/card-content/mee-rewards-more-activities-card-item/div/a/div/span').click()
805 | time.sleep(1)
806 | browser.switch_to.window(window_name = browser.window_handles[1])
807 | time.sleep(random.randint(13, 17) if not FAST else random.randint(5, 8))
808 | browser.close()
809 | time.sleep(2)
810 | browser.switch_to.window(window_name = browser.window_handles[0])
811 | time.sleep(2)
812 |
813 | def completeMorePromotionQuiz(browser: WebDriver, cardNumber: int):
814 | browser.find_element(By.XPATH, f'//*[@id="app-host"]/ui-view/mee-rewards-dashboard/main/div/mee-rewards-more-activities-card/mee-card-group/div/mee-card[{str(cardNumber)}]/div/card-content/mee-rewards-more-activities-card-item/div/a/div/span').click()
815 | time.sleep(1)
816 | browser.switch_to.window(window_name=browser.window_handles[1])
817 | time.sleep(8 if not FAST else 5)
818 | if not waitUntilQuizLoads(browser):
819 | resetTabs(browser)
820 | return
821 | CurrentQuestionNumber = browser.execute_script("return _w.rewardsQuizRenderInfo.currentQuestionNumber")
822 | if CurrentQuestionNumber == 1 and isElementExists(browser, By.XPATH, '//*[@id="rqStartQuiz"]'):
823 | browser.find_element(By.XPATH, '//*[@id="rqStartQuiz"]').click()
824 | waitUntilVisible(browser, By.XPATH, '//*[@id="currentQuestionContainer"]/div/div[1]', 10)
825 | time.sleep(3)
826 | numberOfQuestions = browser.execute_script("return _w.rewardsQuizRenderInfo.maxQuestions")
827 | Questions = numberOfQuestions - CurrentQuestionNumber + 1
828 | numberOfOptions = browser.execute_script("return _w.rewardsQuizRenderInfo.numberOfOptions")
829 | for question in range(Questions):
830 | if numberOfOptions == 8:
831 | answers = []
832 | for i in range(8):
833 | if browser.find_element(By.ID, "rqAnswerOption" + str(i)).get_attribute("iscorrectoption").lower() == "true":
834 | answers.append("rqAnswerOption" + str(i))
835 | for answer in answers:
836 | browser.find_element(By.ID, answer).click()
837 | time.sleep(5)
838 | if not waitUntilQuestionRefresh(browser):
839 | return
840 | time.sleep(5)
841 | elif numberOfOptions == 4:
842 | correctOption = browser.execute_script("return _w.rewardsQuizRenderInfo.correctAnswer")
843 | for i in range(4):
844 | if browser.find_element(By.ID, "rqAnswerOption" + str(i)).get_attribute("data-option") == correctOption:
845 | browser.find_element(By.ID, "rqAnswerOption" + str(i)).click()
846 | time.sleep(5)
847 | if not waitUntilQuestionRefresh(browser):
848 | return
849 | break
850 | time.sleep(5)
851 | time.sleep(5)
852 | browser.close()
853 | time.sleep(2)
854 | browser.switch_to.window(window_name=browser.window_handles[0])
855 | time.sleep(2)
856 |
857 | def completeMorePromotionABC(browser: WebDriver, cardNumber: int):
858 | browser.find_element(By.XPATH, f'//*[@id="app-host"]/ui-view/mee-rewards-dashboard/main/div/mee-rewards-more-activities-card/mee-card-group/div/mee-card[{str(cardNumber)}]/div/card-content/mee-rewards-more-activities-card-item/div/a/div/span').click()
859 | time.sleep(1)
860 | browser.switch_to.window(window_name=browser.window_handles[1])
861 | time.sleep(8 if not FAST else 5)
862 | counter = str(browser.find_element(By.XPATH, '//*[@id="QuestionPane0"]/div[2]').get_attribute('innerHTML'))[:-1][1:]
863 | numberOfQuestions = max([int(s) for s in counter.split() if s.isdigit()])
864 | for question in range(numberOfQuestions):
865 | browser.execute_script(f'document.evaluate("//*[@id=\'QuestionPane{str(question)}\']/div[1]/div[2]/a[{str(random.randint(1, 3))}]/div", document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue.click()')
866 | time.sleep(8 if not FAST else 5)
867 | time.sleep(5)
868 | browser.close()
869 | time.sleep(2)
870 | browser.switch_to.window(window_name=browser.window_handles[0])
871 | time.sleep(2)
872 |
873 | def completeMorePromotionThisOrThat(browser: WebDriver, cardNumber: int):
874 | browser.find_element(By.XPATH, f'//*[@id="app-host"]/ui-view/mee-rewards-dashboard/main/div/mee-rewards-more-activities-card/mee-card-group/div/mee-card[{str(cardNumber)}]/div/card-content/mee-rewards-more-activities-card-item/div/a/div/span').click()
875 | time.sleep(1)
876 | browser.switch_to.window(window_name=browser.window_handles[1])
877 | time.sleep(8 if not FAST else 5)
878 | if not waitUntilQuizLoads(browser):
879 | resetTabs(browser)
880 | return
881 | CrrentQuestionNumber = browser.execute_script("return _w.rewardsQuizRenderInfo.currentQuestionNumber")
882 | NumberOfQuestionsLeft = 10 - CrrentQuestionNumber + 1
883 | if CrrentQuestionNumber == 1 and isElementExists(browser, By.XPATH, '//*[@id="rqStartQuiz"]'):
884 | browser.find_element(By.XPATH, '//*[@id="rqStartQuiz"]').click()
885 | waitUntilVisible(browser, By.XPATH, '//*[@id="currentQuestionContainer"]/div/div[1]', 10)
886 | time.sleep(3)
887 | for question in range(NumberOfQuestionsLeft):
888 | answerEncodeKey = browser.execute_script("return _G.IG")
889 |
890 | answer1 = browser.find_element(By.ID, "rqAnswerOption0")
891 | answer1Title = answer1.get_attribute('data-option')
892 | answer1Code = getAnswerCode(answerEncodeKey, answer1Title)
893 |
894 | answer2 = browser.find_element(By.ID, "rqAnswerOption1")
895 | answer2Title = answer2.get_attribute('data-option')
896 | answer2Code = getAnswerCode(answerEncodeKey, answer2Title)
897 |
898 | correctAnswerCode = browser.execute_script("return _w.rewardsQuizRenderInfo.correctAnswer")
899 |
900 | if (answer1Code == correctAnswerCode):
901 | answer1.click()
902 | time.sleep(8 if not FAST else 5)
903 | elif (answer2Code == correctAnswerCode):
904 | answer2.click()
905 | time.sleep(8 if not FAST else 5)
906 |
907 | time.sleep(5)
908 | browser.close()
909 | time.sleep(2)
910 | browser.switch_to.window(window_name=browser.window_handles[0])
911 | time.sleep(2)
912 |
913 | def completeMorePromotions(browser: WebDriver):
914 | morePromotions = getDashboardData(browser)['morePromotions']
915 | i = 0
916 | for promotion in morePromotions:
917 | try:
918 | i += 1
919 | if promotion['complete'] == False and promotion['pointProgressMax'] != 0:
920 | if promotion['promotionType'] == "urlreward":
921 | completeMorePromotionSearch(browser, i)
922 | elif promotion['promotionType'] == "quiz":
923 | if promotion['pointProgressMax'] == 10:
924 | completeMorePromotionABC(browser, i)
925 | elif promotion['pointProgressMax'] == 30 or promotion['pointProgressMax'] == 40:
926 | completeMorePromotionQuiz(browser, i)
927 | elif promotion['pointProgressMax'] == 50:
928 | completeMorePromotionThisOrThat(browser, i)
929 | else:
930 | if promotion['pointProgressMax'] == 100 or promotion['pointProgressMax'] == 200:
931 | completeMorePromotionSearch(browser, i)
932 | if promotion['complete'] == False and promotion['pointProgressMax'] == 100 and promotion['promotionType'] == "" \
933 | and promotion['destinationUrl'] == "https://rewards.microsoft.com":
934 | completeMorePromotionSearch(browser, i)
935 | except:
936 | resetTabs(browser)
937 |
938 | def getRemainingSearches(browser: WebDriver):
939 | dashboard = getDashboardData(browser)
940 | searchPoints = 1
941 | counters = dashboard['userStatus']['counters']
942 | if not 'pcSearch' in counters:
943 | return 0, 0
944 | progressDesktop = counters['pcSearch'][0]['pointProgress'] + counters['pcSearch'][1]['pointProgress']
945 | targetDesktop = counters['pcSearch'][0]['pointProgressMax'] + counters['pcSearch'][1]['pointProgressMax']
946 | if targetDesktop == 33 :
947 | #Level 1 EU
948 | searchPoints = 3
949 | elif targetDesktop == 55 :
950 | #Level 1 US
951 | searchPoints = 5
952 | elif targetDesktop == 102 :
953 | #Level 2 EU
954 | searchPoints = 3
955 | elif targetDesktop >= 170 :
956 | #Level 2 US
957 | searchPoints = 5
958 | remainingDesktop = int((targetDesktop - progressDesktop) / searchPoints)
959 | remainingMobile = 0
960 | if dashboard['userStatus']['levelInfo']['activeLevel'] != "Level1":
961 | progressMobile = counters['mobileSearch'][0]['pointProgress']
962 | targetMobile = counters['mobileSearch'][0]['pointProgressMax']
963 | remainingMobile = int((targetMobile - progressMobile) / searchPoints)
964 | return remainingDesktop, remainingMobile
965 |
966 | def isElementExists(browser: WebDriver, _by: By, element: str) -> bool:
967 | '''Returns True if given element exists else False'''
968 | try:
969 | browser.find_element(_by, element)
970 | except NoSuchElementException:
971 | return False
972 | return True
973 |
974 | def validateTime(time: str):
975 | '''
976 | check the time format and return the time if it is valid, otherwise return None
977 | '''
978 | try:
979 | t = datetime.strptime(time, "%H:%M").strftime("%H:%M")
980 | except ValueError:
981 | return None
982 | else:
983 | return t
984 |
985 | def argumentParser():
986 | '''
987 | getting args from command line (--everyday [time:(HH:MM)], --session, --headless)
988 | '''
989 | parser = ArgumentParser(description="Microsoft Rewards Farmer V2.1",
990 | allow_abbrev=False,
991 | usage="You may use execute the program with the default config or use arguments to configure available options.")
992 | parser.add_argument('--everyday',
993 | metavar=None,
994 | help='[Optional] This argument takes an input as time in 24h format (HH:MM) to execute the program at the given time everyday.',
995 | type=str,
996 | required=False)
997 | parser.add_argument('--headless',
998 | help='[Optional] Enable headless browser.',
999 | action = 'store_true',
1000 | required=False)
1001 | parser.add_argument('--session',
1002 | help='[Optional] Creates session for each account and use it.',
1003 | action='store_true',
1004 | required=False)
1005 | parser.add_argument('--error',
1006 | help='[Optional] Display errors when app fails.',
1007 | action='store_true',
1008 | required=False)
1009 | parser.add_argument('--fast',
1010 | help="[Optional] Reduce delays where ever it's possible to make script faster.",
1011 | action='store_true',
1012 | required=False)
1013 | args = parser.parse_args()
1014 | if args.everyday:
1015 | if isinstance(validateTime(args.everyday), str):
1016 | args.everyday = validateTime(args.everyday)
1017 | else:
1018 | parser.error(f'"{args.everyday}" is not valid. Please use (HH:MM) format.')
1019 | if args.fast:
1020 | global FAST
1021 | FAST = True
1022 | if len(sys.argv) > 1:
1023 | for arg in vars(args):
1024 | prBlue(f"[INFO] {arg} : {getattr(args, arg)}")
1025 | return args
1026 |
1027 | def logs():
1028 | '''
1029 | Read logs and check whether account farmed or not
1030 | '''
1031 | global LOGS
1032 | shared_items =[]
1033 | try:
1034 | # Read datas on 'logs_accounts.txt'
1035 | LOGS = json.load(open(f"Logs_{filename}.txt", "r"))
1036 | # sync accounts and logs file for new accounts or remove accounts from logs.
1037 | for user in ACCOUNTS:
1038 | shared_items.append(user['username'])
1039 | if not user['username'] in LOGS.keys():
1040 | LOGS[user["username"]] = {"Last check": "",
1041 | "Today's points": 0,
1042 | "Points": 0}
1043 | if shared_items != LOGS.keys():
1044 | diff = LOGS.keys() - shared_items
1045 | for accs in list(diff):
1046 | del LOGS[accs]
1047 |
1048 | # check that if any of accounts has farmed today or not.
1049 | for account in LOGS.keys():
1050 | if LOGS[account]["Last check"] == str(date.today()) and list(LOGS[account].keys()) == ['Last check', "Today's points", 'Points']:
1051 | FINISHED_ACCOUNTS.append(account)
1052 | elif LOGS[account]['Last check'] == 'Your account has been suspended':
1053 | FINISHED_ACCOUNTS.append(account)
1054 | elif LOGS[account]['Last check'] == str(date.today()) and list(LOGS[account].keys()) == ['Last check', "Today's points", 'Points',
1055 | 'Daily', 'Punch cards', 'More promotions', 'PC searches']:
1056 | continue
1057 | else:
1058 | LOGS[account]['Daily'] = False
1059 | LOGS[account]['Punch cards'] = False
1060 | LOGS[account]['More promotions'] = False
1061 | LOGS[account]['PC searches'] = False
1062 | updateLogs()
1063 | prGreen('\n[LOGS] Logs loaded successfully.\n')
1064 | except FileNotFoundError:
1065 | prRed(f'\n[LOGS] "Logs_{filename}.txt" file not found.')
1066 | LOGS = {}
1067 | for account in ACCOUNTS:
1068 | LOGS[account["username"]] = {"Last check": "",
1069 | "Today's points": 0,
1070 | "Points": 0,
1071 | "Daily": False,
1072 | "Punch cards": False,
1073 | "More promotions": False,
1074 | "PC searches": False}
1075 | updateLogs()
1076 | prGreen(f'[LOGS] "Logs_{filename}.txt" created.\n')
1077 |
1078 | def updateLogs():
1079 | global LOGS
1080 | with open(f'Logs_{filename}.txt', 'w') as file:
1081 | file.write(json.dumps(LOGS, indent = 4))
1082 |
1083 | def cleanLogs():
1084 | del LOGS[CURRENT_ACCOUNT]["Daily"]
1085 | del LOGS[CURRENT_ACCOUNT]["Punch cards"]
1086 | del LOGS[CURRENT_ACCOUNT]["More promotions"]
1087 | del LOGS[CURRENT_ACCOUNT]["PC searches"]
1088 |
1089 | def checkInternetConnection():
1090 | system = platform.system()
1091 | while True:
1092 | try:
1093 | if system == "Windows":
1094 | subprocess.check_output(["ping", "-n", "1", "8.8.8.8"], timeout=5)
1095 | elif system == "Linux":
1096 | subprocess.check_output(["ping", "-c", "1", "8.8.8.8"], timeout=5)
1097 | return
1098 | except (subprocess.CalledProcessError, subprocess.TimeoutExpired):
1099 | prRed("[ERROR] No internet connection.")
1100 | time.sleep(1)
1101 |
1102 | def prRed(prt):
1103 | print(f"\033[91m{prt}\033[00m")
1104 | def prGreen(prt):
1105 | print(f"\033[92m{prt}\033[00m")
1106 | def prYellow(prt):
1107 | print(f"\033[93m{prt}\033[00m")
1108 | def prBlue(prt):
1109 | print(f"\033[94m{prt}\033[00m")
1110 | def prPurple(prt):
1111 | print(f"\033[95m{prt}\033[00m")
1112 |
1113 | def logo():
1114 | prRed("")
1115 | prPurple(" by @Charlesbel upgraded by @Farshadz1997 version 2.1\n")
1116 |
1117 | try:
1118 | account_path = os.path.dirname(os.path.abspath(__file__)) + '/accounts.json'
1119 | filename, ext = os.path.splitext(os.path.basename(account_path))
1120 | ACCOUNTS = json.load(open(account_path, "r"))
1121 | except FileNotFoundError:
1122 | with open(account_path, 'w') as f:
1123 | f.write(json.dumps([{
1124 | "username": "Your Email",
1125 | "password": "Your Password"
1126 | }], indent=4))
1127 | prPurple(f"""
1128 | [ACCOUNT] Accounts credential file "{filename}{ext}" created.
1129 | [ACCOUNT] Edit with your credentials and save, then press any key to continue...
1130 | """)
1131 | input()
1132 | ACCOUNTS = json.load(open(account_path, "r"))
1133 |
1134 | def farmer():
1135 | '''
1136 | fuction that runs other functions to farm.
1137 | '''
1138 | global ERROR, MOBILE, CURRENT_ACCOUNT
1139 | try:
1140 | for account in ACCOUNTS:
1141 | CURRENT_ACCOUNT = account['username']
1142 | if CURRENT_ACCOUNT in FINISHED_ACCOUNTS:
1143 | continue
1144 | if LOGS[CURRENT_ACCOUNT]["Last check"] != str(date.today()):
1145 | LOGS[CURRENT_ACCOUNT]["Last check"] = str(date.today())
1146 | updateLogs()
1147 | prYellow('********************' + CURRENT_ACCOUNT + '********************')
1148 | if not LOGS[CURRENT_ACCOUNT]['PC searches']:
1149 | browser = browserSetup(False, PC_USER_AGENT)
1150 | print('[LOGIN]', 'Logging-in...')
1151 | login(browser, account['username'], account['password'])
1152 | prGreen('[LOGIN] Logged-in successfully !')
1153 | startingPoints = POINTS_COUNTER
1154 | prGreen('[POINTS] You have ' + str(POINTS_COUNTER) + ' points on your account !')
1155 | browser.get('https://rewards.microsoft.com/dashboard')
1156 | if not LOGS[CURRENT_ACCOUNT]['Daily']:
1157 | print('[DAILY SET]', 'Trying to complete the Daily Set...')
1158 | completeDailySet(browser)
1159 | LOGS[CURRENT_ACCOUNT]['Daily'] = True
1160 | updateLogs()
1161 | prGreen('[DAILY SET] Completed the Daily Set successfully !')
1162 | if not LOGS[CURRENT_ACCOUNT]['Punch cards']:
1163 | print('[PUNCH CARDS]', 'Trying to complete the Punch Cards...')
1164 | completePunchCards(browser)
1165 | LOGS[CURRENT_ACCOUNT]['Punch cards'] = True
1166 | updateLogs()
1167 | prGreen('[PUNCH CARDS] Completed the Punch Cards successfully !')
1168 | if not LOGS[CURRENT_ACCOUNT]['More promotions']:
1169 | print('[MORE PROMO]', 'Trying to complete More Promotions...')
1170 | completeMorePromotions(browser)
1171 | LOGS[CURRENT_ACCOUNT]['More promotions'] = True
1172 | updateLogs()
1173 | prGreen('[MORE PROMO] Completed More Promotions successfully !')
1174 | remainingSearches, remainingSearchesM = getRemainingSearches(browser)
1175 | MOBILE = True if remainingSearchesM != 0 else False
1176 | if remainingSearches != 0:
1177 | print('[BING]', 'Starting Desktop and Edge Bing searches...')
1178 | bingSearches(browser, remainingSearches)
1179 | prGreen('[BING] Finished Desktop and Edge Bing searches !')
1180 | LOGS[CURRENT_ACCOUNT]['PC searches'] = True
1181 | updateLogs()
1182 | ERROR = False
1183 | browser.quit()
1184 |
1185 | if MOBILE:
1186 | browser = browserSetup(True, account.get('mobile_user_agent', MOBILE_USER_AGENT))
1187 | print('[LOGIN]', 'Logging-in...')
1188 | login(browser, account['username'], account['password'], True)
1189 | prGreen('[LOGIN] Logged-in successfully !')
1190 | if LOGS[account['username']]['PC searches'] and ERROR:
1191 | startingPoints = POINTS_COUNTER
1192 | browser.get('https://rewards.microsoft.com/dashboard')
1193 | remainingSearches, remainingSearchesM = getRemainingSearches(browser)
1194 | if remainingSearchesM != 0:
1195 | print('[BING]', 'Starting Mobile Bing searches...')
1196 | bingSearches(browser, remainingSearchesM, True)
1197 | prGreen('[BING] Finished Mobile Bing searches !')
1198 | browser.quit()
1199 |
1200 | New_points = POINTS_COUNTER - startingPoints
1201 | prGreen('[POINTS] You have earned ' + str(New_points) + ' points today !')
1202 | prGreen('[POINTS] You are now at ' + str(POINTS_COUNTER) + ' points !\n')
1203 |
1204 | FINISHED_ACCOUNTS.append(CURRENT_ACCOUNT)
1205 | LOGS[CURRENT_ACCOUNT]["Today's points"] = New_points
1206 | LOGS[CURRENT_ACCOUNT]["Points"] = POINTS_COUNTER
1207 | cleanLogs()
1208 | updateLogs()
1209 |
1210 | except FunctionTimedOut:
1211 | prRed('[ERROR] Time out raised.\n')
1212 | ERROR = True
1213 | browser.quit()
1214 | farmer()
1215 | except SessionNotCreatedException:
1216 | prBlue('[Driver] Session not created.')
1217 | prBlue('[Driver] Please download correct version of webdriver form link below:')
1218 | prBlue('[Driver] https://chromedriver.chromium.org/downloads')
1219 | input('Press any key to close...')
1220 | exit()
1221 | except KeyboardInterrupt:
1222 | ERROR = True
1223 | browser.quit()
1224 | input('\n\033[94m[INFO] Farmer paused. Press enter to continue...\033[00m\n')
1225 | farmer()
1226 | except Exception as e:
1227 | print(e, '\n') if ARGS.error else print('\n')
1228 | ERROR = True
1229 | browser.quit()
1230 | checkInternetConnection()
1231 | farmer()
1232 | else:
1233 | FINISHED_ACCOUNTS.clear()
1234 |
1235 | def main():
1236 | display = Display(visible=0, size=(900, 800))
1237 | display.start()
1238 |
1239 | global LANG, GEO, TZ, ARGS
1240 | # show colors in terminal
1241 | os.system('color')
1242 | logo()
1243 | # Get the arguments from the command line
1244 | ARGS = argumentParser()
1245 | LANG, GEO, TZ = getCCodeLangAndOffset()
1246 | # set time to launch the program if everyday is not set
1247 | # if not ARGS.everyday:
1248 | # answer = input('''If you want to run the program at a specific time, type your desired time in 24h format (HH:MM) else press Enter
1249 | # (\033[93manything other than time causes the script to start immediately\033[00m): ''')
1250 | # run_on = validate_time(answer)
1251 | # else:
1252 | # run_on = ARGS.everyday
1253 | run_on = None
1254 | if run_on is not None:
1255 | while True:
1256 | if datetime.now().strftime("%H:%M") == run_on:
1257 | start = time.time()
1258 | logs()
1259 | farmer()
1260 | if ARGS.everyday is None:
1261 | break
1262 | time.sleep(30)
1263 | else:
1264 | start = time.time()
1265 | logs()
1266 | farmer()
1267 | end = time.time()
1268 | delta = end - start
1269 | hour, remain = divmod(delta, 3600)
1270 | min, sec = divmod(remain, 60)
1271 | print(f"The farmer takes : {hour:02.0f}:{min:02.0f}:{sec:02.0f}")
1272 | # input('Press any key to close the program...')
1273 | display.stop()
1274 |
1275 | if __name__ == '__main__':
1276 | main()
1277 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | pyyaml
2 | pyvirtualdisplay
3 | certifi
4 | chardet
5 | idna
6 | requests
7 | selenium
8 | urllib3
9 | ipapi
10 | func_timeout
11 | random-word==1.0.7
12 | pyyaml
13 |
--------------------------------------------------------------------------------
/scripts/upgrade_browser.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | sudo apt-get update -y
3 | sudo apt install -y google-chrome-stable
4 | sudo apt install -y chromium-chromedriver
--------------------------------------------------------------------------------
/ss.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | sudo apt-get update -y
3 | sudo apt install -y shadowsocks-libev
4 | sudo vim /etc/shadowsocks-libev/config.json
--------------------------------------------------------------------------------
/upload_log.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | PROJECT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
3 | LOG_NAME="${PROJECT_DIR}/logs/log_"$*""
4 |
5 | # push log
6 | cd ${PROJECT_DIR}
7 | git pull
8 | cp ~/Logs_accounts.txt ${LOG_NAME};
9 | git add ${LOG_NAME}
10 | git commit -m "[log]"$*""
11 | git push
12 |
13 | # update browser, driver version
14 | /bin/bash scripts/upgrade_browser.sh > browser.txt
15 |
16 | # clean large size log
17 | logfile=cron.log
18 | filesize=$(stat -c %s "$logfile")
19 |
20 | if [ "$filesize" -gt $((200 * 1024 * 1024)) ]; then
21 | echo "Log file is larger than 200MB, deleting..."
22 | rm "$logfile"
23 | fi
--------------------------------------------------------------------------------