Greasy Fork

Greasy Fork is available in English.

套壳油猴的广告拦截脚本.副本

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

当前为 2022-12-15 提交的版本,查看 最新版本

// ==UserScript==
// @name 套壳油猴的广告拦截脚本.副本
// @author Lemon399
// @version 2.4.0.9
// @description 将 ABP 中的元素隐藏规则转换为 CSS 使用
// @require http://greasyfork.icu/scripts/452263-extended-css/code/extended-css.js?version=1128208
// @resource jiekouAD https://code.gitlink.org.cn/damengzhu/banad/raw/branch/main/jiekouAD.txt
// @resource CSSRule https://code.gitlink.org.cn/damengzhu/abpmerge/raw/branch/main/CSSRule.txt
// @match *://*/*
// @run-at document-start
// @grant unsafeWindow
// @grant GM_registerMenuCommand
// @grant GM_unregisterMenuCommand
// @grant GM_getValue
// @grant GM_deleteValue
// @grant GM_setValue
// @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
// ==/UserScript==

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

 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 = [];
 onlineRules.push(
 {
 标识: "jiekouAD",
 地址: "https://code.gitlink.org.cn/damengzhu/banad/raw/branch/main/jiekouAD.txt",
 在线更新: !!1,
 筛选后存储: !!1,
 },
 {
 标识: "CSSRule",
 地址: "https://code.gitlink.org.cn/damengzhu/abpmerge/raw/branch/main/CSSRule.txt",
 在线更新: !!1,
 筛选后存储: !!0,
 }
 );
 let defaultRules = `
! 没有 ## #@# #?# #@?#
! #$# #@$# #$?# #@$?# 的行和
! 开头为 ! 的行会忽略
!
! 由于语法限制,内置规则中
! 一个反斜杠需要改成两个,像这样 \\
!
! 若要修改地址,请注意同步修改
! 头部的 @connect 和 @resource

`;

 const CRRE =
 /^(~?[\w-]+(?:\.[\w-]+)*(?:\.[\w-]+|\.\*)(?:,~?[\w-]+(?:\.[\w-]+)*(?:\.[\w-]+|\.\*))*)?(#@?\$?\??#)([^\s^+].*)/,
 BRRE =
 /^(?:@@?)(\|\|?)?(https?:\/\/)?([^\s"<>`]+?[|^]?)\$((?:~?[\w-]+(?:=[\s\w'":.-]+)?|_+)(?:,(?:~?[\w-]+(?:=[\s\w'":.-]+)?|_+))*)$/,
 CCRE = /^\/\* (.+?) \*\/ /,
 BROpts = [
 "elemhide",
 "ehide",
 "specifichide",
 "shide",
 "generichide",
 "ghide",
 ];
 const CRFlags = ["##", "#@#", "#?#", "#@?#", "#$#", "#@$#", "#$?#", "#@$?#"];
 function bRuleSpliter(rule) {
 const group = rule.match(BRRE),
 body = group[3],
 options = group[4].split(","),
 sepChar = "[!#&'()+,/:;=?@~|{}$]",
 anyChar = '([^\\s"<>`]*)',
 eh = hasSome(options, ["elemhide", "ehide"]),
 sh = hasSome(options, ["specifichide", "shide"]),
 gh = hasSome(options, ["generichide", "ghide"]);
 let urlres = "";
 urlres += group[1]
 ? group[2]
 ? `^${group[2]}`
 : `^https?://((${anyChar}:)?(${anyChar}@))?([\\w-]+\\.)*?`
 : `^${anyChar}`;
 urlres += body
 .replace(/[-\\$+.()[\]{}]/g, "\\$&")
 .replace(/\|$/, "$")
 .replace(/\|/g, "\\|")
 .replace(/\^$/, `(${sepChar}|$)`)
 .replace(/\^/g, sepChar)
 .replace(/\*$/g, "")
 .replace(/\*/g, anyChar);
 return {
 rule: rule,
 match: urlres,
 level: eh ? 3 : gh && sh ? 3 : sh ? 2 : gh ? 1 : 0,
 };
 }
 function isBasicRule(rule) {
 return BRRE.test(rule) && hasSome(rule, BROpts);
 }
 function bRuleParser(rule, url = location.href) {
 return new RegExp(rule.match).test(url) ? rule.level : 0;
 }
 function findMatches(string, res) {
 let result = [-1, null];
 res.forEach((re, i) => {
 const match = string.match(re);
 if (match) result = [i, match];
 });
 return result;
 }
 function getEtag(header) {
 const result = findMatches(header, [
 /(e|E)tag: \"(\w+)\"/,
 // WebMonkey 系
 /(e|E)tag: \[\"(\w+)\"\]/,
 // 书签地球
 /(e|E)tag=\"(\w+)\"/,
 ]);
 return result[1] ? result[1][2] : null;
 }
 function makeRuleBox() {
 return {
 black: [],
 white: [],
 };
 }
 function domainChecker(domains) {
 const results = [],
 invResults = [],
 urlSuffix = /\.+?[\w-]+$/.exec(location.hostname);
 let totalResult = [0, false],
 black = false,
 white = false,
 match = false;
 domains.forEach((domain) => {
 if (domain.endsWith(".*") && Array.isArray(urlSuffix)) {
 domain = domain.replace(".*", urlSuffix[0]);
 }
 const invert = domain[0] == "~";
 if (invert) domain = domain.slice(1);
 const result = location.hostname.endsWith(domain);
 if (invert) {
 if (result) white = true;
 invResults.push([domain.length, !result]);
 } else {
 if (result) black = true;
 results.push([domain.length, result]);
 }
 });
 if (results.length > 0 && !black) {
 match = false;
 } else if (invResults.length > 0 && !white) {
 match = true;
 } else {
 results.forEach((r) => {
 if (r[0] >= totalResult[0] && r[1]) {
 totalResult = r;
 }
 });
 invResults.forEach((r) => {
 if (r[0] >= totalResult[0] && !r[1]) {
 totalResult = r;
 }
 });
 match = totalResult[1];
 }
 return [match, results.length == 0];
 }
 function hasSome(str, arr) {
 return arr.some((word) => str.includes(word));
 }
 function ruleSpliter(rule) {
 var _a;
 const group = rule.match(CRRE);
 if (group) {
 const sel = group[3],
 type = CRFlags.indexOf(group[2]),
 matchResult = !group[1]
 ? [true, true]
 : domainChecker(group[1].split(","));
 if (sel && matchResult[0]) {
 return {
 black: type % 2 ? "white" : "black",
 type: Math.floor(type / 2),
 place: (_a = group[1]) !== null && _a !== void 0 ? _a : "*",
 generic: matchResult[1],
 sel,
 };
 }
 }
 }
 function ruleLoader(rule) {
 if (
 hasSome(rule, [
 ":matches-path(",
 ":min-text-length(",
 ":watch-attr(",
 ":-abp-properties(",
 ":matches-property(",
 "if-not(",
 ])
 )
 return;
 // 去掉开头空格
 rule = rule.replace(/^ +/, "");
 // 如果 #$# 不包含 {} 就排除
 // 可以尽量排除 Snippet Filters
 if (/(\w|^)#\$#/.test(rule) && !/{.+}/.test(rule)) return;
 // ## -> #?#
 if (
 /(\w|^)#@?#/.test(rule) &&
 hasSome(rule, [
 ":has(",
 ":-abp-has(",
 "[-ext-has=",
 ":has-text(",
 "contains(",
 "-abp-contains(",
 "[-ext-contains=",
 "matches-css(",
 "[-ext-matches-css=",
 "matches-css-before(",
 "[-ext-matches-css-before=",
 "matches-css-after(",
 "[-ext-matches-css-after=",
 "matches-attr(",
 "nth-ancestor(",
 "upward(",
 "xpath(",
 "remove()",
 "not(",
 ])
 ) {
 rule = rule.replace(/(\w|^)##/, "$1#?#").replace(/(\w|^)#@#/, "$1#@?#");
 }
 // :style(...) 转换
 // example.com#?##id:style(color: red)
 // example.com#$?##id { color: red }
 if (rule.includes(":style(")) {
 rule = rule
 .replace(/(\w|^)##/, "$1#$#")
 .replace(/(\w|^)#@#/, "$1#@$#")
 .replace(/(\w|^)#\?#/, "$1#$?#")
 .replace(/(\w|^)#@\?#/, "$1#@$?#")
 .replace(/:style\(/, " { ")
 .replace(/\)$/, " }");
 }
 return ruleSpliter(rule);
 }
 function logger(type, ...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]} `,
 `display: inline-block; color: white; background: ${data[1]}; border-radius: .75em; padding: 2px 5px`,
 ...data.splice(2)
 );
 break;
 case "count":
 console.count(data[0]);
 break;
 }
 }
 function textToBlobUrl(text) {
 return URL.createObjectURL(new Blob([text]));
 }
 function downUrl(url, name) {
 const a = document.createElement("a");
 a.href = url;
 a.download = name;
 Object.assign(a.style, {
 position: "fixed",
 top: "200%",
 });
 document.body.appendChild(a);
 setTimeout(() => {
 a.click();
 a.remove();
 }, 0);
 }

 var _a, _b, _c;
 const selectors = makeRuleBox(),
 extSelectors = makeRuleBox(),
 styles = makeRuleBox(),
 extStyles = makeRuleBox(),
 styleBoxes = ["genHideCss", "genExtraCss", "spcHideCss", "spcExtraCss"],
 values = {
 get black() {
 const arrStr = gmValue("get", false, "ajs_disabled_domains", "");
 return typeof arrStr == "string" && arrStr.length > 0
 ? arrStr.split(",")
 : [];
 },
 set black(v) {
 gmValue(
 "set",
 false,
 "ajs_disabled_domains",
 v === null || v === void 0 ? void 0 : v.join()
 );
 },
 get rules() {
 return gmValue("get", true, "ajs_saved_abprules", {});
 },
 set rules(v) {
 gmValue("set", true, "ajs_saved_abprules", v);
 },
 get css() {
 return gmValue("get", true, `ajs_saved_styles_${location.hostname}`, {
 needUpdate: true,
 genHideCss: "",
 genExtraCss: "",
 spcHideCss: "",
 spcExtraCss: "",
 });
 },
 set css(v) {
 gmValue("set", true, `ajs_saved_styles_${location.hostname}`, v);
 },
 get hasSave() {
 const arrStr = gmValue("get", false, "ajs_hasSave_domains", "");
 return typeof arrStr == "string" && arrStr.length > 0
 ? arrStr.split(",")
 : [];
 },
 set hasSave(v) {
 gmValue(
 "set",
 false,
 "ajs_hasSave_domains",
 v === null || v === void 0 ? void 0 : v.join()
 );
 },
 get time() {
 return gmValue("get", false, "ajs_rules_ver", "0/0/0 0:0:0");
 },
 set time(v) {
 gmValue("set", false, "ajs_rules_ver", v);
 },
 get drlen() {
 return gmValue("get", false, "ajs_drule_length", 0);
 },
 set drlen(v) {
 gmValue("set", false, "ajs_drule_length", v);
 },
 get etags() {
 return gmValue("get", true, "ajs_rules_etags", {});
 },
 set etags(v) {
 gmValue("set", true, "ajs_rules_etags", v);
 },
 get brules() {
 return gmValue("get", true, "ajs_modifier_rules", []);
 },
 set brules(v) {
 gmValue("set", true, "ajs_modifier_rules", v);
 },
 },
 data = {
 disabled: false,
 saved: false,
 update: true,
 updating: false,
 receivedRules: "",
 customRules: defaultRules,
 allRules: "",
 presetCss:
 " {display: none !important;width: 0 !important;height: 0 !important;} ",
 genHideCss: "",
 genExtraCss: "",
 spcHideCss: "",
 spcExtraCss: "",
 bRules: {
 levels: [],
 rules: [],
 },
 appliedLevel: 0,
 appliedCount: 0,
 records: [],
 isFrame: tm.unsafeWindow.self !== tm.unsafeWindow.top,
 isClean: false,
 mutex: "__lemon__abp__parser__$__",
 timeout: 6000,
 xTimeout: 700,
 },
 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() {
 var _a;
 let cssCount = "";
 if ((data.appliedLevel & 1) == 0)
 cssCount += data.genHideCss + data.genExtraCss;
 if ((data.appliedLevel & 2) == 0)
 cssCount += data.spcHideCss + data.spcExtraCss;
 return data.isClean
 ? "已清空,点击刷新重新加载规则"
 : `${
 data.saved
 ? "CSS: " +
 ((_a = cssCount.match(/{/g)) === null || _a === void 0
 ? void 0
 : _a.length)
 : "规则: " +
 data.appliedCount +
 "/" +
 data.allRules.split("\n").length
 },点击清空规则`;
 },
 },
 export: {
 id: undefined,
 text: "下载统计报告",
 },
 };
 data.customRules +=
 "\n" +
 ((_c =
 (_b =
 (_a = tm.GM_info.script) === null || _a === void 0
 ? void 0
 : _a.options) === null || _b === void 0
 ? void 0
 : _b.comment) !== null && _c !== void 0
 ? _c
 : "") +
 "\n";
 function gmMenu(name, cb) {
 var _a;
 const id = (_a = menus[name].id) !== null && _a !== void 0 ? _a : false;
 if (
 typeof tm.GM_registerMenuCommand != "function" ||
 typeof tm.GM_unregisterMenuCommand != "function" ||
 data.isFrame
 )
 return;
 if (typeof id == "number") {
 tm.GM_unregisterMenuCommand(id);
 menus[name].id = undefined;
 }
 if (typeof cb == "function") {
 menus[name].id = tm.GM_registerMenuCommand(menus[name].text, cb);
 }
 }
 function gmValue(action, json, key, value) {
 switch (action) {
 case "get":
 let v;
 try {
 v = tm.GM_getValue(key, json ? JSON.stringify(value) : value);
 } catch (error) {
 return;
 }
 return json && typeof v == "string" ? JSON.parse(v) : v;
 case "set":
 try {
 value === null || value === undefined
 ? tm.GM_deleteValue(key)
 : tm.GM_setValue(key, json ? JSON.stringify(value) : value);
 } catch (error) {
 tm.GM_deleteValue(key);
 }
 break;
 }
 }
 function promiseXhr(details) {
 return __awaiter(this, void 0, void 0, function* () {
 let loaded = false;
 try {
 return yield new Promise((resolve, reject) => {
 tm.GM_xmlhttpRequest(
 Object.assign(
 {
 onload(e) {
 loaded = true;
 resolve(e);
 },
 onabort: reject.bind(null, "abort"),
 onerror(e) {
 reject({
 error: "error",
 resp: e,
 });
 },
 ontimeout: reject.bind(null, "timeout"),
 onreadystatechange(e) {
 // X 浏览器超时中断
 if (e.readyState === 4) {
 setTimeout(() => {
 if (!loaded)
 reject({
 error: "X timeout",
 resp: e,
 });
 }, data.xTimeout);
 }
 // Via 浏览器超时中断,不给成功状态...
 if (e.readyState === 3) {
 setTimeout(() => {
 if (!loaded)
 reject({
 error: "Via timeout",
 resp: e,
 });
 }, data.timeout);
 }
 },
 timeout: data.timeout,
 },
 details
 )
 );
 });
 } catch (error) {}
 });
 }
 function storeRule(rule, resp) {
 const savedRules = values.rules,
 savedEtags = values.etags;
 if (resp.responseHeaders) {
 const etag = getEtag(resp.responseHeaders);
 if (etag) {
 savedEtags[rule.标识] = etag;
 values.etags = savedEtags;
 }
 }
 if (resp.responseText) {
 if (rule.筛选后存储) {
 let parsed = "";
 resp.responseText.split("\n").forEach((rule) => {
 if (CRRE.test(rule) || isBasicRule(rule)) parsed += rule + "\n";
 });
 savedRules[rule.标识] = parsed;
 } else {
 savedRules[rule.标识] = resp.responseText;
 }
 values.rules = savedRules;
 if (Object.keys(values.rules).length === 0) {
 data.receivedRules += "\n" + savedRules[rule.标识] + "\n";
 }
 }
 }
 function fetchRuleBody(rule) {
 var _a;
 return __awaiter(this, void 0, void 0, function* () {
 const getResp = yield promiseXhr({
 method: "GET",
 responseType: "text",
 url: rule.地址,
 });
 if (
 getResp &&
 (getResp === null || getResp === void 0
 ? void 0
 : getResp.responseText) &&
 ((_a = getResp.responseText) === null || _a === void 0
 ? void 0
 : _a.length) > 0
 ) {
 storeRule(rule, getResp);
 return true;
 } else return false;
 });
 }
 function fetchRule(rule) {
 return new Promise((resolve, reject) =>
 __awaiter(this, void 0, void 0, function* () {
 var _a, _b, _e;
 const headResp = yield promiseXhr({
 method: "HEAD",
 responseType: "text",
 url: rule.地址,
 });
 if (!headResp) {
 reject("HEAD 失败");
 } else {
 const etag = getEtag(
 typeof headResp.responseHeaders == "string"
 ? headResp.responseHeaders
 : (_b = (_a = headResp).getAllResponseHeaders) === null ||
 _b === void 0
 ? void 0
 : _b.call(_a)
 ),
 savedEtags = values.etags;
 if (
 (headResp === null || headResp === void 0
 ? void 0
 : headResp.responseText) &&
 ((_e = headResp.responseText) === null || _e === void 0
 ? void 0
 : _e.length) > 0
 ) {
 storeRule(rule, headResp);
 !etag || etag !== savedEtags[rule.标识]
 ? resolve()
 : reject("ETag 一致");
 } else {
 if (!etag || etag !== savedEtags[rule.标识]) {
 (yield fetchRuleBody(rule)) ? resolve() : reject("GET 失败");
 } else reject("ETag 一致");
 }
 }
 })
 );
 }
 function fetchRules(apply) {
 return __awaiter(this, void 0, void 0, function* () {
 const has = values.hasSave;
 let hasUpdate = onlineRules.length;
 data.updating = true;
 gmMenu("update", () => undefined);
 for (const rule of onlineRules) {
 if (rule.在线更新) {
 yield fetchRule(rule).catch((error) => {
 hasUpdate--;
 });
 }
 }
 values.time = new Date().toLocaleString("zh-CN");
 if (has.length > 0 && hasUpdate > 0) {
 has.forEach((host) => {
 const save = gmValue("get", true, `ajs_saved_styles_${host}`);
 save.needUpdate = true;
 gmValue("set", true, `ajs_saved_styles_${host}`, save);
 });
 }
 initRules(apply);
 });
 }
 function performUpdate(force, apply) {
 if (data.isFrame) return Promise.reject();
 return force || new Date(values.time).getDate() !== new Date().getDate()
 ? fetchRules(apply)
 : Promise.resolve();
 }
 function switchDisabledStat() {
 const disaList = values.black;
 data.disabled = !disaList.includes(location.hostname);
 if (data.disabled) {
 disaList.push(location.hostname);
 } else {
 disaList.splice(disaList.indexOf(location.hostname), 1);
 }
 values.black = disaList;
 location.reload();
 }
 function makeInitMenu() {
 gmMenu("update", () =>
 __awaiter(this, void 0, void 0, function* () {
 yield performUpdate(true, false);
 location.reload();
 })
 );
 gmMenu("count", cleanRules);
 }
 function initRules(apply) {
 const abpRules = values.rules;
 if (typeof tm.GM_getResourceText == "function") {
 onlineRules.forEach((rule) => {
 let resRule;
 try {
 resRule = tm.GM_getResourceText(rule.标识);
 } catch (error) {
 resRule = "";
 }
 if (resRule && !abpRules[rule.标识]) abpRules[rule.标识] = resRule;
 });
 }
 const abpKeys = Object.keys(abpRules);
 abpKeys.forEach((name) => {
 data.receivedRules += "\n" + abpRules[name] + "\n";
 });
 values.drlen = data.customRules.length;
 data.allRules = data.customRules + data.receivedRules;
 data.updating = false;
 makeInitMenu();
 if (apply) splitRules();
 return data.receivedRules.length;
 }
 function styleInject(csss, extra) {
 if (extra) {
 csss.split("\n").forEach((css) => {
 new ExtendedCss({
 styleSheet: css.replace(CCRE, ""),
 }).apply();
 });
 } else {
 if (typeof tm.GM_addStyle == "function") {
 tm.GM_addStyle(csss);
 } else {
 const elem = document.createElement("style");
 elem.textContent = csss;
 document.documentElement.appendChild(elem);
 }
 }
 }
 function styleApply() {
 if (data.appliedLevel === 3) return;
 if (data.genHideCss.length > 0 && data.appliedLevel !== 1) {
 styleInject(data.genHideCss, false);
 }
 if (data.spcHideCss.length > 0 && data.appliedLevel !== 2) {
 styleInject(data.spcHideCss, false);
 }
 if (data.genExtraCss.length > 0 && data.appliedLevel !== 1) {
 styleInject(data.genExtraCss, true);
 }
 if (data.spcExtraCss.length > 0 && data.appliedLevel !== 2) {
 styleInject(data.spcExtraCss, true);
 }
 gmMenu("export", reportRecord);
 }
 function reportRecord() {
 const flags = ["##", "#?#", "#$#", "#$?#"];
 let text = "! 应用地址: \n! " + location.href + "\n";
 function pushRecord(css) {
 if (css.match(CCRE) === null) return void 0;
 const extra = css.match(CCRE)[1],
 rule = css.replace(CCRE, ""),
 sel = rule.replace(/ {.+$/, ""),
 fi = parseInt(extra.slice(0, 1)),
 place = extra.slice(1),
 count =
 fi % 2 == 1
 ? ExtendedCss.query(sel).length
 : document.querySelectorAll(sel).length,
 item = (place == "*" ? "" : place) + flags[fi] + (fi >= 2 ? rule : sel);
 if (count > 0) {
 text += `\n! 匹配元素数量: ${count}\n${item}\n`;
 data.records.push([item, count]);
 }
 }
 if (data.bRules.levels.length > 0) {
 data.bRules.levels.forEach((l, i) => {
 if (l > 0) {
 text += `\n! 禁用${l == 2 ? "特定" : "通用"}元素隐藏\n${
 data.bRules.rules[i]
 }\n`;
 }
 });
 }
 styleBoxes.forEach((box, i) => {
 if ((data.appliedLevel & (i >= 2 ? 2 : 1)) == 0 && data[box].length > 0) {
 data[box].split("\n").forEach((css) => pushRecord(css));
 }
 });
 logger("info", "地址: " + location.href);
 logger("data", data.records);
 // X 浏览器 疑似 GM_download 不支持 blob:
 // if (typeof GM_download == "function") {
 // GM_download(textToBlobUrl(text), `拦截报告_${location.hostname}.txt`);
 // } else {
 downUrl(textToBlobUrl(text), `拦截报告_${location.hostname}.txt`);
 // }
 }
 function cleanRules() {
 if (confirm(`是否清空存储规则 (${Object.keys(values.rules).length}) ?`)) {
 const has = values.hasSave;
 values.rules = {};
 values.time = "0/0/0 0:0:0";
 values.drlen = 0;
 values.etags = {};
 values.brules = [];
 if (has.length > 0) {
 has.forEach((host) => {
 gmValue("set", true, `ajs_saved_styles_${host}`);
 });
 values.hasSave = null;
 }
 data.appliedCount = 0;
 data.allRules = "";
 data.isClean = true;
 gmMenu("update");
 gmMenu("export");
 gmMenu("count", () => location.reload());
 }
 }
 function parseRules() {
 styleBoxes.forEach((box) => {
 data[box] = "";
 });
 [styles, extStyles].forEach((r, t) => {
 r.black
 .filter((v) => !r.white.includes(v))
 .forEach((s) => {
 const checkResult = ExtendedCss.validate(s.sel.split("{")[0]);
 if (checkResult.ok) {
 data[
 styleBoxes[s.generic ? t : t + 2]
 ] += `/* ${s.type}${s.place} */ ${s.sel} \n`;
 data.appliedCount++;
 } else {
 logger(
 "color",
 "选择器检查错误:",
 "maroon",
 s.sel.split("{")[0],
 checkResult.error
 );
 }
 });
 });
 [selectors, extSelectors].forEach((r, t) => {
 r.black
 .filter((v) => !r.white.includes(v))
 .forEach((s, i) => {
 const checkResult = ExtendedCss.validate(s.sel);
 if (checkResult.ok) {
 data[styleBoxes[s.generic ? t : t + 2]] += `${
 i == 0 ? "" : "\n"
 }/* ${s.type}${s.place} */ ${s.sel + data.presetCss}`;
 data.appliedCount++;
 } else {
 logger(
 "color",
 "选择器检查错误:",
 "maroon",
 s.sel,
 checkResult.error
 );
 }
 });
 });
 if (values.brules.length > 0) parseBRules();
 gmMenu("count", cleanRules);
 saveCss();
 if (!data.saved) styleApply();
 }
 function splitRules() {
 const bRules = [];
 data.allRules.split("\n").forEach((rule) => {
 const ruleObj = ruleLoader(rule),
 boxes = [selectors, extSelectors, styles, extStyles];
 if (typeof ruleObj != "undefined") {
 if (
 ruleObj.black == "black" &&
 boxes[ruleObj.type].white.includes(ruleObj)
 )
 return;
 boxes[ruleObj.type][ruleObj.black].push(ruleObj);
 } else if (isBasicRule(rule)) {
 bRules.push(bRuleSpliter(rule));
 }
 });
 values.brules = bRules;
 parseRules();
 }
 function parseBRules() {
 const mrules = values.brules;
 data.bRules.levels = [];
 data.bRules.rules = [];
 mrules.forEach((br) => {
 data.bRules.levels.push(bRuleParser(br));
 data.bRules.rules.push(br.rule);
 });
 data.appliedLevel = Math.max(...data.bRules.levels);
 }
 function saveCss() {
 const styles = {
 needUpdate: false,
 genHideCss: data.genHideCss,
 genExtraCss: data.genExtraCss,
 spcHideCss: data.spcHideCss,
 spcExtraCss: data.spcExtraCss,
 },
 has = values.hasSave;
 values.css = styles;
 if (!has.includes(location.hostname)) has.push(location.hostname);
 values.hasSave = has;
 }
 function readCss() {
 const styles = values.css;
 if (!hasSome(Object.keys(styles), styleBoxes)) {
 values.css = {
 needUpdate: true,
 genHideCss: "",
 genExtraCss: "",
 spcHideCss: "",
 spcExtraCss: "",
 };
 return false;
 }
 if (values.brules.length > 0) parseBRules();
 styleBoxes.forEach((sname) => {
 var _a;
 if (styles[sname].length > 0) {
 data.saved = true;
 data.update =
 (_a = styles.needUpdate) !== null && _a !== void 0 ? _a : true;
 data[sname] = styles[sname];
 }
 });
 return data.saved;
 }
 function main() {
 var _a, _b;
 return __awaiter(this, void 0, void 0, function* () {
 data.disabled = values.black.includes(location.hostname);
 gmMenu("disable", switchDisabledStat);
 if (data.disabled) return;
 if (
 ((_b =
 (_a = tm.unsafeWindow.mbrowser) === null || _a === void 0
 ? void 0
 : _a.getVersionCode) === null || _b === void 0
 ? void 0
 : _b.call(_a)) >= 662
 ) {
 const vars = [
 "ajs_disabled_domains",
 "ajs_saved_abprules",
 "ajs_rules_etags",
 "ajs_rules_ver",
 ],
 stor = tm.unsafeWindow.localStorage;
 vars.forEach((key) => {
 if (stor.getItem(key)) {
 stor.removeItem(key);
 }
 });
 }
 if (values.drlen === data.customRules.length) readCss();
 saved: {
 if (data.saved) {
 styleApply();
 makeInitMenu();
 if (!data.update) break saved;
 }
 if (initRules(false) === 0) yield performUpdate(true, true);
 splitRules();
 }
 try {
 yield performUpdate(false, false);
 } catch (error) {
 logger("warn", "iframe: ", location.href, " 取消更新");
 }
 });
 }
 function runOnce(key, func) {
 if (key in tm.unsafeWindow) return;
 tm.unsafeWindow[key] = true;
 func();
 }
 runOnce(data.mutex, main);
})(
 {
 GM_info: typeof GM_info == "object" ? GM_info : {},
 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_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,
 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
);