tianteng

各种开车网站的优化

As of 2024-07-16. See the latest version.

  1. // ==UserScript==
  2. // @name tianteng
  3. // @namespace https://greasyfork.org/xmlspy
  4. // @version 1.3.2
  5. // @description 各种开车网站的优化
  6.  
  7. // @author xmlspy
  8. // @license MIT
  9.  
  10. // @require https://cdn.jsdelivr.net/npm/jquery@3.7.1/dist/jquery.min.js
  11.  
  12. // @include *
  13. // @connect *
  14.  
  15. // @run-at document-start
  16.  
  17. // @grant GM_xmlhttpRequest
  18. // @grant GM.setClipboard
  19. // @grant GM.xmlhttpRequest
  20. // @grant unsafeWindow
  21. // @grant GM_log
  22. // @grant GM_info
  23.  
  24.  
  25. // ==/UserScript==
  26.  
  27. /*
  28. 1. 以下开车的网站经常换域名,本程序使用特征识别,不使用网址进行判断,
  29. 即使域名换了也能识别并进入本程序(skrbt,javbus,紳士漫畫,JAVLibrary,BTSOW,松鼠症倉庫)
  30. 2. javbus,
  31. * 所有页面,搜索按钮后面都添加"粘贴&搜索"按钮,点击后复制剪贴板的内容到搜索框并自动点击搜索按钮
  32. * 所有页面,添加"打开skrbt"的链接
  33. * 影片明细页面,添加复制车牌号按钮,删除磁链的onclick事件(否则会执行两次打开磁链事件),添加 在javlibrary中打开
  34. * 论坛明细页面,为每个磁力链后面添加"复制磁链"和"打开磁链"按钮,为每个回复添加"复制所有磁链",
  35. "打开所有磁链","复制所有磁链(不含点评)"和"打开所有磁链(不含点评) 4个按钮(气死各种课代表)
  36. 3. 松鼠症倉庫,去除点击广告
  37. 4. 紳士漫畫,
  38. * 明细页面,添加搜索框
  39. * 下拉阅读页面,图片由一列改为两列
  40. * 所有页面, 为搜索框后面添加 粘贴&搜索 按钮
  41. 5. JAVLibrary,
  42. * 所有页面,添加 打开skrbt 链接
  43. * 所有页面,添加 粘贴&搜索 按钮
  44. * 所有页面,删除 url重定向
  45. * 详情页面,添加 复制车牌 按钮
  46. * 详情页面,添加 javbus中查询 链接
  47. * 详情页面,删除 名称中的链接,否则很容易误点,又不容易复制文字
  48. 6. BTSOW,添加 粘贴&搜索 按钮
  49. 7. skrbt,
  50. * 所有页面,添加 粘贴&搜索 按钮
  51. * 搜索结果列表页面,每条结果后面都添加 "复制磁链"和"点击磁链"按钮,不用进入明细页面
  52. 8. 知乎,添加 粘贴&搜索 按钮
  53. 9. 百度,添加 粘贴&搜索 按钮
  54.  
  55. * 2024-7-16
  56. * 影片明细页面添加 在javlibrary中打开;
  57. * 论坛明细页面,为每个回复添加"复制所有磁链","打开所有磁链","复制所有磁链(不含点评)"和"打开所有磁链(不含点评) 4个按钮
  58. */
  59. (function () {
  60. "use strict";
  61.  
  62. /**
  63. * skrbt
  64. */
  65. const skrbtDomain = "skrbtqx";
  66. const skrbtHost = skrbtDomain + ".top";
  67. const skrbtUrl = "https://" + skrbtHost;
  68.  
  69. /**
  70. * javbus
  71. */
  72. const javbusDomain = "busfan";
  73. const javabusUrl = `https://www.${javbusDomain}.shop`;
  74.  
  75. /**
  76. * javLibrary
  77. */
  78. var javLibDomain = "y78k";
  79. var javLibUrl = "https://www." + javLibDomain + ".com";
  80. let javLibRegx = "(" + javLibDomain + "|javlib|javlibrary)";
  81.  
  82. const enableDebug = true;
  83. let seq = 0;
  84. // function (){}
  85.  
  86. // // 获取 HTMLElement 构造函数
  87. // const HTMLElementConstructor = HTMLElement;
  88.  
  89. // // 创建一个代理对象来拦截 HTMLElement 的构造函数
  90. // const HTMLElementProxy = new Proxy(HTMLElementConstructor, {
  91. // construct(target, args, newTarget) {
  92. // console.log("Creating a new HTMLElement instance");
  93. // // 创建一个新的 HTMLElement 实例
  94. // const instance = new target(...args);
  95. // // 返回一个新的代理对象来拦截实例的属性和方法
  96. // return new Proxy(instance, {
  97. // get(target, prop, receiver) {
  98. // console.log(`Accessing property: ${prop}`);
  99. // return Reflect.get(target, prop, receiver);
  100. // },
  101. // set(target, prop, value, receiver) {
  102. // console.log(`Setting property: ${prop} to ${value}`);
  103. // return Reflect.set(target, prop, value, receiver);
  104. // },
  105. // has(target, prop) {
  106. // console.log(`Checking if property exists: ${prop}`);
  107. // return Reflect.has(target, prop);
  108. // },
  109. // deleteProperty(target, prop) {
  110. // console.log(`Deleting property: ${prop}`);
  111. // return Reflect.deleteProperty(target, prop);
  112. // },
  113. // ownKeys(target) {
  114. // console.log(`Enumerating properties`);
  115. // return Reflect.ownKeys(target);
  116. // },
  117. // getOwnPropertyDescriptor(target, prop) {
  118. // console.log(`Getting property descriptor for: ${prop}`);
  119. // return Reflect.getOwnPropertyDescriptor(target, prop);
  120. // },
  121. // defineProperty(target, prop, descriptor) {
  122. // console.log(`Defining property: ${prop}`);
  123. // return Reflect.defineProperty(target, prop, descriptor);
  124. // },
  125. // });
  126. // },
  127. // });
  128.  
  129. // // 替换全局的 HTMLElement 构造函数
  130. // Object.defineProperty(window, "HTMLElement", {
  131. // value: HTMLElementProxy,
  132. // writable: false,
  133. // configurable: false,
  134. // });
  135.  
  136. // // 测试
  137. // const div = document.createElement("div");
  138. // div.innerHTML = "Hello, World!";
  139. // console.log(div.innerHTML);
  140. // div.innerHTML = "Hello, Proxy!";
  141. // console.log(div.innerHTML);
  142. /////////////////////////////////////////////////////////////////////////////
  143. // 事件拦截
  144. /////////////////////////////////////////////////////////////////////////////
  145. debug(document.querySelector("title"));
  146.  
  147. //松鼠症倉庫 地址发布页 https://ahrilist.top/
  148.  
  149. const ep = EventTarget.prototype;
  150. // setTimeout(function () {
  151. // if (!isNativeCode(ep.addEventListener)) {
  152. // debug(`addEventListener 原型被更改为:${ep.addEventListener.toString()}`);
  153. // }
  154. // });
  155. // if(!ep.constructorOriginal){
  156. // ep.constructorOriginal = ep.constructor;
  157. // ep.constructor=function(){
  158. // debug('构造器');
  159. // this.constructorOriginal();
  160. // }
  161. // }
  162. // function monster1(disposition) {
  163. // this.disposition = disposition;
  164. // }
  165.  
  166. // const handler1 = {
  167. // construct(target, args) {
  168. // console.log(`Creating a ${target.name}`);
  169. // // Expected output: "Creating a monster1"
  170.  
  171. // return new target(...args);
  172. // },
  173. // };
  174.  
  175. // const proxy1 = new Proxy(monster1, handler1);
  176.  
  177. // console.log(new proxy1('fierce').disposition);
  178.  
  179. if (!ep.addEventListenerOriginal) {
  180. ep.addEventListenerOriginal = ep.addEventListener;
  181. ep.addEventListener = function (type, callback, options) {
  182. // if (/ahri8\.top/.test(window.location.href)) {
  183. // debug(`添加事件监听器:target: ${this} type: ${type} callback: ${callback} options: ${options}`);
  184. if (this) {
  185. /////////////////////////////////////////////////////////////////////////////
  186. // 松鼠症倉庫
  187. /////////////////////////////////////////////////////////////////////////////
  188. if (
  189. this.className &&
  190. this.className.includes &&
  191. this.className.includes("apo")
  192. ) {
  193. debug("禁止点击广告", "松鼠症倉庫");
  194. return;
  195. }
  196. // }
  197. this.allListeners = this.allListeners || [];
  198. this.allListeners.push({ type, callback, options });
  199. // this.addEventListenerOriginal(type, callback, options);
  200. this.addEventListenerOriginal.apply(this, arguments);
  201. } else {
  202. debug(
  203. `[this] is bad. type: ${type} callback: ${callback} options: ${options}`,
  204. "addEventListenerHook"
  205. );
  206. }
  207. };
  208. }
  209. if (!ep.removeEventListenerOriginal) {
  210. ep.removeEventListenerOriginal = ep.removeEventListener;
  211. ep.removeEventListener = function (type, callback, options) {
  212. if (this) {
  213. this.removeEventListenerOriginal.apply(this, arguments);
  214. this.allListeners = this.allListeners || [];
  215. const index = this.allListeners.indexOf({ type, callback, options });
  216. if (index != -1) {
  217. this.allListeners.splice(index, 1);
  218. }
  219. } else {
  220. debug(
  221. `[this] is bad. type: ${type} callback: ${callback} options: ${options}`,
  222. "removeEventListenerHook"
  223. );
  224. }
  225. };
  226. }
  227.  
  228. /////////////////////////////////////////////////////////////////////////////
  229. // 节点变化监控
  230. /////////////////////////////////////////////////////////////////////////////
  231. new MutationObserver(function (mutationsList, observer) {
  232. // Use traditional 'for loops' for IE 11
  233. // console.log(mutationsList);
  234. for (let mutation of mutationsList) {
  235. if (mutation.type === "childList") {
  236. const target = mutation.target;
  237. if (target["id"] == "magnet-table") {
  238. debug(mutation.addedNodes);
  239. }
  240. } else if (mutation.type === "attributes") {
  241. if (mutation.attributeName.startsWith("on")) {
  242. debug(mutation, "MutationObserver");
  243. // debug(`target: ${mutation.target}`);
  244. }
  245. }
  246. }
  247. }).observe(document, {
  248. childList: true,
  249. subtree: true,
  250. attributes: true,
  251. //attributeFilter: [],
  252. attributeOldValue: true,
  253. characterData: false,
  254. characterDataOldValue: false,
  255. });
  256.  
  257. // execute(()=>{},()=>{});
  258. ///////////////////////////////////////////////////////////////////////////
  259. // jquery.ready
  260. ///////////////////////////////////////////////////////////////////////////
  261. $(function () {
  262. // execute("松鼠症倉庫", /ahri8\.top/, () => {
  263. // removeEvents(document.querySelectorAll("a.apo"), "click");
  264.  
  265. // debug("-------------------------------------------------------xxxx");
  266. // });
  267. ///////////////////////////////////////////////////////////////////////////
  268. // oschina
  269. ///////////////////////////////////////////////////////////////////////////
  270. execute("开源中国", /oschina\.net/, () => {
  271. debug("修改首页某些链接无法中键点击问题.", "开源中国");
  272. $(`[data-href]`).each(function () {
  273. const $this = $(this);
  274. const href = $this.attr("data-href");
  275. const classCss = $this.attr("class");
  276. const title = $this.attr("title");
  277. const innerHtml = this.innerHTML;
  278.  
  279. const html = `<a target="_blank" title="${title}" href="${href}" class="${classCss}">${innerHtml}</a>`;
  280. $this.replaceWith(html);
  281. });
  282.  
  283. debug("删除url中的重定向.", "开源中国");
  284. $('a[href*="/action/GoToLink?url"]').each(function (index) {
  285. // https://www.oschina.net/action/GoToLink?url=https%3A%2F%2Fcode.visualstudio.com%2Fupdates%2Fv1_91
  286. var url = getQueryVariable(this, "url");
  287. this.href = decodeURIComponent(url);
  288. });
  289. });
  290. ///////////////////////////////////////////////////////////////////////////
  291. // gitee.com
  292. ///////////////////////////////////////////////////////////////////////////
  293. execute("gitee", /gitee\.com/, () => {
  294. debug("删除url中的重定向.", "gitee");
  295. $('a[href*="/link?target"]').each(function (index) {
  296. var url = getQueryVariable(this, "target");
  297. this.href = decodeURIComponent(url);
  298. });
  299. });
  300.  
  301. ///////////////////////////////////////////////////////////////////////////
  302. // 紳士漫畫永久域名: wnacg.com 紳士漫畫永久地址發佈頁: wnacg.date
  303. ///////////////////////////////////////////////////////////////////////////
  304. execute("紳士漫畫", $('head>title:contains("紳士漫畫")'), () => {
  305. if (location.href.includes("photos-index-aid")) {
  306. debug("明细页面添加搜索框", "紳士漫畫");
  307. const searchInput = `
  308. <div class="search" style="float:right;">
  309. <form id="album_search q-form" action="/search/" method="get" _lpchecked="1">
  310. <div class="input-append" id="q-input">
  311. <input type="text" class="search-query ui-autocomplete-input tips"
  312. name="q" value="" title="搜索漫畫" autocomplete="off"
  313. role="textbox" aria-autocomplete="list" aria-haspopup="true">
  314. <input style="display:none" type="radio" name="f" value="_all" checked="">
  315. <input style="display:none" name="s" value="create_time_DESC">
  316. <input style="display:none" name="syn" value="yes">
  317. <button type="" name=""></button>
  318. </div>
  319. </form>
  320. </div>
  321. `;
  322. $("#bodywrap").prepend(searchInput);
  323. }
  324.  
  325. if (location.href.includes("photos-slide-aid")) {
  326. debug("下拉阅读页面,图片由一列改为两列", "紳士漫畫");
  327. const nodeToObserve = document.querySelector("#img_list");
  328. $(nodeToObserve).css({
  329. width: "100%",
  330. display: "flex",
  331. "flex-wrap": "wrap",
  332. "justify-content": "flex-start",
  333. "overflow-x": "hidden",
  334. });
  335. const imgWidth = document.documentElement.clientWidth / 2 - 10;
  336. const imgHeight = document.documentElement.clientHeight - 50;
  337. new MutationObserver((mutations, observer) => {
  338. $("#img_list>div").css({
  339. flex: "1",
  340. "background-color": "#cacaca",
  341. margin: "0 5px 5px 0",
  342. width: "calc((100% - 10px) / 2)",
  343. "min-width": "calc((100% - 10px) / 2)",
  344. "max-width": "calc((100% - 10px) / 2)",
  345. });
  346. $("#img_list>div>img").on("load", (e) => {
  347. drawImage(e.target, imgWidth, imgHeight);
  348. });
  349. }).observe(nodeToObserve, { childList: true });
  350. }
  351.  
  352. if ($("input.search-query").length > 0) {
  353. debug("为搜索框后面添加 粘贴&搜索 按钮", "紳士漫畫");
  354. const $pasteAndSearchButton = $(
  355. `<button style="float:right;height:30px;">粘贴&amp;搜索</button>`
  356. );
  357. $("#bodywrap").prepend($pasteAndSearchButton);
  358. $pasteAndSearchButton.on("click", () => {
  359. navigator.clipboard.readText().then((clipText) => {
  360. if (clipText != null && $.trim(clipText) != "") {
  361. $("[name=q]").val($.trim(clipText));
  362. $("#q-input > button").click();
  363. }
  364. });
  365. });
  366. }
  367. });
  368.  
  369. ///////////////////////////////////////////////////////////////////////////
  370. // JAVLibrary
  371. ///////////////////////////////////////////////////////////////////////////
  372. execute("JAVLibrary", $('head>title:contains("JAVLibrary")'), () => {
  373. // ---- 所有页面
  374.  
  375. // 删除广告
  376. $(".socialmedia,#bottombanner13,#topbanner11,#sidebanner11").remove();
  377. $("#leftmenu>div>ul:nth-child(2)>li:nth-child(2)").remove();
  378.  
  379. // 调节UI
  380. $("#content").css("padding-top", "10px");
  381. $("#toplogo").css("height", "50px");
  382. $("#toplogo").find('img[src*="logo-top"]').attr("height", "40");
  383.  
  384. // 添加 打开skrbt 连接
  385. $(".advsearch").append(
  386. `&nbsp;&nbsp;<a href="${skrbtUrl}" target="_blank">打开skrbt</a>`
  387. );
  388.  
  389. // 添加 粘贴&搜索 按钮
  390. const styleMap = {};
  391. $("#idsearchbutton")[0] &&
  392. $("#idsearchbutton")[0]
  393. .computedStyleMap()
  394. .forEach((value, key) => {
  395. styleMap[key] = value;
  396. });
  397. const $pasteAndSearchButton = $(
  398. `<input type="button" value="粘贴&搜索" id="pasteAndSearch"></input>`
  399. );
  400. $pasteAndSearchButton.css(styleMap);
  401. $pasteAndSearchButton.click(() => {
  402. navigator.clipboard.readText().then((clipText) => {
  403. if (clipText != null && $.trim(clipText) != "") {
  404. $("#idsearchbox").val(clipText);
  405. $("#idsearchbutton").click();
  406. }
  407. });
  408. });
  409. $("#idsearchbutton").parent().append($pasteAndSearchButton);
  410.  
  411. // 恢复原始url,删除重定向
  412. $.each($("a[href^='redirect.php?url']"), function (index, a) {
  413. var url = getQueryVariable(a, "url");
  414. a.href = decodeURIComponent(url);
  415. if (!a.href.startsWith("https")) {
  416. a.href = a.href.replace("http", "https");
  417. }
  418. a.text = a.text + " " + a.href + " ";
  419. if (a.href.includes("yimuhe")) {
  420. $(a)
  421. .parentsUntil("tr")
  422. .closest(".t")
  423. .css("background-color", "#6B6C83");
  424. a.style = "font-size:20px;";
  425. } else {
  426. a.style = "font-size:20px;";
  427. }
  428. });
  429.  
  430. // ---- 详情页面
  431.  
  432. if (/.*\?v=.*/.test(location.href)) {
  433. // 添加 复制车牌 按钮
  434. let chePai = document.querySelector(
  435. "#video_id > table > tbody > tr > td.text"
  436. ).innerText;
  437. let toAppendElement = document.querySelector(
  438. "#video_id > table > tbody > tr > td.text"
  439. );
  440. appendCopyButton(chePai, toAppendElement);
  441.  
  442. // 添加 javbus中查询 链接
  443. let trTag = document.querySelector("#video_id > table > tbody > tr");
  444. let javdbQueryId = "javdbQueryId";
  445. trTag.innerHTML = [
  446. trTag.innerHTML,
  447. '<td><a id="',
  448. javdbQueryId,
  449. '"href="',
  450. javabusUrl,
  451. "/",
  452. chePai,
  453. '">javbus中查询</a></td>',
  454. ].join("");
  455.  
  456. // 添加 打开SkrBt 链接
  457. $(trTag).append(
  458. [
  459. '<td><a target="_blank" ',
  460. 'href="',
  461. skrbtUrl,
  462. "/search?keyword=",
  463. chePai,
  464. '">打开SkrBT</a></td>',
  465. ].join("")
  466. );
  467.  
  468. // 删除名称中的链接,否则很容易误点,又不容易复制文字
  469. const videoTitleNode = document.querySelector("#video_title > h3 > a");
  470. if (videoTitleNode) {
  471. const videoTitle = videoTitleNode.getInnerHTML();
  472. videoTitleNode.parentNode.innerText = videoTitle;
  473. }
  474. }
  475. });
  476.  
  477. ///////////////////////////////////////////////////////////////////////////
  478. // 永久域名:https://www.javbus.com 防屏蔽地址:https://www.fanbus.help
  479. // 防屏蔽地址:https://www.javsee.help 防屏蔽地址:https://www.buscdn.help
  480. ///////////////////////////////////////////////////////////////////////////
  481. execute(
  482. "javbus",
  483. [
  484. $('head>title:contains("JavBus")'),
  485. // /genre/hd , /genre/sub
  486. $("body > nav > div > div.navbar-header.mh50 > a > img[alt='JavBus']"),
  487. // 论坛
  488. "#toptb.jav-nav",
  489. ],
  490. () => {
  491. debug("添加 粘贴&搜索 按钮", "javbus");
  492. const searchButton = $(
  493. "button[onclick=\"searchs('search-input')\"]:first"
  494. );
  495. const searchInput = $("#search-input:first");
  496. addPasteAndSearchButton(searchButton, searchInput);
  497.  
  498. // 调整样式
  499. $(".nav>li>a").attr("style", "padding-left:8px;padding-right:8px;");
  500.  
  501. debug("添加 打开skrbt 链接", "javbus");
  502. //添加skrbt链接
  503. $(".nav-title.nav-inactive:last,ul.nav.navbar-nav:first").append(`
  504. <li class="hidden-md hidden-sm">
  505. <a href="${skrbtUrl}" target="_blank">打开skrbt</a>
  506. </li>
  507. `);
  508.  
  509. let chePaiNode = document.querySelector(
  510. "body > div.container > div.row.movie > div.col-md-3.info > p:nth-child(1) > span:nth-child(2)"
  511. );
  512. // ----- 明细页面
  513. if (chePaiNode) {
  514. debug("添加复制车牌号按钮", "javbus");
  515. const chePai = chePaiNode.innerText.trim();
  516. const toAppendElement = document.querySelector(
  517. "body > div.container > div.row.movie > div.col-md-3.info > p:nth-child(1)"
  518. );
  519. appendCopyButton(chePai, toAppendElement);
  520.  
  521. debug("删除磁力链接中的onclick事件", "javbus");
  522. setInterval(() => $("#magnet-table td").removeAttr("onclick"), 1000);
  523.  
  524. debug('添加 在javlibrary中打开','javabus');
  525. //https://www.y78k.com/cn/vl_searchbyid.php?keyword=SUJI-241
  526. const javLibLink =`<a href="${javLibUrl}/cn/vl_searchbyid.php?keyword=${chePai}">在javlib中打开</a>`;
  527. $(toAppendElement).append(javLibLink);
  528.  
  529. }
  530.  
  531. // ---- 论坛明细页面
  532. if (location.href.includes("mod=viewthread")) {
  533. debug("为磁链添加按钮", "javbus");
  534. function toAlienMagnet(magnet, alien) {
  535. alien = alien ? alien : "-";
  536. let part1 = magnet.slice(0, 21);
  537. let part2 = magnet.slice(21);
  538. return `${part1}${alien}${part2}`;
  539. }
  540. function toNormalMagnet(magnet, alien) {
  541. alien = alien ? alien : "-";
  542. return magnet.replace(alien, "");
  543. }
  544. function getMagnetRegExp(alien) {
  545. if (alien) {
  546. return new RegExp(
  547. `(?:magnet:\\?xt=urn:btih:)?(?:(?:[0-9a-f]{1}${alien}[0-9a-f]{39})|(?:[ABCDEFGHIJKLMNOPQRSTUVWXYZ234567]${alien}[ABCDEFGHIJKLMNOPQRSTUVWXYZ234567]{31}))`,
  548. "gim"
  549. );
  550. } else {
  551. return /(?:magnet:\?xt=urn:btih:)?(?:[0-9a-fA-F]{40}|[ABCDEFGHIJKLMNOPQRSTUVWXYZ234567]{32})/gim;
  552. }
  553. }
  554. function completeMagnet(magnet) {
  555. if (!magnet) {
  556. return magnet;
  557. }
  558. if (magnet.length === 32 || magnet.length === 40) {
  559. return `magnet:?xt=urn:btih:${magnet}`;
  560. }
  561. return magnet;
  562. }
  563.  
  564. // 所有按钮的点击事件处理
  565. $(document).on(
  566. "click",
  567. 'button[class*="tianteng-button"]',
  568. function (e) {
  569. let button = $(e.target);
  570. let buttonType = button.data("tiantengButton");
  571. // 复制磁链
  572. if (buttonType === "copy") {
  573. let magnet = button.data("tiantengMagnet");
  574. GM.setClipboard(toNormalMagnet(magnet), "text");
  575. return;
  576. }
  577. // 打开磁链
  578. if (buttonType === "click") {
  579. let magnet = button.data("tiantengMagnet");
  580. setTimeout(() => window.open(toNormalMagnet(magnet)), 500);
  581. return;
  582. }
  583. // 复制所有磁链
  584. if (buttonType === "copyAll") {
  585. let postId = button.data("tiantengPostId");
  586. let magnets = "";
  587. $(`[data-tianteng-button="copy"]`, $(`#${postId}`)).each(
  588. function () {
  589. let magnet = $(this).data("tiantengMagnet");
  590. magnets = magnets + toNormalMagnet(magnet) + "\n";
  591. }
  592. );
  593. GM.setClipboard(magnets, "text");
  594. return;
  595. }
  596. // 打开所有磁链
  597. if (buttonType === "clickAll") {
  598. let postId = button.data("tiantengPostId");
  599. $(`[data-tianteng-button="copy"]`, $(`#${postId}`)).each(
  600. function () {
  601. let magnet = $(this).data("tiantengMagnet");
  602. magnet = toNormalMagnet(magnet);
  603. setTimeout(() => window.open(toNormalMagnet(magnet)), 500);
  604. }
  605. );
  606. return;
  607. }
  608. // 复制所有磁链(不含点评)
  609. if (buttonType === "copyAllNot") {
  610. let postId = button.data("tiantengPostMessageId");
  611. let magnets = "";
  612. $(`[data-tianteng-button="copy"]`, $(`#${postId}`)).each(
  613. function () {
  614. let magnet = $(this).data("tiantengMagnet");
  615. magnets = magnets + toNormalMagnet(magnet) + "\n";
  616. }
  617. );
  618. GM.setClipboard(magnets, "text");
  619. return;
  620. }
  621. // 打开所有磁链(不含点评)
  622. if (buttonType === "clickAllNot") {
  623. let postId = button.data("tiantengPostMessageId");
  624. $(`[data-tianteng-button="copy"]`, $(`#${postId}`)).each(
  625. function () {
  626. let magnet = $(this).data("tiantengMagnet");
  627. magnet = toNormalMagnet(magnet);
  628. setTimeout(() => window.open(toNormalMagnet(magnet)), 500);
  629. }
  630. );
  631. return;
  632. }
  633. }
  634. ); // end 所有按钮事件
  635.  
  636. let magnetRegExp = getMagnetRegExp();
  637.  
  638. // 先处理a标签元素中的磁链,加上标记
  639. $(`div[id^="post_"] a[href^="magnet:?xt=urn:btih:"]`).each(
  640. function () {
  641. let magnetAlien = completeMagnet($(this).attr("href"));
  642. magnetAlien = toAlienMagnet(magnetAlien);
  643. // $(this).data('tiantengStatus','@');
  644. let html = this.outerHTML.replace(
  645. magnetRegExp,
  646. (match, offset, str) =>
  647. toAlienMagnet(completeMagnet(match), "@")
  648. );
  649.  
  650. html = html.replace("href", `data-tianteng-status="ok" href`);
  651.  
  652. html = `${html}
  653. <button style="margin:0;padding:3px;"
  654. class="jav-button tianteng-button"
  655. data-tianteng-button="copy"
  656. data-tianteng-magnet="${magnetAlien}"
  657. type="button">复制磁链
  658. </button>
  659. <button style="margin:0;padding:3px;"
  660. class="jav-button tianteng-button"
  661. data-tianteng-button="click"
  662. data-tianteng-magnet="${magnetAlien}"
  663. type="button">打开磁链
  664. </button>`;
  665. this.outerHTML = html;
  666. }
  667. );
  668. // 再处理所有文本节点,加上标记
  669. $('div[id^="post_"]').each(function () {
  670. const treeWalker = document.createTreeWalker(
  671. this,
  672. NodeFilter.SHOW_TEXT
  673. );
  674.  
  675. while (treeWalker.nextNode()) {
  676. const node = treeWalker.currentNode;
  677. if (node.nodeValue && magnetRegExp.test(node.nodeValue)) {
  678. node.nodeValue = node.nodeValue.replace(
  679. magnetRegExp,
  680. (match, offset, str) =>
  681. toAlienMagnet(completeMagnet(match), "tianteng")
  682. );
  683. }
  684. }
  685. });
  686.  
  687. // 去除标记
  688. $('div[id^="post_"]').each(function () {
  689. // 去除文本节点中磁链的标记
  690. let magnetAlienRegExp = getMagnetRegExp("tianteng");
  691. let html = this.innerHTML;
  692. html = html.replace(magnetAlienRegExp, function (match) {
  693. match = toNormalMagnet(match, "tianteng");
  694. let magnetAlien = toAlienMagnet(match);
  695. return `
  696. <a href="${match}" data-tianteng-status="ok">${match}</a>
  697. <button style="margin:0;padding:3px;"
  698. class="jav-button tianteng-button"
  699. data-tianteng-button="copy"
  700. data-tianteng-magnet="${magnetAlien}"
  701. type="button">复制磁链
  702. </button>
  703. <button style="margin:0;padding:3px;"
  704. class="jav-button tianteng-button"
  705. data-tianteng-button="click"
  706. data-tianteng-magnet="${magnetAlien}"
  707. type="button">打开磁链
  708. </button>`;
  709. });
  710. // 去除A标签中磁链的标记
  711. magnetAlienRegExp = getMagnetRegExp("@");
  712. html = html.replace(magnetAlienRegExp, function (match) {
  713. return toNormalMagnet(match, "@");
  714. });
  715.  
  716. this.innerHTML = html;
  717.  
  718. const postId = $(this).attr("id");
  719. const id = postId.replace("post_", "");
  720. const postMessageId = `postmessage_${id}`;
  721.  
  722. // 添加 4个 "所有" 按钮,在每个回复的开头和结尾,共8个
  723. if (
  724. $(`[data-tianteng-button="copy"]`, $(`#${postId}`)).length > 0
  725. ) {
  726. let allButtonHtml = `
  727. <button style="margin:0;padding:5px;"
  728. class="jav-button tianteng-button"
  729. data-tianteng-button="copyAll"
  730. data-tianteng-post-id="${postId}"
  731. data-tianteng-post-message-id="${postMessageId}"
  732. type="button">复制所有磁链
  733. </button>
  734. <button style="margin:0;padding:5px;"
  735. class="jav-button tianteng-button"
  736. data-tianteng-button="clickAll"
  737. data-tianteng-post-id="${postId}"
  738. data-tianteng-post-message-id="${postMessageId}"
  739. type="button">打开所有磁链
  740. </button>
  741. <button style="margin:0;padding:5px;margin-left:10px;"
  742. class="jav-button tianteng-button"
  743. data-tianteng-button="copyAllNot"
  744. data-tianteng-post-id="${postId}"
  745. data-tianteng-post-message-id="${postMessageId}"
  746. type="button">复制所有磁链(不含点评)
  747. </button>
  748. <button style="margin:0;padding:5px;"
  749. class="jav-button tianteng-button"
  750. data-tianteng-button="clickAllNot"
  751. data-tianteng-post-id="${postId}"
  752. data-tianteng-post-message-id="${postMessageId}"
  753. type="button">打开所有磁链(不含点评)
  754. </button><br>`;
  755. $(`#${postMessageId}`).prepend(allButtonHtml);
  756. $(`#${postMessageId}`).append(allButtonHtml);
  757. }
  758. });
  759.  
  760. } // end if 论坛明细页面
  761. } // end callback
  762. );
  763. ///////////////////////////////////////////////////////////////////////////
  764. // BTSOW https://btsow.motorcycles https://btsow.com
  765. ///////////////////////////////////////////////////////////////////////////
  766. execute("btsow", $('head>title:contains("BTSOW")'), () => {
  767. const $searchButton = $(
  768. "form.form-inline>div.input-group>span.input-group-btn"
  769. ),
  770. $searchInput = $(
  771. `form.form-inline>div.input-group>input[name="keyword"]`
  772. ),
  773. $pasteAndSearchButton = $(`
  774. <span class="input-group-btn">
  775. <button type="button" class="btn btn-default">
  776. <span class="glyphicon glyphicon-search" aria-hidden="true"></span>
  777. 粘贴&搜索
  778. </button>
  779. </span>`);
  780.  
  781. $searchButton.after($pasteAndSearchButton);
  782. $pasteAndSearchButton.click(() => {
  783. navigator.clipboard.readText().then((clipText) => {
  784. if (clipText != null && $.trim(clipText) != "") {
  785. $searchInput.val($.trim(clipText));
  786. document.querySelector("body > div.container > form").submit();
  787. }
  788. });
  789. });
  790. });
  791. ///////////////////////////////////////////////////////////////////////////
  792. // https://skrbtqx.top 永久地址: skrfabu.top skrso.link
  793. ///////////////////////////////////////////////////////////////////////////
  794. execute("skrbt", $(`head>link[rel='shortcut icon'][href*='skrbt']`), () => {
  795. const $searchButton = $("button.search-btn");
  796. const $searchInput = $(`input.search-input[name='keyword']`);
  797. const $pasteAndSearchButton = addPasteAndSearchButton(
  798. $searchButton,
  799. $searchInput
  800. );
  801. // 调整'粘贴&搜索'按钮样式
  802. $pasteAndSearchButton.removeAttr("style");
  803. $pasteAndSearchButton.css("margin-left", "3px");
  804. $pasteAndSearchButton.attr("class", $searchButton.attr("class"));
  805. // 删除广告
  806. function removeAd() {
  807. const $container = $(".col-md-6:eq(2)");
  808. $container.remove(".label.label-primary");
  809. $container
  810. .find('a.rrt.common-link[href^="http"]')
  811. .parent()
  812. .parent()
  813. .remove();
  814. }
  815. removeAd();
  816.  
  817. ///搜索结果列表页面
  818. if (location.href.includes("search")) {
  819. let buttonsHtml = `
  820. <span class="rrmiv"><button class="btn btn-danger copy" type="button">复制磁链</button></span>
  821. <span class="rrmiv"><button class="btn btn-danger click" type="button">点击磁链</button></span>`;
  822. addButtonsForSkrbt(buttonsHtml, $(".col-md-6:eq(2)"), (el) => {
  823. const classValue = $(el).attr("class");
  824. if (classValue && classValue.includes("copy")) {
  825. return "copy";
  826. }
  827. if (classValue && classValue.includes("click")) {
  828. return "click";
  829. }
  830. return "other";
  831. });
  832.  
  833. // 自动分页插件兼容,删除广告
  834. const nodeToObserve = document.querySelectorAll(".col-md-6")[2];
  835. new MutationObserver((mutationRecords, observer) => {
  836. $("a.rrt.common-link").each((index, el) => {
  837. if ($(el).parent().find(".btn.btn-danger.copy").length === 0) {
  838. $(el).after(buttonsHtml);
  839. }
  840. });
  841.  
  842. removeAd();
  843. }).observe(nodeToObserve, { childList: true });
  844. } // end if
  845. });
  846. ///////////////////////////////////////////////////////////////////////////
  847. // 知乎
  848. ///////////////////////////////////////////////////////////////////////////
  849. execute("知乎", /zhihu\.com/, () => {
  850. const searchButton = $(`button[class*="SearchBar-searchButton"]`);
  851. const $searchInput = $(`#Popover1-toggle`);
  852. addPasteAndSearchButton(searchButton, searchInput);
  853. });
  854. ///////////////////////////////////////////////////////////////////////////
  855. // 百度
  856. ///////////////////////////////////////////////////////////////////////////
  857. execute("百度", /baidu\.com/, () => {
  858. const $searchButton = $(`#su`);
  859. const $searchInput = $(`#kw`);
  860. addPasteAndSearchButton(searchButton, searchInput);
  861. });
  862. });
  863.  
  864. /////////////////////////////////////////////////////////////////////////////
  865. // 公共方法
  866. /////////////////////////////////////////////////////////////////////////////
  867.  
  868. function execute(title, condition, callback) {
  869. if (checkCondition(condition) === true) {
  870. if (callback) {
  871. debug(condition.toString(), title);
  872. callback(title, condition);
  873. }
  874. }
  875. }
  876.  
  877. /**
  878. *
  879. * @param {RegExp|Function|Boolean|String|jQuery} condition
  880. * @returns {Boolean}
  881. */
  882. function checkCondition(condition) {
  883. if ($.type(condition) === "regexp") {
  884. return condition.test(window.location.href);
  885. }
  886. if ($.isFunction(condition)) {
  887. return condition() === true;
  888. }
  889. if ($.type(condition) === "boolean") {
  890. return condition === true;
  891. }
  892. if ($.type(condition) === "string") {
  893. return document.querySelector(condition) != null;
  894. }
  895. if (condition instanceof jQuery) {
  896. return condition.length > 0;
  897. }
  898.  
  899. if ($.isArray(condition)) {
  900. for (let c of condition) {
  901. if (checkCondition(c)) {
  902. return true;
  903. }
  904. }
  905. }
  906. return false;
  907. }
  908.  
  909. function addPasteAndSearchButton($searchButton, $searchInput, callback) {
  910. const styleMap = { "margin-left": "5px" };
  911. $searchButton[0] &&
  912. $searchButton[0].computedStyleMap().forEach((value, key) => {
  913. styleMap[key] = value;
  914. });
  915. let $pasteAndSearchButton = $(
  916. `<input type="button" value="粘贴&搜索" id="pasteAndSearch"></input>`
  917. );
  918.  
  919. $pasteAndSearchButton.css(styleMap);
  920. $searchButton.after($pasteAndSearchButton);
  921. $pasteAndSearchButton.click(() => {
  922. navigator.clipboard.readText().then((clipText) => {
  923. if (clipText != null && $.trim(clipText) != "") {
  924. $searchInput.val($.trim(clipText));
  925. $searchButton.click();
  926. }
  927. });
  928. });
  929. callback && callback($searchButton, $searchInput, $pasteAndSearchButton);
  930. return $pasteAndSearchButton;
  931. }
  932.  
  933. function appendCopyButton(chePai, toAppendElement) {
  934. var copyButton = document.createElement("button");
  935. copyButton.innerHTML = "复 制";
  936. copyButton.setAttribute("id", "copyButton");
  937. toAppendElement.appendChild(copyButton);
  938. document.addEventListener("click", (e) => {
  939. if (e.target.getAttribute("id") === "copyButton") {
  940. GM.setClipboard(chePai, "text");
  941. }
  942. });
  943. }
  944.  
  945. function debug(str, title) {
  946. if (enableDebug) {
  947. if (!str) {
  948. str = "";
  949. }
  950. if (!Array.isArray(str)) {
  951. str = [str];
  952. }
  953. seq++;
  954. console.log(
  955. `%ctianteng ${GM_info.script.version}】 ${title ? title : "debug"}:`,
  956. "color: yellow;font-size: large;font-weight: bold;background-color: darkblue;",
  957. seq,
  958. ...str
  959. );
  960. }
  961. }
  962.  
  963. function isNativeCode(obj) {
  964. const nativeCodeTag = "[native code]";
  965. return obj && obj.toString && obj.toString().includes(nativeCodeTag);
  966. }
  967.  
  968. function getQueryVariable(anchor, variable) {
  969. var query = anchor.search.substring(1);
  970. var vars = query.split("&");
  971. for (var i = 0; i < vars.length; i++) {
  972. var pair = vars[i].split("=");
  973. if (pair[0] == variable) {
  974. return pair[1];
  975. }
  976. }
  977. return false;
  978. }
  979.  
  980. /**
  981. * 图片按宽高比例进行自动缩放
  982. * @param ImgObj
  983. * 缩放图片源对象
  984. * @param maxWidth
  985. * 允许缩放的最大宽度
  986. * @param maxHeight
  987. * 允许缩放的最大高度
  988. * @usage
  989. * 调用:<img src="图片" onload="javascript:drawImage(this,300,200)">
  990. */
  991. function drawImage(ImgObj, maxWidth, maxHeight) {
  992. var image = new Image();
  993. //原图片原始地址(用于获取原图片的真实宽高,当<img>标签指定了宽、高时不受影响)
  994. image.src = ImgObj.src;
  995. // 用于设定图片的宽度和高度
  996. var tempWidth;
  997. var tempHeight;
  998.  
  999. if (image.width > 0 && image.height > 0) {
  1000. //原图片宽高比例 大于 指定的宽高比例,这就说明了原图片的宽度必然 > 高度
  1001. if (image.width / image.height >= maxWidth / maxHeight) {
  1002. if (image.width > maxWidth) {
  1003. tempWidth = maxWidth;
  1004. // 按原图片的比例进行缩放
  1005. tempHeight = (image.height * maxWidth) / image.width;
  1006. } else {
  1007. // 按原图片的大小进行缩放
  1008. tempWidth = image.width;
  1009. tempHeight = image.height;
  1010. }
  1011. } else {
  1012. // 原图片的高度必然 > 宽度
  1013. if (image.height > maxHeight) {
  1014. tempHeight = maxHeight;
  1015. // 按原图片的比例进行缩放
  1016. tempWidth = (image.width * maxHeight) / image.height;
  1017. } else {
  1018. // 按原图片的大小进行缩放
  1019. tempWidth = image.width;
  1020. tempHeight = image.height;
  1021. }
  1022. }
  1023. // 设置页面图片的宽和高
  1024. ImgObj.height = tempHeight;
  1025. ImgObj.width = tempWidth;
  1026. // 提示图片的原来大小
  1027. ImgObj.alt = image.width + "×" + image.height;
  1028. }
  1029. }
  1030.  
  1031. /**
  1032. *
  1033. * @param {EventTarget|NodeList|Array|jQuery} elements
  1034. * @param {undefined|null|String|Array} events
  1035. */
  1036. function removeEvents(elements, events) {
  1037. if (!elements) return;
  1038. if (elements instanceof EventTarget) {
  1039. elements = [elements];
  1040. }
  1041. if (elements instanceof jQuery) {
  1042. elements = elements.toArray();
  1043. }
  1044.  
  1045. if (!events) {
  1046. elements.forEach((element) => {
  1047. for (let t in element) {
  1048. if (t.startsWith("on") && element[t] != null) {
  1049. element[t] = null;
  1050. console.log("cleanup removed listener from " + element.nodeName, t);
  1051. }
  1052. }
  1053. for (let t of element.allListeners || []) {
  1054. element.removeEventListener(t.type, t.callback, t.options);
  1055. console.log(
  1056. "cleanup removed listener from " + element.nodeName,
  1057. t.type
  1058. );
  1059. }
  1060. element.allListeners = [];
  1061. });
  1062. } else {
  1063. if (typeof events === "string") {
  1064. events = [events];
  1065. }
  1066. if (!Array.isArray(events)) {
  1067. return;
  1068. }
  1069. events.forEach((event) => {
  1070. const onEvent = "on" + event;
  1071. elements.forEach((element) => {
  1072. for (let t in element) {
  1073. if (t.startsWith(onEvent) && element[t] != null) {
  1074. element[t] = null;
  1075. console.log(
  1076. "cleanup removed listener from " + element.nodeName,
  1077. t
  1078. );
  1079. }
  1080. }
  1081. // const toRemoved = [];
  1082. element.allListeners = element.allListeners || [];
  1083. let allListenersNew;
  1084. element.allListeners.forEach((t, i) => {
  1085. if (t.type === event) {
  1086. element.removeEventListener(t.type, t.callback, t.options);
  1087. allListenersNew = element.allListeners.slice(i, 1);
  1088. // toRemoved.push(i);
  1089. console.log(
  1090. "cleanup removed listener from " + element.nodeName,
  1091. t.type
  1092. );
  1093. }
  1094. });
  1095. // toRemoved.forEach((item, index) => {
  1096. // element.allListeners = element.allListeners.slice(item, 1);
  1097. // });
  1098. if (allListenersNew) {
  1099. element.allListeners = allListenersNew;
  1100. }
  1101. });
  1102. });
  1103. }
  1104. }
  1105.  
  1106. function addButtonsForSkrbt(
  1107. buttonsHtml,
  1108. delegateElement,
  1109. buttonTypeCallback
  1110. ) {
  1111. delegateElement.find("a.rrt.common-link").after(buttonsHtml);
  1112.  
  1113. delegateElement.click((event) => {
  1114. const buttonType = buttonTypeCallback(event.target);
  1115. if ("copy" !== buttonType && "click" !== buttonType) {
  1116. return;
  1117. }
  1118. let liNode = $(event.target).parent().parent();
  1119.  
  1120. const exeButtonClick = () => {
  1121. if ("copy" === buttonType) {
  1122. navigator.clipboard.writeText(liNode.find(".magnet").attr("href"));
  1123. } else {
  1124. // liNode.find('.magnet').trigger('click'); //不好使
  1125. liNode.find(".magnet")[0].click();
  1126. }
  1127. };
  1128.  
  1129. if (liNode.find(".magnet").length != 0) {
  1130. // 磁链已经添加过
  1131. exeButtonClick();
  1132. return;
  1133. }
  1134. let detailUrl = liNode.find("a.rrt.common-link").attr("href");
  1135. detailUrl = `${skrbtUrl}${detailUrl}`;
  1136. $.get(detailUrl, function (data, textStatus, jqXHR) {
  1137. liNode.find("#errorTip").remove();
  1138. //成功后在页面添加磁链
  1139. const magnet = $(data).find("#magnet").attr("href");
  1140. if (magnet) {
  1141. const aHtml =
  1142. '<a class="magnet" href="' + magnet + '">' + magnet + "</a>";
  1143. liNode.append(aHtml);
  1144. exeButtonClick();
  1145. } else {
  1146. liNode.append(
  1147. '<span id="errorTip">1.获取磁链失败,等会儿再试一试! 若仍然有问题请刷新网页.</span>'
  1148. );
  1149. }
  1150. }).fail(function (e) {
  1151. //失败后在页面提示
  1152. liNode.append(
  1153. '<span id="errorTip">2.获取磁链失败,等会儿再试一试! 若仍然有问题请刷新网页.</span>'
  1154. );
  1155. console.log(e);
  1156. });
  1157. });
  1158. }
  1159. })();