Microsoft Rewards Auto Task Completer

Automatically complete Microsoft Rewards tasks with one click

Size

10.6 KB

Version

1.0.1

Created

Jan 11, 2026

Updated

24 days ago

1// ==UserScript==
2// @name		Microsoft Rewards Auto Task Completer
3// @description		Automatically complete Microsoft Rewards tasks with one click
4// @version		1.0.1
5// @match		https://*.rewards.bing.com/*
6// @icon		https://rewards.bing.com/rewards.png
7// @grant		GM.getValue
8// @grant		GM.setValue
9// @grant		GM.openInTab
10// ==/UserScript==
11(function() {
12    'use strict';
13
14    console.log('Microsoft Rewards Auto Task Completer - Extension loaded');
15
16    // Debounce function to prevent excessive calls
17    function debounce(func, wait) {
18        let timeout;
19        return function executedFunction(...args) {
20            const later = () => {
21                clearTimeout(timeout);
22                func(...args);
23            };
24            clearTimeout(timeout);
25            timeout = setTimeout(later, wait);
26        };
27    }
28
29    // Main initialization function
30    async function init() {
31        console.log('Initializing Microsoft Rewards Auto Task Completer');
32        
33        // Wait for the page to fully load
34        if (document.readyState === 'loading') {
35            document.addEventListener('DOMContentLoaded', init);
36            return;
37        }
38
39        // Wait a bit for Angular to render the content
40        await new Promise(resolve => setTimeout(resolve, 3000));
41
42        createAutoCompleteButton();
43        observePageChanges();
44    }
45
46    // Create the auto-complete button
47    function createAutoCompleteButton() {
48        console.log('Creating auto-complete button');
49
50        // Check if button already exists
51        if (document.getElementById('rewards-auto-complete-btn')) {
52            console.log('Button already exists');
53            return;
54        }
55
56        // Find the rewards banner to place our button
57        const banner = document.querySelector('#rewardsBanner .banner-padded-content');
58        if (!banner) {
59            console.log('Banner not found, retrying in 2 seconds');
60            setTimeout(createAutoCompleteButton, 2000);
61            return;
62        }
63
64        // Create button container
65        const buttonContainer = document.createElement('div');
66        buttonContainer.id = 'rewards-auto-complete-container';
67        buttonContainer.style.cssText = `
68            position: fixed;
69            bottom: 30px;
70            right: 30px;
71            z-index: 10000;
72            display: flex;
73            flex-direction: column;
74            gap: 10px;
75        `;
76
77        // Create main button
78        const button = document.createElement('button');
79        button.id = 'rewards-auto-complete-btn';
80        button.innerHTML = '🚀 Auto Complete Tasks';
81        button.style.cssText = `
82            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
83            color: white;
84            border: none;
85            padding: 15px 25px;
86            font-size: 16px;
87            font-weight: bold;
88            border-radius: 30px;
89            cursor: pointer;
90            box-shadow: 0 4px 15px rgba(102, 126, 234, 0.4);
91            transition: all 0.3s ease;
92            font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
93        `;
94
95        // Add hover effect
96        button.addEventListener('mouseenter', () => {
97            button.style.transform = 'translateY(-2px)';
98            button.style.boxShadow = '0 6px 20px rgba(102, 126, 234, 0.6)';
99        });
100
101        button.addEventListener('mouseleave', () => {
102            button.style.transform = 'translateY(0)';
103            button.style.boxShadow = '0 4px 15px rgba(102, 126, 234, 0.4)';
104        });
105
106        // Add click handler
107        button.addEventListener('click', startAutoComplete);
108
109        // Create status display
110        const statusDiv = document.createElement('div');
111        statusDiv.id = 'rewards-auto-complete-status';
112        statusDiv.style.cssText = `
113            background: white;
114            color: #333;
115            padding: 12px 20px;
116            border-radius: 20px;
117            font-size: 14px;
118            font-weight: 500;
119            box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1);
120            display: none;
121            text-align: center;
122            font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
123        `;
124
125        buttonContainer.appendChild(button);
126        buttonContainer.appendChild(statusDiv);
127        document.body.appendChild(buttonContainer);
128
129        console.log('Auto-complete button created successfully');
130    }
131
132    // Start the auto-complete process
133    async function startAutoComplete() {
134        console.log('Starting auto-complete process');
135
136        const button = document.getElementById('rewards-auto-complete-btn');
137        const statusDiv = document.getElementById('rewards-auto-complete-status');
138
139        // Disable button during processing
140        button.disabled = true;
141        button.style.opacity = '0.6';
142        button.style.cursor = 'not-allowed';
143
144        // Show status
145        statusDiv.style.display = 'block';
146        statusDiv.textContent = '🔍 Scanning for tasks...';
147
148        try {
149            // Get all task cards
150            const tasks = await getAllTasks();
151            console.log(`Found ${tasks.length} total tasks`);
152
153            // Filter incomplete tasks with valid links
154            const incompleteTasks = tasks.filter(task => !task.isCompleted && task.hasLink && task.href && !task.href.startsWith('microsoft-edge://'));
155            console.log(`Found ${incompleteTasks.length} incomplete tasks to complete`);
156
157            if (incompleteTasks.length === 0) {
158                statusDiv.textContent = '✅ All tasks completed!';
159                setTimeout(() => {
160                    statusDiv.style.display = 'none';
161                }, 3000);
162                button.disabled = false;
163                button.style.opacity = '1';
164                button.style.cursor = 'pointer';
165                return;
166            }
167
168            // Save current state
169            await GM.setValue('autoCompleteInProgress', true);
170            await GM.setValue('tasksToComplete', JSON.stringify(incompleteTasks));
171            await GM.setValue('currentTaskIndex', 0);
172
173            statusDiv.textContent = `🎯 Opening task 1 of ${incompleteTasks.length}...`;
174
175            // Start completing tasks
176            await completeTasksSequentially(incompleteTasks);
177
178        } catch (error) {
179            console.error('Error during auto-complete:', error);
180            statusDiv.textContent = '❌ Error occurred';
181            statusDiv.style.background = '#ff4444';
182            statusDiv.style.color = 'white';
183            setTimeout(() => {
184                statusDiv.style.display = 'none';
185                statusDiv.style.background = 'white';
186                statusDiv.style.color = '#333';
187            }, 3000);
188            button.disabled = false;
189            button.style.opacity = '1';
190            button.style.cursor = 'pointer';
191        }
192    }
193
194    // Get all tasks from the page
195    async function getAllTasks() {
196        const cards = Array.from(document.querySelectorAll('mee-card[role="listitem"]'));
197        
198        return cards.map((card, index) => {
199            const link = card.querySelector('a.ds-card-sec, a[href*="bing.com"]');
200            const title = card.querySelector('.c-heading, h3')?.textContent?.trim();
201            const description = card.querySelector('.c-paragraph-4, p')?.textContent?.trim();
202            const href = link?.getAttribute('href');
203            const isCompleted = card.querySelector('.mee-icon-SkypeCircleCheck, [data-bi-id*="complete"]') !== null;
204            
205            return {
206                index,
207                title,
208                description,
209                href,
210                isCompleted,
211                hasLink: !!href
212            };
213        });
214    }
215
216    // Complete tasks sequentially
217    async function completeTasksSequentially(tasks) {
218        const statusDiv = document.getElementById('rewards-auto-complete-status');
219
220        for (let i = 0; i < tasks.length; i++) {
221            const task = tasks[i];
222            console.log(`Opening task ${i + 1}/${tasks.length}: ${task.title}`);
223
224            statusDiv.textContent = `🎯 Task ${i + 1}/${tasks.length}: ${task.title || 'Opening...'}`;
225
226            // Save progress
227            await GM.setValue('currentTaskIndex', i);
228
229            // Open task in new tab
230            await GM.openInTab(task.href, false);
231
232            // Wait before opening next task
233            await new Promise(resolve => setTimeout(resolve, 5000));
234        }
235
236        // All tasks completed
237        console.log('All tasks opened successfully');
238        statusDiv.textContent = '✅ All tasks opened! Check tabs to complete them.';
239        statusDiv.style.background = '#4CAF50';
240        statusDiv.style.color = 'white';
241
242        // Clean up state
243        await GM.deleteValue('autoCompleteInProgress');
244        await GM.deleteValue('tasksToComplete');
245        await GM.deleteValue('currentTaskIndex');
246
247        // Re-enable button
248        setTimeout(() => {
249            const button = document.getElementById('rewards-auto-complete-btn');
250            button.disabled = false;
251            button.style.opacity = '1';
252            button.style.cursor = 'pointer';
253            statusDiv.style.display = 'none';
254            statusDiv.style.background = 'white';
255            statusDiv.style.color = '#333';
256        }, 5000);
257    }
258
259    // Observe page changes to re-inject button if needed
260    function observePageChanges() {
261        const debouncedCheck = debounce(() => {
262            if (!document.getElementById('rewards-auto-complete-btn')) {
263                console.log('Button removed, recreating...');
264                createAutoCompleteButton();
265            }
266        }, 1000);
267
268        const observer = new MutationObserver(debouncedCheck);
269        observer.observe(document.body, {
270            childList: true,
271            subtree: true
272        });
273
274        console.log('Page observer initialized');
275    }
276
277    // Check if we're resuming from a task completion
278    async function checkResumeState() {
279        const inProgress = await GM.getValue('autoCompleteInProgress', false);
280        
281        if (inProgress) {
282            console.log('Detected incomplete auto-complete session');
283            const tasksJson = await GM.getValue('tasksToComplete', '[]');
284            const currentIndex = await GM.getValue('currentTaskIndex', 0);
285            
286            try {
287                const tasks = JSON.parse(tasksJson);
288                if (currentIndex < tasks.length - 1) {
289                    console.log(`Resuming from task ${currentIndex + 1}`);
290                    // Could implement resume logic here if needed
291                }
292            } catch (e) {
293                console.error('Error parsing saved tasks:', e);
294            }
295        }
296    }
297
298    // Start the extension
299    checkResumeState();
300    init();
301
302})();
Microsoft Rewards Auto Task Completer | Robomonkey