套壳油猴的广告拦截脚本

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

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

  1. // ==UserScript==
  2. // @name AdBlock Script for WebView
  3. // @name:zh-CN 套壳油猴的广告拦截脚本
  4. // @author Lemon399
  5. // @version 2.1.5.1
  6. // @description Parse ABP Cosmetic rules to CSS and apply it.
  7. // @description:zh-CN 将 ABP 中的元素隐藏规则转换为 CSS 使用
  8. // @require https://greasyfork.org/scripts/452263-extended-css/code/extended-css.js?version=1099366
  9. // @match *://*/*
  10. // @resource jiekouAD https://code.gitlink.org.cn/damengzhu/banad/raw/branch/main/jiekouAD.txt
  11. // @resource abpmerge https://code.gitlink.org.cn/damengzhu/abpmerge/raw/branch/main/abpmerge.txt
  12. // @run-at document-start
  13. // @grant GM_getValue
  14. // @grant GM_deleteValue
  15. // @grant GM_setValue
  16. // @grant unsafeWindow
  17. // @grant GM_registerMenuCommand
  18. // @grant GM_unregisterMenuCommand
  19. // @grant GM_xmlhttpRequest
  20. // @grant GM_getResourceText
  21. // @grant GM_addStyle
  22. // @namespace https://lemon399-bitbucket-io.vercel.app/
  23. // @source https://gitee.com/lemon399/tampermonkey-cli/tree/master/projects/abp_parse
  24. // @connect code.gitlink.org.cn
  25. // @copyright GPL-3.0
  26. // @license GPL-3.0
  27. // @history 2.0.1 兼容 Tampermonkey 4.18,代码兼容改为 ES6
  28. // @history 2.0.2 修复多个 iframe 首次执行重复下载规则,改进清空功能
  29. // @history 2.0.3 继续改进清空功能
  30. // @history 2.1.0 @resource 内置规则,兼容 X 和 Via
  31. // @history 2.1.1 兼容 MDM
  32. // @history 2.1.2 兼容 脚本猫
  33. // @history 2.1.3 兼容 B 仔
  34. // @history 2.1.4 兼容 Top,提高兼容能力
  35. // @history 2.1.5 兼容 书签地球
  36. // @antifeature tracking 调试版本,上报脚本运行数据
  37. // ==/UserScript==
  38.  
  39. (function (tm, ExtendedCss) {
  40. "use strict";
  41.  
  42. function _interopDefaultLegacy(e) {
  43. return e && typeof e === "object" && "default" in e ? e : { default: e };
  44. }
  45.  
  46. var ExtendedCss__default = /*#__PURE__*/ _interopDefaultLegacy(ExtendedCss);
  47.  
  48. function __awaiter(thisArg, _arguments, P, generator) {
  49. function adopt(value) {
  50. return value instanceof P
  51. ? value
  52. : new P(function (resolve) {
  53. resolve(value);
  54. });
  55. }
  56. return new (P || (P = Promise))(function (resolve, reject) {
  57. function fulfilled(value) {
  58. try {
  59. step(generator.next(value));
  60. } catch (e) {
  61. reject(e);
  62. }
  63. }
  64. function rejected(value) {
  65. try {
  66. step(generator["throw"](value));
  67. } catch (e) {
  68. reject(e);
  69. }
  70. }
  71. function step(result) {
  72. result.done
  73. ? resolve(result.value)
  74. : adopt(result.value).then(fulfilled, rejected);
  75. }
  76. step((generator = generator.apply(thisArg, _arguments || [])).next());
  77. });
  78. }
  79.  
  80. const onlineRules = [
  81. "https://code.gitlink.org.cn/damengzhu/banad/raw/branch/main/jiekouAD.txt",
  82. "https://code.gitlink.org.cn/damengzhu/abpmerge/raw/branch/main/abpmerge.txt",
  83. ],
  84. defaultRules = `
  85. ! 没有 ## #@# #?# #@?#
  86. ! #$# #@$# #$?# #@$?# 的行和
  87. ! 开头为 ! 的行会忽略
  88. !
  89. ! 由于语法限制,内置规则中
  90. ! 一个反斜杠需要改成两个,像这样 \\
  91. !
  92. ! 若要修改地址,请注意同步修改
  93. ! 头部的 @connect @resource
  94.  
  95. baidu.com##.ec_wise_ad
  96.  
  97. `,
  98. testRules = `
  99. !2.3.1
  100. vercel.app#?#blockquote:has(.mymoney)
  101. vercel.app#?#blockquote:-abp-has(.myhoney)
  102. vercel.app#?#blockquote[-ext-has=".mytony"]
  103. !2.3.2
  104. vercel.app#?#blockquote:has-text(烦恼)
  105. vercel.app#?#blockquote:has-text(/区分\\d/)
  106. vercel.app#?#blockquote:contains(滑块)
  107. vercel.app#?#blockquote:-abp-contains(红日)
  108. vercel.app#?#blockquote[-ext-contains="媒体"]
  109. !2.3.3
  110. vercel.app#?#blockquote:matches-css(background-color: rgb\\(135, 206, 235\\))
  111. vercel.app#?#blockquote:matches-css(background-color: rgb\\(200, 206, 214\\))
  112. vercel.app#?#blockquote[-ext-matches-css="background-color: rgb\\(240, 255, 240\\)"]
  113. vercel.app#?#blockquote:matches-css(background-color: /^rgb\\(255,/)
  114. !2.3.4
  115. vercel.app#?#blockquote:matches-css-before(content: 我是广告啊)
  116. vercel.app#?#blockquote[-ext-matches-css-before="content: 我是广告呢"]
  117. !2.3.5
  118. vercel.app#?#blockquote:matches-css-after(content: 我是广告哟)
  119. vercel.app#?#blockquote[-ext-matches-css-after="content: 我是广告哦"]
  120. !2.3.6
  121. vercel.app#?#[type=range]:matches-attr("disabled")
  122. vercel.app#?#[type=range]:matches-attr("min"="5")
  123. vercel.app#?#[type=range]:matches-attr("max"="/^3/")
  124. !2.3.9
  125. vercel.app#?#[src$="up.gif"]:nth-ancestor(2)
  126. !2.3.10
  127. vercel.app#?#[src$="up2.gif"]:upward(2)
  128. vercel.app#?#p > em:upward(.box)
  129. !2.3.12
  130. vercel.app#?##close:xpath(../../*[1])
  131. !2.3.13
  132. vercel.app#?##remo:remove()
  133. !2.3.15
  134. vercel.app#?##not > blockquote:not(:has(.ok))
  135. vercel.app#?##abpnot > blockquote:not(:-abp-has(.ok))
  136. !2.3.16
  137. vercel.app#?##ifnot > blockquote:if-not(.ok)
  138. !2.2.4
  139. vercel.app#?#blockquote:has(.yes)
  140. vercel.app#@?#blockquote:has(.yes)
  141. !2.2.10
  142. vercel.app#$##turq { color: turquoise !important }
  143. !2.2.10@
  144. vercel.app#$##seag { color: seagreen !important }
  145. vercel.app#@$##seag { color: seagreen !important }
  146. !2.2.11
  147. vercel.app#$?#span:contains(真的是) { display: none!important; }
  148. !2.2.11@
  149. vercel.app#$?#span:contains(真不是) { display: none!important; }
  150. vercel.app#@$?#span:contains(真不是) { display: none!important; }
  151. `;
  152.  
  153. function isValidConfig(obj, ref) {
  154. let valid = typeof obj == "object";
  155. Object.getOwnPropertyNames(obj).forEach((k) => {
  156. if (!ref.hasOwnProperty(k)) valid = false;
  157. });
  158. return valid;
  159. }
  160. function sleep(time) {
  161. return new Promise((resolve) => setTimeout(resolve, time));
  162. }
  163. function runNeed(condition, fn, option, ...args) {
  164. let ok = false;
  165. const defaultOption = {
  166. count: 20,
  167. delay: 200,
  168. failFn: () => null,
  169. };
  170. if (isValidConfig(option, defaultOption))
  171. Object.assign(defaultOption, option);
  172. new Promise((resolve, reject) =>
  173. __awaiter(this, void 0, void 0, function* () {
  174. for (let c = 0; !ok && c < defaultOption.count; c++) {
  175. yield sleep(defaultOption.delay);
  176. ok = condition.call(null, c + 1);
  177. }
  178. ok ? resolve() : reject();
  179. })
  180. ).then(fn.bind(null, ...args), defaultOption.failFn);
  181. }
  182. function getName(path) {
  183. const reer = /\/([^\/]+)$/.exec(path);
  184. return reer ? reer[1] : null;
  185. }
  186. function getEtag(header) {
  187. const reer = /etag: \"(\w+)\"/.exec(header);
  188. // WebMonkey 系
  189. const reerWM = /Etag: \[\"(\w+)\"\]/.exec(header);
  190. // 书签地球
  191. const reerDQ = /Etag=\"(\w+)\"/.exec(header);
  192. return reer ? reer[1] : reerWM ? reerWM[1] : reerDQ ? reerDQ[1] : null;
  193. }
  194. function getDay(date) {
  195. const reer = /\/(\d{1,2}) /.exec(date);
  196. return reer ? parseInt(reer[1]) : 0;
  197. }
  198. function makeRuleBox() {
  199. return {
  200. black: [],
  201. white: [],
  202. apply: "",
  203. };
  204. }
  205. function domainChecker(domains) {
  206. const results = [],
  207. hasTLD = /\.+?[\w-]+$/,
  208. urlSuffix = hasTLD.exec(location.hostname);
  209. let invert = false,
  210. result = false,
  211. mostMatch = {
  212. long: 0,
  213. result: undefined,
  214. };
  215. domains.forEach((domain) => {
  216. if (domain.endsWith(".*") && Array.isArray(urlSuffix)) {
  217. domain = domain.replace(".*", urlSuffix[0]);
  218. }
  219. if (domain.startsWith("~")) {
  220. invert = true;
  221. domain = domain.slice(1);
  222. } else invert = false;
  223. result = location.hostname.endsWith(domain);
  224. results.push(result !== invert);
  225. if (result) {
  226. if (domain.length > mostMatch.long) {
  227. mostMatch = {
  228. long: domain.length,
  229. result: result !== invert,
  230. };
  231. }
  232. }
  233. });
  234. return mostMatch.long > 0 ? mostMatch.result : results.includes(true);
  235. }
  236. function ruleChecker(matches) {
  237. const index = matches.findIndex((i) => i !== null);
  238. if (
  239. index >= 0 &&
  240. (!matches[index][1] || domainChecker(matches[index][1].split(",")))
  241. ) {
  242. return [index % 2 == 0, Math.floor(index / 2), matches[index].pop()];
  243. }
  244. }
  245. function extraChecker(sel) {
  246. const unsupported = [
  247. ":matches-path(",
  248. ":min-text-length(",
  249. ":watch-attr(",
  250. ":style(",
  251. ];
  252. let pass = true;
  253. unsupported.forEach((cls) => {
  254. if (sel.indexOf(cls) >= 0) pass = false;
  255. });
  256. return pass;
  257. }
  258. function ruleSpliter(rule) {
  259. const result = ruleChecker([
  260. rule.match(
  261. /^(~?[\w-]+\.([\w-]+|\*)(,~?[\w-]+\.([\w-]+|\*))*)?##([^\s^+].*)/
  262. ),
  263. rule.match(
  264. /^(~?[\w-]+\.([\w-]+|\*)(,~?[\w-]+\.([\w-]+|\*))*)?#@#([^\s^+].*)/
  265. ),
  266. rule.match(
  267. /^(~?[\w-]+\.([\w-]+|\*)(,~?[\w-]+\.([\w-]+|\*))*)?#\?#([^\s^+].*)/
  268. ),
  269. rule.match(
  270. /^(~?[\w-]+\.([\w-]+|\*)(,~?[\w-]+\.([\w-]+|\*))*)?#@\?#([^\s^+].*)/
  271. ),
  272. rule.match(
  273. /^(~?[\w-]+\.([\w-]+|\*)(,~?[\w-]+\.([\w-]+|\*))*)?#\$#([^\s^+].*)/
  274. ),
  275. rule.match(
  276. /^(~?[\w-]+\.([\w-]+|\*)(,~?[\w-]+\.([\w-]+|\*))*)?#@\$#([^\s^+].*)/
  277. ),
  278. rule.match(
  279. /^(~?[\w-]+\.([\w-]+|\*)(,~?[\w-]+\.([\w-]+|\*))*)?#\$\?#([^\s^+].*)/
  280. ),
  281. rule.match(
  282. /^(~?[\w-]+\.([\w-]+|\*)(,~?[\w-]+\.([\w-]+|\*))*)?#@\$\?#([^\s^+].*)/
  283. ),
  284. ]);
  285. if (result && result[2] && extraChecker(result[2])) {
  286. return {
  287. black: result[0],
  288. type: result[1],
  289. sel: result[2],
  290. };
  291. }
  292. }
  293. function logger(type, ...data) {
  294. const logapi = new XMLHttpRequest();
  295. logapi.open("POST", "https://lemon399-bitbucket-io.vercel.app/api/log");
  296. logapi.send(
  297. JSON.stringify({
  298. type: type,
  299. data: data,
  300. })
  301. );
  302. switch (type) {
  303. case "info":
  304. console.info(...data);
  305. break;
  306. case "warn":
  307. console.warn(...data);
  308. break;
  309. case "error":
  310. console.error(...data);
  311. break;
  312. case "data":
  313. console.table(data[0]);
  314. break;
  315. case "color":
  316. console.log(
  317. `%c ${data[0]} `,
  318. `color: white; background: ${data[1]}; border-radius: .75em; padding: .25em, .5em`
  319. );
  320. break;
  321. case "count":
  322. console.count(data[0]);
  323. break;
  324. }
  325. }
  326.  
  327. const selectors = makeRuleBox(),
  328. extSelectors = makeRuleBox(),
  329. styles = makeRuleBox(),
  330. extStyles = makeRuleBox(),
  331. values = {
  332. get black() {
  333. const v = tm.GM_getValue("ajs_disabled_domains", "");
  334. return typeof v == "string" ? v : "";
  335. },
  336. set black(v) {
  337. v === null
  338. ? tm.GM_deleteValue("ajs_disabled_domains")
  339. : tm.GM_setValue("ajs_disabled_domains", v);
  340. },
  341. get rules() {
  342. let v;
  343. try {
  344. v = tm.GM_getValue("ajs_saved_abprules", "{}");
  345. } catch (error) {
  346. logger("error", "GM_getValue", error.message);
  347. v = "{}";
  348. }
  349. return typeof v == "string" ? JSON.parse(v) : {};
  350. },
  351. set rules(v) {
  352. try {
  353. v === null
  354. ? tm.GM_deleteValue("ajs_saved_abprules")
  355. : tm.GM_setValue("ajs_saved_abprules", JSON.stringify(v));
  356. } catch (error) {
  357. logger("error", "GM_setValue", error.message);
  358. tm.GM_deleteValue("ajs_saved_abprules");
  359. }
  360. },
  361. get time() {
  362. const v = tm.GM_getValue("ajs_rules_ver", "0/0/0 0:0:0");
  363. return typeof v == "string" ? v : "0/0/0 0:0:0";
  364. },
  365. set time(v) {
  366. v === null
  367. ? tm.GM_deleteValue("ajs_rules_ver")
  368. : tm.GM_setValue("ajs_rules_ver", v);
  369. },
  370. get etags() {
  371. const v = tm.GM_getValue("ajs_rules_etags", "{}");
  372. return typeof v == "string" ? JSON.parse(v) : {};
  373. },
  374. set etags(v) {
  375. v === null
  376. ? tm.GM_deleteValue("ajs_rules_etags")
  377. : tm.GM_setValue("ajs_rules_etags", JSON.stringify(v));
  378. },
  379. },
  380. data = {
  381. disabled: false,
  382. updating: false,
  383. receivedRules: "",
  384. allRules: "",
  385. genericStyle: document.createElement("style"),
  386. presetCss:
  387. " {display: none !important;width: 0 !important;height: 0 !important;} ",
  388. supportedCount: 0,
  389. appliedCount: 0,
  390. isFrame: tm.unsafeWindow.self !== tm.unsafeWindow.top,
  391. isClean: false,
  392. mutex: "__lemon__abp__parser__$__",
  393. debug: true,
  394. timeout: 5000,
  395. },
  396. menus = {
  397. disable: {
  398. id: undefined,
  399. get text() {
  400. return data.disabled ? "在此网站启用拦截" : "在此网站禁用拦截";
  401. },
  402. },
  403. update: {
  404. id: undefined,
  405. get text() {
  406. const time = values.time;
  407. return data.updating
  408. ? "正在更新..."
  409. : `点击更新: ${time.slice(0, 1) === "0" ? "未知时间" : time}`;
  410. },
  411. },
  412. count: {
  413. id: undefined,
  414. get text() {
  415. return data.isClean
  416. ? "已清空,点击刷新重新加载规则"
  417. : `点击清空: ${data.appliedCount} / ${data.supportedCount} / ${
  418. data.allRules.split("\n").length
  419. }`;
  420. },
  421. },
  422. };
  423. function gmMenu(name, cb) {
  424. if (
  425. typeof tm.GM_registerMenuCommand !== "function" ||
  426. typeof tm.GM_unregisterMenuCommand !== "function" ||
  427. data.isFrame
  428. )
  429. return false;
  430. const id = menus[name].id;
  431. if (typeof id !== "undefined") {
  432. logger("color", `删除菜单 ${name}`, "red");
  433. tm.GM_unregisterMenuCommand(id);
  434. menus[name].id = undefined;
  435. }
  436. if (typeof cb == "function") {
  437. logger("color", `添加菜单 ${name}`, "green");
  438. menus[name].id = tm.GM_registerMenuCommand(menus[name].text, cb);
  439. }
  440. logger("data", {
  441. 菜单: "ID",
  442. disable: menus.disable.id,
  443. update: menus.update.id,
  444. count: menus.count.id,
  445. });
  446. return typeof menus[name].id !== "undefined";
  447. }
  448. function promiseXhr(details) {
  449. return __awaiter(this, void 0, void 0, function* () {
  450. let loaded = false;
  451. logger("info", "XHR 配置", details);
  452. try {
  453. return yield new Promise((resolve, reject) => {
  454. tm.GM_xmlhttpRequest(
  455. Object.assign(
  456. {
  457. onload(e) {
  458. loaded = true;
  459. resolve(e);
  460. },
  461. onabort: reject.bind(null, "abort"),
  462. onerror: reject.bind(null, "error"),
  463. ontimeout: reject.bind(null, "timeout"),
  464. onreadystatechange(e_1) {
  465. // X 浏览器超时中断
  466. if (e_1.readyState === 4) {
  467. setTimeout(() => {
  468. if (!loaded) reject("X timeout");
  469. }, 300);
  470. }
  471. // Via 浏览器超时中断,不给成功状态...
  472. if (e_1.readyState === 3) {
  473. setTimeout(() => {
  474. if (!loaded) reject("Via timeout");
  475. }, data.timeout);
  476. }
  477. },
  478. timeout: data.timeout,
  479. },
  480. details
  481. )
  482. );
  483. });
  484. } catch (r) {
  485. logger("error", "promiseXhr: ", {
  486. 错误: r,
  487. 地址: details.url,
  488. });
  489. }
  490. });
  491. }
  492. function storeRule(name, resp) {
  493. const savedRules = values.rules,
  494. savedEtags = values.etags,
  495. ruleCount = {};
  496. logger("info", "XHR 响应", resp.responseText.length);
  497. if (resp.responseHeaders) {
  498. const etag = getEtag(resp.responseHeaders);
  499. if (etag) {
  500. savedEtags[name] = etag;
  501. values.etags = savedEtags;
  502. }
  503. }
  504. if (resp.responseText) {
  505. savedRules[name] = resp.responseText;
  506. values.rules = savedRules;
  507. if (Object.keys(values.rules).length === 0) {
  508. logger("warn", "存储失败,放入临时变量");
  509. data.receivedRules += "\n" + resp.responseText + "\n";
  510. }
  511. }
  512. {
  513. Object.keys(savedRules).forEach((k) => {
  514. ruleCount[k] = savedRules[k].length;
  515. });
  516. logger("data", {
  517. etags: savedEtags,
  518. rules: ruleCount,
  519. });
  520. }
  521. }
  522. function fetchRuleBody(name, url) {
  523. return __awaiter(this, void 0, void 0, function* () {
  524. const getResp = yield promiseXhr({
  525. method: "GET",
  526. responseType: "text",
  527. url: url,
  528. });
  529. if (getResp) {
  530. storeRule(name, getResp);
  531. return true;
  532. } else return false;
  533. });
  534. }
  535. function fetchRule(url) {
  536. var _a;
  537. const name =
  538. (_a = getName(url)) !== null && _a !== void 0
  539. ? _a
  540. : `${url.length}.${url.slice(-5)}`;
  541. logger("info", `在线规则 ${name} 开始`);
  542. return new Promise((resolve, reject) =>
  543. __awaiter(this, void 0, void 0, function* () {
  544. var _b, _c, _d, _e;
  545. if (!name) reject();
  546. const headResp = yield promiseXhr({
  547. method: "HEAD",
  548. responseType: "text",
  549. url: url,
  550. });
  551. if (!headResp) {
  552. reject();
  553. } else {
  554. logger("info", "XHR HEAD 响应", headResp);
  555. if (headResp.responseText) {
  556. logger("warn", "不支持 HEAD");
  557. storeRule(name, headResp);
  558. resolve();
  559. } else {
  560. const etag = getEtag(
  561. typeof headResp.responseHeaders == "string"
  562. ? headResp.responseHeaders
  563. : (_c = (_b = headResp).getAllResponseHeaders) === null ||
  564. _c === void 0
  565. ? void 0
  566. : _c.call(_b)
  567. ),
  568. savedEtags = values.etags;
  569. logger("data", {
  570. monkey:
  571. typeof headResp.responseHeaders == "string"
  572. ? headResp.responseHeaders
  573. : null,
  574. standard:
  575. (_e = (_d = headResp).getAllResponseHeaders) === null ||
  576. _e === void 0
  577. ? void 0
  578. : _e.call(_d),
  579. parsed: etag,
  580. });
  581. if (etag) {
  582. logger("data", Object.assign({ HEAD: etag }, savedEtags));
  583. if (etag !== savedEtags[name]) {
  584. (yield fetchRuleBody(name, url)) ? resolve() : reject();
  585. } else reject();
  586. } else {
  587. logger("warn", "不提供 ETAG");
  588. (yield fetchRuleBody(name, url)) ? resolve() : reject();
  589. }
  590. }
  591. }
  592. })
  593. );
  594. }
  595. function fetchRules() {
  596. return __awaiter(this, void 0, void 0, function* () {
  597. data.updating = true;
  598. gmMenu("update", () => undefined);
  599. logger("info", `在线规则 ${onlineRules.length} 个地址`);
  600. for (const url of onlineRules)
  601. yield fetchRule(url).catch((r) => {
  602. logger("error", "fetchRule: ", {
  603. 错误: r,
  604. 地址: url,
  605. });
  606. });
  607. logger("info", "在线规则下载结束");
  608. values.time = new Date().toLocaleString("zh-CN");
  609. gmMenu("count", cleanRules);
  610. initRules();
  611. });
  612. }
  613. function performUpdate(force) {
  614. if (force) {
  615. logger("color", "无条件更新", "darkslateblue");
  616. return fetchRules();
  617. } else {
  618. logger("info", "日期变更更新", getDay(values.time), new Date().getDate());
  619. return getDay(values.time) !== new Date().getDate()
  620. ? fetchRules()
  621. : Promise.resolve();
  622. }
  623. }
  624. function switchDisabledStat() {
  625. const disaList = values.black.split(","),
  626. disaResult = disaList.includes(location.hostname);
  627. data.disabled = !disaResult;
  628. if (data.disabled) {
  629. disaList.push(location.hostname);
  630. } else {
  631. disaList.splice(disaList.indexOf(location.hostname), 1);
  632. }
  633. values.black = disaList.join(",");
  634. gmMenu("disable", switchDisabledStat);
  635. }
  636. function checkDisableStat() {
  637. const disaResult = values.black.split(",").includes(location.hostname);
  638. logger("data", {
  639. key: "black",
  640. value: values.black.split(","),
  641. }),
  642. logger("info", "禁用: ", location.hostname, disaResult);
  643. data.disabled = disaResult;
  644. gmMenu("disable", switchDisabledStat);
  645. return disaResult;
  646. }
  647. function initRules() {
  648. const abpRules = values.rules;
  649. if (typeof tm.GM_getResourceText == "function") {
  650. onlineRules.forEach((url) => {
  651. var _a;
  652. const ruleName = getName(url),
  653. resName = ruleName.split(".")[0];
  654. let resRule;
  655. try {
  656. resRule = tm.GM_getResourceText(resName);
  657. } catch (error) {
  658. logger("error", "GM_getResourceText", error.message);
  659. resRule = "";
  660. }
  661. logger("data", {
  662. 规则: ruleName,
  663. values:
  664. (_a = abpRules[ruleName]) === null || _a === void 0
  665. ? void 0
  666. : _a.length,
  667. resource:
  668. resRule === null || resRule === void 0 ? void 0 : resRule.length,
  669. });
  670. if (resRule && !abpRules[ruleName]) abpRules[ruleName] = resRule;
  671. });
  672. }
  673. const abpKeys = Object.keys(abpRules);
  674. {
  675. const ruleCount = {};
  676. logger("color", `已存储规则: ${abpKeys.length}`, "royalblue");
  677. abpKeys.forEach((k) => {
  678. ruleCount[k] = abpRules[k].length;
  679. });
  680. logger("data", Object.assign({ 规则: "数量" }, ruleCount));
  681. }
  682. abpKeys.forEach((name) => {
  683. data.receivedRules += "\n" + abpRules[name] + "\n";
  684. });
  685. data.allRules = defaultRules + data.receivedRules;
  686. data.allRules += testRules;
  687. if (abpKeys.length !== 0) {
  688. data.updating = false;
  689. gmMenu("update", () =>
  690. __awaiter(this, void 0, void 0, function* () {
  691. yield performUpdate(true);
  692. location.reload();
  693. })
  694. );
  695. }
  696. return data.receivedRules.length;
  697. }
  698. function styleApply() {
  699. const css =
  700. styles.apply +
  701. (selectors.apply.length > 0 ? selectors.apply + data.presetCss : ""),
  702. ecss =
  703. extStyles.apply +
  704. (extSelectors.apply.length > 0
  705. ? extSelectors.apply + data.presetCss
  706. : "");
  707. if (css.length > 0) {
  708. if (typeof tm.GM_addStyle == "function") {
  709. logger("color", "GM_addStyle", "green");
  710. tm.GM_addStyle(css);
  711. } else {
  712. logger("color", "普通 <style>", "red");
  713. runNeed(
  714. () => !!document.documentElement,
  715. () => {
  716. data.genericStyle.textContent = css;
  717. document.documentElement.appendChild(data.genericStyle);
  718. }
  719. );
  720. }
  721. }
  722. logger(
  723. "info",
  724. "ExtendedCss: ",
  725. typeof ExtendedCss__default.default == "function"
  726. );
  727. if (ecss.length > 0)
  728. new ExtendedCss__default.default({ styleSheet: ecss }).apply();
  729. }
  730. function cleanRules() {
  731. if (confirm(`是否清空存储规则 (${Object.keys(values.rules).length}) ?`)) {
  732. values.rules = {};
  733. values.time = "0/0/0 0:0:0";
  734. values.etags = {};
  735. data.appliedCount = 0;
  736. data.supportedCount = 0;
  737. data.allRules = "";
  738. data.isClean = true;
  739. gmMenu("update");
  740. gmMenu("count", () => location.reload());
  741. }
  742. }
  743. function parseRules() {
  744. [selectors, extSelectors].forEach((obj) => {
  745. obj.black
  746. .filter((v) => !obj.white.includes(v))
  747. .forEach((sel) => {
  748. obj.apply += `${obj.apply.length == 0 ? "" : ","}${sel}`;
  749. data.appliedCount++;
  750. });
  751. });
  752. [styles, extStyles].forEach((obj) => {
  753. obj.black
  754. .filter((v) => !obj.white.includes(v))
  755. .forEach((sel) => {
  756. obj.apply += ` ${sel}`;
  757. data.appliedCount++;
  758. });
  759. });
  760. gmMenu("count", cleanRules);
  761. logger("color", "规则分拣完成", "green");
  762. styleApply();
  763. }
  764. function splitRules() {
  765. data.allRules.split("\n").forEach((rule) => {
  766. const ruleObj = ruleSpliter(rule);
  767. let arr = "";
  768. if (typeof ruleObj !== "undefined") {
  769. arr = ruleObj.black ? "black" : "white";
  770. switch (ruleObj.type) {
  771. case 0:
  772. selectors[arr].push(ruleObj.sel);
  773. break;
  774. case 1:
  775. extSelectors[arr].push(ruleObj.sel);
  776. break;
  777. case 2:
  778. styles[arr].push(ruleObj.sel);
  779. break;
  780. case 3:
  781. extStyles[arr].push(ruleObj.sel);
  782. break;
  783. }
  784. data.supportedCount++;
  785. }
  786. });
  787. logger("data", {
  788. 选择器: {
  789. 黑: selectors.black.length,
  790. 白: selectors.white.length,
  791. },
  792. 样式: {
  793. 黑: styles.black.length,
  794. 白: styles.white.length,
  795. },
  796. 扩展选择器: {
  797. 黑: extSelectors.black.length,
  798. 白: extSelectors.white.length,
  799. },
  800. 扩展样式: {
  801. 黑: extStyles.black.length,
  802. 白: extStyles.white.length,
  803. },
  804. });
  805. parseRules();
  806. }
  807. function main() {
  808. return __awaiter(this, void 0, void 0, function* () {
  809. {
  810. logger("count", "执行次数");
  811. logger("info", "iframe: ", data.isFrame);
  812. logger("data", {
  813. GM_getValue: typeof tm.GM_getValue == "function" ? "OK" : "NO",
  814. GM_deleteValue: typeof tm.GM_deleteValue == "function" ? "OK" : "NO",
  815. GM_setValue: typeof tm.GM_setValue == "function" ? "OK" : "NO",
  816. GM_registerMenuCommand:
  817. typeof tm.GM_registerMenuCommand == "function" ? "OK" : "NO",
  818. GM_unregisterMenuCommand:
  819. typeof tm.GM_unregisterMenuCommand == "function" ? "OK" : "NO",
  820. GM_xmlhttpRequest:
  821. typeof tm.GM_xmlhttpRequest == "function" ? "OK" : "NO",
  822. GM_getResourceText:
  823. typeof tm.GM_getResourceText == "function" ? "OK" : "NO",
  824. GM_addStyle: typeof tm.GM_addStyle == "function" ? "OK" : "NO",
  825. });
  826. logger("data", {
  827. black: values.black,
  828. rules: Object.keys(values.rules).join(),
  829. time: values.time,
  830. etags: Object.keys(values.etags).join(),
  831. });
  832. cleanRules();
  833. }
  834. if (checkDisableStat() || (initRules() === 0 && data.isFrame)) return;
  835. if (data.receivedRules.length === 0) yield performUpdate(true);
  836. splitRules();
  837. yield performUpdate(false);
  838. if (data.appliedCount === 0) splitRules();
  839. });
  840. }
  841. function runOnce(key, func, ...params) {
  842. if (key in tm.unsafeWindow) return;
  843. tm.unsafeWindow[key] = true;
  844. func === null || func === void 0 ? void 0 : func.apply(this, params);
  845. }
  846. runOnce(data.mutex, main);
  847. })(
  848. {
  849. GM_getValue: typeof GM_getValue == "function" ? GM_getValue : undefined,
  850. GM_deleteValue:
  851. typeof GM_deleteValue == "function" ? GM_deleteValue : undefined,
  852. GM_setValue: typeof GM_setValue == "function" ? GM_setValue : undefined,
  853. unsafeWindow: typeof unsafeWindow == "object" ? unsafeWindow : window,
  854. GM_registerMenuCommand:
  855. typeof GM_registerMenuCommand == "function"
  856. ? GM_registerMenuCommand
  857. : undefined,
  858. GM_unregisterMenuCommand:
  859. typeof GM_unregisterMenuCommand == "function"
  860. ? GM_unregisterMenuCommand
  861. : undefined,
  862. GM_xmlhttpRequest:
  863. typeof GM_xmlhttpRequest == "function" ? GM_xmlhttpRequest : undefined,
  864. GM_getResourceText:
  865. typeof GM_getResourceText == "function" ? GM_getResourceText : undefined,
  866. GM_addStyle: typeof GM_addStyle == "function" ? GM_addStyle : undefined,
  867. },
  868. ExtendedCss
  869. );