Greasy Fork

Greasy Fork is available in English.

优雅的广告拦截脚本

abp规则转换js脚本

当前为 2022-08-20 提交的版本,查看 最新版本

// ==UserScript==
// @name 优雅的广告拦截脚本
// @author 酷安@耗子Sky
// @description abp规则转换js脚本
// @version 4.0
// @match *://*/*
// @grant GM_setValue
// @grant GM_getValue
// @grant GM_registerMenuCommand
// @grant GM_unregisterMenuCommand
// @grant GM_xmlhttpRequest
// @grant GM_addStyle
// @run-at document-start
// @connect code.gitlink.org.cn
// @namespace http://greasyfork.icu/users/452911
// ==/UserScript==

(function () {
  let rules = `
! 没有两个 # 的行和 开头为 ! 的行会忽略
! baidu.com##.ec_wise_ad
!
! :remove() 会用 js 移除元素,:remove() 必须放在行尾
! baidu.com###ad:remove()
! :click() 会用 js 模拟点击元素,必须放在行尾
! baidu.com###btn:click()
! 上面两个可以带参数,格式
! remove(100, 4, 200)
! 代表 首先延时 100 ms,然后执行 4 次,两次间隔 200 ms
!
! 由于语法限制,一个反斜杠需要改成两个,像这样 \\ 
!
! 脚本会首先尝试从下面的地址数组获取规则
! 获取到的规则将会与内置规则合并
! 所有规则获取完毕以后才会应用规则
!
! 若要修改地址,请注意同步修改头部的 @connect 的域名
`,
      ruleUrls = [
          "https://code.gitlink.org.cn/damengzhu/banad/raw/branch/main/jiekouAD.txt",
          "https://code.gitlink.org.cn/damengzhu/abpmerge/raw/branch/main/abpmerge.txt",
      ],
      selarray = [],
      welarray = [],
      seloarray = [],
      menuNum = null,
      disaKey = "ajs_disabled_domains",
      rulesKey = "ajs_saved_rules",
      savedRules = GM_getValue(rulesKey, undefined),
      disas = GM_getValue(disaKey, "").split(","),
      disa = disas.includes(location.hostname);

  function gmMenuMgmt(disabled) {
      if (menuNum) {
          GM_unregisterMenuCommand(menuNum);
      }
      menuNum = GM_registerMenuCommand(
          disabled ? "在此网站启用拦截" : "在此网站禁用拦截",
          gmValuesMgmt.bind(this, !disabled)
      );
  }

  function gmValuesMgmt(add) {
      if (add) {
          if (!disas.includes(location.hostname)) {
              disas.push(location.hostname);
          }
          GM_setValue(disaKey, disas.join(","));
          disas = GM_getValue(disaKey, "").split(",");
          gmMenuMgmt(true);
      } else {
          if (disas.includes(location.hostname)) {
              disas.splice(disas.indexOf(location.hostname), 1);
          }
          GM_setValue(disaKey, disas.join(","));
          disas = GM_getValue(disaKey, "").split(",");
          gmMenuMgmt(false);
      }
  }

  function execOperation(sel, param, click) {
      setTimeout(() => {
          for (let c = parseInt(param[1]); c >= 1; --c) {
              setTimeout(() => {
                  document
                      .querySelectorAll(sel)
                      .forEach((a) => (click ? a.click() : a.remove()));
              }, parseInt(param[2]) * (c - 1));
          }
      }, parseInt(param[0]));
  }
  function pushOperation(sel, op, type) {
      let tempParamArray = ["0", "1", "0"];
      if (sel.split(op)[1].indexOf(",") > 0) {
          tempParamArray = sel.split(op)[1].slice(0, -1).split(",");
      }
      seloarray.push({
          sel: sel.split(op)[0],
          type: type,
          param: tempParamArray,
      });
  }
  function parseFunc(sel) {
      if (sel.indexOf(":remove(") > 0) {
          pushOperation(sel, ":remove(", 1);
      } else if (sel.indexOf(":click(") > 0) {
          pushOperation(sel, ":click(", 2);
      } else {
          seloarray.push({ sel: sel, type: 0 });
      }
  }
  function parseDomains(rule, sep) {
      let domains = rule.split(sep)[0].split(","),
          selector = rule.split(sep)[1];
      domains.forEach((domain) => {
          if (domain.slice(0, 1) == "~") {
              if (location.hostname.indexOf(domain.slice(1)) >= 0) return;
          } else {
              if (location.hostname.indexOf(domain) < 0 && domain !== "*") return;
          }
          if (sep == "#@#") {
              welarray.push(selector);
          } else {
              selarray.push(selector);
          }
      });
  }
  function fetchRules(first, callback) {
      savedRules = "";
      new Promise((resolve) => {
          let count = 0,
              append = (text) => {
                  if (text) savedRules += `\n${text}\n`;
                  count++;
                  if (count >= ruleUrls.length) {
                      GM_setValue(rulesKey, savedRules);
                      if (first) rules += savedRules;
                      resolve();
                  }
              };

          ruleUrls.forEach((url) => {
              GM_xmlhttpRequest({
                  url: url,
                  onload: (r) => {
                      append(r.responseText);
                  },
                  onabort: append.bind(this),
                  onerror: append.bind(this),
                  ontimeout: append.bind(this),
              });
          });
      }).then(callback);
  }
  function myfun(update) {
      let styelem = document.createElement("style");
      gmMenuMgmt(disa);

      rules.split("\n").forEach((rule) => {
          if (rule.indexOf("!") == 0) {
              return;
          } else if (rule.indexOf("[") == 0) {
              return;
          } else if (rule.indexOf("##+js") >= 0) {
              return;
          } else if (rule.indexOf("##^") >= 0) {
              return;
          } else if (rule.indexOf("#@#") > 0) {
              parseDomains(rule, "#@#");
          } else if (rule.indexOf("#@#") == 0) {
              welarray.push(rule.slice(3));
          } else if (rule.indexOf("##") > 0) {
              parseDomains(rule, "##");
          } else if (rule.indexOf("##") == 0) {
              selarray.push(rule.slice(2));
          }
      });

      selarray.forEach((sel) => {
          if (!welarray.includes(sel)) parseFunc(sel);
      });

      document.documentElement.appendChild(styelem);
      let csel = "";
      seloarray.forEach((selo) => {
          switch (selo.type) {
              case 0:
                  csel += `,${selo.sel}`;
                  break;
              case 1:
                  execOperation(selo.sel, selo.param, 0);
                  break;
              case 2:
                  execOperation(selo.sel, selo.param, 1);
                  break;
          }
      });
      if (csel.length >= 2) {
          let crule = csel.slice(1) + " {display: none !important;}";
          styelem.textContent = crule;
          let astyelem = GM_addStyle(crule);

          GM_registerMenuCommand(
              `此页面应用了 ${csel.slice(1).split(',').length} 项 CSS 规则`,
              () => {
                  let test = prompt('测试规则,不要带域名,不支持排除,不会保存,刷新失效');
                  if(test && test.length>0){
                      if (test.slice(0,2)=='##') test = test.slice(2);
                      test += " {display: none !important;}";
                      if (astyelem) astyelem.textContent += test;
                      styelem.textContent += test;
                  }
              }
          );
      }

      if (update) {
          fetchRules(false, () => null);
      }
  }

  gmMenuMgmt(disa);
  if (disa) return;

  if (typeof savedRules !== "string") {
      fetchRules(true, myfun.bind(this, false));
  } else {
      rules += savedRules;
      myfun(true);
  }
})();