Microsoft Bing Rewards每日任务脚本

自动完成微软积分每日搜索任务

目前為 2024-10-18 提交的版本,檢視 最新版本

// ==UserScript==
// @name         Microsoft Bing Rewards每日任务脚本
// @namespace    https://gf.qytechs.cn/users/1362311
// @version      4.0.1
// @description  自动完成微软积分每日搜索任务
// @author       honguangli
// @license      MIT
// @match        https://www.bing.com/*
// @match        https://cn.bing.com/*
// @icon         https://www.bing.com/favicon.ico
// @run-at       document-end
// @grant        GM_registerMenuCommand
// @grant        GM_addStyle
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_xmlhttpRequest
// ==/UserScript==

(function() {
    'use strict';

    const pathnames = ['/', '/search']; // 触发搜索页面

    const searchTimes = 40; // 自动搜索次数

    const searchDelaySecondsMin = 15; // 每次搜索最小延迟时间,单位秒
    const searchDelaySecondsMax = 30; // 每次搜索最大延迟时间,单位秒
    const searchDelaySecondsFirst = 3; // 首次搜索延迟时间,单位秒,设置为0时立即触发
    const closeTaskCardDelaySeconds = 0; // 搜索完成后弹窗自动关闭延迟时间,单位秒,设置为0时需手动关闭

    const searchKeySource = ['BaiduHot','TouTiaoHot','DouYinHot', 'WeiBoHot']; // 搜索词条库

    const countKey = 'count'; // 计数器
    const pointsKey = 'points'; // 积分
    const keywordsKey = 'search'; // 搜索词条
    const searchParamKey = 'param'; // 搜索参数

    let searchTimeoutId = null; // 搜索延时器id
    let scrollIntervalId = null; // 模拟浏览定时器id
    let delayIntervalId = null; // 搜索任务倒计时定时器id

    GM_addStyle('#reward-task { position: fixed; top: 0; left: 0; width: 100%; background-color: rgba(0, 0, 0, .2); z-index: 99999; }');
    GM_addStyle('#reward-task > .reward-task-content { width: 608px; margin: calc(50vh - 32px) auto 0; padding: 20px; background-color: #ffffff; border: 1px solid #e4e7ed; border-radius: 20px; color: #303133; overflow: hidden; transition: 0.3s; box-shadow: 0px 0px 12px rgba(0,0,0,0.12); }');
    GM_addStyle('#reward-task > .reward-task-content > div { display: flex; align-items: center; column-gap: 20px; }');
    GM_addStyle('#reward-task > .reward-task-content .reward-task-stop, #reward-task > .reward-task-content .reward-task-cancel { display: inline-block; line-height: 1; white-space: nowrap; cursor: pointer; background: #fff; border: 1px solid #dcdfe6; -webkit-appearance: none; text-align: center; -webkit-box-sizing: border-box; box-sizing: border-box; outline: 0; margin: 0; -webkit-transition: .1s; transition: .1s; font-weight: 500; padding: 9px 15px; font-size: 12px; border-radius: 3px; color: #fff; background: #ebb563; border-color: #ebb563; }');

    // 注册(不可用)菜单
    const registerMenuCommand = () => {
        // 开始
        GM_registerMenuCommand('开始', function () {
            start();
        }, 'o');

        // 停止
        GM_registerMenuCommand('停止', function () {
            stop();
        }, 'o');
    };

    // 开始
    const start = () => {
        GM_setValue(countKey, 1);
        GM_setValue(pointsKey, -1);
        search();
    };

    // 结束
    const stop = () => {
        GM_setValue(keywordsKey, {});
        GM_setValue(countKey, 0);
        GM_setValue(pointsKey, -1);
        clearTimeout(searchTimeoutId);
        clearInterval(scrollIntervalId);
    };

    // 获取词条
    const getSearchInfo = () => {
        return new Promise((resolve, reject) => {
            const today = new Date();
            today.setHours(0);
            today.setMinutes(0);
            today.setSeconds(0);
            today.setMilliseconds(0);

            let source = Math.floor(Math.random() * searchKeySource.length);
            const saveConfig = GM_getValue(keywordsKey);
            // 当日缓存的搜索词还未用完
            if (saveConfig && saveConfig.time === today.getTime()) {
                if (saveConfig.keywords.length > 0) {
                    const keyword = saveConfig.keywords[0];
                    saveConfig.keywords.splice(0, 1);
                    GM_setValue(keywordsKey, saveConfig);
                    resolve(keyword);
                } else {
                    source = (saveConfig.source + 1) % searchKeySource.length;
                }
            }

            // 重置配置
            const config = {
                time: today.getTime(),
                source: source,
                keywords: [],
            };

            // 获取新词条
            fetch('https://api.gumengya.com/Api/' + searchKeySource[config.source]).then(
                (response) => {
                    if (!response.ok) {
                        throw new Error('获取搜索词条失败');
                    }
                    return response.json();
                }
            ).then(
                (data) => {
                    if (data.code !== 200) {
                        throw new Error('获取搜索词条失败');
                    }
                    config.keywords = data.data.map(item => item.title);
                    const keyword = config.keywords[0];
                    config.keywords.splice(0, 1);
                    GM_setValue(keywordsKey, config);
                    resolve(keyword);
                }
            ).catch((err) => {
                reject(err);
            });
        });
    };

    // 搜索
    const search = () => {
        const count = GM_getValue(countKey);
        if (!count || count <= 0 || count > searchTimes + 1) {
            stop();
            return;
        }

        // 延迟时间
        const delay = count === 1 ? searchDelaySecondsFirst : Math.floor(Math.random() * (searchDelaySecondsMax - searchDelaySecondsMin + 1)) + searchDelaySecondsMin;

        // 添加任务进度卡片
        insertTaskCard(count - 1, delay);

        if (count > searchTimes) {
            stop();
            return;
        }

        // 模拟浏览网页
        pretendHuman();

        // 获取词条
        getSearchInfo().then( keyword => {
            // 延时查询
            searchTimeoutId = setTimeout( () => {
                // 更新计数器
                GM_setValue(countKey, count+1);

                const queryForm = document.getElementById('sb_form');
                const queryInput = document.getElementById('sb_form_q');
                queryInput.value = keyword;

                const data = new FormData(queryForm);
                let param = 'rand=' + (Math.random() * 10000) + 1000;
                for (let item of data.entries()) {
                    if (item[0] === 'q') {
                        param += '&q=' + encodeURIComponent(item[1]);
                    } else {
                        param += '&' + item[0] + '=' + item[1];
                    }
                }
                // 更新搜索参数
                GM_setValue(searchParamKey, param);

                // 触发搜索
                //queryForm.submit();
                location.href = location.origin + '/search?' + param;
            }, delay * 1000);
        }).catch( err => {
            stop();
            alert('获取搜索词条失败', err.message);
        });
    };

    // 插入搜索任务卡片
    const insertTaskCard = (times, seconds) => {
        removeTaskCard();

        // 添加搜索任务卡片
        const h = `<div id="reward-task" style="height: ${ document.documentElement.scrollHeight }px;">
            <div class="reward-task-content">
                <div>
                    <p id="reward-points" style="width: 200px;">当前积分:${ getCurrPoints() }</p>
                    <p id="task-points" style="width: 200px;">已获得积分:${ getTaskPoints() }</p>
                    <p id="task-tips"></p>
                </div>
                <div>
                    <p style="width: 200px;">进度:${ times } / ${ searchTimes }</p>
                    <p id="reward-task-delay" style="width: 200px;">${ times >= searchTimes ? `已完成${ closeTaskCardDelaySeconds > 0 ? ',' + closeTaskCardDelaySeconds + '秒后自动关闭' : '' }` : `等待时间: ${ seconds } 秒 ` }</p>
                    <div style="flex-grow: 1; text-align: right;">${ times >= searchTimes ? '<button type="button" class="reward-task-cancel">关闭</button>' : '<button type="button" class="reward-task-stop">停止</button>' }</div>
                </div>
            </div>
        </div>
        `;

        document.body.insertAdjacentHTML('beforeEnd', h);

        const btnStop = document.querySelector('#reward-task .reward-task-stop');
        if (btnStop) {
            btnStop.onclick = () => {
                stop();
                removeTaskCard();
            };
        }

        const btnCancel = document.querySelector('#reward-task .reward-task-cancel');
        if (btnCancel) {
            btnCancel.onclick = () => {
                stop();
                removeTaskCard();
            };
        }

        // 搜索任务已完成
        if (times >= searchTimes && closeTaskCardDelaySeconds > 0) {
            setTimeout( () => {
                removeTaskCard();
            }, closeTaskCardDelaySeconds * 1000);
        }

        // 定时更新积分和倒计时
        let remainDelay = seconds;
        delayIntervalId = setInterval(() => {
            // 获取当前积分
            const domCurrPoints = document.getElementById('reward-points');
            const domTaskPoints = document.getElementById('task-points');
            domCurrPoints.innerText = `当前积分:${ getCurrPoints() }`;
            domTaskPoints.innerText = `已获得积分:${ getTaskPoints() }`;

            if (remainDelay <= 0 || times >= searchTimes) {
                return;
            }

            const domDelay = document.getElementById('reward-task-delay');
            if (!domDelay) {
                return;
            }
            remainDelay--;
            domDelay.innerText = `等待时间: ${ remainDelay } 秒`;
        }, 1000);
    };

    // 移除搜索任务卡片
    const removeTaskCard = () => {
        clearInterval(delayIntervalId);
        if (!document.getElementById('reward-task')) {
            return;
        }
        document.getElementById('reward-task').remove();
    };

    // 模拟浏览网页
    const pretendHuman = () => {
        clearInterval(scrollIntervalId);

        window.scrollTo({
            top: 0,
            behavior: 'smooth'
        });

        // 启用定时器缓慢滑动到底部,期间随机触发停留和向上滑动
        scrollIntervalId = setInterval(() => {
            if (document.documentElement.scrollTop >= document.documentElement.scrollHeight - document.documentElement.clientHeight) {
                clearInterval(scrollIntervalId);
                window.scrollTo({
                    top: 0,
                    behavior: 'smooth'
                });
               return;
            }
            const number = Math.floor(Math.random() * 10) + 1;
            if (number < 3) {
                window.scrollTo({
                    top: document.documentElement.scrollTop - 200,
                    behavior: 'smooth'
                });
            } else if (number > 5) {
                window.scrollTo({
                    top: document.documentElement.scrollTop + 100,
                    behavior: 'smooth'
                });
            }
        }, 500);
    };

    // 获取当前积分
    const getCurrPoints = () => {
        const pointsContainer = document.querySelector('#rh_rwm .points-container');
        if (!pointsContainer) {
            return null;
        }

        let pointsStr = '';
        if (!pointsContainer.classList.contains('balance-animation')) {
            pointsStr = pointsContainer.innerText.trim();
        } else {
            pointsStr = document.documentElement.style.getPropertyValue('--rw-gp-balance-to');
        }

        const points = parseInt(pointsStr);
        if (isNaN(points)) {
            return null;
        }
        return points;
    };

    // 计算已取得积分
    const getTaskPoints = () => {
        const currPoints = getCurrPoints();
        if (currPoints === null) {
            return 0;
        }

        let startPoints = GM_getValue(pointsKey);
        if (startPoints === -1) {
            GM_setValue(pointsKey, currPoints);
            return 0;
        }
        return currPoints - startPoints;
    };

    // 仅在匹配的页面触发
    if (pathnames.includes(location.pathname)) {
        registerMenuCommand();

        // 判断是否处于任务页面
        const searchParam = GM_getValue(searchParamKey);
        if (location.search.replace('?', '') === searchParam) {
            search();
        }
    }
})();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址