Google & baidu Switcher (ALL in One)

谷歌、百度、必应的搜索引擎跳转工具,脚本默认自动更新检测,可在菜单自定义设置必应按钮,搜索引擎跳转的最佳体验。

当前为 2021-06-06 提交的版本,查看 最新版本

  1. /* jshint esversion: 8 */
  2. // ==UserScript==
  3. // @name Google & baidu Switcher (ALL in One)
  4. // @name:en Google & baidu & Bing Switcher (ALL in One)
  5. // @name:zh-TW 谷歌、百度、必應的搜索引擎跳轉工具
  6. // @version 3.0.20210606.2
  7. // @author F9y4ng
  8. // @description 谷歌、百度、必应的搜索引擎跳转工具,脚本默认自动更新检测,可在菜单自定义设置必应按钮,搜索引擎跳转的最佳体验。
  9. // @description:en Google, Baidu and Bing search engine tool, Automatically updated and detected by default, The Bing button can be customized.
  10. // @description:zh-TW 谷歌、百度、必應的搜索引擎跳轉工具,腳本默認自動更新檢測,可在菜單自定義設置必應按鈕,搜索引擎跳轉的最佳體驗。
  11. // @namespace https://openuserjs.org/scripts/t3xtf0rm4tgmail.com/Google_baidu_Switcher_(ALL_in_One)
  12. // @supportURL https://github.com/F9y4ng/GreasyFork-Scripts/issues
  13. // @icon https://www.google.com/favicon.ico
  14. // @include *://*.google.*/search*
  15. // @include *://*.google.*/webhp*
  16. // @include *://www.baidu.com/*
  17. // @include *://image.baidu.com/*
  18. // @include *://*.bing.com/*
  19. // @exclude *://*.google.*/sorry/*
  20. // @exclude *://*.google.*/url*
  21. // @exclude *://www.baidu.com/link*
  22. // @compatible Chrome 兼容TamperMonkey, ViolentMonkey
  23. // @compatible Firefox 兼容Greasemonkey4.0+, TamperMonkey, ViolentMonkey
  24. // @compatible Opera 兼容TamperMonkey, ViolentMonkey
  25. // @compatible Safari 兼容Tampermonkey • Safari
  26. // @require https://cdn.jsdelivr.net/npm/notice.js@0.4.0/dist/notice.js
  27. // @note 新增animate动画效果,压缩代码中的CSS.\n新增更新内容提示。\n修正一些bugs.
  28. // @grant GM_info
  29. // @grant GM_registerMenuCommand
  30. // @grant GM.registerMenuCommand
  31. // @grant GM_unregisterMenuCommand
  32. // @grant GM_openInTab
  33. // @grant GM_getValue
  34. // @grant GM.getValue
  35. // @grant GM_setValue
  36. // @grant GM.setValue
  37. // @license GPL-3.0-only
  38. // @create 2015-10-07
  39. // @copyright 2015-2021, F9y4ng
  40. // @run-at document-start
  41. // ==/UserScript==
  42.  
  43. !(function () {
  44. "use strict";
  45.  
  46. /* customize */
  47.  
  48. const isVersionDetection = true; // Set "false" to turn off the Version Detection forever.
  49. const isdebug = false; // set "true" to debug scripts, May cause script response slower.
  50.  
  51. /* Perfectly Compatible For Greasemonkey4.0+, TamperMonkey, ViolentMonkey * F9y4ng * 20210605 */
  52.  
  53. let GMsetValue, GMgetValue, GMregisterMenuCommand, GMunregisterMenuCommand, GMnotification, GMopenInTab;
  54. const GMinfo = GM_info;
  55. const handlerInfo = GMinfo.scriptHandler;
  56. const isGM = Boolean(handlerInfo.toLowerCase() === "greasemonkey");
  57. const debug = isdebug ? console.log.bind(console) : () => {};
  58. const error = isdebug ? console.error.bind(console) : () => {};
  59. const defCon = {
  60. // Global default value
  61. scriptName: GMinfo.script.name,
  62. curVersion: GMinfo.script.version,
  63. support: GMinfo.script.supportURL,
  64. isNoticed: sessionStorage.getItem("nCount") | 0,
  65. isNeedUpdate: 0,
  66. updateNote: null,
  67. fetchResult: true,
  68. lastRuntime: new Date().toLocaleString("en-US", {
  69. timeZoneName: "short",
  70. hour12: false,
  71. }),
  72. titleCase: (str, bool) => {
  73. // bool: true for Whole sentence.
  74. const RegExp = bool ? /( |^)[a-z]/g : /(^)[a-z]/g;
  75. return str
  76. .toString()
  77. .toLowerCase()
  78. .replace(RegExp, L => {
  79. return L.toUpperCase();
  80. });
  81. },
  82. randString: (n, v, r) => {
  83. // v: true for only letters.
  84. let s = "";
  85. let a = "0123456789";
  86. let b = "abcdefghijklmnopqrstuvwxyz";
  87. let c = b.toUpperCase();
  88. n = Number.isFinite(n) ? n : 10;
  89. v ? (r = b + c) : (r = a + b + a + c);
  90. for (; n > 0; --n) {
  91. s += r[Math.floor(Math.random() * r.length)];
  92. }
  93. return s;
  94. },
  95. };
  96. defCon.rName = defCon.randString(7, true);
  97. defCon.noticeHTML = str => {
  98. return String(`<div class="${defCon.rName}"><dl>${str}<dl></div>`);
  99. };
  100.  
  101. if (isGM) {
  102. GMsetValue = GM.setValue;
  103. GMgetValue = GM.getValue;
  104. GMregisterMenuCommand = GM.registerMenuCommand;
  105. GMunregisterMenuCommand = () => {};
  106. GMopenInTab = (a, b) => {
  107. window.open(a, defCon.randString(b.length, true).slice(-6));
  108. };
  109. } else {
  110. GMsetValue = GM_setValue;
  111. GMgetValue = GM_getValue;
  112. GMregisterMenuCommand = GM_registerMenuCommand;
  113. GMunregisterMenuCommand = GM_unregisterMenuCommand;
  114. GMopenInTab = GM_openInTab;
  115. }
  116.  
  117. GMnotification = (text = "", type = "info", closeWith = true, Interval = 0, timeout = 30, url = "", autoclose = false, closeToreload = false) => {
  118. try {
  119. new NoticeJs({
  120. text: text,
  121. type: type,
  122. closeWith: closeWith ? ["button"] : ["click"],
  123. timeout: timeout ? timeout : 30,
  124. width: 400,
  125. position: "bottomRight",
  126. animation: {
  127. open: "animated fadeIn",
  128. close: "animated fadeOut",
  129. },
  130. callbacks: {
  131. onShow: [
  132. function () {
  133. if (Interval) {
  134. const m = setInterval(() => {
  135. Interval ? --Interval : clearInterval(m);
  136. const y = document.querySelector(`.${defCon.rName} dl dd em`);
  137. if (y) {
  138. y.innerHTML = Interval;
  139. }
  140. }, 1e3);
  141. }
  142. },
  143. ],
  144. onClick: [
  145. function () {
  146. if (url) {
  147. const w = window.open(url, "Update.Scripts");
  148. if (autoclose) {
  149. setTimeout(() => {
  150. if (isGM) {
  151. window.opener = null;
  152. }
  153. w ? w.close() : error("//-> window not exsits.");
  154. GMnotification(
  155. defCon.noticeHTML(
  156. `<dd>如果您已更新了脚本,请点击<a href="javascript:void(0)" \
  157. onclick="location.reload()" class="im"\
  158. >这里</a>刷新使其生效。</a></dd>`
  159. ),
  160. "info",
  161. true,
  162. 0,
  163. 200
  164. );
  165. }, 2e3);
  166. }
  167. }
  168. },
  169. ],
  170. onClose: [
  171. function () {
  172. if (closeToreload) {
  173. location.reload();
  174. }
  175. },
  176. ],
  177. },
  178. }).show();
  179. } catch (e) {
  180. error("//-> GMnotification error:\n", e);
  181. }
  182. };
  183.  
  184. /* SYSTEM INFO */
  185.  
  186. console.info(
  187. `%c[GB-Init]%c\nVersion: ${defCon.curVersion} %c[%s]%c\nExtension: %s\nlastRuntime: ${defCon.lastRuntime}`,
  188. "font-weight:bold;color:dodgerblue",
  189. "color:0",
  190. "color:snow",
  191. checkVersion() instanceof Object === isVersionDetection,
  192. "color:0",
  193. defCon.titleCase(handlerInfo)
  194. );
  195.  
  196. /* Version Detection Start */
  197.  
  198. function fetchVersion(u) {
  199. return new Promise((e, t) => {
  200. fetch(u, {
  201. method: "GET",
  202. mode: "cors",
  203. cache: "no-store",
  204. credentials: "omit",
  205. })
  206. .then(e => {
  207. if (!e.ok) {
  208. throw Error(e.statusText);
  209. }
  210. return e.text();
  211. })
  212. .then(t => {
  213. let n = defCon.curVersion;
  214. let m = defCon.updateNote;
  215. t.split(/[\r\n]+/).forEach(function (item) {
  216. let key = item.match(/^(\/\/\s+@version\s+)(\S+)$/);
  217. if (key) {
  218. n = key[2];
  219. }
  220. let note = item.match(/^(\/\/\s+@note\s+)(.+)$/);
  221. if (note) {
  222. m = note[2];
  223. }
  224. });
  225. if (n !== undefined) {
  226. switch (compareVersion(defCon.curVersion, n)) {
  227. case 2:
  228. e([2, n, m, u]);
  229. break;
  230. case 1:
  231. e([1, n, m, u]);
  232. break;
  233. default:
  234. e([0, n, m, u]);
  235. break;
  236. }
  237. }
  238. })
  239. .catch(e => {
  240. error("//-> fetchVersion() error:\n", e);
  241. t();
  242. });
  243. });
  244. }
  245.  
  246. function compareVersion(current, compare) {
  247. let compare_array = compare.split(".");
  248. let current_array = current.split(".");
  249. let upgradeID = 0;
  250. if (compare_array.length === current_array.length) {
  251. for (let i = 0; i < compare_array.length; i++) {
  252. if (parseInt(compare_array[i]) < parseInt(current_array[i])) {
  253. upgradeID = 2;
  254. break;
  255. } else {
  256. if (parseInt(compare_array[i]) === parseInt(current_array[i])) {
  257. continue;
  258. } else {
  259. upgradeID = 1;
  260. break;
  261. }
  262. }
  263. }
  264. } else {
  265. upgradeID = 2;
  266. }
  267. return upgradeID;
  268. }
  269.  
  270. async function checkVersion(s = false) {
  271. let t, result;
  272. const m = await GMgetValue("_is_Ver_Det_");
  273. isVersionDetection ? (result = m === undefined ? isVersionDetection : Boolean(m)) : (result = false);
  274. if (result) {
  275. t = await fetchVersion(`https://greasyfork.org/scripts/12909/code/${defCon.randString(32)}.meta.js`).catch(async () => {
  276. defCon.fetchResult = false;
  277. });
  278. if (!defCon.fetchResult) {
  279. t = await fetchVersion(`https://raw.githubusercontent.com/F9y4ng/GreasyFork-Scripts/master/Google%20%26%20Baidu%20Switcher.meta.js`).catch(
  280. async () => {
  281. t = [0, defCon.curVersion, ""];
  282. }
  283. );
  284. }
  285. if (typeof t !== "undefined") {
  286. defCon.isNeedUpdate = t[0];
  287. const lastestVersion = t[1];
  288. const updateNote = ((w = "") => {
  289. t[2].split(/\\n/).forEach(function (item) {
  290. w += `<li>${item}</li>`;
  291. });
  292. return w ? `<dd class="disappear"><ul>${w}</ul></dd>` : "";
  293. })();
  294. const updateUrl = t[3].replace("meta", "user");
  295. const recheckURLs = new URL(
  296. updateUrl
  297. .replace("raw.githubusercontent", "github")
  298. .replace("master", "blob/master")
  299. .replace(/code\/[^/]+\.js/, "")
  300. );
  301. const sourceSite = defCon.titleCase(recheckURLs.hostname).split(".")[0];
  302.  
  303. switch (defCon.isNeedUpdate) {
  304. case 2:
  305. if (!s) {
  306. console.warn(
  307. String(
  308. `%c[GB-Update]%c\nWe found a new version, But %cthe latest version ` +
  309. `%c${lastestVersion}%c is lower than your local version %c${defCon.curVersion}.%c\n\n` +
  310. `Please confirm whether you need to upgrade your local script, and then you need to update it manually.\n\n` +
  311. `If you no longer need the update prompt, please set "isVersionDetection" to "false" in your local code!\n\n` +
  312. `[${sourceSite}]`
  313. ),
  314. "font-weight:bold;color:crimson",
  315. "font-weight:bold;color:0",
  316. "color:0",
  317. "font-weight:bold;color:tomato",
  318. "color:0",
  319. "font-weight:bold;color:darkred",
  320. "color:0"
  321. );
  322. }
  323. if (defCon.isNoticed < 2 || s) {
  324. GMnotification(
  325. defCon.noticeHTML(
  326. `<dt>${defCon.scriptName}</dt>
  327. <dd><span>发现版本异常</span>检测到新版本 <i>${lastestVersion}</i> 低于您的本地版本\
  328. <i>${defCon.curVersion}</i>,由于您曾编辑过本地脚本,脚本将被设置为默认禁止自动更新。</dd>\
  329. <dd>如需覆盖安装,请点击<a href="${recheckURLs}" target="_blank" class="im">这里</a>手动升级。</dd>\
  330. <dd>[ ${sourceSite} ]</dd><dd style="font-size:11px!important;color:lemonchiffon;\
  331. font-style:italic">注:若要重新启用自动更新功能,您需要在“脚本更新源”覆盖安装新版本后,\
  332. 从脚本菜单重新启用自动检测。</dd><dd style="text-align: center">\
  333. <img src="https://z3.ax1x.com/2021/06/03/28UFHJ.jpg" alt="开启自动检测"></dd>`
  334. ),
  335. "error",
  336. true,
  337. 0,
  338. 350,
  339. null,
  340. false,
  341. true
  342. );
  343. GMsetValue("_is_Ver_Det_", false);
  344. sessionStorage.setItem("nCount", ++defCon.isNoticed);
  345. }
  346. break;
  347. case 1:
  348. if (!s) {
  349. console.info(
  350. String(
  351. `%c[GB-Update]%c\nWe found a new version: %c${lastestVersion}%c.\n` +
  352. `Please upgrade from your update source to the latest version.\n` +
  353. `[${sourceSite}]`
  354. ),
  355. "font-weight:bold;color:crimson",
  356. "color:0",
  357. "color:crimson",
  358. "color:0"
  359. );
  360. }
  361. if (defCon.isNoticed < 2 || s) {
  362. GMnotification(
  363. defCon.noticeHTML(
  364. `<dt>${defCon.scriptName}</dt>\
  365. <dd><span>发现版本更新</span>最新版本 <i>${lastestVersion}</i>,如果您现在需要更新,请点击这里完成自动升级安装。</dd>\
  366. ${updateNote}<dd>[ ${sourceSite} ]</dd><dd onmouseover="this.parentNode.children[2].style.display='block';\
  367. this.style.display='none'" style="text-align:center">&gt;&gt; 查看更新内容 &lt;&lt;</dd>`
  368. ),
  369. "warning",
  370. false,
  371. 0,
  372. 80,
  373. `${updateUrl}`,
  374. true
  375. );
  376. sessionStorage.setItem("nCount", ++defCon.isNoticed);
  377. }
  378. break;
  379. default:
  380. debug(
  381. `%c[GB-Update]%c\nCurretVersion: %c${defCon.curVersion}%c is up-to-date!`,
  382. "font-weight:bold;color:darkcyan",
  383. "color:0",
  384. "color:red",
  385. "color:0"
  386. );
  387. if (s) {
  388. GMnotification(
  389. defCon.noticeHTML(
  390. `<dt>${defCon.scriptName}</dt>\
  391. <dd><span>更新成功</span>当前版本 <i>${defCon.curVersion}</i> 已为最新!</dd>\
  392. <dd>[ ${sourceSite} ]</dd>`
  393. ),
  394. "success"
  395. );
  396. }
  397. break;
  398. }
  399. } else {
  400. console.error(
  401. "%c[GB-Update]\n%cSome Unexpected Errors Caused Version Detection Failure.\nProbably Caused By NetworkError.",
  402. "font-weight:bold;color:red",
  403. "font-weight:bold;color:darkred"
  404. );
  405. }
  406. } else {
  407. console.warn(
  408. `%c[GB-Update]%c\nVersion detection has been turned off forever. %cBye%c!`,
  409. "font-weight:bold;color:red",
  410. "color:0",
  411. "color:darkred",
  412. "color:0"
  413. );
  414. }
  415. }
  416.  
  417. /* Menus & Button insert */
  418.  
  419. !(async function () {
  420. /* Get Promise Value */
  421.  
  422. const is_Use_Bing = parseInt(await GMgetValue("_if_Use_Bing_"));
  423. const is_Ver_Det = await GMgetValue("_is_Ver_Det_");
  424.  
  425. /* Set Default Value */
  426.  
  427. const CONST = {
  428. isSecurityPolicy: false,
  429. rndidName: defCon.randString(9, true),
  430. rndclassName: defCon.randString(12, true),
  431. bdyx: defCon.randString(5, true),
  432. ggyx: defCon.randString(5, true),
  433. bbyx: defCon.randString(5, true),
  434. isVDResult: isVersionDetection ? (is_Ver_Det === undefined ? isVersionDetection : Boolean(is_Ver_Det)) : false,
  435. isUseBing: (() => {
  436. if (isNaN(is_Use_Bing)) {
  437. GMsetValue("_if_Use_Bing_", 0);
  438. console.warn(
  439. "%c[GB-Warning]%c\nThis is your first visit, the Bing search button will not be inserted by default.",
  440. "font-weight:bold;color:salmon",
  441. "color:1"
  442. );
  443. return false;
  444. } else {
  445. return Boolean(is_Use_Bing);
  446. }
  447. })(),
  448. noticeCss: `@charset "UTF-8";.animated{animation-duration:1s;animation-fill-mode:both}.animated.infinite{animation-iteration-count:infinite}.animated.hinge{animation-duration:2s}.animated.bounceIn,.animated.bounceOut,.animated.flipOutX,.animated.flipOutY{animation-duration:.75s}@keyframes fadeIn{from{opacity:0}to{opacity:1}}.fadeIn{animation-name:fadeIn}@keyframes fadeOut{from{opacity:1}to{opacity:0}}.fadeOut{animation-name:fadeOut}.noticejs-top{top:0;width:100%}.noticejs-top .item{border-radius:0!important;margin:0!important}.noticejs-topRight{top:10px;right:10px}.noticejs-topLeft{top:10px;left:10px}.noticejs-topCenter{top:10px;left:50%;transform:translate(-50%)}.noticejs-middleLeft,.noticejs-middleRight{right:10px;top:50%;transform:translateY(-50%)}.noticejs-middleLeft{left:10px}.noticejs-middleCenter{top:50%;left:50%;transform:translate(-50%,-50%)}.noticejs-bottom{bottom:0;width:100%}.noticejs-bottom .item{border-radius:0!important;margin:0!important}.noticejs-bottomRight{bottom:10px;right:10px}.noticejs-bottomLeft{bottom:10px;left:10px}.noticejs-bottomCenter{bottom:10px;left:50%;transform:translate(-50%)}.noticejs{z-index:99999!important;font-family:Helvetica Neue,Helvetica,Arial,sans-serif}.noticejs .item{margin:0 0 10px;border-radius:3px;overflow:hidden}.noticejs .item .close{float:right;font-size:18px;font-weight:700;line-height:1;color:#fff;text-shadow:0 1px 0 #fff;opacity:1;margin-right:7px}.noticejs .item .close:hover{opacity:.5;color:#000}.noticejs .item a{color:#fff;border-bottom:1px dashed #fff}.noticejs .item a,.noticejs .item a:hover{text-decoration:none}.noticejs .success{background-color:#64ce83}.noticejs .success .noticejs-heading{background-color:#3da95c;color:#fff;padding:10px}.noticejs .success .noticejs-body{color:#fff;padding:10px!important}.noticejs .success .noticejs-body:hover{visibility:visible!important}.noticejs .success .noticejs-content{visibility:visible}.noticejs .info{background-color:#3ea2ff}.noticejs .info .noticejs-heading{background-color:#067cea;color:#fff;padding:10px}.noticejs .info .noticejs-body{color:#fff;padding:10px!important}.noticejs .info .noticejs-body:hover{visibility:visible!important}.noticejs .info .noticejs-content{visibility:visible}.noticejs .warning{background-color:#ff7f48}.noticejs .warning .noticejs-heading{background-color:#f44e06;color:#fff;padding:10px!important}.noticejs .warning .noticejs-body{color:#fff;padding:10px}.noticejs .warning .noticejs-body:hover{visibility:visible!important}.noticejs .warning .noticejs-content{visibility:visible}.noticejs .error{background-color:#e74c3c}.noticejs .error .noticejs-heading{background-color:#ba2c1d;color:#fff;padding:10px!important}.noticejs .error .noticejs-body{color:#fff;padding:10px}.noticejs .error .noticejs-body:hover{visibility:visible!important}.noticejs .error .noticejs-content{visibility:visible}.noticejs .progressbar{width:100%}.noticejs .progressbar .bar{width:1%;height:30px;background-color:#4caf50}.noticejs .success .noticejs-progressbar{width:100%;background-color:#64ce83;margin-top:-1px}.noticejs .success .noticejs-progressbar .noticejs-bar{width:100%;height:5px;background:#3da95c}.noticejs .info .noticejs-progressbar{width:100%;background-color:#3ea2ff;margin-top:-1px}.noticejs .info .noticejs-progressbar .noticejs-bar{width:100%;height:5px;background:#067cea}.noticejs .warning .noticejs-progressbar{width:100%;background-color:#ff7f48;margin-top:-1px}.noticejs .warning .noticejs-progressbar .noticejs-bar{width:100%;height:5px;background:#f44e06}.noticejs .error .noticejs-progressbar{width:100%;background-color:#e74c3c;margin-top:-1px}.noticejs .error .noticejs-progressbar .noticejs-bar{width:100%;height:5px;background:#ba2c1d}@keyframes noticejs-fadeOut{0%{opacity:1}to{opacity:0}}.noticejs-fadeOut{animation-name:noticejs-fadeOut}@keyframes noticejs-modal-in{to{opacity:.3}}@keyframes noticejs-modal-out{to{opacity:0}}.noticejs{position:fixed;z-index:10050;width:400px}.noticejs ::-webkit-scrollbar{width:8px}.noticejs ::-webkit-scrollbar-button{width:8px;height:5px}.noticejs ::-webkit-scrollbar-track{border-radius:10px}.noticejs ::-webkit-scrollbar-thumb{background:hsla(0,0%,100%,.5);border-radius:10px}.noticejs ::-webkit-scrollbar-thumb:hover{background:#fff}.noticejs-modal{position:fixed;width:100%;height:100%;background-color:#000;z-index:10000;opacity:.3;left:0;top:0}.noticejs-modal-open{opacity:0;animation:noticejs-modal-in .3s ease-out}.noticejs-modal-close{animation:noticejs-modal-out .3s ease-out;animation-fill-mode:forwards}.${defCon.rName}{padding:4px 4px 0 4px!important}.${defCon.rName} dl dt{margin:2px 0 8px 0!important;font-size:16px!important;font-weight:900!important}.${defCon.rName} dl dd{margin:3px 6px 0 0!important;font-size:14px!important;line-height:180%!important;margin-inline-start:10px!important}.${defCon.rName} dl dd em{color:#fff;font-family:Candara,sans-serif!important;font-size:24px!important;padding:0 5px}.${defCon.rName} dl dd span{font-weight:700;font-size:15px!important;margin-right:8px}.${defCon.rName} dl dd u{color:#ff8c00;font-weight:600;font-size:16px;text-decoration:none;padding:0 3px}.${defCon.rName} dl dd i{font-family:Candara,sans-serif!important;font-size:20px!important}.${defCon.rName} dl dd .im{color:gold;font-size:16px;font-weight:900;padding:0 3px}.${defCon.rName} ul{width:90%;display:inline-block;text-align:left;vertical-align:top;color:rgba(255, 255, 255, 0.5);padding:0.2em;margin:0;counter-reset:xxx 0}.${defCon.rName} li{list-style:none;font-style:italic!important;position:relative;padding:0 0 0 0.1em;margin:0 0 0 2px;-webkit-transition:.12s;transition:.12s}.${defCon.rName} li::before{content:counter(xxx,decimal) "、";counter-increment:xxx 1;font-family:'Roboto Condensed';font-size:1em;-webkit-transition:.5s;transition:.5s}.${defCon.rName} .disappear{display:none}`,
  449. };
  450.  
  451. let curretSite = {
  452. SiteTypeID: 0,
  453. SiteName: "",
  454. SplitName: "",
  455. MainType: "",
  456. HtmlCode: "",
  457. StyleType: "",
  458. };
  459.  
  460. const listSite = {
  461. baidu: {
  462. SiteTypeID: 1,
  463. SiteName: "Baidu",
  464. SplitName: "tn",
  465. MainType: ".s_btn_wr",
  466. HtmlCode: CONST.isUseBing
  467. ? String(`
  468. <span id="${CONST.ggyx}">
  469. <input type="button" title="Google一下" value="Google"/>
  470. </span>
  471. <span id="${CONST.bbyx}">
  472. <input type="button" title="Bing一下" value="Bing ®"/>
  473. </span>`)
  474. : String(`
  475. <span id="${CONST.ggyx}">
  476. <input type="button" title="Google一下" value="Google一下"/>
  477. </span>`),
  478. StyleCode: CONST.isUseBing
  479. ? `#form{white-space:nowrap} #u{z-index:1!important} #${CONST.rndidName} #${CONST.bbyx}{margin-left:-1.5px} #${CONST.rndidName} #${CONST.ggyx}{margin-left:2px}#${CONST.bbyx} input{background:#4e6ef2;border-top-right-radius:10px;border-bottom-right-radius:10px;cursor: pointer;height:40px;color:#fff;width:80px;border:1px solid #3476d2;font-size:16px;font-weight:bold}#${CONST.ggyx} input{background:#4e6ef2;border-top-left-radius:10px;border-bottom-left-radius:10px;cursor:pointer;height:40px;color:#fff;width:80px;border:1px solid #3476d2;font-size:16px;font-weight:bold}#${CONST.ggyx} input:hover,#${CONST.bbyx} input:hover{background: #4662D9;border:1px solid #3476d2}`
  480. : `#form{white-space:nowrap}#u{z-index: 1!important}#${CONST.rndidName}{margin-left:6px}#${CONST.ggyx} input{background: #4e6ef2;border-radius:10px;cursor:pointer;height:40px;color:#fff;width:112px;border:1px solid #3476d2;text-shadow: 0 0 2px #ffffff!important;font-size:16px}#${CONST.ggyx} input:hover{background:#4662D9;border: 1px solid #3476d2}`,
  481. },
  482. google: {
  483. SiteTypeID: 2,
  484. SiteName: "Google",
  485. SplitName: "tbm",
  486. MainType: "form button[type='submit']",
  487. HtmlCode: CONST.isUseBing
  488. ? String(`
  489. <span id="${CONST.bdyx}">
  490. <input type="button" title="百度一下" value="百度一下"/>
  491. </span>
  492. <span id="${CONST.bbyx}">
  493. <input type="button" title="Bing一下" value="Bing一下"/>
  494. </span>`)
  495. : String(`
  496. <span id="${CONST.bdyx}">
  497. <input type="button" title="百度一下" value="百度一下"/>
  498. </span>`),
  499. StyleCode: CONST.isUseBing
  500. ? `#${CONST.rndidName}{margin:3px 4px 0 -5px}#${CONST.rndidName} #${CONST.bdyx}{padding:5px 0 4px 18px;border-left:1px solid #ddd}#${CONST.rndidName} #${CONST.bbyx}{margin-left:-2px}.scrollspan{padding:1px 0 0 18px!important}.scrollbars{height:26px!important;font-size:13px!important;font-weight:normal!important;text-shadow:0 0 1px #ffffff!important}#${CONST.bdyx} input{cursor:pointer;padding:1px 1px 1px 6px!important;border:1px solid transparent;background:#1a73e8;box-shadow:none;border-top-left-radius:24px;border-bottom-left-radius:24px;width:90px;height:38px;font-size:15px;font-weight:600;color:#fff}#${CONST.bbyx} input{cursor:pointer;padding:1px 6px 1px 1px!important;border:1px solid transparent;background:#1a73e8;box-shadow:none;border-top-right-radius:24px;border-bottom-right-radius:24px;width:90px;height:38px;font-size:15px;font-weight:600;color:#fff}#${CONST.bdyx} input:hover,#${CONST.bbyx} input:hover{background: #2b7de9}`
  501. : `#${CONST.rndidName}{margin: 3px 4px 0 -5px} #${CONST.rndidName} #${CONST.bdyx}{padding:5px 0 4px 18px; border-left:1px solid #ddd} .scrollspan{padding:1px 0 0 18px!important} .scrollbars{height: 26px!important; font-size: 13px!important; font-weight: normal!important; text-shadow: 0 0 1px #ffffff !important} #${CONST.bdyx} input{cursor: pointer; border: 1px solid transparent; background: #1a73e8; box-shadow: none; border-radius: 24px; width: 90px; height: 38px; font-size: 14px; font-weight: 600; color: #fff} #${CONST.bdyx} input:hover{background: #2b7de9}`,
  502. },
  503. bing: {
  504. SiteTypeID: 3,
  505. SiteName: "Bing",
  506. SplitName: "undefined",
  507. MainType: "#sb_go_par",
  508. HtmlCode: String(`
  509. <span id="${CONST.bdyx}">
  510. <input type="button" title="百度一下" value="百度"/>
  511. </span>
  512. <span id="${CONST.ggyx}">
  513. <input type="button" title="Google一下" value="Google"/>
  514. </span>`),
  515. StyleCode: `#${CONST.rndidName}{height:44px;width:120px;margin: 2px 10px 2px 0}#${CONST.bdyx} input,#${CONST.ggyx} input{cursor:pointer;width:auto 60px;height:40px;background-color:#f7faff;border:1px solid #0095B7;color:#0095B7;margin-left:-1px;font-family:'Microsoft YaHei'!important;font-size:16px;font-weight:700;border-radius:4px}.scrollspan{height:32px!important}.scrollbars{height:30px!important}#${CONST.bdyx} input:hover,#${CONST.ggyx} input:hover{background-color:#fff;transition:border linear .1s,box-shadow linear .3s;box-shadow:1px 1px 8px #08748D;border: 2px solid #0095B7;text-shadow:0 0 1px #0095B7!important;color:#0095B7}`,
  516. },
  517. other: { SiteTypeID: 0 },
  518. };
  519.  
  520. const newSiteType = {
  521. BAIDU: listSite.baidu.SiteTypeID,
  522. GOOGLE: listSite.google.SiteTypeID,
  523. BING: listSite.bing.SiteTypeID,
  524. OTHERS: 0,
  525. };
  526.  
  527. debug("//-> Initialization complete, start running...");
  528.  
  529. if (location.host.includes(".baidu.com")) {
  530. // Include baidu
  531. curretSite = listSite.baidu;
  532. } else if (location.host.includes(".bing.com")) {
  533. // Include bing
  534. curretSite = listSite.bing;
  535. } else if (/^([0-9a-z-]+\.)?google(\.[a-z]{2,3}){1,3}$/.test(location.host)) {
  536. // Regular google
  537. curretSite = listSite.google;
  538. } else {
  539. curretSite = listSite.other;
  540. }
  541.  
  542. CONST.vim = GetUrlParam(curretSite.SplitName);
  543.  
  544. if (
  545. (curretSite.SiteTypeID === newSiteType.GOOGLE && /^(lcl|flm|fin)$/.test(CONST.vim)) ||
  546. (curretSite.SiteTypeID === newSiteType.BING && /^(maps)$/.test(CONST.vim)) ||
  547. (curretSite.SiteTypeID === newSiteType.BAIDU && /^(news|vsearch|baiduimagedetail)$/.test(CONST.vim))
  548. ) {
  549. CONST.isSecurityPolicy = true;
  550. }
  551.  
  552. /* insert Menus */
  553.  
  554. let menuManager = {
  555. inUse_switch: (_status, Name, Tips) => {
  556. const info = x => {
  557. return defCon.noticeHTML(`<dd>${Tips}已成功<u>${x}</u>,网页将在<em>3</em>秒后自动刷新!</dd>`);
  558. };
  559. if (_status) {
  560. GMsetValue(`${Name}`, 0);
  561. GMnotification(info("\u6e05\u9664"), "info", true, 3);
  562. } else {
  563. GMsetValue(`${Name}`, 1);
  564. GMnotification(info("\u6dfb\u52a0"), "success", true, 3);
  565. }
  566. setTimeout(() => {
  567. location.reload();
  568. }, 3e3);
  569. },
  570.  
  571. menuRemove: x => {
  572. x ? GMunregisterMenuCommand(x) : error("//-> menuRemove() not found item: %s.", typeof x);
  573. },
  574.  
  575. registerMenuCommand: function (e) {
  576. let Already, _Use_Bing__;
  577. let _use_Bing_ID, in_Use_feedBack_ID, in_UpdateCheck_ID;
  578.  
  579. // Remove menus if the menus exists.
  580. this.menuRemove(_use_Bing_ID);
  581. this.menuRemove(in_Use_feedBack_ID);
  582. this.menuRemove(in_UpdateCheck_ID);
  583.  
  584. e ? (_Use_Bing__ = "\ufff0\u2705 【已开启】") : (_Use_Bing__ = "\ufff0\u274c 【已关闭】");
  585.  
  586. _use_Bing_ID = GMregisterMenuCommand(`${_Use_Bing__}Bing 搜索跳转`, () => {
  587. if (!Already) {
  588. this.inUse_switch(e, "_if_Use_Bing_", "Bing 按钮");
  589. Already = true;
  590. }
  591. });
  592. // "false" is disabled forever.
  593. if (isVersionDetection) {
  594. // check VDR value to insert menu.
  595. if (CONST.isVDResult) {
  596. in_UpdateCheck_ID = GMregisterMenuCommand("\ufff5\ud83d\udd0e 【检查】版本更新", () => {
  597. checkVersion(true);
  598. });
  599. } else {
  600. in_UpdateCheck_ID = GMregisterMenuCommand("\ufff5\ud83d\udcdb 【已关闭】版本更新 \u267b 重新开启", () => {
  601. GMsetValue("_is_Ver_Det_", true);
  602. GMnotification(defCon.noticeHTML(`<dd>更新检测正在重新打开,网页将在<em>3</em>秒后自动刷新!</dd>`), "info", true, 3);
  603. setTimeout(() => {
  604. sessionStorage.clear();
  605. location.reload();
  606. }, 3e3);
  607. });
  608. }
  609. }
  610. in_Use_feedBack_ID = GMregisterMenuCommand("\ufff9\ud83e\udde1 【提建议】说出您的意见!", () => {
  611. GMopenInTab(`${defCon.support ? defCon.support : "https://greasyfork.org/scripts/12909/feedback"}`, {
  612. active: true,
  613. insert: true,
  614. setParent: true,
  615. });
  616. });
  617. },
  618.  
  619. menuDisplay: function () {
  620. // disabled menus if set SecurityPolicy.
  621. if (!CONST.isSecurityPolicy) {
  622. safeFunction(() => {
  623. this.registerMenuCommand(CONST.isUseBing);
  624. });
  625. }
  626.  
  627. console.log(
  628. "%c[GB-Status]%c\nInsert the Bing Search Button: %c%s",
  629. "font-weight:bold;color:darkorange",
  630. "color:0",
  631. "font-weight:bold;color:red",
  632. defCon.titleCase(CONST.isUseBing && !CONST.isSecurityPolicy)
  633. );
  634. },
  635.  
  636. init: function () {
  637. this.menuDisplay();
  638. },
  639. };
  640.  
  641. /* Insert search Button */
  642.  
  643. let searchManager = {
  644. insertSearchButton: function () {
  645. try {
  646. const getTarget = curretSite.MainType;
  647. const doHtml = curretSite.HtmlCode;
  648. const doStyName = `${CONST.rndclassName}`;
  649. const doStyle = CONST.noticeCss + curretSite.StyleCode;
  650. const userSpan = document.createElement("span");
  651. userSpan.id = `${CONST.rndidName}`;
  652. userSpan.innerHTML = doHtml;
  653. const SpanID = `#${userSpan.id}`;
  654. let Target = document.querySelector(getTarget);
  655.  
  656. addStyle(doStyle, doStyName, "head");
  657.  
  658. if (!document.querySelector(SpanID) && getSearchValue().length > 0 && Target) {
  659. if (/^(nws|vid|bks)$/.test(CONST.vim.trim())) {
  660. Target = Target.parentNode.parentNode.firstChild;
  661. Target.insertBefore(userSpan, Target.firstChild);
  662. if (document.querySelector(SpanID)) {
  663. document.querySelector(SpanID).setAttribute("style", "float:right");
  664. }
  665. } else {
  666. insterAfter(userSpan, Target);
  667. // Baidu image fixed
  668. if (document.querySelector(SpanID) && /^baiduimage$/.test(CONST.vim.trim())) {
  669. document.querySelector(SpanID).setAttribute("style", "margin-left:12px");
  670. }
  671. // Bing image fixed
  672. if (document.querySelector(".b_searchboxForm") && /^images$/.test(CONST.vim.trim())) {
  673. if (location.href.replace(/view=detailV2/, "") !== location.href) {
  674. document.querySelector(".b_searchboxForm").setAttribute("style", "width:640px");
  675. }
  676. }
  677. }
  678.  
  679. debug(`//-> searchManager $(Target): ${Target}`);
  680.  
  681. document.querySelectorAll(`#${CONST.ggyx}, #${CONST.bbyx}, #${CONST.bdyx}`).forEach(per => {
  682. per.addEventListener("click", () => {
  683. let gotoUrl = "about:blank";
  684. switch (per.id) {
  685. case `${CONST.ggyx}`:
  686. if (/^(baiduimage|images)$/.test(CONST.vim.trim())) {
  687. gotoUrl = "https://www.google.com/search?hl=zh-CN&source=lnms&tbm=isch&sa=X&q=";
  688. } else {
  689. gotoUrl = "https://www.google.com/search?hl=zh-CN&source=hp&newwindow=1&q=";
  690. }
  691. break;
  692. case `${CONST.bbyx}`:
  693. if (/^(isch|baiduimage)$/.test(CONST.vim.trim())) {
  694. gotoUrl = "https://cn.bing.com/images/search?first=1&tsc=ImageBasicHover&q=";
  695. } else {
  696. gotoUrl = "https://cn.bing.com/search?q=";
  697. }
  698. break;
  699. case `${CONST.bdyx}`:
  700. if (/^(images|isch)$/.test(CONST.vim.trim())) {
  701. gotoUrl = "https://image.baidu.com/search/index?tn=baiduimage&ps=1&ie=utf-8&word=";
  702. } else {
  703. gotoUrl = "https://www.baidu.com/s?ie=utf-8&rqlang=cn&wd=";
  704. }
  705. break;
  706. default:
  707. break;
  708. }
  709. GMopenInTab(decodeURI(gotoUrl + getSearchValue()), {
  710. active: true,
  711. insert: true,
  712. setParent: true,
  713. });
  714. });
  715. });
  716. }
  717. return true;
  718. } catch (e) {
  719. error("//-> searchManager.insertSearchButton() error:\n", e);
  720. return false;
  721. }
  722. },
  723.  
  724. scrollDetect: function () {
  725. switch (curretSite.SiteTypeID) {
  726. case newSiteType.GOOGLE:
  727. scrollButton(`#${CONST.rndidName}`, "scrollspan", 35);
  728. scrollButton(`#${CONST.rndidName} #${CONST.bdyx} input`, "scrollbars", 35);
  729. if (CONST.isUseBing) {
  730. scrollButton(`#${CONST.rndidName} #${CONST.bbyx} input`, "scrollbars", 35);
  731. }
  732. break;
  733. case newSiteType.BING:
  734. if (/^(images|videos)$/.test(CONST.vim.trim())) {
  735. scrollButton(`#${CONST.rndidName}`, "scrollspan", 50);
  736. scrollButton(`#${CONST.rndidName} #${CONST.bdyx} input`, "scrollbars", 50);
  737. scrollButton(`#${CONST.rndidName} #${CONST.ggyx} input`, "scrollbars", 50);
  738. }
  739. break;
  740. default:
  741. debug(`//-> No scrolling detecting.`);
  742. break;
  743. }
  744. return true;
  745. },
  746.  
  747. doSwitch: function () {
  748. try {
  749. if (curretSite.SiteTypeID !== newSiteType.OTHERS) {
  750. if (CONST.isSecurityPolicy) {
  751. console.log(
  752. "%c[GB-Prohibit]%c\nBlocked By: %c%s Security Policy",
  753. "font-weight:bold;color:indigo",
  754. "color:0",
  755. "font-weight:bold;color:darkred",
  756. curretSite.SiteName
  757. );
  758. return;
  759. } else {
  760. const callback = mutations => {
  761. mutations.forEach(mutation => {
  762. if (document.querySelector(`.${CONST.rndclassName}`) && document.querySelector(`#${CONST.rndidName}`)) {
  763. debug(`//-> Already Insert Button & CSS.`);
  764. } else {
  765. debug(
  766. "%c[GB-MutationObserver]\n%c(%c%s%c has changed: %c%s%c)",
  767. "font-weight:bold;color:olive",
  768. "color:0",
  769. "color:olive",
  770. mutation.type,
  771. "color:0",
  772. "font-weight:bold;color:red",
  773. defCon.titleCase(this.insertSearchButton() && this.scrollDetect()),
  774. "color:0"
  775. );
  776. }
  777. });
  778. };
  779. const opts = { childList: true, subtree: true };
  780. let observer = new MutationObserver(callback);
  781. observer.observe(document, opts);
  782. RAFInterval(
  783. () => {
  784. if (!document.querySelector(`#${CONST.rndidName}`) || !document.querySelector(`.${CONST.rndclassName}`)) {
  785. return this.insertSearchButton() && this.scrollDetect();
  786. }
  787. },
  788. 500,
  789. true
  790. );
  791. console.log(
  792. "%c[GB-Switch]%c\nWe are using The %c%s%c Search Engine.",
  793. "font-weight:bold;color:Green",
  794. "color:0",
  795. "font-weight:bold;color:darkcyan",
  796. curretSite.SiteName,
  797. "font-weight:normal;color:0"
  798. );
  799. }
  800. }
  801. } catch (e) {
  802. error("//-> searchManager.doSwitch() error:\n", e);
  803. }
  804. },
  805.  
  806. init: function () {
  807. this.doSwitch();
  808. },
  809. };
  810.  
  811. /* important functions */
  812.  
  813. function scrollButton(paraName, classNameIn, scrollSize) {
  814. debug(`//-> ${curretSite.SiteName} Scrolling Detecting: ${paraName}`);
  815. const oDiv = document.querySelector(paraName);
  816. let H = 0;
  817. let Y = oDiv;
  818. if (Y !== null) {
  819. while (Y) {
  820. H += Y.offsetTop;
  821. Y = Y.offsetParent;
  822. }
  823. document.addEventListener("scroll", () => {
  824. const s = document.body.scrollTop || document.documentElement.scrollTop;
  825. debug(`//-> H=${H} S=${s} H-S=(${H - s})`);
  826. if (s > H + scrollSize) {
  827. oDiv.setAttribute("class", classNameIn);
  828. } else {
  829. oDiv.removeAttribute("class");
  830. }
  831. });
  832. }
  833. }
  834.  
  835. function addStyle(css, className, addToTarget, isReload, initType) {
  836. RAFInterval(
  837. () => {
  838. try {
  839. let addTo = document.querySelector(addToTarget);
  840. if (typeof addToTarget === "undefined") {
  841. addTo = document.head || document.body || document.documentElement || document;
  842. }
  843. isReload = isReload || false;
  844. initType = initType || "text/css";
  845. if (typeof addToTarget === "undefined" || (typeof addToTarget !== "undefined" && document.querySelector(addToTarget))) {
  846. if (isReload === true) {
  847. safeRemove(`.${className}`);
  848. } else if (isReload === false && document.querySelector(`.${className}`)) {
  849. return true;
  850. }
  851. const cssNode = document.createElement("style");
  852. if (className !== null) {
  853. cssNode.className = className;
  854. }
  855. cssNode.setAttribute("type", initType);
  856. cssNode.innerHTML = css;
  857. addTo.appendChild(cssNode);
  858. }
  859. return true;
  860. } catch (e) {
  861. error(`//-> addStyle() error:\n`, e);
  862. return false;
  863. }
  864. },
  865. 20,
  866. true
  867. );
  868. }
  869.  
  870. function safeRemove(Css) {
  871. safeFunction(() => {
  872. const removeNodes = document.querySelectorAll(Css);
  873. for (let i = 0; i < removeNodes.length; i++) {
  874. removeNodes[i].remove();
  875. }
  876. });
  877. }
  878.  
  879. function safeFunction(func) {
  880. try {
  881. func();
  882. } catch (e) {
  883. error("//-> Function error:\n", e);
  884. }
  885. }
  886.  
  887. function getSearchValue() {
  888. let val = "";
  889. document.querySelectorAll('input[name="wd"], input[name="q"], input[name="word"]').forEach((item, index, arr) => {
  890. val = arr[0].value;
  891. if (val) {
  892. debug(`//-> INPUT: ${val} - INDEX: ${index} - OLD: ${item.value}`);
  893. }
  894. });
  895. if (val === null || val === "" || typeof val === "undefined") {
  896. const kvl = location.search.substr(1).split("&");
  897. for (let i = 0; i < kvl.length; i++) {
  898. let value = kvl[i].replace(/^(wd|word|kw|query|q)=/, "");
  899. if (value !== kvl[i]) {
  900. val = value;
  901. }
  902. }
  903. val = val.replace(/\+/g, " ");
  904. if (val) {
  905. debug(`//-> QUERY: ${val}`);
  906. }
  907. }
  908. return encodeURIComponent(val);
  909. }
  910.  
  911. function GetUrlParam(paraName) {
  912. if (paraName === "undefined") {
  913. const parameter = document.location.pathname.toString();
  914. const arr = parameter.split("/");
  915. return arr[1];
  916. } else {
  917. const url = document.location.toString();
  918. const arrObj = url.split("?");
  919. if (arrObj.length > 1) {
  920. const arrPara = arrObj[1].split("&");
  921. let arr;
  922. for (let i = 0; i < arrPara.length; i++) {
  923. arr = arrPara[i].split("=");
  924. if (arr !== null && arr[0] === paraName) {
  925. return arr[1];
  926. }
  927. }
  928. return "";
  929. } else {
  930. return "";
  931. }
  932. }
  933. }
  934.  
  935. function RAFInterval(callback, period, runNow) {
  936. const needCount = (period / 1000) * 60;
  937. let times = 0;
  938. if (runNow === true) {
  939. const shouldFinish = callback();
  940. if (shouldFinish) {
  941. return;
  942. }
  943. }
  944.  
  945. function step() {
  946. if (times < needCount) {
  947. times++;
  948. requestAnimationFrame(step);
  949. } else {
  950. const shouldFinish = callback() || false;
  951. if (!shouldFinish) {
  952. times = 0;
  953. requestAnimationFrame(step);
  954. } else {
  955. return;
  956. }
  957. }
  958. }
  959. requestAnimationFrame(step);
  960. }
  961.  
  962. function insterAfter(newElement, targetElement) {
  963. if (targetElement !== null) {
  964. const parent = targetElement.parentNode;
  965. if (parent.lastChild === targetElement) {
  966. parent.appendChild(newElement);
  967. } else {
  968. parent.insertBefore(newElement, targetElement.nextSibling);
  969. }
  970. }
  971. }
  972.  
  973. /* Let`s enjoy it! */
  974.  
  975. !(function () {
  976. try {
  977. debug("//-> Insert Ext Menu.");
  978. menuManager.init();
  979. debug("//-> Insert Search Button.");
  980. searchManager.init();
  981. window.onload = () => {
  982. if (isVersionDetection && !CONST.isVDResult) {
  983. debug("//-> Ready to Insert Random Tips.");
  984. if (Math.ceil(Math.random() * 20) > 18) {
  985. GMnotification(
  986. defCon.noticeHTML(
  987. `<dd title="随机提示">如果您修改过代码,在覆盖安装新代码后,您仍要从菜单中再开启检测功能,\
  988. 才能恢复自动更新。</dd><dd style="text-align: center" title="随机提示"><img\
  989. src="https://z3.ax1x.com/2021/06/03/28UFHJ.jpg" alt="开启自动检测"></dd>`
  990. ),
  991. "info",
  992. true,
  993. 0,
  994. 80
  995. );
  996. }
  997. }
  998. };
  999. } catch (e) {
  1000. console.error("%c[GB-Error]%c\n%s", "font-weight:bold;color:red", "font-weight:bold;color:darkred", e);
  1001. }
  1002. })();
  1003. })();
  1004. })();