Greasy Fork is available in English.

搜索引擎切换器魔改版

用于快速切换搜索引擎。有漂亮的高斯模糊外观和深色模式适配。当您滚动网页时,侧栏会自动收起,而当鼠标靠近时,侧栏则会弹出。您可以修改脚本以添加或重新排序搜索引擎。

질문, 리뷰하거나, 이 스크립트를 신고하세요.
  1. // ==UserScript==
  2. // @name 搜索引擎切换器魔改版
  3. // @namespace https://greasyfork.org/zh-CN/scripts/490643
  4. // @version 1.3
  5. // @description 用于快速切换搜索引擎。有漂亮的高斯模糊外观和深色模式适配。当您滚动网页时,侧栏会自动收起,而当鼠标靠近时,侧栏则会弹出。您可以修改脚本以添加或重新排序搜索引擎。
  6. // @author Corlius
  7. // @homepageURL https://github.com/Corlius/Corlius-Scripts
  8. // @icon https://www.google.com/s2/favicons?sz=64&domain=bing.com
  9. // @match *://www.baidu.com/s*
  10. // @match *://www.baidu.com/baidu*
  11. // @match *://duckduckgo.com/*
  12. // @match *://search.brave.com/search*
  13. // @match *://www.google.com/search*
  14. // @match *://www.google.com.hk/search*
  15. // @match *://weixin.sogou.com/weixin*
  16. // @match *://www.bing.com/search*
  17. // @match *://cn.bing.com/search*
  18. // @match *://www.zhihu.com/search*
  19. // @match *://search.cnki.com.cn/Search/Result*
  20. // @match *://www.sogou.com/web*
  21. // @match *://fsoufsou.com/search*
  22. // @match *://www.xiaohongshu.com/search_result/*
  23. // @match *://www.douyin.com/search/*
  24. // @match *://www.douban.com/search*
  25. // @match *://search.bilibili.com/*
  26. // @match *://www.youtube.com/results?search_query=*
  27. // @license MIT
  28. // @grant unsafeWindow
  29. // @grant window.onload
  30. // @grant GM_getValue
  31. // @grant GM_setValue
  32. // @run-at document-body
  33. // ==/UserScript==
  34.  
  35. // 搜索网址配置
  36. const urlMapping = [
  37. {
  38. name: "Google",
  39. searchUrl: "https://www.google.com/search?q=",
  40. keyName: "q",
  41. testUrl: /https:\/\/www.google.com\/search.*/,
  42. },
  43. {
  44. name: "Bing",
  45. searchUrl: "https://www.bing.com/search?q=",
  46. keyName: "q",
  47. testUrl: /https:\/\/www.bing.com\/search.*/,
  48. },
  49. {
  50. name: "Brave",
  51. searchUrl: "https://search.brave.com/search?q=",
  52. keyName: "q",
  53. testUrl: /https:\/\/search.brave.com\/search.*/,
  54. },
  55. {
  56. name: "DuckDuckGo",
  57. searchUrl: "https://duckduckgo.com/?q=",
  58. keyName: "q",
  59. testUrl: /https:\/\/duckduckgo.com\/*/,
  60. },
  61. {
  62. name: "YouTube",
  63. searchUrl: "https://www.youtube.com/results?search_query=",
  64. keyName: "search_query",
  65. testUrl: /https:\/\/www.youtube.com\/results.*/,
  66. },
  67. {
  68. name: "BiliBili",
  69. searchUrl: "https://search.bilibili.com/all?keyword=",
  70. keyName: "keyword",
  71. testUrl: /https:\/\/search.bilibili.com\/all.*/,
  72. },
  73. {
  74. name: "Douyin",
  75. searchUrl: "https://www.douyin.com/search/",
  76. keyName: "",
  77. testUrl: /https:\/\/www.douyin.com\/search.*/,
  78. },
  79. {
  80. name: "Baidu",
  81. searchUrl: "https://www.baidu.com/s?wd=",
  82. keyName: "wd",
  83. testUrl: /https:\/\/www.baidu.com\/.*/,
  84. },
  85. {
  86. name: "RedBook",
  87. searchUrl: "https://www.xiaohongshu.com/search_result?keyword=",
  88. keyName: "keyword",
  89. testUrl: /https:\/\/www.xiaohongshu.com\/search_result.*/,
  90. },
  91. {
  92. name: "Douban",
  93. searchUrl: "https://www.douban.com/search?q=",
  94. keyName: "q",
  95. testUrl: /https:\/\/www.douban.com\/search.*/,
  96. },
  97. {
  98. name: "WeChat",
  99. searchUrl: "https://weixin.sogou.com/weixin?type=2&s_from=input&query=",
  100. keyName: "query",
  101. testUrl: /https:\/\/weixin.sogou.com\/weixin.*/,
  102. },
  103. {
  104. name: "Zhihu",
  105. searchUrl: "https://www.zhihu.com/search?q=",
  106. keyName: "q",
  107. testUrl: /https:\/\/www.zhihu.com\/search.*/,
  108. },
  109. {
  110. name: "CNKI",
  111. searchUrl: "https://search.cnki.com.cn/Search/Result?content=",
  112. keyName: "content",
  113. testUrl: /https:\/\/search.cnki.com.cn\/Search\/Result.*/,
  114. },
  115. ];
  116.  
  117. // 根据参数名获取URL中的参数值
  118. function getQueryVariable(variable) {
  119. let query = window.location.search.substring(1);
  120. let vars = query.split("&");
  121. for (let varPair of vars) {
  122. let [key, value] = varPair.split("=");
  123. if (key === variable) {
  124. // 对提取出的参数值进行URI解码
  125. return decodeURI(decodeURIComponent(value));
  126. }
  127. }
  128. return null;
  129. }
  130.  
  131. // 从当前URL中提取搜索关键词
  132. function getKeywords() {
  133. const hostname = window.location.hostname;
  134. const pathname = window.location.pathname;
  135. const url = window.location.href;
  136.  
  137. // 特殊处理抖音搜索关键词
  138. if (hostname === 'www.douyin.com' && pathname.startsWith('/search/')) {
  139. const keywordPattern = /^\/search\/([^?]+)/;
  140. const match = pathname.match(keywordPattern);
  141. if (match && match[1]) {
  142. return decodeURIComponent(match[1]);
  143. }
  144. }
  145. for (let mapping of urlMapping) {
  146. if (mapping.name === "Baidu") {
  147. const params = new URL(url).searchParams;
  148. if (params.has('wd')) {
  149. return params.get('wd');
  150. } else if (url.includes('word=')) {
  151. let wd = url.match(/word=([^&]*)/)[1];
  152. return decodeURI(decodeURIComponent(wd));
  153. }
  154. } else if (mapping.testUrl.test(url)) {
  155. return getQueryVariable(mapping.keyName) || "";
  156. }
  157. }
  158. return "";
  159. }
  160.  
  161. // 特定的配置修改
  162. function adjustForSpecificBrowsers() {
  163. // 适配火狐浏览器的百度搜索
  164. if (navigator.userAgent.includes("Firefox")) {
  165. const baiduMapping = urlMapping.find(item => item.name === "Baidu");
  166. if (baiduMapping) {
  167. baiduMapping.searchUrl = "https://www.baidu.com/baidu?wd=";
  168. baiduMapping.testUrl = /https:\/\/www.baidu.com\/baidu.*/;
  169. }
  170. }
  171.  
  172. // 适配必应搜索
  173. if (window.location.hostname === 'cn.bing.com') {
  174. const bingMapping = {
  175. name: "Bing",
  176. searchUrl: "https://cn.bing.com/search?q=",
  177. keyName: "q",
  178. testUrl: /https:\/\/cn.bing.com\/search.*/,
  179. };
  180. const bingIndex = urlMapping.findIndex(item => item.name === "Bing");
  181. if (bingIndex !== -1) {
  182. urlMapping[bingIndex] = bingMapping;
  183. }
  184. }
  185. }
  186.  
  187. // 根据搜索关键词和配置给搜索链接设置样式和动作
  188. function setupSearchLinks(keywords) {
  189.  
  190. // 判断是否为暗色模式
  191. let isDarkMode = window.matchMedia('(prefers-color-scheme: dark)').matches;
  192.  
  193. // 如果当前页面是YouTube,则设置为深色模式
  194. //if (window.location.hostname === 'www.youtube.com') {
  195. // isDarkMode = true; // 强制深色模式
  196. //}
  197.  
  198. // 如果当前页面是DouYin,则设置为深色模式
  199. if (window.location.hostname === 'www.douyin.com') {
  200. isDarkMode = true; // 强制深色模式
  201. }
  202.  
  203. // 在文档中添加主容器
  204. const mainDiv = document.createElement("div");
  205. mainDiv.id = "search-app-box";
  206. Object.assign(mainDiv.style, {
  207. position: "fixed",
  208. top: "150px",
  209. left: "0px", // 初始位置在左侧
  210. width: "115px",
  211. fontSize: "13px",
  212. fontFamily: "sans-serif",
  213. backgroundColor: isDarkMode ? 'hsla(0, 0%, 15%, .8)' : 'hsla(0, 0%, 98%, .8)',
  214. backdropFilter: "blur(10px)",
  215. webkitBackdropFilter: "blur(10px)",
  216. borderRadius: "0 15px 15px 0",
  217. zIndex: "9999",
  218. transition: "left 0.5s ease-in-out", // 左侧滑动动画
  219. cursor: "pointer",
  220. boxShadow: "0 8px 10px rgba(0,0,0,0.06)",
  221. overflow: "hidden",
  222. });
  223.  
  224. document.body.appendChild(mainDiv);
  225.  
  226. // 在搜索引擎链接前添加居中显示的标题"Engines"
  227. const enginesTitle = document.createElement('div');
  228. enginesTitle.textContent = "Engines";
  229. Object.assign(enginesTitle.style, {
  230. fontSize: "15px",
  231. fontWeight: "bold",
  232. padding: '6px 0 6px 15px',
  233. color: isDarkMode ? 'hsla(0, 0%, 80%, 1)' : 'hsla(0, 0%, 20%, 1)',
  234. backgroundColor: isDarkMode ? 'hsla(0, 0%, 10%, .8)' : 'hsla(0, 0%, 80%, .8)',
  235. });
  236. mainDiv.appendChild(enginesTitle);
  237.  
  238. // 为每个搜索引擎创建链接
  239. urlMapping.forEach(({ name, searchUrl }) => {
  240. const link = document.createElement('a');
  241. link.textContent = name;
  242. link.href = `${searchUrl}${encodeURIComponent(keywords)}`;
  243. mainDiv.appendChild(link);
  244.  
  245. // 设置链接样式
  246. Object.assign(link.style, {
  247. display: 'block',
  248. padding: '5px 0 5px 15px',
  249. textDecoration: 'none',
  250. color: isDarkMode ? 'hsla(0, 0%, 80%, 1)' : 'hsla(0, 0%, 40%, 1)',
  251. });
  252.  
  253. // 添加鼠标放置在链接上时的背景色变化
  254. link.addEventListener('mouseenter', () => {
  255. link.style.backgroundColor = isDarkMode ? 'hsla(0, 0%, 30%, .8)' : 'hsla(0, 0%, 92%, .8)';
  256. });
  257.  
  258. // 当鼠标离开链接时恢复背景色
  259. link.addEventListener('mouseleave', () => {
  260. link.style.backgroundColor = '';
  261. });
  262. });
  263.  
  264. // 滚动时隐藏主容器
  265. window.addEventListener('scroll', () => {
  266. mainDiv.style.left = "-95px";
  267. });
  268.  
  269. // 鼠标接近主容器时显示容器
  270. window.addEventListener("mousemove", function (event) {
  271. const rect = mainDiv.getBoundingClientRect();
  272. const dx = Math.abs(event.clientX - rect.right);
  273. const dy = Math.abs(event.clientY - ((rect.top + rect.bottom) / 2));
  274. var dxLimit = 130;
  275. if (window.location.hostname === 'www.bing.com') {
  276. dxLimit = 25;
  277. }
  278. if (dx < dxLimit && dy < 200) {
  279. mainDiv.style.left = "0";
  280. }
  281. });
  282.  
  283.  
  284. }
  285.  
  286. // 页面加载完成后进行初始化
  287. window.addEventListener("DOMContentLoaded", function () {
  288. adjustForSpecificBrowsers(); // 调整特定浏览器的配置
  289. setupSearchLinks(getKeywords()); // 设置搜索链接
  290. });