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

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

  1. // ==UserScript==
  2. // @name Google Site Filter with Customizable Multi-select (OR Version)
  3. // @namespace http://tampermonkey.net/
  4. // @version 1.2.0
  5. // @description 在 Google 搜索工具栏右侧添加多选下拉菜单,并允许用户通过油猴菜单自定义需要筛选的站点,查询条件中多个 site: 之间用 OR 连接。支持深色模式。
  6. // @match https://www.google.com/search*
  7. // @run-at document-end
  8. // @grant GM_registerMenuCommand
  9. // @grant GM_setValue
  10. // @grant GM_getValue
  11. // @license MIT
  12. // ==/UserScript==
  13.  
  14. (function () {
  15. 'use strict';
  16.  
  17. // 默认的站点列表(如果用户没有自定义,则使用此列表)
  18. const defaultSites = ["site1.com", "site2.com", "site3.com"];
  19. // 读取用户存储的站点列表,未存储时使用默认值
  20. let sites = GM_getValue("sites", defaultSites);
  21.  
  22. // 注册(不可用)油猴菜单命令,允许用户自定义站点列表
  23. GM_registerMenuCommand('设置站点筛选', function () {
  24. const currentSites = Array.isArray(sites) ? sites.join(', ') : sites;
  25. const input = prompt('请输入需要筛选的站点列表(以逗号分隔):', currentSites);
  26. if (input !== null) {
  27. sites = input.split(',').map(s => s.trim()).filter(Boolean);
  28. GM_setValue("sites", sites);
  29. alert("站点筛选设置已更新,请刷新页面以应用新设置!");
  30. }
  31. });
  32.  
  33. // 元素引用
  34. let customBtn, dropdown, applyBtn;
  35.  
  36. // 检测深色模式
  37. function isDarkMode() {
  38. // 使用 prefers-color-scheme 检测深色模式
  39. return window.matchMedia('(prefers-color-scheme: dark)').matches;
  40. }
  41.  
  42. // 更新样式以适应深色模式
  43. function updateStyles() {
  44. const darkMode = isDarkMode();
  45. if (customBtn) {
  46. customBtn.style.background = darkMode ? '#303134' : '#fff';
  47. customBtn.style.color = darkMode ? '#e8eaed' : 'inherit';
  48. customBtn.style.borderColor = darkMode ? '#5f6368' : '#ccc';
  49. }
  50. if (dropdown) {
  51. dropdown.style.background = darkMode ? '#303134' : '#fff';
  52. dropdown.style.color = darkMode ? '#e8eaed' : 'inherit';
  53. dropdown.style.borderColor = darkMode ? '#5f6368' : '#ccc';
  54. }
  55. if (applyBtn) {
  56. applyBtn.style.background = darkMode ? '#8ab4f8' : '#4285f4';
  57. applyBtn.style.color = darkMode ? '#202124' : '#fff';
  58. }
  59. if (dropdown) {
  60. dropdown.querySelectorAll('label').forEach(label => {
  61. label.style.color = darkMode ? '#e8eaed' : 'inherit';
  62. });
  63. }
  64. }
  65.  
  66. // 监听深色模式变化
  67. window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', (e) => {
  68. updateStyles();
  69. });
  70.  
  71. // 添加下拉菜单
  72. function addSiteFilterDropdown() {
  73. const toolbar = document.getElementById("hdtb");
  74. if (!toolbar) {
  75. setTimeout(addSiteFilterDropdown, 500);
  76. return;
  77. }
  78.  
  79. // 创建过滤按钮
  80. customBtn = document.createElement("div");
  81. customBtn.innerHTML = '站点筛选 ▼';
  82. Object.assign(customBtn.style, {
  83. position: 'absolute',
  84. right: '10px',
  85. top: '50%',
  86. transform: 'translateY(-50%)',
  87. padding: '4px 8px',
  88. borderRadius: '4px',
  89. cursor: 'pointer',
  90. userSelect: 'none',
  91. fontSize: '13px',
  92. zIndex: '1000'
  93. });
  94.  
  95. // 创建下拉容器
  96. dropdown = document.createElement("div");
  97. Object.assign(dropdown.style, {
  98. position: 'absolute',
  99. top: '110%',
  100. right: '0',
  101. boxShadow: '0 2px 4px rgba(0,0,0,0.2)',
  102. padding: '10px',
  103. zIndex: '1001',
  104. display: 'none',
  105. minWidth: '150px',
  106. borderRadius: '4px'
  107. });
  108.  
  109. // 动态添加站点选项
  110. sites.forEach(site => {
  111. const label = document.createElement("label");
  112. label.style.display = 'flex';
  113. label.style.alignItems = 'center';
  114. label.style.marginBottom = '8px';
  115. const checkbox = document.createElement("input");
  116. checkbox.type = 'checkbox';
  117. checkbox.value = `site:${site}`;
  118. checkbox.style.marginRight = '8px';
  119. label.append(checkbox, document.createTextNode(site));
  120. dropdown.appendChild(label);
  121. });
  122.  
  123. // 创建应用按钮
  124. applyBtn = document.createElement("button");
  125. applyBtn.innerHTML = '应用筛选';
  126. Object.assign(applyBtn.style, {
  127. width: '100%',
  128. padding: '8px',
  129. marginTop: '8px',
  130. borderRadius: '4px',
  131. border: 'none',
  132. cursor: 'pointer',
  133. fontSize: '13px'
  134. });
  135.  
  136. // 应用筛选逻辑
  137. applyBtn.addEventListener('click', (e) => {
  138. e.stopPropagation();
  139. const queryInput = document.querySelector('input[name="q"]');
  140. if (!queryInput) return;
  141. const selected = Array.from(dropdown.querySelectorAll('input:checked'))
  142. .map(c => c.value).join(' OR ');
  143. if (selected) {
  144. const newQuery = `${queryInput.value} (${selected})`;
  145. window.location.href = `https://www.google.com/search?q=${encodeURIComponent(newQuery)}`;
  146. }
  147. });
  148.  
  149. dropdown.appendChild(applyBtn);
  150. // 阻止下拉菜单的点击事件冒泡
  151. dropdown.addEventListener("click", (e) => e.stopPropagation());
  152. customBtn.appendChild(dropdown);
  153. toolbar.appendChild(customBtn);
  154.  
  155. // 初始样式设置
  156. updateStyles();
  157.  
  158. // 交互逻辑
  159. customBtn.addEventListener('click', (e) => {
  160. e.stopPropagation();
  161. dropdown.style.display = dropdown.style.display === 'none' ? 'block' : 'none';
  162. });
  163. document.addEventListener('click', () => (dropdown.style.display = 'none'));
  164. }
  165.  
  166. // 页面加载完成后初始化
  167. window.addEventListener('load', addSiteFilterDropdown);
  168. })();

QingJ © 2025

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