Greasy Fork is available in English.

搜索引擎净化

一个轻量级的搜索引擎优化脚本。自动净化百度、谷歌、必应等搜索结果页面,支持移除广告、优化重定向链接、清理URL、隐藏弹窗等功能,让搜索体验更简洁高效

بۇ قوليازمىنى قاچىلاش؟
ئاپتورنىڭ تەۋسىيەلىگەن قوليازمىسى

سىز بەلكىم 123云盘解锁 نى ياقتۇرۇشىڭىز مۇمكىن.

بۇ قوليازمىنى قاچىلاش
  1. // ==UserScript==
  2. // @name 搜索引擎净化
  3. // @namespace https://github.com/QingJ01/Search_clear
  4. // @version 1.1.0
  5. // @icon data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAFU0lEQVRoQ81aTWhUVxQ+902cMdVJMthV6SLubEFrwFKoCGZTBKE6nVgqdWHcaNyYLLrUart00XHjRBc1m9LSJHVSKBQLTUAsLS0YuxC7yhTEVcs8Z2x+NHNvz7nz3jh58967P2+CHhjIZO7P9533nXvOvfcx6IKN36wOrK7DXhzqIHN6+oEJ/FsMgIBBOTyDCghWYQAu542/8T8Lk8dyC12YGoe2NAK91kDALHVEgDiKwwyYD8XKAhpzk4XclHnfZg9jAp63x5njnLMDHQXVKZYK2QlTItoEfI8Dc77ASZrS6L65AviEyRPRIiDB89QN1DVJZfONwWKG8eFiPueqJlMSOPttda9IOTc30etRGF3W4MNXP8wtxpGIJTA2Uz2KkkHP2wSoyneavwueL43kylGtIwmcma2eZCD1brG6aILTbRZDIpSAJ5v5lwK8RxLlNBQmpw4CzYB17r4AzauehyscPjSZz1XaG3YQGJutYcBu3mpTZw/hQXoGKumfYPfqKOx6NqIC/vx3XJ1KH/QPRRLwdE9B21VbYzX4N3Uf7vR+DkSAvpO9yt+EY/UfjObCPDHanidaT0BKRzjzWL9QTdM1W9pyC/7YegX+ce6Hjnmidhuy4nWT+dxSoT/nd2gRODNdvYjlwacmI8W1fdTzq/R4FHC/7/6V87Dn6SmjaQXnl7AYvEidJAEvcJfwz8RLJsmDPP7XlpmWVOLQ7Xz2HhxavmZEABu3AloS8BIWZdtE9gBB/4Je9zWuM1hG9MGp2j2dpoE2fKJUyBWbBBKuPL7X/0x/aQEEZCBTQJsZK5cKfXmWdN0n8PO9nwAFq63ZxAHJiIKZJZUPBaqt533ClnGACyYfZWOz1XFo1jzGRsCJQFJ7bf0dOPLfN8bD0GrEzs7WbuCW8KRpb0pI09nDRgEbNYd9ILMyPgG70qEb0mknRCsRETEyxhaQwGNa/wdNOlKS+vGV013xvj+vFQEMZCsCc9s+gkc9v2lzJs+qckMSAlVEop2BqTQg7esalQlLPbeg7jyM7WJJANjYd4/vmhRwv2eKslTQMfL8+0++VhK2D2KoIIEaVqDioA4gakPeVxVo/lh+jUPxEmc2ZbUcD/cHGAN1zAEcc4HaTORD0qEMS+BVWXrX0xEYXrmsBhBowYBNGRHQTVwE6N3V83K6r7IHlAFsWUrg6E7RqJSgmoe2gyo5kO5J1zrxQu0+rt82zwEEAk8r/GJOay+gkgOVBIeWr0swtGzqeH/f6jl4e01LwUG/uRmH75TltG45EfcESPMExs+mut6nUtpwS+kR8cpp+qa7mQ8rHwgwAW/fFlKwf7/9uFL7w8uXzU4lNjyDtg2NtyeghBZrVELMbTveakOS2b9yYcNmhKQzvf2wMnH5q5RqzojfN24p5VPQ3NRTHkjzrPQ41fHtpru5CcrNlETHpp4G0N2Z+TVNsHLUAR8mN1Pw2F4Gr3/0vuFkTjcWgpOStH7GJTau3gmTmwV4XDmfH6lQ/86jRcPaiAL2Tu9nodUpeXxH442OOLEBLvuEXHxEHe5q5YUgEL9kIOBp3ieXR+NNSjS70AuPuON1OqF+WcxF7YyGXXREXnAkPa3oLvPmmh82ps4VU+ITuwRk8JKPX4oCHxrEwcle4G1NpGzaMSpvKVs5YhOO3iOfDK42gvF88DbGWELBDt4hGB3Ba++hDeUjJZNxYErnjlhLQmEAkpzmRRAyBu6PoyWhKC9KIviyh8meum0sFxhbBNGYEw6UdeSSWEJxcqBlV+D1FHNSb2HGxFdtxCC2pw+9LoBg8YOv3GA6rQhYv7cVQevKJG7e/wGC2pwVj9Yh6QAAAABJRU5ErkJggg==
  6. // @description 一个轻量级的搜索引擎优化脚本。自动净化百度、谷歌、必应等搜索结果页面,支持移除广告、优化重定向链接、清理URL、隐藏弹窗等功能,让搜索体验更简洁高效
  7. // @author QingJ
  8. // @license Apache Licence 2.0
  9. // @match *://*.google.com/*
  10. // @match *://*.google.com.hk/*
  11. // @match *://*.google.co.jp/*
  12. // @match *://*.baidu.com/*
  13. // @match *://*.bing.com/*
  14. // @match *://*.cn.bing.com/*
  15. // @match *://*.s.cn.bing.net/*
  16. // @match *://*.sogou.com/*
  17. // @match *://*.m.sogou.com/*
  18. // @match *://*.wap.sogou.com/*
  19. // @match *://*.so.com/*
  20. // @match *://*.m.so.com/*
  21. // @match *://*.sm.cn/*
  22. // @match *://*.m.sm.cn/*
  23. // @match *://*.yz.m.sm.cn/*
  24. // @match *://*.so.toutiao.com/*
  25. // @grant GM_addStyle
  26. // @grant unsafeWindow
  27. // @grant GM_getValue
  28. // @grant GM_setValue
  29. // @grant GM_openInTab
  30. // @grant GM_xmlhttpRequest
  31. // @connect api.staticj.top
  32. // @run-at document-start
  33. // @require https://code.jquery.com/jquery-3.6.0.min.js
  34. // ==/UserScript==
  35.  
  36. (function (cat) {
  37. "use strict";
  38.  
  39. const userConfig = {
  40. css: " {display: none !important;width: 0 !important;height: 0 !important;} ",
  41. timeout: 10000,
  42. tryCount: 5,
  43. tryTimeout: 500,
  44. };
  45.  
  46. const commonFunctionObject = {
  47. GMgetValue(key, defaultValue) {
  48. return GM_getValue(key, defaultValue);
  49. },
  50. GMsetValue(key, value) {
  51. GM_setValue(key, value);
  52. },
  53. GMopenInTab(url) {
  54. GM_openInTab(url, { active: true });
  55. },
  56. randomNumber() {
  57. return Math.floor(Math.random() * 100000000);
  58. },
  59. webToast(config) {
  60. const message = config.message || '';
  61. const background = config.background || '#333';
  62. const toast = document.createElement('div');
  63. toast.style.cssText = `
  64. position: fixed;
  65. top: 50%;
  66. left: 50%;
  67. transform: translate(-50%, -50%);
  68. padding: 10px 20px;
  69. background: ${background};
  70. color: #fff;
  71. border-radius: 4px;
  72. z-index: 999999;
  73. `;
  74. toast.textContent = message;
  75. document.body.appendChild(toast);
  76. setTimeout(() => toast.remove(), 2000);
  77. },
  78. request(method, url, data) {
  79. return new Promise((resolve, reject) => {
  80. GM_xmlhttpRequest({
  81. method: method,
  82. url: url,
  83. data: data,
  84. onload: function (response) {
  85. resolve(response);
  86. },
  87. onerror: function (error) {
  88. reject(error);
  89. }
  90. });
  91. });
  92. }
  93. };
  94.  
  95. /**
  96. * 常量定义
  97. */
  98. const HOSTS = {
  99. BAIDU: 'baidu.com',
  100. GOOGLE: 'google.com',
  101. BING: 'bing.com',
  102. SOGOU: 'sogou.com',
  103. SO: 'so.com',
  104. SM: 'sm.cn'
  105. };
  106.  
  107. /**
  108. * 工具函数:移除元素
  109. */
  110. function removeElements(selector) {
  111. try {
  112. document.querySelectorAll(selector).forEach(el => el.remove());
  113. } catch (e) {
  114. console.error('移除元素失败:', selector, e);
  115. }
  116. }
  117.  
  118. /**
  119. * 检查当前域名是否匹配
  120. */
  121. function isMatchHost(host) {
  122. return location.host.includes(host);
  123. }
  124.  
  125. /**
  126. * 添加样式
  127. */
  128. function addStyle(css, pass = 0) {
  129. let el;
  130. if (pass >= userConfig.tryCount) return;
  131. if (typeof cat.GM_addStyle == "function") {
  132. el = cat.GM_addStyle(css);
  133. } else {
  134. el = document.createElement("style");
  135. el.textContent = css;
  136. document.documentElement.appendChild(el);
  137. }
  138. if (typeof el == "object") {
  139. if (!el || !document.documentElement.contains(el)) {
  140. setTimeout(() => {
  141. addStyle(css, pass + 1);
  142. }, userConfig.tryTimeout);
  143. }
  144. }
  145. }
  146.  
  147. /**
  148. * 搜索引擎广告过滤
  149. */
  150. function removeAds() {
  151. // 百度广告过滤
  152. if (isMatchHost(HOSTS.BAIDU)) {
  153. // 移除顶部和右侧广告
  154. removeElements('.ec_wise_ad');
  155. removeElements('#content_right');
  156.  
  157. // 移除带有广告标记的内容 - 更精确的选择器
  158. document.querySelectorAll('#content_left > div').forEach(container => {
  159. // 检查是否包含广告标记
  160. if (container.querySelector('.f13 > span')?.textContent?.includes('广告') ||
  161. container.querySelector('a[data-landurl]') ||
  162. container.querySelector('span.tuiguang')?.textContent?.includes('广告') ||
  163. container.querySelector('span.brand')?.textContent?.includes('广告') ||
  164. container.querySelector('span[data-tuiguang]')) {
  165. container.remove();
  166. }
  167. });
  168.  
  169. // 移除多余元素 - 更精确的选择器
  170. removeElements('#content_right > br');
  171. removeElements('#content_right > div:not([id])');
  172. removeElements('#content_left > div.result-op');
  173. removeElements('#content_left > div[class*="recommend"]');
  174.  
  175. // 移除劫持和推荐
  176. removeElements('.res_top_banner');
  177. removeElements('#content_left div[class*="_rs"]');
  178.  
  179. // 移除手机版广告
  180. if (location.host.includes('m.baidu.com')) {
  181. // 基础广告元素
  182. removeElements([
  183. '.ec_wise_ad',
  184. '.ec-result-inner',
  185. '.c-result.result-op',
  186. '.download-tip',
  187. '.float-ball',
  188. '.ball-wrapper',
  189. '.na-like-container'
  190. ].join(','));
  191.  
  192. // 移除带有广告标记的内容
  193. document.querySelectorAll('.c-container').forEach(container => {
  194. if (container.querySelector('.c-icons-outer')?.textContent?.includes('广告') ||
  195. container.hasAttribute('data-tuiguang') ||
  196. container.querySelector('[data-tuiguang]')) {
  197. container.remove();
  198. }
  199. });
  200.  
  201. // 移除底部推广
  202. removeElements([
  203. '.c-recommends',
  204. '.c-flex-recommend',
  205. '.c-recommend-tip',
  206. '[data-module="recommend"]'
  207. ].join(','));
  208. }
  209. }
  210.  
  211. // 谷歌广告过滤
  212. if (isMatchHost(HOSTS.GOOGLE)) {
  213. removeElements([
  214. '.commercial-unit',
  215. '#tads',
  216. '#bottomads',
  217. 'div[aria-label="广告"]',
  218. 'div[aria-label="Ads"]'
  219. ].join(','));
  220. }
  221.  
  222. // 必应广告过滤
  223. if (isMatchHost(HOSTS.BING)) {
  224. removeElements([
  225. 'li.b_ad',
  226. '.pa_sb',
  227. '.adsMvC',
  228. 'a[h$=",Ads"]',
  229. 'a[href*="/aclick?ld="]',
  230. 'DIV#bnp_container',
  231. '.ad_sc'
  232. ].join(','));
  233.  
  234. // 移除特定图片的广告
  235. document.querySelectorAll('.b_algo').forEach(algo => {
  236. const img = algo.querySelector('.rms_img');
  237. if (img && (img.src.includes('/th?id=OADD2.') ||
  238. img.src.includes('=AdsPlus'))) {
  239. algo.remove();
  240. }
  241. });
  242. }
  243.  
  244. // 搜狗广告过滤
  245. if (isMatchHost(HOSTS.SOGOU)) {
  246. removeElements([
  247. '#so_kw-ad',
  248. '#m-spread-left',
  249. '#m-spread-bottom'
  250. ].join(','));
  251.  
  252. // 移除带有广告标记的内容
  253. document.querySelectorAll('#righttop_box li').forEach(li => {
  254. if (li.querySelector('span')?.textContent.includes('广告')) {
  255. li.remove();
  256. }
  257. });
  258. }
  259.  
  260. // 360搜索广告过滤
  261. if (isMatchHost(HOSTS.SO)) {
  262. removeElements([
  263. '.res-mediav',
  264. '.e_result',
  265. '.c-title-tag',
  266. 'DIV.res-mediav-right',
  267. 'DIV.inner_left',
  268. '#so-activity-entry',
  269. 'DIV.tg-wrap'
  270. ].join(','));
  271. }
  272.  
  273. // 神马搜索广告过滤
  274. if (isMatchHost(HOSTS.SM)) {
  275. removeElements([
  276. '.ad-wrapper',
  277. '.ec_wise_ad',
  278. '.qb-download-banner-non-share',
  279. 'DIV[data-text-ad]',
  280. '.ad-block'
  281. ].join(','));
  282.  
  283. // 移除手机版广告
  284. if (location.host.includes('m.sm.cn')) {
  285. removeElements([
  286. 'DIV.ad-alert-info',
  287. '.se-recommend-word-list-container',
  288. '#se-recommend-word-list-container',
  289. '[class*="ball-wrapper"]',
  290. 'DIV#page-copyright.se-page-copyright[style*="margin-bottom: 50px"]',
  291. 'DIV[style*="position: fixed; bottom: 0px"]',
  292. '[ad_dot_url*="http"]',
  293. '.dl-banner-without-logo',
  294. '.ad_result',
  295. '.biz_sponsor'
  296. ].join(','));
  297. }
  298. }
  299. }
  300.  
  301. /**
  302. * 搜索引擎重定向优化
  303. */
  304. function redirectOptimize() {
  305. // 处理百度重定向
  306. if (isMatchHost(HOSTS.BAIDU)) {
  307. document.querySelectorAll('a[href*="baidu.com/link"]:not([ac-redirect-processed])').forEach(link => {
  308. try {
  309. // 标记已处理,避免重复
  310. link.setAttribute('ac-redirect-processed', '1');
  311.  
  312. // 保存原始链接
  313. const originalHref = link.href;
  314.  
  315. // 移除原有的点击事件
  316. link.removeAttribute('onclick');
  317. link.removeAttribute('onmousedown');
  318.  
  319. // 使用GM_xmlhttpRequest处理重定向
  320. link.addEventListener('click', function (e) {
  321. e.preventDefault();
  322. e.stopPropagation();
  323.  
  324. GM_xmlhttpRequest({
  325. method: "GET",
  326. url: originalHref,
  327. headers: {
  328. "Accept": "*/*",
  329. "Referer": originalHref
  330. },
  331. timeout: 5000,
  332. onload: function (response) {
  333. let directUrl = response.finalUrl;
  334. if (!directUrl) {
  335. // 尝试从响应文本中提取URL
  336. const matches = /URL='([^']+)'/.exec(response.responseText);
  337. directUrl = matches ? matches[1] : null;
  338. }
  339. if (directUrl && !directUrl.includes('baidu.com/link')) {
  340. window.open(directUrl, '_blank');
  341. } else {
  342. window.open(originalHref, '_blank');
  343. }
  344. },
  345. onerror: function () {
  346. window.open(originalHref, '_blank');
  347. }
  348. });
  349. }, { once: true }); // 确保事件只触发一次
  350.  
  351. } catch (e) {
  352. console.error('百度重定向处理失败:', e);
  353. }
  354. });
  355. }
  356.  
  357. // 处理谷歌重定向
  358. if (isMatchHost(HOSTS.GOOGLE)) {
  359. document.querySelectorAll('a[onmousedown]:not([ac-redirect-processed]), a[data-jsarwt]:not([ac-redirect-processed])').forEach(link => {
  360. try {
  361. // 标记已处理
  362. link.setAttribute('ac-redirect-processed', '1');
  363.  
  364. // 移除Google的重定向属性
  365. link.removeAttribute('onmousedown');
  366. link.removeAttribute('data-jsarwt');
  367. link.removeAttribute('ping');
  368.  
  369. // 新标签页打开
  370. link.setAttribute('target', '_blank');
  371.  
  372. } catch (e) {
  373. console.error('谷歌重定向处理失败:', e);
  374. }
  375. });
  376. }
  377.  
  378. // 处理必应重定向
  379. if (isMatchHost(HOSTS.BING)) {
  380. document.querySelectorAll('a[href*="/click?"]:not([ac-redirect-processed]), a[href*="go.microsoft.com"]:not([ac-redirect-processed])').forEach(link => {
  381. try {
  382. // 标记已处理
  383. link.setAttribute('ac-redirect-processed', '1');
  384.  
  385. // 尝试从href中提取目标URL
  386. const url = new URL(link.href);
  387. let targetUrl = url.searchParams.get('u') || url.searchParams.get('r');
  388.  
  389. if (targetUrl) {
  390. // 设置解码后的URL
  391. link.href = decodeURIComponent(targetUrl);
  392. link.setAttribute('target', '_blank');
  393.  
  394. // 移除原有的点击事件
  395. link.removeAttribute('onclick');
  396. link.removeAttribute('onmousedown');
  397. }
  398. } catch (e) {
  399. console.error('必应重定向处理失败:', e);
  400. }
  401. });
  402. }
  403. }
  404.  
  405. /**
  406. * 隐藏必应APP弹窗
  407. */
  408. function hideBingPopup() {
  409. if (isMatchHost(HOSTS.BING)) {
  410. addStyle('div#bnp_container {display: none !important;}');
  411.  
  412. const observer = new MutationObserver(() => {
  413. const closeBtn = document.querySelector('div#sacs_close');
  414. if (closeBtn) {
  415. closeBtn.click();
  416. }
  417. });
  418.  
  419. observer.observe(document.body, {
  420. childList: true,
  421. subtree: true
  422. });
  423. }
  424. }
  425.  
  426. /**
  427. * URL参数清理
  428. */
  429. function shortenUrl() {
  430. sturl();
  431. window.addEventListener('locationchange', sturl);
  432. }
  433.  
  434. function sturl() {
  435. try {
  436. let url = new URL(window.location.href);
  437. let changed = false;
  438.  
  439. // 需要移除的查询参数
  440. const params = [
  441. // 百度参数 - 完整列表
  442. 'rsp', 'prefixsug', 'fr', 'bsst', 'f', 'inputT', 'usm', 'rsv_page',
  443. 'rqlang', 'rsv_t', 'oq', 'rsv_pq', 'rsv_spt', 'ie', 'rsv_enter',
  444. 'rsv_sug1', 'rsv_sug7', 'rsv_sug2', 'rsv_sug3', 'rsv_iqid',
  445. 'rsv_bp', 'rsv_btype', 'rsv_idx', 'rsv_dl', 'issp', 'cshid',
  446. 'tn', 'rsv_sug4', 'rtt', 'bsst', 'rsv_sid', 'rsv_tn', '_ss',
  447. 'rsv_jmp', 'rsv_bl', 'rsv_sug5', 'rsv_sug6', 'rsv_sug8', 'rsv_sug9', 'bar',
  448.  
  449. // 谷歌参数 - 完整列表
  450. 'tbas', 'ved', 'uact', 'ei', 'ie', 'oq', 'sclient', 'cshid', 'dpr',
  451. 'iflsig', 'aqs', 'gs_lcp', 'source', 'sourceid', 'sxsrf', 'pccc',
  452. 'sa', 'biw', 'bih', 'hl', 'newwindow', 'stick', 'gws_rd', 'client',
  453. 'gs_rn', 'tbo', 'dcr', 'safe', 'ssui', 'psi',
  454.  
  455. // 必应参数 - 完整列表
  456. 'tsc', 'sp', 'FORM', 'form', 'pq', 'sc', 'qs', 'sk', 'cvid', 'lq',
  457. 'ghsh', 'ghacc', 'ghpl', 'ghc', 'ubireng', 'FPIG', 'PC', 'setmkt',
  458. 'setlang', 'mkt', 'qpvt', 'ensearch', 'first'
  459. ];
  460.  
  461. // 移除参数
  462. params.forEach(param => {
  463. if (url.searchParams.has(param)) {
  464. url.searchParams.delete(param);
  465. changed = true;
  466. }
  467. });
  468.  
  469. // 特殊参数处理
  470. const specialParams = [
  471. ['start', '0'],
  472. ['page', '1'],
  473. ['offset', '0'],
  474. ['first', '1']
  475. ];
  476.  
  477. if (url.searchParams.get('start') === '0') {
  478. url.searchParams.delete('start');
  479. changed = true;
  480. }
  481.  
  482. // 如果有改变则更新URL
  483. if (changed) {
  484. window.history.replaceState(null, null, url.toString());
  485. }
  486.  
  487. } catch (e) {
  488. console.error('URL参数清理失败:', e);
  489. }
  490. }
  491.  
  492. // 添加 locationchange 事件支持
  493. const originalPushState = history.pushState;
  494. const originalReplaceState = history.replaceState;
  495.  
  496. history.pushState = function () {
  497. originalPushState.apply(this, arguments);
  498. window.dispatchEvent(new Event('locationchange'));
  499. };
  500.  
  501. history.replaceState = function () {
  502. originalReplaceState.apply(this, arguments);
  503. window.dispatchEvent(new Event('locationchange'));
  504. };
  505.  
  506. window.addEventListener('popstate', () => {
  507. window.dispatchEvent(new Event('locationchange'));
  508. });
  509.  
  510. // SearchEnginesNavigation 类定义
  511. class SearchEnginesNavigation {
  512. constructor() {
  513. this.navigationDataCache = "navigation_data_cache";
  514. this.customNavigationkey = "custom-navigation-key-8898";
  515. this.searchEnginesData = [
  516. { "host": "www.baidu.com", "element": "#content_right", "elementInput": "#kw" },
  517. { "host": "www.so.com", "element": "#side", "elementInput": "#keyword" },
  518. { "host": "www.sogou.com", "element": "#right", "elementInput": "#upquery" },
  519. { "host": "cn.bing.com", "element": "#b_context", "elementInput": "#sb_form_q" },
  520. { "host": "www.bing.com", "element": "#b_context", "elementInput": "#sb_form_q" },
  521. { "host": "www4.bing.com", "element": "#b_context", "elementInput": "#sb_form_q" },
  522. { "host": "so.toutiao.com", "element": ".s-side-list", "elementInput": "input[type='search']" },
  523. { "host": "www.google.com", "element": "#rhs", "elementInput": "input[name='q']" }
  524. ];
  525. }
  526.  
  527. getNavigationData(element, elementInput) {
  528. const defaultNavigationData = [
  529. {
  530. "name": "搜索引擎", "list": [
  531. { "name": "百度", "url": "https://www.baidu.com/s?wd=@@" },
  532. { "name": "必应", "url": "https://cn.bing.com/search?q=@@" },
  533. { "name": "Google", "url": "https://www.google.com/search?q=@@" },
  534. { "name": "360搜索", "url": "https://www.so.com/s?ie=utf-8&fr=none&src=360sou_newhome&nlpv=basest&q=@@" },
  535. { "name": "搜狗", "url": "https://www.sogou.com/web?query=@@" },
  536. { "name": "头条搜索", "url": "https://so.toutiao.com/search?dvpf=pc&source=input&keyword=@@" }
  537. ]
  538. },
  539. {
  540. "name": "资源搜索", "list": [
  541. { "name": "财经搜索", "url": "https://www.shaduizi.com/s/search?q=@@&currentPage=1" },
  542. { "name": "百度百科", "url": "https://baike.baidu.com/item/@@" },
  543. { "name": "知乎搜索", "url": "https://www.zhihu.com/search?type=content&q=@@" },
  544. { "name": "B站搜索", "url": "https://search.bilibili.com/all?keyword=@@&from_source=webtop_search&spm_id_from=333.851" },
  545. { "name": "抖音搜索", "url": "https://www.douyin.com/search/@@?aid=0a9fc74b-01e8-4fb0-9509-307c5c07fda1&publish_time=0&sort_type=0&source=normal_search&type=general" },
  546. { "name": "搜狗|公众号", "url": "https://weixin.sogou.com/weixin?type=2&query=@@" },
  547. { "name": "搜狗|知乎", "url": "https://www.sogou.com/sogou?pid=sogou-wsse-ff111e4a5406ed40&insite=zhihu.com&ie=utf8&p=73351201&query=@@&ie=utf8&p=73351201&query=@@" },
  548. { "name": "豆瓣搜索", "url": "https://www.douban.com/search?q=@@" },
  549. { "name": "电影搜索", "url": "https://www.cupfox.com/search?key=@@" },
  550. { "name": "维基百科", "url": "https://en.wikipedia.org/w/index.php?search=@@" },
  551. { "name": "法律法规", "url": "https://www.pkulaw.com/law/chl?Keywords=@@" },
  552. { "name": "icon搜索", "url": "https://www.iconfont.cn/search/index?searchType=icon&q=@@" },
  553. { "name": "github", "url": "https://github.com/search?q=@@" },
  554. { "name": "csdn", "url": "https://so.csdn.net/so/search?q=@@&t=&u=" },
  555. { "name": "stackoverflow", "url": "https://stackoverflow.com/" }
  556. ]
  557. }
  558. ];
  559.  
  560. let cacheNavigationData = commonFunctionObject.GMgetValue(this.navigationDataCache, null);
  561. if (!cacheNavigationData) {
  562. cacheNavigationData = defaultNavigationData;
  563. }
  564.  
  565. let finalNavigationData = null;
  566. try {
  567. let customNavigationData = commonFunctionObject.GMgetValue(this.customNavigationkey, null);
  568. finalNavigationData = customNavigationData ? cacheNavigationData.concat(customNavigationData) : cacheNavigationData;
  569. } catch (e) {
  570. finalNavigationData = cacheNavigationData;
  571. }
  572.  
  573. this.createHtml(element, elementInput, finalNavigationData);
  574.  
  575. // 更新缓存数据
  576. commonFunctionObject.request("get", "http://api.staticj.top/script/api/get/navigation_json_url?t=" + new Date().getTime(), null)
  577. .then(resultData => {
  578. let dataJson = JSON.parse(resultData.data);
  579. if (dataJson?.url) {
  580. commonFunctionObject.request("get", dataJson.url, null)
  581. .then(resultData2 => {
  582. let serverNavigationData = resultData2.data;
  583. if (!cacheNavigationData ||
  584. (cacheNavigationData && serverNavigationData.length != JSON.stringify(cacheNavigationData).length)) {
  585. commonFunctionObject.GMsetValue(this.navigationDataCache, JSON.parse(serverNavigationData));
  586. }
  587. })
  588. .catch(() => { });
  589. }
  590. })
  591. .catch(() => { });
  592. }
  593.  
  594. createCss(elementNum) {
  595. const cssContent = `
  596. /* 导航容器样式 */
  597. #QingjByeBug {
  598. background: #fff;
  599. border-radius: 8px;
  600. box-shadow: 0 2px 8px rgba(0,0,0,0.1);
  601. padding: 15px;
  602. margin-bottom: 20px;
  603. }
  604.  
  605. /* 分类样式 */
  606. .ddfdfd${elementNum}dffssqa {
  607. margin-top: 13px;
  608. }
  609.  
  610. .ddfdfd${elementNum}dffssqa:first-child {
  611. margin-top: 0;
  612. }
  613.  
  614. /* 标题样式 */
  615. .ddfdfd${elementNum}dffssqa>.title {
  616. font-size: 15px;
  617. color: #333;
  618. margin-bottom: 10px;
  619. padding-bottom: 8px;
  620. border-bottom: 1px solid #eee;
  621. }
  622.  
  623. .ddfdfd${elementNum}dffssqa>.title b {
  624. position: relative;
  625. padding-left: 10px;
  626. }
  627.  
  628. .ddfdfd${elementNum}dffssqa>.title b:before {
  629. content: '';
  630. position: absolute;
  631. left: 0;
  632. top: 50%;
  633. transform: translateY(-50%);
  634. width: 4px;
  635. height: 16px;
  636. background: #4e6ef2;
  637. border-radius: 2px;
  638. }
  639.  
  640. /* 链接列表样式 */
  641. .ddfdfd${elementNum}dffssqa>.content-list {
  642. display: flex;
  643. flex-wrap: wrap;
  644. gap: 8px;
  645. }
  646.  
  647. /* 链接样式 */
  648. .ddfdfd${elementNum}dffssqa>.content-list>a {
  649. flex: 0 0 calc(31% - 4px);
  650. text-decoration: none;
  651. color: #333;
  652. background: #f5f5f5;
  653. border: 1px solid transparent;
  654. border-radius: 4px;
  655. padding: 6px 2px;
  656. text-align: center;
  657. font-size: 13px;
  658. line-height: 1.5;
  659. overflow: hidden;
  660. white-space: nowrap;
  661. text-overflow: ellipsis;
  662. transition: all 0.3s ease;
  663. }
  664.  
  665. .ddfdfd${elementNum}dffssqa>.content-list>a:hover {
  666. background: #4e6ef2;
  667. color: #fff;
  668. transform: translateY(-1px);
  669. box-shadow: 0 2px 8px rgba(78,110,242,0.3);
  670. }
  671.  
  672. /* 底部信息样式 */
  673. #QingjByeBug > div:last-child {
  674. margin-top: 15px;
  675. padding-top: 10px;
  676. border-top: 1px solid #eee;
  677. color: #999;
  678. font-size: 12px;
  679. }
  680.  
  681. #QingjByeBug > div:last-child a {
  682. color: #666;
  683. text-decoration: none;
  684. transition: color 0.3s ease;
  685. }
  686.  
  687. #QingjByeBug > div:last-child a:hover {
  688. color: #4e6ef2;
  689. }
  690.  
  691. /* 自定义按钮样式 */
  692. a[name="customNavigation"] {
  693. display: inline-flex;
  694. align-items: center;
  695. gap: 4px;
  696. }
  697.  
  698. a[name="customNavigation"]:before {
  699. content: '🔧';
  700. font-size: 14px;
  701. }
  702. `;
  703.  
  704. if ($("#plugin_css_style_dddsoo").length == 0) {
  705. $("body").prepend(`<style id='plugin_css_style_dddsoo'>${cssContent}</style>`);
  706. }
  707. }
  708.  
  709. createHtml(element, elementInput, navigationData) {
  710. $("#QingjByeBug").remove(); // 保持原有ID
  711.  
  712. const elementNum = commonFunctionObject.randomNumber();
  713. let isComplete = true;
  714.  
  715. // 添加这一行,确保CSS样式被添加
  716. this.createCss(elementNum);
  717.  
  718. const elementInterval = setInterval(() => {
  719. if (isComplete) {
  720. const $element = $(element);
  721. const $box = $("#QingjByeBug");
  722. isComplete = false;
  723.  
  724. if ($element.length != 0 && $box.length == 0) {
  725. let html = "<div id='QingjByeBug'>";
  726.  
  727. // 遍历导航分类
  728. navigationData.forEach(category => {
  729. html += `
  730. <div class='ddfdfd${elementNum}dffssqa'>
  731. <div class='title'><b>${category.name}</b></div>
  732. <div class='content-list'>
  733. `;
  734.  
  735. // 遍历分类下的链接
  736. category.list.forEach(item => {
  737. html += `<a target='_blank' name='navigation' data-url='${item.url}' href='javascript:void(0);'>${item.name}</a>`;
  738. });
  739.  
  740. html += "</div></div>";
  741. });
  742.  
  743. html += `
  744. <div style='margin-bottom:10px;margin-top:5px;font-size:12px;'>
  745. <a target='_blank' href='https://greatest.deepsurf.us/zh-CN/scripts/520018'>*该数据由 搜索引擎净化 提供</a>
  746. &nbsp;&nbsp;
  747. <a href="javascript:void(0);" name="customNavigation">自定义网址</a>
  748. </div>
  749. </div>`;
  750.  
  751. // 插入导航面板
  752. $element.prepend(html);
  753.  
  754. // 绑定链接点击事件
  755. $("#QingjByeBug a[name='navigation']").on("click", function (e) {
  756. e.preventDefault();
  757. const url = $(this).data("url").replace("@@", $(elementInput).val());
  758. commonFunctionObject.GMopenInTab(url);
  759. });
  760.  
  761. // 绑定自定义导航事件
  762. $("#QingjByeBug a[name='customNavigation']").on("click", function (e) {
  763. e.preventDefault();
  764. self.showSetingDialog();
  765. });
  766. }
  767. isComplete = true;
  768. }
  769. }, 100);
  770. }
  771.  
  772. showSetingDialog() {
  773. const customNavigation = commonFunctionObject.GMgetValue(this.customNavigationkey, null);
  774. const customNavigationData = customNavigation ? JSON.stringify(customNavigation, null, 4) : "";
  775.  
  776. const content = `
  777. <div class="custom-navigation-dialog">
  778. <div class="notice-section">
  779. <h3>注意事项:</h3>
  780. <ol>
  781. <li>请严格按照格式添加,否则不生效</li>
  782. <li>数据为json格式,请确保json格式正确,必要时请到 <a target="_blank" href="https://www.json.cn/">json.cn</a> 校验</li>
  783. <li>点击下面"示例"按钮,查看具体格式情况</li>
  784. <li>链接中的搜索关键词请用"@@"代替,脚本会自动替换成当前搜索词</li>
  785. <li>清空 -> 保存,则取消自定义的导航网址</li>
  786. </ol>
  787. </div>
  788. <div class="textarea-section">
  789. <textarea
  790. placeholder="请严格按照格式填写,否则不生效"
  791. class="navigation-textarea"
  792. >${customNavigationData}</textarea>
  793. </div>
  794. <div class="button-section">
  795. <button class="navigation-example">示例</button>
  796. <button class="navigation-clear">清空</button>
  797. <button class="navigation-save">保存自定义导航</button>
  798. </div>
  799. </div>
  800. `;
  801.  
  802. // 创建弹窗样式
  803. const style = document.createElement('style');
  804. style.textContent = `
  805. .custom-navigation-dialog {
  806. font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  807. color: #333;
  808. padding: 20px;
  809. }
  810.  
  811. .custom-navigation-dialog .notice-section {
  812. background: #f8f9fa;
  813. border-radius: 8px;
  814. padding: 15px 20px;
  815. margin-bottom: 20px;
  816. }
  817.  
  818. .custom-navigation-dialog .notice-section h3 {
  819. color: #e74c3c;
  820. margin: 0 0 10px 0;
  821. font-size: 16px;
  822. font-weight: 600;
  823. }
  824.  
  825. .custom-navigation-dialog .notice-section ol {
  826. margin: 0;
  827. padding-left: 20px;
  828. }
  829.  
  830. .custom-navigation-dialog .notice-section li {
  831. line-height: 1.6;
  832. margin-bottom: 5px;
  833. color: #666;
  834. font-size: 14px;
  835. }
  836.  
  837. .custom-navigation-dialog .notice-section a {
  838. color: #2196f3;
  839. text-decoration: none;
  840. transition: color 0.3s;
  841. }
  842.  
  843. .custom-navigation-dialog .notice-section a:hover {
  844. color: #1976d2;
  845. text-decoration: underline;
  846. }
  847.  
  848. .custom-navigation-dialog .textarea-section {
  849. margin: 20px 0;
  850. }
  851.  
  852. .custom-navigation-dialog .navigation-textarea {
  853. width: 100%;
  854. height: 200px;
  855. padding: 12px;
  856. border: 1px solid #ddd;
  857. border-radius: 8px;
  858. font-family: Consolas, Monaco, 'Courier New', monospace;
  859. font-size: 14px;
  860. line-height: 1.5;
  861. resize: none;
  862. background-color: #fff;
  863. transition: border-color 0.3s, box-shadow 0.3s;
  864. }
  865.  
  866. .custom-navigation-dialog .navigation-textarea:focus {
  867. outline: none;
  868. border-color: #4e6ef2;
  869. box-shadow: 0 0 0 3px rgba(78,110,242,0.1);
  870. }
  871.  
  872. .custom-navigation-dialog .button-section {
  873. text-align: center;
  874. margin-top: 20px;
  875. }
  876.  
  877. .custom-navigation-dialog button {
  878. padding: 8px 20px;
  879. margin: 0 8px;
  880. border: none;
  881. border-radius: 6px;
  882. font-size: 14px;
  883. font-weight: 500;
  884. cursor: pointer;
  885. transition: all 0.3s ease;
  886. }
  887.  
  888. .custom-navigation-dialog button:hover {
  889. transform: translateY(-1px);
  890. }
  891.  
  892. .custom-navigation-dialog .navigation-example {
  893. background: #f5f5f5;
  894. color: #333;
  895. }
  896.  
  897. .custom-navigation-dialog .navigation-example:hover {
  898. background: #e0e0e0;
  899. }
  900.  
  901. .custom-navigation-dialog .navigation-clear {
  902. background: #ff4d4f;
  903. color: white;
  904. }
  905.  
  906. .custom-navigation-dialog .navigation-clear:hover {
  907. background: #ff7875;
  908. }
  909.  
  910. .custom-navigation-dialog .navigation-save {
  911. background: #4e6ef2;
  912. color: white;
  913. }
  914.  
  915. .custom-navigation-dialog .navigation-save:hover {
  916. background: #6c87f5;
  917. }
  918.  
  919. .custom-navigation-dialog-overlay {
  920. position: fixed;
  921. top: 0;
  922. left: 0;
  923. right: 0;
  924. bottom: 0;
  925. background: rgba(0, 0, 0, 0.5);
  926. z-index: 999998;
  927. animation: fadeIn 0.3s ease;
  928. }
  929.  
  930. .custom-navigation-dialog-container {
  931. position: fixed;
  932. top: 50%;
  933. left: 50%;
  934. transform: translate(-50%, -50%);
  935. background: white;
  936. border-radius: 12px;
  937. box-shadow: 0 4px 24px rgba(0, 0, 0, 0.15);
  938. z-index: 999999;
  939. width: 90%;
  940. max-width: 600px;
  941. max-height: 90vh;
  942. overflow: auto;
  943. animation: slideIn 0.3s ease;
  944. }
  945.  
  946. .custom-navigation-dialog-close {
  947. position: absolute;
  948. right: 16px;
  949. top: 16px;
  950. width: 28px;
  951. height: 28px;
  952. border-radius: 50%;
  953. border: none;
  954. background: #f5f5f5;
  955. color: #666;
  956. font-size: 20px;
  957. line-height: 28px;
  958. text-align: center;
  959. cursor: pointer;
  960. transition: all 0.3s ease;
  961. padding: 0;
  962. display: flex;
  963. align-items: center;
  964. justify-content: center;
  965. }
  966.  
  967. .custom-navigation-dialog-close:hover {
  968. background: #ff4d4f;
  969. color: white;
  970. }
  971.  
  972. @keyframes fadeIn {
  973. from { opacity: 0; }
  974. to { opacity: 1; }
  975. }
  976.  
  977. @keyframes slideIn {
  978. from {
  979. opacity: 0;
  980. transform: translate(-50%, -48%);
  981. }
  982. to {
  983. opacity: 1;
  984. transform: translate(-50%, -50%);
  985. }
  986. }
  987. `;
  988.  
  989. // 创建遮罩层
  990. const overlay = document.createElement('div');
  991. overlay.className = 'custom-navigation-dialog-overlay';
  992.  
  993. // 创建弹窗容器
  994. const dialogContainer = document.createElement('div');
  995. dialogContainer.className = 'custom-navigation-dialog-container';
  996. dialogContainer.innerHTML = content;
  997.  
  998. // 创建关闭按钮
  999. const closeBtn = document.createElement('button');
  1000. closeBtn.className = 'custom-navigation-dialog-close';
  1001. closeBtn.innerHTML = '×';
  1002. dialogContainer.appendChild(closeBtn);
  1003.  
  1004. // 添加样式和元素到页面
  1005. document.head.appendChild(style);
  1006. document.body.appendChild(overlay);
  1007. document.body.appendChild(dialogContainer);
  1008.  
  1009. // 绑定事件
  1010. const textarea = dialogContainer.querySelector('.navigation-textarea');
  1011. const exampleJson = [{
  1012. "name": "我的导航",
  1013. "list": [
  1014. { "name": "百度", "url": "https://www.baidu.com/s?wd=@@" },
  1015. { "name": "必应", "url": "https://cn.bing.com/search?q=@@" }
  1016. ]
  1017. }];
  1018.  
  1019. // 示例按钮事件
  1020. dialogContainer.querySelector('.navigation-example').onclick = () => {
  1021. textarea.value = JSON.stringify(exampleJson, null, 4);
  1022. };
  1023.  
  1024. // 清空按钮事件
  1025. dialogContainer.querySelector('.navigation-clear').onclick = () => {
  1026. textarea.value = '';
  1027. };
  1028.  
  1029. // 保存按钮事件
  1030. dialogContainer.querySelector('.navigation-save').onclick = () => {
  1031. const content = textarea.value;
  1032. if (!content) {
  1033. commonFunctionObject.GMsetValue(this.customNavigationkey, null);
  1034. commonFunctionObject.webToast({ "message": "保存成功:数据为空", "background": "#4e6ef2" });
  1035. closeDialog();
  1036. return;
  1037. }
  1038.  
  1039. try {
  1040. const contentJson = JSON.parse(content);
  1041. if (this.validateNavigationFormat(contentJson)) {
  1042. commonFunctionObject.GMsetValue(this.customNavigationkey, contentJson);
  1043. commonFunctionObject.webToast({ "message": "保存成功", "background": "#4e6ef2" });
  1044. closeDialog();
  1045. // 刷新导航显示
  1046. this.show();
  1047. } else {
  1048. commonFunctionObject.webToast({ "message": "格式错误,请更正", "background": "#ff4d4f" });
  1049. }
  1050. } catch (e) {
  1051. commonFunctionObject.webToast({ "message": "格式错误,请更正", "background": "#ff4d4f" });
  1052. }
  1053. };
  1054.  
  1055. // 关闭弹窗函数
  1056. const closeDialog = () => {
  1057. overlay.remove();
  1058. dialogContainer.remove();
  1059. style.remove();
  1060. };
  1061.  
  1062. // 关闭按钮事件
  1063. closeBtn.onclick = closeDialog;
  1064. // 点击遮罩层关闭
  1065. overlay.onclick = closeDialog;
  1066. // 阻止弹窗点击事件冒泡到遮罩
  1067. dialogContainer.onclick = (e) => e.stopPropagation();
  1068. }
  1069.  
  1070. validateNavigationFormat(data) {
  1071. if (!Array.isArray(data)) return false;
  1072.  
  1073. return data.every(category => {
  1074. if (typeof category !== 'object' || !category.name || !Array.isArray(category.list)) {
  1075. return false;
  1076. }
  1077. return category.list.every(item => {
  1078. return typeof item === 'object' &&
  1079. typeof item.name === 'string' &&
  1080. typeof item.url === 'string';
  1081. });
  1082. });
  1083. }
  1084.  
  1085. show() {
  1086. const host = window.location.host;
  1087. const href = window.location.href;
  1088.  
  1089. if ((host === "www.baidu.com") ||
  1090. (host === "www.so.com" && href.includes("www.so.com/s")) ||
  1091. (host === "www.sogou.com" && (href.includes("www.sogou.com/web") || href.includes("www.sogou.com/sogou"))) ||
  1092. (host === "cn.bing.com" && href.includes("cn.bing.com/search")) ||
  1093. (host === "www.bing.com" && href.includes("www.bing.com/search")) ||
  1094. (host === "www4.bing.com" && href.includes("www4.bing.com/search")) ||
  1095. (host === "so.toutiao.com" && href.includes("so.toutiao.com/search")) ||
  1096. (host === "www.google.com" && href.includes("www.google.com/search"))) {
  1097.  
  1098. const currentSearchEnginesData = this.searchEnginesData.find(item => host === item.host);
  1099. if (currentSearchEnginesData) {
  1100. this.getNavigationData(currentSearchEnginesData.element, currentSearchEnginesData.elementInput);
  1101. }
  1102. }
  1103. }
  1104.  
  1105. start() {
  1106. this.show();
  1107. }
  1108. }
  1109.  
  1110. /**
  1111. * 初始化函数
  1112. */
  1113. function init() {
  1114. removeAds();
  1115. redirectOptimize();
  1116. hideBingPopup();
  1117. shortenUrl();
  1118. new SearchEnginesNavigation().start();
  1119. }
  1120.  
  1121. // 使用 MutationObserver 监听DOM变化
  1122. const observer = new MutationObserver(() => {
  1123. removeAds();
  1124. redirectOptimize();
  1125. });
  1126.  
  1127. observer.observe(document, {
  1128. childList: true,
  1129. subtree: true,
  1130. attributes: true,
  1131. attributeFilter: ["id", "class"]
  1132. });
  1133.  
  1134. // 初始化执行
  1135. if (document.readyState === 'loading') {
  1136. document.addEventListener('DOMContentLoaded', init);
  1137. } else {
  1138. init();
  1139. }
  1140.  
  1141. })({
  1142. GM_info: typeof GM_info == "object" ? GM_info : {},
  1143. unsafeWindow: typeof unsafeWindow == "object" ? unsafeWindow : window,
  1144. GM_addStyle: typeof GM_addStyle == "function" ? GM_addStyle : undefined,
  1145. });