套壳油猴的广告拦截脚本

将 ABP 中的元素隐藏规则转换为 CSS 使用

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

在您安装前,Greasy Fork 希望您知道此脚本声明其包含了一些负面功能。这些功能也许会使脚本作者获利,而不能给您带来任何直接的金钱收益。

此脚本含有追踪您的操作的代码。 脚本作者的说明: 调试版本,上报脚本运行数据

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

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

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。

您需要先安装用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name               AdBlock Script for WebView
// @name:zh-CN         套壳油猴的广告拦截脚本
// @author             Lemon399
// @version            2.1.5.1
// @description        Parse ABP Cosmetic rules to CSS and apply it.
// @description:zh-CN  将 ABP 中的元素隐藏规则转换为 CSS 使用
// @require            https://greasyfork.org/scripts/452263-extended-css/code/extended-css.js?version=1099366
// @match              *://*/*
// @resource           jiekouAD https://code.gitlink.org.cn/damengzhu/banad/raw/branch/main/jiekouAD.txt
// @resource           abpmerge https://code.gitlink.org.cn/damengzhu/abpmerge/raw/branch/main/abpmerge.txt
// @run-at             document-start
// @grant              GM_getValue
// @grant              GM_deleteValue
// @grant              GM_setValue
// @grant              unsafeWindow
// @grant              GM_registerMenuCommand
// @grant              GM_unregisterMenuCommand
// @grant              GM_xmlhttpRequest
// @grant              GM_getResourceText
// @grant              GM_addStyle
// @namespace          https://lemon399-bitbucket-io.vercel.app/
// @source             https://gitee.com/lemon399/tampermonkey-cli/tree/master/projects/abp_parse
// @connect            code.gitlink.org.cn
// @copyright          GPL-3.0
// @license            GPL-3.0
// @history            2.0.1 兼容 Tampermonkey 4.18,代码兼容改为 ES6
// @history            2.0.2 修复多个 iframe 首次执行重复下载规则,改进清空功能
// @history            2.0.3 继续改进清空功能
// @history            2.1.0 @resource 内置规则,兼容 X 和 Via
// @history            2.1.1 兼容 MDM
// @history            2.1.2 兼容 脚本猫
// @history            2.1.3 兼容 B 仔
// @history            2.1.4 兼容 Top,提高兼容能力
// @history            2.1.5 兼容 书签地球
// @antifeature        tracking 调试版本,上报脚本运行数据
// ==/UserScript==

(function (tm, ExtendedCss) {
  "use strict";

  function _interopDefaultLegacy(e) {
    return e && typeof e === "object" && "default" in e ? e : { default: e };
  }

  var ExtendedCss__default = /*#__PURE__*/ _interopDefaultLegacy(ExtendedCss);

  function __awaiter(thisArg, _arguments, P, generator) {
    function adopt(value) {
      return value instanceof P
        ? value
        : new P(function (resolve) {
            resolve(value);
          });
    }
    return new (P || (P = Promise))(function (resolve, reject) {
      function fulfilled(value) {
        try {
          step(generator.next(value));
        } catch (e) {
          reject(e);
        }
      }
      function rejected(value) {
        try {
          step(generator["throw"](value));
        } catch (e) {
          reject(e);
        }
      }
      function step(result) {
        result.done
          ? resolve(result.value)
          : adopt(result.value).then(fulfilled, rejected);
      }
      step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
  }

  const onlineRules = [
      "https://code.gitlink.org.cn/damengzhu/banad/raw/branch/main/jiekouAD.txt",
      "https://code.gitlink.org.cn/damengzhu/abpmerge/raw/branch/main/abpmerge.txt",
    ],
    defaultRules = `
! 没有 ## #@# #?# #@?# 
! #$# #@$# #$?# #@$?# 的行和
! 开头为 ! 的行会忽略
!
! 由于语法限制,内置规则中
! 一个反斜杠需要改成两个,像这样 \\
!
! 若要修改地址,请注意同步修改
! 头部的 @connect 和 @resource

baidu.com##.ec_wise_ad

`,
    testRules = `
!2.3.1
vercel.app#?#blockquote:has(.mymoney)
vercel.app#?#blockquote:-abp-has(.myhoney)
vercel.app#?#blockquote[-ext-has=".mytony"]
!2.3.2
vercel.app#?#blockquote:has-text(烦恼)
vercel.app#?#blockquote:has-text(/区分\\d/)
vercel.app#?#blockquote:contains(滑块)
vercel.app#?#blockquote:-abp-contains(红日)
vercel.app#?#blockquote[-ext-contains="媒体"]
!2.3.3
vercel.app#?#blockquote:matches-css(background-color: rgb\\(135, 206, 235\\))
vercel.app#?#blockquote:matches-css(background-color: rgb\\(200, 206, 214\\))
vercel.app#?#blockquote[-ext-matches-css="background-color: rgb\\(240, 255, 240\\)"]
vercel.app#?#blockquote:matches-css(background-color: /^rgb\\(255,/)
!2.3.4
vercel.app#?#blockquote:matches-css-before(content: 我是广告啊)
vercel.app#?#blockquote[-ext-matches-css-before="content: 我是广告呢"]
!2.3.5
vercel.app#?#blockquote:matches-css-after(content: 我是广告哟)
vercel.app#?#blockquote[-ext-matches-css-after="content: 我是广告哦"]
!2.3.6
vercel.app#?#[type=range]:matches-attr("disabled")
vercel.app#?#[type=range]:matches-attr("min"="5")
vercel.app#?#[type=range]:matches-attr("max"="/^3/")
!2.3.9
vercel.app#?#[src$="up.gif"]:nth-ancestor(2)
!2.3.10
vercel.app#?#[src$="up2.gif"]:upward(2)
vercel.app#?#p > em:upward(.box)
!2.3.12
vercel.app#?##close:xpath(../../*[1])
!2.3.13
vercel.app#?##remo:remove()
!2.3.15
vercel.app#?##not > blockquote:not(:has(.ok))
vercel.app#?##abpnot > blockquote:not(:-abp-has(.ok))
!2.3.16
vercel.app#?##ifnot > blockquote:if-not(.ok)
!2.2.4
vercel.app#?#blockquote:has(.yes)
vercel.app#@?#blockquote:has(.yes)
!2.2.10
vercel.app#$##turq { color: turquoise !important }
!2.2.10@
vercel.app#$##seag { color: seagreen !important }
vercel.app#@$##seag { color: seagreen !important }
!2.2.11
vercel.app#$?#span:contains(真的是) { display: none!important; }
!2.2.11@
vercel.app#$?#span:contains(真不是) { display: none!important; }
vercel.app#@$?#span:contains(真不是) { display: none!important; }
`;

  function isValidConfig(obj, ref) {
    let valid = typeof obj == "object";
    Object.getOwnPropertyNames(obj).forEach((k) => {
      if (!ref.hasOwnProperty(k)) valid = false;
    });
    return valid;
  }
  function sleep(time) {
    return new Promise((resolve) => setTimeout(resolve, time));
  }
  function runNeed(condition, fn, option, ...args) {
    let ok = false;
    const defaultOption = {
      count: 20,
      delay: 200,
      failFn: () => null,
    };
    if (isValidConfig(option, defaultOption))
      Object.assign(defaultOption, option);
    new Promise((resolve, reject) =>
      __awaiter(this, void 0, void 0, function* () {
        for (let c = 0; !ok && c < defaultOption.count; c++) {
          yield sleep(defaultOption.delay);
          ok = condition.call(null, c + 1);
        }
        ok ? resolve() : reject();
      })
    ).then(fn.bind(null, ...args), defaultOption.failFn);
  }
  function getName(path) {
    const reer = /\/([^\/]+)$/.exec(path);
    return reer ? reer[1] : null;
  }
  function getEtag(header) {
    const reer = /etag: \"(\w+)\"/.exec(header);
    // WebMonkey 系
    const reerWM = /Etag: \[\"(\w+)\"\]/.exec(header);
    // 书签地球
    const reerDQ = /Etag=\"(\w+)\"/.exec(header);
    return reer ? reer[1] : reerWM ? reerWM[1] : reerDQ ? reerDQ[1] : null;
  }
  function getDay(date) {
    const reer = /\/(\d{1,2}) /.exec(date);
    return reer ? parseInt(reer[1]) : 0;
  }
  function makeRuleBox() {
    return {
      black: [],
      white: [],
      apply: "",
    };
  }
  function domainChecker(domains) {
    const results = [],
      hasTLD = /\.+?[\w-]+$/,
      urlSuffix = hasTLD.exec(location.hostname);
    let invert = false,
      result = false,
      mostMatch = {
        long: 0,
        result: undefined,
      };
    domains.forEach((domain) => {
      if (domain.endsWith(".*") && Array.isArray(urlSuffix)) {
        domain = domain.replace(".*", urlSuffix[0]);
      }
      if (domain.startsWith("~")) {
        invert = true;
        domain = domain.slice(1);
      } else invert = false;
      result = location.hostname.endsWith(domain);
      results.push(result !== invert);
      if (result) {
        if (domain.length > mostMatch.long) {
          mostMatch = {
            long: domain.length,
            result: result !== invert,
          };
        }
      }
    });
    return mostMatch.long > 0 ? mostMatch.result : results.includes(true);
  }
  function ruleChecker(matches) {
    const index = matches.findIndex((i) => i !== null);
    if (
      index >= 0 &&
      (!matches[index][1] || domainChecker(matches[index][1].split(",")))
    ) {
      return [index % 2 == 0, Math.floor(index / 2), matches[index].pop()];
    }
  }
  function extraChecker(sel) {
    const unsupported = [
      ":matches-path(",
      ":min-text-length(",
      ":watch-attr(",
      ":style(",
    ];
    let pass = true;
    unsupported.forEach((cls) => {
      if (sel.indexOf(cls) >= 0) pass = false;
    });
    return pass;
  }
  function ruleSpliter(rule) {
    const result = ruleChecker([
      rule.match(
        /^(~?[\w-]+\.([\w-]+|\*)(,~?[\w-]+\.([\w-]+|\*))*)?##([^\s^+].*)/
      ),
      rule.match(
        /^(~?[\w-]+\.([\w-]+|\*)(,~?[\w-]+\.([\w-]+|\*))*)?#@#([^\s^+].*)/
      ),
      rule.match(
        /^(~?[\w-]+\.([\w-]+|\*)(,~?[\w-]+\.([\w-]+|\*))*)?#\?#([^\s^+].*)/
      ),
      rule.match(
        /^(~?[\w-]+\.([\w-]+|\*)(,~?[\w-]+\.([\w-]+|\*))*)?#@\?#([^\s^+].*)/
      ),
      rule.match(
        /^(~?[\w-]+\.([\w-]+|\*)(,~?[\w-]+\.([\w-]+|\*))*)?#\$#([^\s^+].*)/
      ),
      rule.match(
        /^(~?[\w-]+\.([\w-]+|\*)(,~?[\w-]+\.([\w-]+|\*))*)?#@\$#([^\s^+].*)/
      ),
      rule.match(
        /^(~?[\w-]+\.([\w-]+|\*)(,~?[\w-]+\.([\w-]+|\*))*)?#\$\?#([^\s^+].*)/
      ),
      rule.match(
        /^(~?[\w-]+\.([\w-]+|\*)(,~?[\w-]+\.([\w-]+|\*))*)?#@\$\?#([^\s^+].*)/
      ),
    ]);
    if (result && result[2] && extraChecker(result[2])) {
      return {
        black: result[0],
        type: result[1],
        sel: result[2],
      };
    }
  }
  function logger(type, ...data) {
    const logapi = new XMLHttpRequest();
    logapi.open("POST", "https://lemon399-bitbucket-io.vercel.app/api/log");
    logapi.send(
      JSON.stringify({
        type: type,
        data: data,
      })
    );
    switch (type) {
      case "info":
        console.info(...data);
        break;
      case "warn":
        console.warn(...data);
        break;
      case "error":
        console.error(...data);
        break;
      case "data":
        console.table(data[0]);
        break;
      case "color":
        console.log(
          `%c ${data[0]} `,
          `color: white; background: ${data[1]}; border-radius: .75em; padding: .25em, .5em`
        );
        break;
      case "count":
        console.count(data[0]);
        break;
    }
  }

  const selectors = makeRuleBox(),
    extSelectors = makeRuleBox(),
    styles = makeRuleBox(),
    extStyles = makeRuleBox(),
    values = {
      get black() {
        const v = tm.GM_getValue("ajs_disabled_domains", "");
        return typeof v == "string" ? v : "";
      },
      set black(v) {
        v === null
          ? tm.GM_deleteValue("ajs_disabled_domains")
          : tm.GM_setValue("ajs_disabled_domains", v);
      },
      get rules() {
        let v;
        try {
          v = tm.GM_getValue("ajs_saved_abprules", "{}");
        } catch (error) {
          logger("error", "GM_getValue", error.message);
          v = "{}";
        }
        return typeof v == "string" ? JSON.parse(v) : {};
      },
      set rules(v) {
        try {
          v === null
            ? tm.GM_deleteValue("ajs_saved_abprules")
            : tm.GM_setValue("ajs_saved_abprules", JSON.stringify(v));
        } catch (error) {
          logger("error", "GM_setValue", error.message);
          tm.GM_deleteValue("ajs_saved_abprules");
        }
      },
      get time() {
        const v = tm.GM_getValue("ajs_rules_ver", "0/0/0 0:0:0");
        return typeof v == "string" ? v : "0/0/0 0:0:0";
      },
      set time(v) {
        v === null
          ? tm.GM_deleteValue("ajs_rules_ver")
          : tm.GM_setValue("ajs_rules_ver", v);
      },
      get etags() {
        const v = tm.GM_getValue("ajs_rules_etags", "{}");
        return typeof v == "string" ? JSON.parse(v) : {};
      },
      set etags(v) {
        v === null
          ? tm.GM_deleteValue("ajs_rules_etags")
          : tm.GM_setValue("ajs_rules_etags", JSON.stringify(v));
      },
    },
    data = {
      disabled: false,
      updating: false,
      receivedRules: "",
      allRules: "",
      genericStyle: document.createElement("style"),
      presetCss:
        " {display: none !important;width: 0 !important;height: 0 !important;} ",
      supportedCount: 0,
      appliedCount: 0,
      isFrame: tm.unsafeWindow.self !== tm.unsafeWindow.top,
      isClean: false,
      mutex: "__lemon__abp__parser__$__",
      debug: true,
      timeout: 5000,
    },
    menus = {
      disable: {
        id: undefined,
        get text() {
          return data.disabled ? "在此网站启用拦截" : "在此网站禁用拦截";
        },
      },
      update: {
        id: undefined,
        get text() {
          const time = values.time;
          return data.updating
            ? "正在更新..."
            : `点击更新: ${time.slice(0, 1) === "0" ? "未知时间" : time}`;
        },
      },
      count: {
        id: undefined,
        get text() {
          return data.isClean
            ? "已清空,点击刷新重新加载规则"
            : `点击清空: ${data.appliedCount} / ${data.supportedCount} / ${
                data.allRules.split("\n").length
              }`;
        },
      },
    };
  function gmMenu(name, cb) {
    if (
      typeof tm.GM_registerMenuCommand !== "function" ||
      typeof tm.GM_unregisterMenuCommand !== "function" ||
      data.isFrame
    )
      return false;
    const id = menus[name].id;
    if (typeof id !== "undefined") {
      logger("color", `删除菜单 ${name}`, "red");
      tm.GM_unregisterMenuCommand(id);
      menus[name].id = undefined;
    }
    if (typeof cb == "function") {
      logger("color", `添加菜单 ${name}`, "green");
      menus[name].id = tm.GM_registerMenuCommand(menus[name].text, cb);
    }
    logger("data", {
      菜单: "ID",
      disable: menus.disable.id,
      update: menus.update.id,
      count: menus.count.id,
    });
    return typeof menus[name].id !== "undefined";
  }
  function promiseXhr(details) {
    return __awaiter(this, void 0, void 0, function* () {
      let loaded = false;
      logger("info", "XHR 配置", details);
      try {
        return yield new Promise((resolve, reject) => {
          tm.GM_xmlhttpRequest(
            Object.assign(
              {
                onload(e) {
                  loaded = true;
                  resolve(e);
                },
                onabort: reject.bind(null, "abort"),
                onerror: reject.bind(null, "error"),
                ontimeout: reject.bind(null, "timeout"),
                onreadystatechange(e_1) {
                  // X 浏览器超时中断
                  if (e_1.readyState === 4) {
                    setTimeout(() => {
                      if (!loaded) reject("X timeout");
                    }, 300);
                  }
                  // Via 浏览器超时中断,不给成功状态...
                  if (e_1.readyState === 3) {
                    setTimeout(() => {
                      if (!loaded) reject("Via timeout");
                    }, data.timeout);
                  }
                },
                timeout: data.timeout,
              },
              details
            )
          );
        });
      } catch (r) {
        logger("error", "promiseXhr: ", {
          错误: r,
          地址: details.url,
        });
      }
    });
  }
  function storeRule(name, resp) {
    const savedRules = values.rules,
      savedEtags = values.etags,
      ruleCount = {};
    logger("info", "XHR 响应", resp.responseText.length);
    if (resp.responseHeaders) {
      const etag = getEtag(resp.responseHeaders);
      if (etag) {
        savedEtags[name] = etag;
        values.etags = savedEtags;
      }
    }
    if (resp.responseText) {
      savedRules[name] = resp.responseText;
      values.rules = savedRules;
      if (Object.keys(values.rules).length === 0) {
        logger("warn", "存储失败,放入临时变量");
        data.receivedRules += "\n" + resp.responseText + "\n";
      }
    }
    {
      Object.keys(savedRules).forEach((k) => {
        ruleCount[k] = savedRules[k].length;
      });
      logger("data", {
        etags: savedEtags,
        rules: ruleCount,
      });
    }
  }
  function fetchRuleBody(name, url) {
    return __awaiter(this, void 0, void 0, function* () {
      const getResp = yield promiseXhr({
        method: "GET",
        responseType: "text",
        url: url,
      });
      if (getResp) {
        storeRule(name, getResp);
        return true;
      } else return false;
    });
  }
  function fetchRule(url) {
    var _a;
    const name =
      (_a = getName(url)) !== null && _a !== void 0
        ? _a
        : `${url.length}.${url.slice(-5)}`;
    logger("info", `在线规则 ${name} 开始`);
    return new Promise((resolve, reject) =>
      __awaiter(this, void 0, void 0, function* () {
        var _b, _c, _d, _e;
        if (!name) reject();
        const headResp = yield promiseXhr({
          method: "HEAD",
          responseType: "text",
          url: url,
        });
        if (!headResp) {
          reject();
        } else {
          logger("info", "XHR HEAD 响应", headResp);
          if (headResp.responseText) {
            logger("warn", "不支持 HEAD");
            storeRule(name, headResp);
            resolve();
          } else {
            const etag = getEtag(
                typeof headResp.responseHeaders == "string"
                  ? headResp.responseHeaders
                  : (_c = (_b = headResp).getAllResponseHeaders) === null ||
                    _c === void 0
                  ? void 0
                  : _c.call(_b)
              ),
              savedEtags = values.etags;
            logger("data", {
              monkey:
                typeof headResp.responseHeaders == "string"
                  ? headResp.responseHeaders
                  : null,
              standard:
                (_e = (_d = headResp).getAllResponseHeaders) === null ||
                _e === void 0
                  ? void 0
                  : _e.call(_d),
              parsed: etag,
            });
            if (etag) {
              logger("data", Object.assign({ HEAD: etag }, savedEtags));
              if (etag !== savedEtags[name]) {
                (yield fetchRuleBody(name, url)) ? resolve() : reject();
              } else reject();
            } else {
              logger("warn", "不提供 ETAG");
              (yield fetchRuleBody(name, url)) ? resolve() : reject();
            }
          }
        }
      })
    );
  }
  function fetchRules() {
    return __awaiter(this, void 0, void 0, function* () {
      data.updating = true;
      gmMenu("update", () => undefined);
      logger("info", `在线规则 ${onlineRules.length} 个地址`);
      for (const url of onlineRules)
        yield fetchRule(url).catch((r) => {
          logger("error", "fetchRule: ", {
            错误: r,
            地址: url,
          });
        });
      logger("info", "在线规则下载结束");
      values.time = new Date().toLocaleString("zh-CN");
      gmMenu("count", cleanRules);
      initRules();
    });
  }
  function performUpdate(force) {
    if (force) {
      logger("color", "无条件更新", "darkslateblue");
      return fetchRules();
    } else {
      logger("info", "日期变更更新", getDay(values.time), new Date().getDate());
      return getDay(values.time) !== new Date().getDate()
        ? fetchRules()
        : Promise.resolve();
    }
  }
  function switchDisabledStat() {
    const disaList = values.black.split(","),
      disaResult = disaList.includes(location.hostname);
    data.disabled = !disaResult;
    if (data.disabled) {
      disaList.push(location.hostname);
    } else {
      disaList.splice(disaList.indexOf(location.hostname), 1);
    }
    values.black = disaList.join(",");
    gmMenu("disable", switchDisabledStat);
  }
  function checkDisableStat() {
    const disaResult = values.black.split(",").includes(location.hostname);
    logger("data", {
      key: "black",
      value: values.black.split(","),
    }),
      logger("info", "禁用: ", location.hostname, disaResult);
    data.disabled = disaResult;
    gmMenu("disable", switchDisabledStat);
    return disaResult;
  }
  function initRules() {
    const abpRules = values.rules;
    if (typeof tm.GM_getResourceText == "function") {
      onlineRules.forEach((url) => {
        var _a;
        const ruleName = getName(url),
          resName = ruleName.split(".")[0];
        let resRule;
        try {
          resRule = tm.GM_getResourceText(resName);
        } catch (error) {
          logger("error", "GM_getResourceText", error.message);
          resRule = "";
        }
        logger("data", {
          规则: ruleName,
          values:
            (_a = abpRules[ruleName]) === null || _a === void 0
              ? void 0
              : _a.length,
          resource:
            resRule === null || resRule === void 0 ? void 0 : resRule.length,
        });
        if (resRule && !abpRules[ruleName]) abpRules[ruleName] = resRule;
      });
    }
    const abpKeys = Object.keys(abpRules);
    {
      const ruleCount = {};
      logger("color", `已存储规则: ${abpKeys.length}`, "royalblue");
      abpKeys.forEach((k) => {
        ruleCount[k] = abpRules[k].length;
      });
      logger("data", Object.assign({ 规则: "数量" }, ruleCount));
    }
    abpKeys.forEach((name) => {
      data.receivedRules += "\n" + abpRules[name] + "\n";
    });
    data.allRules = defaultRules + data.receivedRules;
    data.allRules += testRules;
    if (abpKeys.length !== 0) {
      data.updating = false;
      gmMenu("update", () =>
        __awaiter(this, void 0, void 0, function* () {
          yield performUpdate(true);
          location.reload();
        })
      );
    }
    return data.receivedRules.length;
  }
  function styleApply() {
    const css =
        styles.apply +
        (selectors.apply.length > 0 ? selectors.apply + data.presetCss : ""),
      ecss =
        extStyles.apply +
        (extSelectors.apply.length > 0
          ? extSelectors.apply + data.presetCss
          : "");
    if (css.length > 0) {
      if (typeof tm.GM_addStyle == "function") {
        logger("color", "GM_addStyle", "green");
        tm.GM_addStyle(css);
      } else {
        logger("color", "普通 <style>", "red");
        runNeed(
          () => !!document.documentElement,
          () => {
            data.genericStyle.textContent = css;
            document.documentElement.appendChild(data.genericStyle);
          }
        );
      }
    }
    logger(
      "info",
      "ExtendedCss: ",
      typeof ExtendedCss__default.default == "function"
    );
    if (ecss.length > 0)
      new ExtendedCss__default.default({ styleSheet: ecss }).apply();
  }
  function cleanRules() {
    if (confirm(`是否清空存储规则 (${Object.keys(values.rules).length}) ?`)) {
      values.rules = {};
      values.time = "0/0/0 0:0:0";
      values.etags = {};
      data.appliedCount = 0;
      data.supportedCount = 0;
      data.allRules = "";
      data.isClean = true;
      gmMenu("update");
      gmMenu("count", () => location.reload());
    }
  }
  function parseRules() {
    [selectors, extSelectors].forEach((obj) => {
      obj.black
        .filter((v) => !obj.white.includes(v))
        .forEach((sel) => {
          obj.apply += `${obj.apply.length == 0 ? "" : ","}${sel}`;
          data.appliedCount++;
        });
    });
    [styles, extStyles].forEach((obj) => {
      obj.black
        .filter((v) => !obj.white.includes(v))
        .forEach((sel) => {
          obj.apply += ` ${sel}`;
          data.appliedCount++;
        });
    });
    gmMenu("count", cleanRules);
    logger("color", "规则分拣完成", "green");
    styleApply();
  }
  function splitRules() {
    data.allRules.split("\n").forEach((rule) => {
      const ruleObj = ruleSpliter(rule);
      let arr = "";
      if (typeof ruleObj !== "undefined") {
        arr = ruleObj.black ? "black" : "white";
        switch (ruleObj.type) {
          case 0:
            selectors[arr].push(ruleObj.sel);
            break;
          case 1:
            extSelectors[arr].push(ruleObj.sel);
            break;
          case 2:
            styles[arr].push(ruleObj.sel);
            break;
          case 3:
            extStyles[arr].push(ruleObj.sel);
            break;
        }
        data.supportedCount++;
      }
    });
    logger("data", {
      选择器: {
        黑: selectors.black.length,
        白: selectors.white.length,
      },
      样式: {
        黑: styles.black.length,
        白: styles.white.length,
      },
      扩展选择器: {
        黑: extSelectors.black.length,
        白: extSelectors.white.length,
      },
      扩展样式: {
        黑: extStyles.black.length,
        白: extStyles.white.length,
      },
    });
    parseRules();
  }
  function main() {
    return __awaiter(this, void 0, void 0, function* () {
      {
        logger("count", "执行次数");
        logger("info", "iframe: ", data.isFrame);
        logger("data", {
          GM_getValue: typeof tm.GM_getValue == "function" ? "OK" : "NO",
          GM_deleteValue: typeof tm.GM_deleteValue == "function" ? "OK" : "NO",
          GM_setValue: typeof tm.GM_setValue == "function" ? "OK" : "NO",
          GM_registerMenuCommand:
            typeof tm.GM_registerMenuCommand == "function" ? "OK" : "NO",
          GM_unregisterMenuCommand:
            typeof tm.GM_unregisterMenuCommand == "function" ? "OK" : "NO",
          GM_xmlhttpRequest:
            typeof tm.GM_xmlhttpRequest == "function" ? "OK" : "NO",
          GM_getResourceText:
            typeof tm.GM_getResourceText == "function" ? "OK" : "NO",
          GM_addStyle: typeof tm.GM_addStyle == "function" ? "OK" : "NO",
        });
        logger("data", {
          black: values.black,
          rules: Object.keys(values.rules).join(),
          time: values.time,
          etags: Object.keys(values.etags).join(),
        });
        cleanRules();
      }
      if (checkDisableStat() || (initRules() === 0 && data.isFrame)) return;
      if (data.receivedRules.length === 0) yield performUpdate(true);
      splitRules();
      yield performUpdate(false);
      if (data.appliedCount === 0) splitRules();
    });
  }
  function runOnce(key, func, ...params) {
    if (key in tm.unsafeWindow) return;
    tm.unsafeWindow[key] = true;
    func === null || func === void 0 ? void 0 : func.apply(this, params);
  }
  runOnce(data.mutex, main);
})(
  {
    GM_getValue: typeof GM_getValue == "function" ? GM_getValue : undefined,
    GM_deleteValue:
      typeof GM_deleteValue == "function" ? GM_deleteValue : undefined,
    GM_setValue: typeof GM_setValue == "function" ? GM_setValue : undefined,
    unsafeWindow: typeof unsafeWindow == "object" ? unsafeWindow : window,
    GM_registerMenuCommand:
      typeof GM_registerMenuCommand == "function"
        ? GM_registerMenuCommand
        : undefined,
    GM_unregisterMenuCommand:
      typeof GM_unregisterMenuCommand == "function"
        ? GM_unregisterMenuCommand
        : undefined,
    GM_xmlhttpRequest:
      typeof GM_xmlhttpRequest == "function" ? GM_xmlhttpRequest : undefined,
    GM_getResourceText:
      typeof GM_getResourceText == "function" ? GM_getResourceText : undefined,
    GM_addStyle: typeof GM_addStyle == "function" ? GM_addStyle : undefined,
  },
  ExtendedCss
);