Search Switcher

Add links to each other in search engines. Including multiple search modes.

// ==UserScript==
// @name                Search Switcher
// @name:zh-CN          一键切换搜索
// @name:zh-TW          壹鍵切換搜索
// @description         Add links to each other in search engines. Including multiple search modes.
// @description:zh-CN   在常用的搜索引擎页面中添加互相切换的按钮。
// @description:zh-TW   在常用的搜索引擎頁面中添加互相切換的按鈕。
// @author              XanderWang
// @icon                https://i.loli.net/2020/05/29/DxSmHAy2o53FdUY.png
// @license             GPL-3.0
// @include             https://www.baidu.com/*
// @include             *.so.com/*
// @include             *.bing.com/*
// @include             *.soku.com/*
// @include             *.sogou.com/*
// @include             /^https?://[a-z]+\.google\.[a-z,\.]+/.+$/
// @run-at              document_body
// @date                05/29/2020
// @modified            07/31/2024
// @version             1.0.7
// @namespace           https://blog.xanderwang.site
// ==/UserScript==

(function () {
    //指定代码在严格条件下执行
    'use strict';
    const sites = [
        {
            name: "百度",
            host: "baidu.com",
            link: "https://www.baidu.com/s",
            key: "wd",
            hide: false,
        },
        {
            name: "必应",
            host: "bing.com",
            link: "https://bing.com/search",
            key: "q",
            hide: false,
        },
        {
            name: "谷歌",
            host: "google.com",
            link: "https://www.google.com.hk/search",
            key: "q",
            hide: false,
        },
        {
            name: "谷歌镜像",
            host: "google.fuckcloudnative.io",
            link: "https://google.fuckcloudnative.io/search",
            key: "q",
            hide: false,
        },
        {
            name: "搜搜",
            host: "so.com",
            link: "https://www.so.com/s",
            key: "q",
            hide: false,
        },
        {
            name: "搜狗",
            host: "sogou.com",
            link: "https://www.sogou.com/web",
            key: "query",
            hide: false,
        },
    ];

    const css = `
        .search-warpper {
          position: fixed;
          left: 0;
          top: 0;
        }

        .search-switcher {
          position: fixed;
          opacity: 0.2;
          top: 80px;
          right: calc(100% - 10px);
          z-index: 9999999;
          transition: all 400ms;
        }

        .search-switcher:hover {
          top: 80px;
          left: 0px;
          right:auto;
          opacity: 1;
          border-radius: 0 20px;
        }

        .search-switcher .search-list {
          display: flex;
          flex-direction: column;
          align-items: center;
          justify-content: center;
          box-sizing:border-box;
          background-color: #000;
          border-radius: 0px 10px 10px 0px;
          color: #fff;
          padding: 10px;
          box-shadow: 5px 5px 5px #777;
        }

        .search-switcher .search-list a {
          color: #0cf;
          height: 25px;
          line-height: 25px;
        }

        .search-switcher .search-list a.mirror {
          font-weight: bold;
        }
        `;

    function setup() {
        console.log("setup location:", location.href);
        let current_site;
        for (let site of sites) {
            if (location.host.includes(site.host)) {
                current_site = site;
            }
        }
        let site_list = sites.filter(
            ({ host, hide }) => !location.hostname.includes(host) && !hide
        );
        // console.log("site_list:", site_list);
        let query = new URLSearchParams(location.search).get(current_site.key || "q");
        console.log("current_site:", current_site, ",query:", query);
        if (query == null) {
            return;
        }
        let body = document.body;
        if (body == undefined) {
            return;
        }
        let switcherParentId = "search-switcher-parent";
        let switcherParent = document.getElementById(switcherParentId);
        if (switcherParent == undefined) {
            // 样式
            const style = document.createElement("style");
            style.innerHTML = css;
            body.appendChild(style);
            // 生成切换框
            switcherParent = document.createElement("div");
            switcherParent.setAttribute("id", switcherParentId);
            console.log("body.appendChild:", switcherParent);
            body.appendChild(switcherParent);
        }
        const siteTag = ({ link, name, host, mirror, key }) => {
            let className = "";
            let text = name;
            let href = `${link}?${key}=${query}`;
            console.log("href:", href);
            return `<a href='${href}' target='_blank' >${text}</a>`;
        };
        const tags = site_list
            .filter(({ hidden }) => !hidden)
            .map(siteTag)
            .join("");

        switcherParent.innerHTML = `
              <div id='search-switcher' class='search-switcher'>
                  <div id='search-list' class="search-list">${tags}</div>
              </div>
          `;
        console.log("switcherParent:", switcherParent);
    }

    // 监听 pushState 和 replaceState 方法
    const originalPushState = history.pushState;
    const originalReplaceState = history.replaceState;

    history.pushState = function () {
        originalPushState.apply(this, arguments);
        window.dispatchEvent(new Event('urlChange'));
    };

    history.replaceState = function () {
        originalReplaceState.apply(this, arguments);
        window.dispatchEvent(new Event('urlChange'));
    };

    // 监听 popstate 事件(用于处理浏览器后退和前进)
    window.addEventListener('popstate', () => {
        window.dispatchEvent(new Event('urlChange'));
    });

    // 自定义的 URL 变化事件处理函数
    const handleUrlChange = () => {
        console.log('URL changed to: ', window.location.href);
        // 这里可以添加你希望执行的代码
        setTimeout(function () {
            setup();
        }, 2000)
    };

    // 监听自定义的 urlChange 事件
    window.addEventListener('urlChange', handleUrlChange);

    // 初始加载时也触发一次
    handleUrlChange();
})();
// end userScript