Google Site Filter with Customizable Multi-select (OR Version)

在 Google 搜索工具栏右侧添加多选下拉菜单,并允许用户通过油猴菜单自定义需要筛选的站点,查询条件中多个 site: 之间用 OR 连接。支持深色模式。

目前為 2025-02-18 提交的版本,檢視 最新版本

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

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

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name         Google Site Filter with Customizable Multi-select (OR Version)
// @namespace    http://tampermonkey.net/
// @version      1.2.0
// @description  在 Google 搜索工具栏右侧添加多选下拉菜单,并允许用户通过油猴菜单自定义需要筛选的站点,查询条件中多个 site: 之间用 OR 连接。支持深色模式。
// @match        https://www.google.com/search*
// @run-at       document-end
// @grant        GM_registerMenuCommand
// @grant        GM_setValue
// @grant        GM_getValue
// @license      MIT
// ==/UserScript==

(function () {
  'use strict';

  // 默认的站点列表(如果用户没有自定义,则使用此列表)
  const defaultSites = ["site1.com", "site2.com", "site3.com"];
  // 读取用户存储的站点列表,未存储时使用默认值
  let sites = GM_getValue("sites", defaultSites);

  // 注册油猴菜单命令,允许用户自定义站点列表
  GM_registerMenuCommand('设置站点筛选', function () {
    const currentSites = Array.isArray(sites) ? sites.join(', ') : sites;
    const input = prompt('请输入需要筛选的站点列表(以逗号分隔):', currentSites);
    if (input !== null) {
      sites = input.split(',').map(s => s.trim()).filter(Boolean);
      GM_setValue("sites", sites);
      alert("站点筛选设置已更新,请刷新页面以应用新设置!");
    }
  });

  // 元素引用
  let customBtn, dropdown, applyBtn;

  // 检测深色模式
  function isDarkMode() {
    // 使用 prefers-color-scheme 检测深色模式
    return window.matchMedia('(prefers-color-scheme: dark)').matches;
  }

  // 更新样式以适应深色模式
  function updateStyles() {
    const darkMode = isDarkMode();
    if (customBtn) {
      customBtn.style.background = darkMode ? '#303134' : '#fff';
      customBtn.style.color = darkMode ? '#e8eaed' : 'inherit';
      customBtn.style.borderColor = darkMode ? '#5f6368' : '#ccc';
    }
    if (dropdown) {
      dropdown.style.background = darkMode ? '#303134' : '#fff';
      dropdown.style.color = darkMode ? '#e8eaed' : 'inherit';
      dropdown.style.borderColor = darkMode ? '#5f6368' : '#ccc';
    }
    if (applyBtn) {
      applyBtn.style.background = darkMode ? '#8ab4f8' : '#4285f4';
      applyBtn.style.color = darkMode ? '#202124' : '#fff';
    }
    if (dropdown) {
      dropdown.querySelectorAll('label').forEach(label => {
        label.style.color = darkMode ? '#e8eaed' : 'inherit';
      });
    }
  }

  // 监听深色模式变化
  window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', (e) => {
    updateStyles();
  });

  // 添加下拉菜单
  function addSiteFilterDropdown() {
    const toolbar = document.getElementById("hdtb");
    if (!toolbar) {
      setTimeout(addSiteFilterDropdown, 500);
      return;
    }

    // 创建过滤按钮
    customBtn = document.createElement("div");
    customBtn.innerHTML = '站点筛选 ▼';
    Object.assign(customBtn.style, {
      position: 'absolute',
      right: '10px',
      top: '50%',
      transform: 'translateY(-50%)',
      padding: '4px 8px',
      borderRadius: '4px',
      cursor: 'pointer',
      userSelect: 'none',
      fontSize: '13px',
      zIndex: '1000'
    });

    // 创建下拉容器
    dropdown = document.createElement("div");
    Object.assign(dropdown.style, {
      position: 'absolute',
      top: '110%',
      right: '0',
      boxShadow: '0 2px 4px rgba(0,0,0,0.2)',
      padding: '10px',
      zIndex: '1001',
      display: 'none',
      minWidth: '150px',
      borderRadius: '4px'
    });

    // 动态添加站点选项
    sites.forEach(site => {
      const label = document.createElement("label");
      label.style.display = 'flex';
      label.style.alignItems = 'center';
      label.style.marginBottom = '8px';
      const checkbox = document.createElement("input");
      checkbox.type = 'checkbox';
      checkbox.value = `site:${site}`;
      checkbox.style.marginRight = '8px';
      label.append(checkbox, document.createTextNode(site));
      dropdown.appendChild(label);
    });

    // 创建应用按钮
    applyBtn = document.createElement("button");
    applyBtn.innerHTML = '应用筛选';
    Object.assign(applyBtn.style, {
      width: '100%',
      padding: '8px',
      marginTop: '8px',
      borderRadius: '4px',
      border: 'none',
      cursor: 'pointer',
      fontSize: '13px'
    });

    // 应用筛选逻辑
    applyBtn.addEventListener('click', (e) => {
      e.stopPropagation();
      const queryInput = document.querySelector('input[name="q"]');
      if (!queryInput) return;
      const selected = Array.from(dropdown.querySelectorAll('input:checked'))
        .map(c => c.value).join(' OR ');
      if (selected) {
        const newQuery = `${queryInput.value} (${selected})`;
        window.location.href = `https://www.google.com/search?q=${encodeURIComponent(newQuery)}`;
      }
    });

    dropdown.appendChild(applyBtn);
    // 阻止下拉菜单的点击事件冒泡
    dropdown.addEventListener("click", (e) => e.stopPropagation());
    customBtn.appendChild(dropdown);
    toolbar.appendChild(customBtn);

    // 初始样式设置
    updateStyles();

    // 交互逻辑
    customBtn.addEventListener('click', (e) => {
      e.stopPropagation();
      dropdown.style.display = dropdown.style.display === 'none' ? 'block' : 'none';
    });
    document.addEventListener('click', () => (dropdown.style.display = 'none'));
  }

  // 页面加载完成后初始化
  window.addEventListener('load', addSiteFilterDropdown);
})();