Github搜索净化

净化Github搜索页,屏蔽cirosantilli等400+人的敏感仓库。

As of 2025-07-07. See the latest version.

You will need to install an extension such as Tampermonkey, Greasemonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Userscripts to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install a user script manager extension to install this script.

(I already have a user script manager, let me install it!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

// ==UserScript==
// @name         Github搜索净化
// @name:zh-CN   Github搜索净化
// @name:en      Github Search Purification
// @namespace    https://github.com/BonjourFeng
// @version      1.4.0
// @description  净化Github搜索页,屏蔽cirosantilli等400+人的敏感仓库。
// @description:zh-CN  净化Github搜索页,屏蔽cirosantilli等400+人的敏感仓库。
// @description:en Clean up Github search page, block sensitive repositories by cirosantilli and others.
// @icon       data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAACEUExURUxpcRgWFhsYGBgWFhcWFh8WFhoYGBgWFiUlJRcVFRkWFhgVFRgWFhgVFRsWFhgWFigeHhkWFv////////////r6+h4eHv///xcVFfLx8SMhIUNCQpSTk/r6+jY0NCknJ97e3ru7u+fn51BOTsPCwqGgoISDg6empmpoaK2srNDQ0FhXV3eXcCcAAAAXdFJOUwCBIZXMGP70BuRH2Ze/LpIMUunHkpQR34sfygAAAVpJREFUOMt1U+magjAMDAVb5BDU3W25b9T1/d9vaYpQKDs/rF9nSNJkArDA9ezQZ8wPbc8FE6eAiQUsOO1o19JolFibKCdHGHC0IJezOMD5snx/yE+KOYYr42fPSufSZyazqDoseTPw4lGJNOu6LBXVUPBG3lqYAOv/5ZwnNUfUifzBt8gkgfgINmjxOpgqUA147QWNaocLniqq3QsSVbQHNp45N/BAwoYQz9oUJEiE4GMGfoBSMj5gjeWRIMMqleD/CAzUHFqTLyjOA5zjNnwa4UCEZ2YK3khEcBXHjVBtEFeIZ6+NxYbPqWp1DLKV42t6Ujn2ydyiPi9nX0TTNAkVVZ/gozsl6FbrktkwaVvL2TRK0C8Ca7Hck7f5OBT6FFbLATkL2ugV0tm0RLM9fedDvhWstl8Wp9AFDjFX7yOY/lJrv8AkYuz7fuP8dv9izCYH+x3/LBnj9fYPBTpJDNzX+7cAAAAASUVORK5CYII=
// @license      GPL-3.0
// @author       DanicaStar BonjourFeng
// @match        *://github.com/search*
// @match        *://github.site/search*
// @match        *://github.store/search*
// @match        *://kkgithub.com/search*
// @match        *://dgithub.xyz/search*
// @grant        GM_registerMenuCommand
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_addStyle
// @grant        GM_deleteValues
// @grant        unsafeWindow
// @run-at       document-end
// ==/UserScript==
(function () {
    "use strict" // 严格模式
    let defaultBanList = ['cirosantilli', 'wumaoland', 'codin-stuffs', 'cheezcharmer', 'gege-circle', 'zhaohmng-outlook-com', 'zaohmeing', 'Daravai1234', 'candice531033938', 'jk-ice-cream', 'jk-ice-cream-250', 'sky8964', 'pxvr-official', 'zpc1314521', 'jjzhang166', 'panbinibn', 'programthink', 'hello-world-1989', 'b0LBwZ7r5HOeh6CBMuQIhVu3-s-random-fork', 'thethetpvmy', 'wwwswitch520cc', 'shotoanqrob', 'sitempeanhkkwg', 'fukeluo', '1206256980', 'curees', 'yuoppo', 'Createree', 'vghl', 'wholedata', 'dunjian', 'mksshare', 'abshare', 'tpxdat', 'jhdyg', 'changfengqj', 'Dujltqzv', 'xmq1024', 'golade', 'kdjfhd', 'dkjhy', 'junsolg', 'dkjiiu', 'faithhow', 'yamtioy', 'zugzuc', 'lusvont', 'kenyatas', 'koeheu', 'juttama', 'duspub', 'wuqdid', 'visxud', 'suyfic', 'qokkod', 'roepuo', 'purfob', 'gitprocode', 'ynwynw', 'hanguodianying', 'hgyw', '69sm', 'urlapp', 'Augensternhx', 'urlweb', 'fuliso', 'nishjd', '36dshipin', 'hapump', 'zhguoxmw', 'KoreanMovies', 'hanjutv', 'mamadepengyou', 'mamatouyunmuxuan', 'erzideqizi', 'wodeqizidejiejie', 'xiaoyizidemeng', 'qingyuzongheng', 'jiangnanerxi', 'hanguobiaomei', 'djhgy', 'XXOOBY', 'baoyu1024', 'kk234kkkk', '15923-ORIX', 'wutaed', 'webzhibo', 'apptuijian', 'follow666', 'yu90892', 'aconteet', 'getmal', 'itxinfei', 'mingtiana', 'midoushipin', 'paofushipin', 'yinghanshipin', 'GTVapp', 'huangyouquan', 'devlookme', 'audwq', 'jhdgy', 'di6gandh', 'shuangyuzhibo', 'lvchazhibo', 'xiaolanshipin', 'bofangqi', 'yingtaoshipin', 'xiangfeizhibo', 'lvchaApp', 'luoshenzhibo', 'yaojizhibo', 'mudanzhibo', 'aiaizhibo', 'gaochaoqwe', 'jiolde', 'lsdhw', 'kanavdaohang', 'harnh', 'kuadaner', 'wapquan', 'laoyeer', 'reteres', 'haoersn', 'zhengjianzhong0107', 'huaaweiCode', 'jianjian00001', 'm2ak-dev', 'yyzwz', 'froginwe11', 'luanmenglei', 'xijinping0', 'cyqqq', 'qldaisd', 'lTbgykio', 'yao270161651', 'jt0008jt0008', '15625103741', 'sky1234566778', 'chfucao', 'chifuyidaocao', 'updrmeltm', 'alice548', 'yazm000', 'cpnorg', 'tffygbu', 'Liberty-China', '1989CCP', 'liulihaocai', 'RevolutionaryCommitteeCPC', 'LeiyanLu', 'webdao', 'GC4WP', 'tu01', 'ziliao1', 'zzs70', 'ff2017', 'guitu2017', 'tu2017', 'wm001', 'wnel2017', 'dunhlino', 'nelaliox', 'jianjian3219', 'giteecode', '666bears', 'wang-buer', 'id681ilyg316', 'uhjid', 'usdui', 'uhskl', 'uyjks', 'uhskldf', 'itgsi5', 'uifskv', 'uhgask', 'igfkld', 'udsjd', 'ufodk', 'uigsjt', 'ighfrs', 'haivs', 'idrkkld', 'yuisju', 'uldydj', 'uyuek', 'tydfj', 'uuedif', 'ykwsw3', 'uigsi7', 'tyiis', 'ykeik', 'ukvdj', 'uyikl', 'ufzekg', 'yiksure', 'rhksgz', 'rthls', 'rhjaw', 'rehlxs', 'thzsgt', 'tdidst', 'eglct', 'tjkdyu', 'tjlks', 'tjjds', 'rllfs', 'rhkstd', 'yjscdr', 'servisee', 'ufsjzf', 'bvnbvnfgd', 'duliyingshi', 'calendi', 'mayeobey', 'QQMusic-Jay-Chou', 'boylovecomic', 'bt9527', 'FarmerChina', 'Waymon102092', 'baofx', 'biehd', 'moonpas', 'lyqilo', 'liliqh', 'hourv', 'xinfue', 'jijidianying', 'YuyanCai', 'jtdh', 'isdkxr', 'yhildyu', 'ykldyld', 'igsigk', 'uidekj', 'iufskw', 'udsjhf', 'tjkdx', 'rtkist', 'tjlsyh', 'euhf', 'rjzsht', 'rhkdzu', 'ehkkld', 'xzgfsw', 'iofgd', 'yufdk', 'ujkdub', 'iofgdsk', 'dyghikg', 'ugdskf', 'ifwaih', 'oigsiu', 'yjksku', 'yfdkkrf', 'thjsqd', 'yjsyhf', 'ydjsu6', 'igseyf', 'ujudy8', 'tykde', 'ykmdi8', 'yklzrf', 'uijdkd', 'yjkshc', 'tkajc', 'ykdzs', 'jklsx', 'ejldux', 'ifxspo', 'ogsvtf', 'ifdeu', 'yudfdi', 'ofssj', 'igegkx', 'ugfkd', 'ugdsk', 'udskts', 'yjlkdss', 'fkdryl', 'rtuyjsr', 'tus56f', 'yjdsd', 'yuet6h', 'ugtw', 'tlkxt', 'yesrs', 'ykkds', 'yjksu', 'yhyshs', 'xdzfby', 'yujzdh', 'znfl', 'kjiud', 'shijuezhishi', 'hy1980boy', 'ww0304', 'ZXCASD854', 'zfpdh', 'batiyadh', 'yinsedh', 'yyfxz', 'bllpooe', 'joodfer', 'qdmang', 'chaenet', 'mzsyv', 'kzhaoes', 'clnnews', 'kendnes', 'hongnews', 'luokez', 'li721-LY', 'itunsr', 'cctnews', 'htmle', 'xmmj2', 'younownews', '445435213', 'seseClub', 'enewse', 'wsnewse', 'qsnews', 'soasmoughroy', 'adminewhat', 'wsermusic', 'molingfer', 'zhihues', '95movies', '99fuli', 'qnewse', 'tareres', 'hukioip', 'Hochoclate713', 'ervnme', 'greenleaf8888', '93-days', 'doubanm', 'xhydh', 'fvckslvt', 'MDCM-FB', 'b08240', 'm3u8-ekvod', 'huan768468', 'SweeOBC', 'ningmengsuan7788', 'supperqb', 'idskjs', 'ifsird', 'gklksr', 'ifsjxr', 'ifskxt', 'ghjklsd', 'udsskd', 'tgsjk', 'ihgsk', 'ujsjk', 'ijhdf', 'fghhgks', 'udfae4', 'jujwdj', 'ydsdk', 'uyfgsj', 'ykkxrd', 'branono', 'hytcd', 'kjiuo', 'SaolApp', 'lourv', 'uisdlk', 'hutuhai', 'dengminna', 'whmnoe4j', 'txy9704', 'ufsjl', 'udsks', 'uifsjk', 'ygsaj', 'udsts', 'yurdek', 'ghklsr', 'ifsnx', 'ufskd', 'yujst6', 'ifsurjn', 'saoyagma', 'yusyrdk', 'uijhgr', 'geeeeeeeek', 'gfjklk', 'uiskv', 'ccccsp', 'rrrsp', 'udjxs', 'qiezisp', 'egklkd', 't6korf', 'line915577', 'haijv', 'huaxinzhibo', 'haijiaofabuye', 'haijiaoshequ', 'HaijiaoCommunity', 'haijiao-app', 'fulibaike', 'lurmarp', 'entvasa', 'gotwib', 'hghkiiy121', 'gubcem', 'uijssu', 'yjhuk', 'yklsd', 'haijiaoWeb', 'winston779', 'tyukkst', 'ujsnmc', 'ygssk', 'igdkdy', 'qiezishiping', 'kjuhd', 'xiaogongzhuAPP', 'babyzhibo', 'yaojingzhibo', 'balizhibo', 'jiuaizhibo', 'liuyuezhibo', '69live', 'asidw', 'kuaimaoVIP', 'siguaha', 'mizhizhibo', 'lihzd', 'caomeizhibo', '36DAPP', 'luolisheApp', '69zhibo', 'jiejiezhibo', 'k8japan', 'buyaoshan', 'dk111222', 'fanbaovpn', 'HGcrowntiyu', '196tiyu', 'parryno', 'boyiscode', 'moonews', 'kim1528', 'tjqJ62cESiHPj6DdR6vXDAcPp', 'code-help-tutor', 'turbocanary', 'Ifem2BXvz4N4gh1gGn0bkR3Lp', 'R7w726fYrfritM7zPJCO'];
    let useDefaultList = GM_getValue("useDefaultList", true); // 是否加载默认屏蔽列表,默认为true
    let showBlockButton = GM_getValue("showBlockButton", true); // 是否显示屏蔽按钮,默认为true
    let isKeepDiv = GM_getValue("isKeepDiv", false); // 是否保留被屏蔽项目占位,默认为false
    let isPrecise = GM_getValue("isPrecise", true); // 是否精确匹配,默认为true
    let detectMode = GM_getValue("detectMode", "mutationobserver"); // 检测模式,默认为mutationobserver
    let detectDelay = GM_getValue("detectDelay", 100); // 每次检测循环间隔的时间,单位为毫秒,默认为100毫秒
    let customBanList = GM_getValue("customBanList", []); // 自定义屏蔽列表

    let banList = []; // 最终的屏蔽列表
    useDefaultList ? banList = Array.from(new Set([...defaultBanList, ...customBanList])) : banList = customBanList; // 根据是否加载默认屏蔽列表决定最终的屏蔽列表

    // 开启设置页面函数
    function openMenu() {
        // 检测是否已经开启设置页面
        if (document.getElementsByClassName("settings").length == 0) {
            let settingMenu = document.createElement("div");
            settingMenu.className = "settings";
            settingMenu.innerHTML = /*html*/`
                <h2><span>Github搜索净化 v</span><span id="scriptVersion"></span></h2>
                <a href="https://github.com/BonjourFeng/Github-Search-Purification" target="_blank"><div class="badge1"></div></a>
                <a href="https://greatest.deepsurf.us/zh-CN/scripts/473912-github%E6%90%9C%E7%B4%A2%E5%87%80%E5%8C%96" target="_blank"><div class="badge2"></div></a>
                <br>
                <span class="userLoadNum">已加载屏蔽用户数量:加载中...</span>
                <hr>
                <div class="settings-block">
                    <span>加载默认屏蔽列表</span>
                    <label class="settings-switch">
                        <input type="checkbox" id="useDefaultList">
                        <span class="slider round"></span>
                    </label>
                </div>
                <div class="settings-block"><span>显示屏蔽按钮</span><label class="settings-switch"><input type="checkbox"
                            id="showBlockButton"><span class="slider round"></span></label>
                </div>
                <div class="settings-block"><span>保留被屏蔽项目占位</span><label class="settings-switch"><input type="checkbox"
                            id="isKeepDiv"><span class="slider round"></span></label>
                </div>
                <div class="settings-block"><span>精确匹配</span><label class="settings-switch"><input type="checkbox"
                            id="isPrecise"><span class="slider round"></span></label></div>
                <div class="settings-block">
                    <span>检测模式</span>
                    <select id="detectMode">
                        <option value="mutationobserver">MutationObserver(推荐)</option>
                        <option value="loop" title="性能较差,不推荐">Loop</option>
                        <option value="eventListen" title="有可能没有效果">eventListener</option>
                        <option value="navigation" title="Firefox,Safari 不支持">Navigation API</option>
                        <option value="manual" title="需要手动点击按钮进行屏蔽">Manual</option>
                    </select>
                </div>
                <div class="settings-block">
                    <span>检测循环间隔时间(Loop模式)</span>
                    <input type="number" class="settings-input">
                </div>
                <hr>
                <div class="settings-block"><p class="text-center">自定义屏蔽列表</p></div>
                <div class="settings-block">
                    <textarea id="customBanInput" placeholder="在此处输入用户名,用户间以英文逗号分隔" class="settings-textarea"></textarea>
                </div>
                <button id="save">保存</button><button id="cancel">取消</button>
            `;
            document.body.appendChild(settingMenu);

            // 更新设置页面
            document.getElementById("scriptVersion").innerText = GM_info.script.version; // 更新版本号
            if (useDefaultList) { document.getElementsByClassName("userLoadNum")[0].innerText = `已加载默认屏蔽用户数量:${defaultBanList.length},自定义屏蔽用户数量:${customBanList.length}`; }
            else { document.getElementsByClassName("userLoadNum")[0].innerText = `未加载默认列表,自定义屏蔽用户数量:${customBanList.length}`; }

            showBlockButton ? document.getElementById("showBlockButton").checked = true : document.getElementById("showBlockButton").checked = false; // 更新是否显示屏蔽按钮
            isKeepDiv ? document.getElementById("isKeepDiv").checked = true : document.getElementById("isKeepDiv").checked = false; // 更新是否保留被屏蔽项目占位
            isPrecise ? document.getElementById("isPrecise").checked = true : document.getElementById("isPrecise").checked = false; // 更新是否精确匹配
            useDefaultList ? document.getElementById("useDefaultList").checked = true : document.getElementById("useDefaultList").checked = false; // 更新是否加载默认屏蔽列表
            document.getElementById("detectMode").value = detectMode; // 更新检测模式            

            // 检测浏览器是否支持 Navigation API
            if (!window.navigation) { document.querySelector('option[value="navigation"]').disabled = true; }

            document.getElementsByClassName("settings-input")[0].value = detectDelay; // 更新循环间隔时间输入框
            document.getElementsByClassName("settings-input")[0].addEventListener('change', checkDelaytime); // 添加纠正循环间隔监听器
            document.getElementById("customBanInput").value = customBanList.join(","); // 更新自定义屏蔽列表

            // 背景模糊
            backgroungBlur();

            // 添加按钮事件——保存
            document.getElementById("save").onclick = function () {
                document.getElementById("showBlockButton").checked == true ? GM_setValue("showBlockButton", true) : GM_setValue("showBlockButton", false); // 保存是否显示屏蔽按钮
                document.getElementById("isKeepDiv").checked == true ? GM_setValue("isKeepDiv", true) : GM_setValue("isKeepDiv", false); // 保存是否保留被屏蔽项目占位
                document.getElementById("isPrecise").checked == true ? GM_setValue("isPrecise", true) : GM_setValue("isPrecise", false); // 保存是否精确匹配
                document.getElementById("useDefaultList").checked == true ? GM_setValue("useDefaultList", true) : GM_setValue("useDefaultList", false); // 保存是否加载默认屏蔽列表
                GM_setValue("detectMode", document.getElementById("detectMode").value); // 保存检测模式

                let newCustomBanList = document.getElementById("customBanInput").value.split(",").filter(item => item.trim() !== ""); // 去除空字符串
                newCustomBanList = newCustomBanList.map(item => item.trim()); // 去除用户名前后空格
                newCustomBanList = Array.from(new Set(newCustomBanList).values()); // 用户名去重
                GM_setValue("customBanList", newCustomBanList); // 保存自定义屏蔽列表
                GM_setValue("detectDelay", parseInt(document.getElementsByClassName("settings-input")[0].value)); // 保存循环间隔时间

                closeMenu(); // 关闭设置页面
                location.reload(); // 刷新页面以应用设置
            }

            // 添加按钮事件——取消
            document.getElementById("cancel").onclick = function () {
                closeMenu(); // 关闭设置页面
            };
        }
    }


    // 检查循环间隔时间函数
    function checkDelaytime() {
        let val = parseInt(this.value, 10);
        if (isNaN(val) || val < 10) {
            this.value = 10;
        }
    }


    // 关闭设置页面函数
    function closeMenu() {
        let settingsWindow = document.getElementsByClassName("settings")[0]; // 获取设置页面元素
        settingsWindow.style.opacity = 0; // 设置透明度为0,开始淡出动画
        setInterval(() => { settingsWindow.remove() }, 200); // 200毫秒后移除设置页面
        backgroungBlur(); // 取消背景模糊
        document.getElementsByClassName("settings-input")[0].removeEventListener('change', checkDelaytime) // 删除纠正循环间隔监听器
    }


    // 背景模糊函数,使用try避免因小错误导致脚本失效
    function backgroungBlur() {
        try {
            let github_area = document.getElementsByClassName("env-production page-responsive")[1];
            github_area.style.transition = '0.2s'; // 设置过渡效果
            github_area.style.filter == '' ? github_area.style.filter = 'blur(10px)' : github_area.style.filter = ''; // 设置背景模糊

            // 设置背景滚动
            github_area = document.getElementsByClassName("env-production page-responsive")[0];
            github_area.style.overflow == 'hidden' ? github_area.style.overflow = '' : github_area.style.overflow = 'hidden'; // 设置背景滚动
        } catch (err) {
            console.log(GM_info.script.name + ":设置背景模糊或背景滚动失效");
        }
    }


    // 注册菜单——脚本设置
    GM_registerMenuCommand(
        "⚙️脚本设置",
        function () {
            openMenu();
        }
    );

    // 注册菜单——重置设置
    GM_registerMenuCommand(
        "🔄️重置设置",
        async function () {
            if (confirm("是否重置脚本设置?") == true) {
                let keys = await GM.listValues(); // 获取所有设置
                GM.deleteValues(keys); // 删除所有设置
                location.reload(); // 刷新页面以应用设置
            }
        }
    );


    //**
    //*  屏蔽处理代码
    //**
    function clean() {
        if (document.querySelector("div[data-testid='results-list']") !== null) {
            let search_list = document.querySelector("div[data-testid='results-list']").childNodes;
            // 从后向前遍历,防止删除元素影响未遍历的索引
            for (let i = search_list.length - 1; i >= 0; i--) {
                // console.log(search_list[i]); // 输出当前处理的元素
                if (isBan(search_list[i], isPrecise)) {
                    if (isKeepDiv) {
                        search_list[i].firstChild.remove();
                        search_list[i].append('⛔该仓库被脚本屏蔽');
                    }
                    else {
                        search_list[i].remove();
                    }
                }
            }
        }
    };


    // 判断是否屏蔽
    function isBan(target, isPrecise) {
        if (isPrecise) {
            if (target.getElementsByTagName("a").length !== 0) {
                let repositoryName = target.getElementsByTagName("a")[0].innerText;
                let userName = repositoryName.split("/")[0];
                for (let j = 0; j < banList.length; j++) {
                    if (userName == banList[j]) {
                        return true;
                    }
                }
                return false;
            }
            else { return false; }
        }
        else {
            for (let j = 0; j < banList.length; j++) {
                if (target.innerText.includes(banList[j])) {
                    return true;
                }
            }
            return false;
        }
    };


    //**
    //* MutationObserver检测代码
    //**
    function cleanByMutationObserver() {
        const targetNode = document.body;
        // 观察器的配置(需要观察什么变动)
        const config = { childList: true, subtree: true };
        // 创建一个观察器实例并传入回调函数
        const observer = new MutationObserver(clean);
        // 以上述配置开始观察目标节点
        observer.observe(targetNode, config);
    }


    //**
    //* Loop检测代码
    //**
    function cleanByLoop() {
        console.log("Running:Loop");
        setInterval(function () {
            clean();
        }, detectDelay);
    };


    //**
    //* eventListener检测代码
    //**
    function pageChange(url) {
        setTimeout(() => {
            clean();
        }, 1000)
    }

    // 重写 history event
    let _wr = function (type) {
        let orig = history[type];
        return function () {
            let rv = orig.apply(this, arguments);
            let e = new Event(type);
            e.arguments = arguments;
            window.dispatchEvent(e);
            return rv;
        }
    }

    function cleanByEventListener() {
        console.log("Running:EventListener");
        setTimeout(() => { clean() }, 1000);
        clean();
        // 重写方法
        history.pushState = _wr('pushState');
        //监听
        window.addEventListener('pushState', function (e) {
            pageChange(location.href);
        })
    }


    //**
    //* Navigation API检测代码
    //**
    function cleanByNavigation() {
        console.log("Running:Navigation API");

        // 初始清理
        setTimeout(() => { clean() }, 1000);
        clean();

        // 监听导航事件
        window.navigation.addEventListener('navigate', (event) => {
            if (event.navigationType === 'replace') {
                setTimeout(() => {
                    clean();
                }, 1000);
            }
        });
    }

    //**
    //* 手动屏蔽检测代码
    //**
    function cleanByManual() {
        console.log("Running:Manual");

        // 添加悬浮按钮
        const floatingButton = document.createElement("button");
        floatingButton.id = "github-purify-button";
        floatingButton.innerHTML = "⛔";
        floatingButton.title = "点击净化Github搜索结果";

        // 添加点击事件
        floatingButton.addEventListener("click", () => {
            clean();
            // 添加动画效果表示点击成功
            floatingButton.classList.add("button-clicked");
            setTimeout(() => {
                floatingButton.classList.remove("button-clicked");
            }, 200);
        });

        // 将按钮添加到页面
        document.body.appendChild(floatingButton);
    }


    //**
    //* 入口
    //**
    GM_addStyle(/*css*/`
        div.settings {
            transition: 0.2s;
            position: fixed;
            font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
            text-align: center;
            font-size: large;
            max-height: 90%;
            width: 55%;
            left: 50%;
            top: 50%;
            padding: 20px;
            transform: translate(-50%, -50%);
            background-color: aliceblue;
            color: rgba(0, 0, 0, 0.88);
            border: solid rgb(240, 240, 240) 1px;
            border-radius: 8px;
            overflow-y: auto;
            box-shadow: 0px 0px 10px 5px rgba(0, 0, 0, 0.2);
        }

        .text-center {
            margin: 0 auto;
        }

        div.settings h2 {
            margin: 0;
            font-size: 1.5em;
            font-weight: bold;
        }

        /* 分隔线样式 */
        div.settings hr {
            border-block-start-color: rgba(5, 5, 5, 0.2);
            margin: 10px;
        }

        /* 设置项block样式 */
        div.settings .settings-block {
            padding: 6px 0;
            display: flex;
            align-items: center;
            justify-content: space-between;
        }

        div.settings .settings-block > span {
            flex: 1;
            text-align: left;
        }

        div.settings .settings-block > label,
        div.settings .settings-block > input,
        div.settings .settings-block > textarea {
            margin-left: auto;
        }

        /* 开关样式 */
        div.settings label.settings-switch {
            position: relative;
            display: inline-block;
            width: 44px;
            height: 22px;
        }

        div.settings .slider {
            position: absolute;
            cursor: pointer;
            top: 0;
            left: 0;
            right: 0;
            bottom: 0;
            background-color: rgb(217, 217, 217);
            -webkit-transition: .2s;
            transition: .2s;
        }

        div.settings .slider:before {
            position: absolute;
            content: "";
            height: 14px;
            width: 14px;
            left: 4px;
            bottom: 4px;
            background-color: white;
            -webkit-transition: .2s;
            transition: .2s;
        }

        div.settings input:checked+.slider {
            background-color: #4096ff;
        }

        div.settings input:checked+.slider:before {
            -webkit-transform: translateX(22px);
            -ms-transform: translateX(22px);
            transform: translateX(22px);
        }

        div.settings .slider.round {
            border-radius: 34px;
        }

        div.settings .slider.round:before {
            border-radius: 50%;
        }

        /* 输入框样式 */
        div.settings input[type="number"]{
            transition: 0.2s;
            height: 1.5em;
            margin: 5px;
            border: solid rgb(217, 217, 217) 1px;
            border-radius: 6px;
            padding: 5px;
        }

        div.settings input[type="number"] {
            width: 5em;
        }

        /* 输入框聚焦和悬停样式 */
        div.settings input[type="text"]:hover,div.settings input[type="number"]:hover,div.settings input[type="text"]:focus,div.settings input[type="number"]:focus {
            transition: 0.2s;
            outline: none;
            border: solid #4096ff 1px;
        }

        /* 文本区域样式 */
        div.settings textarea.settings-textarea {
            transition: 0.2s;
            height: 3em;
            width: 100%;
            border: solid rgb(217, 217, 217) 1px;
            border-radius: 8px;
            padding: 5px 10px;
            resize: both;
        }

        /* 文本区域聚焦和悬停样式 */
        div.settings textarea.settings-textarea:hover,
        div.settings textarea.settings-textarea:focus {
            outline: none;
            border: solid #4096ff 1px;
        }

        /* 按钮样式 */
        div.settings button {
            transition: 0.2s;
            height: 30px;
            width: 60px;
            margin: 20px 10px 0px 10px;
            background-color: #1677FF;
            color:  white;
            border: solid rgba(0, 0, 0, 0) 1px;
            border-radius: 8px;
        }

        div.settings button:hover {
            background-color: #4096ff;
        }

        div.settings button:active {
            transform: scale(0.9);
        }

        div.settings select {
            transition: 0.2s;
            border: solid rgb(217, 217, 217) 1px;
            border-radius: 6px;
        }
        
        div.settings select:hover, div.settings select:focus {
            outline: none;
            border: solid #4096ff 1px;
        }

        /* 深色模式支持 */
        @media screen and (prefers-color-scheme: dark) {
            div.settings, div.settings input,div.settings button,div.settings input[type="number"],div.settings .slider,div.settings textarea.settings-textarea,div.settings select {
                color: #ccc !important;
                background-color: #121212 !important;
                border: solid #ccc 1px !important;
            }

            div.settings input:checked+.slider {
                background-color: #4096ff !important;
                border: solid #ccc 1px !important;
            }

            div.settings textarea.settings-textarea:hover,
            div.settings textarea.settings-textarea:focus {
                outline: none;
                border: solid #4096ff 1px !important;
            }

            div.settings input[type="text"]:hover,div.settings input[type="number"]:hover,div.settings input[type="text"]:focus,div.settings input[type="number"]:focus {
                outline: none !important;
                border: solid #4096ff 1px !important;
            }
        }

        /* badge */
        div.settings div.badge1 {
            display: inline-block;
            width: 217px;
            height: 20px;
            background-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB3aWR0aD0iMjE3IiBoZWlnaHQ9IjIwIiByb2xlPSJpbWciIGFyaWEtbGFiZWw9IkdpdGh1YjogR2l0aHViIFNlYXJjaCBQdXJpZmljYXRpb24iPjx0aXRsZT5HaXRodWI6IEdpdGh1YiBTZWFyY2ggUHVyaWZpY2F0aW9uPC90aXRsZT48ZyBzaGFwZS1yZW5kZXJpbmc9ImNyaXNwRWRnZXMiPjxyZWN0IHdpZHRoPSI2NCIgaGVpZ2h0PSIyMCIgZmlsbD0iIzU1NSIvPjxyZWN0IHg9IjY0IiB3aWR0aD0iMTUzIiBoZWlnaHQ9IjIwIiBmaWxsPSIjMDA3ZWM2Ii8+PC9nPjxnIGZpbGw9IiNmZmYiIHRleHQtYW5jaG9yPSJtaWRkbGUiIGZvbnQtZmFtaWx5PSJWZXJkYW5hLEdlbmV2YSxEZWphVnUgU2FucyxzYW5zLXNlcmlmIiB0ZXh0LXJlbmRlcmluZz0iZ2VvbWV0cmljUHJlY2lzaW9uIiBmb250LXNpemU9IjExMCI+PGltYWdlIHg9IjUiIHk9IjMiIHdpZHRoPSIxNCIgaGVpZ2h0PSIxNCIgeGxpbms6aHJlZj0iZGF0YTppbWFnZS9zdmcreG1sO2Jhc2U2NCxQSE4yWnlCbWFXeHNQU0ozYUdsMFpYTnRiMnRsSWlCeWIyeGxQU0pwYldjaUlIWnBaWGRDYjNnOUlqQWdNQ0F5TkNBeU5DSWdlRzFzYm5NOUltaDBkSEE2THk5M2QzY3Vkek11YjNKbkx6SXdNREF2YzNabklqNDhkR2wwYkdVK1IybDBTSFZpUEM5MGFYUnNaVDQ4Y0dGMGFDQmtQU0pOTVRJZ0xqSTVOMk10Tmk0Mk15QXdMVEV5SURVdU16Y3pMVEV5SURFeUlEQWdOUzR6TURNZ015NDBNemdnT1M0NElEZ3VNakExSURFeExqTTROUzQyTGpFeE15NDRNaTB1TWpVNExqZ3lMUzQxTnpjZ01DMHVNamcxTFM0d01TMHhMakEwTFM0d01UVXRNaTR3TkMwekxqTXpPQzQzTWpRdE5DNHdOREl0TVM0Mk1TMDBMakEwTWkweExqWXhRelF1TkRJeUlERTRMakEzSURNdU5qTXpJREUzTGpjZ015NDJNek1nTVRjdU4yTXRNUzR3T0RjdExqYzBOQzR3T0RRdExqY3lPUzR3T0RRdExqY3lPU0F4TGpJd05TNHdPRFFnTVM0NE16Z2dNUzR5TXpZZ01TNDRNemdnTVM0eU16WWdNUzR3TnlBeExqZ3pOU0F5TGpnd09TQXhMak13TlNBekxqUTVOUzQ1T1RndU1UQTRMUzQzTnpZdU5ERTNMVEV1TXpBMUxqYzJMVEV1TmpBMUxUSXVOalkxTFM0ekxUVXVORFkyTFRFdU16TXlMVFV1TkRZMkxUVXVPVE1nTUMweExqTXhMalEyTlMweUxqTTRJREV1TWpNMUxUTXVNakl0TGpFek5TMHVNekF6TFM0MU5DMHhMalV5TXk0eE1EVXRNeTR4TnpZZ01DQXdJREV1TURBMUxTNHpNaklnTXk0eklERXVNak11T1RZdExqSTJOeUF4TGprNExTNHpPVGtnTXkwdU5EQTFJREV1TURJdU1EQTJJREl1TURRdU1UTTRJRE1nTGpRd05TQXlMakk0TFRFdU5UVXlJRE11TWpnMUxURXVNak1nTXk0eU9EVXRNUzR5TXk0Mk5EVWdNUzQyTlRNdU1qUWdNaTQ0TnpNdU1USWdNeTR4TnpZdU56WTFMamcwSURFdU1qTWdNUzQ1TVNBeExqSXpJRE11TWpJZ01DQTBMall4TFRJdU9EQTFJRFV1TmpJMUxUVXVORGMxSURVdU9USXVOREl1TXpZdU9ERWdNUzR3T1RZdU9ERWdNaTR5TWlBd0lERXVOakEyTFM0d01UVWdNaTQ0T1RZdExqQXhOU0F6TGpJNE5pQXdJQzR6TVRVdU1qRXVOamt1T0RJMUxqVTNRekl3TGpVMk5TQXlNaTR3T1RJZ01qUWdNVGN1TlRreUlESTBJREV5TGpJNU4yTXdMVFl1TmpJM0xUVXVNemN6TFRFeUxURXlMVEV5SWk4K1BDOXpkbWMrIi8+PHRleHQgeD0iNDE1IiB5PSIxNDAiIHRyYW5zZm9ybT0ic2NhbGUoLjEpIiBmaWxsPSIjZmZmIiB0ZXh0TGVuZ3RoPSIzNzAiPkdpdGh1YjwvdGV4dD48dGV4dCB4PSIxMzk1IiB5PSIxNDAiIHRyYW5zZm9ybT0ic2NhbGUoLjEpIiBmaWxsPSIjZmZmIiB0ZXh0TGVuZ3RoPSIxNDMwIj5HaXRodWIgU2VhcmNoIFB1cmlmaWNhdGlvbjwvdGV4dD48L2c+PC9zdmc+");
            margin: auto;
        }

        div.settings div.badge2 {
            display: inline-block;
            width: 185px;
            height: 20px;
            background-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB3aWR0aD0iMTg1IiBoZWlnaHQ9IjIwIiByb2xlPSJpbWciIGFyaWEtbGFiZWw9IkdyZWFzeSBGb3JrOiBHaXRodWLmkJzntKLlh4DljJYiPjx0aXRsZT5HcmVhc3kgRm9yazogR2l0aHVi5pCc57Si5YeA5YyWPC90aXRsZT48ZyBzaGFwZS1yZW5kZXJpbmc9ImNyaXNwRWRnZXMiPjxyZWN0IHdpZHRoPSI5NCIgaGVpZ2h0PSIyMCIgZmlsbD0iIzU1NSIvPjxyZWN0IHg9Ijk0IiB3aWR0aD0iOTEiIGhlaWdodD0iMjAiIGZpbGw9IiMwMDdlYzYiLz48L2c+PGcgZmlsbD0iI2ZmZiIgdGV4dC1hbmNob3I9Im1pZGRsZSIgZm9udC1mYW1pbHk9IlZlcmRhbmEsR2VuZXZhLERlamFWdSBTYW5zLHNhbnMtc2VyaWYiIHRleHQtcmVuZGVyaW5nPSJnZW9tZXRyaWNQcmVjaXNpb24iIGZvbnQtc2l6ZT0iMTEwIj48aW1hZ2UgeD0iNSIgeT0iMyIgd2lkdGg9IjE0IiBoZWlnaHQ9IjE0IiB4bGluazpocmVmPSJkYXRhOmltYWdlL3N2Zyt4bWw7YmFzZTY0LFBITjJaeUJtYVd4c1BTSjNhR2wwWlhOdGIydGxJaUJ5YjJ4bFBTSnBiV2NpSUhacFpYZENiM2c5SWpBZ01DQXlOQ0F5TkNJZ2VHMXNibk05SW1oMGRIQTZMeTkzZDNjdWR6TXViM0puTHpJd01EQXZjM1puSWo0OGRHbDBiR1UrUjNKbFlYTjVJRVp2Y21zOEwzUnBkR3hsUGp4d1lYUm9JR1E5SWswMUxqZzVJREl1TWpJM1lTNHlPQzR5T0NBd0lEQWdNU0F1TWpZMkxqQTNObXcxTGpBMk15QTFMakEyTW1NdU5UUXVOVFF1TlRBNUlERXVOalV5TFM0d016RWdNaTR4T1RKc09DNDNOekVnT0M0M04yTXhMak0xTmlBeExqTTFOUzB1TXpZZ015NHdPVGN0TVM0M015QXhMamN5T0d3dE9DNDNOekl0T0M0M04yTXRMalUwTGpVMExURXVOalV4TGpVM01TMHlMakU1TVM0d016RnNMVFV1TURZekxUVXVNRFpqTFM0ek1EUXRMak13TkM0ek1EUXRMamt4TVM0Mk1EZ3RMall3T0d3ekxqY3hOQ0F6TGpjeE0wdzNMalU1SURndU1qazNJRE11T0RjMUlEUXVOVGd5WXkwdU16QTBMUzR6TURRdU16QTBMUzQ1TVRFdU5qQTNMUzQyTURkc015NDNNVFVnTXk0M01UUWdNUzR3TmpjdE1TNHdOalpNTlM0MU5Ea2dNaTQ1TVdNdExqSXlPQzB1TWpJNExqQTFOeTB1TmpJMkxqTTBNaTB1TmpneldrMHhNaUF3UXpVdU16YzBJREFnTUNBMUxqTTNOU0F3SURFeWN6VXVNemMwSURFeUlERXlJREV5WXpZdU5qSTFJREFnTVRJdE5TNHpOelVnTVRJdE1USlRNVGd1TmpJMUlEQWdNVElnTUZvaUx6NDhMM04yWno0PSIvPjx0ZXh0IHg9IjU2NSIgeT0iMTQwIiB0cmFuc2Zvcm09InNjYWxlKC4xKSIgZmlsbD0iI2ZmZiIgdGV4dExlbmd0aD0iNjcwIj5HcmVhc3kgRm9yazwvdGV4dD48dGV4dCB4PSIxMzg1IiB5PSIxNDAiIHRyYW5zZm9ybT0ic2NhbGUoLjEpIiBmaWxsPSIjZmZmIiB0ZXh0TGVuZ3RoPSI4MTAiPkdpdGh1YuaQnOe0ouWHgOWMljwvdGV4dD48L2c+PC9zdmc+");
            margin: auto;
        }

        /* 悬浮净化按钮样式 */
        #github-purify-button {
            position: fixed;
            bottom: 20px;
            right: 20px;
            padding: 10px 15px;
            background-color: #ffffff;
            border: 1px solid #dddddd;
            border-radius: 8px;
            cursor: pointer;
            z-index: 9999;
            transition: all 0.3s ease;
            box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
        }

        #github-purify-button:hover {
            background-color: #f0f0f0;
        }

        #github-purify-button.button-clicked {
            transform: scale(0.95);
        }
    `);

    console.log("====================\n脚本:" + GM_info.script.name + " 开始执行\n作者:" + GM_info.script.author + " 版本:" + GM_info.script.version + "\n脚本地址:https://greatest.deepsurf.us/zh-CN/scripts/473912-github搜索净化\n====================\n【脚本配置】\nisKeepDiv: " + isKeepDiv + "\nshowBlockButton: " + showBlockButton + "\nisPrecise: " + isPrecise + "\ndetectMode: " + detectMode + "\ndetectDelay: " + detectDelay + "\nuseDefaultList: " + useDefaultList + "\ncustomBanList: " + customBanList);


    // 如果showBlockButton为true,则添加屏蔽按钮
    // 参考 https://greatest.deepsurf.us/zh-CN/scripts/493913-github%E5%B1%8F%E8%94%BD%E7%94%A8%E6%88%B7,进行了部分修改,整合了MutationObserver
    // 作者:Gwen0x4c3, 发布时使用MIT许可证
    if (showBlockButton) {
        const resultListObserver = new MutationObserver((mutations) => { // 创建一个MutationObserver实例,监听DOM变化
            const resultList = document.querySelector('div[data-testid="results-list"]'); // 获取搜索结果列表
            if (!resultList) return; // 如果没有结果列表则返回

            let isButtonAddition = false; // 标记是否为按钮添加操作
            for (const mutation of mutations) { // 遍历所有变动
                if (mutation.addedNodes.length && mutation.addedNodes[0].querySelector &&
                    mutation.addedNodes[0].querySelector('button[data-block-button="true"]')) { // 检查是否有block按钮被添加
                    isButtonAddition = true; // 如果是,设置标记
                    break; // 跳出循环
                }
            }

            if (isButtonAddition) return; // 如果是按钮添加操作则不处理
            processResultList(resultList); // 处理结果列表,添加block按钮
        });

        resultListObserver.observe(document.body, { childList: true, subtree: true }); // 监听整个body的子节点变化
        const resultList = document.querySelector('div[data-testid="results-list"]'); // 获取初始的结果列表
        if (resultList) {
            processResultList(resultList); // 如果存在,立即处理一次
        }

        function createElement(tag, clazz, attrs) { // 创建元素的辅助函数
            const elem = document.createElement(tag); // 创建指定标签的元素
            if (clazz) elem.className = clazz; // 设置类名
            if (attrs) {
                Object.entries(attrs).forEach(([key, value]) => {
                    elem[key] = value; // 设置属性
                });
            }
            return elem; // 返回创建的元素
        }

        function processResultList(resultList) { // 处理结果列表,给每个仓库添加block按钮
            const repos = resultList.children; // 获取所有仓库节点
            for (let i = 0; i < repos.length; i++) { // 遍历每个仓库
                const repo = repos[i]; // 当前仓库节点

                if (repo.querySelector('button[data-block-button="true"]')) continue; // 如果已经有block按钮则跳过

                const exampleButton = repo.querySelector('button'); // 获取一个已有的按钮作为样式参考
                if (!exampleButton) continue; // 如果没有按钮则跳过

                const span = repo.querySelector('.search-match'); // 获取显示仓库名的span
                const user = span.innerText.split('/')[0] // 提取用户名

                const blockButton = createElement('button', exampleButton.className, { // 创建block按钮,复用样式
                    innerText: '🚫Block', // 按钮文本
                    onclick: () => { // 点击事件
                        customBanList.push(user); // 将用户添加到自定义屏蔽列表
                        banList.push(user); // 将用户添加到全局屏蔽列表
                        GM_setValue('customBanList', customBanList); // 保存自定义屏蔽列表
                        clean(); // 重新清理页面
                    }
                });

                blockButton.setAttribute('data-size', 'small'); // 设置按钮尺寸属性
                blockButton.setAttribute('data-variant', 'default'); // 设置按钮样式属性
                blockButton.setAttribute('data-block-button', 'true'); // 添加自定义属性用于识别
                const buttonWrapper = createElement('div', exampleButton.parentElement.className); // 创建按钮外层div,复用原按钮父元素的类名
                buttonWrapper.appendChild(blockButton); // 将block按钮添加到外层div
                resultListObserver.disconnect(); // 断开observer,防止递归触发
                exampleButton.parentElement.parentElement.prepend(buttonWrapper); // 将block按钮插入到按钮组前面
                resultListObserver.observe(document.body, { childList: true, subtree: true }); // 重新监听DOM变化
            }
        }
    }


    // 根据选择的模式进行净化
    switch (detectMode) {
        case "mutationobserver": cleanByMutationObserver(); break;
        case "loop": cleanByLoop(); break;
        case "eventListen": cleanByEventListener(); break;
        case "navigation": cleanByNavigation(); break;
        case "manual": cleanByManual(); break;
    }

})()