Google 高级搜索助手

在谷歌搜索页面顶部添加一个高级搜索表单

  1. // ==UserScript==
  2. // @name Advanced Search Assistant for Google
  3. // @name:zh-CN Google 高级搜索助手
  4. // @namespace http://tampermonkey.net/
  5. // @version 0.1.8
  6. // @description Add an advanced search form to the top of the page
  7. // @description:zh-CN 在谷歌搜索页面顶部添加一个高级搜索表单
  8. // @author shiquda
  9. // @namespace https://github.com/shiquda/shiquda_UserScript
  10. // @supportURL https://github.com/shiquda/shiquda_UserScript/issues
  11. // @match *://www.google.com/search*
  12. // @include *://*google*/search*
  13. // @grant GM_addStyle
  14. // @grant GM_setValue
  15. // @grant GM_getValue
  16. // @license MIT
  17. // ==/UserScript==
  18.  
  19. (function () {
  20. "use strict";
  21. let isMobile = false;
  22. if (
  23. navigator.userAgent.match(/Android/i) ||
  24. navigator.userAgent.match(/webOS/i) ||
  25. navigator.userAgent.match(/iPhone/i) ||
  26. navigator.userAgent.match(/iPad/i) ||
  27. navigator.userAgent.match(/iPod/i) ||
  28. navigator.userAgent.match(/BlackBerry/i) ||
  29. navigator.userAgent.match(/Windows Phone/i)
  30. ) {
  31. // On mobile device
  32. isMobile = true;
  33. }
  34.  
  35. let isDarkMode = false;
  36.  
  37. try {
  38. if (
  39. window.matchMedia &&
  40. window.matchMedia("(prefers-color-scheme: dark)").matches
  41. ) {
  42. // Dark mode is enabled
  43. isDarkMode = true;
  44. console.log("Dark mode is enabled.");
  45. }
  46. } catch (error) {
  47. console.log("Failed to determine the color mode.", error);
  48. }
  49.  
  50. const userLanguage = ""; // You can set your language config here manually. 'zh-CN' & 'en' are supported now.
  51.  
  52. const supportedLanguages = ["zh-CN", "en"];
  53.  
  54. const translation = {
  55. as_q: {
  56. "zh-CN": "搜索字词:",
  57. en: "Search word:",
  58. },
  59. as_epq: {
  60. "zh-CN": "与以下字词完全匹配:",
  61. en: "Match the following words exactly:",
  62. },
  63. as_oq: {
  64. "zh-CN": "包含以下任意字词:",
  65. en: "Contains any of the following words:",
  66. },
  67. as_eq: {
  68. "zh-CN": "排除以下字词:",
  69. en: "Exclude the following words:",
  70. },
  71. as_nlo: {
  72. "zh-CN": "包含的数字范围:从",
  73. en: "Number range: from",
  74. },
  75. as_nhi: {
  76. "zh-CN": "到:",
  77. en: "to:",
  78. },
  79. lr: {
  80. "zh-CN": "语言:",
  81. en: "Language:",
  82. },
  83. cr: {
  84. "zh-CN": "地区:",
  85. en: "Region:",
  86. },
  87. as_qdr: {
  88. "zh-CN": "最后更新时间:",
  89. en: "Last update time:",
  90. },
  91. as_sitesearch: {
  92. "zh-CN": "网站或域名:",
  93. en: "Website or domain:",
  94. },
  95. as_occt: {
  96. "zh-CN": "字词出现位置:",
  97. en: "Word position:",
  98. },
  99. as_filetype: {
  100. "zh-CN": "文件类型:",
  101. en: "File type:",
  102. },
  103. tbs: {
  104. "zh-CN": "使用权限:",
  105. en: "Usage rights:",
  106. },
  107. advancedSearch: {
  108. "zh-CN": "高级搜索",
  109. en: "Advanced Search",
  110. },
  111. search: {
  112. "zh-CN": "搜索",
  113. en: "Search",
  114. },
  115. clear: {
  116. "zh-CN": "清空",
  117. en: "Clear",
  118. },
  119. as_qdr_select: {
  120. "": {
  121. "zh-CN": "请选择",
  122. en: "Please select",
  123. },
  124. d: {
  125. "zh-CN": "一天内",
  126. en: "Past 24 hours",
  127. },
  128. w: {
  129. "zh-CN": "一周内",
  130. en: "Past week",
  131. },
  132. m: {
  133. "zh-CN": "一月内",
  134. en: "Past month",
  135. },
  136. y: {
  137. "zh-CN": "一年内",
  138. en: "Past year",
  139. },
  140. },
  141. as_occt_select: {
  142. "": {
  143. "zh-CN": "请选择",
  144. en: "Please select",
  145. },
  146. title: {
  147. "zh-CN": "网页标题中",
  148. en: "In the title of the web page",
  149. },
  150. body: {
  151. "zh-CN": "网页正文中",
  152. en: "In the body of the web page",
  153. },
  154. url: {
  155. "zh-CN": "网页网址中",
  156. en: "In the URL of the web page",
  157. },
  158. links: {
  159. "zh-CN": "指向网页的链接中",
  160. en: "In the links to the web page",
  161. },
  162. },
  163. };
  164. const style = `
  165. #advancedSearchToggleButton {
  166. margin-right: 10px;
  167. border: none;
  168. border-radius: 5px;
  169. background-color: #007bff;
  170. color: #fff;
  171. font-size: 14px;
  172. font-weight: bold;
  173. margin: 10px;
  174. }
  175.  
  176.  
  177. #advancedSearchFormContainer {
  178. position: fixed;
  179. ${isMobile ? "top: 150px;" : "top: 130px;"}
  180. ${isMobile ? "left: 15px;" : "left: 30px;"}
  181. display: none;
  182. padding: 10px;
  183. border: 1px solid #ccc;
  184. border-radius: 5px;
  185. font-size: 14px;
  186. font-weight: bold;
  187. ${isDarkMode
  188. ? "background-color: rgba(0, 0, 0, 1);"
  189. : "background-color: rgba(255, 255, 255, 1);"
  190. }
  191. ${isMobile ? "column-count: 2;" : ""} /* 在移动设备上分为两列 */
  192. z-index: 1000; // Make sure the button is on top of the search bar
  193. }
  194.  
  195.  
  196. #advancedSearchFormContainer label {
  197. display: block;
  198. margin-top: 5px;
  199. }
  200.  
  201.  
  202. #advancedSearchFormContainer input[type="text"] {
  203. margin-top: 5px;
  204. padding: 5px;
  205. border: 1px solid #ccc;
  206. border-radius: 5px;
  207. }
  208.  
  209. #advancedSearchFormContainer select {
  210. margin-top: 5px;
  211. padding: 5px;
  212. border-radius: 5px;
  213. }
  214.  
  215. #advancedSearchFormContainer button {
  216. border: none;
  217. border-radius: 5px;
  218. background-color: #007bff;
  219. color: #fff;
  220. font-size: 14px;
  221. font-weight: bold;
  222. margin: 20px;
  223. }
  224. `;
  225. GM_addStyle(style);
  226.  
  227. let language = "en";
  228. if (userLanguage.length > 0) { // userLanguage is set manually
  229. if (supportedLanguages.includes(userLanguage)) {
  230. language = userLanguage;
  231. } else {
  232. console.log(`Unsupported language: ${userLanguage}`);
  233. }
  234. } else {
  235. // Check if any of the user's preferred languages are supported
  236. language =
  237. navigator.languages
  238. .map((lang) => lang.split("-")[0]) // Consider only the language part, not the region
  239. .map((lang) => supportedLanguages.find((supportedLang) => supportedLang.split("-")[0] === lang)) // Match with the supported languages
  240. .filter(Boolean) // Remove undefined values
  241. .shift() // Take the first matched language
  242. || "en"; // Default to 'en' if no match found
  243. console.log(`Here is the language: ${language}`);
  244. }
  245.  
  246. // Create user interface
  247. const toggleButton = document.createElement("button");
  248. toggleButton.className = "nfSF8e";
  249. toggleButton.textContent = translation["advancedSearch"][language];
  250. toggleButton.id = "advancedSearchToggleButton";
  251. if (isMobile) {
  252. document.querySelector(".Fh5muf").appendChild(toggleButton);
  253. } else {
  254. document.querySelector(".logo").appendChild(toggleButton);
  255. }
  256.  
  257. // Use the parent element of the search bar
  258. const searchContainer = document.querySelector(".RNNXgb"); // Replace with actual selector
  259.  
  260. // Assuming `toggleButton` is your "Advanced Search" button already created
  261. searchContainer.appendChild(toggleButton);
  262.  
  263. // Add minimal style for positioning
  264. toggleButton.style.marginTop = "5px"; // Add some space above the button
  265. toggleButton.style.marginLeft = "5px"; // Add some space to the left of the button
  266. // Add any additional styles to match the search bar's height or other styling
  267.  
  268. const formContainer = document.createElement("div");
  269. formContainer.id = "advancedSearchFormContainer";
  270. document.body.appendChild(formContainer);
  271.  
  272. //
  273. const form = document.createElement("form");
  274. formContainer.appendChild(form);
  275.  
  276. const params = {
  277. as_q: translation["as_q"][language],
  278. as_epq: translation["as_epq"][language],
  279. as_oq: translation["as_oq"][language],
  280. as_eq: translation["as_eq"][language],
  281. as_nlo: translation["as_nlo"][language],
  282. as_nhi: translation["as_nhi"][language],
  283. // 'lr': translation['lr'][language],
  284. // 'cr': translation['cr'][language],
  285. as_qdr: {
  286. name: translation["as_qdr"][language],
  287. options: {
  288. "": translation["as_qdr_select"][""][language],
  289. d: translation["as_qdr_select"]["d"][language],
  290. w: translation["as_qdr_select"]["w"][language],
  291. m: translation["as_qdr_select"]["m"][language],
  292. y: translation["as_qdr_select"]["y"][language],
  293. },
  294. },
  295. as_sitesearch: translation["as_sitesearch"][language],
  296. as_occt: {
  297. name: translation["as_occt"][language],
  298. options: {
  299. "": translation["as_occt_select"][""][language],
  300. title: translation["as_occt_select"]["title"][language],
  301. body: translation["as_occt_select"]["body"][language],
  302. url: translation["as_occt_select"]["url"][language],
  303. links: translation["as_occt_select"]["links"][language],
  304. },
  305. },
  306. as_filetype: translation["as_filetype"][language],
  307. // 'tbs': translation['tbs'][language],
  308. };
  309.  
  310. for (const param in params) {
  311. if (typeof params[param] === "object") {
  312. const label = document.createElement("label");
  313. label.textContent = params[param].name;
  314. const select = document.createElement("select");
  315. select.name = param;
  316.  
  317. Object.keys(params[param]["options"]).forEach((option) => {
  318. const optionElement = document.createElement("option");
  319. optionElement.value = option;
  320. optionElement.textContent = params[param]["options"][option];
  321. select.appendChild(optionElement);
  322. });
  323.  
  324. form.appendChild(label);
  325. form.appendChild(select);
  326. form.appendChild(document.createElement("br"));
  327. continue;
  328. }
  329. const label = document.createElement("label");
  330. label.textContent = params[param];
  331. const input = document.createElement("input");
  332. input.name = param;
  333. input.type = "text";
  334. form.appendChild(label);
  335. form.appendChild(input);
  336. form.appendChild(document.createElement("br"));
  337. }
  338.  
  339. const searchButton = document.createElement("button");
  340. searchButton.textContent = translation["search"][language];
  341. form.appendChild(searchButton);
  342.  
  343. // Add a clear button to reset the form
  344. const clearButton = document.createElement("button");
  345. clearButton.textContent = translation["clear"][language];
  346. clearButton.addEventListener("click", function (event) {
  347. event.preventDefault();
  348. form.reset();
  349. });
  350. form.appendChild(clearButton);
  351.  
  352. // Load saved data and fill the form when opening a new page
  353. window.addEventListener("load", function () {
  354. for (const param in params) {
  355. const savedValue = GM_getValue(param);
  356. if (savedValue) {
  357. form[param].value = savedValue;
  358. }
  359. }
  360. });
  361.  
  362. // Save form data to Greasemonkey storage
  363. form.addEventListener("input", function () {
  364. for (const param in params) {
  365. GM_setValue(param, form[param].value);
  366. }
  367. });
  368.  
  369. // Toggle the form display
  370. toggleButton.addEventListener("click", function (event) {
  371. event.preventDefault();
  372. let status = formContainer.style.display;
  373. status = status === "none" || status === "" ? "block" : "none";
  374. formContainer.style.display = status;
  375. });
  376.  
  377. // Submit the form
  378. form.addEventListener("submit", function (event) {
  379. event.preventDefault();
  380. const searchParams = new URLSearchParams();
  381. for (const param in params) {
  382. const value = form[param].value;
  383. if (value) {
  384. searchParams.set(param, value);
  385. }
  386. }
  387. const searchUrl =
  388. "https://www.google.com/search?" + searchParams.toString();
  389. window.location.href = searchUrl;
  390. });
  391. })();

QingJ © 2025

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