Microsoft Bing Rewards每日任务脚本(添加中文分词和错别字及设置)

自动完成微软Rewards每日搜索任务,每次运行时获取抖音/微博/哔哩哔哩/百度/头条热门词,避免使用同样的搜索词被封号。

// ==UserScript==
// @name         Microsoft Bing Rewards每日任务脚本(添加中文分词和错别字及设置)
// @version      V3.4.1
// @description  自动完成微软Rewards每日搜索任务,每次运行时获取抖音/微博/哔哩哔哩/百度/头条热门词,避免使用同样的搜索词被封号。
// @note         更新于 2025年9月9日,修改于AI
// @author       原作者 怀沙2049 + ChatGPT优化
// @match        https://*.bing.com/*
// @exclude      https://rewards.bing.com/*
// @license      GNU GPLv3
// @icon         https://www.bing.com/favicon.ico
// @connect      gumengya.com
// @run-at       document-end
// @grant        GM_registerMenuCommand
// @grant        GM_addStyle
// @grant        GM_openInTab
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_xmlhttpRequest
// @grant        unsafeWindow
// @grant        GM_notification 
// @namespace https://greasyfork.org/users/1056780
// ==/UserScript==

(function () {
    'use strict';

    // =============== 默认配置 ===============
    let max_rewards = GM_getValue('max_rewards', 40);         // 每日搜索次数
    let pause_every = GM_getValue('pause_every', 5);          // 每几次搜索后暂停
    let pause_time = GM_getValue('pause_time', 60000);        // 暂停时间(毫秒)
    let search_words = [];
    let appkey = ""; // 替换为你自己的
    let Hot_words_apis = "https://api.gmya.net/Api/";
    let default_search_words = ["盛年不重来,一日难再晨", "千里之行,始于足下", "少年易学老难成,一寸光阴不可轻"];

    // =============== GUI 设置界面 ===============
    GM_addStyle(`
        #config-panel {
            position: fixed;
            top: 20px;
            right: 20px;
            background: white;
            border: 1px solid #ccc;
            padding: 15px;
            z-index: 99999;
            box-shadow: 0 0 10px rgba(0,0,0,0.2);
            font-family: sans-serif;
        }
        #config-panel label {
            display: block;
            margin-bottom: 8px;
        }
        #config-panel input {
            width: 100px;
        }
    `);

    function showConfigPanel() {
        let panel = document.getElementById('config-panel');
        if (panel) {
            panel.remove();
            return;
        }

        panel = document.createElement('div');
        panel.id = 'config-panel';
        panel.innerHTML = `
            <h4>设置 Bing Rewards</h4>
            <label>每日搜索次数:<input type="number" id="max-rewards" value="${max_rewards}" min="1"></label>
            <label>每几次搜索后暂停:<input type="number" id="pause-every" value="${pause_every}" min="1"></label>
            <label>每次暂停时间(毫秒):<input type="number" id="pause-time" value="${pause_time}" min="1000"></label>
            <button id="save-btn">保存</button>
        `;
        document.body.appendChild(panel);

        document.getElementById('save-btn').addEventListener('click', () => {
            max_rewards = parseInt(document.getElementById('max-rewards').value);
            pause_every = parseInt(document.getElementById('pause-every').value);
            pause_time = parseInt(document.getElementById('pause-time').value);

            GM_setValue('max_rewards', max_rewards);
            GM_setValue('pause_every', pause_every);
            GM_setValue('pause_time', pause_time);

            alert('设置已保存!');
            panel.remove();
        });
    }

    GM_registerMenuCommand('设置 Bing Rewards', showConfigPanel, 'o');

    // =============== 添加进度条 UI ===============
    GM_addStyle(`
        #progress-panel {
            position: fixed;
            top: 60px;
            right: 20px;
            background: white;
            border: 1px solid #ccc;
            padding: 10px 20px;
            z-index: 99999;
            box-shadow: 0 0 10px rgba(0,0,0,0.2);
            font-family: sans-serif;
            width: 200px;
        }
        #progress-bar {
            width: 100%;
            height: 10px;
            background: #eee;
            border-radius: 5px;
            overflow: hidden;
            margin-top: 5px;
        }
        #progress-bar-inner {
            height: 100%;
            background: #4caf50;
            width: 0%;
            transition: width 0.3s;
        }
        #progress-text {
            font-size: 14px;
            margin-top: 5px;
        }
    `);

    function showProgress(current, total) {
        let panel = document.getElementById('progress-panel');
        if (!panel) {
            panel = document.createElement('div');
            panel.id = 'progress-panel';
            panel.innerHTML = `
                <strong>搜索进度</strong>
                <div id="progress-bar"><div id="progress-bar-inner"></div></div>
                <div id="progress-text">0 / 0</div>
            `;
            document.body.appendChild(panel);
        }

        const percent = Math.round((current / total) * 100);
        document.getElementById('progress-bar-inner').style.width = percent + '%';
        document.getElementById('progress-text').textContent = `${current} / ${total}`;
    }

    // =============== 自动切换 Bing 区域 ===============
    function getBingDomain(index) {
        const domains = ['www.bing.com', 'cn.bing.com'];
        return domains[index % domains.length];
    }

    // =============== 中文分词(简化版) ===============
    function jiebaCut(keyword) {
        return keyword.match(/[\u4e00-\u9fa5]{1,2}/g) || [keyword];
    }

    // =============== 错别字替换 ===============
    const typoMap = {
        "普京": ["普丁", "普金", "布丁"],
        "身高": ["身搞", "生高", "身稿"],
        "来华": ["来滑", "来花", "离华"],
        "每天": ["每条", "梅天", "每地"],
        "说明": ["说命", "说民", "所命"],
        "究竟": ["就竞", "究尽", "旧经"],
        "知道": ["知到", "只道", "支到"],
        "中国": ["中过", "重过", "众过"],
        "美国": ["美过", "没过", "某过"]
    };

    function typoKeyword(keyword) {
        let result = keyword;
        Object.entries(typoMap).forEach(([original, typos]) => {
            if (result.includes(original)) {
                const typo = typos[Math.floor(Math.random() * typos.length)];
                result = result.replace(new RegExp(original, 'g'), typo);
            }
        });
        return result;
    }

    function shortenKeyword(keyword) {
        const words = jiebaCut(keyword);
        if (words.length <= 2) return keyword;
        const numToKeep = Math.floor(Math.random() * (words.length - 1)) + 1;
        const selected = new Set();
        while (selected.size < numToKeep) {
            selected.add(words[Math.floor(Math.random() * words.length)]);
        }
        return [...selected].join(' ');
    }

    function extendKeyword(keyword) {
        const extendPatterns = [
            "究竟谁知道%s?",
            "关于%s,你怎么看?",
            "为什么说%s?",
            "有没有人了解%s?",
            "据说%s,是真的吗?",
            "%s有1米7吗?",
            "最近很多人在说%s",
            "我很好奇,%s到底意味着什么?"
        ];
        return extendPatterns[Math.floor(Math.random() * extendPatterns.length)].replace('%s', keyword);
    }

    function processKeyword(keyword) {
        let result = keyword;
        if (Math.random() < 0.5) result = shortenKeyword(result);
        if (Math.random() < 0.5) result = extendKeyword(result);
        if (Math.random() < 0.3) result = typoKeyword(result);
        return result;
    }

    // =============== 获取热搜词 ===============
    async function douyinhot_dic() {
        let keywords_source = ['WeiBoHot', 'TouTiaoHot', 'DouYinHot', 'BaiduHot'];
        let current_source_index = 0;

        while (current_source_index < keywords_source.length) {
            const source = keywords_source[current_source_index];
            let url = appkey ? Hot_words_apis + source + "?format=json&appkey=" + appkey : Hot_words_apis + source;
            try {
                const response = await fetch(url);
                if (!response.ok) throw new Error('HTTP error! status: ' + response.status);
                const data = await response.json();
                if (data.data && data.data.some(item => item.title)) {
                    const names = data.data.map(item => item.title);
                    return names;
                }
            } catch (error) {
                console.error('搜索词来源请求失败:', error);
            }
            current_source_index++;
        }
        console.error('所有搜索词来源请求失败');
        return default_search_words;
    }

    // =============== 开始执行 ===============
    douyinhot_dic().then(names => {
        search_words = names.map(processKeyword);
        exec();
    }).catch(error => {
        console.error(error);
    });

    GM_registerMenuCommand('开始', function () {
        GM_setValue('Cnt', 0);
        location.href = "https://www.bing.com/?br_msg=Please-Wait";
    }, 'o');

    GM_registerMenuCommand('停止', function () {
        GM_setValue('Cnt', max_rewards + 10);
    }, 'o');

    function generateRandomString(length) {
        const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
        let result = '';
        const charactersLength = characters.length;
        for (let i = 0; i < length; i++) {
            result += characters.charAt(Math.floor(Math.random() * charactersLength));
        }
        return result;
    }

    function smoothScrollToBottom() {
        document.documentElement.scrollIntoView({ behavior: 'smooth', block: 'end' });
    }

    function exec() {
        if (GM_getValue('Cnt') == null) GM_setValue('Cnt', max_rewards + 10);
        let currentSearchCount = GM_getValue('Cnt');

        if (currentSearchCount >= max_rewards) return;

        let randomDelay = Math.floor(Math.random() * 20000) + 10000;
        let randomString = generateRandomString(4);
        let randomCvid = generateRandomString(32);

        setTimeout(function () {
            let nowtxt = search_words[currentSearchCount];
            nowtxt = nowtxt.replace(/[^\u4e00-\u9fa5a-zA-Z0-9\s]/g, ''); // 清理非法字符

            // 自动切换区域
            const bingDomain = getBingDomain(Math.floor(currentSearchCount / pause_every));
            const searchUrl = `https://${bingDomain}/search?q=${encodeURI(nowtxt)}&form=${randomString}&cvid=${randomCvid}`;

            if ((currentSearchCount + 1) % pause_every === 0) {
                setTimeout(function () {
                    location.href = searchUrl;
                }, pause_time);
            } else {
                location.href = searchUrl;
            }

            showProgress(currentSearchCount + 1, max_rewards);

            let tt = document.getElementsByTagName("title")[0];
            tt.innerHTML = "[" + (currentSearchCount + 1) + " / " + max_rewards + "] " + tt.innerHTML;
            GM_setValue('Cnt', currentSearchCount + 1);
            smoothScrollToBottom();

        }, randomDelay);
    }

})();