// ==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://greasyforks.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
);