tianteng

1. 绅士漫画,下拉浏览页面,由原先的一列模式改为两列模式 2. javbus, 添加 "粘贴并搜索" 按钮; 添加 "打开srbt" 链接; 详情页面添加复制车牌号按钮.

Fra 01.07.2024. Se den seneste versjonen.

You will need to install an extension such as Tampermonkey, Greasemonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Userscripts to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install a user script manager extension to install this script.

(I already have a user script manager, let me install it!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

// ==UserScript==
// @name         tianteng
// @namespace    https://greasyfork.org/xmlspy
// @version      0.5.0
// @description  1. 绅士漫画,下拉浏览页面,由原先的一列模式改为两列模式 2. javbus, 添加 "粘贴并搜索" 按钮; 添加 "打开srbt" 链接; 详情页面添加复制车牌号按钮.

// @author       xmlspy
// @license      MIT

// @require      https://cdn.jsdelivr.net/npm/[email protected]/dist/jquery.min.js

// @include      *
// @connect      *

// @run-at document-start

// @grant        GM_xmlhttpRequest
// @grant        GM.setClipboard
// @grant        GM.xmlhttpRequest
// @grant        unsafeWindow
// @grant        GM_log
// @grant        GM_info


// ==/UserScript==

(function () {
  "use strict";
  const enableDebug = true;
  let seq = 0;

  //////////////////////////////////////////////////////////////////////////////////////////////
  /////////////////// 事件拦截
  /////////////////////////////////////////////////////////////////////////////////////////////
  debug(document.querySelector("title"));
  //松鼠症倉庫 地址发布页 https://ahrilist.top/
  const ep = EventTarget.prototype;
  if (ep.addEventListenerOriginal == null) {
    ep.addEventListenerOriginal = ep.addEventListener;
    function addEventListenerHook(type, callback, options) {
      // if (/ahri8\.top/.test(window.location.href)) {
      if (this.className && this.className.includes("apo")) {
        debug("松鼠症倉庫-禁止点击广告");
        return;
      }
      // }
      this.allListeners = this.allListeners || [];
      this.allListeners.push({ type, callback, options });
      this.addEventListenerOriginal(type, callback, options);
    }
    ep.addEventListener = addEventListenerHook;
  }

  const skrbtDomain = "skrbtqx";
  const skrbtHost = skrbtDomain + ".top";
  const skrbtUrl = "https://" + skrbtHost;

  // execute(()=>{},()=>{});

  $(function () {
    // execute("松鼠症倉庫", /ahri8\.top/, () => {
    //   removeEvents(document.querySelectorAll("a.apo"), "click");

    //   debug("-------------------------------------------------------xxxx");
    // });
    execute("开源中国", /oschina\.net(\/)?$/, () => {
      $("div.headline > div.head-news > div").each(function (index) {
        const $this = $(this);
        const href = $this.attr("data-href");
        const classCss = $this.attr("class");
        const title = $this.attr("title");
        const html = `<a target="_blank" title="${title}" href="${href}" class="${classCss}">${title}</a>`;
        $this.replaceWith(html);
      });
    });
    //////////////////////////////////////////////////////////////////////////////////////////////
    /////////////////// 紳士漫畫永久域名: wnacg.com 紳士漫畫永久地址發佈頁: wnacg.date
    /////////////////////////////////////////////////////////////////////////////////////////////
    execute("紳士漫畫", '$head>title:contains("紳士漫畫")', () => {
      if (location.href.includes("photos-slide-aid")) {
        const nodeToObserve = document.querySelector("#img_list");
        $(nodeToObserve).css({
          width: "100%",
          display: "flex",
          "flex-wrap": "wrap",
          "justify-content": "flex-start",
          "overflow-x": "hidden",
        });
        const imgWidth = document.documentElement.clientWidth / 2 - 10;
        const imgHeight = document.documentElement.clientHeight - 50;
        const observer = new MutationObserver((mutations, observer) => {
          $("#img_list>div").css({
            flex: "1",
            "background-color": "#cacaca",
            margin: "0 5px 5px 0",
            width: "calc((100% - 10px) / 2)",
            "min-width": "calc((100% - 10px) / 2)",
            "max-width": "calc((100% - 10px) / 2)",
          });
          $("#img_list>div>img").on("load", (e) => {
            drawImage(e.target, imgWidth, imgHeight);
          });
        });
        observer.observe(nodeToObserve, { childList: true });
      }
    });

    //////////////////////////////////////////////////////////////////////////////////////////////
    // 永久域名:https://www.javbus.com 防屏蔽地址:https://www.fanbus.help
    // 防屏蔽地址:https://www.javsee.help 防屏蔽地址:https://www.buscdn.help
    /////////////////////////////////////////////////////////////////////////////////////////////
    execute(
      "javbus",
      [
        '$head>title:contains("JavBus")',
        // /genre/hd , /genre/sub
        "$body > nav > div > div.navbar-header.mh50 > a > img[alt='JavBus']",
        // 论坛
        "#toptb.jav-nav",
      ],
      () => {
        const searchButton = $(
          "button[onclick=\"searchs('search-input')\"]:first"
        );
        const searchInput = $("#search-input:first");
        addPasteAndSearchButton(searchButton, searchInput);

        // 调整样式
        $(".nav>li>a").attr("style", "padding-left:8px;padding-right:8px;");

        //添加skrbt链接
        $(".nav-title.nav-inactive:last,ul.nav.navbar-nav:first").append(`
                      <li class="hidden-md hidden-sm">
                          <a href="${skrbtUrl}" target="_blank">打开skrbt</a>
                      </li>
                  `);

        let chePaiNode = document.querySelector(
          "body > div.container > div.row.movie > div.col-md-3.info > p:nth-child(1) > span:nth-child(2)"
        );
        // 明细页面
        if (chePaiNode) {
          const chePai = chePaiNode.innerText.trim();
          const toAppendElement = document.querySelector(
            "body > div.container > div.row.movie > div.col-md-3.info > p:nth-child(1)"
          );

          appendCopyButton(chePai, toAppendElement);
          // 删除磁力链接中的onclick事件
          setInterval(() => $("#magnet-table td").removeAttr("onclick"), 1000);
        }
      }
    );

    //////////////////////////////////////////////////////////////////////////////////////////////
    /////////////////// 添加 粘贴&搜索 按钮
    /////////////////////////////////////////////////////////////////////////////////////////////
    [
      // 知乎
      {
        title: "知乎-添加'粘贴&搜索'按钮",
        condition: /zhihu\.com/,
        searchButton: '$button[class*="SearchBar-searchButton"]',
        searchInput: "#Popover1-toggle",
      },
      // skrbt 永 久 地 址 ( 务 必 收 藏 ): skrfabu.top skrso.link
      {
        title: "skrbt-添加'粘贴&搜索'按钮",
        condition: `$head>link[rel='shortcut icon'][href*='skrbt']`,
        searchButton: `$button.search-btn`,
        searchInput: `$input.search-input[name='keyword']`,
      },
      // 百度
      {
        title: "百度-添加'粘贴&搜索'按钮",
        condition: /baidu\.com/,
        searchButton: `#su`,
        searchInput: `#kw`,
      },
      // 必应
      // {
      //   condition: /bing\.com/,
      //   searchButton: ()=>{
      //     let inputs = document.querySelectorAll('input');
      //     return inputs[1];
      //   },
      //   searchInput: `#sb_form_q`,
      // },
    ].forEach((v, k) => {
      let { title, condition, searchButton, searchInput, callback } = v;
      execute(title, condition, () => {
        searchButton = evalParam(searchButton);
        searchInput = evalParam(searchInput);
        addPasteAndSearchButton(searchButton, searchInput, callback);
      });
    });
  });
  //////////////////////////////////////////////////////////////////////////////////////////////
  /////////////////// 公共方法
  /////////////////////////////////////////////////////////////////////////////////////////////

  /**
   *
   * @param {String|Function} param
   * 当类型为String时,
   *  - 如果param是以$开头,则认为这个param为Jquery表达式,会去掉字符$,并返回;
   *  - 否则,认为param为常规css选择符,会返回document.querySelector(param)
   * 当类型为Function时,
   *  直接执行此方法,并使用$()包装并返回
   *
   * @returns {Jquery} 返回Jquery对象
   *
   * @example
   * - evalParam('$div[style="btn"]'); // param为jquery的css selector,返回$('div[style="btn"]')
   * - evalParam('#container'); // param为常规的css selector,返回 $(document.querySelecotr('#container'))
   * - evalParam(()=>{
   *     return document.querySelector('#container');
   *   });  // param为方法,返回$(param())
   *
   */
  function evalParam(param) {
    if ($.type(param) === "string") {
      if (param.startsWith("$")) {
        return $(param.substring(1));
      }
      return $(document.querySelector(param));
    }
    if ($.isFunction(param)) {
      return $(param());
    }
  }

  function execute(title, condition, callback) {
    if (checkCondition(condition) === true) {
      if (callback) {
        debug(condition.toString(), title);
        callback();
      }
    }
    // if ($.isArray(condition)) {
    //   for (let c of condition) {
    //     if (checkCondition(c)) {
    //       debug(condition.toString(), title);
    //       callback && callback();
    //       return;
    //     }
    //   }
    // }
  }

  /**
   *
   * @param {RegExp|Function|Boolean|String} condition
   * @returns {Boolean}
   */
  function checkCondition(condition) {
    if ($.type(condition) === "regexp") {
      const href = window.location.href;
      return condition.test(href);
    }
    if ($.isFunction(condition)) {
      return condition() === true;
    }
    if ($.type(condition) === "boolean") {
      return condition === true;
    }
    if ($.type(condition) === "string") {
      if (condition.startsWith("$")) {
        return $(condition.substring(1)).length > 0;
      }
      return document.querySelector(condition) != null;
    }

    if ($.isArray(condition)) {
      for (let c of condition) {
        if (checkCondition(c)) {
          return true;
        }
      }
    }
    return false;
  }

  function addPasteAndSearchButton($searchButton, $searchInput, callback) {
    const styleMap = {};
    $searchButton[0].computedStyleMap().forEach((value, key) => {
      styleMap[key] = value;
    });
    const $pasteAndSearchButton = $(
      `<input type="button" value="粘贴&搜索" id="pasteAndSearch"></input>`
    );
    $pasteAndSearchButton.css(styleMap);
    $searchButton.after($pasteAndSearchButton);
    $pasteAndSearchButton.click(() => {
      navigator.clipboard.readText().then((clipText) => {
        if (clipText != null && $.trim(clipText) != "") {
          $searchInput.val($.trim(clipText));
          $searchButton.click();
        }
      });
    });
    callback && callback($searchButton, $searchInput, $pasteAndSearchButton);
  }

  function appendCopyButton(chePai, toAppendElement) {
    var copyButton = document.createElement("button");
    copyButton.innerHTML = "复 制";
    copyButton.setAttribute("id", "copyButton");
    toAppendElement.appendChild(copyButton);
    document.addEventListener("click", (e) => {
      if (e.target.getAttribute("id") === "copyButton") {
        GM.setClipboard(chePai, "text");
      }
    });
  }

  function debug(str, title) {
    if (enableDebug) {
      if (!str) {
        str = "";
      }
      if (!Array.isArray(str)) {
        str = [str];
      }
      seq++;
      console.log(
        `%c【tianteng ${GM_info.script.version}】 ${title ? title : "debug"}:`,
        "color: yellow;font-size: large;font-weight: bold;background-color: darkblue;",
        seq,
        ...str
      );
    }
  }

  /**
   * 图片按宽高比例进行自动缩放
   * @param ImgObj
   *     缩放图片源对象
   * @param maxWidth
   *     允许缩放的最大宽度
   * @param maxHeight
   *     允许缩放的最大高度
   * @usage
   *     调用:<img src="图片" onload="javascript:drawImage(this,300,200)">
   */
  function drawImage(ImgObj, maxWidth, maxHeight) {
    var image = new Image();
    //原图片原始地址(用于获取原图片的真实宽高,当<img>标签指定了宽、高时不受影响)
    image.src = ImgObj.src;
    // 用于设定图片的宽度和高度
    var tempWidth;
    var tempHeight;

    if (image.width > 0 && image.height > 0) {
      //原图片宽高比例 大于 指定的宽高比例,这就说明了原图片的宽度必然 > 高度
      if (image.width / image.height >= maxWidth / maxHeight) {
        if (image.width > maxWidth) {
          tempWidth = maxWidth;
          // 按原图片的比例进行缩放
          tempHeight = (image.height * maxWidth) / image.width;
        } else {
          // 按原图片的大小进行缩放
          tempWidth = image.width;
          tempHeight = image.height;
        }
      } else {
        // 原图片的高度必然 > 宽度
        if (image.height > maxHeight) {
          tempHeight = maxHeight;
          // 按原图片的比例进行缩放
          tempWidth = (image.width * maxHeight) / image.height;
        } else {
          // 按原图片的大小进行缩放
          tempWidth = image.width;
          tempHeight = image.height;
        }
      }
      // 设置页面图片的宽和高
      ImgObj.height = tempHeight;
      ImgObj.width = tempWidth;
      // 提示图片的原来大小
      ImgObj.alt = image.width + "×" + image.height;
    }
  }

  /**
   *
   * @param {EventTarget|NodeList|Array|jQuery} elements
   * @param {undefined|null|String|Array} events
   */
  function removeEvents(elements, events) {
    if (!elements) return;
    if (elements instanceof EventTarget) {
      elements = [elements];
    }
    if (elements instanceof jQuery) {
      elements = elements.toArray();
    }

    if (!events) {
      elements.forEach((element) => {
        for (let t in element) {
          if (t.startsWith("on") && element[t] != null) {
            element[t] = null;
            console.log("cleanup removed listener from " + element.nodeName, t);
          }
        }
        for (let t of element.allListeners || []) {
          element.removeEventListener(t.type, t.callback, t.options);
          console.log(
            "cleanup removed listener from " + element.nodeName,
            t.type
          );
        }
        element.allListeners = [];
      });
    } else {
      if (typeof events === "string") {
        events = [events];
      }
      if (!Array.isArray(events)) {
        return;
      }
      events.forEach((event) => {
        const onEvent = "on" + event;
        elements.forEach((element) => {
          for (let t in element) {
            if (t.startsWith(onEvent) && element[t] != null) {
              element[t] = null;
              console.log(
                "cleanup removed listener from " + element.nodeName,
                t
              );
            }
          }
          // const toRemoved = [];
          element.allListeners = element.allListeners || [];
          let allListenersNew;
          element.allListeners.forEach((t, i) => {
            if (t.type === event) {
              element.removeEventListener(t.type, t.callback, t.options);
              allListenersNew = element.allListeners.slice(i, 1);
              // toRemoved.push(i);
              console.log(
                "cleanup removed listener from " + element.nodeName,
                t.type
              );
            }
          });
          // toRemoved.forEach((item, index) => {
          //   element.allListeners = element.allListeners.slice(item, 1);
          // });
          if (allListenersNew) {
            element.allListeners = allListenersNew;
          }
        });
      });
    }
  }
})();