添加自定义css和js(广告屏蔽等)

可自定义css选择器屏蔽页面广告,添加js脚本

目前为 2022-07-01 提交的版本。查看 最新版本

  1. // ==UserScript==
  2. // @name 添加自定义css和js(广告屏蔽等)
  3. // @description 可自定义css选择器屏蔽页面广告,添加js脚本
  4. // @namespace _cus_ad_sp
  5. // @version 2.11.2
  6. // @author vizo
  7. // @license MIT
  8. // @include /https?\:\/\/(?!greasyfork).*/
  9. // @run-at document-start
  10. // @grant GM_addStyle
  11. // @grant GM_setValue
  12. // @grant GM_getValue
  13. // @grant GM_deleteValue
  14. // @grant GM_listValues
  15. // @grant GM_addElement
  16. // @grant GM_registerMenuCommand
  17. // @grant GM_setClipboard
  18. // @grant GM_xmlhttpRequest
  19. // @grant GM_download
  20. // @grant unsafeWindow
  21. // @connect *
  22. // @require https://unpkg.com/jquery@3.6.0/dist/jquery.min.js
  23. // @require https://unpkg.com/vue@2.6.14/dist/vue.min.js
  24. // @require https://unpkg.com/tiny-oss@0.5.1/dist/tiny-oss.min.js
  25. // @require https://unpkg.com/vio-utils@2.7.8/index.js
  26. // @require https://unpkg.com/@vizoy/tmk-utils@1.4.1/index.js
  27. // @require https://unpkg.com/@vizoy/sw2@1.0.3/sw2.js
  28. // @require https://unpkg.com/axios@0.27.2/dist/axios.min.js
  29. // @noframes
  30.  
  31. // ==/UserScript==
  32. Object.assign(TMK, vio)
  33. TMK.sw = sw
  34. unsafeWindow.TMK = TMK
  35. unsafeWindow.$j = $
  36. unsafeWindow.axios = axios
  37.  
  38. const html = (s) => {
  39. return s[0]
  40. }
  41.  
  42. const G = {
  43. hostIgnore: /\b(taobao|jd|tmall|bilibili|iviewui)\.com|^(192\.|localhost|127\.)\b|\bbaidu\.com\/s\?wd=|quicker/i,
  44. ifrIgnore: /\b(github|qq|geetest|taobao|aliyundrive|163)\.com|\brecaptcha/i,
  45. linkIgnore: /\b(github|gitee)\.com/i,
  46. tmpTime: 0,
  47. cusStyCnt: '',
  48. html: html`
  49. <div id="wp5rh" v-show="dialog1s">
  50. <div class="mwp_5c" :class="{'expandJS': isExpandJS, 'ld': isLoad}">
  51. <div class="tit1v">设置</div>
  52. <div class="tamp-cfg-modal" v-show="isShowTampModal">
  53. <textarea class="txa-cfg" @change="changeTampCfg" v-model="tampCfgVal" placeholder="oss配置"></textarea>
  54. </div>
  55. <div class="c7d-item">
  56. <p class="stiz">
  57. <span class="s0l">打开面板快捷键</span>
  58. <span class="oss-zbtn" @click="hdlTgOssModal">oss</span>
  59. <span class="view-all-set" @click="hdlViewAllSet">{{ viewSetText }}</span>
  60. </p>
  61. <input type="text" class="inpy" v-model="eKey" placeholder="请输入a-z 用逗号隔开">
  62. </div>
  63. <div class="c7d-item css-item-xh" v-show="!showAllSet">
  64. <p class="stiz">
  65. <span class="s0l">添加css(不含style标签)</span>
  66. <span class="s0r" :class="{on: disCSS}" @click="hdlTgDisCss">{{ disCssText }}</span>
  67. </p>
  68. <textarea class="txtr1z" :class="{'disabled': disCSS}" v-model="texCssVal" :readonly="disCSS" spellcheck="false" placeholder="请输入css代码" @click="hdlExpandJSJs(1)"></textarea>
  69. </div>
  70. <div class="c7d-item js-item-xh" v-show="!showAllSet">
  71. <p class="stiz">
  72. <span class="s0l">添加js(不含script标签)</span>
  73. <span class="s0r" :class="{on: disJS}" @click="hdlTgDisJs">{{ disJsText }}</span>
  74. </p>
  75. <textarea class="txtr1z" :class="{'disabled': disJS}" v-model="texJsVal" :readonly="disJS" spellcheck="false" placeholder="请输入js代码" @click="hdlExpandJSJs(2)"></textarea>
  76. </div>
  77. <div class="c7d-item allset-item" v-show="showAllSet">
  78. <p class="stiz st1k">
  79. <span class="s1p">已添加的网站(可删除) {{ addedNum }} </span>
  80. <span class="s2p imt-c" @click="hdlImportCfg">导入配置</span>
  81. <span class="s2p ext-c" @click="hdlExportCfg">导出配置</span>
  82. </p>
  83. <input type="file" hidden ref="inp_hide" @change="hdlUpFile">
  84. <textarea class="txtr1z" v-model="allAddedText"></textarea>
  85. </div>
  86. <div class="btn-w">
  87. <button class="c5kbtn b2" @click="hdlCancel">取消</button>
  88. <button class="c5kbtn b1" @click="hdlSave">保存</button>
  89. </div>
  90. </div>
  91. </div>
  92. `,
  93. }
  94.  
  95. ;(function() {
  96. if (TMK.isMobile()) return
  97. let k = GM_getValue(`_cfg_${location.host}`) || {}
  98. k = typeof k === 'string' ? JSON.parse(k) : k
  99. if (k.css && !k.disCSS) {
  100. tryAddCusSty(k.css)
  101. }
  102. })();
  103.  
  104. tryAddGmSty()
  105.  
  106. function tryAddGmSty() {
  107. const isAdd = document.head.querySelector('.sty777rx')
  108. if (!isAdd) {
  109. GM_addElement('style', {
  110. class: 'sty777rx',
  111. textContent: `
  112. html body .dn8x {
  113. display: none !important;
  114. visibility: hidden !important;
  115. overflow: hidden !important;
  116. height: 0 !important;
  117. width: 0 !important;
  118. transform: scale(0) !important;
  119. position: fixed !important;
  120. top: -99999px !important;
  121. left: -99999px !important;
  122. z-index: -100;
  123. }
  124. html body .GM-Asd-yisi,
  125. html body .GM-Asd-certain {
  126. overflow: hidden !important;
  127. background-image: none !important;
  128. }
  129. html body .adsbygoogle {
  130. display: none !important;
  131. }
  132. .GM-Asd-yisi::before,
  133. .GM-Asd-certain::before {
  134. content: attr(fxkasd);
  135. width: 100% !important;
  136. height: 100% !important;
  137. font-size: 16px;
  138. color: #ddd !important;
  139. background-color: transparent !important;
  140. display: flex !important;
  141. justify-content: center;
  142. align-items: center;
  143. font-weight: normal;
  144. font-style: normal;
  145. font-family: Arial sans-serif;
  146. position: absolute !important;
  147. top: 0;
  148. left: 0;
  149. z-index: 1;
  150. }
  151. .GM-Asd-certain.imgRx,
  152. .GM-Asd-certain.ifrIx,
  153. img.GM-Asd-certain {
  154. visibility: hidden !important;
  155. overflow: hidden !important;
  156. height: 0 !important;
  157. }
  158. .GM-Asd-certain.bdAsd::before {
  159. content: '百度广告' !important;
  160. }
  161. .GM-Asd-certain.gooAsd::before {
  162. content: '谷歌广告' !important;
  163. }
  164. .GM-Asd-certain.qrc7Box::before {
  165. content: '二维码';
  166. }
  167. .GM-Asd-yisi > *,
  168. .GM-Asd-certain > * {
  169. visibility: hidden !important;
  170. opacity: 0 !important;
  171. }
  172. .GM-Asd-yisi:hover > *,
  173. .GM-Asd-certain:hover > * {
  174. visibility: visible !important;
  175. opacity: 0.8 !important;
  176. animation: anim5z 1.7s both;
  177. }
  178. html .rtv8x {
  179. position: relative !important;
  180. }
  181. @keyframes anim5z {
  182. 0% {
  183. opacity: 0;
  184. }
  185. 30% {
  186. opacity: 0;
  187. }
  188. 100% {
  189. opacity: 0.8;
  190. }
  191. }
  192. @keyframes anim8z {
  193. 90% {
  194. visibility: visible;
  195. }
  196. 100% {
  197. opacity: 0;
  198. visibility: hidden;
  199. }
  200. }
  201. .GM-Asd-yisi:hover::before,
  202. .GM-Asd-certain:hover::before {
  203. animation: anim8z 1.5s both;
  204. }
  205. #wp5rh [hidden] {
  206. display: none !important;
  207. }
  208. #wp5rh, #wp5rh * {
  209. margin: 0;
  210. padding: 0;
  211. box-sizing: border-box !important;
  212. }
  213. #wp5rh {
  214. width: 28vw;
  215. height: 68vh;
  216. min-width: 440px;
  217. min-height: 400px;
  218. padding: 30px;
  219. background: #fff;
  220. border-radius: 3px;
  221. font-family: sans-serif,"HelveticaNeue",Helvetica,"PingFangSC","MicrosoftYaHei","HiraginoSansGB",Arial;
  222. line-height: 1.5;
  223. font-size: 12px;
  224. resize: both;
  225. box-shadow: 0 0 5px #ccc;
  226. position: fixed;
  227. top: 0;
  228. right: 0;
  229. bottom: 0;
  230. left: 0;
  231. z-index: 50050;
  232. margin: auto;
  233. }
  234. #wp5rh .mwp_5c {
  235. height: 100%;
  236. display: flex;
  237. flex-direction: column;
  238. position: relative;
  239. }
  240. #wp5rh .mwp_5c::before {
  241. content: '加载中...';
  242. background: #fff9;
  243. font-size: 14px;
  244. color: #999;
  245. justify-content: center;
  246. align-items: center;
  247. position: absolute;
  248. top: 0;
  249. right: 0;
  250. bottom: 0;
  251. left: 0;
  252. z-index: 1;
  253. display: none;
  254. }
  255. #wp5rh .mwp_5c.ld::before {
  256. display: flex;
  257. }
  258. #wp5rh .tit1v {
  259. color: #555;
  260. font-size: 18px;
  261. text-align: center;
  262. margin-bottom: 15px;
  263. }
  264. #wp5rh .c7d-item {
  265. margin-bottom: 10px;
  266. display: flex;
  267. flex-direction: column;
  268. flex-wrap: wrap;
  269. }
  270. #wp5rh .allset-item {
  271. flex: 1;
  272. }
  273. #wp5rh .css-item-xh {
  274. flex: 3;
  275. transition: flex .3s;
  276. }
  277. #wp5rh .js-item-xh {
  278. flex: 1;
  279. transition: flex .3s;
  280. }
  281. #wp5rh .mwp_5c.expandJS .css-item-xh {
  282. flex: 1;
  283. }
  284. #wp5rh .mwp_5c.expandJS .js-item-xh {
  285. flex: 3;
  286. }
  287. #wp5rh .stiz {
  288. font-size: 14px;
  289. color: #555;
  290. margin-bottom: 3px;
  291. position: relative;
  292. text-align: left;
  293. display: flex;
  294. }
  295. #wp5rh .tamp-cfg-modal {
  296. width: 250px;
  297. height: 170px;
  298. padding: 10px;
  299. border-radius: 2px;
  300. background: #f1f1f1;
  301. position: absolute;
  302. top: -50px;
  303. right: 0;
  304. bottom: 0;
  305. left: 0;
  306. margin: auto;
  307. z-index: 2;
  308. }
  309. #wp5rh .tamp-cfg-modal .txa-cfg {
  310. width: 100%;
  311. height: 100%;
  312. resize: none;
  313. color: #777 !important;
  314. font-family: Consolas;
  315. font-size: 12px;
  316. padding: 6px;
  317. overflow-y: auto;
  318. border: 1px solid #e6e6e6;
  319. background: #fafafa;
  320. }
  321. #wp5rh .tamp-cfg-modal .txa-cfg::-webkit-input-placeholder {
  322. color: #ccc !important;
  323. }
  324. #wp5rh .stiz .s0l {
  325. flex: 1;
  326. }
  327. #wp5rh .stiz .s0r {
  328. color: #09e;
  329. cursor: pointer;
  330. user-select: none;
  331. margin-left: 10px;
  332. }
  333. #wp5rh .stiz .s0r.on {
  334. color: #9a9a9a;
  335. }
  336. #wp5rh .oss-zbtn {
  337. color: #c7c7c7;
  338. cursor: pointer;
  339. user-select: none;
  340. margin-right: 10px;
  341. }
  342. #wp5rh .view-all-set {
  343. color: #09e;
  344. cursor: pointer;
  345. user-select: none;
  346. }
  347. #wp5rh .st1k {
  348. display: flex;
  349. }
  350. #wp5rh .st1k .s1p {
  351. flex: 1;
  352. }
  353. #wp5rh .st1k .s2p {
  354. width: 65px;
  355. color: #09e;
  356. cursor: pointer;
  357. text-align: right;
  358. white-space: nowrap;
  359. overflow: hidden;
  360. }
  361. #wp5rh .inpy {
  362. flex: 0 0 auto;
  363. height: 32px;
  364. border: 1px solid #ddd;
  365. color: #555;
  366. background: #fff;
  367. border-radius: 2px;
  368. padding: 0 10px;
  369. outline: none;
  370. }
  371. #wp5rh .inpy:focus {
  372. border: 1px solid #c1c1c1;
  373. }
  374. #wp5rh .txtr1z {
  375. width: 100%;
  376. flex: 1;
  377. color: #555;
  378. padding: 6px;
  379. line-height: 1.4;
  380. overflow-x: hidden;
  381. overflow-y: auto;
  382. border-radius: 2px;
  383. border: 1px solid #ddd;
  384. background: #fff;
  385. font-size: 12px;
  386. resize: none;
  387. white-space: pre-line;
  388. outline: none;
  389. font-family: Consolas,sans-serif,"Helvetica Neue",Helvetica,"PingFang SC","Microsoft YaHei";
  390. }
  391. #wp5rh .txtr1z::-webkit-input-placeholder {
  392. color: #c5c5c5;
  393. }
  394. #wp5rh .txtr1z:focus {
  395. border: 1px solid #39e;
  396. }
  397. #wp5rh .txtr1z.disabled {
  398. color: #999;
  399. background: #f5f5f5;
  400. }
  401. #wp5rh .txtr1z::-webkit-scrollbar {
  402. width: 4px;
  403. }
  404. #wp5rh .txtr1z::-webkit-scrollbar-corner,
  405. #wp5rh .txtr1z::-webkit-scrollbar-track {
  406. background-color: #fff;
  407. }
  408. #wp5rh .txtr1z::-webkit-scrollbar-thumb {
  409. background: #fff;
  410. }
  411. #wp5rh .txtr1z:hover::-webkit-scrollbar-thumb {
  412. background: #e1e1e1;
  413. }
  414. #wp5rh .txtr1z:hover::-webkit-scrollbar-corner,
  415. #wp5rh .txtr1z:hover::-webkit-scrollbar-track {
  416. background-color: #f7f7f7;
  417. }
  418. #wp5rh .btn-w {
  419. margin-top: 5px;
  420. display: flex;
  421. flex-direction: row-reverse;
  422. }
  423. #wp5rh .btn-w .c5kbtn {
  424. width: 90px;
  425. height: 32px;
  426. border-radius: 2px;
  427. margin-right: 10px;
  428. font-family: sans-serif,"Helvetica Neue",Helvetica,"PingFang SC","Microsoft YaHei" !important;
  429. cursor: pointer;
  430. outline: none;
  431. border: 0;
  432. }
  433. #wp5rh .btn-w .c5kbtn.b1 {
  434. color: #fff !important;
  435. background: #09e !important;
  436. }
  437. #wp5rh .btn-w .c5kbtn.b2 {
  438. color: #555 !important;
  439. background: #f1f1f1 !important;
  440. }
  441. #wp5rh .btn-w .c5kbtn:first-child {
  442. margin-right: 0;
  443. }
  444. #wp5rh .btn-w .c5kbtn:focus {
  445. border: 0;
  446. }
  447. #wp5rh .btn-w .c5kbtn:hover {
  448. opacity: 0.9;
  449. }
  450. `,
  451. })
  452. }
  453. }
  454.  
  455. const vm = new Vue({
  456. data() {
  457. return {
  458. // 模态框状态
  459. dialog1s: false,
  460. // 快捷键名称
  461. eKey: '',
  462. showAllSet: false,
  463. // css代码
  464. texCssVal: '',
  465. // js代码
  466. texJsVal: '',
  467. // 已添加的网站
  468. allAddedText: '',
  469. disCSS: false,
  470. disJS: false,
  471. // 是否展开js
  472. isExpandJS: false,
  473. isLoad: false,
  474. // oss配置modal
  475. isShowTampModal: false,
  476. tampCfgVal: '',
  477. }
  478. },
  479. computed: {
  480. viewSetText() {
  481. return this.showAllSet ? '查看当前网站' : '查看全部网站'
  482. },
  483. addedNum() {
  484. return this.allAddedText
  485. .split('\n')
  486. .filter(v => !!v)
  487. .length
  488. },
  489. disCssText() {
  490. return this.disCSS ? '已禁用' : '禁用css'
  491. },
  492. disJsText() {
  493. return this.disJS ? '已禁用' : '禁用js'
  494. },
  495. },
  496. watch: {
  497. eKey(nVal) {
  498. this.eKey = /[a-z\,]/.test(nVal) ? nVal : ''
  499. GM_setValue('_gus_keyboard', this.eKey)
  500. },
  501. dialog1s(nVal) {
  502. if (!nVal) {
  503. this.showAllSet = false
  504. this.isShowTampModal = false
  505. }
  506. },
  507. },
  508. methods: {
  509. setGmVal(obj) {
  510. obj.firstTime = obj.firstTime ?? Math.trunc(Date.now() / 1e3)
  511. return GM_setValue(`_cfg_${location.host}`, obj)
  512. },
  513. getGmVal() {
  514. let gmVal = GM_getValue(`_cfg_${location.host}`) || {}
  515. return typeof gmVal === 'string' ? JSON.parse(gmVal) : gmVal
  516. },
  517. hdlTgOssModal() {
  518. this.isShowTampModal = !this.isShowTampModal
  519. },
  520. hdlExpandJSJs(type) {
  521. this.isExpandJS = type === 2
  522. },
  523. changeTampCfg() {
  524. GM_setValue('tampOssCfg7n', this.tampCfgVal)
  525. },
  526. async hdlSave() {
  527. if (!this.showAllSet) {
  528. this.saveCssAndJs()
  529. this.initAddedWebToTextArea()
  530. } else {
  531. this.updateTextAreaValToGm()
  532. await this.saveJsonToOss('state')
  533. await this.saveJsonToOss('cfg')
  534. location.reload()
  535. }
  536. this.dialog1s = false
  537. },
  538. hdlCancel() {
  539. this.dialog1s = false
  540. },
  541. // 禁用css
  542. hdlTgDisCss() {
  543. this.disCSS = !this.disCSS
  544. },
  545. // 禁用js
  546. hdlTgDisJs() {
  547. this.disJS = !this.disJS
  548. },
  549. async saveCssAndJs() {
  550. tryAddCusSty(this.texCssVal)
  551. document.querySelectorAll('.cusSty9z1p').forEach((v, i, y) => {
  552. if (i !== y.length - 1) {
  553. v.remove()
  554. } else {
  555. v.disabled = this.disCSS
  556. }
  557. })
  558. const gm = this.getGmVal()
  559. this.setGmVal({
  560. ...gm,
  561. css: this.texCssVal,
  562. js: this.texJsVal,
  563. disCSS: this.disCSS,
  564. disJS: this.disJS,
  565. })
  566. if (!this.texCssVal && !this.texJsVal) {
  567. GM_deleteValue(`_cfg_${location.host}`)
  568. }
  569. // 同步至oss
  570. if ( !await this.saveJsonToOss('state') ) {
  571. alert('同步失败, 请导出配置后在其他网站重新导入配置就能同步了')
  572. return
  573. }
  574. await this.saveJsonToOss('cfg')
  575. if (
  576. gm.disJS !== this.disJS
  577. || gm.js !== this.texJsVal
  578. || !this.texCssVal.trim()
  579. && !this.texJsVal.trim()
  580. ) {
  581. await TMK.timeout(500)
  582. location.reload()
  583. }
  584. },
  585. saveJsonToOss(name) {
  586. let gmCfg = GM_getValue('tampOssCfg7n')
  587. if (!gmCfg) return Promise.resolve(true)
  588. gmCfg = typeof gmCfg === 'string' ? JSON.parse(gmCfg) : gmCfg
  589. const oss = new TinyOSS(gmCfg.ossParams)
  590. const lastTime = Date.now()
  591. const data = name === 'state' ? { lastTime } : this.getAllCfg()
  592. const blob = new Blob([JSON.stringify(data)], { type: 'text/json' })
  593. const date = TMK.fmt(Date.now(), 'Y-M-D')
  594. GM_setValue('tampCfgUpdateTime', lastTime)
  595. return new Promise(async (resolve) => {
  596. try {
  597. if (name === 'cfg') {
  598. oss.put(`json/tamp-cfg/cus-cssjs/${date}/${name}.json`, blob)
  599. await TMK.timeout(300)
  600. }
  601. await oss.put(`json/tamp-cfg/cus-cssjs/1-cfg/${name}.json`, blob, {
  602. onprogress(e) {
  603. if (e.total > 0) {
  604. return resolve(true)
  605. }
  606. }
  607. })
  608. } catch (err) {
  609. return resolve(false)
  610. }
  611. })
  612. },
  613. GM_req(url) {
  614. return new Promise((resolve, reject) => {
  615. GM_xmlhttpRequest({
  616. url,
  617. method: 'get',
  618. responseType: 'json',
  619. onload: function(xhr) {
  620. resolve(xhr.response)
  621. },
  622. })
  623. })
  624. },
  625. async updateCfgFromOss() {
  626. const gmCfg = this.getOssCfg()
  627. const gmLastTime = GM_getValue('tampCfgUpdateTime')
  628. if (gmCfg) {
  629. try {
  630. const url1 = `${gmCfg.state}&t=${Date.now()}`
  631. const url2 = `${gmCfg.cfg}&t=${Date.now()}`
  632. const res = await this.GM_req(url1)
  633. const { lastTime } = res
  634. const now = Date.now()
  635. if (
  636. !gmLastTime
  637. || lastTime > gmLastTime
  638. || now - gmLastTime > 3e4
  639. ) {
  640. const rCfg = await this.GM_req(url2)
  641. this.updateJsonToGm(rCfg)
  642. // 这里也初始化一次
  643. this.initAddedWebToTextArea()
  644. GM_setValue('tampCfgUpdateTime', now)
  645. }
  646. } catch (e) {
  647. TMK.log( e.message )
  648. }
  649. }
  650. },
  651. // 判断是否从远程更新
  652. tryUpdateCfgFromOss() {
  653. const gmTime = GM_getValue('pageRefreshTime')
  654. const now = Date.now()
  655. if (!gmTime || now - gmTime > 5000) {
  656. GM_setValue('pageRefreshTime', now)
  657. return new Promise(async (resolve) => {
  658. this.isLoad = true
  659. await this.updateCfgFromOss()
  660. this.isLoad = false
  661. resolve()
  662. })
  663. }
  664. },
  665. updateTextAreaValToGm() {
  666. const gmArr = GM_listValues()
  667. .filter(v => v.startsWith('_cfg_'))
  668. .map(v => v.replace(/^_cfg_/, ''))
  669. const cArr = this.allAddedText.split('\n')
  670. gmArr.forEach(v => {
  671. if (!cArr.some(c => v === c)) {
  672. GM_deleteValue(`_cfg_${v}`)
  673. }
  674. })
  675. },
  676. updateJsonToGm(obj) {
  677. if (!obj) return
  678. GM_listValues()
  679. .filter(v => /^_gus_|^_cfg_/.test(v))
  680. .forEach(v => {
  681. GM_deleteValue(v)
  682. })
  683. // 初始化firstTime
  684. for (let i in obj) {
  685. if (!obj[i].firstTime) {
  686. obj[i].firstTime = Math.trunc(Date.now() / 1e3)
  687. }
  688. }
  689. for (let k in obj) {
  690. GM_setValue(k, obj[k])
  691. }
  692. },
  693. tgCfgDialog() {
  694. this.dialog1s = !this.dialog1s
  695. },
  696. hdlViewAllSet() {
  697. this.showAllSet = !this.showAllSet
  698. },
  699. // 导入配置
  700. hdlImportCfg() {
  701. this.$refs.inp_hide.click()
  702. },
  703. // 导出配置
  704. hdlExportCfg() {
  705. const obj = this.getAllCfg()
  706. TMK.downloadText(JSON.stringify(obj, null, 2), '1.json')
  707. },
  708. // 获取oss配置
  709. getOssCfg() {
  710. let gmCfg = GM_getValue('tampOssCfg7n')
  711. if (!gmCfg) return
  712. try {
  713. return typeof gmCfg === 'string' ? JSON.parse(gmCfg) : gmCfg
  714. } catch (err) {}
  715. },
  716. initOssVal() {
  717. const gmCfg = this.getOssCfg()
  718. if (gmCfg) {
  719. this.tampCfgVal = JSON.stringify(gmCfg)
  720. }
  721. },
  722. // 获取所有已配置的网站数据
  723. getAllCfg() {
  724. const obj = GM_listValues()
  725. .filter(v => /^_gus_|^_cfg_/.test(v))
  726. .reduce((acc, v) => {
  727. let gmVal = GM_getValue(v)
  728. gmVal = typeof gmVal === 'string' && gmVal > 1 ? JSON.parse(gmVal) : gmVal
  729. return {
  730. ...acc,
  731. [v]: gmVal
  732. }
  733. }, {})
  734. for (let k in obj) {
  735. if (k.startsWith('_cfg_')) {
  736. if (!obj[k]?.css.trim() && !obj[k]?.js.trim()) {
  737. Reflect.deleteProperty(obj, k)
  738. }
  739. }
  740. }
  741. return obj
  742. },
  743. hdlUpFile(e) {
  744. let file = e.target.files[0]
  745. if (file) {
  746. let reader = new FileReader()
  747. reader.readAsText(file, 'utf-8')
  748. reader.onload = async (evt) => {
  749. try {
  750. oUp = JSON.parse(evt.target.result)
  751. this.updateJsonToGm(oUp)
  752. if (!await this.saveJsonToOss('state')) {
  753. alert('上传失败, 请选择其他网站重新上传')
  754. return
  755. }
  756. await this.saveJsonToOss('cfg')
  757. this.initCssJsVal()
  758. this.initAddedWebToTextArea()
  759. this.initAddedScript()
  760. setTimeout(() => {
  761. location.reload()
  762. }, 200)
  763. } catch (e) {
  764. // 上传失败
  765. }
  766. }
  767. }
  768. },
  769. async resetCss() {
  770. this.texCssVal = ''
  771. this.disCSS = false
  772. this.setGmVal({
  773. ...this.getGmVal(),
  774. css: '',
  775. disCSS: false,
  776. })
  777. await this.saveJsonToOss('state')
  778. await this.saveJsonToOss('cfg')
  779. location.reload()
  780. },
  781. async resetJs() {
  782. this.texJsVal = ''
  783. this.disJS = false
  784. this.setGmVal({
  785. ...this.getGmVal(),
  786. js: '',
  787. disJS: false,
  788. })
  789. await this.saveJsonToOss('state')
  790. await this.saveJsonToOss('cfg')
  791. location.reload()
  792. },
  793. initEvt() {
  794. document.addEventListener('keydown', e => {
  795. const el = e.target
  796. const edt = el.getAttribute('contenteditable')
  797. const unEdt = edt !== 'true' && edt !== ''
  798. if (
  799. !(/text|search|number|password|tel|url|email/.test(el.type))
  800. && el.tagName !== 'TEXTAREA'
  801. && unEdt
  802. && !e.altKey
  803. && !e.ctrlKey
  804. && this.eKey.split(',').map(v => v.trim()).includes(e.key)
  805. ) {
  806. this.tgCfgDialog()
  807. }
  808. if (/esc/i.test(e.key)) {
  809. this.dialog1s = false
  810. }
  811. })
  812. },
  813. initEkey() {
  814. this.eKey = GM_getValue('_gus_keyboard') || ''
  815. },
  816. initCssJsVal() {
  817. this.texCssVal = this.getGmVal().css || ''
  818. this.texJsVal = this.getGmVal().js || ''
  819. this.disCSS = !!this.getGmVal().disCSS
  820. this.disJS = !!this.getGmVal().disJS
  821. },
  822. initAddedWebToTextArea() {
  823. const sorted = this.sortSiteList(GM_listValues())
  824. const nArr = sorted
  825. .filter(v => v.startsWith('_cfg_'))
  826. .map(v => v.replace(/^_cfg_/, ''))
  827. this.allAddedText = nArr.join('\n')
  828. },
  829. initAddedScript() {
  830. let js = this.getGmVal().js
  831. let isDisabled = this.getGmVal().disJS
  832. if (js && !isDisabled) {
  833. GM_addElement('script', {
  834. type: 'module',
  835. textContent: js,
  836. })
  837. }
  838. },
  839. // 网站列表排序, 按时间倒序排列
  840. sortSiteList(siteList) {
  841. if (!siteList.length) return []
  842. const nArr = siteList.map(v => {
  843. return {
  844. name: v,
  845. t: GM_getValue(v)?.firstTime,
  846. }
  847. })
  848. .sort((a, b) => {
  849. return a.t - b.t > 0 ? -1 : 0
  850. })
  851. .map(v => v.name)
  852. return nArr
  853. },
  854. },
  855. async mounted() {
  856. this.initEvt()
  857. this.initOssVal()
  858. this.initEkey()
  859. await this.tryUpdateCfgFromOss()
  860. this.initAddedWebToTextArea()
  861. this.initCssJsVal()
  862. this.initAddedScript()
  863. },
  864. })
  865.  
  866.  
  867. function tryAddCusSty(styCnt) {
  868. const clsName = 'cusSty9z1p'
  869. if (document.querySelector('.' + clsName)) {
  870. return
  871. }
  872. if (styCnt) {
  873. G.cusStyCnt = styCnt
  874. } else {
  875. styCnt = G.cusStyCnt
  876. }
  877. GM_addElement('style', {
  878. class: clsName,
  879. textContent: styCnt
  880. })
  881. }
  882.  
  883. function tryAppendWp5() {
  884. const wp5 = document.getElementById('wp5rh')
  885. if (!wp5) {
  886. document.body.insertAdjacentHTML('beforeend', G.html)
  887. }
  888. }
  889.  
  890. // MKS
  891. // ==== 规则 start gvz =======================
  892. function isIgnHost() {
  893. return G.hostIgnore.test(location.host + location.pathname)
  894. }
  895.  
  896. function isIgnLink(linkUrl) {
  897. try {
  898. const lnk = new URL(linkUrl.replace(/^\/\//, 'https://'))
  899. return G.linkIgnore.test(lnk.host + lnk.pathname)
  900. } catch {
  901. return false
  902. }
  903. }
  904.  
  905. function isIgnIfr(url) {
  906. try {
  907. const ifr = new URL(url.replace(/^\/\//, 'https://'))
  908. return G.ifrIgnore.test(ifr.host + ifr.pathname)
  909. } catch {
  910. return false
  911. }
  912. }
  913.  
  914. // 是否是广告商
  915. function isAdvertiser(str) {
  916. return /\b(cpu\.baidu|pos\.baidu|google(sy|ad)|mediav)\b|adsbygoogle|adx\.php/.test(str)
  917. }
  918.  
  919. function isBlank(el) {
  920. return /_blank/i.test(el.target)
  921. }
  922.  
  923. function isHtmlOrBody(el) {
  924. return /^(body|html)$/i.test(el.nodeName)
  925. }
  926.  
  927. function imgSrcYsAd(src) {
  928. if (!src || src.includes('data:image/')) {
  929. return false
  930. }
  931. const str = src.slice(0, 80) + src.slice(-120)
  932. return /(\b|_)(ad[sv]?|close|adve\w+)[-_]?\d*\.(png|jpg|gif|webp)/i.test(str)
  933. }
  934.  
  935. function adTxt(s) {
  936. if (!s) return false
  937. return /(?<=[^个有打是癣很的多小种])广告(?=[^好太很多不有真比也是还])/.test(s.slice(0, 2000))
  938. }
  939.  
  940. function adm(s) {
  941. if (!s || !s.length) return false
  942. if (typeof s !== 'string' || s.includes('data:image/')) {
  943. return false
  944. }
  945. if (s.length > 2000) {
  946. s = s.slice(0, 800) + s.slice(-800)
  947. }
  948. return (
  949. /(\b|_)ad[sv]?(ver)?[-_]?\d{0,10}(\b|_)|Adver|\badsense|(\b|_)ad[sv]?[_-]\w+/i.test(s)
  950. || /(\b|_)ad[A-Z][a-z]{2,6}\d{0,4}\b|[a-z]{4}Ad(\b|_)|(\b|_)sinaad|topAd/.test(s)
  951. || /[\b_]ave[-_]{1,6}/.test(s)
  952. || isAdvertiser(s)
  953. ) && !hasUUID(s)
  954. }
  955.  
  956. // sgn
  957. function hasAdSign(el, rmTxt = false) {
  958. if (!el) return false
  959. const attArr = [...el.attributes].filter(v => v.nodeName !== 'style')
  960. return (adTxt(el.textContent) && !rmTxt)
  961. || hasAdTextInBeAf(el)
  962. || attArr.some(v => adm(v.nodeValue) || adTxt(v.nodeValue))
  963. }
  964.  
  965. function hasSibling(el) {
  966. return TMK.getSiblings(el).length > 1
  967. }
  968.  
  969. function isGif(str) {
  970. if (!str) return false
  971. return /(\.(gif|php|jsp|asp)(\b|_))|^data:image\/gif;/i.test(str)
  972. }
  973.  
  974. function ysGifAd(el) {
  975. const lazy = attr(el, 'data-src')
  976. const src = attr(el, 'src')
  977. return isGif(src)
  978. && !lazy
  979. && !isSwiper(el.parentElement)
  980. && likeAdSize(el)
  981. && !isSmallSize(el)
  982. }
  983.  
  984. function ysVideoAd(el) {
  985. if (el.tagName !== 'VIDEO') {
  986. return
  987. }
  988. const loop = attr(el, 'loop')
  989. const autoplay = attr(el, 'autoplay')
  990. const muted = attr(el, 'muted')
  991. return hasAdSign(el)
  992. || (loop && autoplay && muted && likeAdSize(el))
  993. }
  994.  
  995. function lnkEqImgUrl(link, imgUrl) {
  996. return link === imgUrl
  997. }
  998.  
  999. function isAbs(url) {
  1000. return /^https?|^\/\//i.test(url)
  1001. }
  1002.  
  1003. function isSwiper(el) {
  1004. const pEl = el.parentElement
  1005. const gEl = pEl.parentElement
  1006. const inc = (ex) => {
  1007. const p = attr(ex, 'class')
  1008. return p ? p.includes('swiper') : false
  1009. }
  1010. return inc(el) || inc(pEl) || inc(gEl)
  1011. }
  1012.  
  1013. // 大小是否符合广告的尺寸(面积)
  1014. function likeAdSize(el) {
  1015. return (
  1016. !isSmallSize(el)
  1017. && !isLargerSize(el)
  1018. && bcr(el).height < 710
  1019. )
  1020. }
  1021.  
  1022. function isLargerSize(el) {
  1023. return bcr(el).width * bcr(el).height >= 900 * 600
  1024. && !biggerRatio(el)
  1025. }
  1026.  
  1027. function isSmallSize(el) {
  1028. const w = bcr(el).width
  1029. const h = bcr(el).height
  1030. return (
  1031. (w * h) <= (80 * 40)
  1032. || w < 65
  1033. || h < 30
  1034. )
  1035. && w > 0
  1036. && h > 0
  1037. }
  1038.  
  1039. function siblingHasAd(el) {
  1040. const sib = TMK.getSiblings(el).filter(v => !/style|script/i.test(v.nodeName))
  1041. return sib.some(v => hasAdSign(v))
  1042. }
  1043.  
  1044. // 判断是否在页面边角吗角落
  1045. function isCorner(el) {
  1046. const winW = window.innerWidth
  1047. const winH = window.innerHeight
  1048. const x = bcr(el).x
  1049. const y = bcr(el).y
  1050. const w = bcr(el).width
  1051. const h = bcr(el).height
  1052. const p = 40
  1053. return (
  1054. (x - p <= 0 && y - p <= 0)
  1055. || (x - p <= 0 && y + h + p >= winH)
  1056. || (x + w + p >= winW && y - p <= 0)
  1057. || (x + w + p >= winW && y + h + p >= winH)
  1058. )
  1059. && (w > 0 && w < 580)
  1060. && (h > 0 && h < 620)
  1061. && isFixed(el)
  1062. }
  1063.  
  1064. // 靠近顶部
  1065. function isNearTop(el) {
  1066. const y = bcr(el).top
  1067. const ht = bcr(document.documentElement).top
  1068. return y >= 0
  1069. && y <= 60
  1070. && ht > -10
  1071. && bcr(el).width > 30
  1072. && bcr(el).height > 30
  1073. }
  1074.  
  1075. function likeLogo(el) {
  1076. return isNearTop(el)
  1077. && bcr(el).left < 800
  1078. && bcr(el).width < 330
  1079. }
  1080.  
  1081. function hasUUID(str) {
  1082. return /[a-f\d]{4}(?:[a-f\d]{4}-){4}[a-f\d]{12}/i.test(str)
  1083. }
  1084.  
  1085. function hasScript(el) {
  1086. return el.querySelectorAll('script').length > 0
  1087. }
  1088.  
  1089. function hasIframe(el) {
  1090. return el.querySelectorAll('iframe').length > 0
  1091. }
  1092.  
  1093. function hasAdTextInBeAf(el) {
  1094. const bf = (str) => {
  1095. const cnt = getComputedStyle(el, str).getPropertyValue('content')
  1096. return adTxt(cnt)
  1097. }
  1098. return bf('::before')|| bf('::after')
  1099. }
  1100.  
  1101. function likeQrcSize(el) {
  1102. const iw = bcr(el).width
  1103. const ih = bcr(el).height
  1104. return iw > 80 && ih > 80 &&
  1105. iw < 385 && ih < 390 &&
  1106. iw / ih > 0.7 && iw / ih < 1.1
  1107. }
  1108.  
  1109. function isFixed(el) {
  1110. return getComputedStyle(el).position === 'fixed'
  1111. }
  1112.  
  1113. function isFxk(el) {
  1114. const arr = TMK.pEls(el)
  1115. return !!attr(el, 'fxkasd') || arr.some(v => !!attr(v, 'fxkasd'))
  1116. }
  1117.  
  1118. // 宽高比例疑似
  1119. function ysAdRatio(el) {
  1120. const w = bcr(el).width
  1121. const h = bcr(el).height
  1122. return ( (w / h) > 3.6 || (h / w) > 3.6 )
  1123. && w > 30
  1124. && h > 30
  1125. }
  1126.  
  1127. function biggerRatio(el) {
  1128. const w = bcr(el).width
  1129. const h = bcr(el).height
  1130. return (w / h) > 10
  1131. && w > 30
  1132. && h > 30
  1133. }
  1134.  
  1135. function ifrHasIfr(el) {
  1136. try {
  1137. const doc = el.contentWindow?.document
  1138. return [...doc.querySelectorAll('iframe')].length > 0
  1139. } catch {
  1140. return false
  1141. }
  1142. }
  1143.  
  1144. // MKS
  1145. // ===== 规则 end =========================================
  1146.  
  1147. function bcr(el) {
  1148. return el.getBoundingClientRect()
  1149. }
  1150.  
  1151. function setFxK(el, str) {
  1152. el.setAttribute('fxkasd', str.toUpperCase())
  1153. }
  1154.  
  1155. function attr(el, p) {
  1156. return el ? el.getAttribute(p) : ''
  1157. }
  1158.  
  1159. // 内联a标签转换为inline-block
  1160. function setInlineBlock(link) {
  1161. if (getComputedStyle(link).display === 'inline') {
  1162. link.style.display = 'inline-block'
  1163. }
  1164. }
  1165.  
  1166. // 如果是static则设置为relative
  1167. function setEleAsRelative(el) {
  1168. if (getComputedStyle(el).position === 'static') {
  1169. el.style.position = 'relative'
  1170. el.classList.add('rtv8x')
  1171. }
  1172. }
  1173.  
  1174. function linkHost(url) {
  1175. return TMK.isAbsUrl(url) ? new URL(url).host : null
  1176. }
  1177.  
  1178. function compareTwoBox(el1, el2) {
  1179. const w = bcr(el1).width
  1180. const h = bcr(el1).height
  1181. const pw = bcr(el2).width
  1182. const ph = bcr(el2).height
  1183. const cs = getComputedStyle
  1184. const pTop = Number(cs(el1).paddingTop.slice(0, -2))
  1185. const pRight = Number(cs(el1).paddingRight.slice(0, -2))
  1186. const pBom = Number(cs(el1).paddingBottom.slice(0, -2))
  1187. const pLeft = Number(cs(el1).paddingLeft.slice(0, -2))
  1188. return (Math.abs(pw + pLeft + pRight - w) < 32
  1189. && Math.abs(ph + pTop + pBom - h) < 32
  1190. && pw > 36
  1191. && ph > 36)
  1192. || (w < 6 || h < 6)
  1193. }
  1194.  
  1195. function setCertainCls(el, cls = '') {
  1196. const hasFk = (fk) => {
  1197. return !!el?.src?.includes(fk) || [...el.querySelectorAll('iframe')]?.some(ifr => ifr?.src?.includes(fk))
  1198. }
  1199. const bdCls = hasFk('pos.baidu') ? 'bdAsd' : ''
  1200. const ggCls = hasFk('googlead') ? 'gooAsd' : ''
  1201. const clsStr = `GM-Asd-certain ${bdCls} ${ggCls} ${cls}`.trim().replace(/\s{2,}/, ' ').split(' ')
  1202. el.classList.add(...clsStr)
  1203. }
  1204.  
  1205. // 删除添加的屏蔽class和标记
  1206. function removeAsdMk(el, isRecursive) {
  1207. let dArr = [el]
  1208. if (isRecursive) {
  1209. dArr = [...dArr, ...TMK.pEls(el)]
  1210. }
  1211. dArr.forEach(v => {
  1212. v.classList.remove(
  1213. 'GM-Asd-yisi',
  1214. 'GM-Asd-certain',
  1215. 'bdAsd',
  1216. 'gooAsd',
  1217. 'qrc7Box',
  1218. 'x8x',
  1219. )
  1220. v.removeAttribute('fxkasd')
  1221. })
  1222. }
  1223.  
  1224. function tryBkSiblingAndReturnRes(el) {
  1225. const sib = TMK.getSiblings(el).filter(v => !/style|script/i.test(v.nodeName))
  1226. let isSuc = false
  1227. sib.forEach(v => {
  1228. if (hasAdSign(v)) {
  1229. isSuc = true
  1230. trySetMkRecursive(v, 'sib01', 'sib02')
  1231. }
  1232. })
  1233. return isSuc
  1234. }
  1235.  
  1236. function imgIsLargeSize(img) {
  1237. if (img.nodeName !== 'IMG') {
  1238. return false
  1239. }
  1240. return isLargerSize(img)
  1241. }
  1242.  
  1243. function trySetMkRecursive(el, mk1, mk2, clsStr = '') {
  1244. if (
  1245. !el
  1246. || isFxk(el)
  1247. || el.id === 'wp5rh'
  1248. ) {
  1249. return
  1250. }
  1251. const isForce = clsStr.includes('dn8x')
  1252. el.classList.add('x8x')
  1253. setEleAsRelative(el)
  1254. const zArr = [...[el], ...TMK.pEls(el)].reverse()
  1255. const laEl = zArr[zArr.length - 1]
  1256. let isAdd = false
  1257. for (let pl of zArr) {
  1258. // 避免Dom嵌套过深
  1259. if (zArr.length > 20) {
  1260. break
  1261. }
  1262. if (compareTwoBox(pl, laEl) && pl !== el) {
  1263. if (
  1264. !isHtmlOrBody(pl)
  1265. && (likeAdSize(laEl) || isForce)
  1266. ) {
  1267. setEleAsRelative(pl)
  1268. setCertainCls(pl, clsStr)
  1269. setFxK(pl, mk1)
  1270. isAdd = true
  1271. }
  1272. break
  1273. }
  1274. }
  1275. const ipl = el.parentElement
  1276. if (!likeAdSize(el) && !isForce) {
  1277. return
  1278. }
  1279. if (
  1280. !isAdd
  1281. && !isHtmlOrBody(el)
  1282. ) {
  1283. setCertainCls(el, clsStr)
  1284. setFxK(el, mk2)
  1285. } else if (
  1286. !isHtmlOrBody(ipl)
  1287. && (
  1288. !isAdd
  1289. || imgIsLargeSize(el)
  1290. )
  1291. ) {
  1292. setEleAsRelative(ipl)
  1293. setCertainCls(ipl, clsStr + ' imgRx')
  1294. setFxK(ipl, mk2)
  1295. }
  1296. }
  1297.  
  1298. // 屏蔽body直接子元素疑似AD bda
  1299. function blockBodyCdYsAd() {
  1300. document.querySelectorAll('body > *, body > * > *, div[class*="fixed"], div[id*="fixed"]').forEach(el => {
  1301. const isLnk = el.tagName === 'A'
  1302. const largesAd = isLnk
  1303. && isLargerSize(el)
  1304. && document.querySelectorAll('*').length > 800
  1305. const largerZdx = Number(getComputedStyle(el).zIndex) > 9980
  1306. const imgInLnk = el.querySelectorAll('a > img').length > 0
  1307. const hasVdo = el.querySelectorAll('video').length > 0
  1308. if (
  1309. largesAd
  1310. || (
  1311. (
  1312. largerZdx
  1313. || hasScript(el)
  1314. || imgInLnk
  1315. || hasVdo
  1316. )
  1317. && isCorner(el)
  1318. && likeAdSize(el)
  1319. )
  1320. ) {
  1321. el.classList.add('dn8x')
  1322. el.style.display = 'none'
  1323. return
  1324. }
  1325. })
  1326. }
  1327.  
  1328. // 屏蔽div中含有script的疑似AD spt
  1329. function blockScriptInDiv() {
  1330. document.querySelectorAll('body script').forEach(el => {
  1331. const pEl = el.parentElement
  1332. if (isLargerSize(pEl)) {
  1333. removeAsdMk(el, true)
  1334. return
  1335. }
  1336. if (isFxk(pEl)) {
  1337. return
  1338. }
  1339. let prevNum = 0
  1340. let prevEl = el.previousElementSibling
  1341. while (prevEl) {
  1342. if (prevEl.nodeName === 'SCRIPT') {
  1343. prevNum++
  1344. }
  1345. prevEl = prevEl.previousElementSibling
  1346. }
  1347. if (!prevNum && tryBkSiblingAndReturnRes(el)) {
  1348. return
  1349. }
  1350. if (hasAdSign(el) || hasAdSign(pEl)) {
  1351. trySetMkRecursive(pEl, 's01', 's02')
  1352. }
  1353. })
  1354. }
  1355.  
  1356. // 屏蔽疑似ad的box sltad
  1357. function blockYsSlt() {
  1358. const sArr = ['div[class*="-ad" i]', 'div[class*="ad-" i]', 'div[class*="_ad" i]', 'div[class*="ad_" i]',
  1359. 'div[id*="-ad" i]', 'div[id*="ad-" i]', 'div[id*="_ad" i]', 'div[id*="ad_" i]',
  1360. 'li[class*="-ad" i]', 'li[class*="ad-" i]', 'li[class*="_ad" i]', 'li[class*="ad_" i]',
  1361. 'li[id*="-ad" i]', 'li[id*="ad-" i]', 'li[id*="_ad" i]', 'li[id*="ad_" i]',
  1362. 'li[class*="mediav" i]',
  1363. 'div[class*="mediav" i]',
  1364. 'div[data-spm*="ad-" i]', 'div[class*="ave" i]', 'div[aria-label*="ad-" i]', 'div[id*="ave" i]', 'li[class*="ave" i]', 'li[id*="ave" i]', 'li[data-spm*="ave" i]', 'ins[class*="ad" i]', 'ins[id*="ad" i]',
  1365. ]
  1366. document.querySelectorAll(sArr.join(',')).forEach(el => {
  1367. if (isLargerSize(el)) {
  1368. removeAsdMk(el, true)
  1369. return
  1370. }
  1371. if (isFxk(el)) {
  1372. return
  1373. }
  1374. if (adm(el.id) || adm(el.className)) {
  1375. if (
  1376. hasAdSign(el)
  1377. && (likeAdSize(el) || isFixed(el))
  1378. ) {
  1379. trySetMkRecursive(el, 's51', 's52')
  1380. }
  1381. }
  1382. })
  1383. }
  1384.  
  1385. // 屏蔽注释中包含广告的下一元素 cmt
  1386. function blockCommentsHasAd() {
  1387. let dgLmt = 12
  1388. const cdArr = []
  1389. let cdNds = Array.from(document.body?.childNodes || [])
  1390. while (--dgLmt && cdNds.length) {
  1391. cdArr.push(...cdNds)
  1392. cdNds = cdNds.map(v => [...v.childNodes]).flat(1)
  1393. }
  1394. const cmtArr = cdArr.filter(v => {
  1395. return v.nodeType === 8
  1396. && v.nodeValue.length < 50
  1397. && /廣告|广告|\bAD\b|\badsense|\badv/.test(v.nodeValue)
  1398. && !/结束|end/i.test(v.nodeValue)
  1399. })
  1400. cmtArr.forEach(v => {
  1401. let nextEl = v.nextElementSibling
  1402. while (nextEl && /style|script/i.test(nextEl.nodeName)) {
  1403. nextEl = nextEl.nextElementSibling
  1404. }
  1405. trySetMkRecursive(nextEl, 'C01', 'C02')
  1406. })
  1407. }
  1408.  
  1409. // 屏蔽iframe广告 ifs
  1410. function blockIfrAd() {
  1411. document.querySelectorAll('iframe').forEach(v => {
  1412. const src = attr(v, 'src')
  1413. if (isIgnIfr(src)) {
  1414. return
  1415. }
  1416. if (isLargerSize(v)) {
  1417. removeAsdMk(v, true)
  1418. return
  1419. }
  1420. if (isAdvertiser(src)) {
  1421. trySetMkRecursive(v, 'f01', 'f02', 'ifrIx dn8x')
  1422. return
  1423. }
  1424. const pEl = v.parentElement
  1425. const rLen = () => {
  1426. return [
  1427. hasAdSign(v),
  1428. hasAdSign(pEl),
  1429. ysAdRatio(v),
  1430. ].filter(v => !!v).length
  1431. }
  1432. if (
  1433. rLen() >= 1
  1434. || (
  1435. ifrHasIfr(v)
  1436. && ysAdRatio(v)
  1437. )
  1438. || (
  1439. isNearTop(v)
  1440. && ysAdRatio(v)
  1441. )
  1442. ) {
  1443. trySetMkRecursive(v, 'f01', 'f02', 'ifrIx')
  1444. }
  1445. })
  1446. }
  1447.  
  1448. function blockYsVideoAd() {
  1449. document.querySelectorAll('video').forEach(vdo => {
  1450. const rLen = () => {
  1451. return [
  1452. ysVideoAd(vdo),
  1453. ]
  1454. .filter(v => !!v)
  1455. .length
  1456. }
  1457. if (
  1458. rLen() >= 1
  1459. || ysAdRatio(vdo)
  1460. ) {
  1461. trySetMkRecursive(vdo, 'vdo01', 'vdo02', 'vdoRb')
  1462. }
  1463. })
  1464. }
  1465.  
  1466. // ims
  1467. function blockYsImgInLink() {
  1468. Array.from(document.querySelectorAll('a > img, a > * > img, a > * > * > img')).forEach(el => {
  1469. const link = el.closest('a')
  1470. const pEl = link.parentElement
  1471. const lnkUrl = attr(link, 'href')
  1472. if (isIgnLink(lnkUrl)) {
  1473. return
  1474. }
  1475. const rArrLen = () => {
  1476. return [
  1477. isBlank(link),
  1478. ysGifAd(el),
  1479. imgSrcYsAd(attr(el, 'src')),
  1480. hasAdSign(link),
  1481. hasAdSign(pEl),
  1482. hasAdSign(el),
  1483. siblingHasAd(link),
  1484. siblingHasAd(el),
  1485. isNearTop(el),
  1486. biggerRatio(el),
  1487. ].filter(v => !!v).length
  1488. }
  1489. if (
  1490. (
  1491. rArrLen() >= 2
  1492. && !isSmallSize(el)
  1493. && !likeLogo(el)
  1494. ) || (
  1495. isCorner(el)
  1496. && ysGifAd(el)
  1497. )
  1498. ) {
  1499. trySetMkRecursive(el, 'i01', 'i02')
  1500. }
  1501. })
  1502. }
  1503.  
  1504. function wchDom() {
  1505. TMK.watchDom('body', TMK.throttle(() => {
  1506. tryAddCusSty()
  1507. tryAddGmSty()
  1508. }, 500))
  1509. }
  1510.  
  1511. function regMainEvt() {
  1512. ['mousemove', 'scroll'].forEach(evt => {
  1513. document.addEventListener(evt, insMainAdFn)
  1514. })
  1515. }
  1516.  
  1517. function insMainAdFn() {
  1518. const pnow = performance.now()
  1519. let now = Date.now()
  1520. if (now - G.tmpTime > 800 || pnow < 6000) {
  1521. G.tmpTime = now
  1522. if (!isIgnHost()) {
  1523. // 链接下的图片
  1524. blockYsImgInLink()
  1525. blockBodyCdYsAd()
  1526. blockYsSlt()
  1527. blockCommentsHasAd()
  1528. // 确认iframe广告
  1529. blockIfrAd()
  1530. blockScriptInDiv()
  1531. // 视频广告
  1532. blockYsVideoAd()
  1533. }
  1534. }
  1535. }
  1536.  
  1537. function initTimer() {
  1538. insMainAdFn()
  1539. setTimeout(initTimer, performance.now() < 6000 ? 350 : 8000)
  1540. }
  1541.  
  1542. async function initFunc() {
  1543. if (TMK.isMobile()) return
  1544. setTimeout(() => {
  1545. if (!isIgnHost()) {
  1546. regMainEvt()
  1547. }
  1548. }, 5e3)
  1549. initTimer()
  1550. await TMK.loadEl('body')
  1551. tryAppendWp5()
  1552. vm.$mount('#wp5rh')
  1553. GM_registerMenuCommand('打开设置面板', vm.tgCfgDialog)
  1554. GM_registerMenuCommand('清空当前网站添加的CSS', vm.resetCss)
  1555. GM_registerMenuCommand('清空当前网站添加的JS', vm.resetJs)
  1556. wchDom()
  1557. }
  1558.  
  1559. initFunc()

QingJ © 2025

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