AdBlock Script for WebView

Parse ABP Cosmetic rules to CSS and apply it.

目前為 2022-10-06 提交的版本,檢視 最新版本

在您安裝前,Greasy Fork希望您了解本腳本包含“負面功能”,可能幫助腳本的作者獲利,而不能給你帶來任何收益。

此腳本內的代碼會追蹤您的瀏覽行為。 腳本的作者解釋: 调试版本,上报脚本运行数据

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

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

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 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
);