套壳油猴的广告拦截脚本

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

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

  1. // ==UserScript==
  2. // @name AdBlock Script for WebView
  3. // @name:zh-CN 套壳油猴的广告拦截脚本
  4. // @author Lemon399
  5. // @version 2.2.3
  6. // @description Parse ABP Cosmetic rules to CSS and apply it.
  7. // @description:zh-CN 将 ABP 中的元素隐藏规则转换为 CSS 使用
  8. // @require https://gf.qytechs.cn/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. // @history 2.2.0 更改规则地址数据类型,禁用后自动刷新页面
  37. // @history 2.2.1 修复多个严重错误
  38. // @history 2.2.2 转换 :style()
  39. // @history 2.2.3 识别使用扩充的选择器的 ## 和 #@#
  40. // ==/UserScript==
  41.  
  42. (function (vm, ExtendedCss) {
  43. "use strict";
  44.  
  45. function __awaiter(thisArg, _arguments, P, generator) {
  46. function adopt(value) {
  47. return value instanceof P
  48. ? value
  49. : new P(function (resolve) {
  50. resolve(value);
  51. });
  52. }
  53. return new (P || (P = Promise))(function (resolve, reject) {
  54. function fulfilled(value) {
  55. try {
  56. step(generator.next(value));
  57. } catch (e) {
  58. reject(e);
  59. }
  60. }
  61. function rejected(value) {
  62. try {
  63. step(generator["throw"](value));
  64. } catch (e) {
  65. reject(e);
  66. }
  67. }
  68. function step(result) {
  69. result.done
  70. ? resolve(result.value)
  71. : adopt(result.value).then(fulfilled, rejected);
  72. }
  73. step((generator = generator.apply(thisArg, _arguments || [])).next());
  74. });
  75. }
  76.  
  77. const onlineRules = [
  78. {
  79. 标识: "jiekouAD",
  80. 地址: "https://code.gitlink.org.cn/damengzhu/banad/raw/branch/main/jiekouAD.txt",
  81. 在线更新: !!1,
  82. },
  83. {
  84. 标识: "abpmerge",
  85. 地址: "https://code.gitlink.org.cn/damengzhu/abpmerge/raw/branch/main/abpmerge.txt",
  86. 在线更新: !!0,
  87. },
  88. ],
  89. defaultRules = `
  90. ! 没有 ## #@# #?# #@?#
  91. ! #$# #@$# #$?# #@$?# 的行和
  92. ! 开头为 ! 的行会忽略
  93. !
  94. ! 由于语法限制,内置规则中
  95. ! 一个反斜杠需要改成两个,像这样 \\
  96. !
  97. ! 若要修改地址,请注意同步修改
  98. ! 头部的 @connect @resource
  99.  
  100. `;
  101.  
  102. function isValidConfig(obj, ref) {
  103. let valid = typeof obj == "object";
  104. if (valid)
  105. Object.getOwnPropertyNames(obj).forEach((k) => {
  106. if (!ref.hasOwnProperty(k)) valid = false;
  107. });
  108. return valid;
  109. }
  110. function sleep(time) {
  111. return new Promise((resolve) => setTimeout(resolve, time));
  112. }
  113. function runNeed(condition, fn, option, ...args) {
  114. let ok = false;
  115. const defaultOption = {
  116. count: 20,
  117. delay: 200,
  118. failFn: () => null,
  119. };
  120. if (isValidConfig(option, defaultOption))
  121. Object.assign(defaultOption, option);
  122. new Promise((resolve, reject) =>
  123. __awaiter(this, void 0, void 0, function* () {
  124. for (let c = 0; !ok && c < defaultOption.count; c++) {
  125. yield sleep(defaultOption.delay);
  126. ok = condition.call(null, c + 1);
  127. }
  128. ok ? resolve() : reject();
  129. })
  130. ).then(fn.bind(null, ...args), defaultOption.failFn);
  131. }
  132. function getEtag(header) {
  133. const reer = /etag: \"(\w+)\"/.exec(header);
  134. // WebMonkey 系
  135. const reerWM = /Etag: \[\"(\w+)\"\]/.exec(header);
  136. // 书签地球
  137. const reerDQ = /Etag=\"(\w+)\"/.exec(header);
  138. return reer ? reer[1] : reerWM ? reerWM[1] : reerDQ ? reerDQ[1] : null;
  139. }
  140. function getDay(date) {
  141. const reer = /\/(\d{1,2}) /.exec(date);
  142. return reer ? parseInt(reer[1]) : 0;
  143. }
  144. function makeRuleBox() {
  145. return {
  146. black: [],
  147. white: [],
  148. apply: [],
  149. };
  150. }
  151. function domainChecker(domains) {
  152. const results = [],
  153. urlSuffix = /\.+?[\w-]+$/.exec(location.hostname);
  154. let mostMatch = {
  155. long: 0,
  156. result: false,
  157. };
  158. domains.forEach((domain) => {
  159. if (domain.endsWith(".*") && Array.isArray(urlSuffix)) {
  160. domain = domain.replace(".*", urlSuffix[0]);
  161. }
  162. const invert = domain.startsWith("~");
  163. if (invert) domain = domain.slice(1);
  164. const result = location.hostname.endsWith(domain);
  165. results.push(result !== invert);
  166. if (result) {
  167. if (domain.length > mostMatch.long) {
  168. mostMatch = {
  169. long: domain.length,
  170. result: result !== invert,
  171. };
  172. }
  173. }
  174. });
  175. return mostMatch.long > 0 ? mostMatch.result : results.includes(true);
  176. }
  177. function ruleChecker(matches) {
  178. const index = matches.findIndex((i) => i !== null);
  179. if (
  180. index >= 0 &&
  181. (!matches[index][1] || domainChecker(matches[index][1].split(",")))
  182. ) {
  183. return [index % 2 == 0, Math.floor(index / 2), matches[index].pop()];
  184. }
  185. }
  186. function hasSome(str, arr) {
  187. return arr.some((word) => str.includes(word));
  188. }
  189. function ruleSpliter(rule) {
  190. // ## -> #?#
  191. if (
  192. /(\w|^)#@?#/.test(rule) &&
  193. hasSome(rule, [
  194. ":has(",
  195. ":-abp-has(",
  196. "[-ext-has=",
  197. ":has-text(",
  198. "contains(",
  199. "-abp-contains(",
  200. "[-ext-contains=",
  201. "matches-css(",
  202. "[-ext-matches-css=",
  203. "matches-css-before(",
  204. "[-ext-matches-css-before=",
  205. "matches-css-after(",
  206. "[-ext-matches-css-after=",
  207. "matches-attr(",
  208. "nth-ancestor(",
  209. "upward(",
  210. "xpath(",
  211. "remove()",
  212. "not(",
  213. "if-not(",
  214. ])
  215. ) {
  216. rule = rule.replace(/(\w|^)##/, "$1#?#").replace(/(\w|^)#@#/, "$1#@?#");
  217. }
  218. // :style(...) 转换
  219. // example.com#?##id:style(color: red)
  220. // example.com#$?##id { color: red }
  221. if (rule.includes(":style(")) {
  222. rule = rule
  223. .replace(/(\w|^)##/, "$1#$#")
  224. .replace(/(\w|^)#@#/, "$1#@$#")
  225. .replace(/(\w|^)#\?#/, "$1#$?#")
  226. .replace(/(\w|^)#@\?#/, "$1#@$?#")
  227. .replace(/:style\(/, " { ")
  228. .replace(/\)$/, " }");
  229. }
  230. const result = ruleChecker([
  231. rule.match(
  232. /^(~?[\w-]+(\.[\w-]+)*(\.[\w-]+|\.\*)(,~?[\w-]+(\.[\w-]+)*(\.[\w-]+|\.\*))*)?##([^\s^+].*)/
  233. ),
  234. rule.match(
  235. /^(~?[\w-]+(\.[\w-]+)*(\.[\w-]+|\.\*)(,~?[\w-]+(\.[\w-]+)*(\.[\w-]+|\.\*))*)?#@#([^\s+].*)/
  236. ),
  237. rule.match(
  238. /^(~?[\w-]+(\.[\w-]+)*(\.[\w-]+|\.\*)(,~?[\w-]+(\.[\w-]+)*(\.[\w-]+|\.\*))*)?#\?#([^\s].*)/
  239. ),
  240. rule.match(
  241. /^(~?[\w-]+(\.[\w-]+)*(\.[\w-]+|\.\*)(,~?[\w-]+(\.[\w-]+)*(\.[\w-]+|\.\*))*)?#@\?#([^\s].*)/
  242. ),
  243. rule.match(
  244. /^(~?[\w-]+(\.[\w-]+)*(\.[\w-]+|\.\*)(,~?[\w-]+(\.[\w-]+)*(\.[\w-]+|\.\*))*)?#\$#([^\s].*)/
  245. ),
  246. rule.match(
  247. /^(~?[\w-]+(\.[\w-]+)*(\.[\w-]+|\.\*)(,~?[\w-]+(\.[\w-]+)*(\.[\w-]+|\.\*))*)?#@\$#([^\s].*)/
  248. ),
  249. rule.match(
  250. /^(~?[\w-]+(\.[\w-]+)*(\.[\w-]+|\.\*)(,~?[\w-]+(\.[\w-]+)*(\.[\w-]+|\.\*))*)?#\$\?#([^\s].*)/
  251. ),
  252. rule.match(
  253. /^(~?[\w-]+(\.[\w-]+)*(\.[\w-]+|\.\*)(,~?[\w-]+(\.[\w-]+)*(\.[\w-]+|\.\*))*)?#@\$\?#([^\s].*)/
  254. ),
  255. ]);
  256. if (
  257. result &&
  258. result[2] &&
  259. !hasSome(result[2], [
  260. ":matches-path(",
  261. ":min-text-length(",
  262. ":watch-attr(",
  263. ":-abp-properties(",
  264. ":matches-property(",
  265. ])
  266. ) {
  267. return {
  268. black: result[0],
  269. type: result[1],
  270. sel: result[2],
  271. };
  272. }
  273. }
  274.  
  275. const selectors = makeRuleBox(),
  276. extSelectors = makeRuleBox(),
  277. styles = makeRuleBox(),
  278. extStyles = makeRuleBox(),
  279. values = {
  280. get black() {
  281. const v = vm.GM_getValue("ajs_disabled_domains", "");
  282. return typeof v == "string" ? v : "";
  283. },
  284. set black(v) {
  285. v === null
  286. ? vm.GM_deleteValue("ajs_disabled_domains")
  287. : vm.GM_setValue("ajs_disabled_domains", v);
  288. },
  289. get rules() {
  290. let v;
  291. try {
  292. v = vm.GM_getValue("ajs_saved_abprules", "{}");
  293. } catch (error) {
  294. v = "{}";
  295. }
  296. return typeof v == "string" ? JSON.parse(v) : {};
  297. },
  298. set rules(v) {
  299. try {
  300. v === null
  301. ? vm.GM_deleteValue("ajs_saved_abprules")
  302. : vm.GM_setValue("ajs_saved_abprules", JSON.stringify(v));
  303. } catch (error) {
  304. vm.GM_deleteValue("ajs_saved_abprules");
  305. }
  306. },
  307. get time() {
  308. const v = vm.GM_getValue("ajs_rules_ver", "0/0/0 0:0:0");
  309. return typeof v == "string" ? v : "0/0/0 0:0:0";
  310. },
  311. set time(v) {
  312. v === null
  313. ? vm.GM_deleteValue("ajs_rules_ver")
  314. : vm.GM_setValue("ajs_rules_ver", v);
  315. },
  316. get etags() {
  317. const v = vm.GM_getValue("ajs_rules_etags", "{}");
  318. return typeof v == "string" ? JSON.parse(v) : {};
  319. },
  320. set etags(v) {
  321. v === null
  322. ? vm.GM_deleteValue("ajs_rules_etags")
  323. : vm.GM_setValue("ajs_rules_etags", JSON.stringify(v));
  324. },
  325. },
  326. data = {
  327. disabled: false,
  328. updating: false,
  329. receivedRules: "",
  330. allRules: "",
  331. presetCss:
  332. " {display: none !important;width: 0 !important;height: 0 !important;} ",
  333. supportedCount: 0,
  334. appliedCount: 0,
  335. isFrame: vm.unsafeWindow.self !== vm.unsafeWindow.top,
  336. isClean: false,
  337. mutex: "__lemon__abp__parser__$__",
  338. timeout: 5000,
  339. xTimeout: 700,
  340. },
  341. menus = {
  342. disable: {
  343. id: undefined,
  344. get text() {
  345. return data.disabled ? "在此网站启用拦截" : "在此网站禁用拦截";
  346. },
  347. },
  348. update: {
  349. id: undefined,
  350. get text() {
  351. const time = values.time;
  352. return data.updating
  353. ? "正在更新..."
  354. : `点击更新: ${time.slice(0, 1) === "0" ? "未知时间" : time}`;
  355. },
  356. },
  357. count: {
  358. id: undefined,
  359. get text() {
  360. return data.isClean
  361. ? "已清空,点击刷新重新加载规则"
  362. : `点击清空: ${data.appliedCount} / ${data.supportedCount} / ${
  363. data.allRules.split("\n").length
  364. }`;
  365. },
  366. },
  367. };
  368. function gmMenu(name, cb) {
  369. if (
  370. typeof vm.GM_registerMenuCommand != "function" ||
  371. typeof vm.GM_unregisterMenuCommand != "function" ||
  372. data.isFrame
  373. )
  374. return false;
  375. if (typeof menus[name].id != "undefined") {
  376. vm.GM_unregisterMenuCommand(menus[name].id);
  377. menus[name].id = undefined;
  378. }
  379. if (typeof cb == "function") {
  380. menus[name].id = vm.GM_registerMenuCommand(menus[name].text, cb);
  381. }
  382. return typeof menus[name].id != "undefined";
  383. }
  384. function promiseXhr(details) {
  385. return __awaiter(this, void 0, void 0, function* () {
  386. let loaded = false;
  387. try {
  388. return yield new Promise((resolve, reject) => {
  389. vm.GM_xmlhttpRequest(
  390. Object.assign(
  391. {
  392. onload(e) {
  393. loaded = true;
  394. resolve(e);
  395. },
  396. onabort: reject.bind(null, "abort"),
  397. onerror: reject.bind(null, "error"),
  398. ontimeout: reject.bind(null, "timeout"),
  399. onreadystatechange(e_1) {
  400. // X 浏览器超时中断
  401. if (e_1.readyState === 4) {
  402. setTimeout(() => {
  403. if (!loaded) reject("X timeout");
  404. }, data.xTimeout);
  405. }
  406. // Via 浏览器超时中断,不给成功状态...
  407. if (e_1.readyState === 3) {
  408. setTimeout(() => {
  409. if (!loaded) reject("Via timeout");
  410. }, data.timeout);
  411. }
  412. },
  413. timeout: data.timeout,
  414. },
  415. details
  416. )
  417. );
  418. });
  419. } catch (error) {}
  420. });
  421. }
  422. function storeRule(name, resp) {
  423. const savedRules = values.rules,
  424. savedEtags = values.etags;
  425. if (resp.responseHeaders) {
  426. const etag = getEtag(resp.responseHeaders);
  427. if (etag) {
  428. savedEtags[name] = etag;
  429. values.etags = savedEtags;
  430. }
  431. }
  432. if (resp.responseText) {
  433. savedRules[name] = resp.responseText;
  434. values.rules = savedRules;
  435. if (Object.keys(values.rules).length === 0) {
  436. data.receivedRules += "\n" + resp.responseText + "\n";
  437. }
  438. }
  439. }
  440. function fetchRuleBody(rule) {
  441. var _a;
  442. return __awaiter(this, void 0, void 0, function* () {
  443. const getResp = yield promiseXhr({
  444. method: "GET",
  445. responseType: "text",
  446. url: rule.地址,
  447. });
  448. if (
  449. getResp &&
  450. (getResp === null || getResp === void 0
  451. ? void 0
  452. : getResp.responseText) &&
  453. ((_a = getResp.responseText) === null || _a === void 0
  454. ? void 0
  455. : _a.length) > 0
  456. ) {
  457. storeRule(rule.标识, getResp);
  458. return true;
  459. } else return false;
  460. });
  461. }
  462. function fetchRule(rule) {
  463. return new Promise((resolve, reject) =>
  464. __awaiter(this, void 0, void 0, function* () {
  465. var _a, _b, _c;
  466. const headResp = yield promiseXhr({
  467. method: "HEAD",
  468. responseType: "text",
  469. url: rule.地址,
  470. });
  471. if (!headResp) {
  472. reject();
  473. } else {
  474. if (
  475. (headResp === null || headResp === void 0
  476. ? void 0
  477. : headResp.responseText) &&
  478. ((_a = headResp.responseText) === null || _a === void 0
  479. ? void 0
  480. : _a.length) > 0
  481. ) {
  482. storeRule(rule.标识, headResp);
  483. resolve();
  484. } else {
  485. const etag = getEtag(
  486. typeof headResp.responseHeaders == "string"
  487. ? headResp.responseHeaders
  488. : (_c = (_b = headResp).getAllResponseHeaders) === null ||
  489. _c === void 0
  490. ? void 0
  491. : _c.call(_b)
  492. ),
  493. savedEtags = values.etags;
  494. if (etag) {
  495. if (etag !== savedEtags[rule.标识]) {
  496. (yield fetchRuleBody(rule)) ? resolve() : reject();
  497. } else reject();
  498. } else {
  499. (yield fetchRuleBody(rule)) ? resolve() : reject();
  500. }
  501. }
  502. }
  503. })
  504. );
  505. }
  506. function fetchRules() {
  507. return __awaiter(this, void 0, void 0, function* () {
  508. data.updating = true;
  509. gmMenu("update", () => undefined);
  510. for (const rule of onlineRules) {
  511. rule.在线更新 && (yield fetchRule(rule).catch((error) => {}));
  512. }
  513. values.time = new Date().toLocaleString("zh-CN");
  514. gmMenu("count", cleanRules);
  515. initRules();
  516. });
  517. }
  518. function performUpdate(force) {
  519. if (force) {
  520. return fetchRules();
  521. } else {
  522. return getDay(values.time) !== new Date().getDate()
  523. ? fetchRules()
  524. : Promise.resolve();
  525. }
  526. }
  527. function switchDisabledStat() {
  528. const disaList = values.black.length === 0 ? [] : values.black.split(",");
  529. data.disabled = !disaList.includes(location.hostname);
  530. if (data.disabled) {
  531. disaList.push(location.hostname);
  532. } else {
  533. disaList.splice(disaList.indexOf(location.hostname), 1);
  534. }
  535. values.black = disaList.join(",");
  536. location.reload();
  537. }
  538. function checkDisableStat() {
  539. const disaResult = values.black.split(",").includes(location.hostname);
  540. data.disabled = disaResult;
  541. gmMenu("disable", switchDisabledStat);
  542. return disaResult;
  543. }
  544. function initRules() {
  545. const abpRules = values.rules;
  546. if (typeof vm.GM_getResourceText == "function") {
  547. onlineRules.forEach((rule) => {
  548. let resRule;
  549. try {
  550. resRule = vm.GM_getResourceText(rule.标识);
  551. } catch (error) {
  552. resRule = "";
  553. }
  554. if (resRule && !abpRules[rule.标识]) abpRules[rule.标识] = resRule;
  555. });
  556. }
  557. const abpKeys = Object.keys(abpRules);
  558. abpKeys.forEach((name) => {
  559. data.receivedRules += "\n" + abpRules[name] + "\n";
  560. });
  561. data.allRules = defaultRules + data.receivedRules;
  562. if (abpKeys.length !== 0) {
  563. data.updating = false;
  564. gmMenu("update", () =>
  565. __awaiter(this, void 0, void 0, function* () {
  566. yield performUpdate(true);
  567. location.reload();
  568. })
  569. );
  570. }
  571. return data.receivedRules.length;
  572. }
  573. function styleApply() {
  574. const css =
  575. styles.apply.join(" ") +
  576. (selectors.apply.length > 0
  577. ? selectors.apply.join() + data.presetCss
  578. : ""),
  579. ecss =
  580. extStyles.apply.join(" ") +
  581. (extSelectors.apply.length > 0
  582. ? extSelectors.apply.join() + data.presetCss
  583. : "");
  584. if (css.length > 0) {
  585. if (typeof vm.GM_addStyle == "function") {
  586. vm.GM_addStyle(css);
  587. } else {
  588. runNeed(
  589. () => !!document.documentElement,
  590. () => {
  591. const elem = document.createElement("style");
  592. elem.textContent = css;
  593. document.documentElement.appendChild(elem);
  594. }
  595. );
  596. }
  597. }
  598. if (ecss.length > 0) {
  599. runNeed(
  600. () => !!document.documentElement,
  601. () => new ExtendedCss({ styleSheet: ecss }).apply()
  602. );
  603. }
  604. }
  605. function cleanRules() {
  606. if (confirm(`是否清空存储规则 (${Object.keys(values.rules).length}) ?`)) {
  607. values.rules = {};
  608. values.time = "0/0/0 0:0:0";
  609. values.etags = {};
  610. data.appliedCount = 0;
  611. data.supportedCount = 0;
  612. data.allRules = "";
  613. data.isClean = true;
  614. gmMenu("update");
  615. gmMenu("count", () => location.reload());
  616. }
  617. }
  618. function parseRules() {
  619. [selectors, extSelectors].forEach((obj) => {
  620. obj.black
  621. .filter((v) => !obj.white.includes(v))
  622. .forEach((sel) => {
  623. obj.apply.push(sel);
  624. data.appliedCount++;
  625. });
  626. });
  627. [styles, extStyles].forEach((obj) => {
  628. obj.black
  629. .filter((v) => !obj.white.includes(v))
  630. .forEach((sel) => {
  631. obj.apply.push(sel);
  632. data.appliedCount++;
  633. });
  634. });
  635. gmMenu("count", cleanRules);
  636. styleApply();
  637. }
  638. function splitRules() {
  639. data.allRules.split("\n").forEach((rule) => {
  640. const ruleObj = ruleSpliter(rule);
  641. if (typeof ruleObj != "undefined") {
  642. const arr = ruleObj.black ? "black" : "white";
  643. switch (ruleObj.type) {
  644. case 0:
  645. selectors[arr].push(ruleObj.sel);
  646. break;
  647. case 1:
  648. extSelectors[arr].push(ruleObj.sel);
  649. break;
  650. case 2:
  651. styles[arr].push(ruleObj.sel);
  652. break;
  653. case 3:
  654. extStyles[arr].push(ruleObj.sel);
  655. break;
  656. }
  657. data.supportedCount++;
  658. }
  659. });
  660. parseRules();
  661. }
  662. function main() {
  663. return __awaiter(this, void 0, void 0, function* () {
  664. if (checkDisableStat() || (initRules() === 0 && data.isFrame)) return;
  665. if (data.receivedRules.length === 0) yield performUpdate(true);
  666. splitRules();
  667. yield performUpdate(false);
  668. if (data.appliedCount === 0) splitRules();
  669. });
  670. }
  671. function runOnce(key, func, ...params) {
  672. if (key in vm.unsafeWindow) return;
  673. vm.unsafeWindow[key] = true;
  674. func === null || func === void 0 ? void 0 : func(...params);
  675. }
  676. runOnce(data.mutex, main);
  677. })(
  678. {
  679. GM_getValue: typeof GM_getValue == "function" ? GM_getValue : undefined,
  680. GM_deleteValue:
  681. typeof GM_deleteValue == "function" ? GM_deleteValue : undefined,
  682. GM_setValue: typeof GM_setValue == "function" ? GM_setValue : undefined,
  683. unsafeWindow: typeof unsafeWindow == "object" ? unsafeWindow : window,
  684. GM_registerMenuCommand:
  685. typeof GM_registerMenuCommand == "function"
  686. ? GM_registerMenuCommand
  687. : undefined,
  688. GM_unregisterMenuCommand:
  689. typeof GM_unregisterMenuCommand == "function"
  690. ? GM_unregisterMenuCommand
  691. : undefined,
  692. GM_xmlhttpRequest:
  693. typeof GM_xmlhttpRequest == "function" ? GM_xmlhttpRequest : undefined,
  694. GM_getResourceText:
  695. typeof GM_getResourceText == "function" ? GM_getResourceText : undefined,
  696. GM_addStyle: typeof GM_addStyle == "function" ? GM_addStyle : undefined,
  697. },
  698. ExtendedCss
  699. );

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址